From 01de67b9a4fcdf01102ccc3cb7dc24beebf6c7ea Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 3 Jan 2018 11:10:40 +0100 Subject: Add avatar max size limit --- server/controllers/api/config.ts | 15 ++++++++++++++- server/helpers/custom-validators/activitypub/actor.ts | 4 ++-- server/helpers/custom-validators/activitypub/misc.ts | 2 +- server/initializers/constants.ts | 12 ++++++------ server/middlewares/validators/users.ts | 11 ++++++++++- server/models/activitypub/actor.ts | 16 ++++++++-------- server/models/server/server.ts | 2 +- server/tests/api/check-params/users.ts | 8 ++++++++ server/tests/api/fixtures/avatar-big.png | Bin 0 -> 146585 bytes 9 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 server/tests/api/fixtures/avatar-big.png (limited to 'server') diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 2f1132904..35c89835b 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -1,7 +1,7 @@ import * as express from 'express' import { isSignupAllowed } from '../../helpers/utils' -import { CONFIG } from '../../initializers' +import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' import { asyncMiddleware } from '../../middlewares' import { ServerConfig } from '../../../shared' @@ -24,6 +24,19 @@ async function getConfig (req: express.Request, res: express.Response, next: exp }, transcoding: { enabledResolutions + }, + avatar: { + file: { + size: { + max: CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max + }, + extensions: CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME + } + }, + video: { + file: { + extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME + } } } diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts index 630bace30..700e06007 100644 --- a/server/helpers/custom-validators/activitypub/actor.ts +++ b/server/helpers/custom-validators/activitypub/actor.ts @@ -24,7 +24,7 @@ function isActorPublicKeyValid (publicKey: string) { typeof publicKey === 'string' && publicKey.startsWith('-----BEGIN PUBLIC KEY-----') && publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 && - validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY) + validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY) } const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+') @@ -42,7 +42,7 @@ function isActorPrivateKeyValid (privateKey: string) { privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') && // Sometimes there is a \n at the end, so just assert the string contains the end mark privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 && - validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY) + validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY) } function isRemoteActorValid (remoteActor: any) { diff --git a/server/helpers/custom-validators/activitypub/misc.ts b/server/helpers/custom-validators/activitypub/misc.ts index aa6ffc9bd..75d308e9d 100644 --- a/server/helpers/custom-validators/activitypub/misc.ts +++ b/server/helpers/custom-validators/activitypub/misc.ts @@ -17,7 +17,7 @@ function isActivityPubUrlValid (url: string) { isURLOptions.require_tld = false } - return exists(url) && validator.isURL('' + url, isURLOptions) && validator.isLength('' + url, CONSTRAINTS_FIELDS.ACTOR.URL) + return exists(url) && validator.isURL('' + url, isURLOptions) && validator.isLength('' + url, CONSTRAINTS_FIELDS.ACTORS.URL) } function isBaseActivityValid (activity: any, type: string) { diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 31bb6c981..aefb91537 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -133,9 +133,6 @@ const CONFIG = { } } -const AVATARS_DIR = { - ACCOUNT: join(CONFIG.STORAGE.AVATARS_DIR, 'account') -} // --------------------------------------------------------------------------- const CONSTRAINTS_FIELDS = { @@ -169,12 +166,15 @@ const CONSTRAINTS_FIELDS = { FILE_SIZE: { min: 10 }, URL: { min: 3, max: 2000 } // Length }, - ACTOR: { + ACTORS: { PUBLIC_KEY: { min: 10, max: 5000 }, // Length PRIVATE_KEY: { min: 10, max: 5000 }, // Length URL: { min: 3, max: 2000 }, // Length AVATAR: { - EXTNAME: [ '.png', '.jpeg', '.jpg' ] + EXTNAME: [ '.png', '.jpeg', '.jpg' ], + FILE_SIZE: { + max: 2 * 1024 * 1024 // 2MB + } } }, VIDEO_EVENTS: { @@ -345,6 +345,7 @@ if (isTestInstance() === true) { REMOTE_SCHEME.WS = 'ws' STATIC_MAX_AGE = '0' ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 + CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB } CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT) @@ -372,7 +373,6 @@ export { PREVIEWS_SIZE, REMOTE_SCHEME, FOLLOW_STATES, - AVATARS_DIR, SERVER_ACTOR_NAME, PRIVATE_RSA_KEY_SIZE, SORTABLE_COLUMNS, diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 7c77e9a39..7de3e442c 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts @@ -12,6 +12,7 @@ import { isSignupAllowed } from '../../helpers/utils' import { CONSTRAINTS_FIELDS } from '../../initializers' import { UserModel } from '../../models/account/user' import { areValidationErrors } from './utils' +import Multer = require('multer') const usersAddValidator = [ body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), @@ -100,7 +101,7 @@ const usersUpdateMeValidator = [ const usersUpdateMyAvatarValidator = [ body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( 'This file is not supported. Please, make sure it is of the following type : ' - + CONSTRAINTS_FIELDS.ACTOR.AVATAR.EXTNAME.join(', ') + + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') ), (req: express.Request, res: express.Response, next: express.NextFunction) => { @@ -108,6 +109,14 @@ const usersUpdateMyAvatarValidator = [ if (areValidationErrors(req, res)) return + const imageFile = req.files['avatarfile'][0] as Express.Multer.File + if (imageFile.size > CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max) { + res.status(400) + .send({ error: `The size of the avatar is too big (>${CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max}).` }) + .end() + return + } + return next() } ] diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index a12f3ec9e..ff5ab2e32 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts @@ -87,17 +87,17 @@ export class ActorModel extends Model { @AllowNull(false) @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) url: string @AllowNull(true) @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY.max)) publicKey: string @AllowNull(true) @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY.max)) privateKey: string @AllowNull(false) @@ -112,27 +112,27 @@ export class ActorModel extends Model { @AllowNull(false) @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) inboxUrl: string @AllowNull(false) @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) outboxUrl: string @AllowNull(false) @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) sharedInboxUrl: string @AllowNull(false) @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) followersUrl: string @AllowNull(false) @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url')) - @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) followingUrl: string @CreatedAt diff --git a/server/models/server/server.ts b/server/models/server/server.ts index d35aa0ca4..122e5f74f 100644 --- a/server/models/server/server.ts +++ b/server/models/server/server.ts @@ -27,7 +27,7 @@ export class ServerModel extends Model { @AllowNull(false) @Default(SERVERS_SCORE.BASE) @IsInt - @Max(SERVERS_SCORE.MAX) + @Max(SERVERS_SCORE.max) @Column score: number diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 33d92ac24..14fcf8703 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts @@ -276,6 +276,14 @@ describe('Test users API validators', function () { await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) }) + it('Should fail with a big file', async function () { + const fields = {} + const attaches = { + 'avatarfile': join(__dirname, '..', 'fixtures', 'avatar-big.png') + } + await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) + }) + it('Should succeed with the correct params', async function () { const fields = {} const attaches = { diff --git a/server/tests/api/fixtures/avatar-big.png b/server/tests/api/fixtures/avatar-big.png new file mode 100644 index 000000000..e593e40da Binary files /dev/null and b/server/tests/api/fixtures/avatar-big.png differ -- cgit v1.2.3