diff options
Diffstat (limited to 'server/middlewares/validators/videos/videos.ts')
-rw-r--r-- | server/middlewares/validators/videos/videos.ts | 105 |
1 files changed, 62 insertions, 43 deletions
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 8864be269..dfd472400 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -73,6 +73,7 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ | |||
73 | .custom(isIdValid).withMessage('Should have correct video channel id'), | 73 | .custom(isIdValid).withMessage('Should have correct video channel id'), |
74 | 74 | ||
75 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 75 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
76 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy" | ||
76 | logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files }) | 77 | logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files }) |
77 | 78 | ||
78 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | 79 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) |
@@ -88,9 +89,11 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ | |||
88 | if (!videoFile.duration) await addDurationToVideo(videoFile) | 89 | if (!videoFile.duration) await addDurationToVideo(videoFile) |
89 | } catch (err) { | 90 | } catch (err) { |
90 | logger.error('Invalid input file in videosAddLegacyValidator.', { err }) | 91 | logger.error('Invalid input file in videosAddLegacyValidator.', { err }) |
91 | res.status(HttpStatusCode.UNPROCESSABLE_ENTITY_422) | ||
92 | .json({ error: 'Video file unreadable.' }) | ||
93 | 92 | ||
93 | res.fail({ | ||
94 | status: HttpStatusCode.UNPROCESSABLE_ENTITY_422, | ||
95 | message: 'Video file unreadable.' | ||
96 | }) | ||
94 | return cleanUpReqFiles(req) | 97 | return cleanUpReqFiles(req) |
95 | } | 98 | } |
96 | 99 | ||
@@ -105,6 +108,7 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ | |||
105 | */ | 108 | */ |
106 | const videosAddResumableValidator = [ | 109 | const videosAddResumableValidator = [ |
107 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 110 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
111 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumable" | ||
108 | const user = res.locals.oauth.token.User | 112 | const user = res.locals.oauth.token.User |
109 | 113 | ||
110 | const body: express.CustomUploadXFile<express.UploadXFileMetadata> = req.body | 114 | const body: express.CustomUploadXFile<express.UploadXFileMetadata> = req.body |
@@ -118,9 +122,11 @@ const videosAddResumableValidator = [ | |||
118 | if (!file.duration) await addDurationToVideo(file) | 122 | if (!file.duration) await addDurationToVideo(file) |
119 | } catch (err) { | 123 | } catch (err) { |
120 | logger.error('Invalid input file in videosAddResumableValidator.', { err }) | 124 | logger.error('Invalid input file in videosAddResumableValidator.', { err }) |
121 | res.status(HttpStatusCode.UNPROCESSABLE_ENTITY_422) | ||
122 | .json({ error: 'Video file unreadable.' }) | ||
123 | 125 | ||
126 | res.fail({ | ||
127 | status: HttpStatusCode.UNPROCESSABLE_ENTITY_422, | ||
128 | message: 'Video file unreadable.' | ||
129 | }) | ||
124 | return cleanup() | 130 | return cleanup() |
125 | } | 131 | } |
126 | 132 | ||
@@ -164,6 +170,7 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([ | |||
164 | .withMessage('Should specify the file mimetype'), | 170 | .withMessage('Should specify the file mimetype'), |
165 | 171 | ||
166 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 172 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
173 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit" | ||
167 | const videoFileMetadata = { | 174 | const videoFileMetadata = { |
168 | mimetype: req.headers['x-upload-content-type'] as string, | 175 | mimetype: req.headers['x-upload-content-type'] as string, |
169 | size: +req.headers['x-upload-content-length'], | 176 | size: +req.headers['x-upload-content-length'], |
@@ -207,6 +214,7 @@ const videosUpdateValidator = getCommonVideoEditAttributes().concat([ | |||
207 | .custom(isIdValid).withMessage('Should have correct video channel id'), | 214 | .custom(isIdValid).withMessage('Should have correct video channel id'), |
208 | 215 | ||
209 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 216 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
217 | res.docs = 'https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo' | ||
210 | logger.debug('Checking videosUpdate parameters', { parameters: req.body }) | 218 | logger.debug('Checking videosUpdate parameters', { parameters: req.body }) |
211 | 219 | ||
212 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | 220 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) |
@@ -242,12 +250,14 @@ async function checkVideoFollowConstraints (req: express.Request, res: express.R | |||
242 | const serverActor = await getServerActor() | 250 | const serverActor = await getServerActor() |
243 | if (await VideoModel.checkVideoHasInstanceFollow(video.id, serverActor.id) === true) return next() | 251 | if (await VideoModel.checkVideoHasInstanceFollow(video.id, serverActor.id) === true) return next() |
244 | 252 | ||
245 | return res.status(HttpStatusCode.FORBIDDEN_403) | 253 | return res.fail({ |
246 | .json({ | 254 | status: HttpStatusCode.FORBIDDEN_403, |
247 | errorCode: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS, | 255 | message: 'Cannot get this video regarding follow constraints.', |
248 | error: 'Cannot get this video regarding follow constraints.', | 256 | type: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS.toString(), |
249 | originUrl: video.url | 257 | data: { |
250 | }) | 258 | originUrl: video.url |
259 | } | ||
260 | }) | ||
251 | } | 261 | } |
252 | 262 | ||
253 | const videosCustomGetValidator = ( | 263 | const videosCustomGetValidator = ( |
@@ -258,6 +268,7 @@ const videosCustomGetValidator = ( | |||
258 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 268 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
259 | 269 | ||
260 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 270 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
271 | res.docs = 'https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo' | ||
261 | logger.debug('Checking videosGet parameters', { parameters: req.params }) | 272 | logger.debug('Checking videosGet parameters', { parameters: req.params }) |
262 | 273 | ||
263 | if (areValidationErrors(req, res)) return | 274 | if (areValidationErrors(req, res)) return |
@@ -276,8 +287,10 @@ const videosCustomGetValidator = ( | |||
276 | 287 | ||
277 | // Only the owner or a user that have blacklist rights can see the video | 288 | // Only the owner or a user that have blacklist rights can see the video |
278 | if (!user || !user.canGetVideo(video)) { | 289 | if (!user || !user.canGetVideo(video)) { |
279 | return res.status(HttpStatusCode.FORBIDDEN_403) | 290 | return res.fail({ |
280 | .json({ error: 'Cannot get this private/internal or blacklisted video.' }) | 291 | status: HttpStatusCode.FORBIDDEN_403, |
292 | message: 'Cannot get this private/internal or blacklisted video.' | ||
293 | }) | ||
281 | } | 294 | } |
282 | 295 | ||
283 | return next() | 296 | return next() |
@@ -291,7 +304,10 @@ const videosCustomGetValidator = ( | |||
291 | if (isUUIDValid(req.params.id)) return next() | 304 | if (isUUIDValid(req.params.id)) return next() |
292 | 305 | ||
293 | // Don't leak this unlisted video | 306 | // Don't leak this unlisted video |
294 | return res.status(HttpStatusCode.NOT_FOUND_404).end() | 307 | return res.fail({ |
308 | status: HttpStatusCode.NOT_FOUND_404, | ||
309 | message: 'Video not found' | ||
310 | }) | ||
295 | } | 311 | } |
296 | } | 312 | } |
297 | ] | 313 | ] |
@@ -318,6 +334,7 @@ const videosRemoveValidator = [ | |||
318 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 334 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
319 | 335 | ||
320 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 336 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
337 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo" | ||
321 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) | 338 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) |
322 | 339 | ||
323 | if (areValidationErrors(req, res)) return | 340 | if (areValidationErrors(req, res)) return |
@@ -344,13 +361,11 @@ const videosChangeOwnershipValidator = [ | |||
344 | 361 | ||
345 | const nextOwner = await AccountModel.loadLocalByName(req.body.username) | 362 | const nextOwner = await AccountModel.loadLocalByName(req.body.username) |
346 | if (!nextOwner) { | 363 | if (!nextOwner) { |
347 | res.status(HttpStatusCode.BAD_REQUEST_400) | 364 | res.fail({ message: 'Changing video ownership to a remote account is not supported yet' }) |
348 | .json({ error: 'Changing video ownership to a remote account is not supported yet' }) | ||
349 | |||
350 | return | 365 | return |
351 | } | 366 | } |
352 | res.locals.nextOwner = nextOwner | ||
353 | 367 | ||
368 | res.locals.nextOwner = nextOwner | ||
354 | return next() | 369 | return next() |
355 | } | 370 | } |
356 | ] | 371 | ] |
@@ -370,8 +385,10 @@ const videosTerminateChangeOwnershipValidator = [ | |||
370 | const videoChangeOwnership = res.locals.videoChangeOwnership | 385 | const videoChangeOwnership = res.locals.videoChangeOwnership |
371 | 386 | ||
372 | if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) { | 387 | if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) { |
373 | res.status(HttpStatusCode.FORBIDDEN_403) | 388 | res.fail({ |
374 | .json({ error: 'Ownership already accepted or refused' }) | 389 | status: HttpStatusCode.FORBIDDEN_403, |
390 | message: 'Ownership already accepted or refused' | ||
391 | }) | ||
375 | return | 392 | return |
376 | } | 393 | } |
377 | 394 | ||
@@ -388,9 +405,10 @@ const videosAcceptChangeOwnershipValidator = [ | |||
388 | const videoChangeOwnership = res.locals.videoChangeOwnership | 405 | const videoChangeOwnership = res.locals.videoChangeOwnership |
389 | const isAble = await isAbleToUploadVideo(user.id, videoChangeOwnership.Video.getMaxQualityFile().size) | 406 | const isAble = await isAbleToUploadVideo(user.id, videoChangeOwnership.Video.getMaxQualityFile().size) |
390 | if (isAble === false) { | 407 | if (isAble === false) { |
391 | res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) | 408 | res.fail({ |
392 | .json({ error: 'The user video quota is exceeded with this video.' }) | 409 | status: HttpStatusCode.PAYLOAD_TOO_LARGE_413, |
393 | 410 | message: 'The user video quota is exceeded with this video.' | |
411 | }) | ||
394 | return | 412 | return |
395 | } | 413 | } |
396 | 414 | ||
@@ -538,9 +556,10 @@ const commonVideosFiltersValidator = [ | |||
538 | (req.query.filter === 'all-local' || req.query.filter === 'all') && | 556 | (req.query.filter === 'all-local' || req.query.filter === 'all') && |
539 | (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false) | 557 | (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false) |
540 | ) { | 558 | ) { |
541 | res.status(HttpStatusCode.UNAUTHORIZED_401) | 559 | res.fail({ |
542 | .json({ error: 'You are not allowed to see all local videos.' }) | 560 | status: HttpStatusCode.UNAUTHORIZED_401, |
543 | 561 | message: 'You are not allowed to see all local videos.' | |
562 | }) | ||
544 | return | 563 | return |
545 | } | 564 | } |
546 | 565 | ||
@@ -581,9 +600,7 @@ function areErrorsInScheduleUpdate (req: express.Request, res: express.Response) | |||
581 | if (!req.body.scheduleUpdate.updateAt) { | 600 | if (!req.body.scheduleUpdate.updateAt) { |
582 | logger.warn('Invalid parameters: scheduleUpdate.updateAt is mandatory.') | 601 | logger.warn('Invalid parameters: scheduleUpdate.updateAt is mandatory.') |
583 | 602 | ||
584 | res.status(HttpStatusCode.BAD_REQUEST_400) | 603 | res.fail({ message: 'Schedule update at is mandatory.' }) |
585 | .json({ error: 'Schedule update at is mandatory.' }) | ||
586 | |||
587 | return true | 604 | return true |
588 | } | 605 | } |
589 | } | 606 | } |
@@ -605,26 +622,27 @@ async function commonVideoChecksPass (parameters: { | |||
605 | if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return false | 622 | if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return false |
606 | 623 | ||
607 | if (!isVideoFileMimeTypeValid(files)) { | 624 | if (!isVideoFileMimeTypeValid(files)) { |
608 | res.status(HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) | 625 | res.fail({ |
609 | .json({ | 626 | status: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415, |
610 | error: 'This file is not supported. Please, make sure it is of the following type: ' + | 627 | message: 'This file is not supported. Please, make sure it is of the following type: ' + |
611 | CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') | 628 | CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') |
612 | }) | 629 | }) |
613 | |||
614 | return false | 630 | return false |
615 | } | 631 | } |
616 | 632 | ||
617 | if (!isVideoFileSizeValid(videoFileSize.toString())) { | 633 | if (!isVideoFileSizeValid(videoFileSize.toString())) { |
618 | res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) | 634 | res.fail({ |
619 | .json({ error: 'This file is too large. It exceeds the maximum file size authorized.' }) | 635 | status: HttpStatusCode.PAYLOAD_TOO_LARGE_413, |
620 | 636 | message: 'This file is too large. It exceeds the maximum file size authorized.' | |
637 | }) | ||
621 | return false | 638 | return false |
622 | } | 639 | } |
623 | 640 | ||
624 | if (await isAbleToUploadVideo(user.id, videoFileSize) === false) { | 641 | if (await isAbleToUploadVideo(user.id, videoFileSize) === false) { |
625 | res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) | 642 | res.fail({ |
626 | .json({ error: 'The user video quota is exceeded with this video.' }) | 643 | status: HttpStatusCode.PAYLOAD_TOO_LARGE_413, |
627 | 644 | message: 'The user video quota is exceeded with this video.' | |
645 | }) | ||
628 | return false | 646 | return false |
629 | } | 647 | } |
630 | 648 | ||
@@ -650,9 +668,10 @@ export async function isVideoAccepted ( | |||
650 | 668 | ||
651 | if (!acceptedResult || acceptedResult.accepted !== true) { | 669 | if (!acceptedResult || acceptedResult.accepted !== true) { |
652 | logger.info('Refused local video.', { acceptedResult, acceptParameters }) | 670 | logger.info('Refused local video.', { acceptedResult, acceptParameters }) |
653 | res.status(HttpStatusCode.FORBIDDEN_403) | 671 | res.fail({ |
654 | .json({ error: acceptedResult.errorMessage || 'Refused local video' }) | 672 | status: HttpStatusCode.FORBIDDEN_403, |
655 | 673 | message: acceptedResult.errorMessage || 'Refused local video' | |
674 | }) | ||
656 | return false | 675 | return false |
657 | } | 676 | } |
658 | 677 | ||