|
@@ -2,14 +2,32 @@ import { Meteor } from 'meteor/meteor';
|
|
|
import { FilesCollection } from 'meteor/ostrio:files';
|
|
|
import { createBucket } from './lib/grid/createBucket';
|
|
|
import fs from 'fs';
|
|
|
+import FileType from 'file-type';
|
|
|
import path from 'path';
|
|
|
import { AttachmentStoreStrategyFilesystem, AttachmentStoreStrategyGridFs} from '/models/lib/attachmentStoreStrategy';
|
|
|
import FileStoreStrategyFactory, {moveToStorage, rename, STORAGE_NAME_FILESYSTEM, STORAGE_NAME_GRIDFS} from '/models/lib/fileStoreStrategy';
|
|
|
|
|
|
+let attachmentUploadMimeTypes = [];
|
|
|
+let attachmentUploadSize = 0;
|
|
|
let attachmentBucket;
|
|
|
let storagePath;
|
|
|
+
|
|
|
if (Meteor.isServer) {
|
|
|
attachmentBucket = createBucket('attachments');
|
|
|
+
|
|
|
+ if (process.env.ATTACHMENTS_UPLOAD_MIME_TYPES) {
|
|
|
+ attachmentUploadMimeTypes = process.env.ATTACHMENTS_UPLOAD_MIME_TYPES.split(',');
|
|
|
+ attachmentUploadMimeTypes = attachmentUploadMimeTypes.map(value => value.trim());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (process.env.ATTACHMENTS_UPLOAD_MAX_SIZE) {
|
|
|
+ attachmentUploadSize = parseInt(process.env.ATTACHMENTS_UPLOAD_MAX_SIZE);
|
|
|
+
|
|
|
+ if (isNaN(attachmentUploadSize)) {
|
|
|
+ attachmentUploadSize = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
storagePath = path.join(process.env.WRITABLE_PATH, 'attachments');
|
|
|
}
|
|
|
|
|
@@ -34,13 +52,39 @@ Attachments = new FilesCollection({
|
|
|
return ret;
|
|
|
},
|
|
|
onAfterUpload(fileObj) {
|
|
|
- let storage = fileObj.meta.copyStorage || STORAGE_NAME_GRIDFS;
|
|
|
+ let isValid = true;
|
|
|
+
|
|
|
+ if (attachmentUploadMimeTypes.length) {
|
|
|
+ const mimeTypeResult = Promise.await(FileType.fromFile(fileObj.path));
|
|
|
+
|
|
|
+ const mimeType = (mimeTypeResult ? mimeTypeResult.mime : fileObj.type);
|
|
|
+ const baseMimeType = mimeType.split('/', 1)[0];
|
|
|
+
|
|
|
+ isValid = attachmentUploadMimeTypes.includes(mimeType) || attachmentUploadMimeTypes.includes(baseMimeType + '/*') || attachmentUploadMimeTypes.includes('*');
|
|
|
+
|
|
|
+ if (!isValid) {
|
|
|
+ console.log("Validation of uploaded file failed: file " + fileObj.path + " - mimetype " + mimeType);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (attachmentUploadSize && fileObj.size > attachmentUploadSize) {
|
|
|
+ console.log("Validation of uploaded file failed: file " + fileObj.path + " - size " + fileObj.size);
|
|
|
+ isValid = false;
|
|
|
+ }
|
|
|
+
|
|
|
// current storage is the filesystem, update object and database
|
|
|
Object.keys(fileObj.versions).forEach(versionName => {
|
|
|
fileObj.versions[versionName].storage = STORAGE_NAME_FILESYSTEM;
|
|
|
});
|
|
|
+
|
|
|
Attachments.update({ _id: fileObj._id }, { $set: { "versions" : fileObj.versions } });
|
|
|
- moveToStorage(fileObj, storage, fileStoreStrategyFactory);
|
|
|
+
|
|
|
+ if (isValid) {
|
|
|
+ let storage = fileObj.meta.copyStorage || STORAGE_NAME_GRIDFS;
|
|
|
+ moveToStorage(fileObj, storage, fileStoreStrategyFactory);
|
|
|
+ } else {
|
|
|
+ this.remove(fileObj._id);
|
|
|
+ }
|
|
|
},
|
|
|
interceptDownload(http, fileObj, versionName) {
|
|
|
const ret = fileStoreStrategyFactory.getFileStrategy(fileObj, versionName).interceptDownload(http, this.cacheControl);
|
|
@@ -57,10 +101,16 @@ Attachments = new FilesCollection({
|
|
|
// - if the board is public, everyone (even unconnected) can download it
|
|
|
// - if the board is private, only board members can download it
|
|
|
protected(fileObj) {
|
|
|
+ // file may have been deleted already again after upload validation failed
|
|
|
+ if (!fileObj) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
const board = Boards.findOne(fileObj.meta.boardId);
|
|
|
if (board.isPublic()) {
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
return board.hasMember(this.userId);
|
|
|
},
|
|
|
});
|