diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/config.ts | 15 | ||||
-rw-r--r-- | server/helpers/custom-validators/activitypub/actor.ts | 4 | ||||
-rw-r--r-- | server/helpers/custom-validators/activitypub/misc.ts | 2 | ||||
-rw-r--r-- | server/initializers/constants.ts | 12 | ||||
-rw-r--r-- | server/middlewares/validators/users.ts | 11 | ||||
-rw-r--r-- | server/models/activitypub/actor.ts | 16 | ||||
-rw-r--r-- | server/models/server/server.ts | 2 | ||||
-rw-r--r-- | server/tests/api/check-params/users.ts | 8 | ||||
-rw-r--r-- | server/tests/api/fixtures/avatar-big.png | bin | 0 -> 146585 bytes |
9 files changed, 50 insertions, 20 deletions
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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { isSignupAllowed } from '../../helpers/utils' | 2 | import { isSignupAllowed } from '../../helpers/utils' |
3 | 3 | ||
4 | import { CONFIG } from '../../initializers' | 4 | import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' |
5 | import { asyncMiddleware } from '../../middlewares' | 5 | import { asyncMiddleware } from '../../middlewares' |
6 | import { ServerConfig } from '../../../shared' | 6 | import { ServerConfig } from '../../../shared' |
7 | 7 | ||
@@ -24,6 +24,19 @@ async function getConfig (req: express.Request, res: express.Response, next: exp | |||
24 | }, | 24 | }, |
25 | transcoding: { | 25 | transcoding: { |
26 | enabledResolutions | 26 | enabledResolutions |
27 | }, | ||
28 | avatar: { | ||
29 | file: { | ||
30 | size: { | ||
31 | max: CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max | ||
32 | }, | ||
33 | extensions: CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME | ||
34 | } | ||
35 | }, | ||
36 | video: { | ||
37 | file: { | ||
38 | extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME | ||
39 | } | ||
27 | } | 40 | } |
28 | } | 41 | } |
29 | 42 | ||
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) { | |||
24 | typeof publicKey === 'string' && | 24 | typeof publicKey === 'string' && |
25 | publicKey.startsWith('-----BEGIN PUBLIC KEY-----') && | 25 | publicKey.startsWith('-----BEGIN PUBLIC KEY-----') && |
26 | publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 && | 26 | publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 && |
27 | validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY) | 27 | validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY) |
28 | } | 28 | } |
29 | 29 | ||
30 | const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+') | 30 | const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+') |
@@ -42,7 +42,7 @@ function isActorPrivateKeyValid (privateKey: string) { | |||
42 | privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') && | 42 | privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') && |
43 | // Sometimes there is a \n at the end, so just assert the string contains the end mark | 43 | // Sometimes there is a \n at the end, so just assert the string contains the end mark |
44 | privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 && | 44 | privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 && |
45 | validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY) | 45 | validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY) |
46 | } | 46 | } |
47 | 47 | ||
48 | function isRemoteActorValid (remoteActor: any) { | 48 | 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) { | |||
17 | isURLOptions.require_tld = false | 17 | isURLOptions.require_tld = false |
18 | } | 18 | } |
19 | 19 | ||
20 | return exists(url) && validator.isURL('' + url, isURLOptions) && validator.isLength('' + url, CONSTRAINTS_FIELDS.ACTOR.URL) | 20 | return exists(url) && validator.isURL('' + url, isURLOptions) && validator.isLength('' + url, CONSTRAINTS_FIELDS.ACTORS.URL) |
21 | } | 21 | } |
22 | 22 | ||
23 | function isBaseActivityValid (activity: any, type: string) { | 23 | 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 = { | |||
133 | } | 133 | } |
134 | } | 134 | } |
135 | 135 | ||
136 | const AVATARS_DIR = { | ||
137 | ACCOUNT: join(CONFIG.STORAGE.AVATARS_DIR, 'account') | ||
138 | } | ||
139 | // --------------------------------------------------------------------------- | 136 | // --------------------------------------------------------------------------- |
140 | 137 | ||
141 | const CONSTRAINTS_FIELDS = { | 138 | const CONSTRAINTS_FIELDS = { |
@@ -169,12 +166,15 @@ const CONSTRAINTS_FIELDS = { | |||
169 | FILE_SIZE: { min: 10 }, | 166 | FILE_SIZE: { min: 10 }, |
170 | URL: { min: 3, max: 2000 } // Length | 167 | URL: { min: 3, max: 2000 } // Length |
171 | }, | 168 | }, |
172 | ACTOR: { | 169 | ACTORS: { |
173 | PUBLIC_KEY: { min: 10, max: 5000 }, // Length | 170 | PUBLIC_KEY: { min: 10, max: 5000 }, // Length |
174 | PRIVATE_KEY: { min: 10, max: 5000 }, // Length | 171 | PRIVATE_KEY: { min: 10, max: 5000 }, // Length |
175 | URL: { min: 3, max: 2000 }, // Length | 172 | URL: { min: 3, max: 2000 }, // Length |
176 | AVATAR: { | 173 | AVATAR: { |
177 | EXTNAME: [ '.png', '.jpeg', '.jpg' ] | 174 | EXTNAME: [ '.png', '.jpeg', '.jpg' ], |
175 | FILE_SIZE: { | ||
176 | max: 2 * 1024 * 1024 // 2MB | ||
177 | } | ||
178 | } | 178 | } |
179 | }, | 179 | }, |
180 | VIDEO_EVENTS: { | 180 | VIDEO_EVENTS: { |
@@ -345,6 +345,7 @@ if (isTestInstance() === true) { | |||
345 | REMOTE_SCHEME.WS = 'ws' | 345 | REMOTE_SCHEME.WS = 'ws' |
346 | STATIC_MAX_AGE = '0' | 346 | STATIC_MAX_AGE = '0' |
347 | ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 | 347 | ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 |
348 | CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB | ||
348 | } | 349 | } |
349 | 350 | ||
350 | CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT) | 351 | CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT) |
@@ -372,7 +373,6 @@ export { | |||
372 | PREVIEWS_SIZE, | 373 | PREVIEWS_SIZE, |
373 | REMOTE_SCHEME, | 374 | REMOTE_SCHEME, |
374 | FOLLOW_STATES, | 375 | FOLLOW_STATES, |
375 | AVATARS_DIR, | ||
376 | SERVER_ACTOR_NAME, | 376 | SERVER_ACTOR_NAME, |
377 | PRIVATE_RSA_KEY_SIZE, | 377 | PRIVATE_RSA_KEY_SIZE, |
378 | SORTABLE_COLUMNS, | 378 | 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' | |||
12 | import { CONSTRAINTS_FIELDS } from '../../initializers' | 12 | import { CONSTRAINTS_FIELDS } from '../../initializers' |
13 | import { UserModel } from '../../models/account/user' | 13 | import { UserModel } from '../../models/account/user' |
14 | import { areValidationErrors } from './utils' | 14 | import { areValidationErrors } from './utils' |
15 | import Multer = require('multer') | ||
15 | 16 | ||
16 | const usersAddValidator = [ | 17 | const usersAddValidator = [ |
17 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), | 18 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), |
@@ -100,7 +101,7 @@ const usersUpdateMeValidator = [ | |||
100 | const usersUpdateMyAvatarValidator = [ | 101 | const usersUpdateMyAvatarValidator = [ |
101 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( | 102 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( |
102 | 'This file is not supported. Please, make sure it is of the following type : ' | 103 | 'This file is not supported. Please, make sure it is of the following type : ' |
103 | + CONSTRAINTS_FIELDS.ACTOR.AVATAR.EXTNAME.join(', ') | 104 | + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') |
104 | ), | 105 | ), |
105 | 106 | ||
106 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 107 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
@@ -108,6 +109,14 @@ const usersUpdateMyAvatarValidator = [ | |||
108 | 109 | ||
109 | if (areValidationErrors(req, res)) return | 110 | if (areValidationErrors(req, res)) return |
110 | 111 | ||
112 | const imageFile = req.files['avatarfile'][0] as Express.Multer.File | ||
113 | if (imageFile.size > CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max) { | ||
114 | res.status(400) | ||
115 | .send({ error: `The size of the avatar is too big (>${CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max}).` }) | ||
116 | .end() | ||
117 | return | ||
118 | } | ||
119 | |||
111 | return next() | 120 | return next() |
112 | } | 121 | } |
113 | ] | 122 | ] |
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<ActorModel> { | |||
87 | 87 | ||
88 | @AllowNull(false) | 88 | @AllowNull(false) |
89 | @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) | 89 | @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) |
90 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) | 90 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) |
91 | url: string | 91 | url: string |
92 | 92 | ||
93 | @AllowNull(true) | 93 | @AllowNull(true) |
94 | @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key')) | 94 | @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key')) |
95 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY.max)) | 95 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY.max)) |
96 | publicKey: string | 96 | publicKey: string |
97 | 97 | ||
98 | @AllowNull(true) | 98 | @AllowNull(true) |
99 | @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key')) | 99 | @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key')) |
100 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY.max)) | 100 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY.max)) |
101 | privateKey: string | 101 | privateKey: string |
102 | 102 | ||
103 | @AllowNull(false) | 103 | @AllowNull(false) |
@@ -112,27 +112,27 @@ export class ActorModel extends Model<ActorModel> { | |||
112 | 112 | ||
113 | @AllowNull(false) | 113 | @AllowNull(false) |
114 | @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url')) | 114 | @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url')) |
115 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) | 115 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) |
116 | inboxUrl: string | 116 | inboxUrl: string |
117 | 117 | ||
118 | @AllowNull(false) | 118 | @AllowNull(false) |
119 | @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url')) | 119 | @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url')) |
120 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) | 120 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) |
121 | outboxUrl: string | 121 | outboxUrl: string |
122 | 122 | ||
123 | @AllowNull(false) | 123 | @AllowNull(false) |
124 | @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url')) | 124 | @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url')) |
125 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) | 125 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) |
126 | sharedInboxUrl: string | 126 | sharedInboxUrl: string |
127 | 127 | ||
128 | @AllowNull(false) | 128 | @AllowNull(false) |
129 | @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url')) | 129 | @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url')) |
130 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) | 130 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) |
131 | followersUrl: string | 131 | followersUrl: string |
132 | 132 | ||
133 | @AllowNull(false) | 133 | @AllowNull(false) |
134 | @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url')) | 134 | @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url')) |
135 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) | 135 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max)) |
136 | followingUrl: string | 136 | followingUrl: string |
137 | 137 | ||
138 | @CreatedAt | 138 | @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<ServerModel> { | |||
27 | @AllowNull(false) | 27 | @AllowNull(false) |
28 | @Default(SERVERS_SCORE.BASE) | 28 | @Default(SERVERS_SCORE.BASE) |
29 | @IsInt | 29 | @IsInt |
30 | @Max(SERVERS_SCORE.MAX) | 30 | @Max(SERVERS_SCORE.max) |
31 | @Column | 31 | @Column |
32 | score: number | 32 | score: number |
33 | 33 | ||
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 () { | |||
276 | await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) | 276 | await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) |
277 | }) | 277 | }) |
278 | 278 | ||
279 | it('Should fail with a big file', async function () { | ||
280 | const fields = {} | ||
281 | const attaches = { | ||
282 | 'avatarfile': join(__dirname, '..', 'fixtures', 'avatar-big.png') | ||
283 | } | ||
284 | await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) | ||
285 | }) | ||
286 | |||
279 | it('Should succeed with the correct params', async function () { | 287 | it('Should succeed with the correct params', async function () { |
280 | const fields = {} | 288 | const fields = {} |
281 | const attaches = { | 289 | 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 --- /dev/null +++ b/server/tests/api/fixtures/avatar-big.png | |||
Binary files differ | |||