2
0

uploads.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. "use strict";
  2. var express = require('express');
  3. var router = express.Router();
  4. var readChunk = require('read-chunk'),
  5. fileType = require('file-type'),
  6. Promise = require('bluebird'),
  7. fs = Promise.promisifyAll(require('fs-extra')),
  8. path = require('path'),
  9. _ = require('lodash');
  10. var validPathRe = new RegExp("^([a-z0-9\\/-]+\\.[a-z0-9]+)$");
  11. var validPathThumbsRe = new RegExp("^([0-9]+\\.png)$");
  12. // ==========================================
  13. // SERVE UPLOADS FILES
  14. // ==========================================
  15. router.get('/t/*', (req, res, next) => {
  16. let fileName = req.params[0];
  17. if(!validPathThumbsRe.test(fileName)) {
  18. return res.sendStatus(404).end();
  19. }
  20. //todo: Authentication-based access
  21. res.sendFile(fileName, {
  22. root: lcdata.getThumbsPath(),
  23. dotfiles: 'deny'
  24. }, (err) => {
  25. if (err) {
  26. res.status(err.status).end();
  27. }
  28. });
  29. });
  30. router.post('/img', lcdata.uploadImgHandler, (req, res, next) => {
  31. let destFolder = _.chain(req.body.folder).trim().toLower().value();
  32. ws.emit('uploadsValidateFolder', {
  33. auth: WSInternalKey,
  34. content: destFolder
  35. }, (destFolderPath) => {
  36. if(!destFolderPath) {
  37. return res.json({ ok: false, msg: 'Invalid Folder' });
  38. }
  39. Promise.map(req.files, (f) => {
  40. let destFilename = '';
  41. let destFilePath = '';
  42. return lcdata.validateUploadsFilename(f.originalname, destFolder).then((fname) => {
  43. destFilename = fname;
  44. destFilePath = path.resolve(destFolderPath, destFilename);
  45. return readChunk(f.path, 0, 262);
  46. }).then((buf) => {
  47. //-> Check MIME type by magic number
  48. let mimeInfo = fileType(buf);
  49. if(!_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], mimeInfo.mime)) {
  50. return Promise.reject(new Error('Invalid file type.'));
  51. }
  52. return true;
  53. }).then(() => {
  54. //-> Move file to final destination
  55. return fs.moveAsync(f.path, destFilePath, { clobber: false });
  56. }).then(() => {
  57. return {
  58. ok: true,
  59. filename: destFilename,
  60. filesize: f.size
  61. };
  62. }).reflect();
  63. }, {concurrency: 3}).then((results) => {
  64. let uplResults = _.map(results, (r) => {
  65. if(r.isFulfilled()) {
  66. return r.value();
  67. } else {
  68. return {
  69. ok: false,
  70. msg: r.reason().message
  71. }
  72. }
  73. });
  74. res.json({ ok: true, results: uplResults });
  75. }).catch((err) => {
  76. res.json({ ok: false, msg: err.message });
  77. });
  78. });
  79. });
  80. router.get('/*', (req, res, next) => {
  81. let fileName = req.params[0];
  82. if(!validPathRe.test(fileName)) {
  83. return res.sendStatus(404).end();
  84. }
  85. //todo: Authentication-based access
  86. res.sendFile(fileName, {
  87. root: git.getRepoPath() + '/uploads/',
  88. dotfiles: 'deny'
  89. }, (err) => {
  90. if (err) {
  91. res.status(err.status).end();
  92. }
  93. });
  94. });
  95. module.exports = router;