diff options
Diffstat (limited to 'server/server/helpers/custom-validators/runners/jobs.ts')
-rw-r--r-- | server/server/helpers/custom-validators/runners/jobs.ts | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/server/server/helpers/custom-validators/runners/jobs.ts b/server/server/helpers/custom-validators/runners/jobs.ts new file mode 100644 index 000000000..78c6c2e1e --- /dev/null +++ b/server/server/helpers/custom-validators/runners/jobs.ts | |||
@@ -0,0 +1,197 @@ | |||
1 | import { UploadFilesForCheck } from 'express' | ||
2 | import validator from 'validator' | ||
3 | import { CONSTRAINTS_FIELDS, RUNNER_JOB_STATES } from '@server/initializers/constants.js' | ||
4 | import { | ||
5 | LiveRTMPHLSTranscodingSuccess, | ||
6 | RunnerJobSuccessPayload, | ||
7 | RunnerJobType, | ||
8 | RunnerJobUpdatePayload, | ||
9 | VideoStudioTranscodingSuccess, | ||
10 | VODAudioMergeTranscodingSuccess, | ||
11 | VODHLSTranscodingSuccess, | ||
12 | VODWebVideoTranscodingSuccess | ||
13 | } from '@peertube/peertube-models' | ||
14 | import { exists, isArray, isFileValid, isSafeFilename } from '../misc.js' | ||
15 | |||
16 | const RUNNER_JOBS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.RUNNER_JOBS | ||
17 | |||
18 | const runnerJobTypes = new Set([ 'vod-hls-transcoding', 'vod-web-video-transcoding', 'vod-audio-merge-transcoding' ]) | ||
19 | function isRunnerJobTypeValid (value: RunnerJobType) { | ||
20 | return runnerJobTypes.has(value) | ||
21 | } | ||
22 | |||
23 | function isRunnerJobSuccessPayloadValid (value: RunnerJobSuccessPayload, type: RunnerJobType, files: UploadFilesForCheck) { | ||
24 | return isRunnerJobVODWebVideoResultPayloadValid(value as VODWebVideoTranscodingSuccess, type, files) || | ||
25 | isRunnerJobVODHLSResultPayloadValid(value as VODHLSTranscodingSuccess, type, files) || | ||
26 | isRunnerJobVODAudioMergeResultPayloadValid(value as VODHLSTranscodingSuccess, type, files) || | ||
27 | isRunnerJobLiveRTMPHLSResultPayloadValid(value as LiveRTMPHLSTranscodingSuccess, type) || | ||
28 | isRunnerJobVideoStudioResultPayloadValid(value as VideoStudioTranscodingSuccess, type, files) | ||
29 | } | ||
30 | |||
31 | // --------------------------------------------------------------------------- | ||
32 | |||
33 | function isRunnerJobProgressValid (value: string) { | ||
34 | return validator.default.isInt(value + '', RUNNER_JOBS_CONSTRAINTS_FIELDS.PROGRESS) | ||
35 | } | ||
36 | |||
37 | function isRunnerJobUpdatePayloadValid (value: RunnerJobUpdatePayload, type: RunnerJobType, files: UploadFilesForCheck) { | ||
38 | return isRunnerJobVODWebVideoUpdatePayloadValid(value, type, files) || | ||
39 | isRunnerJobVODHLSUpdatePayloadValid(value, type, files) || | ||
40 | isRunnerJobVideoStudioUpdatePayloadValid(value, type, files) || | ||
41 | isRunnerJobVODAudioMergeUpdatePayloadValid(value, type, files) || | ||
42 | isRunnerJobLiveRTMPHLSUpdatePayloadValid(value, type, files) | ||
43 | } | ||
44 | |||
45 | // --------------------------------------------------------------------------- | ||
46 | |||
47 | function isRunnerJobTokenValid (value: string) { | ||
48 | return exists(value) && validator.default.isLength(value, RUNNER_JOBS_CONSTRAINTS_FIELDS.TOKEN) | ||
49 | } | ||
50 | |||
51 | function isRunnerJobAbortReasonValid (value: string) { | ||
52 | return validator.default.isLength(value, RUNNER_JOBS_CONSTRAINTS_FIELDS.REASON) | ||
53 | } | ||
54 | |||
55 | function isRunnerJobErrorMessageValid (value: string) { | ||
56 | return validator.default.isLength(value, RUNNER_JOBS_CONSTRAINTS_FIELDS.ERROR_MESSAGE) | ||
57 | } | ||
58 | |||
59 | function isRunnerJobStateValid (value: any) { | ||
60 | return exists(value) && RUNNER_JOB_STATES[value] !== undefined | ||
61 | } | ||
62 | |||
63 | function isRunnerJobArrayOfStateValid (value: any) { | ||
64 | return isArray(value) && value.every(v => isRunnerJobStateValid(v)) | ||
65 | } | ||
66 | |||
67 | // --------------------------------------------------------------------------- | ||
68 | |||
69 | export { | ||
70 | isRunnerJobTypeValid, | ||
71 | isRunnerJobSuccessPayloadValid, | ||
72 | isRunnerJobUpdatePayloadValid, | ||
73 | isRunnerJobTokenValid, | ||
74 | isRunnerJobErrorMessageValid, | ||
75 | isRunnerJobProgressValid, | ||
76 | isRunnerJobAbortReasonValid, | ||
77 | isRunnerJobArrayOfStateValid, | ||
78 | isRunnerJobStateValid | ||
79 | } | ||
80 | |||
81 | // --------------------------------------------------------------------------- | ||
82 | |||
83 | function isRunnerJobVODWebVideoResultPayloadValid ( | ||
84 | _value: VODWebVideoTranscodingSuccess, | ||
85 | type: RunnerJobType, | ||
86 | files: UploadFilesForCheck | ||
87 | ) { | ||
88 | return type === 'vod-web-video-transcoding' && | ||
89 | isFileValid({ files, field: 'payload[videoFile]', mimeTypeRegex: null, maxSize: null }) | ||
90 | } | ||
91 | |||
92 | function isRunnerJobVODHLSResultPayloadValid ( | ||
93 | _value: VODHLSTranscodingSuccess, | ||
94 | type: RunnerJobType, | ||
95 | files: UploadFilesForCheck | ||
96 | ) { | ||
97 | return type === 'vod-hls-transcoding' && | ||
98 | isFileValid({ files, field: 'payload[videoFile]', mimeTypeRegex: null, maxSize: null }) && | ||
99 | isFileValid({ files, field: 'payload[resolutionPlaylistFile]', mimeTypeRegex: null, maxSize: null }) | ||
100 | } | ||
101 | |||
102 | function isRunnerJobVODAudioMergeResultPayloadValid ( | ||
103 | _value: VODAudioMergeTranscodingSuccess, | ||
104 | type: RunnerJobType, | ||
105 | files: UploadFilesForCheck | ||
106 | ) { | ||
107 | return type === 'vod-audio-merge-transcoding' && | ||
108 | isFileValid({ files, field: 'payload[videoFile]', mimeTypeRegex: null, maxSize: null }) | ||
109 | } | ||
110 | |||
111 | function isRunnerJobLiveRTMPHLSResultPayloadValid ( | ||
112 | value: LiveRTMPHLSTranscodingSuccess, | ||
113 | type: RunnerJobType | ||
114 | ) { | ||
115 | return type === 'live-rtmp-hls-transcoding' && (!value || (typeof value === 'object' && Object.keys(value).length === 0)) | ||
116 | } | ||
117 | |||
118 | function isRunnerJobVideoStudioResultPayloadValid ( | ||
119 | _value: VideoStudioTranscodingSuccess, | ||
120 | type: RunnerJobType, | ||
121 | files: UploadFilesForCheck | ||
122 | ) { | ||
123 | return type === 'video-studio-transcoding' && | ||
124 | isFileValid({ files, field: 'payload[videoFile]', mimeTypeRegex: null, maxSize: null }) | ||
125 | } | ||
126 | |||
127 | // --------------------------------------------------------------------------- | ||
128 | |||
129 | function isRunnerJobVODWebVideoUpdatePayloadValid ( | ||
130 | value: RunnerJobUpdatePayload, | ||
131 | type: RunnerJobType, | ||
132 | _files: UploadFilesForCheck | ||
133 | ) { | ||
134 | return type === 'vod-web-video-transcoding' && | ||
135 | (!value || (typeof value === 'object' && Object.keys(value).length === 0)) | ||
136 | } | ||
137 | |||
138 | function isRunnerJobVODHLSUpdatePayloadValid ( | ||
139 | value: RunnerJobUpdatePayload, | ||
140 | type: RunnerJobType, | ||
141 | _files: UploadFilesForCheck | ||
142 | ) { | ||
143 | return type === 'vod-hls-transcoding' && | ||
144 | (!value || (typeof value === 'object' && Object.keys(value).length === 0)) | ||
145 | } | ||
146 | |||
147 | function isRunnerJobVODAudioMergeUpdatePayloadValid ( | ||
148 | value: RunnerJobUpdatePayload, | ||
149 | type: RunnerJobType, | ||
150 | _files: UploadFilesForCheck | ||
151 | ) { | ||
152 | return type === 'vod-audio-merge-transcoding' && | ||
153 | (!value || (typeof value === 'object' && Object.keys(value).length === 0)) | ||
154 | } | ||
155 | |||
156 | function isRunnerJobLiveRTMPHLSUpdatePayloadValid ( | ||
157 | value: RunnerJobUpdatePayload, | ||
158 | type: RunnerJobType, | ||
159 | files: UploadFilesForCheck | ||
160 | ) { | ||
161 | let result = type === 'live-rtmp-hls-transcoding' && !!value && !!files | ||
162 | |||
163 | result &&= isFileValid({ files, field: 'payload[masterPlaylistFile]', mimeTypeRegex: null, maxSize: null, optional: true }) | ||
164 | |||
165 | result &&= isFileValid({ | ||
166 | files, | ||
167 | field: 'payload[resolutionPlaylistFile]', | ||
168 | mimeTypeRegex: null, | ||
169 | maxSize: null, | ||
170 | optional: !value.resolutionPlaylistFilename | ||
171 | }) | ||
172 | |||
173 | if (files['payload[resolutionPlaylistFile]']) { | ||
174 | result &&= isSafeFilename(value.resolutionPlaylistFilename, 'm3u8') | ||
175 | } | ||
176 | |||
177 | return result && | ||
178 | isSafeFilename(value.videoChunkFilename, 'ts') && | ||
179 | ( | ||
180 | ( | ||
181 | value.type === 'remove-chunk' | ||
182 | ) || | ||
183 | ( | ||
184 | value.type === 'add-chunk' && | ||
185 | isFileValid({ files, field: 'payload[videoChunkFile]', mimeTypeRegex: null, maxSize: null }) | ||
186 | ) | ||
187 | ) | ||
188 | } | ||
189 | |||
190 | function isRunnerJobVideoStudioUpdatePayloadValid ( | ||
191 | value: RunnerJobUpdatePayload, | ||
192 | type: RunnerJobType, | ||
193 | _files: UploadFilesForCheck | ||
194 | ) { | ||
195 | return type === 'video-studio-transcoding' && | ||
196 | (!value || (typeof value === 'object' && Object.keys(value).length === 0)) | ||
197 | } | ||