]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/custom-validators/misc.ts
Bumped to version v5.2.1
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / misc.ts
1 import 'multer'
2 import { UploadFilesForCheck } from 'express'
3 import { sep } from 'path'
4 import validator from 'validator'
5 import { isShortUUID, shortToUUID } from '@shared/extra-utils'
6
7 function exists (value: any) {
8 return value !== undefined && value !== null
9 }
10
11 function isSafePath (p: string) {
12 return exists(p) &&
13 (p + '').split(sep).every(part => {
14 return [ '..' ].includes(part) === false
15 })
16 }
17
18 function isSafeFilename (filename: string, extension?: string) {
19 const regex = extension
20 ? new RegExp(`^[a-z0-9-]+\\.${extension}$`)
21 : new RegExp(`^[a-z0-9-]+\\.[a-z0-9]{1,8}$`)
22
23 return typeof filename === 'string' && !!filename.match(regex)
24 }
25
26 function isSafePeerTubeFilenameWithoutExtension (filename: string) {
27 return filename.match(/^[a-z0-9-]+$/)
28 }
29
30 function isArray (value: any): value is any[] {
31 return Array.isArray(value)
32 }
33
34 function isNotEmptyIntArray (value: any) {
35 return Array.isArray(value) && value.every(v => validator.isInt('' + v)) && value.length !== 0
36 }
37
38 function isNotEmptyStringArray (value: any) {
39 return Array.isArray(value) && value.every(v => typeof v === 'string' && v.length !== 0) && value.length !== 0
40 }
41
42 function isArrayOf (value: any, validator: (value: any) => boolean) {
43 return isArray(value) && value.every(v => validator(v))
44 }
45
46 function isDateValid (value: string) {
47 return exists(value) && validator.isISO8601(value)
48 }
49
50 function isIdValid (value: string) {
51 return exists(value) && validator.isInt('' + value)
52 }
53
54 function isUUIDValid (value: string) {
55 return exists(value) && validator.isUUID('' + value, 4)
56 }
57
58 function areUUIDsValid (values: string[]) {
59 return isArray(values) && values.every(v => isUUIDValid(v))
60 }
61
62 function isIdOrUUIDValid (value: string) {
63 return isIdValid(value) || isUUIDValid(value)
64 }
65
66 function isBooleanValid (value: any) {
67 return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
68 }
69
70 function isIntOrNull (value: any) {
71 return value === null || validator.isInt('' + value)
72 }
73
74 // ---------------------------------------------------------------------------
75
76 function isFileValid (options: {
77 files: UploadFilesForCheck
78
79 maxSize: number | null
80 mimeTypeRegex: string | null
81
82 field?: string
83
84 optional?: boolean // Default false
85 }) {
86 const { files, mimeTypeRegex, field, maxSize, optional = false } = options
87
88 // Should have files
89 if (!files) return optional
90
91 const fileArray = isArray(files)
92 ? files
93 : files[field]
94
95 if (!fileArray || !isArray(fileArray) || fileArray.length === 0) {
96 return optional
97 }
98
99 // The file exists
100 const file = fileArray[0]
101 if (!file?.originalname) return false
102
103 // Check size
104 if ((maxSize !== null) && file.size > maxSize) return false
105
106 if (mimeTypeRegex === null) return true
107
108 return checkMimetypeRegex(file.mimetype, mimeTypeRegex)
109 }
110
111 function checkMimetypeRegex (fileMimeType: string, mimeTypeRegex: string) {
112 return new RegExp(`^${mimeTypeRegex}$`, 'i').test(fileMimeType)
113 }
114
115 // ---------------------------------------------------------------------------
116
117 function toCompleteUUID (value: string) {
118 if (isShortUUID(value)) {
119 try {
120 return shortToUUID(value)
121 } catch {
122 return null
123 }
124 }
125
126 return value
127 }
128
129 function toCompleteUUIDs (values: string[]) {
130 return values.map(v => toCompleteUUID(v))
131 }
132
133 function toIntOrNull (value: string) {
134 const v = toValueOrNull(value)
135
136 if (v === null || v === undefined) return v
137 if (typeof v === 'number') return v
138
139 return validator.toInt('' + v)
140 }
141
142 function toBooleanOrNull (value: any) {
143 const v = toValueOrNull(value)
144
145 if (v === null || v === undefined) return v
146 if (typeof v === 'boolean') return v
147
148 return validator.toBoolean('' + v)
149 }
150
151 function toValueOrNull (value: string) {
152 if (value === 'null') return null
153
154 return value
155 }
156
157 function toIntArray (value: any) {
158 if (!value) return []
159 if (isArray(value) === false) return [ validator.toInt(value) ]
160
161 return value.map(v => validator.toInt(v))
162 }
163
164 // ---------------------------------------------------------------------------
165
166 export {
167 exists,
168 isArrayOf,
169 isNotEmptyIntArray,
170 isArray,
171 isIntOrNull,
172 isIdValid,
173 isSafePath,
174 isNotEmptyStringArray,
175 isUUIDValid,
176 toCompleteUUIDs,
177 toCompleteUUID,
178 isIdOrUUIDValid,
179 isDateValid,
180 toValueOrNull,
181 toBooleanOrNull,
182 isBooleanValid,
183 toIntOrNull,
184 areUUIDsValid,
185 toIntArray,
186 isFileValid,
187 isSafePeerTubeFilenameWithoutExtension,
188 isSafeFilename,
189 checkMimetypeRegex
190 }