aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/middlewares/validators/videos.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/middlewares/validators/videos.ts')
-rw-r--r--server/middlewares/validators/videos.ts252
1 files changed, 121 insertions, 131 deletions
diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts
index 5ffc85210..3cbf98312 100644
--- a/server/middlewares/validators/videos.ts
+++ b/server/middlewares/validators/videos.ts
@@ -3,11 +3,11 @@ import { body, param, query } from 'express-validator/check'
3import { UserRight, VideoPrivacy } from '../../../shared' 3import { UserRight, VideoPrivacy } from '../../../shared'
4import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc' 4import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc'
5import { 5import {
6 checkVideoExists,
7 isVideoAbuseReasonValid, 6 isVideoAbuseReasonValid,
8 isVideoCategoryValid, 7 isVideoCategoryValid,
9 isVideoDescriptionValid, 8 isVideoDescriptionValid,
10 isVideoDurationValid, 9 isVideoDurationValid,
10 isVideoExist,
11 isVideoFile, 11 isVideoFile,
12 isVideoLanguageValid, 12 isVideoLanguageValid,
13 isVideoLicenceValid, 13 isVideoLicenceValid,
@@ -20,12 +20,11 @@ import {
20import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils' 20import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
21import { logger } from '../../helpers/logger' 21import { logger } from '../../helpers/logger'
22import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers' 22import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers'
23
24import { database as db } from '../../initializers/database' 23import { database as db } from '../../initializers/database'
25import { UserInstance } from '../../models/account/user-interface' 24import { UserInstance } from '../../models/account/user-interface'
25import { VideoInstance } from '../../models/video/video-interface'
26import { authenticate } from '../oauth' 26import { authenticate } from '../oauth'
27import { areValidationErrors, checkErrors } from './utils' 27import { areValidationErrors } from './utils'
28import { isVideoExistsPromise } from '../../helpers/index'
29 28
30const videosAddValidator = [ 29const videosAddValidator = [
31 body('videofile').custom((value, { req }) => isVideoFile(req.files)).withMessage( 30 body('videofile').custom((value, { req }) => isVideoFile(req.files)).withMessage(
@@ -42,68 +41,58 @@ const videosAddValidator = [
42 body('privacy').custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'), 41 body('privacy').custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
43 body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'), 42 body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'),
44 43
45 (req: express.Request, res: express.Response, next: express.NextFunction) => { 44 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
46 logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files }) 45 logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files })
47 46
48 checkErrors(req, res, () => { 47 if (areValidationErrors(req, res)) return
49 const videoFile: Express.Multer.File = req.files['videofile'][0] 48
50 const user = res.locals.oauth.token.User 49 const videoFile: Express.Multer.File = req.files['videofile'][0]
50 const user = res.locals.oauth.token.User
51 51
52 return db.VideoChannel.loadByIdAndAccount(req.body.channelId, user.Account.id) 52 const videoChannel = await db.VideoChannel.loadByIdAndAccount(req.body.channelId, user.Account.id)
53 .then(videoChannel => { 53 if (!videoChannel) {
54 if (!videoChannel) { 54 res.status(400)
55 res.status(400) 55 .json({ error: 'Unknown video video channel for this account.' })
56 .json({ error: 'Unknown video video channel for this account.' }) 56 .end()
57 .end()
58 57
59 return undefined 58 return
60 } 59 }
61 60
62 res.locals.videoChannel = videoChannel 61 res.locals.videoChannel = videoChannel
63 62
64 return user.isAbleToUploadVideo(videoFile) 63 const isAble = await user.isAbleToUploadVideo(videoFile)
65 }) 64 if (isAble === false) {
66 .then(isAble => { 65 res.status(403)
67 if (isAble === false) { 66 .json({ error: 'The user video quota is exceeded with this video.' })
68 res.status(403) 67 .end()
69 .json({ error: 'The user video quota is exceeded with this video.' }) 68
70 .end() 69 return
71 70 }
72 return undefined 71
73 } 72 let duration: number
74 73
75 return getDurationFromVideoFile(videoFile.path) 74 try {
76 .catch(err => { 75 duration = await getDurationFromVideoFile(videoFile.path)
77 logger.error('Invalid input file in videosAddValidator.', err) 76 } catch (err) {
78 res.status(400) 77 logger.error('Invalid input file in videosAddValidator.', err)
79 .json({ error: 'Invalid input file.' }) 78 res.status(400)
80 .end() 79 .json({ error: 'Invalid input file.' })
81 80 .end()
82 return undefined 81
83 }) 82 return
84 }) 83 }
85 .then(duration => { 84
86 // Previous test failed, abort 85 if (!isVideoDurationValid('' + duration)) {
87 if (duration === undefined) return undefined 86 return res.status(400)
88 87 .json({
89 if (!isVideoDurationValid('' + duration)) { 88 error: 'Duration of the video file is too big (max: ' + CONSTRAINTS_FIELDS.VIDEOS.DURATION.max + 's).'
90 return res.status(400) 89 })
91 .json({ 90 .end()
92 error: 'Duration of the video file is too big (max: ' + CONSTRAINTS_FIELDS.VIDEOS.DURATION.max + 's).' 91 }
93 }) 92
94 .end() 93 videoFile['duration'] = duration
95 } 94
96 95 return next()
97 videoFile['duration'] = duration
98 next()
99 })
100 .catch(err => {
101 logger.error('Error in video add validator', err)
102 res.sendStatus(500)
103
104 return undefined
105 })
106 })
107 } 96 }
108] 97]
109 98
@@ -118,61 +107,59 @@ const videosUpdateValidator = [
118 body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'), 107 body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
119 body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'), 108 body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'),
120 109
121 (req: express.Request, res: express.Response, next: express.NextFunction) => { 110 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
122 logger.debug('Checking videosUpdate parameters', { parameters: req.body }) 111 logger.debug('Checking videosUpdate parameters', { parameters: req.body })
123 112
124 checkErrors(req, res, () => { 113 if (areValidationErrors(req, res)) return
125 checkVideoExists(req.params.id, res, () => { 114 if (!await isVideoExist(req.params.id, res)) return
126 const video = res.locals.video 115
127 116 const video = res.locals.video
128 // We need to make additional checks 117
129 if (video.isOwned() === false) { 118 // We need to make additional checks
130 return res.status(403) 119 if (video.isOwned() === false) {
131 .json({ error: 'Cannot update video of another server' }) 120 return res.status(403)
132 .end() 121 .json({ error: 'Cannot update video of another server' })
133 } 122 .end()
134 123 }
135 if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) { 124
136 return res.status(403) 125 if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) {
137 .json({ error: 'Cannot update video of another user' }) 126 return res.status(403)
138 .end() 127 .json({ error: 'Cannot update video of another user' })
139 } 128 .end()
140 129 }
141 if (video.privacy !== VideoPrivacy.PRIVATE && req.body.privacy === VideoPrivacy.PRIVATE) { 130
142 return res.status(409) 131 if (video.privacy !== VideoPrivacy.PRIVATE && req.body.privacy === VideoPrivacy.PRIVATE) {
143 .json({ error: 'Cannot set "private" a video that was not private anymore.' }) 132 return res.status(409)
144 .end() 133 .json({ error: 'Cannot set "private" a video that was not private anymore.' })
145 } 134 .end()
146 135 }
147 next() 136
148 }) 137 return next()
149 })
150 } 138 }
151] 139]
152 140
153const videosGetValidator = [ 141const videosGetValidator = [
154 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 142 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
155 143
156 (req: express.Request, res: express.Response, next: express.NextFunction) => { 144 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
157 logger.debug('Checking videosGet parameters', { parameters: req.params }) 145 logger.debug('Checking videosGet parameters', { parameters: req.params })
158 146
159 checkErrors(req, res, () => { 147 if (areValidationErrors(req, res)) return
160 checkVideoExists(req.params.id, res, () => { 148 if (!await isVideoExist(req.params.id, res)) return
161 const video = res.locals.video
162 149
163 // Video is not private, anyone can access it 150 const video = res.locals.video
164 if (video.privacy !== VideoPrivacy.PRIVATE) return next()
165 151
166 authenticate(req, res, () => { 152 // Video is not private, anyone can access it
167 if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) { 153 if (video.privacy !== VideoPrivacy.PRIVATE) return next()
168 return res.status(403)
169 .json({ error: 'Cannot get this private video of another user' })
170 .end()
171 }
172 154
173 next() 155 authenticate(req, res, () => {
174 }) 156 if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) {
175 }) 157 return res.status(403)
158 .json({ error: 'Cannot get this private video of another user' })
159 .end()
160 }
161
162 return next()
176 }) 163 })
177 } 164 }
178] 165]
@@ -180,17 +167,16 @@ const videosGetValidator = [
180const videosRemoveValidator = [ 167const videosRemoveValidator = [
181 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 168 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
182 169
183 (req: express.Request, res: express.Response, next: express.NextFunction) => { 170 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
184 logger.debug('Checking videosRemove parameters', { parameters: req.params }) 171 logger.debug('Checking videosRemove parameters', { parameters: req.params })
185 172
186 checkErrors(req, res, () => { 173 if (areValidationErrors(req, res)) return
187 checkVideoExists(req.params.id, res, () => { 174 if (!await isVideoExist(req.params.id, res)) return
188 // Check if the user who did the request is able to delete the video 175
189 checkUserCanDeleteVideo(res.locals.oauth.token.User, res, () => { 176 // Check if the user who did the request is able to delete the video
190 next() 177 if (!checkUserCanDeleteVideo(res.locals.oauth.token.User, res.locals.video, res)) return
191 }) 178
192 }) 179 return next()
193 })
194 } 180 }
195] 181]
196 182
@@ -201,7 +187,9 @@ const videosSearchValidator = [
201 (req: express.Request, res: express.Response, next: express.NextFunction) => { 187 (req: express.Request, res: express.Response, next: express.NextFunction) => {
202 logger.debug('Checking videosSearch parameters', { parameters: req.params }) 188 logger.debug('Checking videosSearch parameters', { parameters: req.params })
203 189
204 checkErrors(req, res, next) 190 if (areValidationErrors(req, res)) return
191
192 return next()
205 } 193 }
206] 194]
207 195
@@ -209,12 +197,13 @@ const videoAbuseReportValidator = [
209 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 197 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
210 body('reason').custom(isVideoAbuseReasonValid).withMessage('Should have a valid reason'), 198 body('reason').custom(isVideoAbuseReasonValid).withMessage('Should have a valid reason'),
211 199
212 (req: express.Request, res: express.Response, next: express.NextFunction) => { 200 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
213 logger.debug('Checking videoAbuseReport parameters', { parameters: req.body }) 201 logger.debug('Checking videoAbuseReport parameters', { parameters: req.body })
214 202
215 checkErrors(req, res, () => { 203 if (areValidationErrors(req, res)) return
216 checkVideoExists(req.params.id, res, next) 204 if (!await isVideoExist(req.params.id, res)) return
217 }) 205
206 return next()
218 } 207 }
219] 208]
220 209
@@ -222,12 +211,13 @@ const videoRateValidator = [
222 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 211 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
223 body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'), 212 body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'),
224 213
225 (req: express.Request, res: express.Response, next: express.NextFunction) => { 214 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
226 logger.debug('Checking videoRate parameters', { parameters: req.body }) 215 logger.debug('Checking videoRate parameters', { parameters: req.body })
227 216
228 checkErrors(req, res, () => { 217 if (areValidationErrors(req, res)) return
229 checkVideoExists(req.params.id, res, next) 218 if (!await isVideoExist(req.params.id, res)) return
230 }) 219
220 return next()
231 } 221 }
232] 222]
233 223
@@ -239,7 +229,7 @@ const videosShareValidator = [
239 logger.debug('Checking videoShare parameters', { parameters: req.params }) 229 logger.debug('Checking videoShare parameters', { parameters: req.params })
240 230
241 if (areValidationErrors(req, res)) return 231 if (areValidationErrors(req, res)) return
242 if (!await isVideoExistsPromise(req.params.id, res)) return 232 if (!await isVideoExist(req.params.id, res)) return
243 233
244 const share = await db.VideoShare.load(req.params.accountId, res.locals.video.id) 234 const share = await db.VideoShare.load(req.params.accountId, res.locals.video.id)
245 if (!share) { 235 if (!share) {
@@ -248,7 +238,6 @@ const videosShareValidator = [
248 } 238 }
249 239
250 res.locals.videoShare = share 240 res.locals.videoShare = share
251
252 return next() 241 return next()
253 } 242 }
254] 243]
@@ -270,24 +259,25 @@ export {
270 259
271// --------------------------------------------------------------------------- 260// ---------------------------------------------------------------------------
272 261
273function checkUserCanDeleteVideo (user: UserInstance, res: express.Response, callback: () => void) { 262function checkUserCanDeleteVideo (user: UserInstance, video: VideoInstance, res: express.Response) {
274 // Retrieve the user who did the request 263 // Retrieve the user who did the request
275 if (res.locals.video.isOwned() === false) { 264 if (video.isOwned() === false) {
276 return res.status(403) 265 res.status(403)
277 .json({ error: 'Cannot remove video of another server, blacklist it' }) 266 .json({ error: 'Cannot remove video of another server, blacklist it' })
278 .end() 267 .end()
268 return false
279 } 269 }
280 270
281 // Check if the user can delete the video 271 // Check if the user can delete the video
282 // The user can delete it if s/he is an admin 272 // The user can delete it if s/he is an admin
283 // Or if s/he is the video's account 273 // Or if s/he is the video's account
284 const account = res.locals.video.VideoChannel.Account 274 const account = video.VideoChannel.Account
285 if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && account.userId !== user.id) { 275 if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && account.userId !== user.id) {
286 return res.status(403) 276 res.status(403)
287 .json({ error: 'Cannot remove video of another user' }) 277 .json({ error: 'Cannot remove video of another user' })
288 .end() 278 .end()
279 return false
289 } 280 }
290 281
291 // If we reach this comment, we can delete the video 282 return true
292 callback()
293} 283}