You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
4.4 KiB

  1. 'use strict'
  2. /* global wiki */
  3. module.exports = false
  4. return
  5. const express = require('express')
  6. const router = express.Router()
  7. const readChunk = require('read-chunk')
  8. const fileType = require('file-type')
  9. const Promise = require('bluebird')
  10. const fs = Promise.promisifyAll(require('fs-extra'))
  11. const path = require('path')
  12. const _ = require('lodash')
  13. const validPathRe = new RegExp('^([a-z0-9/-' + wiki.data.regex.cjk + wiki.data.regex.arabic + ']+\\.[a-z0-9]+)$')
  14. const validPathThumbsRe = new RegExp('^([a-z0-9]+\\.png)$')
  15. // ==========================================
  16. // SERVE UPLOADS FILES
  17. // ==========================================
  18. router.get('/t/*', (req, res, next) => {
  19. let fileName = req.params[0]
  20. if (!validPathThumbsRe.test(fileName)) {
  21. return res.sendStatus(404).end()
  22. }
  23. // todo: Authentication-based access
  24. res.sendFile(fileName, {
  25. root: wiki.disk.getThumbsPath(),
  26. dotfiles: 'deny'
  27. }, (err) => {
  28. if (err) {
  29. res.status(err.status).end()
  30. }
  31. })
  32. })
  33. router.post('/img', wiki.disk.uploadImgHandler, (req, res, next) => {
  34. let destFolder = _.chain(req.body.folder).trim().toLower().value()
  35. wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => {
  36. if (!destFolderPath) {
  37. res.json({ ok: false, msg: wiki.lang.t('errors:invalidfolder') })
  38. return true
  39. }
  40. Promise.map(req.files, (f) => {
  41. let destFilename = ''
  42. let destFilePath = ''
  43. return wiki.disk.validateUploadsFilename(f.originalname, destFolder, true).then((fname) => {
  44. destFilename = fname
  45. destFilePath = path.resolve(destFolderPath, destFilename)
  46. return readChunk(f.path, 0, 262)
  47. }).then((buf) => {
  48. // -> Check MIME type by magic number
  49. let mimeInfo = fileType(buf)
  50. if (!_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], mimeInfo.mime)) {
  51. return Promise.reject(new Error(wiki.lang.t('errors:invalidfiletype')))
  52. }
  53. return true
  54. }).then(() => {
  55. // -> Move file to final destination
  56. return fs.moveAsync(f.path, destFilePath, { clobber: false })
  57. }).then(() => {
  58. return {
  59. ok: true,
  60. filename: destFilename,
  61. filesize: f.size
  62. }
  63. }).reflect()
  64. }, {concurrency: 3}).then((results) => {
  65. let uplResults = _.map(results, (r) => {
  66. if (r.isFulfilled()) {
  67. return r.value()
  68. } else {
  69. return {
  70. ok: false,
  71. msg: r.reason().message
  72. }
  73. }
  74. })
  75. res.json({ ok: true, results: uplResults })
  76. return true
  77. }).catch((err) => {
  78. res.json({ ok: false, msg: err.message })
  79. return true
  80. })
  81. })
  82. })
  83. router.post('/file', wiki.disk.uploadFileHandler, (req, res, next) => {
  84. let destFolder = _.chain(req.body.folder).trim().toLower().value()
  85. wiki.upl.validateUploadsFolder(destFolder).then((destFolderPath) => {
  86. if (!destFolderPath) {
  87. res.json({ ok: false, msg: wiki.lang.t('errors:invalidfolder') })
  88. return true
  89. }
  90. Promise.map(req.files, (f) => {
  91. let destFilename = ''
  92. let destFilePath = ''
  93. return wiki.disk.validateUploadsFilename(f.originalname, destFolder, false).then((fname) => {
  94. destFilename = fname
  95. destFilePath = path.resolve(destFolderPath, destFilename)
  96. // -> Move file to final destination
  97. return fs.moveAsync(f.path, destFilePath, { clobber: false })
  98. }).then(() => {
  99. return {
  100. ok: true,
  101. filename: destFilename,
  102. filesize: f.size
  103. }
  104. }).reflect()
  105. }, {concurrency: 3}).then((results) => {
  106. let uplResults = _.map(results, (r) => {
  107. if (r.isFulfilled()) {
  108. return r.value()
  109. } else {
  110. return {
  111. ok: false,
  112. msg: r.reason().message
  113. }
  114. }
  115. })
  116. res.json({ ok: true, results: uplResults })
  117. return true
  118. }).catch((err) => {
  119. res.json({ ok: false, msg: err.message })
  120. return true
  121. })
  122. })
  123. })
  124. router.get('/*', (req, res, next) => {
  125. let fileName = req.params[0]
  126. if (!validPathRe.test(fileName)) {
  127. return res.sendStatus(404).end()
  128. }
  129. // todo: Authentication-based access
  130. res.sendFile(fileName, {
  131. root: wiki.git.getRepoPath() + '/uploads/',
  132. dotfiles: 'deny'
  133. }, (err) => {
  134. if (err) {
  135. res.status(err.status).end()
  136. }
  137. })
  138. })
  139. module.exports = router