v1.18.x
barisusakli 8 years ago
parent 7d8477289d
commit ef90702049

@ -10,6 +10,7 @@ var mime = require('mime');
var winston = require('winston');
var db = require('../database');
var image = require('../image');
var uploadsController = require('../controllers/uploads');
module.exports = function (Groups) {
@ -37,7 +38,7 @@ module.exports = function (Groups) {
if (tempPath) {
return next(null, tempPath);
}
writeImageDataToFile(data.imageData, next);
image.writeImageDataToTempFile(data.imageData, next);
},
function (_tempPath, next) {
tempPath = _tempPath;
@ -97,24 +98,6 @@ module.exports = function (Groups) {
});
}
function writeImageDataToFile(imageData, callback) {
// Calculate md5sum of image
// This is required because user data can be private
var md5sum = crypto.createHash('md5');
md5sum.update(imageData);
md5sum = md5sum.digest('hex');
// Save image
var tempPath = path.join(nconf.get('upload_path'), md5sum + '.png');
var buffer = new Buffer(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
fs.writeFile(tempPath, buffer, {
encoding: 'base64'
}, function (err) {
callback(err, tempPath);
});
}
Groups.removeCover = function (data, callback) {
db.deleteObjectFields('group:' + data.groupName, ['cover:url', 'cover:thumb:url', 'cover:position'], callback);
};

@ -1,8 +1,13 @@
'use strict';
var os = require('os');
var fs = require('fs');
var path = require('path');
var Jimp = require('jimp');
var async = require('async');
var crypto = require('crypto');
var file = require('./file');
var plugins = require('./plugins');
var image = module.exports;
@ -65,9 +70,6 @@ image.resizeImage = function (data, callback) {
}
},
function (image, next) {
if (data.write === false) {
return next();
}
image.write(data.target || data.path, next);
}
], function (err) {
@ -83,7 +85,7 @@ image.normalise = function (path, extension, callback) {
path: path,
extension: extension
}, function (err) {
callback(err);
callback(err, path + '.png');
});
} else {
new Jimp(path, function (err, image) {
@ -91,7 +93,7 @@ image.normalise = function (path, extension, callback) {
return callback(err);
}
image.write(path + '.png', function (err) {
callback(err);
callback(err, path + '.png');
});
});
}
@ -116,3 +118,28 @@ image.convertImageToBase64 = function (path, callback) {
callback(err, data ? data.toString('base64') : null);
});
};
image.mimeFromBase64 = function (imageData) {
return imageData.slice(5, imageData.indexOf('base64') - 1);
};
image.extensionFromBase64 = function (imageData) {
return file.typeToExtension(image.mimeFromBase64(imageData));
};
image.writeImageDataToTempFile = function (imageData, callback) {
var filename = crypto.createHash('md5').update(imageData).digest('hex');
var type = image.mimeFromBase64(imageData);
var extension = file.typeToExtension(type);
var filepath = path.join(os.tmpdir(), filename + extension);
var buffer = new Buffer(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
fs.writeFile(filepath, buffer, {
encoding: 'base64'
}, function (err) {
callback(err, filepath);
});
};

@ -1,11 +1,8 @@
'use strict';
var async = require('async');
var path = require('path');
var fs = require('fs');
var os = require('os');
var nconf = require('nconf');
var crypto = require('crypto');
var winston = require('winston');
var request = require('request');
var mime = require('mime');
@ -19,78 +16,7 @@ var db = require('../database');
module.exports = function (User) {
User.uploadPicture = function (uid, picture, callback) {
var uploadSize = parseInt(meta.config.maximumProfileImageSize, 10) || 256;
var extension = path.extname(picture.name);
var updateUid = uid;
var imageDimension = parseInt(meta.config.profileImageDimension, 10) || 128;
var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1;
var keepAllVersions = parseInt(meta.config['profile:keepAllUserImages'], 10) === 1;
var uploadedImage;
if (parseInt(meta.config.allowProfileImageUploads) !== 1) {
return callback(new Error('[[error:profile-image-uploads-disabled]]'));
}
if (picture.size > uploadSize * 1024) {
return callback(new Error('[[error:file-too-big, ' + uploadSize + ']]'));
}
if (!extension) {
return callback(new Error('[[error:invalid-image-extension]]'));
}
async.waterfall([
function (next) {
if (plugins.hasListeners('filter:uploadImage')) {
return plugins.fireHook('filter:uploadImage', {
image: picture,
uid: updateUid
}, next);
}
var filename = updateUid + '-profileimg' + (keepAllVersions ? '-' + Date.now() : '') + (convertToPNG ? '.png' : extension);
async.waterfall([
function (next) {
file.isFileTypeAllowed(picture.path, next);
},
function (next) {
image.resizeImage({
path: picture.path,
extension: extension,
width: imageDimension,
height: imageDimension,
write: false,
}, next);
},
function (next) {
if (!convertToPNG) {
return next();
}
async.series([
async.apply(image.normalise, picture.path, extension),
async.apply(fs.rename, picture.path + '.png', picture.path)
], function (err) {
next(err);
});
},
function (next) {
file.saveFileToLocal(filename, 'profile', picture.path, next);
},
], next);
},
function (_image, next) {
uploadedImage = _image;
User.setUserFields(updateUid, {
uploadedpicture: uploadedImage.url,
picture: uploadedImage.url
}, next);
},
function (next) {
next(null, uploadedImage);
}
], callback);
User.uploadCroppedPicture({uid: uid, file: picture}, callback);
};
User.uploadFromUrl = function (uid, url, callback) {
@ -142,7 +68,7 @@ module.exports = function (User) {
User.updateCoverPicture = function (data, callback) {
var url;
var image = {
var picture = {
name: 'profileCover',
uid: data.uid
};
@ -167,12 +93,14 @@ module.exports = function (User) {
return setImmediate(next, null, data.file.path);
}
saveImageDataToTempFile(data.imageData, next);
image.writeImageDataToTempFile(data.imageData, next);
},
function (path, next) {
image.path = path;
picture.path = path;
uploadProfileOrCover('profilecover', image, data.imageData, next);
var extension = data.file ? file.typeToExtension(data.file.type) : image.extensionFromBase64(data.imageData);
var filename = generateProfileImageFilename(data.uid, 'profilecover', extension);
uploadProfileOrCover(filename, picture, next);
},
function (uploadData, next) {
url = uploadData.url;
@ -186,7 +114,7 @@ module.exports = function (User) {
}
}
], function (err) {
deleteFile(image.path);
deleteFile(picture.path);
callback(err, {
url: url
});
@ -195,75 +123,102 @@ module.exports = function (User) {
User.uploadCroppedPicture = function (data, callback) {
var url;
var image = {
name: 'profileAvatar',
uid: data.uid
};
if (parseInt(meta.config.allowProfileImageUploads) !== 1) {
return callback(new Error('[[error:profile-image-uploads-disabled]]'));
}
if (!data.imageData) {
if (!data.imageData && !data.file) {
return callback(new Error('[[error:invalid-data]]'));
}
var size = data.file ? data.file.size : data.imageData.length;
var uploadSize = parseInt(meta.config.maximumProfileImageSize, 10) || 256;
if (size > uploadSize * 1024) {
return callback(new Error('[[error:file-too-big, ' + meta.config.maximumProfileImageSize + ']]'));
}
var type = data.file ? data.file.type : image.mimeFromBase64(data.imageData);
var extension = file.typeToExtension(type);
if (!extension) {
return callback(new Error('[[error:invalid-image-extension]]'));
}
var uploadedImage;
var picture = {
name: 'profileAvatar',
uid: data.uid
};
async.waterfall([
function (next) {
var size = data.imageData.length;
var uploadSize = parseInt(meta.config.maximumProfileImageSize, 10) || 256;
if (size > uploadSize * 1024) {
return next(new Error('[[error:file-too-big, ' + meta.config.maximumProfileImageSize + ']]'));
if (data.file) {
return setImmediate(next, null, data.file.path);
}
saveImageDataToTempFile(data.imageData, next);
image.writeImageDataToTempFile(data.imageData, next);
},
function (path, next) {
image.path = path;
uploadProfileOrCover('profileavatar', image, data.imageData, next);
convertToPNG(path, extension, next);
},
function (uploadData, next) {
url = uploadData.url;
function (path, next) {
picture.path = path;
var imageDimension = parseInt(meta.config.profileImageDimension, 10) || 128;
image.resizeImage({
path: picture.path,
extension: extension,
width: imageDimension,
height: imageDimension
}, next);
},
function (next) {
var filename = generateProfileImageFilename(data.uid, 'profileavatar', extension);
uploadProfileOrCover(filename, picture, next);
},
function (_uploadedImage, next) {
uploadedImage = _uploadedImage;
User.setUserFields(data.uid, {
uploadedpicture: url,
picture: url
uploadedpicture: uploadedImage.url,
picture: uploadedImage.url
}, next);
}
], function (err) {
deleteFile(image.path);
callback(err, {
url: url
});
deleteFile(picture.path);
callback(err, uploadedImage);
});
};
function saveImageDataToTempFile(imageData, callback) {
var filename = crypto.createHash('md5').update(imageData).digest('hex');
var filepath = path.join(os.tmpdir(), filename);
var buffer = new Buffer(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
function convertToPNG(path, extension, callback) {
var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1;
if (!convertToPNG) {
return setImmediate(callback, null, path);
}
fs.writeFile(filepath, buffer, {
encoding: 'base64'
}, function (err) {
callback(err, filepath);
image.normalise(path, extension, function (err, newPath) {
if (err) {
return callback(err);
}
deleteFile(path);
callback(null, newPath);
});
}
function uploadProfileOrCover(type, image, imageData, callback) {
function uploadProfileOrCover(filename, image, callback) {
if (plugins.hasListeners('filter:uploadImage')) {
return plugins.fireHook('filter:uploadImage', {
image: image,
uid: image.uid
}, callback);
}
var filename = generateProfileImageFilename(image.uid, type, imageData);
saveFileToLocal(filename, image, callback);
}
function generateProfileImageFilename(uid, type, imageData) {
var extension = file.typeToExtension(imageData.slice(5, imageData.indexOf('base64') - 1));
function generateProfileImageFilename(uid, type, extension) {
var keepAllVersions = parseInt(meta.config['profile:keepAllUserImages'], 10) === 1;
var filename = uid + '-' + type + (keepAllVersions ? '-' + Date.now() : '') + (extension || '');
return filename;
var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1;
return uid + '-' + type + (keepAllVersions ? '-' + Date.now() : '') + (convertToPNG ? '.png' : extension);
}
function saveFileToLocal(filename, image, callback) {
@ -277,6 +232,7 @@ module.exports = function (User) {
function (upload, next) {
next(null, {
url: nconf.get('relative_path') + upload.url,
path: upload.path,
name: image.name
});
}

@ -0,0 +1,177 @@
<html>
<head>
<title>Excessive Load Warning</title>
<link href='https://fonts.googleapis.com/css?family=Ubuntu:400,500,700' rel='stylesheet' type='text/css'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
body {
background: #00A9EA;
color: white;
font-family: 'Ubuntu', sans-serif;
text-align: center;
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
}
h1 {
font-size: 250px;
color: #fff;
opacity: 0.5;
margin: 10px;
cursor: pointer;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
}
p {
font-size: 20px;
}
p strong {
font-size: 28px;
}
@media (max-width: 640px) {
h1 {
font-size: 125px;
}
p {
font-size: 16px;
}
p strong {
font-size: 20px;
}
}
.center {
position: relative;
top: 50%;
-webkit-transform: translateY(50%);
-ms-transform: translateY(50%);
transform: translateY(50%);
}
@-webkit-keyframes bounce {
0%, 20%, 53%, 80%, 100% {
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
40%, 43% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -30px, 0);
transform: translate3d(0, -30px, 0);
}
70% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -15px, 0);
transform: translate3d(0, -15px, 0);
}
90% {
-webkit-transform: translate3d(0,-4px,0);
transform: translate3d(0,-4px,0);
}
}
@keyframes bounce {
0%, 20%, 53%, 80%, 100% {
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
40%, 43% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -30px, 0);
transform: translate3d(0, -30px, 0);
}
70% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -15px, 0);
transform: translate3d(0, -15px, 0);
}
90% {
-webkit-transform: translate3d(0,-4px,0);
transform: translate3d(0,-4px,0);
}
}
.bounce {
-webkit-animation-name: bounce;
animation-name: bounce;
-webkit-transform-origin: center bottom;
-ms-transform-origin: center bottom;
transform-origin: center bottom;
}
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.animated.infinite {
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.animated.hinge {
-webkit-animation-duration: 2s;
animation-duration: 2s;
}
.hide {
display: none;
}
</style>
<script type="text/javascript">
window.onload = function() {
var count = 0,
bounce = document.getElementById('click-me');
bounce.onclick = function() {
count++;
bounce.className = '';
setTimeout(function() {
bounce.className = 'animated bounce';
}, 50);
if (count > 5) {
document.getElementById('hide').className = '';
}
};
}
</script>
</head>
<body>
<div class="wrapper">
<div class="center">
<h1 id="click-me" class="animated bounce">503</h1>
<p>
<strong>This forum is temporarily unavailable due to excessive load.</strong>
</p>
<p>
We shouldn't be down for long. Please check back shortly. Sorry for the inconvenience!
</p>
<p>
&nbsp;<small id="hide" class="hide">Alright. You can stop clicking... it's not going to make the site come back sooner!</small>
</p>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

@ -707,8 +707,8 @@ describe('Groups', function () {
describe('groups cover', function () {
var socketGroups = require('../src/socket.io/groups');
var regularUid;
var logoPath = path.join(__dirname, '../public/logo.png');
var imagePath = path.join(__dirname, '../public/groupcover.png');
var logoPath = path.join(__dirname, '../test/files/test.png');
var imagePath = path.join(__dirname, '../test/files/groupcover.png');
before(function (done) {
User.create({username: 'regularuser', password: '123456'}, function (err, uid) {
assert.ifError(err);

@ -67,18 +67,18 @@ describe('Upload Controllers', function () {
});
it('should upload a profile picture', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/user/regular/uploadpicture', path.join(__dirname, '../public/logo.png'), {}, jar, csrf_token, function (err, res, body) {
helpers.uploadFile(nconf.get('url') + '/api/user/regular/uploadpicture', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
assert.equal(body.length, 1);
assert.equal(body[0].url, '/assets/uploads/profile/' + regularUid + '-profileimg.png');
assert.equal(body[0].url, '/assets/uploads/profile/' + regularUid + '-profileavatar.png');
done();
});
});
it('should upload an image to a post', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../public/logo.png'), {cid: cid}, jar, csrf_token, function (err, res, body) {
helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), {cid: cid}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
@ -91,7 +91,7 @@ describe('Upload Controllers', function () {
it('should upload a file to a post', function (done) {
meta.config.allowFileUploads = 1;
helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../public/503.html'), {cid: cid}, jar, csrf_token, function (err, res, body) {
helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/503.html'), {cid: cid}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
@ -118,7 +118,7 @@ describe('Upload Controllers', function () {
});
it('should upload site logo', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/admin/uploadlogo', path.join(__dirname, '../public/logo.png'), {}, jar, csrf_token, function (err, res, body) {
helpers.uploadFile(nconf.get('url') + '/api/admin/uploadlogo', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
@ -128,7 +128,7 @@ describe('Upload Controllers', function () {
});
it('should upload category image', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/admin/category/uploadpicture', path.join(__dirname, '../public/logo.png'), {params: JSON.stringify({cid: cid})}, jar, csrf_token, function (err, res, body) {
helpers.uploadFile(nconf.get('url') + '/api/admin/category/uploadpicture', path.join(__dirname, '../test/files/test.png'), {params: JSON.stringify({cid: cid})}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
@ -138,7 +138,7 @@ describe('Upload Controllers', function () {
});
it('should upload favicon', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/admin/uploadfavicon', path.join(__dirname, '../public/favicon.ico'), {}, jar, csrf_token, function (err, res, body) {
helpers.uploadFile(nconf.get('url') + '/api/admin/uploadfavicon', path.join(__dirname, '../test/files/favicon.ico'), {}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
@ -148,7 +148,7 @@ describe('Upload Controllers', function () {
});
it('should upload touch icon', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/admin/uploadTouchIcon', path.join(__dirname, '../public/logo.png'), {}, jar, csrf_token, function (err, res, body) {
helpers.uploadFile(nconf.get('url') + '/api/admin/uploadTouchIcon', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));

@ -2,6 +2,7 @@
var assert = require('assert');
var async = require('async');
var path = require('path');
var nconf = require('nconf');
var request = require('request');
@ -510,27 +511,33 @@ describe('User', function () {
});
it('should upload profile picture', function (done) {
var path = require('path');
var picture = {
path: path.join(nconf.get('base_dir'), 'public', 'logo.png'),
size: 7189,
name: 'logo.png'
};
User.uploadPicture(uid, picture, function (err, uploadedPicture) {
assert.ifError(err);
assert.equal(uploadedPicture.url, '/assets/uploads/profile/' + uid + '-profileimg.png');
assert.equal(uploadedPicture.path, path.join(nconf.get('base_dir'), 'public', 'uploads', 'profile', uid + '-profileimg.png'));
done();
helpers.copyFile(
path.join(nconf.get('base_dir'), 'test/files/test.png'),
path.join(nconf.get('base_dir'), 'test/files/test_copy.png')
, function (err) {
assert.ifError(err);
var picture = {
path: path.join(nconf.get('base_dir'), 'test/files/test_copy.png'),
size: 7189,
name: 'test_copy.png',
type: 'image/png'
};
User.uploadPicture(uid, 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'));
done();
});
});
});
it('should return error if profile image uploads disabled', function (done) {
meta.config.allowProfileImageUploads = 0;
var path = require('path');
var picture = {
path: path.join(nconf.get('base_dir'), 'public', 'logo.png'),
path: path.join(nconf.get('base_dir'), 'test/files/test.png'),
size: 7189,
name: 'logo.png'
name: 'test.png',
type: 'image/png'
};
User.uploadPicture(uid, picture, function (err) {
assert.equal(err.message, '[[error:profile-image-uploads-disabled]]');
@ -540,11 +547,11 @@ describe('User', function () {
it('should return error if profile image is too big', function (done) {
meta.config.allowProfileImageUploads = 1;
var path = require('path');
var picture = {
path: path.join(nconf.get('base_dir'), 'public', 'logo.png'),
path: path.join(nconf.get('base_dir'), 'test/files/test.png'),
size: 265000,
name: 'logo.png'
name: 'test.png',
type: 'image/png'
};
User.uploadPicture(uid, picture, function (err) {
assert.equal(err.message, '[[error:file-too-big, 256]]');
@ -552,12 +559,11 @@ describe('User', function () {
});
});
it('should return error if profile image file has no extension', function (done) {
var path = require('path');
it('should return error if profile image has no mime type', function (done) {
var picture = {
path: path.join(nconf.get('base_dir'), 'public', 'logo.png'),
path: path.join(nconf.get('base_dir'), 'test/files/test.png'),
size: 7189,
name: 'logo'
name: 'test'
};
User.uploadPicture(uid, picture, function (err) {
assert.equal(err.message, '[[error:invalid-image-extension]]');

Loading…
Cancel
Save