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