diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index 7fa2026823..027e328037 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -239,25 +239,18 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' if (!url) { return false; } - socket.emit('user.uploadProfileImageFromUrl', { - uid: ajaxify.data.uid, - url: url, - }, function (err, url) { - if (err) { - return app.alertError(err); - } - uploadModal.modal('hide'); + uploadModal.modal('hide'); + + pictureCropper.handleImageCrop({ + url: url, + socketMethod: 'user.uploadCroppedPicture', + aspectRatio: '1 / 1', + allowSkippingCrop: false, + paramName: 'uid', + paramValue: ajaxify.data.theirid, + }, onUploadComplete); - pictureCropper.handleImageCrop({ - url: url, - socketMethod: 'user.uploadCroppedPicture', - aspectRatio: '1 / 1', - allowSkippingCrop: false, - paramName: 'uid', - paramValue: ajaxify.data.theirid, - }, onUploadComplete); - }); return false; }); }); diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 61f4cad452..b5bd4cf3a5 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -148,7 +148,10 @@ editController.uploadPicture = function (req, res, next) { return helpers.notAllowed(req, res); } - user.uploadPicture(updateUid, userPhoto, next); + user.uploadCroppedPicture({ + uid: updateUid, + file: userPhoto, + }, next); }, ], function (err, image) { file.delete(userPhoto.path); diff --git a/src/socket.io/user/picture.js b/src/socket.io/user/picture.js index 682cd59239..8f8c0577c3 100644 --- a/src/socket.io/user/picture.js +++ b/src/socket.io/user/picture.js @@ -49,23 +49,6 @@ module.exports = function (SocketUser) { ], callback); }; - SocketUser.uploadProfileImageFromUrl = function (socket, data, callback) { - if (!socket.uid || !data.url || !data.uid) { - return callback(new Error('[[error:invalid-data]]')); - } - async.waterfall([ - function (next) { - user.isAdminOrSelf(socket.uid, data.uid, next); - }, - function (next) { - user.uploadFromUrl(data.uid, data.url, next); - }, - function (uploadedImage, next) { - next(null, uploadedImage ? uploadedImage.url : null); - }, - ], callback); - }; - SocketUser.removeUploadedPicture = function (socket, data, callback) { if (!socket.uid || !data || !data.uid) { return callback(new Error('[[error:invalid-data]]')); diff --git a/src/user/picture.js b/src/user/picture.js index 271bed47fc..d1a4dac7b0 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -1,8 +1,6 @@ 'use strict'; var async = require('async'); -var request = require('request'); -var mime = require('mime'); var winston = require('winston'); var plugins = require('../plugins'); @@ -12,52 +10,6 @@ var meta = require('../meta'); var db = require('../database'); module.exports = function (User) { - User.uploadPicture = function (uid, picture, callback) { - User.uploadCroppedPicture({ uid: uid, file: picture }, callback); - }; - - User.uploadFromUrl = function (uid, url, callback) { - if (!plugins.hasListeners('filter:uploadImage')) { - return callback(new Error('[[error:no-plugin]]')); - } - - async.waterfall([ - function (next) { - request.head(url, function (err, res, body) { - if (err) { - return setTimeout(next.bind(null, new Error('[[error:invalid-url]]')), err.message === 'Parse Error' ? 1000 : 0); - } - next(null, res, body); - }); - }, - function (res, body, next) { - var uploadSize = parseInt(meta.config.maximumProfileImageSize, 10) || 256; - var size = res.headers['content-length']; - var type = res.headers['content-type']; - var extension = mime.getExtension(type); - - if (['png', 'jpeg', 'jpg', 'gif'].indexOf(extension) === -1) { - return callback(new Error('[[error:invalid-image-extension]]')); - } - - if (size > uploadSize * 1024) { - return callback(new Error('[[error:file-too-big, ' + uploadSize + ']]')); - } - - plugins.fireHook('filter:uploadImage', { - uid: uid, - image: { - url: url, - name: '', - }, - }, next); - }, - function (image, next) { - next(null, image); - }, - ], callback); - }; - User.updateCoverPosition = function (uid, position, callback) { // Reject anything that isn't two percentages if (!/^[\d.]+%\s[\d.]+%$/.test(position)) { diff --git a/test/user.js b/test/user.js index 528774979a..9a098f4708 100644 --- a/test/user.js +++ b/test/user.js @@ -776,7 +776,10 @@ describe('User', function () { name: 'test_copy.png', type: 'image/png', }; - User.uploadPicture(uid, picture, function (err, uploadedPicture) { + User.uploadCroppedPicture({ + uid: uid, + file: picture, + }, function (err, uploadedPicture) { assert.ifError(err); assert.equal(uploadedPicture.url, '/assets/uploads/profile/' + uid + '-profileavatar.png'); assert.equal(uploadedPicture.path, path.join(nconf.get('base_dir'), 'public', 'uploads', 'profile', uid + '-profileavatar.png')); @@ -794,7 +797,10 @@ describe('User', function () { name: 'test.png', type: 'image/png', }; - User.uploadPicture(uid, picture, function (err) { + User.uploadCroppedPicture({ + uid: uid, + file: picture, + }, function (err) { assert.equal(err.message, '[[error:profile-image-uploads-disabled]]'); done(); }); @@ -808,7 +814,11 @@ describe('User', function () { name: 'test.png', type: 'image/png', }; - User.uploadPicture(uid, picture, function (err) { + + User.uploadCroppedPicture({ + uid: uid, + file: picture, + }, function (err) { assert.equal(err.message, '[[error:file-too-big, 256]]'); done(); }); @@ -820,89 +830,48 @@ describe('User', function () { size: 7189, name: 'test', }; - User.uploadPicture(uid, picture, function (err) { + User.uploadCroppedPicture({ + uid: uid, + file: picture, + }, function (err) { assert.equal(err.message, '[[error:invalid-image]]'); done(); }); }); - it('should return error if no plugins listening for filter:uploadImage when uploading from url', function (done) { - var url = nconf.get('url') + '/assets/logo.png'; - User.uploadFromUrl(uid, url, function (err) { - assert.equal(err.message, '[[error:no-plugin]]'); - done(); - }); - }); - - it('should return error if the extension is invalid when uploading from url', function (done) { - var url = nconf.get('url') + '/favicon.ico'; - - function filterMethod(data, callback) { - callback(null, data); - } - - plugins.registerHook('test-plugin', { hook: 'filter:uploadImage', method: filterMethod }); - - User.uploadFromUrl(uid, url, function (err) { - assert.equal(err.message, '[[error:invalid-image-extension]]'); - done(); - }); - }); - - it('should return error if url is invalid when uploading from url', function (done) { - function filterMethod(data, callback) { - callback(null, data); - } - - plugins.registerHook('test-plugin', { hook: 'filter:uploadImage', method: filterMethod }); - - User.uploadFromUrl(uid, 'http://scanme.nmap.org:2234/index.html', function (err) { - assert.equal(err.message, '[[error:invalid-url]]'); - done(); - }); - }); - - - it('should return error if the file is too big when uploading from url', function (done) { - var url = nconf.get('url') + '/assets/logo.png'; - meta.config.maximumProfileImageSize = 1; - - function filterMethod(data, callback) { - callback(null, data); - } - - plugins.registerHook('test-plugin', { hook: 'filter:uploadImage', method: filterMethod }); - - User.uploadFromUrl(uid, url, function (err) { - assert.equal(err.message, '[[error:file-too-big, ' + meta.config.maximumProfileImageSize + ']]'); - done(); + describe('user.uploadCroppedPicture', function () { + var goodImage = 'data:image/gif;base64,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'; + var badImage = 'data:audio/mp3;base64,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'; + it('should error if both file and imageData are missing', function (done) { + User.uploadCroppedPicture({}, function (err) { + assert.equal('[[error:invalid-data]]', err.message); + done(); + }); }); - }); - it('should error with invalid data', function (done) { - var socketUser = require('../src/socket.io/user'); + it('should error if file size is too big', function (done) { + var temp = meta.config.maximumProfileImageSize; + meta.config.maximumProfileImageSize = 1; + User.uploadCroppedPicture({ + uid: 1, + imageData: goodImage, + }, function (err) { + assert.equal('[[error:file-too-big, 1]]', err.message); - socketUser.uploadProfileImageFromUrl({ uid: uid }, { uid: uid, url: '' }, function (err) { - assert.equal(err.message, '[[error:invalid-data]]'); - done(); + // Restore old value + meta.config.maximumProfileImageSize = temp; + done(); + }); }); - }); - - it('should upload picture when uploading from url', function (done) { - var socketUser = require('../src/socket.io/user'); - var url = nconf.get('url') + '/assets/logo.png'; - meta.config.maximumProfileImageSize = ''; - - function filterMethod(data, callback) { - callback(null, { url: url }); - } - - plugins.registerHook('test-plugin', { hook: 'filter:uploadImage', method: filterMethod }); - socketUser.uploadProfileImageFromUrl({ uid: uid }, { uid: uid, url: url }, function (err, uploadedPicture) { - assert.ifError(err); - assert.equal(uploadedPicture, url); - done(); + it('should not allow image data with bad MIME type to be passed in', function (done) { + User.uploadCroppedPicture({ + uid: 1, + imageData: badImage, + }, function (err) { + assert.equal('[[error:invalid-image]]', err.message); + done(); + }); }); });