Fix images size limit
[oweals/peertube.git] / server / helpers / custom-validators / videos.ts
1 import { Response } from 'express'
2 import 'express-validator'
3 import { values } from 'lodash'
4 import 'multer'
5 import * as validator from 'validator'
6 import { UserRight, VideoPrivacy, VideoRateType } from '../../../shared'
7 import {
8   CONSTRAINTS_FIELDS,
9   VIDEO_CATEGORIES,
10   VIDEO_LICENCES,
11   VIDEO_MIMETYPE_EXT,
12   VIDEO_PRIVACIES,
13   VIDEO_RATE_TYPES,
14   VIDEO_STATES
15 } from '../../initializers'
16 import { VideoModel } from '../../models/video/video'
17 import { exists, isArray, isFileValid } from './misc'
18 import { VideoChannelModel } from '../../models/video/video-channel'
19 import { UserModel } from '../../models/account/user'
20
21 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
22 const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
23
24 function isVideoCategoryValid (value: any) {
25   return value === null || VIDEO_CATEGORIES[ value ] !== undefined
26 }
27
28 function isVideoStateValid (value: any) {
29   return exists(value) && VIDEO_STATES[ value ] !== undefined
30 }
31
32 function isVideoLicenceValid (value: any) {
33   return value === null || VIDEO_LICENCES[ value ] !== undefined
34 }
35
36 function isVideoLanguageValid (value: any) {
37   return value === null ||
38     (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
39 }
40
41 function isVideoDurationValid (value: string) {
42   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
43 }
44
45 function isVideoTruncatedDescriptionValid (value: string) {
46   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
47 }
48
49 function isVideoDescriptionValid (value: string) {
50   return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
51 }
52
53 function isVideoSupportValid (value: string) {
54   return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
55 }
56
57 function isVideoNameValid (value: string) {
58   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
59 }
60
61 function isVideoTagValid (tag: string) {
62   return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
63 }
64
65 function isVideoTagsValid (tags: string[]) {
66   return tags === null || (
67     isArray(tags) &&
68     validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
69     tags.every(tag => isVideoTagValid(tag))
70   )
71 }
72
73 function isVideoAbuseReasonValid (value: string) {
74   return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
75 }
76
77 function isVideoViewsValid (value: string) {
78   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
79 }
80
81 function isVideoRatingTypeValid (value: string) {
82   return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
83 }
84
85 const videoFileTypes = Object.keys(VIDEO_MIMETYPE_EXT).map(m => `(${m})`)
86 const videoFileTypesRegex = videoFileTypes.join('|')
87
88 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
89   return isFileValid(files, videoFileTypesRegex, 'videofile', null)
90 }
91
92 const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
93                                           .map(v => v.replace('.', ''))
94                                           .join('|')
95 const videoImageTypesRegex = `image/(${videoImageTypes})`
96
97 function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
98   return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true)
99 }
100
101 function isVideoPrivacyValid (value: number) {
102   return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
103 }
104
105 function isScheduleVideoUpdatePrivacyValid (value: number) {
106   return validator.isInt(value + '') &&
107     (
108       value === VideoPrivacy.UNLISTED ||
109       value === VideoPrivacy.PUBLIC
110     )
111 }
112
113 function isVideoFileInfoHashValid (value: string) {
114   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
115 }
116
117 function isVideoFileResolutionValid (value: string) {
118   return exists(value) && validator.isInt(value + '')
119 }
120
121 function isVideoFileSizeValid (value: string) {
122   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
123 }
124
125 async function isVideoExist (id: string, res: Response) {
126   let video: VideoModel
127
128   if (validator.isInt(id)) {
129     video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id)
130   } else { // UUID
131     video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id)
132   }
133
134   if (!video) {
135     res.status(404)
136        .json({ error: 'Video not found' })
137        .end()
138
139     return false
140   }
141
142   res.locals.video = video
143   return true
144 }
145
146 async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
147   if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
148     const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
149     if (!videoChannel) {
150       res.status(400)
151          .json({ error: 'Unknown video video channel on this instance.' })
152          .end()
153
154       return false
155     }
156
157     res.locals.videoChannel = videoChannel
158     return true
159   }
160
161   const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
162   if (!videoChannel) {
163     res.status(400)
164        .json({ error: 'Unknown video video channel for this account.' })
165        .end()
166
167     return false
168   }
169
170   res.locals.videoChannel = videoChannel
171   return true
172 }
173
174 // ---------------------------------------------------------------------------
175
176 export {
177   isVideoCategoryValid,
178   isVideoLicenceValid,
179   isVideoLanguageValid,
180   isVideoTruncatedDescriptionValid,
181   isVideoDescriptionValid,
182   isVideoFileInfoHashValid,
183   isVideoNameValid,
184   isVideoTagsValid,
185   isScheduleVideoUpdatePrivacyValid,
186   isVideoAbuseReasonValid,
187   isVideoFile,
188   isVideoStateValid,
189   isVideoViewsValid,
190   isVideoRatingTypeValid,
191   isVideoDurationValid,
192   isVideoTagValid,
193   isVideoPrivacyValid,
194   isVideoFileResolutionValid,
195   isVideoFileSizeValid,
196   isVideoExist,
197   isVideoImage,
198   isVideoChannelOfAccountExist,
199   isVideoSupportValid
200 }