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 isVideoViewsValid (value: string) {
116 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
119 function isVideoLikesValid (value: string) {
120 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES)
123 function isVideoDislikesValid (value: string) {
124 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES)
127 function isVideoEventCountValid (value: string) {
128 return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT)
131 function isVideoRatingTypeValid (value: string) {
132 return values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
135 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
137 if (!files) return false
138 if (isArray(files)) return false
140 // Should have videofile file
141 const videofile = files['videofile']
142 if (!videofile || videofile.length === 0) return false
144 // The file should exist
145 const file = videofile[0]
146 if (!file || !file.originalname) return false
148 return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
151 function isVideoFileSizeValid (value: string) {
152 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
155 function isVideoFileResolutionValid (value: string) {
156 return exists(value) && validator.isInt(value + '')
159 function isVideoFileExtnameValid (value: string) {
160 return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
163 function isVideoFileInfoHashValid (value: string) {
164 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
167 function checkVideoExists (id: string, res: express.Response, callback: () => void) {
168 let promise: Promise<VideoInstance>
169 if (validator.isInt(id)) {
170 promise = db.Video.loadAndPopulateAccountAndServerAndTags(+id)
172 promise = db.Video.loadByUUIDAndPopulateAccountAndServerAndTags(id)
175 promise.then(video => {
177 return res.status(404)
178 .json({ error: 'Video not found' })
182 res.locals.video = video
186 logger.error('Error in video request validator.', err)
187 return res.sendStatus(500)
191 // ---------------------------------------------------------------------------
194 isVideoCategoryValid,
196 isVideoLanguageValid,
198 isVideoTruncatedDescriptionValid,
199 isVideoDescriptionValid,
200 isVideoDurationValid,
201 isVideoFileInfoHashValid,
204 isVideoThumbnailValid,
205 isVideoThumbnailDataValid,
206 isVideoFileExtnameValid,
207 isVideoAbuseReasonValid,
211 isVideoRatingTypeValid,
212 isVideoDislikesValid,
213 isVideoEventCountValid,
214 isVideoFileSizeValid,
216 isRemoteVideoPrivacyValid,
217 isVideoFileResolutionValid,
220 isRemoteVideoCategoryValid,
221 isRemoteVideoLicenceValid,
223 isRemoteVideoLanguageValid