diff options
-rw-r--r-- | client/src/app/+my-account/my-account-settings/my-account-settings.component.ts | 6 | ||||
-rw-r--r-- | client/src/app/shared/users/user.model.ts | 7 | ||||
-rw-r--r-- | client/src/app/videos/+video-edit/shared/video-image.component.ts | 11 | ||||
-rw-r--r-- | server/helpers/custom-validators/misc.ts | 4 | ||||
-rw-r--r-- | server/helpers/custom-validators/users.ts | 3 | ||||
-rw-r--r-- | server/helpers/custom-validators/videos.ts | 4 | ||||
-rw-r--r-- | server/middlewares/validators/users.ts | 10 | ||||
-rw-r--r-- | server/middlewares/validators/videos.ts | 45 | ||||
-rw-r--r-- | server/tests/api/check-params/videos.ts | 8 |
9 files changed, 59 insertions, 39 deletions
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts index 15f977e58..14293f14c 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts | |||
@@ -50,6 +50,10 @@ export class MyAccountSettingsComponent implements OnInit { | |||
50 | 50 | ||
51 | changeAvatar () { | 51 | changeAvatar () { |
52 | const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ] | 52 | const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ] |
53 | if (avatarfile.size > this.maxAvatarSize) { | ||
54 | this.notificationsService.error('Error', 'This image is too large.') | ||
55 | return | ||
56 | } | ||
53 | 57 | ||
54 | const formData = new FormData() | 58 | const formData = new FormData() |
55 | formData.append('avatarfile', avatarfile) | 59 | formData.append('avatarfile', avatarfile) |
@@ -59,7 +63,7 @@ export class MyAccountSettingsComponent implements OnInit { | |||
59 | data => { | 63 | data => { |
60 | this.notificationsService.success(this.i18n('Success'), this.i18n('Avatar changed.')) | 64 | this.notificationsService.success(this.i18n('Success'), this.i18n('Avatar changed.')) |
61 | 65 | ||
62 | this.user.account.avatar = data.avatar | 66 | this.user.updateAccountAvatar(data.avatar) |
63 | }, | 67 | }, |
64 | 68 | ||
65 | err => this.notificationsService.error(this.i18n('Error'), err.message) | 69 | err => this.notificationsService.error(this.i18n('Error'), err.message) |
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts index b4be2270f..60a0f26df 100644 --- a/client/src/app/shared/users/user.model.ts +++ b/client/src/app/shared/users/user.model.ts | |||
@@ -9,6 +9,7 @@ import { | |||
9 | import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type' | 9 | import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type' |
10 | import { Actor } from '@app/shared/actor/actor.model' | 10 | import { Actor } from '@app/shared/actor/actor.model' |
11 | import { Account } from '@app/shared/account/account.model' | 11 | import { Account } from '@app/shared/account/account.model' |
12 | import { Avatar } from '../../../../../shared/models/avatars/avatar.model' | ||
12 | 13 | ||
13 | export type UserConstructorHash = { | 14 | export type UserConstructorHash = { |
14 | id: number, | 15 | id: number, |
@@ -84,6 +85,12 @@ export class User implements UserServerModel { | |||
84 | this.updateComputedAttributes() | 85 | this.updateComputedAttributes() |
85 | } | 86 | } |
86 | 87 | ||
88 | updateAccountAvatar (newAccountAvatar: Avatar) { | ||
89 | this.account.avatar = newAccountAvatar | ||
90 | |||
91 | this.updateComputedAttributes() | ||
92 | } | ||
93 | |||
87 | private updateComputedAttributes () { | 94 | private updateComputedAttributes () { |
88 | this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account) | 95 | this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account) |
89 | } | 96 | } |
diff --git a/client/src/app/videos/+video-edit/shared/video-image.component.ts b/client/src/app/videos/+video-edit/shared/video-image.component.ts index df6565857..25955baaa 100644 --- a/client/src/app/videos/+video-edit/shared/video-image.component.ts +++ b/client/src/app/videos/+video-edit/shared/video-image.component.ts | |||
@@ -2,6 +2,8 @@ import { Component, forwardRef, Input } from '@angular/core' | |||
2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' | 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' |
3 | import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' | 3 | import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' |
4 | import { ServerService } from '@app/core' | 4 | import { ServerService } from '@app/core' |
5 | import { NotificationsService } from 'angular2-notifications' | ||
6 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
5 | 7 | ||
6 | @Component({ | 8 | @Component({ |
7 | selector: 'my-video-image', | 9 | selector: 'my-video-image', |
@@ -27,7 +29,9 @@ export class VideoImageComponent implements ControlValueAccessor { | |||
27 | 29 | ||
28 | constructor ( | 30 | constructor ( |
29 | private sanitizer: DomSanitizer, | 31 | private sanitizer: DomSanitizer, |
30 | private serverService: ServerService | 32 | private serverService: ServerService, |
33 | private notificationsService: NotificationsService, | ||
34 | private i18n: I18n | ||
31 | ) {} | 35 | ) {} |
32 | 36 | ||
33 | get videoImageExtensions () { | 37 | get videoImageExtensions () { |
@@ -42,6 +46,11 @@ export class VideoImageComponent implements ControlValueAccessor { | |||
42 | if (event.target.files && event.target.files.length) { | 46 | if (event.target.files && event.target.files.length) { |
43 | const [ file ] = event.target.files | 47 | const [ file ] = event.target.files |
44 | 48 | ||
49 | if (file.size > this.maxVideoImageSize) { | ||
50 | this.notificationsService.error(this.i18n('Error'), this.i18n('This image is too large.')) | ||
51 | return | ||
52 | } | ||
53 | |||
45 | this.file = file | 54 | this.file = file |
46 | this.propagateChange(this.file) | 55 | this.propagateChange(this.file) |
47 | this.updatePreview() | 56 | this.updatePreview() |
diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index 254b4db6c..455aae367 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts | |||
@@ -45,6 +45,7 @@ function isFileValid ( | |||
45 | files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], | 45 | files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], |
46 | mimeTypeRegex: string, | 46 | mimeTypeRegex: string, |
47 | field: string, | 47 | field: string, |
48 | maxSize: number, | ||
48 | optional = false | 49 | optional = false |
49 | ) { | 50 | ) { |
50 | // Should have files | 51 | // Should have files |
@@ -61,6 +62,9 @@ function isFileValid ( | |||
61 | const file = fileArray[ 0 ] | 62 | const file = fileArray[ 0 ] |
62 | if (!file || !file.originalname) return false | 63 | if (!file || !file.originalname) return false |
63 | 64 | ||
65 | // Check size | ||
66 | if (maxSize && file.size > maxSize) return false | ||
67 | |||
64 | return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype) | 68 | return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype) |
65 | } | 69 | } |
66 | 70 | ||
diff --git a/server/helpers/custom-validators/users.ts b/server/helpers/custom-validators/users.ts index b59b766de..ce1323e94 100644 --- a/server/helpers/custom-validators/users.ts +++ b/server/helpers/custom-validators/users.ts | |||
@@ -2,7 +2,6 @@ import 'express-validator' | |||
2 | import * as validator from 'validator' | 2 | import * as validator from 'validator' |
3 | import { UserRole } from '../../../shared' | 3 | import { UserRole } from '../../../shared' |
4 | import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers' | 4 | import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers' |
5 | |||
6 | import { exists, isFileValid } from './misc' | 5 | import { exists, isFileValid } from './misc' |
7 | import { values } from 'lodash' | 6 | import { values } from 'lodash' |
8 | 7 | ||
@@ -52,7 +51,7 @@ const avatarMimeTypes = CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME | |||
52 | .join('|') | 51 | .join('|') |
53 | const avatarMimeTypesRegex = `image/(${avatarMimeTypes})` | 52 | const avatarMimeTypesRegex = `image/(${avatarMimeTypes})` |
54 | function isAvatarFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) { | 53 | function isAvatarFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) { |
55 | return isFileValid(files, avatarMimeTypesRegex, 'avatarfile') | 54 | return isFileValid(files, avatarMimeTypesRegex, 'avatarfile', CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max) |
56 | } | 55 | } |
57 | 56 | ||
58 | // --------------------------------------------------------------------------- | 57 | // --------------------------------------------------------------------------- |
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index a227136ac..ae392f8c2 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts | |||
@@ -86,7 +86,7 @@ const videoFileTypes = Object.keys(VIDEO_MIMETYPE_EXT).map(m => `(${m})`) | |||
86 | const videoFileTypesRegex = videoFileTypes.join('|') | 86 | const videoFileTypesRegex = videoFileTypes.join('|') |
87 | 87 | ||
88 | function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) { | 88 | function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) { |
89 | return isFileValid(files, videoFileTypesRegex, 'videofile') | 89 | return isFileValid(files, videoFileTypesRegex, 'videofile', null) |
90 | } | 90 | } |
91 | 91 | ||
92 | const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME | 92 | const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME |
@@ -95,7 +95,7 @@ const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME | |||
95 | const videoImageTypesRegex = `image/(${videoImageTypes})` | 95 | const videoImageTypesRegex = `image/(${videoImageTypes})` |
96 | 96 | ||
97 | function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) { | 97 | function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) { |
98 | return isFileValid(files, videoImageTypesRegex, field, true) | 98 | return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true) |
99 | } | 99 | } |
100 | 100 | ||
101 | function isVideoPrivacyValid (value: number) { | 101 | function isVideoPrivacyValid (value: number) { |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 8fbab4dd0..55a08a648 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -118,7 +118,7 @@ const usersUpdateMeValidator = [ | |||
118 | 118 | ||
119 | const usersUpdateMyAvatarValidator = [ | 119 | const usersUpdateMyAvatarValidator = [ |
120 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( | 120 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( |
121 | 'This file is not supported. Please, make sure it is of the following type : ' | 121 | 'This file is not supported or too large. Please, make sure it is of the following type : ' |
122 | + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') | 122 | + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') |
123 | ), | 123 | ), |
124 | 124 | ||
@@ -127,14 +127,6 @@ const usersUpdateMyAvatarValidator = [ | |||
127 | 127 | ||
128 | if (areValidationErrors(req, res)) return | 128 | if (areValidationErrors(req, res)) return |
129 | 129 | ||
130 | const imageFile = req.files['avatarfile'][0] as Express.Multer.File | ||
131 | if (imageFile.size > CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max) { | ||
132 | res.status(400) | ||
133 | .send({ error: `The size of the avatar is too big (>${CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max}).` }) | ||
134 | .end() | ||
135 | return | ||
136 | } | ||
137 | |||
138 | return next() | 130 | return next() |
139 | } | 131 | } |
140 | ] | 132 | ] |
diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts index 5595edf17..59d65d5a4 100644 --- a/server/middlewares/validators/videos.ts +++ b/server/middlewares/validators/videos.ts | |||
@@ -38,18 +38,21 @@ import { authenticate } from '../oauth' | |||
38 | import { areValidationErrors } from './utils' | 38 | import { areValidationErrors } from './utils' |
39 | 39 | ||
40 | const videosAddValidator = [ | 40 | const videosAddValidator = [ |
41 | body('videofile').custom((value, { req }) => isVideoFile(req.files)).withMessage( | 41 | body('videofile') |
42 | 'This file is not supported. Please, make sure it is of the following type : ' | 42 | .custom((value, { req }) => isVideoFile(req.files)).withMessage( |
43 | + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') | 43 | 'This file is not supported or too large. Please, make sure it is of the following type : ' |
44 | ), | 44 | + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') |
45 | body('thumbnailfile').custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | 45 | ), |
46 | 'This thumbnail file is not supported. Please, make sure it is of the following type : ' | 46 | body('thumbnailfile') |
47 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 47 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( |
48 | ), | 48 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type : ' |
49 | body('previewfile').custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( | 49 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') |
50 | 'This preview file is not supported. Please, make sure it is of the following type : ' | 50 | ), |
51 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 51 | body('previewfile') |
52 | ), | 52 | .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( |
53 | 'This preview file is not supported or too large. Please, make sure it is of the following type : ' | ||
54 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | ||
55 | ), | ||
53 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), | 56 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), |
54 | body('category') | 57 | body('category') |
55 | .optional() | 58 | .optional() |
@@ -147,14 +150,16 @@ const videosAddValidator = [ | |||
147 | 150 | ||
148 | const videosUpdateValidator = [ | 151 | const videosUpdateValidator = [ |
149 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 152 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
150 | body('thumbnailfile').custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | 153 | body('thumbnailfile') |
151 | 'This thumbnail file is not supported. Please, make sure it is of the following type : ' | 154 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( |
152 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 155 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type : ' |
153 | ), | 156 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') |
154 | body('previewfile').custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( | 157 | ), |
155 | 'This preview file is not supported. Please, make sure it is of the following type : ' | 158 | body('previewfile') |
156 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 159 | .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( |
157 | ), | 160 | 'This preview file is not supported or too large. Please, make sure it is of the following type : ' |
161 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | ||
162 | ), | ||
158 | body('name') | 163 | body('name') |
159 | .optional() | 164 | .optional() |
160 | .custom(isVideoNameValid).withMessage('Should have a valid name'), | 165 | .custom(isVideoNameValid).withMessage('Should have a valid name'), |
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index abbea6ba3..7fce8ba7c 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -326,7 +326,7 @@ describe('Test videos API validator', function () { | |||
326 | const fields = baseCorrectParams | 326 | const fields = baseCorrectParams |
327 | const attaches = { | 327 | const attaches = { |
328 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png'), | 328 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png'), |
329 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm') | 329 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
330 | } | 330 | } |
331 | 331 | ||
332 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 332 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -336,7 +336,7 @@ describe('Test videos API validator', function () { | |||
336 | const fields = baseCorrectParams | 336 | const fields = baseCorrectParams |
337 | const attaches = { | 337 | const attaches = { |
338 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png'), | 338 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png'), |
339 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm') | 339 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
340 | } | 340 | } |
341 | 341 | ||
342 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 342 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -346,7 +346,7 @@ describe('Test videos API validator', function () { | |||
346 | const fields = baseCorrectParams | 346 | const fields = baseCorrectParams |
347 | const attaches = { | 347 | const attaches = { |
348 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png'), | 348 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png'), |
349 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm') | 349 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
350 | } | 350 | } |
351 | 351 | ||
352 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 352 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -356,7 +356,7 @@ describe('Test videos API validator', function () { | |||
356 | const fields = baseCorrectParams | 356 | const fields = baseCorrectParams |
357 | const attaches = { | 357 | const attaches = { |
358 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png'), | 358 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png'), |
359 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short_fake.webm') | 359 | 'videofile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
360 | } | 360 | } |
361 | 361 | ||
362 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 362 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |