]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/custom-validators/videos.ts
d68de66092253e1f08bd88dacf28d0bc959d095f
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / videos.ts
1 import { values } from 'lodash'
2 import * as validator from 'validator'
3 import * as Promise from 'bluebird'
4 import * as express from 'express'
5 import 'express-validator'
6 import 'multer'
7
8 import {
9 CONSTRAINTS_FIELDS,
10 VIDEO_CATEGORIES,
11 VIDEO_LICENCES,
12 VIDEO_LANGUAGES,
13 VIDEO_RATE_TYPES,
14 VIDEO_PRIVACIES,
15 database as db
16 } from '../../initializers'
17 import { isUserUsernameValid } from './users'
18 import { isArray, exists } from './misc'
19 import { VideoInstance } from '../../models'
20 import { logger } from '../../helpers'
21 import { VideoRateType } from '../../../shared'
22 import { isActivityPubUrlValid } from './activitypub/misc'
23
24 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
25 const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
26 const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS
27
28 function isVideoCategoryValid (value: number) {
29 return VIDEO_CATEGORIES[value] !== undefined
30 }
31
32 // Maybe we don't know the remote category, but that doesn't matter
33 function isRemoteVideoCategoryValid (value: string) {
34 return validator.isInt('' + value)
35 }
36
37 function isVideoUrlValid (value: string) {
38 return isActivityPubUrlValid(value)
39 }
40
41 function isVideoLicenceValid (value: number) {
42 return VIDEO_LICENCES[value] !== undefined
43 }
44
45 function isVideoPrivacyValid (value: string) {
46 return VIDEO_PRIVACIES[value] !== undefined
47 }
48
49 // Maybe we don't know the remote privacy setting, but that doesn't matter
50 function isRemoteVideoPrivacyValid (value: string) {
51 return validator.isInt('' + value)
52 }
53
54 // Maybe we don't know the remote licence, but that doesn't matter
55 function isRemoteVideoLicenceValid (value: string) {
56 return validator.isInt('' + value)
57 }
58
59 function isVideoLanguageValid (value: number) {
60 return value === null || VIDEO_LANGUAGES[value] !== undefined
61 }
62
63 // Maybe we don't know the remote language, but that doesn't matter
64 function isRemoteVideoLanguageValid (value: string) {
65 return validator.isInt('' + value)
66 }
67
68 function isVideoNSFWValid (value: any) {
69 return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
70 }
71
72 function isVideoTruncatedDescriptionValid (value: string) {
73 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
74 }
75
76 function isVideoDescriptionValid (value: string) {
77 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
78 }
79
80 function isVideoDurationValid (value: string) {
81 // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
82 return exists(value) &&
83 typeof value === 'string' &&
84 value.startsWith('PT') &&
85 value.endsWith('S') &&
86 validator.isInt(value.replace(/[^0-9]+/, ''), VIDEOS_CONSTRAINTS_FIELDS.DURATION)
87 }
88
89 function isVideoNameValid (value: string) {
90 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
91 }
92
93 function isVideoTagValid (tag: string) {
94 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
95 }
96
97 function isVideoTagsValid (tags: string[]) {
98 return isArray(tags) &&
99 validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
100 tags.every(tag => isVideoTagValid(tag))
101 }
102
103 function isVideoThumbnailValid (value: string) {
104 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL)
105 }
106
107 function isVideoThumbnailDataValid (value: string) {
108 return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA)
109 }
110
111 function isVideoAbuseReasonValid (value: string) {
112 return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
113 }
114
115 function isVideoAbuseReporterUsernameValid (value: string) {
116 return isUserUsernameValid(value)
117 }
118
119 function isVideoViewsValid (value: string) {
120 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
121 }
122
123 function isVideoLikesValid (value: string) {
124 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES)
125 }
126
127 function isVideoDislikesValid (value: string) {
128 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES)
129 }
130
131 function isVideoEventCountValid (value: string) {
132 return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT)
133 }
134
135 function isVideoRatingTypeValid (value: string) {
136 return values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
137 }
138
139 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
140 // Should have files
141 if (!files) return false
142 if (isArray(files)) return false
143
144 // Should have videofile file
145 const videofile = files['videofile']
146 if (!videofile || videofile.length === 0) return false
147
148 // The file should exist
149 const file = videofile[0]
150 if (!file || !file.originalname) return false
151
152 return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
153 }
154
155 function isVideoFileSizeValid (value: string) {
156 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
157 }
158
159 function isVideoFileResolutionValid (value: string) {
160 return exists(value) && validator.isInt(value + '')
161 }
162
163 function isVideoFileExtnameValid (value: string) {
164 return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
165 }
166
167 function isVideoFileInfoHashValid (value: string) {
168 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
169 }
170
171 function checkVideoExists (id: string, res: express.Response, callback: () => void) {
172 let promise: Promise<VideoInstance>
173 if (validator.isInt(id)) {
174 promise = db.Video.loadAndPopulateAccountAndServerAndTags(+id)
175 } else { // UUID
176 promise = db.Video.loadByUUIDAndPopulateAccountAndServerAndTags(id)
177 }
178
179 promise.then(video => {
180 if (!video) {
181 return res.status(404)
182 .json({ error: 'Video not found' })
183 .end()
184 }
185
186 res.locals.video = video
187 callback()
188 })
189 .catch(err => {
190 logger.error('Error in video request validator.', err)
191 return res.sendStatus(500)
192 })
193 }
194
195 // ---------------------------------------------------------------------------
196
197 export {
198 isVideoCategoryValid,
199 isVideoLicenceValid,
200 isVideoLanguageValid,
201 isVideoNSFWValid,
202 isVideoTruncatedDescriptionValid,
203 isVideoDescriptionValid,
204 isVideoDurationValid,
205 isVideoFileInfoHashValid,
206 isVideoNameValid,
207 isVideoTagsValid,
208 isVideoThumbnailValid,
209 isVideoThumbnailDataValid,
210 isVideoFileExtnameValid,
211 isVideoAbuseReasonValid,
212 isVideoAbuseReporterUsernameValid,
213 isVideoFile,
214 isVideoViewsValid,
215 isVideoLikesValid,
216 isVideoRatingTypeValid,
217 isVideoDislikesValid,
218 isVideoEventCountValid,
219 isVideoFileSizeValid,
220 isVideoPrivacyValid,
221 isRemoteVideoPrivacyValid,
222 isVideoFileResolutionValid,
223 checkVideoExists,
224 isVideoTagValid,
225 isRemoteVideoCategoryValid,
226 isRemoteVideoLicenceValid,
227 isVideoUrlValid,
228 isRemoteVideoLanguageValid
229 }