Be tolerant with remote requests
[oweals/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   database as db
15 } from '../../initializers'
16 import { isUserUsernameValid } from './users'
17 import { isArray, exists } from './misc'
18 import { VideoInstance } from '../../models'
19 import { logger } from '../../helpers'
20 import { VideoRateType } from '../../../shared'
21
22 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
23 const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
24 const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS
25
26 function isVideoCategoryValid (value: number) {
27   return VIDEO_CATEGORIES[value] !== undefined
28 }
29
30 // Maybe we don't know the remote category, but that doesn't matter
31 function isRemoteVideoCategoryValid (value: string) {
32   return validator.isInt('' + value)
33 }
34
35 function isVideoLicenceValid (value: number) {
36   return VIDEO_LICENCES[value] !== undefined
37 }
38
39 // Maybe we don't know the remote licence, but that doesn't matter
40 function isRemoteVideoLicenceValid (value: string) {
41   return validator.isInt('' + value)
42 }
43
44 function isVideoLanguageValid (value: number) {
45   return value === null || VIDEO_LANGUAGES[value] !== undefined
46 }
47
48 // Maybe we don't know the remote language, but that doesn't matter
49 function isRemoteVideoLanguageValid (value: string) {
50   return validator.isInt('' + value)
51 }
52
53 function isVideoNSFWValid (value: any) {
54   return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
55 }
56
57 function isVideoDescriptionValid (value: string) {
58   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
59 }
60
61 function isVideoDurationValid (value: string) {
62   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
63 }
64
65 function isVideoNameValid (value: string) {
66   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
67 }
68
69 function isVideoTagsValid (tags: string[]) {
70   return isArray(tags) &&
71          validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
72          tags.every(tag => {
73            return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
74          })
75 }
76
77 function isVideoThumbnailValid (value: string) {
78   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL)
79 }
80
81 function isVideoThumbnailDataValid (value: string) {
82   return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA)
83 }
84
85 function isVideoAbuseReasonValid (value: string) {
86   return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
87 }
88
89 function isVideoAbuseReporterUsernameValid (value: string) {
90   return isUserUsernameValid(value)
91 }
92
93 function isVideoViewsValid (value: string) {
94   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
95 }
96
97 function isVideoLikesValid (value: string) {
98   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES)
99 }
100
101 function isVideoDislikesValid (value: string) {
102   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES)
103 }
104
105 function isVideoEventCountValid (value: string) {
106   return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT)
107 }
108
109 function isVideoRatingTypeValid (value: string) {
110   return values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
111 }
112
113 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
114   // Should have files
115   if (!files) return false
116   if (isArray(files)) return false
117
118   // Should have videofile file
119   const videofile = files['videofile']
120   if (!videofile || videofile.length === 0) return false
121
122   // The file should exist
123   const file = videofile[0]
124   if (!file || !file.originalname) return false
125
126   return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
127 }
128
129 function isVideoFileSizeValid (value: string) {
130   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
131 }
132
133 function isVideoFileResolutionValid (value: string) {
134   return exists(value) && validator.isInt(value + '')
135 }
136
137 function isVideoFileExtnameValid (value: string) {
138   return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
139 }
140
141 function isVideoFileInfoHashValid (value: string) {
142   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
143 }
144
145 function checkVideoExists (id: string, res: express.Response, callback: () => void) {
146   let promise: Promise<VideoInstance>
147   if (validator.isInt(id)) {
148     promise = db.Video.loadAndPopulateAuthorAndPodAndTags(+id)
149   } else { // UUID
150     promise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(id)
151   }
152
153   promise.then(video => {
154     if (!video) {
155       return res.status(404)
156                 .json({ error: 'Video not found' })
157                 .end()
158     }
159
160     res.locals.video = video
161     callback()
162   })
163   .catch(err => {
164     logger.error('Error in video request validator.', err)
165     return res.sendStatus(500)
166   })
167 }
168
169 // ---------------------------------------------------------------------------
170
171 export {
172   isVideoCategoryValid,
173   isVideoLicenceValid,
174   isVideoLanguageValid,
175   isVideoNSFWValid,
176   isVideoDescriptionValid,
177   isVideoDurationValid,
178   isVideoFileInfoHashValid,
179   isVideoNameValid,
180   isVideoTagsValid,
181   isVideoThumbnailValid,
182   isVideoThumbnailDataValid,
183   isVideoFileExtnameValid,
184   isVideoAbuseReasonValid,
185   isVideoAbuseReporterUsernameValid,
186   isVideoFile,
187   isVideoViewsValid,
188   isVideoLikesValid,
189   isVideoRatingTypeValid,
190   isVideoDislikesValid,
191   isVideoEventCountValid,
192   isVideoFileSizeValid,
193   isVideoFileResolutionValid,
194   checkVideoExists,
195   isRemoteVideoCategoryValid,
196   isRemoteVideoLicenceValid,
197   isRemoteVideoLanguageValid
198 }