mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-06 22:15:48 +01:00
closes #725
This commit is contained in:
@@ -33,7 +33,9 @@
|
||||
"heapdump": "^0.3.0",
|
||||
"less": "^2.0.0",
|
||||
"logrotate-stream": "^0.2.3",
|
||||
"mime": "^1.3.4",
|
||||
"mkdirp": "~0.5.0",
|
||||
"mmmagic": "^0.3.13",
|
||||
"morgan": "^1.3.2",
|
||||
"nconf": "~0.7.1",
|
||||
"nodebb-plugin-dbsearch": "^0.1.0",
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
|
||||
"invalid-image-type": "Invalid image type. Allowed types are: %1",
|
||||
"invalid-image-extension": "Invalid image extension",
|
||||
"invalid-file-type": "Invalid file type. Allowed types are: %1",
|
||||
|
||||
"group-name-too-short": "Group name too short",
|
||||
"group-already-exists": "Group already exists",
|
||||
@@ -80,7 +81,6 @@
|
||||
"topic-thumbnails-are-disabled": "Topic thumbnails are disabled.",
|
||||
"invalid-file": "Invalid File",
|
||||
"uploads-are-disabled": "Uploads are disabled",
|
||||
"upload-error": "Upload Error : %1",
|
||||
|
||||
"signature-too-long" : "Sorry, your signature cannot be longer than %1 characters.",
|
||||
|
||||
|
||||
@@ -316,8 +316,7 @@ define('composer/uploads', ['composer/preview', 'csrf'], function(preview, csrf)
|
||||
|
||||
function onUploadError(xhr) {
|
||||
xhr = maybeParse(xhr);
|
||||
|
||||
app.alertError('[[error:upload-error, ' + xhr.responseText + ']]');
|
||||
app.alertError(xhr.responseText);
|
||||
}
|
||||
|
||||
return uploads;
|
||||
|
||||
@@ -130,9 +130,7 @@
|
||||
return ('' + path).split('.').pop();
|
||||
},
|
||||
|
||||
fileMimeType: (function () {
|
||||
// we only care about images, for now
|
||||
var map = {
|
||||
extensionMimeTypeMap: {
|
||||
"bmp": "image/bmp",
|
||||
"cmx": "image/x-cmx",
|
||||
"cod": "image/cis-cod",
|
||||
@@ -143,6 +141,7 @@
|
||||
"jpe": "image/jpeg",
|
||||
"jpeg": "image/jpeg",
|
||||
"jpg": "image/jpeg",
|
||||
"png": "image/png",
|
||||
"pbm": "image/x-portable-bitmap",
|
||||
"pgm": "image/x-portable-graymap",
|
||||
"pnm": "image/x-portable-anymap",
|
||||
@@ -155,13 +154,15 @@
|
||||
"xbm": "image/x-xbitmap",
|
||||
"xpm": "image/x-xpixmap",
|
||||
"xwd": "image/x-xwindowdump"
|
||||
};
|
||||
},
|
||||
|
||||
return function (path) {
|
||||
var extension = utils.fileExtension(path);
|
||||
return map[extension] || '*';
|
||||
};
|
||||
})(),
|
||||
fileMimeType: function (path) {
|
||||
utils.extensionToMimeType(utils.fileExtension(path));
|
||||
},
|
||||
|
||||
extensionToMimeType: function(extension) {
|
||||
return utils.extensionMimeTypeMap[extension] || '*';
|
||||
},
|
||||
|
||||
isRelativeUrl: function(url) {
|
||||
var firstChar = url.slice(0, 1);
|
||||
|
||||
@@ -376,33 +376,26 @@ accountsController.accountSettings = function(req, res, next) {
|
||||
accountsController.uploadPicture = function (req, res, next) {
|
||||
var userPhoto = req.files.files[0];
|
||||
var uploadSize = parseInt(meta.config.maximumProfileImageSize, 10) || 256;
|
||||
|
||||
if (userPhoto.size > uploadSize * 1024) {
|
||||
fs.unlink(userPhoto.path);
|
||||
return next(new Error('[[error:file-too-big, ' + uploadSize + ']]'));
|
||||
}
|
||||
|
||||
var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
|
||||
if (allowedTypes.indexOf(userPhoto.type) === -1) {
|
||||
fs.unlink(userPhoto.path);
|
||||
return next(new Error('[[error:invalid-image-type, ' + allowedTypes.join(', ') + ']]'));
|
||||
}
|
||||
|
||||
var extension = path.extname(userPhoto.name);
|
||||
if (!extension) {
|
||||
fs.unlink(userPhoto.path);
|
||||
return next(new Error('[[error:invalid-image-extension]]'));
|
||||
}
|
||||
|
||||
var updateUid = req.user ? req.user.uid : 0;
|
||||
var imageDimension = parseInt(meta.config.profileImageDimension, 10) || 128;
|
||||
var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1;
|
||||
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
next(userPhoto.size > uploadSize * 1024 ? new Error('[[error:file-too-big, ' + uploadSize + ']]') : null);
|
||||
},
|
||||
function(next) {
|
||||
next(!extension ? new Error('[[error:invalid-image-extension]]') : null);
|
||||
},
|
||||
function(next) {
|
||||
file.isFileTypeAllowed(userPhoto.path, ['png', 'jpeg', 'jpg', 'gif'], next);
|
||||
},
|
||||
function(next) {
|
||||
image.resizeImage(userPhoto.path, extension, imageDimension, imageDimension, next);
|
||||
},
|
||||
function(next) {
|
||||
if (parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1) {
|
||||
if (convertToPNG) {
|
||||
image.convertImageToPng(userPhoto.path, extension, next);
|
||||
} else {
|
||||
next();
|
||||
@@ -412,7 +405,7 @@ accountsController.uploadPicture = function (req, res, next) {
|
||||
user.getUidByUserslug(req.params.userslug, next);
|
||||
},
|
||||
function(uid, next) {
|
||||
if(parseInt(updateUid, 10) === parseInt(uid, 10)) {
|
||||
if (parseInt(updateUid, 10) === parseInt(uid, 10)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -450,7 +443,6 @@ accountsController.uploadPicture = function (req, res, next) {
|
||||
return plugins.fireHook('filter:uploadImage', {image: userPhoto, uid: updateUid}, done);
|
||||
}
|
||||
|
||||
var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1;
|
||||
var filename = updateUid + '-profileimg' + (convertToPNG ? '.png' : extension);
|
||||
|
||||
user.getUserField(updateUid, 'uploadedpicture', function (err, oldpicture) {
|
||||
|
||||
@@ -7,6 +7,7 @@ var uploadsController = {},
|
||||
async = require('async'),
|
||||
|
||||
meta = require('../meta'),
|
||||
file = require('../file'),
|
||||
plugins = require('../plugins'),
|
||||
utils = require('../../public/src/utils'),
|
||||
image = require('../image');
|
||||
@@ -42,12 +43,18 @@ uploadsController.upload = function(req, res, filesIterator, next) {
|
||||
};
|
||||
|
||||
uploadsController.uploadPost = function(req, res, next) {
|
||||
uploadsController.upload(req, res, function(file, next) {
|
||||
if (file.type.match(/image./)) {
|
||||
uploadImage(req.user.uid, file, next);
|
||||
} else {
|
||||
uploadFile(req.user.uid, file, next);
|
||||
uploadsController.upload(req, res, function(uploadedFile, next) {
|
||||
file.isFileTypeAllowed(uploadedFile.path, file.allowedExtensions(), function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (uploadedFile.type.match(/image./)) {
|
||||
uploadImage(req.user.uid, uploadedFile, next);
|
||||
} else {
|
||||
uploadFile(req.user.uid, uploadedFile, next);
|
||||
}
|
||||
});
|
||||
}, next);
|
||||
};
|
||||
|
||||
@@ -57,18 +64,24 @@ uploadsController.uploadThumb = function(req, res, next) {
|
||||
return next(new Error('[[error:topic-thumbnails-are-disabled]]'));
|
||||
}
|
||||
|
||||
uploadsController.upload(req, res, function(file, next) {
|
||||
if(file.type.match(/image./)) {
|
||||
var size = meta.config.topicThumbSize || 120;
|
||||
image.resizeImage(file.path, path.extname(file.name), size, size, function(err) {
|
||||
uploadsController.upload(req, res, function(uploadedFile, next) {
|
||||
file.isFileTypeAllowed(uploadedFile.path, file.allowedExtensions(), function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
uploadImage(req.user.uid, file, next);
|
||||
|
||||
if (uploadedFile.type.match(/image./)) {
|
||||
var size = meta.config.topicThumbSize || 120;
|
||||
image.resizeImage(uploadedFile.path, path.extname(uploadedFile.name), size, size, function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
uploadImage(req.user.uid, uploadedFile, next);
|
||||
});
|
||||
} else {
|
||||
next(new Error('[[error:invalid-file]]'));
|
||||
}
|
||||
});
|
||||
}, next);
|
||||
};
|
||||
|
||||
@@ -88,32 +101,32 @@ function uploadImage(uid, image, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
function uploadFile(uid, file, callback) {
|
||||
function uploadFile(uid, uploadedFile, callback) {
|
||||
if (plugins.hasListeners('filter:uploadFile')) {
|
||||
return plugins.fireHook('filter:uploadFile', {file: file, uid: uid}, callback);
|
||||
return plugins.fireHook('filter:uploadFile', {file: uploadedFile, uid: uid}, callback);
|
||||
}
|
||||
|
||||
if (parseInt(meta.config.allowFileUploads, 10) !== 1) {
|
||||
return callback(new Error('[[error:uploads-are-disabled]]'));
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
if (!uploadedFile) {
|
||||
return callback(new Error('[[error:invalid-file]]'));
|
||||
}
|
||||
|
||||
if (file.size > parseInt(meta.config.maximumFileSize, 10) * 1024) {
|
||||
if (uploadedFile.size > parseInt(meta.config.maximumFileSize, 10) * 1024) {
|
||||
return callback(new Error('[[error:file-too-big, ' + meta.config.maximumFileSize + ']]'));
|
||||
}
|
||||
|
||||
var filename = 'upload-' + utils.generateUUID() + path.extname(file.name);
|
||||
require('../file').saveFileToLocal(filename, 'files', file.path, function(err, upload) {
|
||||
var filename = 'upload-' + utils.generateUUID() + path.extname(uploadedFile.name);
|
||||
file.saveFileToLocal(filename, 'files', uploadedFile.path, function(err, upload) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
url: upload.url,
|
||||
name: file.name
|
||||
name: uploadedFile.name
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
43
src/file.js
43
src/file.js
@@ -3,7 +3,12 @@
|
||||
var fs = require('fs'),
|
||||
nconf = require('nconf'),
|
||||
path = require('path'),
|
||||
winston = require('winston');
|
||||
winston = require('winston'),
|
||||
mmmagic = require('mmmagic'),
|
||||
Magic = mmmagic.Magic,
|
||||
mime = require('mime'),
|
||||
|
||||
meta= require('./meta');
|
||||
|
||||
var file = {};
|
||||
|
||||
@@ -11,7 +16,7 @@ file.saveFileToLocal = function(filename, folder, tempPath, callback) {
|
||||
|
||||
var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), folder, filename);
|
||||
|
||||
winston.info('Saving file '+ filename +' to : ' + uploadPath);
|
||||
winston.verbose('Saving file '+ filename +' to : ' + uploadPath);
|
||||
|
||||
var is = fs.createReadStream(tempPath);
|
||||
var os = fs.createWriteStream(uploadPath);
|
||||
@@ -30,4 +35,38 @@ file.saveFileToLocal = function(filename, folder, tempPath, callback) {
|
||||
is.pipe(os);
|
||||
};
|
||||
|
||||
file.isFileTypeAllowed = function(path, allowedExtensions, callback) {
|
||||
if (!Array.isArray(allowedExtensions) || !allowedExtensions.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
allowedExtensions = allowedExtensions.filter(Boolean).map(function(extension) {
|
||||
return extension.trim();
|
||||
});
|
||||
|
||||
var magic = new Magic(mmmagic.MAGIC_MIME_TYPE);
|
||||
magic.detectFile(path, function(err, mimeType) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var uploadedFileExtension = mime.extension(mimeType);
|
||||
|
||||
if (allowedExtensions.indexOf(uploadedFileExtension) === -1) {
|
||||
return callback(new Error('[[error:invalid-file-type, ' + allowedExtensions.join('-') + ']]'));
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
file.allowedExtensions = function() {
|
||||
var allowedExtensions = (meta.config.allowedFileExtensions || '').trim();
|
||||
if (!allowedExtensions) {
|
||||
return [];
|
||||
}
|
||||
allowedExtensions = allowedExtensions.split(',');
|
||||
return allowedExtensions;
|
||||
};
|
||||
|
||||
module.exports = file;
|
||||
@@ -119,7 +119,10 @@
|
||||
<input type="checkbox" data-field="allowTopicsThumbnail"> <strong>Allow users to upload topic thumbnails</strong>
|
||||
</label>
|
||||
</div>
|
||||
<strong>Topic Thumb Size</strong><br /> <input type="text" class="form-control" value="120" data-field="topicThumbSize">
|
||||
<strong>Topic Thumb Size</strong><br /> <input type="text" class="form-control" value="120" data-field="topicThumbSize"> <br />
|
||||
|
||||
<strong>Allowed file types, (ie png, pdf, zip). Leave empty to allow all.</strong><br /> <input type="text" class="form-control" value="" data-field="allowedFileExtensions"><br />
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user