diff options
Diffstat (limited to 'server/middlewares')
-rw-r--r-- | server/middlewares/auth.ts | 27 | ||||
-rw-r--r-- | server/middlewares/doc.ts | 2 | ||||
-rw-r--r-- | server/middlewares/error.ts | 6 | ||||
-rw-r--r-- | server/middlewares/rate-limiter.ts | 28 | ||||
-rw-r--r-- | server/middlewares/validators/config.ts | 2 | ||||
-rw-r--r-- | server/middlewares/validators/runners/index.ts | 3 | ||||
-rw-r--r-- | server/middlewares/validators/runners/job-files.ts | 27 | ||||
-rw-r--r-- | server/middlewares/validators/runners/jobs.ts | 156 | ||||
-rw-r--r-- | server/middlewares/validators/runners/registration-token.ts | 37 | ||||
-rw-r--r-- | server/middlewares/validators/runners/runners.ts | 95 | ||||
-rw-r--r-- | server/middlewares/validators/sort.ts | 4 | ||||
-rw-r--r-- | server/middlewares/validators/videos/video-live.ts | 9 | ||||
-rw-r--r-- | server/middlewares/validators/videos/video-studio.ts | 2 | ||||
-rw-r--r-- | server/middlewares/validators/videos/videos.ts | 2 |
14 files changed, 387 insertions, 13 deletions
diff --git a/server/middlewares/auth.ts b/server/middlewares/auth.ts index e6025c8ce..0eefa2a8e 100644 --- a/server/middlewares/auth.ts +++ b/server/middlewares/auth.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { Socket } from 'socket.io' | 2 | import { Socket } from 'socket.io' |
3 | import { getAccessToken } from '@server/lib/auth/oauth-model' | 3 | import { getAccessToken } from '@server/lib/auth/oauth-model' |
4 | import { RunnerModel } from '@server/models/runner/runner' | ||
4 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' | 5 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' |
5 | import { logger } from '../helpers/logger' | 6 | import { logger } from '../helpers/logger' |
6 | import { handleOAuthAuthenticate } from '../lib/auth/oauth' | 7 | import { handleOAuthAuthenticate } from '../lib/auth/oauth' |
@@ -27,7 +28,7 @@ function authenticate (req: express.Request, res: express.Response, next: expres | |||
27 | function authenticateSocket (socket: Socket, next: (err?: any) => void) { | 28 | function authenticateSocket (socket: Socket, next: (err?: any) => void) { |
28 | const accessToken = socket.handshake.query['accessToken'] | 29 | const accessToken = socket.handshake.query['accessToken'] |
29 | 30 | ||
30 | logger.debug('Checking socket access token %s.', accessToken) | 31 | logger.debug('Checking access token in runner.') |
31 | 32 | ||
32 | if (!accessToken) return next(new Error('No access token provided')) | 33 | if (!accessToken) return next(new Error('No access token provided')) |
33 | if (typeof accessToken !== 'string') return next(new Error('Access token is invalid')) | 34 | if (typeof accessToken !== 'string') return next(new Error('Access token is invalid')) |
@@ -73,9 +74,31 @@ function optionalAuthenticate (req: express.Request, res: express.Response, next | |||
73 | 74 | ||
74 | // --------------------------------------------------------------------------- | 75 | // --------------------------------------------------------------------------- |
75 | 76 | ||
77 | function authenticateRunnerSocket (socket: Socket, next: (err?: any) => void) { | ||
78 | const runnerToken = socket.handshake.auth['runnerToken'] | ||
79 | |||
80 | logger.debug('Checking runner token in socket.') | ||
81 | |||
82 | if (!runnerToken) return next(new Error('No runner token provided')) | ||
83 | if (typeof runnerToken !== 'string') return next(new Error('Runner token is invalid')) | ||
84 | |||
85 | RunnerModel.loadByToken(runnerToken) | ||
86 | .then(runner => { | ||
87 | if (!runner) return next(new Error('Invalid runner token.')) | ||
88 | |||
89 | socket.handshake.auth.runner = runner | ||
90 | |||
91 | return next() | ||
92 | }) | ||
93 | .catch(err => logger.error('Cannot get runner token.', { err })) | ||
94 | } | ||
95 | |||
96 | // --------------------------------------------------------------------------- | ||
97 | |||
76 | export { | 98 | export { |
77 | authenticate, | 99 | authenticate, |
78 | authenticateSocket, | 100 | authenticateSocket, |
79 | authenticatePromise, | 101 | authenticatePromise, |
80 | optionalAuthenticate | 102 | optionalAuthenticate, |
103 | authenticateRunnerSocket | ||
81 | } | 104 | } |
diff --git a/server/middlewares/doc.ts b/server/middlewares/doc.ts index c43f41977..eef76acaa 100644 --- a/server/middlewares/doc.ts +++ b/server/middlewares/doc.ts | |||
@@ -5,7 +5,7 @@ function openapiOperationDoc (options: { | |||
5 | operationId?: string | 5 | operationId?: string |
6 | }) { | 6 | }) { |
7 | return (req: express.Request, res: express.Response, next: express.NextFunction) => { | 7 | return (req: express.Request, res: express.Response, next: express.NextFunction) => { |
8 | res.locals.docUrl = options.url || 'https://docs.joinpeertube.org/api/rest-reference.html#operation/' + options.operationId | 8 | res.locals.docUrl = options.url || 'https://docs.joinpeertube.org/api-rest-reference.html#operation/' + options.operationId |
9 | 9 | ||
10 | if (next) return next() | 10 | if (next) return next() |
11 | } | 11 | } |
diff --git a/server/middlewares/error.ts b/server/middlewares/error.ts index 540edaeeb..94762e355 100644 --- a/server/middlewares/error.ts +++ b/server/middlewares/error.ts | |||
@@ -5,7 +5,7 @@ import { HttpStatusCode } from '@shared/models' | |||
5 | 5 | ||
6 | function apiFailMiddleware (req: express.Request, res: express.Response, next: express.NextFunction) { | 6 | function apiFailMiddleware (req: express.Request, res: express.Response, next: express.NextFunction) { |
7 | res.fail = options => { | 7 | res.fail = options => { |
8 | const { status = HttpStatusCode.BAD_REQUEST_400, message, title, type, data, instance } = options | 8 | const { status = HttpStatusCode.BAD_REQUEST_400, message, title, type, data, instance, tags } = options |
9 | 9 | ||
10 | const extension = new ProblemDocumentExtension({ | 10 | const extension = new ProblemDocumentExtension({ |
11 | ...data, | 11 | ...data, |
@@ -31,11 +31,11 @@ function apiFailMiddleware (req: express.Request, res: express.Response, next: e | |||
31 | detail: message, | 31 | detail: message, |
32 | 32 | ||
33 | type: type | 33 | type: type |
34 | ? `https://docs.joinpeertube.org/api/rest-reference.html#section/Errors/${type}` | 34 | ? `https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/${type}` |
35 | : undefined | 35 | : undefined |
36 | }, extension) | 36 | }, extension) |
37 | 37 | ||
38 | logger.debug('Bad HTTP request.', { json }) | 38 | logger.debug('Bad HTTP request.', { json, tags }) |
39 | 39 | ||
40 | res.json(json) | 40 | res.json(json) |
41 | } | 41 | } |
diff --git a/server/middlewares/rate-limiter.ts b/server/middlewares/rate-limiter.ts index bc9513969..1eef8b360 100644 --- a/server/middlewares/rate-limiter.ts +++ b/server/middlewares/rate-limiter.ts | |||
@@ -1,10 +1,12 @@ | |||
1 | import express from 'express' | ||
2 | import RateLimit, { Options as RateLimitHandlerOptions } from 'express-rate-limit' | ||
3 | import { RunnerModel } from '@server/models/runner/runner' | ||
1 | import { UserRole } from '@shared/models' | 4 | import { UserRole } from '@shared/models' |
2 | import RateLimit from 'express-rate-limit' | ||
3 | import { optionalAuthenticate } from './auth' | 5 | import { optionalAuthenticate } from './auth' |
4 | 6 | ||
5 | const whitelistRoles = new Set([ UserRole.ADMINISTRATOR, UserRole.MODERATOR ]) | 7 | const whitelistRoles = new Set([ UserRole.ADMINISTRATOR, UserRole.MODERATOR ]) |
6 | 8 | ||
7 | function buildRateLimiter (options: { | 9 | export function buildRateLimiter (options: { |
8 | windowMs: number | 10 | windowMs: number |
9 | max: number | 11 | max: number |
10 | skipFailedRequests?: boolean | 12 | skipFailedRequests?: boolean |
@@ -15,17 +17,33 @@ function buildRateLimiter (options: { | |||
15 | skipFailedRequests: options.skipFailedRequests, | 17 | skipFailedRequests: options.skipFailedRequests, |
16 | 18 | ||
17 | handler: (req, res, next, options) => { | 19 | handler: (req, res, next, options) => { |
20 | // Bypass rate limit for registered runners | ||
21 | if (req.body?.runnerToken) { | ||
22 | return RunnerModel.loadByToken(req.body.runnerToken) | ||
23 | .then(runner => { | ||
24 | if (runner) return next() | ||
25 | |||
26 | return sendRateLimited(res, options) | ||
27 | }) | ||
28 | } | ||
29 | |||
30 | // Bypass rate limit for admins/moderators | ||
18 | return optionalAuthenticate(req, res, () => { | 31 | return optionalAuthenticate(req, res, () => { |
19 | if (res.locals.authenticated === true && whitelistRoles.has(res.locals.oauth.token.User.role)) { | 32 | if (res.locals.authenticated === true && whitelistRoles.has(res.locals.oauth.token.User.role)) { |
20 | return next() | 33 | return next() |
21 | } | 34 | } |
22 | 35 | ||
23 | return res.status(options.statusCode).send(options.message) | 36 | return sendRateLimited(res, options) |
24 | }) | 37 | }) |
25 | } | 38 | } |
26 | }) | 39 | }) |
27 | } | 40 | } |
28 | 41 | ||
29 | export { | 42 | // --------------------------------------------------------------------------- |
30 | buildRateLimiter | 43 | // Private |
44 | // --------------------------------------------------------------------------- | ||
45 | |||
46 | function sendRateLimited (res: express.Response, options: RateLimitHandlerOptions) { | ||
47 | return res.status(options.statusCode).send(options.message) | ||
48 | |||
31 | } | 49 | } |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index 4a9d1cb54..b3e7e5011 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -54,6 +54,7 @@ const customConfigUpdateValidator = [ | |||
54 | body('transcoding.resolutions.1080p').isBoolean(), | 54 | body('transcoding.resolutions.1080p').isBoolean(), |
55 | body('transcoding.resolutions.1440p').isBoolean(), | 55 | body('transcoding.resolutions.1440p').isBoolean(), |
56 | body('transcoding.resolutions.2160p').isBoolean(), | 56 | body('transcoding.resolutions.2160p').isBoolean(), |
57 | body('transcoding.remoteRunners.enabled').isBoolean(), | ||
57 | 58 | ||
58 | body('transcoding.alwaysTranscodeOriginalResolution').isBoolean(), | 59 | body('transcoding.alwaysTranscodeOriginalResolution').isBoolean(), |
59 | 60 | ||
@@ -97,6 +98,7 @@ const customConfigUpdateValidator = [ | |||
97 | body('live.transcoding.resolutions.1440p').isBoolean(), | 98 | body('live.transcoding.resolutions.1440p').isBoolean(), |
98 | body('live.transcoding.resolutions.2160p').isBoolean(), | 99 | body('live.transcoding.resolutions.2160p').isBoolean(), |
99 | body('live.transcoding.alwaysTranscodeOriginalResolution').isBoolean(), | 100 | body('live.transcoding.alwaysTranscodeOriginalResolution').isBoolean(), |
101 | body('live.transcoding.remoteRunners.enabled').isBoolean(), | ||
100 | 102 | ||
101 | body('search.remoteUri.users').isBoolean(), | 103 | body('search.remoteUri.users').isBoolean(), |
102 | body('search.remoteUri.anonymous').isBoolean(), | 104 | body('search.remoteUri.anonymous').isBoolean(), |
diff --git a/server/middlewares/validators/runners/index.ts b/server/middlewares/validators/runners/index.ts new file mode 100644 index 000000000..9a9629a80 --- /dev/null +++ b/server/middlewares/validators/runners/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './jobs' | ||
2 | export * from './registration-token' | ||
3 | export * from './runners' | ||
diff --git a/server/middlewares/validators/runners/job-files.ts b/server/middlewares/validators/runners/job-files.ts new file mode 100644 index 000000000..56afa39aa --- /dev/null +++ b/server/middlewares/validators/runners/job-files.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import express from 'express' | ||
2 | import { HttpStatusCode } from '@shared/models' | ||
3 | import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared' | ||
4 | |||
5 | const tags = [ 'runner' ] | ||
6 | |||
7 | export const runnerJobGetVideoTranscodingFileValidator = [ | ||
8 | isValidVideoIdParam('videoId'), | ||
9 | |||
10 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
11 | if (areValidationErrors(req, res)) return | ||
12 | |||
13 | if (!await doesVideoExist(req.params.videoId, res, 'all')) return | ||
14 | |||
15 | const runnerJob = res.locals.runnerJob | ||
16 | |||
17 | if (runnerJob.privatePayload.videoUUID !== res.locals.videoAll.uuid) { | ||
18 | return res.fail({ | ||
19 | status: HttpStatusCode.FORBIDDEN_403, | ||
20 | message: 'Job is not associated to this video', | ||
21 | tags: [ ...tags, res.locals.videoAll.uuid ] | ||
22 | }) | ||
23 | } | ||
24 | |||
25 | return next() | ||
26 | } | ||
27 | ] | ||
diff --git a/server/middlewares/validators/runners/jobs.ts b/server/middlewares/validators/runners/jobs.ts new file mode 100644 index 000000000..8cb87e946 --- /dev/null +++ b/server/middlewares/validators/runners/jobs.ts | |||
@@ -0,0 +1,156 @@ | |||
1 | import express from 'express' | ||
2 | import { body, param } from 'express-validator' | ||
3 | import { isUUIDValid } from '@server/helpers/custom-validators/misc' | ||
4 | import { | ||
5 | isRunnerJobAbortReasonValid, | ||
6 | isRunnerJobErrorMessageValid, | ||
7 | isRunnerJobProgressValid, | ||
8 | isRunnerJobSuccessPayloadValid, | ||
9 | isRunnerJobTokenValid, | ||
10 | isRunnerJobUpdatePayloadValid | ||
11 | } from '@server/helpers/custom-validators/runners/jobs' | ||
12 | import { isRunnerTokenValid } from '@server/helpers/custom-validators/runners/runners' | ||
13 | import { cleanUpReqFiles } from '@server/helpers/express-utils' | ||
14 | import { RunnerJobModel } from '@server/models/runner/runner-job' | ||
15 | import { HttpStatusCode, RunnerJobState, RunnerJobSuccessBody, RunnerJobUpdateBody, ServerErrorCode } from '@shared/models' | ||
16 | import { areValidationErrors } from '../shared' | ||
17 | |||
18 | const tags = [ 'runner' ] | ||
19 | |||
20 | export const acceptRunnerJobValidator = [ | ||
21 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
22 | if (res.locals.runnerJob.state !== RunnerJobState.PENDING) { | ||
23 | return res.fail({ | ||
24 | status: HttpStatusCode.BAD_REQUEST_400, | ||
25 | message: 'This runner job is not in pending state', | ||
26 | tags | ||
27 | }) | ||
28 | } | ||
29 | |||
30 | return next() | ||
31 | } | ||
32 | ] | ||
33 | |||
34 | export const abortRunnerJobValidator = [ | ||
35 | body('reason').custom(isRunnerJobAbortReasonValid), | ||
36 | |||
37 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
38 | if (areValidationErrors(req, res, { tags })) return | ||
39 | |||
40 | return next() | ||
41 | } | ||
42 | ] | ||
43 | |||
44 | export const updateRunnerJobValidator = [ | ||
45 | body('progress').optional().custom(isRunnerJobProgressValid), | ||
46 | |||
47 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
48 | if (areValidationErrors(req, res, { tags })) return cleanUpReqFiles(req) | ||
49 | |||
50 | const body = req.body as RunnerJobUpdateBody | ||
51 | |||
52 | if (isRunnerJobUpdatePayloadValid(body.payload, res.locals.runnerJob.type, req.files) !== true) { | ||
53 | cleanUpReqFiles(req) | ||
54 | |||
55 | return res.fail({ | ||
56 | status: HttpStatusCode.BAD_REQUEST_400, | ||
57 | message: 'Payload is invalid', | ||
58 | tags | ||
59 | }) | ||
60 | } | ||
61 | |||
62 | return next() | ||
63 | } | ||
64 | ] | ||
65 | |||
66 | export const errorRunnerJobValidator = [ | ||
67 | body('message').custom(isRunnerJobErrorMessageValid), | ||
68 | |||
69 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
70 | if (areValidationErrors(req, res, { tags })) return | ||
71 | |||
72 | return next() | ||
73 | } | ||
74 | ] | ||
75 | |||
76 | export const successRunnerJobValidator = [ | ||
77 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
78 | const body = req.body as RunnerJobSuccessBody | ||
79 | |||
80 | if (isRunnerJobSuccessPayloadValid(body.payload, res.locals.runnerJob.type, req.files) !== true) { | ||
81 | cleanUpReqFiles(req) | ||
82 | |||
83 | return res.fail({ | ||
84 | status: HttpStatusCode.BAD_REQUEST_400, | ||
85 | message: 'Payload is invalid', | ||
86 | tags | ||
87 | }) | ||
88 | } | ||
89 | |||
90 | return next() | ||
91 | } | ||
92 | ] | ||
93 | |||
94 | export const runnerJobGetValidator = [ | ||
95 | param('jobUUID').custom(isUUIDValid), | ||
96 | |||
97 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
98 | if (areValidationErrors(req, res, { tags })) return | ||
99 | |||
100 | const runnerJob = await RunnerJobModel.loadWithRunner(req.params.jobUUID) | ||
101 | |||
102 | if (!runnerJob) { | ||
103 | return res.fail({ | ||
104 | status: HttpStatusCode.NOT_FOUND_404, | ||
105 | message: 'Unknown runner job', | ||
106 | tags | ||
107 | }) | ||
108 | } | ||
109 | |||
110 | res.locals.runnerJob = runnerJob | ||
111 | |||
112 | return next() | ||
113 | } | ||
114 | ] | ||
115 | |||
116 | export const jobOfRunnerGetValidator = [ | ||
117 | param('jobUUID').custom(isUUIDValid), | ||
118 | |||
119 | body('runnerToken').custom(isRunnerTokenValid), | ||
120 | body('jobToken').custom(isRunnerJobTokenValid), | ||
121 | |||
122 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
123 | if (areValidationErrors(req, res, { tags })) return cleanUpReqFiles(req) | ||
124 | |||
125 | const runnerJob = await RunnerJobModel.loadByRunnerAndJobTokensWithRunner({ | ||
126 | uuid: req.params.jobUUID, | ||
127 | runnerToken: req.body.runnerToken, | ||
128 | jobToken: req.body.jobToken | ||
129 | }) | ||
130 | |||
131 | if (!runnerJob) { | ||
132 | cleanUpReqFiles(req) | ||
133 | |||
134 | return res.fail({ | ||
135 | status: HttpStatusCode.NOT_FOUND_404, | ||
136 | message: 'Unknown runner job', | ||
137 | tags | ||
138 | }) | ||
139 | } | ||
140 | |||
141 | if (runnerJob.state !== RunnerJobState.PROCESSING) { | ||
142 | cleanUpReqFiles(req) | ||
143 | |||
144 | return res.fail({ | ||
145 | status: HttpStatusCode.BAD_REQUEST_400, | ||
146 | type: ServerErrorCode.RUNNER_JOB_NOT_IN_PROCESSING_STATE, | ||
147 | message: 'Job is not in "processing" state', | ||
148 | tags | ||
149 | }) | ||
150 | } | ||
151 | |||
152 | res.locals.runnerJob = runnerJob | ||
153 | |||
154 | return next() | ||
155 | } | ||
156 | ] | ||
diff --git a/server/middlewares/validators/runners/registration-token.ts b/server/middlewares/validators/runners/registration-token.ts new file mode 100644 index 000000000..cc31d4a7e --- /dev/null +++ b/server/middlewares/validators/runners/registration-token.ts | |||
@@ -0,0 +1,37 @@ | |||
1 | import express from 'express' | ||
2 | import { param } from 'express-validator' | ||
3 | import { isIdValid } from '@server/helpers/custom-validators/misc' | ||
4 | import { RunnerRegistrationTokenModel } from '@server/models/runner/runner-registration-token' | ||
5 | import { forceNumber } from '@shared/core-utils' | ||
6 | import { HttpStatusCode } from '@shared/models' | ||
7 | import { areValidationErrors } from '../shared/utils' | ||
8 | |||
9 | const tags = [ 'runner' ] | ||
10 | |||
11 | const deleteRegistrationTokenValidator = [ | ||
12 | param('id').custom(isIdValid), | ||
13 | |||
14 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
15 | if (areValidationErrors(req, res, { tags })) return | ||
16 | |||
17 | const registrationToken = await RunnerRegistrationTokenModel.load(forceNumber(req.params.id)) | ||
18 | |||
19 | if (!registrationToken) { | ||
20 | return res.fail({ | ||
21 | status: HttpStatusCode.NOT_FOUND_404, | ||
22 | message: 'Registration token not found', | ||
23 | tags | ||
24 | }) | ||
25 | } | ||
26 | |||
27 | res.locals.runnerRegistrationToken = registrationToken | ||
28 | |||
29 | return next() | ||
30 | } | ||
31 | ] | ||
32 | |||
33 | // --------------------------------------------------------------------------- | ||
34 | |||
35 | export { | ||
36 | deleteRegistrationTokenValidator | ||
37 | } | ||
diff --git a/server/middlewares/validators/runners/runners.ts b/server/middlewares/validators/runners/runners.ts new file mode 100644 index 000000000..71a1275d2 --- /dev/null +++ b/server/middlewares/validators/runners/runners.ts | |||
@@ -0,0 +1,95 @@ | |||
1 | import express from 'express' | ||
2 | import { body, param } from 'express-validator' | ||
3 | import { isIdValid } from '@server/helpers/custom-validators/misc' | ||
4 | import { | ||
5 | isRunnerDescriptionValid, | ||
6 | isRunnerNameValid, | ||
7 | isRunnerRegistrationTokenValid, | ||
8 | isRunnerTokenValid | ||
9 | } from '@server/helpers/custom-validators/runners/runners' | ||
10 | import { RunnerModel } from '@server/models/runner/runner' | ||
11 | import { RunnerRegistrationTokenModel } from '@server/models/runner/runner-registration-token' | ||
12 | import { forceNumber } from '@shared/core-utils' | ||
13 | import { HttpStatusCode, RegisterRunnerBody, ServerErrorCode } from '@shared/models' | ||
14 | import { areValidationErrors } from '../shared/utils' | ||
15 | |||
16 | const tags = [ 'runner' ] | ||
17 | |||
18 | const registerRunnerValidator = [ | ||
19 | body('registrationToken').custom(isRunnerRegistrationTokenValid), | ||
20 | body('name').custom(isRunnerNameValid), | ||
21 | body('description').optional().custom(isRunnerDescriptionValid), | ||
22 | |||
23 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
24 | if (areValidationErrors(req, res, { tags })) return | ||
25 | |||
26 | const body: RegisterRunnerBody = req.body | ||
27 | |||
28 | const runnerRegistrationToken = await RunnerRegistrationTokenModel.loadByRegistrationToken(body.registrationToken) | ||
29 | |||
30 | if (!runnerRegistrationToken) { | ||
31 | return res.fail({ | ||
32 | status: HttpStatusCode.NOT_FOUND_404, | ||
33 | message: 'Registration token is invalid', | ||
34 | tags | ||
35 | }) | ||
36 | } | ||
37 | |||
38 | res.locals.runnerRegistrationToken = runnerRegistrationToken | ||
39 | |||
40 | return next() | ||
41 | } | ||
42 | ] | ||
43 | |||
44 | const deleteRunnerValidator = [ | ||
45 | param('runnerId').custom(isIdValid), | ||
46 | |||
47 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
48 | if (areValidationErrors(req, res, { tags })) return | ||
49 | |||
50 | const runner = await RunnerModel.load(forceNumber(req.params.runnerId)) | ||
51 | |||
52 | if (!runner) { | ||
53 | return res.fail({ | ||
54 | status: HttpStatusCode.NOT_FOUND_404, | ||
55 | message: 'Runner not found', | ||
56 | tags | ||
57 | }) | ||
58 | } | ||
59 | |||
60 | res.locals.runner = runner | ||
61 | |||
62 | return next() | ||
63 | } | ||
64 | ] | ||
65 | |||
66 | const getRunnerFromTokenValidator = [ | ||
67 | body('runnerToken').custom(isRunnerTokenValid), | ||
68 | |||
69 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
70 | if (areValidationErrors(req, res, { tags })) return | ||
71 | |||
72 | const runner = await RunnerModel.loadByToken(req.body.runnerToken) | ||
73 | |||
74 | if (!runner) { | ||
75 | return res.fail({ | ||
76 | status: HttpStatusCode.NOT_FOUND_404, | ||
77 | message: 'Unknown runner token', | ||
78 | type: ServerErrorCode.UNKNOWN_RUNNER_TOKEN, | ||
79 | tags | ||
80 | }) | ||
81 | } | ||
82 | |||
83 | res.locals.runner = runner | ||
84 | |||
85 | return next() | ||
86 | } | ||
87 | ] | ||
88 | |||
89 | // --------------------------------------------------------------------------- | ||
90 | |||
91 | export { | ||
92 | registerRunnerValidator, | ||
93 | deleteRunnerValidator, | ||
94 | getRunnerFromTokenValidator | ||
95 | } | ||
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index e6cc46317..959f663ac 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts | |||
@@ -34,6 +34,10 @@ export const videoChannelsFollowersSortValidator = checkSortFactory(SORTABLE_COL | |||
34 | 34 | ||
35 | export const userRegistrationsSortValidator = checkSortFactory(SORTABLE_COLUMNS.USER_REGISTRATIONS) | 35 | export const userRegistrationsSortValidator = checkSortFactory(SORTABLE_COLUMNS.USER_REGISTRATIONS) |
36 | 36 | ||
37 | export const runnersSortValidator = checkSortFactory(SORTABLE_COLUMNS.RUNNERS) | ||
38 | export const runnerRegistrationTokensSortValidator = checkSortFactory(SORTABLE_COLUMNS.RUNNER_REGISTRATION_TOKENS) | ||
39 | export const runnerJobsSortValidator = checkSortFactory(SORTABLE_COLUMNS.RUNNER_JOBS) | ||
40 | |||
37 | // --------------------------------------------------------------------------- | 41 | // --------------------------------------------------------------------------- |
38 | 42 | ||
39 | function checkSortFactory (columns: string[], tags: string[] = []) { | 43 | function checkSortFactory (columns: string[], tags: string[] = []) { |
diff --git a/server/middlewares/validators/videos/video-live.ts b/server/middlewares/validators/videos/video-live.ts index e80fe1593..2aff831a8 100644 --- a/server/middlewares/validators/videos/video-live.ts +++ b/server/middlewares/validators/videos/video-live.ts | |||
@@ -115,6 +115,15 @@ const videoLiveAddValidator = getCommonVideoEditAttributes().concat([ | |||
115 | }) | 115 | }) |
116 | } | 116 | } |
117 | 117 | ||
118 | if (body.saveReplay && !body.replaySettings?.privacy) { | ||
119 | cleanUpReqFiles(req) | ||
120 | |||
121 | return res.fail({ | ||
122 | status: HttpStatusCode.BAD_REQUEST_400, | ||
123 | message: 'Live replay is enabled but privacy replay setting is missing' | ||
124 | }) | ||
125 | } | ||
126 | |||
118 | const user = res.locals.oauth.token.User | 127 | const user = res.locals.oauth.token.User |
119 | if (!await doesVideoChannelOfAccountExist(body.channelId, user, res)) return cleanUpReqFiles(req) | 128 | if (!await doesVideoChannelOfAccountExist(body.channelId, user, res)) return cleanUpReqFiles(req) |
120 | 129 | ||
diff --git a/server/middlewares/validators/videos/video-studio.ts b/server/middlewares/validators/videos/video-studio.ts index b3e2d8101..4397e887e 100644 --- a/server/middlewares/validators/videos/video-studio.ts +++ b/server/middlewares/validators/videos/video-studio.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | import { cleanUpReqFiles } from '@server/helpers/express-utils' | 10 | import { cleanUpReqFiles } from '@server/helpers/express-utils' |
11 | import { CONFIG } from '@server/initializers/config' | 11 | import { CONFIG } from '@server/initializers/config' |
12 | import { approximateIntroOutroAdditionalSize, getTaskFile } from '@server/lib/video-studio' | 12 | import { approximateIntroOutroAdditionalSize, getTaskFile } from '@server/lib/video-studio' |
13 | import { isAudioFile } from '@shared/extra-utils' | 13 | import { isAudioFile } from '@shared/ffmpeg' |
14 | import { HttpStatusCode, UserRight, VideoState, VideoStudioCreateEdition, VideoStudioTask } from '@shared/models' | 14 | import { HttpStatusCode, UserRight, VideoState, VideoStudioCreateEdition, VideoStudioTask } from '@shared/models' |
15 | import { areValidationErrors, checkUserCanManageVideo, checkUserQuota, doesVideoExist } from '../shared' | 15 | import { areValidationErrors, checkUserCanManageVideo, checkUserQuota, doesVideoExist } from '../shared' |
16 | 16 | ||
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index d3014e8e7..794e1d4f1 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -7,6 +7,7 @@ import { getServerActor } from '@server/models/application/application' | |||
7 | import { ExpressPromiseHandler } from '@server/types/express-handler' | 7 | import { ExpressPromiseHandler } from '@server/types/express-handler' |
8 | import { MUserAccountId, MVideoFullLight } from '@server/types/models' | 8 | import { MUserAccountId, MVideoFullLight } from '@server/types/models' |
9 | import { arrayify, getAllPrivacies } from '@shared/core-utils' | 9 | import { arrayify, getAllPrivacies } from '@shared/core-utils' |
10 | import { getVideoStreamDuration } from '@shared/ffmpeg' | ||
10 | import { HttpStatusCode, ServerErrorCode, UserRight, VideoInclude, VideoState } from '@shared/models' | 11 | import { HttpStatusCode, ServerErrorCode, UserRight, VideoInclude, VideoState } from '@shared/models' |
11 | import { | 12 | import { |
12 | exists, | 13 | exists, |
@@ -37,7 +38,6 @@ import { | |||
37 | isVideoSupportValid | 38 | isVideoSupportValid |
38 | } from '../../../helpers/custom-validators/videos' | 39 | } from '../../../helpers/custom-validators/videos' |
39 | import { cleanUpReqFiles } from '../../../helpers/express-utils' | 40 | import { cleanUpReqFiles } from '../../../helpers/express-utils' |
40 | import { getVideoStreamDuration } from '../../../helpers/ffmpeg' | ||
41 | import { logger } from '../../../helpers/logger' | 41 | import { logger } from '../../../helpers/logger' |
42 | import { deleteFileAndCatch } from '../../../helpers/utils' | 42 | import { deleteFileAndCatch } from '../../../helpers/utils' |
43 | import { getVideoWithAttributes } from '../../../helpers/video' | 43 | import { getVideoWithAttributes } from '../../../helpers/video' |