]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/middlewares/validators/videos/videos.ts
Trim video name also on server
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / videos / videos.ts
CommitLineData
69818c93 1import * as express from 'express'
c8861d5d 2import { body, param, query, ValidationChain } from 'express-validator'
fb719404 3import { isAbleToUploadVideo } from '@server/lib/user'
e6abf95e 4import { getServerActor } from '@server/models/application/application'
ba5a8d89 5import { ExpressPromiseHandler } from '@server/types/express'
e6abf95e
C
6import { MVideoFullLight } from '@server/types/models'
7import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared'
ba5a8d89 8import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
e6abf95e 9import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model'
b60e5f38 10import {
37024082 11 exists,
2baea0c7
C
12 isBooleanValid,
13 isDateValid,
f2eb23cd 14 isFileFieldValid,
2baea0c7
C
15 isIdOrUUIDValid,
16 isIdValid,
17 isUUIDValid,
1cd3facc 18 toArray,
c8861d5d 19 toBooleanOrNull,
2baea0c7
C
20 toIntOrNull,
21 toValueOrNull
6e46de09 22} from '../../../helpers/custom-validators/misc'
e6abf95e
C
23import { isNSFWQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search'
24import { checkUserCanTerminateOwnershipChange, doesChangeVideoOwnershipExist } from '../../../helpers/custom-validators/video-ownership'
2baea0c7
C
25import {
26 isScheduleVideoUpdatePrivacyValid,
ac81d1a0
C
27 isVideoCategoryValid,
28 isVideoDescriptionValid,
f2eb23cd
RK
29 isVideoFileMimeTypeValid,
30 isVideoFileSizeValid,
1cd3facc 31 isVideoFilterValid,
ac81d1a0
C
32 isVideoImage,
33 isVideoLanguageValid,
34 isVideoLicenceValid,
35 isVideoNameValid,
fd8710b8 36 isVideoOriginallyPublishedAtValid,
ac81d1a0 37 isVideoPrivacyValid,
360329cc 38 isVideoSupportValid,
4157cdb1 39 isVideoTagsValid
6e46de09 40} from '../../../helpers/custom-validators/videos'
e6abf95e 41import { cleanUpReqFiles } from '../../../helpers/express-utils'
daf6e480 42import { getDurationFromVideoFile } from '../../../helpers/ffprobe-utils'
6e46de09 43import { logger } from '../../../helpers/logger'
8319d6ae
RK
44import {
45 checkUserCanManageVideo,
46 doesVideoChannelOfAccountExist,
47 doesVideoExist,
48 doesVideoFileOfVideoExist
49} from '../../../helpers/middlewares'
0283eaac 50import { getVideoWithAttributes } from '../../../helpers/video'
e6abf95e
C
51import { CONFIG } from '../../../initializers/config'
52import { CONSTRAINTS_FIELDS, OVERVIEWS } from '../../../initializers/constants'
53import { isLocalVideoAccepted } from '../../../lib/moderation'
54import { Hooks } from '../../../lib/plugins/hooks'
55import { AccountModel } from '../../../models/account/account'
56import { VideoModel } from '../../../models/video/video'
57import { authenticatePromiseIfNeeded } from '../../oauth'
58import { areValidationErrors } from '../utils'
34ca3b52 59
418d092a 60const videosAddValidator = getCommonVideoEditAttributes().concat([
0c237b19 61 body('videofile')
f2eb23cd
RK
62 .custom((value, { req }) => isFileFieldValid(req.files, 'videofile'))
63 .withMessage('Should have a file'),
64 body('name')
0221f8c9 65 .trim()
f2eb23cd
RK
66 .custom(isVideoNameValid)
67 .withMessage('Should have a valid name'),
0f320037 68 body('channelId')
c8861d5d 69 .customSanitizer(toIntOrNull)
2baea0c7 70 .custom(isIdValid).withMessage('Should have correct video channel id'),
b60e5f38 71
a2431b7d 72 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
b60e5f38
C
73 logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files })
74
cf7a61b5
C
75 if (areValidationErrors(req, res)) return cleanUpReqFiles(req)
76 if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req)
a2431b7d 77
b4055e1c 78 const videoFile: Express.Multer.File & { duration?: number } = req.files['videofile'][0]
a2431b7d 79 const user = res.locals.oauth.token.User
b60e5f38 80
0f6acda1 81 if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req)
a2431b7d 82
f2eb23cd
RK
83 if (!isVideoFileMimeTypeValid(req.files)) {
84 res.status(HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415)
85 .json({
86 error: 'This file is not supported. Please, make sure it is of the following type: ' +
87 CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
88 })
89
90 return cleanUpReqFiles(req)
91 }
92
93 if (!isVideoFileSizeValid(videoFile.size.toString())) {
94 res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413)
95 .json({
96 error: 'This file is too large.'
97 })
98
99 return cleanUpReqFiles(req)
100 }
101
fb719404 102 if (await isAbleToUploadVideo(user.id, videoFile.size) === false) {
f2eb23cd 103 res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413)
a2431b7d 104 .json({ error: 'The user video quota is exceeded with this video.' })
a2431b7d 105
cf7a61b5 106 return cleanUpReqFiles(req)
a2431b7d
C
107 }
108
109 let duration: number
110
111 try {
112 duration = await getDurationFromVideoFile(videoFile.path)
113 } catch (err) {
d5b7d911 114 logger.error('Invalid input file in videosAddValidator.', { err })
f2eb23cd
RK
115 res.status(HttpStatusCode.UNPROCESSABLE_ENTITY_422)
116 .json({ error: 'Video file unreadable.' })
a2431b7d 117
cf7a61b5 118 return cleanUpReqFiles(req)
a2431b7d
C
119 }
120
b4055e1c
C
121 videoFile.duration = duration
122
123 if (!await isVideoAccepted(req, res, videoFile)) return cleanUpReqFiles(req)
a2431b7d
C
124
125 return next()
b60e5f38 126 }
a920fef1 127])
b60e5f38 128
418d092a 129const videosUpdateValidator = getCommonVideoEditAttributes().concat([
72c7248b 130 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
360329cc
C
131 body('name')
132 .optional()
0221f8c9 133 .trim()
360329cc 134 .custom(isVideoNameValid).withMessage('Should have a valid name'),
0f320037
C
135 body('channelId')
136 .optional()
c8861d5d 137 .customSanitizer(toIntOrNull)
0f320037 138 .custom(isIdValid).withMessage('Should have correct video channel id'),
b60e5f38 139
a2431b7d 140 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
b60e5f38
C
141 logger.debug('Checking videosUpdate parameters', { parameters: req.body })
142
cf7a61b5
C
143 if (areValidationErrors(req, res)) return cleanUpReqFiles(req)
144 if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req)
0f6acda1 145 if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req)
a2431b7d 146
6221f311 147 // Check if the user who did the request is able to update the video
0f320037 148 const user = res.locals.oauth.token.User
453e83ea 149 if (!checkUserCanManageVideo(user, res.locals.videoAll, UserRight.UPDATE_ANY_VIDEO, res)) return cleanUpReqFiles(req)
a2431b7d 150
0f6acda1 151 if (req.body.channelId && !await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req)
0f320037 152
a2431b7d 153 return next()
b60e5f38 154 }
a920fef1 155])
c173e565 156
8d427346 157async function checkVideoFollowConstraints (req: express.Request, res: express.Response, next: express.NextFunction) {
0283eaac 158 const video = getVideoWithAttributes(res)
8d427346
C
159
160 // Anybody can watch local videos
161 if (video.isOwned() === true) return next()
162
163 // Logged user
164 if (res.locals.oauth) {
165 // Users can search or watch remote videos
166 if (CONFIG.SEARCH.REMOTE_URI.USERS === true) return next()
167 }
168
169 // Anybody can search or watch remote videos
170 if (CONFIG.SEARCH.REMOTE_URI.ANONYMOUS === true) return next()
171
172 // Check our instance follows an actor that shared this video
173 const serverActor = await getServerActor()
174 if (await VideoModel.checkVideoHasInstanceFollow(video.id, serverActor.id) === true) return next()
175
2d53be02 176 return res.status(HttpStatusCode.FORBIDDEN_403)
8d427346 177 .json({
e6abf95e
C
178 errorCode: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS,
179 error: 'Cannot get this video regarding follow constraints.',
180 originUrl: video.url
8d427346
C
181 })
182}
183
7eba5e1f
C
184const videosCustomGetValidator = (
185 fetchType: 'all' | 'only-video' | 'only-video-with-rights' | 'only-immutable-attributes',
186 authenticateInQuery = false
187) => {
96f29c0f
C
188 return [
189 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
7b1f49de 190
96f29c0f
C
191 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
192 logger.debug('Checking videosGet parameters', { parameters: req.params })
11474c3c 193
96f29c0f 194 if (areValidationErrors(req, res)) return
0f6acda1 195 if (!await doesVideoExist(req.params.id, res, fetchType)) return
191764f3 196
943e5193
C
197 // Controllers does not need to check video rights
198 if (fetchType === 'only-immutable-attributes') return next()
199
0283eaac 200 const video = getVideoWithAttributes(res)
453e83ea 201 const videoAll = video as MVideoFullLight
191764f3 202
96f29c0f 203 // Video private or blacklisted
22a73cb8 204 if (videoAll.requiresAuth()) {
eccf70f0 205 await authenticatePromiseIfNeeded(req, res, authenticateInQuery)
8d427346 206
dae86118 207 const user = res.locals.oauth ? res.locals.oauth.token.User : null
191764f3 208
8d427346 209 // Only the owner or a user that have blacklist rights can see the video
22a73cb8 210 if (!user || !user.canGetVideo(videoAll)) {
2d53be02 211 return res.status(HttpStatusCode.FORBIDDEN_403)
22a73cb8 212 .json({ error: 'Cannot get this private/internal or blacklisted video.' })
8d427346 213 }
191764f3 214
8d427346 215 return next()
96f29c0f 216 }
11474c3c 217
96f29c0f
C
218 // Video is public, anyone can access it
219 if (video.privacy === VideoPrivacy.PUBLIC) return next()
11474c3c 220
96f29c0f
C
221 // Video is unlisted, check we used the uuid to fetch it
222 if (video.privacy === VideoPrivacy.UNLISTED) {
223 if (isUUIDValid(req.params.id)) return next()
81ebea48 224
96f29c0f 225 // Don't leak this unlisted video
2d53be02 226 return res.status(HttpStatusCode.NOT_FOUND_404).end()
96f29c0f 227 }
81ebea48 228 }
96f29c0f
C
229 ]
230}
231
232const videosGetValidator = videosCustomGetValidator('all')
eccf70f0 233const videosDownloadValidator = videosCustomGetValidator('all', true)
34ca3b52 234
8319d6ae
RK
235const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
236 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
237 param('videoFileId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid videoFileId'),
238
239 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
240 logger.debug('Checking videoFileMetadataGet parameters', { parameters: req.params })
241
242 if (areValidationErrors(req, res)) return
243 if (!await doesVideoFileOfVideoExist(+req.params.videoFileId, req.params.id, res)) return
244
245 return next()
246 }
247])
248
b60e5f38 249const videosRemoveValidator = [
72c7248b 250 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
34ca3b52 251
a2431b7d 252 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
b60e5f38 253 logger.debug('Checking videosRemove parameters', { parameters: req.params })
34ca3b52 254
a2431b7d 255 if (areValidationErrors(req, res)) return
0f6acda1 256 if (!await doesVideoExist(req.params.id, res)) return
a2431b7d
C
257
258 // Check if the user who did the request is able to delete the video
453e83ea 259 if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.videoAll, UserRight.REMOVE_ANY_VIDEO, res)) return
a2431b7d
C
260
261 return next()
b60e5f38
C
262 }
263]
34ca3b52 264
74d63469
GR
265const videosChangeOwnershipValidator = [
266 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
267
268 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
269 logger.debug('Checking changeOwnership parameters', { parameters: req.params })
270
271 if (areValidationErrors(req, res)) return
0f6acda1 272 if (!await doesVideoExist(req.params.videoId, res)) return
74d63469
GR
273
274 // Check if the user who did the request is able to change the ownership of the video
453e83ea 275 if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.videoAll, UserRight.CHANGE_VIDEO_OWNERSHIP, res)) return
74d63469
GR
276
277 const nextOwner = await AccountModel.loadLocalByName(req.body.username)
278 if (!nextOwner) {
2d53be02 279 res.status(HttpStatusCode.BAD_REQUEST_400)
9ccff238
LD
280 .json({ error: 'Changing video ownership to a remote account is not supported yet' })
281
74d63469
GR
282 return
283 }
284 res.locals.nextOwner = nextOwner
285
286 return next()
287 }
288]
289
290const videosTerminateChangeOwnershipValidator = [
291 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
292
293 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
294 logger.debug('Checking changeOwnership parameters', { parameters: req.params })
295
296 if (areValidationErrors(req, res)) return
297 if (!await doesChangeVideoOwnershipExist(req.params.id, res)) return
298
299 // Check if the user who did the request is able to change the ownership of the video
300 if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
301
dae86118 302 const videoChangeOwnership = res.locals.videoChangeOwnership
74d63469 303
a1587156 304 if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
2d53be02 305 res.status(HttpStatusCode.FORBIDDEN_403)
a1587156 306 .json({ error: 'Ownership already accepted or refused' })
74d63469
GR
307 return
308 }
a1587156
C
309
310 return next()
74d63469
GR
311 }
312]
313
314const videosAcceptChangeOwnershipValidator = [
315 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
316 const body = req.body as VideoChangeOwnershipAccept
0f6acda1 317 if (!await doesVideoChannelOfAccountExist(body.channelId, res.locals.oauth.token.User, res)) return
74d63469
GR
318
319 const user = res.locals.oauth.token.User
dae86118 320 const videoChangeOwnership = res.locals.videoChangeOwnership
fb719404 321 const isAble = await isAbleToUploadVideo(user.id, videoChangeOwnership.Video.getMaxQualityFile().size)
74d63469 322 if (isAble === false) {
f2eb23cd 323 res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413)
74d63469 324 .json({ error: 'The user video quota is exceeded with this video.' })
9ccff238 325
74d63469
GR
326 return
327 }
328
329 return next()
330 }
331]
332
764a9657
C
333const videosOverviewValidator = [
334 query('page')
335 .optional()
336 .isInt({ min: 1, max: OVERVIEWS.VIDEOS.SAMPLES_COUNT })
337 .withMessage('Should have a valid pagination'),
338
339 (req: express.Request, res: express.Response, next: express.NextFunction) => {
340 if (areValidationErrors(req, res)) return
341
342 return next()
343 }
344]
345
418d092a 346function getCommonVideoEditAttributes () {
a920fef1
C
347 return [
348 body('thumbnailfile')
349 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage(
a1587156
C
350 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' +
351 CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
352 ),
a920fef1
C
353 body('previewfile')
354 .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage(
a1587156
C
355 'This preview file is not supported or too large. Please, make sure it is of the following type: ' +
356 CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
357 ),
a920fef1
C
358
359 body('category')
360 .optional()
361 .customSanitizer(toIntOrNull)
362 .custom(isVideoCategoryValid).withMessage('Should have a valid category'),
363 body('licence')
364 .optional()
365 .customSanitizer(toIntOrNull)
366 .custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
367 body('language')
368 .optional()
369 .customSanitizer(toValueOrNull)
370 .custom(isVideoLanguageValid).withMessage('Should have a valid language'),
371 body('nsfw')
372 .optional()
c8861d5d 373 .customSanitizer(toBooleanOrNull)
a920fef1
C
374 .custom(isBooleanValid).withMessage('Should have a valid NSFW attribute'),
375 body('waitTranscoding')
376 .optional()
c8861d5d 377 .customSanitizer(toBooleanOrNull)
a920fef1
C
378 .custom(isBooleanValid).withMessage('Should have a valid wait transcoding attribute'),
379 body('privacy')
380 .optional()
c8861d5d 381 .customSanitizer(toValueOrNull)
a920fef1
C
382 .custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
383 body('description')
384 .optional()
385 .customSanitizer(toValueOrNull)
386 .custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
387 body('support')
388 .optional()
389 .customSanitizer(toValueOrNull)
390 .custom(isVideoSupportValid).withMessage('Should have a valid support text'),
391 body('tags')
392 .optional()
393 .customSanitizer(toValueOrNull)
394 .custom(isVideoTagsValid).withMessage('Should have correct tags'),
395 body('commentsEnabled')
396 .optional()
c8861d5d 397 .customSanitizer(toBooleanOrNull)
a920fef1 398 .custom(isBooleanValid).withMessage('Should have comments enabled boolean'),
7f2cfe3a 399 body('downloadEnabled')
1e74f19a 400 .optional()
c8861d5d 401 .customSanitizer(toBooleanOrNull)
156c50af 402 .custom(isBooleanValid).withMessage('Should have downloading enabled boolean'),
b718fd22 403 body('originallyPublishedAt')
c8861d5d
C
404 .optional()
405 .customSanitizer(toValueOrNull)
406 .custom(isVideoOriginallyPublishedAtValid).withMessage('Should have a valid original publication date'),
a920fef1
C
407 body('scheduleUpdate')
408 .optional()
409 .customSanitizer(toValueOrNull),
410 body('scheduleUpdate.updateAt')
411 .optional()
412 .custom(isDateValid).withMessage('Should have a valid schedule update date'),
413 body('scheduleUpdate.privacy')
414 .optional()
2b65c4e5 415 .customSanitizer(toIntOrNull)
a920fef1 416 .custom(isScheduleVideoUpdatePrivacyValid).withMessage('Should have correct schedule update privacy')
ba5a8d89 417 ] as (ValidationChain | ExpressPromiseHandler)[]
a920fef1 418}
fbad87b0 419
1cd3facc
C
420const commonVideosFiltersValidator = [
421 query('categoryOneOf')
422 .optional()
423 .customSanitizer(toArray)
424 .custom(isNumberArray).withMessage('Should have a valid one of category array'),
425 query('licenceOneOf')
426 .optional()
427 .customSanitizer(toArray)
428 .custom(isNumberArray).withMessage('Should have a valid one of licence array'),
429 query('languageOneOf')
430 .optional()
431 .customSanitizer(toArray)
432 .custom(isStringArray).withMessage('Should have a valid one of language array'),
433 query('tagsOneOf')
434 .optional()
435 .customSanitizer(toArray)
436 .custom(isStringArray).withMessage('Should have a valid one of tags array'),
437 query('tagsAllOf')
438 .optional()
439 .customSanitizer(toArray)
440 .custom(isStringArray).withMessage('Should have a valid all of tags array'),
441 query('nsfw')
442 .optional()
443 .custom(isNSFWQueryValid).withMessage('Should have a valid NSFW attribute'),
444 query('filter')
445 .optional()
446 .custom(isVideoFilterValid).withMessage('Should have a valid filter attribute'),
fe987656
C
447 query('skipCount')
448 .optional()
449 .customSanitizer(toBooleanOrNull)
450 .custom(isBooleanValid).withMessage('Should have a valid skip count boolean'),
37024082
RK
451 query('search')
452 .optional()
453 .custom(exists).withMessage('Should have a valid search'),
1cd3facc
C
454
455 (req: express.Request, res: express.Response, next: express.NextFunction) => {
456 logger.debug('Checking commons video filters query', { parameters: req.query })
457
458 if (areValidationErrors(req, res)) return
459
dae86118 460 const user = res.locals.oauth ? res.locals.oauth.token.User : undefined
0aa52e17
C
461 if (
462 (req.query.filter === 'all-local' || req.query.filter === 'all') &&
463 (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false)
464 ) {
2d53be02 465 res.status(HttpStatusCode.UNAUTHORIZED_401)
1cd3facc
C
466 .json({ error: 'You are not allowed to see all local videos.' })
467
468 return
469 }
470
471 return next()
472 }
473]
474
fbad87b0
C
475// ---------------------------------------------------------------------------
476
477export {
478 videosAddValidator,
479 videosUpdateValidator,
480 videosGetValidator,
8319d6ae 481 videoFileMetadataGetValidator,
eccf70f0 482 videosDownloadValidator,
8d427346 483 checkVideoFollowConstraints,
96f29c0f 484 videosCustomGetValidator,
fbad87b0 485 videosRemoveValidator,
fbad87b0 486
74d63469
GR
487 videosChangeOwnershipValidator,
488 videosTerminateChangeOwnershipValidator,
489 videosAcceptChangeOwnershipValidator,
490
418d092a 491 getCommonVideoEditAttributes,
1cd3facc 492
764a9657
C
493 commonVideosFiltersValidator,
494
495 videosOverviewValidator
fbad87b0
C
496}
497
498// ---------------------------------------------------------------------------
499
500function areErrorsInScheduleUpdate (req: express.Request, res: express.Response) {
501 if (req.body.scheduleUpdate) {
502 if (!req.body.scheduleUpdate.updateAt) {
7373507f
C
503 logger.warn('Invalid parameters: scheduleUpdate.updateAt is mandatory.')
504
2d53be02 505 res.status(HttpStatusCode.BAD_REQUEST_400)
fbad87b0 506 .json({ error: 'Schedule update at is mandatory.' })
fbad87b0
C
507
508 return true
509 }
510 }
511
512 return false
513}
b4055e1c
C
514
515async function isVideoAccepted (req: express.Request, res: express.Response, videoFile: Express.Multer.File & { duration?: number }) {
516 // Check we accept this video
517 const acceptParameters = {
518 videoBody: req.body,
519 videoFile,
520 user: res.locals.oauth.token.User
521 }
89cd1275
C
522 const acceptedResult = await Hooks.wrapFun(
523 isLocalVideoAccepted,
524 acceptParameters,
b4055e1c
C
525 'filter:api.video.upload.accept.result'
526 )
527
528 if (!acceptedResult || acceptedResult.accepted !== true) {
529 logger.info('Refused local video.', { acceptedResult, acceptParameters })
2d53be02 530 res.status(HttpStatusCode.FORBIDDEN_403)
b4055e1c
C
531 .json({ error: acceptedResult.errorMessage || 'Refused local video' })
532
533 return false
534 }
535
536 return true
537}