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'
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'
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
28 function isVideoCategoryValid (value: number) {
29 return VIDEO_CATEGORIES[value] !== undefined
32 // Maybe we don't know the remote category, but that doesn't matter
33 function isRemoteVideoCategoryValid (value: string) {
34 return validator.isInt('' + value)
37 function isVideoUrlValid (value: string) {
38 return isActivityPubUrlValid(value)
41 function isVideoLicenceValid (value: number) {
42 return VIDEO_LICENCES[value] !== undefined
45 function isVideoPrivacyValid (value: string) {
46 return VIDEO_PRIVACIES[value] !== undefined
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)
54 // Maybe we don't know the remote licence, but that doesn't matter
55 function isRemoteVideoLicenceValid (value: string) {
56 return validator.isInt('' + value)
59 function isVideoLanguageValid (value: number) {
60 return value === null || VIDEO_LANGUAGES[value] !== undefined
63 // Maybe we don't know the remote language, but that doesn't matter
64 function isRemoteVideoLanguageValid (value: string) {
65 return validator.isInt('' + value)
68 function isVideoNSFWValid (value: any) {
69 return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
72 function isVideoTruncatedDescriptionValid (value: string) {
73 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
76 function isVideoDescriptionValid (value: string) {
77 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
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)
89 function isVideoNameValid (value: string) {
90 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
93 function isVideoTagValid (tag: string) {
94 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
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))
103 function isVideoThumbnailValid (value: string) {
104 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL)
107 function isVideoThumbnailDataValid (value: string) {
108 return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA)
111 function isVideoAbuseReasonValid (value: string) {
112 return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
115 function isVideoAbuseReporterUsernameValid (value: string) {
116 return isUserUsernameValid(value)
119 function isVideoViewsValid (value: string) {
120 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
123 function isVideoLikesValid (value: string) {
124 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES)
127 function isVideoDislikesValid (value: string) {
128 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES)
131 function isVideoEventCountValid (value: string) {
132 return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT)
135 function isVideoRatingTypeValid (value: string) {
136 return values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
139 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
141 if (!files) return false
142 if (isArray(files)) return false
144 // Should have videofile file
145 const videofile = files['videofile']
146 if (!videofile || videofile.length === 0) return false
148 // The file should exist
149 const file = videofile[0]
150 if (!file || !file.originalname) return false
152 return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
155 function isVideoFileSizeValid (value: string) {
156 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
159 function isVideoFileResolutionValid (value: string) {
160 return exists(value) && validator.isInt(value + '')
163 function isVideoFileExtnameValid (value: string) {
164 return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
167 function isVideoFileInfoHashValid (value: string) {
168 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
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)
176 promise = db.Video.loadByUUIDAndPopulateAccountAndServerAndTags(id)
179 promise.then(video => {
181 return res.status(404)
182 .json({ error: 'Video not found' })
186 res.locals.video = video
190 logger.error('Error in video request validator.', err)
191 return res.sendStatus(500)
195 // ---------------------------------------------------------------------------
198 isVideoCategoryValid,
200 isVideoLanguageValid,
202 isVideoTruncatedDescriptionValid,
203 isVideoDescriptionValid,
204 isVideoDurationValid,
205 isVideoFileInfoHashValid,
208 isVideoThumbnailValid,
209 isVideoThumbnailDataValid,
210 isVideoFileExtnameValid,
211 isVideoAbuseReasonValid,
212 isVideoAbuseReporterUsernameValid,
216 isVideoRatingTypeValid,
217 isVideoDislikesValid,
218 isVideoEventCountValid,
219 isVideoFileSizeValid,
221 isRemoteVideoPrivacyValid,
222 isVideoFileResolutionValid,
225 isRemoteVideoCategoryValid,
226 isRemoteVideoLicenceValid,
228 isRemoteVideoLanguageValid