]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/custom-validators/videos.ts
Add video abuse to activity pub
[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 isVideoViewsValid (value: string) {
116 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
117 }
118
119 function isVideoLikesValid (value: string) {
120 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES)
121 }
122
123 function isVideoDislikesValid (value: string) {
124 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES)
125 }
126
127 function isVideoEventCountValid (value: string) {
128 return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT)
129 }
130
131 function isVideoRatingTypeValid (value: string) {
132 return values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
133 }
134
135 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
136 // Should have files
137 if (!files) return false
138 if (isArray(files)) return false
139
140 // Should have videofile file
141 const videofile = files['videofile']
142 if (!videofile || videofile.length === 0) return false
143
144 // The file should exist
145 const file = videofile[0]
146 if (!file || !file.originalname) return false
147
148 return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
149 }
150
151 function isVideoFileSizeValid (value: string) {
152 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
153 }
154
155 function isVideoFileResolutionValid (value: string) {
156 return exists(value) && validator.isInt(value + '')
157 }
158
159 function isVideoFileExtnameValid (value: string) {
160 return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
161 }
162
163 function isVideoFileInfoHashValid (value: string) {
164 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
165 }
166
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)
171 } else { // UUID
172 promise = db.Video.loadByUUIDAndPopulateAccountAndServerAndTags(id)
173 }
174
175 promise.then(video => {
176 if (!video) {
177 return res.status(404)
178 .json({ error: 'Video not found' })
179 .end()
180 }
181
182 res.locals.video = video
183 callback()
184 })
185 .catch(err => {
186 logger.error('Error in video request validator.', err)
187 return res.sendStatus(500)
188 })
189 }
190
191 // ---------------------------------------------------------------------------
192
193 export {
194 isVideoCategoryValid,
195 isVideoLicenceValid,
196 isVideoLanguageValid,
197 isVideoNSFWValid,
198 isVideoTruncatedDescriptionValid,
199 isVideoDescriptionValid,
200 isVideoDurationValid,
201 isVideoFileInfoHashValid,
202 isVideoNameValid,
203 isVideoTagsValid,
204 isVideoThumbnailValid,
205 isVideoThumbnailDataValid,
206 isVideoFileExtnameValid,
207 isVideoAbuseReasonValid,
208 isVideoFile,
209 isVideoViewsValid,
210 isVideoLikesValid,
211 isVideoRatingTypeValid,
212 isVideoDislikesValid,
213 isVideoEventCountValid,
214 isVideoFileSizeValid,
215 isVideoPrivacyValid,
216 isRemoteVideoPrivacyValid,
217 isVideoFileResolutionValid,
218 checkVideoExists,
219 isVideoTagValid,
220 isRemoteVideoCategoryValid,
221 isRemoteVideoLicenceValid,
222 isVideoUrlValid,
223 isRemoteVideoLanguageValid
224 }