diff options
Diffstat (limited to 'server/middlewares')
33 files changed, 798 insertions, 267 deletions
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index 01e5dd24e..b1e5b5236 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts | |||
@@ -1,11 +1,9 @@ | |||
1 | import { eachSeries } from 'async' | 1 | import { NextFunction, Request, Response } from 'express' |
2 | import { NextFunction, Request, RequestHandler, Response } from 'express' | ||
3 | import { ActivityPubSignature } from '../../shared' | 2 | import { ActivityPubSignature } from '../../shared' |
4 | import { logger } from '../helpers/logger' | 3 | import { logger } from '../helpers/logger' |
5 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' | 4 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' |
6 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers' | 5 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' |
7 | import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' | 6 | import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' |
8 | import { ActorModel } from '../models/activitypub/actor' | ||
9 | import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' | 7 | import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' |
10 | 8 | ||
11 | async function checkSignature (req: Request, res: Response, next: NextFunction) { | 9 | async function checkSignature (req: Request, res: Response, next: NextFunction) { |
@@ -13,7 +11,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
13 | const httpSignatureChecked = await checkHttpSignature(req, res) | 11 | const httpSignatureChecked = await checkHttpSignature(req, res) |
14 | if (httpSignatureChecked !== true) return | 12 | if (httpSignatureChecked !== true) return |
15 | 13 | ||
16 | const actor: ActorModel = res.locals.signature.actor | 14 | const actor = res.locals.signature.actor |
17 | 15 | ||
18 | // Forwarded activity | 16 | // Forwarded activity |
19 | const bodyActor = req.body.actor | 17 | const bodyActor = req.body.actor |
@@ -30,23 +28,16 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
30 | } | 28 | } |
31 | } | 29 | } |
32 | 30 | ||
33 | function executeIfActivityPub (fun: RequestHandler | RequestHandler[]) { | 31 | function executeIfActivityPub (req: Request, res: Response, next: NextFunction) { |
34 | return (req: Request, res: Response, next: NextFunction) => { | 32 | const accepted = req.accepts(ACCEPT_HEADERS) |
35 | const accepted = req.accepts(ACCEPT_HEADERS) | 33 | if (accepted === false || ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.indexOf(accepted) === -1) { |
36 | if (accepted === false || ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.indexOf(accepted) === -1) { | 34 | // Bypass this route |
37 | return next() | 35 | return next('route') |
38 | } | 36 | } |
39 | |||
40 | logger.debug('ActivityPub request for %s.', req.url) | ||
41 | 37 | ||
42 | if (Array.isArray(fun) === true) { | 38 | logger.debug('ActivityPub request for %s.', req.url) |
43 | return eachSeries(fun as RequestHandler[], (f, cb) => { | ||
44 | f(req, res, cb) | ||
45 | }, next) | ||
46 | } | ||
47 | 39 | ||
48 | return (fun as RequestHandler)(req, res, next) | 40 | return next() |
49 | } | ||
50 | } | 41 | } |
51 | 42 | ||
52 | // --------------------------------------------------------------------------- | 43 | // --------------------------------------------------------------------------- |
@@ -83,6 +74,8 @@ async function checkHttpSignature (req: Request, res: Response) { | |||
83 | 74 | ||
84 | const verified = isHTTPSignatureVerified(parsed, actor) | 75 | const verified = isHTTPSignatureVerified(parsed, actor) |
85 | if (verified !== true) { | 76 | if (verified !== true) { |
77 | logger.warn('Signature from %s is invalid', actorUrl, { parsed }) | ||
78 | |||
86 | res.sendStatus(403) | 79 | res.sendStatus(403) |
87 | return false | 80 | return false |
88 | } | 81 | } |
diff --git a/server/middlewares/cache.ts b/server/middlewares/cache.ts index 8ffe75700..ef8611875 100644 --- a/server/middlewares/cache.ts +++ b/server/middlewares/cache.ts | |||
@@ -1,72 +1,16 @@ | |||
1 | import * as express from 'express' | ||
2 | import * as AsyncLock from 'async-lock' | ||
3 | import { parseDuration } from '../helpers/core-utils' | ||
4 | import { Redis } from '../lib/redis' | 1 | import { Redis } from '../lib/redis' |
5 | import { logger } from '../helpers/logger' | 2 | import * as apicache from 'apicache' |
6 | 3 | ||
7 | const lock = new AsyncLock({ timeout: 5000 }) | 4 | // Ensure Redis is initialized |
5 | Redis.Instance.init() | ||
8 | 6 | ||
9 | function cacheRoute (lifetimeArg: string | number) { | 7 | const options = { |
10 | return async function (req: express.Request, res: express.Response, next: express.NextFunction) { | 8 | redisClient: Redis.Instance.getClient(), |
11 | const redisKey = Redis.Instance.generateCachedRouteKey(req) | 9 | appendKey: () => Redis.Instance.getPrefix() |
12 | |||
13 | try { | ||
14 | await lock.acquire(redisKey, async (done) => { | ||
15 | const cached = await Redis.Instance.getCachedRoute(req) | ||
16 | |||
17 | // Not cached | ||
18 | if (!cached) { | ||
19 | logger.debug('No cached results for route %s.', req.originalUrl) | ||
20 | |||
21 | const sendSave = res.send.bind(res) | ||
22 | const redirectSave = res.redirect.bind(res) | ||
23 | |||
24 | res.send = (body) => { | ||
25 | if (res.statusCode >= 200 && res.statusCode < 400) { | ||
26 | const contentType = res.get('content-type') | ||
27 | const lifetime = parseDuration(lifetimeArg) | ||
28 | |||
29 | Redis.Instance.setCachedRoute(req, body, lifetime, contentType, res.statusCode) | ||
30 | .then(() => done()) | ||
31 | .catch(err => { | ||
32 | logger.error('Cannot cache route.', { err }) | ||
33 | return done(err) | ||
34 | }) | ||
35 | } else { | ||
36 | done() | ||
37 | } | ||
38 | |||
39 | return sendSave(body) | ||
40 | } | ||
41 | |||
42 | res.redirect = url => { | ||
43 | done() | ||
44 | |||
45 | return redirectSave(url) | ||
46 | } | ||
47 | |||
48 | return next() | ||
49 | } | ||
50 | |||
51 | if (cached.contentType) res.set('content-type', cached.contentType) | ||
52 | |||
53 | if (cached.statusCode) { | ||
54 | const statusCode = parseInt(cached.statusCode, 10) | ||
55 | if (!isNaN(statusCode)) res.status(statusCode) | ||
56 | } | ||
57 | |||
58 | logger.debug('Use cached result for %s.', req.originalUrl) | ||
59 | res.send(cached.body).end() | ||
60 | |||
61 | return done() | ||
62 | }) | ||
63 | } catch (err) { | ||
64 | logger.error('Cannot serve cached route.', { err }) | ||
65 | return next() | ||
66 | } | ||
67 | } | ||
68 | } | 10 | } |
69 | 11 | ||
12 | const cacheRoute = apicache.options(options).middleware | ||
13 | |||
70 | // --------------------------------------------------------------------------- | 14 | // --------------------------------------------------------------------------- |
71 | 15 | ||
72 | export { | 16 | export { |
diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts index 8b919af0d..d484b3021 100644 --- a/server/middlewares/csp.ts +++ b/server/middlewares/csp.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as helmet from 'helmet' | 1 | import * as helmet from 'helmet' |
2 | import { CONFIG } from '../initializers/constants' | 2 | import { CONFIG } from '../initializers/config' |
3 | 3 | ||
4 | const baseDirectives = Object.assign({}, | 4 | const baseDirectives = Object.assign({}, |
5 | { | 5 | { |
@@ -16,24 +16,22 @@ const baseDirectives = Object.assign({}, | |||
16 | baseUri: ["'self'"], | 16 | baseUri: ["'self'"], |
17 | manifestSrc: ["'self'"], | 17 | manifestSrc: ["'self'"], |
18 | frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed | 18 | frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed |
19 | workerSrc: ["'self'"] // instead of deprecated child-src | 19 | workerSrc: ["'self'", 'blob:'] // instead of deprecated child-src |
20 | }, | 20 | }, |
21 | CONFIG.SERVICES['CSP-LOGGER'] ? { reportUri: CONFIG.SERVICES['CSP-LOGGER'] } : {}, | 21 | CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {}, |
22 | CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} | 22 | CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} |
23 | ) | 23 | ) |
24 | 24 | ||
25 | const baseCSP = helmet.contentSecurityPolicy({ | 25 | const baseCSP = helmet.contentSecurityPolicy({ |
26 | directives: baseDirectives, | 26 | directives: baseDirectives, |
27 | browserSniff: false, | 27 | browserSniff: false, |
28 | reportOnly: true | 28 | reportOnly: CONFIG.CSP.REPORT_ONLY |
29 | }) | 29 | }) |
30 | 30 | ||
31 | const embedCSP = helmet.contentSecurityPolicy({ | 31 | const embedCSP = helmet.contentSecurityPolicy({ |
32 | directives: Object.assign(baseDirectives, { | 32 | directives: Object.assign({}, baseDirectives, { frameAncestors: ['*'] }), |
33 | frameAncestors: ['*'] | ||
34 | }), | ||
35 | browserSniff: false, // assumes a modern browser, but allows CDN in front | 33 | browserSniff: false, // assumes a modern browser, but allows CDN in front |
36 | reportOnly: true | 34 | reportOnly: CONFIG.CSP.REPORT_ONLY |
37 | }) | 35 | }) |
38 | 36 | ||
39 | // --------------------------------------------------------------------------- | 37 | // --------------------------------------------------------------------------- |
diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 1d193d467..2b4e300e4 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import * as OAuthServer from 'express-oauth-server' | 2 | import * as OAuthServer from 'express-oauth-server' |
3 | import 'express-validator' | 3 | import 'express-validator' |
4 | import { OAUTH_LIFETIME } from '../initializers' | 4 | import { OAUTH_LIFETIME } from '../initializers/constants' |
5 | import { logger } from '../helpers/logger' | 5 | import { logger } from '../helpers/logger' |
6 | import { Socket } from 'socket.io' | 6 | import { Socket } from 'socket.io' |
7 | import { getAccessToken } from '../lib/oauth-model' | 7 | import { getAccessToken } from '../lib/oauth-model' |
@@ -35,6 +35,8 @@ function authenticateSocket (socket: Socket, next: (err?: any) => void) { | |||
35 | 35 | ||
36 | logger.debug('Checking socket access token %s.', accessToken) | 36 | logger.debug('Checking socket access token %s.', accessToken) |
37 | 37 | ||
38 | if (!accessToken) return next(new Error('No access token provided')) | ||
39 | |||
38 | getAccessToken(accessToken) | 40 | getAccessToken(accessToken) |
39 | .then(tokenDB => { | 41 | .then(tokenDB => { |
40 | const now = new Date() | 42 | const now = new Date() |
diff --git a/server/middlewares/pagination.ts b/server/middlewares/pagination.ts index 9b497b19e..83304940f 100644 --- a/server/middlewares/pagination.ts +++ b/server/middlewares/pagination.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import 'express-validator' | 1 | import 'express-validator' |
2 | import * as express from 'express' | 2 | import * as express from 'express' |
3 | 3 | ||
4 | import { PAGINATION } from '../initializers' | 4 | import { PAGINATION } from '../initializers/constants' |
5 | 5 | ||
6 | function setDefaultPagination (req: express.Request, res: express.Response, next: express.NextFunction) { | 6 | function setDefaultPagination (req: express.Request, res: express.Response, next: express.NextFunction) { |
7 | if (!req.query.start) req.query.start = 0 | 7 | if (!req.query.start) req.query.start = 0 |
diff --git a/server/middlewares/user-right.ts b/server/middlewares/user-right.ts index 7cea7aa1e..498e3d677 100644 --- a/server/middlewares/user-right.ts +++ b/server/middlewares/user-right.ts | |||
@@ -2,11 +2,10 @@ import * as express from 'express' | |||
2 | import 'express-validator' | 2 | import 'express-validator' |
3 | import { UserRight } from '../../shared' | 3 | import { UserRight } from '../../shared' |
4 | import { logger } from '../helpers/logger' | 4 | import { logger } from '../helpers/logger' |
5 | import { UserModel } from '../models/account/user' | ||
6 | 5 | ||
7 | function ensureUserHasRight (userRight: UserRight) { | 6 | function ensureUserHasRight (userRight: UserRight) { |
8 | return function (req: express.Request, res: express.Response, next: express.NextFunction) { | 7 | return function (req: express.Request, res: express.Response, next: express.NextFunction) { |
9 | const user = res.locals.oauth.token.user as UserModel | 8 | const user = res.locals.oauth.token.user |
10 | if (user.hasRight(userRight) === false) { | 9 | if (user.hasRight(userRight) === false) { |
11 | const message = `User ${user.username} does not have right ${UserRight[userRight]} to access to ${req.path}.` | 10 | const message = `User ${user.username} does not have right ${UserRight[userRight]} to access to ${req.path}.` |
12 | logger.info(message) | 11 | logger.info(message) |
diff --git a/server/middlewares/validators/account.ts b/server/middlewares/validators/account.ts index b3a51e631..96e120a38 100644 --- a/server/middlewares/validators/account.ts +++ b/server/middlewares/validators/account.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { param } from 'express-validator/check' | 2 | import { param } from 'express-validator/check' |
3 | import { isAccountNameValid, isAccountNameWithHostExist, isLocalAccountNameExist } from '../../helpers/custom-validators/accounts' | 3 | import { isAccountNameValid, doesAccountNameWithHostExist, doesLocalAccountNameExist } from '../../helpers/custom-validators/accounts' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { areValidationErrors } from './utils' | 5 | import { areValidationErrors } from './utils' |
6 | 6 | ||
@@ -11,20 +11,20 @@ const localAccountValidator = [ | |||
11 | logger.debug('Checking localAccountValidator parameters', { parameters: req.params }) | 11 | logger.debug('Checking localAccountValidator parameters', { parameters: req.params }) |
12 | 12 | ||
13 | if (areValidationErrors(req, res)) return | 13 | if (areValidationErrors(req, res)) return |
14 | if (!await isLocalAccountNameExist(req.params.name, res)) return | 14 | if (!await doesLocalAccountNameExist(req.params.name, res)) return |
15 | 15 | ||
16 | return next() | 16 | return next() |
17 | } | 17 | } |
18 | ] | 18 | ] |
19 | 19 | ||
20 | const accountsNameWithHostGetValidator = [ | 20 | const accountNameWithHostGetValidator = [ |
21 | param('accountName').exists().withMessage('Should have an account name with host'), | 21 | param('accountName').exists().withMessage('Should have an account name with host'), |
22 | 22 | ||
23 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 23 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
24 | logger.debug('Checking accountsNameWithHostGetValidator parameters', { parameters: req.params }) | 24 | logger.debug('Checking accountsNameWithHostGetValidator parameters', { parameters: req.params }) |
25 | 25 | ||
26 | if (areValidationErrors(req, res)) return | 26 | if (areValidationErrors(req, res)) return |
27 | if (!await isAccountNameWithHostExist(req.params.accountName, res)) return | 27 | if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return |
28 | 28 | ||
29 | return next() | 29 | return next() |
30 | } | 30 | } |
@@ -34,5 +34,5 @@ const accountsNameWithHostGetValidator = [ | |||
34 | 34 | ||
35 | export { | 35 | export { |
36 | localAccountValidator, | 36 | localAccountValidator, |
37 | accountsNameWithHostGetValidator | 37 | accountNameWithHostGetValidator |
38 | } | 38 | } |
diff --git a/server/middlewares/validators/activitypub/activity.ts b/server/middlewares/validators/activitypub/activity.ts index 3f9057c0c..7582f65e7 100644 --- a/server/middlewares/validators/activitypub/activity.ts +++ b/server/middlewares/validators/activitypub/activity.ts | |||
@@ -2,7 +2,6 @@ import * as express from 'express' | |||
2 | import { isRootActivityValid } from '../../../helpers/custom-validators/activitypub/activity' | 2 | import { isRootActivityValid } from '../../../helpers/custom-validators/activitypub/activity' |
3 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
4 | import { getServerActor } from '../../../helpers/utils' | 4 | import { getServerActor } from '../../../helpers/utils' |
5 | import { ActorModel } from '../../../models/activitypub/actor' | ||
6 | 5 | ||
7 | async function activityPubValidator (req: express.Request, res: express.Response, next: express.NextFunction) { | 6 | async function activityPubValidator (req: express.Request, res: express.Response, next: express.NextFunction) { |
8 | logger.debug('Checking activity pub parameters') | 7 | logger.debug('Checking activity pub parameters') |
@@ -13,7 +12,7 @@ async function activityPubValidator (req: express.Request, res: express.Response | |||
13 | } | 12 | } |
14 | 13 | ||
15 | const serverActor = await getServerActor() | 14 | const serverActor = await getServerActor() |
16 | const remoteActor = res.locals.signature.actor as ActorModel | 15 | const remoteActor = res.locals.signature.actor |
17 | if (serverActor.id === remoteActor.id) { | 16 | if (serverActor.id === remoteActor.id) { |
18 | logger.error('Receiving request in INBOX by ourselves!', req.body) | 17 | logger.error('Receiving request in INBOX by ourselves!', req.body) |
19 | return res.status(409).end() | 18 | return res.status(409).end() |
diff --git a/server/middlewares/validators/avatar.ts b/server/middlewares/validators/avatar.ts index ddc14f531..bab3ed118 100644 --- a/server/middlewares/validators/avatar.ts +++ b/server/middlewares/validators/avatar.ts | |||
@@ -2,7 +2,7 @@ import * as express from 'express' | |||
2 | import { body } from 'express-validator/check' | 2 | import { body } from 'express-validator/check' |
3 | import { isAvatarFile } from '../../helpers/custom-validators/users' | 3 | import { isAvatarFile } from '../../helpers/custom-validators/users' |
4 | import { areValidationErrors } from './utils' | 4 | import { areValidationErrors } from './utils' |
5 | import { CONSTRAINTS_FIELDS } from '../../initializers' | 5 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
6 | import { logger } from '../../helpers/logger' | 6 | import { logger } from '../../helpers/logger' |
7 | import { cleanUpReqFiles } from '../../helpers/express-utils' | 7 | import { cleanUpReqFiles } from '../../helpers/express-utils' |
8 | 8 | ||
diff --git a/server/middlewares/validators/blocklist.ts b/server/middlewares/validators/blocklist.ts index 109276c63..7c494de78 100644 --- a/server/middlewares/validators/blocklist.ts +++ b/server/middlewares/validators/blocklist.ts | |||
@@ -2,14 +2,13 @@ import { body, param } from 'express-validator/check' | |||
2 | import * as express from 'express' | 2 | import * as express from 'express' |
3 | import { logger } from '../../helpers/logger' | 3 | import { logger } from '../../helpers/logger' |
4 | import { areValidationErrors } from './utils' | 4 | import { areValidationErrors } from './utils' |
5 | import { isAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' | 5 | import { doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' |
6 | import { UserModel } from '../../models/account/user' | ||
7 | import { AccountBlocklistModel } from '../../models/account/account-blocklist' | 6 | import { AccountBlocklistModel } from '../../models/account/account-blocklist' |
8 | import { isHostValid } from '../../helpers/custom-validators/servers' | 7 | import { isHostValid } from '../../helpers/custom-validators/servers' |
9 | import { ServerBlocklistModel } from '../../models/server/server-blocklist' | 8 | import { ServerBlocklistModel } from '../../models/server/server-blocklist' |
10 | import { ServerModel } from '../../models/server/server' | 9 | import { ServerModel } from '../../models/server/server' |
11 | import { CONFIG } from '../../initializers' | ||
12 | import { getServerActor } from '../../helpers/utils' | 10 | import { getServerActor } from '../../helpers/utils' |
11 | import { WEBSERVER } from '../../initializers/constants' | ||
13 | 12 | ||
14 | const blockAccountValidator = [ | 13 | const blockAccountValidator = [ |
15 | body('accountName').exists().withMessage('Should have an account name with host'), | 14 | body('accountName').exists().withMessage('Should have an account name with host'), |
@@ -18,9 +17,9 @@ const blockAccountValidator = [ | |||
18 | logger.debug('Checking blockAccountByAccountValidator parameters', { parameters: req.body }) | 17 | logger.debug('Checking blockAccountByAccountValidator parameters', { parameters: req.body }) |
19 | 18 | ||
20 | if (areValidationErrors(req, res)) return | 19 | if (areValidationErrors(req, res)) return |
21 | if (!await isAccountNameWithHostExist(req.body.accountName, res)) return | 20 | if (!await doesAccountNameWithHostExist(req.body.accountName, res)) return |
22 | 21 | ||
23 | const user = res.locals.oauth.token.User as UserModel | 22 | const user = res.locals.oauth.token.User |
24 | const accountToBlock = res.locals.account | 23 | const accountToBlock = res.locals.account |
25 | 24 | ||
26 | if (user.Account.id === accountToBlock.id) { | 25 | if (user.Account.id === accountToBlock.id) { |
@@ -42,11 +41,11 @@ const unblockAccountByAccountValidator = [ | |||
42 | logger.debug('Checking unblockAccountByAccountValidator parameters', { parameters: req.params }) | 41 | logger.debug('Checking unblockAccountByAccountValidator parameters', { parameters: req.params }) |
43 | 42 | ||
44 | if (areValidationErrors(req, res)) return | 43 | if (areValidationErrors(req, res)) return |
45 | if (!await isAccountNameWithHostExist(req.params.accountName, res)) return | 44 | if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return |
46 | 45 | ||
47 | const user = res.locals.oauth.token.User as UserModel | 46 | const user = res.locals.oauth.token.User |
48 | const targetAccount = res.locals.account | 47 | const targetAccount = res.locals.account |
49 | if (!await isUnblockAccountExists(user.Account.id, targetAccount.id, res)) return | 48 | if (!await doesUnblockAccountExist(user.Account.id, targetAccount.id, res)) return |
50 | 49 | ||
51 | return next() | 50 | return next() |
52 | } | 51 | } |
@@ -59,11 +58,11 @@ const unblockAccountByServerValidator = [ | |||
59 | logger.debug('Checking unblockAccountByServerValidator parameters', { parameters: req.params }) | 58 | logger.debug('Checking unblockAccountByServerValidator parameters', { parameters: req.params }) |
60 | 59 | ||
61 | if (areValidationErrors(req, res)) return | 60 | if (areValidationErrors(req, res)) return |
62 | if (!await isAccountNameWithHostExist(req.params.accountName, res)) return | 61 | if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return |
63 | 62 | ||
64 | const serverActor = await getServerActor() | 63 | const serverActor = await getServerActor() |
65 | const targetAccount = res.locals.account | 64 | const targetAccount = res.locals.account |
66 | if (!await isUnblockAccountExists(serverActor.Account.id, targetAccount.id, res)) return | 65 | if (!await doesUnblockAccountExist(serverActor.Account.id, targetAccount.id, res)) return |
67 | 66 | ||
68 | return next() | 67 | return next() |
69 | } | 68 | } |
@@ -79,7 +78,7 @@ const blockServerValidator = [ | |||
79 | 78 | ||
80 | const host: string = req.body.host | 79 | const host: string = req.body.host |
81 | 80 | ||
82 | if (host === CONFIG.WEBSERVER.HOST) { | 81 | if (host === WEBSERVER.HOST) { |
83 | return res.status(409) | 82 | return res.status(409) |
84 | .send({ error: 'You cannot block your own server.' }) | 83 | .send({ error: 'You cannot block your own server.' }) |
85 | .end() | 84 | .end() |
@@ -106,8 +105,8 @@ const unblockServerByAccountValidator = [ | |||
106 | 105 | ||
107 | if (areValidationErrors(req, res)) return | 106 | if (areValidationErrors(req, res)) return |
108 | 107 | ||
109 | const user = res.locals.oauth.token.User as UserModel | 108 | const user = res.locals.oauth.token.User |
110 | if (!await isUnblockServerExists(user.Account.id, req.params.host, res)) return | 109 | if (!await doesUnblockServerExist(user.Account.id, req.params.host, res)) return |
111 | 110 | ||
112 | return next() | 111 | return next() |
113 | } | 112 | } |
@@ -122,7 +121,7 @@ const unblockServerByServerValidator = [ | |||
122 | if (areValidationErrors(req, res)) return | 121 | if (areValidationErrors(req, res)) return |
123 | 122 | ||
124 | const serverActor = await getServerActor() | 123 | const serverActor = await getServerActor() |
125 | if (!await isUnblockServerExists(serverActor.Account.id, req.params.host, res)) return | 124 | if (!await doesUnblockServerExist(serverActor.Account.id, req.params.host, res)) return |
126 | 125 | ||
127 | return next() | 126 | return next() |
128 | } | 127 | } |
@@ -141,7 +140,7 @@ export { | |||
141 | 140 | ||
142 | // --------------------------------------------------------------------------- | 141 | // --------------------------------------------------------------------------- |
143 | 142 | ||
144 | async function isUnblockAccountExists (accountId: number, targetAccountId: number, res: express.Response) { | 143 | async function doesUnblockAccountExist (accountId: number, targetAccountId: number, res: express.Response) { |
145 | const accountBlock = await AccountBlocklistModel.loadByAccountAndTarget(accountId, targetAccountId) | 144 | const accountBlock = await AccountBlocklistModel.loadByAccountAndTarget(accountId, targetAccountId) |
146 | if (!accountBlock) { | 145 | if (!accountBlock) { |
147 | res.status(404) | 146 | res.status(404) |
@@ -156,7 +155,7 @@ async function isUnblockAccountExists (accountId: number, targetAccountId: numbe | |||
156 | return true | 155 | return true |
157 | } | 156 | } |
158 | 157 | ||
159 | async function isUnblockServerExists (accountId: number, host: string, res: express.Response) { | 158 | async function doesUnblockServerExist (accountId: number, host: string, res: express.Response) { |
160 | const serverBlock = await ServerBlocklistModel.loadByAccountAndHost(accountId, host) | 159 | const serverBlock = await ServerBlocklistModel.loadByAccountAndHost(accountId, host) |
161 | if (!serverBlock) { | 160 | if (!serverBlock) { |
162 | res.status(404) | 161 | res.status(404) |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index 90108fa82..d015fa6fe 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -2,6 +2,8 @@ import * as express from 'express' | |||
2 | import { body } from 'express-validator/check' | 2 | import { body } from 'express-validator/check' |
3 | import { isUserNSFWPolicyValid, isUserVideoQuotaValid, isUserVideoQuotaDailyValid } from '../../helpers/custom-validators/users' | 3 | import { isUserNSFWPolicyValid, isUserVideoQuotaValid, isUserVideoQuotaDailyValid } from '../../helpers/custom-validators/users' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' | ||
6 | import { Emailer } from '../../lib/emailer' | ||
5 | import { areValidationErrors } from './utils' | 7 | import { areValidationErrors } from './utils' |
6 | 8 | ||
7 | const customConfigUpdateValidator = [ | 9 | const customConfigUpdateValidator = [ |
@@ -42,15 +44,34 @@ const customConfigUpdateValidator = [ | |||
42 | body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), | 44 | body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), |
43 | body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), | 45 | body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), |
44 | 46 | ||
47 | body('followers.instance.enabled').isBoolean().withMessage('Should have a valid followers of instance boolean'), | ||
48 | body('followers.instance.manualApproval').isBoolean().withMessage('Should have a valid manual approval boolean'), | ||
49 | |||
45 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 50 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
46 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) | 51 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) |
47 | 52 | ||
48 | if (areValidationErrors(req, res)) return | 53 | if (areValidationErrors(req, res)) return |
54 | if (!checkInvalidConfigIfEmailDisabled(req.body as CustomConfig, res)) return | ||
49 | 55 | ||
50 | return next() | 56 | return next() |
51 | } | 57 | } |
52 | ] | 58 | ] |
53 | 59 | ||
60 | // --------------------------------------------------------------------------- | ||
61 | |||
54 | export { | 62 | export { |
55 | customConfigUpdateValidator | 63 | customConfigUpdateValidator |
56 | } | 64 | } |
65 | |||
66 | function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) { | ||
67 | if (Emailer.isEnabled()) return true | ||
68 | |||
69 | if (customConfig.signup.requiresEmailVerification === true) { | ||
70 | res.status(400) | ||
71 | .send({ error: 'Emailer is disabled but you require signup email verification.' }) | ||
72 | .end() | ||
73 | return false | ||
74 | } | ||
75 | |||
76 | return true | ||
77 | } | ||
diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts index 969ce2526..e4f5c98fe 100644 --- a/server/middlewares/validators/feeds.ts +++ b/server/middlewares/validators/feeds.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { param, query } from 'express-validator/check' | 2 | import { param, query } from 'express-validator/check' |
3 | import { isAccountIdExist, isAccountNameValid, isAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' | 3 | import { doesAccountIdExist, isAccountNameValid, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' |
4 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' |
5 | import { logger } from '../../helpers/logger' | 5 | import { logger } from '../../helpers/logger' |
6 | import { areValidationErrors } from './utils' | 6 | import { areValidationErrors } from './utils' |
7 | import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' | 7 | import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' |
8 | import { isVideoChannelIdExist, isVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels' | 8 | import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels' |
9 | import { isVideoExist } from '../../helpers/custom-validators/videos' | 9 | import { doesVideoExist } from '../../helpers/custom-validators/videos' |
10 | import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor' | 10 | import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor' |
11 | 11 | ||
12 | const videoFeedsValidator = [ | 12 | const videoFeedsValidator = [ |
@@ -22,10 +22,10 @@ const videoFeedsValidator = [ | |||
22 | 22 | ||
23 | if (areValidationErrors(req, res)) return | 23 | if (areValidationErrors(req, res)) return |
24 | 24 | ||
25 | if (req.query.accountId && !await isAccountIdExist(req.query.accountId, res)) return | 25 | if (req.query.accountId && !await doesAccountIdExist(req.query.accountId, res)) return |
26 | if (req.query.videoChannelId && !await isVideoChannelIdExist(req.query.videoChannelId, res)) return | 26 | if (req.query.videoChannelId && !await doesVideoChannelIdExist(req.query.videoChannelId, res)) return |
27 | if (req.query.accountName && !await isAccountNameWithHostExist(req.query.accountName, res)) return | 27 | if (req.query.accountName && !await doesAccountNameWithHostExist(req.query.accountName, res)) return |
28 | if (req.query.videoChannelName && !await isVideoChannelNameWithHostExist(req.query.videoChannelName, res)) return | 28 | if (req.query.videoChannelName && !await doesVideoChannelNameWithHostExist(req.query.videoChannelName, res)) return |
29 | 29 | ||
30 | return next() | 30 | return next() |
31 | } | 31 | } |
@@ -41,7 +41,7 @@ const videoCommentsFeedsValidator = [ | |||
41 | 41 | ||
42 | if (areValidationErrors(req, res)) return | 42 | if (areValidationErrors(req, res)) return |
43 | 43 | ||
44 | if (req.query.videoId && !await isVideoExist(req.query.videoId, res)) return | 44 | if (req.query.videoId && !await doesVideoExist(req.query.videoId, res)) return |
45 | 45 | ||
46 | return next() | 46 | return next() |
47 | } | 47 | } |
diff --git a/server/middlewares/validators/follows.ts b/server/middlewares/validators/follows.ts index 73fa28be9..2e5a02307 100644 --- a/server/middlewares/validators/follows.ts +++ b/server/middlewares/validators/follows.ts | |||
@@ -4,16 +4,19 @@ import { isTestInstance } from '../../helpers/core-utils' | |||
4 | import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers' | 4 | import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers' |
5 | import { logger } from '../../helpers/logger' | 5 | import { logger } from '../../helpers/logger' |
6 | import { getServerActor } from '../../helpers/utils' | 6 | import { getServerActor } from '../../helpers/utils' |
7 | import { CONFIG, SERVER_ACTOR_NAME } from '../../initializers' | 7 | import { SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants' |
8 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' | 8 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' |
9 | import { areValidationErrors } from './utils' | 9 | import { areValidationErrors } from './utils' |
10 | import { ActorModel } from '../../models/activitypub/actor' | ||
11 | import { loadActorUrlOrGetFromWebfinger } from '../../helpers/webfinger' | ||
12 | import { isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' | ||
10 | 13 | ||
11 | const followValidator = [ | 14 | const followValidator = [ |
12 | body('hosts').custom(isEachUniqueHostValid).withMessage('Should have an array of unique hosts'), | 15 | body('hosts').custom(isEachUniqueHostValid).withMessage('Should have an array of unique hosts'), |
13 | 16 | ||
14 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 17 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
15 | // Force https if the administrator wants to make friends | 18 | // Force https if the administrator wants to make friends |
16 | if (isTestInstance() === false && CONFIG.WEBSERVER.SCHEME === 'http') { | 19 | if (isTestInstance() === false && WEBSERVER.SCHEME === 'http') { |
17 | return res.status(500) | 20 | return res.status(500) |
18 | .json({ | 21 | .json({ |
19 | error: 'Cannot follow on a non HTTPS web server.' | 22 | error: 'Cannot follow on a non HTTPS web server.' |
@@ -33,7 +36,7 @@ const removeFollowingValidator = [ | |||
33 | param('host').custom(isHostValid).withMessage('Should have a valid host'), | 36 | param('host').custom(isHostValid).withMessage('Should have a valid host'), |
34 | 37 | ||
35 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 38 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
36 | logger.debug('Checking unfollow parameters', { parameters: req.params }) | 39 | logger.debug('Checking unfollowing parameters', { parameters: req.params }) |
37 | 40 | ||
38 | if (areValidationErrors(req, res)) return | 41 | if (areValidationErrors(req, res)) return |
39 | 42 | ||
@@ -44,7 +47,7 @@ const removeFollowingValidator = [ | |||
44 | return res | 47 | return res |
45 | .status(404) | 48 | .status(404) |
46 | .json({ | 49 | .json({ |
47 | error: `Follower ${req.params.host} not found.` | 50 | error: `Following ${req.params.host} not found.` |
48 | }) | 51 | }) |
49 | .end() | 52 | .end() |
50 | } | 53 | } |
@@ -54,9 +57,57 @@ const removeFollowingValidator = [ | |||
54 | } | 57 | } |
55 | ] | 58 | ] |
56 | 59 | ||
60 | const getFollowerValidator = [ | ||
61 | param('nameWithHost').custom(isValidActorHandle).withMessage('Should have a valid nameWithHost'), | ||
62 | |||
63 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
64 | logger.debug('Checking get follower parameters', { parameters: req.params }) | ||
65 | |||
66 | if (areValidationErrors(req, res)) return | ||
67 | |||
68 | let follow: ActorFollowModel | ||
69 | try { | ||
70 | const actorUrl = await loadActorUrlOrGetFromWebfinger(req.params.nameWithHost) | ||
71 | const actor = await ActorModel.loadByUrl(actorUrl) | ||
72 | |||
73 | const serverActor = await getServerActor() | ||
74 | follow = await ActorFollowModel.loadByActorAndTarget(actor.id, serverActor.id) | ||
75 | } catch (err) { | ||
76 | logger.warn('Cannot get actor from handle.', { handle: req.params.nameWithHost, err }) | ||
77 | } | ||
78 | |||
79 | if (!follow) { | ||
80 | return res | ||
81 | .status(404) | ||
82 | .json({ | ||
83 | error: `Follower ${req.params.nameWithHost} not found.` | ||
84 | }) | ||
85 | .end() | ||
86 | } | ||
87 | |||
88 | res.locals.follow = follow | ||
89 | return next() | ||
90 | } | ||
91 | ] | ||
92 | |||
93 | const acceptOrRejectFollowerValidator = [ | ||
94 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
95 | logger.debug('Checking accept/reject follower parameters', { parameters: req.params }) | ||
96 | |||
97 | const follow = res.locals.follow | ||
98 | if (follow.state !== 'pending') { | ||
99 | return res.status(400).json({ error: 'Follow is not in pending state.' }).end() | ||
100 | } | ||
101 | |||
102 | return next() | ||
103 | } | ||
104 | ] | ||
105 | |||
57 | // --------------------------------------------------------------------------- | 106 | // --------------------------------------------------------------------------- |
58 | 107 | ||
59 | export { | 108 | export { |
60 | followValidator, | 109 | followValidator, |
61 | removeFollowingValidator | 110 | removeFollowingValidator, |
111 | getFollowerValidator, | ||
112 | acceptOrRejectFollowerValidator | ||
62 | } | 113 | } |
diff --git a/server/middlewares/validators/logs.ts b/server/middlewares/validators/logs.ts new file mode 100644 index 000000000..7380c6edd --- /dev/null +++ b/server/middlewares/validators/logs.ts | |||
@@ -0,0 +1,31 @@ | |||
1 | import * as express from 'express' | ||
2 | import { logger } from '../../helpers/logger' | ||
3 | import { areValidationErrors } from './utils' | ||
4 | import { isDateValid } from '../../helpers/custom-validators/misc' | ||
5 | import { query } from 'express-validator/check' | ||
6 | import { isValidLogLevel } from '../../helpers/custom-validators/logs' | ||
7 | |||
8 | const getLogsValidator = [ | ||
9 | query('startDate') | ||
10 | .custom(isDateValid).withMessage('Should have a valid start date'), | ||
11 | query('level') | ||
12 | .optional() | ||
13 | .custom(isValidLogLevel).withMessage('Should have a valid level'), | ||
14 | query('endDate') | ||
15 | .optional() | ||
16 | .custom(isDateValid).withMessage('Should have a valid end date'), | ||
17 | |||
18 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
19 | logger.debug('Checking getLogsValidator parameters.', { parameters: req.query }) | ||
20 | |||
21 | if (areValidationErrors(req, res)) return | ||
22 | |||
23 | return next() | ||
24 | } | ||
25 | ] | ||
26 | |||
27 | // --------------------------------------------------------------------------- | ||
28 | |||
29 | export { | ||
30 | getLogsValidator | ||
31 | } | ||
diff --git a/server/middlewares/validators/oembed.ts b/server/middlewares/validators/oembed.ts index cd9b27b16..0bb908d0b 100644 --- a/server/middlewares/validators/oembed.ts +++ b/server/middlewares/validators/oembed.ts | |||
@@ -3,12 +3,12 @@ import { query } from 'express-validator/check' | |||
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { isTestInstance } from '../../helpers/core-utils' | 4 | import { isTestInstance } from '../../helpers/core-utils' |
5 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' | 5 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' |
6 | import { isVideoExist } from '../../helpers/custom-validators/videos' | 6 | import { doesVideoExist } from '../../helpers/custom-validators/videos' |
7 | import { logger } from '../../helpers/logger' | 7 | import { logger } from '../../helpers/logger' |
8 | import { CONFIG } from '../../initializers' | ||
9 | import { areValidationErrors } from './utils' | 8 | import { areValidationErrors } from './utils' |
9 | import { WEBSERVER } from '../../initializers/constants' | ||
10 | 10 | ||
11 | const urlShouldStartWith = CONFIG.WEBSERVER.SCHEME + '://' + join(CONFIG.WEBSERVER.HOST, 'videos', 'watch') + '/' | 11 | const urlShouldStartWith = WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, 'videos', 'watch') + '/' |
12 | const videoWatchRegex = new RegExp('([^/]+)$') | 12 | const videoWatchRegex = new RegExp('([^/]+)$') |
13 | const isURLOptions = { | 13 | const isURLOptions = { |
14 | require_host: true, | 14 | require_host: true, |
@@ -52,7 +52,7 @@ const oembedValidator = [ | |||
52 | .end() | 52 | .end() |
53 | } | 53 | } |
54 | 54 | ||
55 | if (!await isVideoExist(videoId, res)) return | 55 | if (!await doesVideoExist(videoId, res)) return |
56 | 56 | ||
57 | return next() | 57 | return next() |
58 | } | 58 | } |
diff --git a/server/middlewares/validators/redundancy.ts b/server/middlewares/validators/redundancy.ts index c72ab78b2..76cf89c40 100644 --- a/server/middlewares/validators/redundancy.ts +++ b/server/middlewares/validators/redundancy.ts | |||
@@ -1,19 +1,15 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import 'express-validator' | 2 | import 'express-validator' |
3 | import { param, body } from 'express-validator/check' | 3 | import { body, param } from 'express-validator/check' |
4 | import { exists, isBooleanValid, isIdOrUUIDValid, toIntOrNull } from '../../helpers/custom-validators/misc' | 4 | import { exists, isBooleanValid, isIdOrUUIDValid, toIntOrNull } from '../../helpers/custom-validators/misc' |
5 | import { isVideoExist } from '../../helpers/custom-validators/videos' | 5 | import { doesVideoExist } from '../../helpers/custom-validators/videos' |
6 | import { logger } from '../../helpers/logger' | 6 | import { logger } from '../../helpers/logger' |
7 | import { areValidationErrors } from './utils' | 7 | import { areValidationErrors } from './utils' |
8 | import { VideoModel } from '../../models/video/video' | ||
9 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 8 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
10 | import { isHostValid } from '../../helpers/custom-validators/servers' | 9 | import { isHostValid } from '../../helpers/custom-validators/servers' |
11 | import { getServerActor } from '../../helpers/utils' | ||
12 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' | ||
13 | import { SERVER_ACTOR_NAME } from '../../initializers' | ||
14 | import { ServerModel } from '../../models/server/server' | 10 | import { ServerModel } from '../../models/server/server' |
15 | 11 | ||
16 | const videoRedundancyGetValidator = [ | 12 | const videoFileRedundancyGetValidator = [ |
17 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), | 13 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), |
18 | param('resolution') | 14 | param('resolution') |
19 | .customSanitizer(toIntOrNull) | 15 | .customSanitizer(toIntOrNull) |
@@ -24,12 +20,12 @@ const videoRedundancyGetValidator = [ | |||
24 | .custom(exists).withMessage('Should have a valid fps'), | 20 | .custom(exists).withMessage('Should have a valid fps'), |
25 | 21 | ||
26 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 22 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
27 | logger.debug('Checking videoRedundancyGetValidator parameters', { parameters: req.params }) | 23 | logger.debug('Checking videoFileRedundancyGetValidator parameters', { parameters: req.params }) |
28 | 24 | ||
29 | if (areValidationErrors(req, res)) return | 25 | if (areValidationErrors(req, res)) return |
30 | if (!await isVideoExist(req.params.videoId, res)) return | 26 | if (!await doesVideoExist(req.params.videoId, res)) return |
31 | 27 | ||
32 | const video: VideoModel = res.locals.video | 28 | const video = res.locals.video |
33 | const videoFile = video.VideoFiles.find(f => { | 29 | const videoFile = video.VideoFiles.find(f => { |
34 | return f.resolution === req.params.resolution && (!req.params.fps || f.fps === req.params.fps) | 30 | return f.resolution === req.params.resolution && (!req.params.fps || f.fps === req.params.fps) |
35 | }) | 31 | }) |
@@ -38,7 +34,31 @@ const videoRedundancyGetValidator = [ | |||
38 | res.locals.videoFile = videoFile | 34 | res.locals.videoFile = videoFile |
39 | 35 | ||
40 | const videoRedundancy = await VideoRedundancyModel.loadLocalByFileId(videoFile.id) | 36 | const videoRedundancy = await VideoRedundancyModel.loadLocalByFileId(videoFile.id) |
41 | if (!videoRedundancy)return res.status(404).json({ error: 'Video redundancy not found.' }) | 37 | if (!videoRedundancy) return res.status(404).json({ error: 'Video redundancy not found.' }) |
38 | res.locals.videoRedundancy = videoRedundancy | ||
39 | |||
40 | return next() | ||
41 | } | ||
42 | ] | ||
43 | |||
44 | const videoPlaylistRedundancyGetValidator = [ | ||
45 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), | ||
46 | param('streamingPlaylistType').custom(exists).withMessage('Should have a valid streaming playlist type'), | ||
47 | |||
48 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
49 | logger.debug('Checking videoPlaylistRedundancyGetValidator parameters', { parameters: req.params }) | ||
50 | |||
51 | if (areValidationErrors(req, res)) return | ||
52 | if (!await doesVideoExist(req.params.videoId, res)) return | ||
53 | |||
54 | const video = res.locals.video | ||
55 | const videoStreamingPlaylist = video.VideoStreamingPlaylists.find(p => p === req.params.streamingPlaylistType) | ||
56 | |||
57 | if (!videoStreamingPlaylist) return res.status(404).json({ error: 'Video playlist not found.' }) | ||
58 | res.locals.videoStreamingPlaylist = videoStreamingPlaylist | ||
59 | |||
60 | const videoRedundancy = await VideoRedundancyModel.loadLocalByStreamingPlaylistId(videoStreamingPlaylist.id) | ||
61 | if (!videoRedundancy) return res.status(404).json({ error: 'Video redundancy not found.' }) | ||
42 | res.locals.videoRedundancy = videoRedundancy | 62 | res.locals.videoRedundancy = videoRedundancy |
43 | 63 | ||
44 | return next() | 64 | return next() |
@@ -75,6 +95,7 @@ const updateServerRedundancyValidator = [ | |||
75 | // --------------------------------------------------------------------------- | 95 | // --------------------------------------------------------------------------- |
76 | 96 | ||
77 | export { | 97 | export { |
78 | videoRedundancyGetValidator, | 98 | videoFileRedundancyGetValidator, |
99 | videoPlaylistRedundancyGetValidator, | ||
79 | updateServerRedundancyValidator | 100 | updateServerRedundancyValidator |
80 | } | 101 | } |
diff --git a/server/middlewares/validators/search.ts b/server/middlewares/validators/search.ts index 6a95d6095..7816d229c 100644 --- a/server/middlewares/validators/search.ts +++ b/server/middlewares/validators/search.ts | |||
@@ -10,6 +10,9 @@ const videosSearchValidator = [ | |||
10 | query('startDate').optional().custom(isDateValid).withMessage('Should have a valid start date'), | 10 | query('startDate').optional().custom(isDateValid).withMessage('Should have a valid start date'), |
11 | query('endDate').optional().custom(isDateValid).withMessage('Should have a valid end date'), | 11 | query('endDate').optional().custom(isDateValid).withMessage('Should have a valid end date'), |
12 | 12 | ||
13 | query('originallyPublishedStartDate').optional().custom(isDateValid).withMessage('Should have a valid published start date'), | ||
14 | query('originallyPublishedEndDate').optional().custom(isDateValid).withMessage('Should have a valid published end date'), | ||
15 | |||
13 | query('durationMin').optional().isInt().withMessage('Should have a valid min duration'), | 16 | query('durationMin').optional().isInt().withMessage('Should have a valid min duration'), |
14 | query('durationMax').optional().isInt().withMessage('Should have a valid max duration'), | 17 | query('durationMax').optional().isInt().withMessage('Should have a valid max duration'), |
15 | 18 | ||
diff --git a/server/middlewares/validators/server.ts b/server/middlewares/validators/server.ts index d85afc2ff..6eff8e9ee 100644 --- a/server/middlewares/validators/server.ts +++ b/server/middlewares/validators/server.ts | |||
@@ -7,7 +7,7 @@ import { body } from 'express-validator/check' | |||
7 | import { isUserDisplayNameValid } from '../../helpers/custom-validators/users' | 7 | import { isUserDisplayNameValid } from '../../helpers/custom-validators/users' |
8 | import { Emailer } from '../../lib/emailer' | 8 | import { Emailer } from '../../lib/emailer' |
9 | import { Redis } from '../../lib/redis' | 9 | import { Redis } from '../../lib/redis' |
10 | import { CONFIG } from '../../initializers/constants' | 10 | import { CONFIG } from '../../initializers/config' |
11 | 11 | ||
12 | const serverGetValidator = [ | 12 | const serverGetValidator = [ |
13 | body('host').custom(isHostValid).withMessage('Should have a valid host'), | 13 | body('host').custom(isHostValid).withMessage('Should have a valid host'), |
@@ -57,7 +57,7 @@ const contactAdministratorValidator = [ | |||
57 | .end() | 57 | .end() |
58 | } | 58 | } |
59 | 59 | ||
60 | if (await Redis.Instance.isContactFormIpExists(req.ip)) { | 60 | if (await Redis.Instance.doesContactFormIpExist(req.ip)) { |
61 | logger.info('Refusing a contact form by %s: already sent one recently.', req.ip) | 61 | logger.info('Refusing a contact form by %s: already sent one recently.', req.ip) |
62 | 62 | ||
63 | return res | 63 | return res |
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index 5ceda845f..b497798d1 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { SORTABLE_COLUMNS } from '../../initializers' | 1 | import { SORTABLE_COLUMNS } from '../../initializers/constants' |
2 | import { checkSort, createSortableColumns } from './utils' | 2 | import { checkSort, createSortableColumns } from './utils' |
3 | 3 | ||
4 | // Initialize constants here for better performances | 4 | // Initialize constants here for better performances |
@@ -11,6 +11,7 @@ const SORTABLE_VIDEOS_SEARCH_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VI | |||
11 | const SORTABLE_VIDEO_CHANNELS_SEARCH_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_CHANNELS_SEARCH) | 11 | const SORTABLE_VIDEO_CHANNELS_SEARCH_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_CHANNELS_SEARCH) |
12 | const SORTABLE_VIDEO_IMPORTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_IMPORTS) | 12 | const SORTABLE_VIDEO_IMPORTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_IMPORTS) |
13 | const SORTABLE_VIDEO_COMMENT_THREADS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_COMMENT_THREADS) | 13 | const SORTABLE_VIDEO_COMMENT_THREADS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_COMMENT_THREADS) |
14 | const SORTABLE_VIDEO_RATES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_RATES) | ||
14 | const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS) | 15 | const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS) |
15 | const SORTABLE_VIDEO_CHANNELS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_CHANNELS) | 16 | const SORTABLE_VIDEO_CHANNELS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_CHANNELS) |
16 | const SORTABLE_FOLLOWERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.FOLLOWERS) | 17 | const SORTABLE_FOLLOWERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.FOLLOWERS) |
@@ -19,6 +20,7 @@ const SORTABLE_USER_SUBSCRIPTIONS_COLUMNS = createSortableColumns(SORTABLE_COLUM | |||
19 | const SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.ACCOUNTS_BLOCKLIST) | 20 | const SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.ACCOUNTS_BLOCKLIST) |
20 | const SORTABLE_SERVERS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.SERVERS_BLOCKLIST) | 21 | const SORTABLE_SERVERS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.SERVERS_BLOCKLIST) |
21 | const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USER_NOTIFICATIONS) | 22 | const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USER_NOTIFICATIONS) |
23 | const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) | ||
22 | 24 | ||
23 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) | 25 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) |
24 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) | 26 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) |
@@ -29,6 +31,7 @@ const videoImportsSortValidator = checkSort(SORTABLE_VIDEO_IMPORTS_COLUMNS) | |||
29 | const videosSearchSortValidator = checkSort(SORTABLE_VIDEOS_SEARCH_COLUMNS) | 31 | const videosSearchSortValidator = checkSort(SORTABLE_VIDEOS_SEARCH_COLUMNS) |
30 | const videoChannelsSearchSortValidator = checkSort(SORTABLE_VIDEO_CHANNELS_SEARCH_COLUMNS) | 32 | const videoChannelsSearchSortValidator = checkSort(SORTABLE_VIDEO_CHANNELS_SEARCH_COLUMNS) |
31 | const videoCommentThreadsSortValidator = checkSort(SORTABLE_VIDEO_COMMENT_THREADS_COLUMNS) | 33 | const videoCommentThreadsSortValidator = checkSort(SORTABLE_VIDEO_COMMENT_THREADS_COLUMNS) |
34 | const videoRatesSortValidator = checkSort(SORTABLE_VIDEO_RATES_COLUMNS) | ||
32 | const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS) | 35 | const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS) |
33 | const videoChannelsSortValidator = checkSort(SORTABLE_VIDEO_CHANNELS_COLUMNS) | 36 | const videoChannelsSortValidator = checkSort(SORTABLE_VIDEO_CHANNELS_COLUMNS) |
34 | const followersSortValidator = checkSort(SORTABLE_FOLLOWERS_COLUMNS) | 37 | const followersSortValidator = checkSort(SORTABLE_FOLLOWERS_COLUMNS) |
@@ -37,6 +40,7 @@ const userSubscriptionsSortValidator = checkSort(SORTABLE_USER_SUBSCRIPTIONS_COL | |||
37 | const accountsBlocklistSortValidator = checkSort(SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS) | 40 | const accountsBlocklistSortValidator = checkSort(SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS) |
38 | const serversBlocklistSortValidator = checkSort(SORTABLE_SERVERS_BLOCKLIST_COLUMNS) | 41 | const serversBlocklistSortValidator = checkSort(SORTABLE_SERVERS_BLOCKLIST_COLUMNS) |
39 | const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COLUMNS) | 42 | const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COLUMNS) |
43 | const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) | ||
40 | 44 | ||
41 | // --------------------------------------------------------------------------- | 45 | // --------------------------------------------------------------------------- |
42 | 46 | ||
@@ -53,9 +57,11 @@ export { | |||
53 | followingSortValidator, | 57 | followingSortValidator, |
54 | jobsSortValidator, | 58 | jobsSortValidator, |
55 | videoCommentThreadsSortValidator, | 59 | videoCommentThreadsSortValidator, |
60 | videoRatesSortValidator, | ||
56 | userSubscriptionsSortValidator, | 61 | userSubscriptionsSortValidator, |
57 | videoChannelsSearchSortValidator, | 62 | videoChannelsSearchSortValidator, |
58 | accountsBlocklistSortValidator, | 63 | accountsBlocklistSortValidator, |
59 | serversBlocklistSortValidator, | 64 | serversBlocklistSortValidator, |
60 | userNotificationsSortValidator | 65 | userNotificationsSortValidator, |
66 | videoPlaylistsSortValidator | ||
61 | } | 67 | } |
diff --git a/server/middlewares/validators/user-notifications.ts b/server/middlewares/validators/user-notifications.ts index 46486e081..3ded8d8cf 100644 --- a/server/middlewares/validators/user-notifications.ts +++ b/server/middlewares/validators/user-notifications.ts | |||
@@ -28,8 +28,22 @@ const updateNotificationSettingsValidator = [ | |||
28 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new comment on my video notification setting'), | 28 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new comment on my video notification setting'), |
29 | body('videoAbuseAsModerator') | 29 | body('videoAbuseAsModerator') |
30 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new video abuse as moderator notification setting'), | 30 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new video abuse as moderator notification setting'), |
31 | body('videoAutoBlacklistAsModerator') | ||
32 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid video auto blacklist notification setting'), | ||
31 | body('blacklistOnMyVideo') | 33 | body('blacklistOnMyVideo') |
32 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new blacklist on my video notification setting'), | 34 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new blacklist on my video notification setting'), |
35 | body('myVideoImportFinished') | ||
36 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid video import finished video notification setting'), | ||
37 | body('myVideoPublished') | ||
38 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid video published notification setting'), | ||
39 | body('commentMention') | ||
40 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid comment mention notification setting'), | ||
41 | body('newFollow') | ||
42 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new follow notification setting'), | ||
43 | body('newUserRegistration') | ||
44 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new user registration notification setting'), | ||
45 | body('newInstanceFollower') | ||
46 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new instance follower notification setting'), | ||
33 | 47 | ||
34 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 48 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
35 | logger.debug('Checking updateNotificationSettingsValidator parameters', { parameters: req.body }) | 49 | logger.debug('Checking updateNotificationSettingsValidator parameters', { parameters: req.body }) |
diff --git a/server/middlewares/validators/user-subscriptions.ts b/server/middlewares/validators/user-subscriptions.ts index c5f8d9d4c..2356745d7 100644 --- a/server/middlewares/validators/user-subscriptions.ts +++ b/server/middlewares/validators/user-subscriptions.ts | |||
@@ -5,9 +5,8 @@ import { logger } from '../../helpers/logger' | |||
5 | import { areValidationErrors } from './utils' | 5 | import { areValidationErrors } from './utils' |
6 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' | 6 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' |
7 | import { areValidActorHandles, isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' | 7 | import { areValidActorHandles, isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' |
8 | import { UserModel } from '../../models/account/user' | ||
9 | import { CONFIG } from '../../initializers' | ||
10 | import { toArray } from '../../helpers/custom-validators/misc' | 8 | import { toArray } from '../../helpers/custom-validators/misc' |
9 | import { WEBSERVER } from '../../initializers/constants' | ||
11 | 10 | ||
12 | const userSubscriptionAddValidator = [ | 11 | const userSubscriptionAddValidator = [ |
13 | body('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to follow (username@domain)'), | 12 | body('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to follow (username@domain)'), |
@@ -44,9 +43,9 @@ const userSubscriptionGetValidator = [ | |||
44 | if (areValidationErrors(req, res)) return | 43 | if (areValidationErrors(req, res)) return |
45 | 44 | ||
46 | let [ name, host ] = req.params.uri.split('@') | 45 | let [ name, host ] = req.params.uri.split('@') |
47 | if (host === CONFIG.WEBSERVER.HOST) host = null | 46 | if (host === WEBSERVER.HOST) host = null |
48 | 47 | ||
49 | const user: UserModel = res.locals.oauth.token.User | 48 | const user = res.locals.oauth.token.User |
50 | const subscription = await ActorFollowModel.loadByActorAndTargetNameAndHostForAPI(user.Account.Actor.id, name, host) | 49 | const subscription = await ActorFollowModel.loadByActorAndTargetNameAndHostForAPI(user.Account.Actor.id, name, host) |
51 | 50 | ||
52 | if (!subscription || !subscription.ActorFollowing.VideoChannel) { | 51 | if (!subscription || !subscription.ActorFollowing.VideoChannel) { |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 1bb0bfb1b..6d8cd7894 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -5,6 +5,7 @@ import { body, param } from 'express-validator/check' | |||
5 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
6 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' | 6 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' |
7 | import { | 7 | import { |
8 | isUserAdminFlagsValid, | ||
8 | isUserAutoPlayVideoValid, | 9 | isUserAutoPlayVideoValid, |
9 | isUserBlockedReasonValid, | 10 | isUserBlockedReasonValid, |
10 | isUserDescriptionValid, | 11 | isUserDescriptionValid, |
@@ -14,9 +15,10 @@ import { | |||
14 | isUserRoleValid, | 15 | isUserRoleValid, |
15 | isUserUsernameValid, | 16 | isUserUsernameValid, |
16 | isUserVideoQuotaDailyValid, | 17 | isUserVideoQuotaDailyValid, |
17 | isUserVideoQuotaValid, isUserVideosHistoryEnabledValid | 18 | isUserVideoQuotaValid, |
19 | isUserVideosHistoryEnabledValid | ||
18 | } from '../../helpers/custom-validators/users' | 20 | } from '../../helpers/custom-validators/users' |
19 | import { isVideoExist } from '../../helpers/custom-validators/videos' | 21 | import { doesVideoExist } from '../../helpers/custom-validators/videos' |
20 | import { logger } from '../../helpers/logger' | 22 | import { logger } from '../../helpers/logger' |
21 | import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/signup' | 23 | import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../helpers/signup' |
22 | import { Redis } from '../../lib/redis' | 24 | import { Redis } from '../../lib/redis' |
@@ -31,6 +33,7 @@ const usersAddValidator = [ | |||
31 | body('videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), | 33 | body('videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), |
32 | body('videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), | 34 | body('videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), |
33 | body('role').custom(isUserRoleValid).withMessage('Should have a valid role'), | 35 | body('role').custom(isUserRoleValid).withMessage('Should have a valid role'), |
36 | body('adminFlags').optional().custom(isUserAdminFlagsValid).withMessage('Should have a valid admin flags'), | ||
34 | 37 | ||
35 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 38 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
36 | logger.debug('Checking usersAdd parameters', { parameters: omit(req.body, 'password') }) | 39 | logger.debug('Checking usersAdd parameters', { parameters: omit(req.body, 'password') }) |
@@ -100,7 +103,7 @@ const usersBlockingValidator = [ | |||
100 | 103 | ||
101 | const deleteMeValidator = [ | 104 | const deleteMeValidator = [ |
102 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 105 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
103 | const user: UserModel = res.locals.oauth.token.User | 106 | const user = res.locals.oauth.token.User |
104 | if (user.username === 'root') { | 107 | if (user.username === 'root') { |
105 | return res.status(400) | 108 | return res.status(400) |
106 | .send({ error: 'You cannot delete your root account.' }) | 109 | .send({ error: 'You cannot delete your root account.' }) |
@@ -113,11 +116,13 @@ const deleteMeValidator = [ | |||
113 | 116 | ||
114 | const usersUpdateValidator = [ | 117 | const usersUpdateValidator = [ |
115 | param('id').isInt().not().isEmpty().withMessage('Should have a valid id'), | 118 | param('id').isInt().not().isEmpty().withMessage('Should have a valid id'), |
119 | body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'), | ||
116 | body('email').optional().isEmail().withMessage('Should have a valid email attribute'), | 120 | body('email').optional().isEmail().withMessage('Should have a valid email attribute'), |
117 | body('emailVerified').optional().isBoolean().withMessage('Should have a valid email verified attribute'), | 121 | body('emailVerified').optional().isBoolean().withMessage('Should have a valid email verified attribute'), |
118 | body('videoQuota').optional().custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), | 122 | body('videoQuota').optional().custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), |
119 | body('videoQuotaDaily').optional().custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), | 123 | body('videoQuotaDaily').optional().custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), |
120 | body('role').optional().custom(isUserRoleValid).withMessage('Should have a valid role'), | 124 | body('role').optional().custom(isUserRoleValid).withMessage('Should have a valid role'), |
125 | body('adminFlags').optional().custom(isUserAdminFlagsValid).withMessage('Should have a valid admin flags'), | ||
121 | 126 | ||
122 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 127 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
123 | logger.debug('Checking usersUpdate parameters', { parameters: req.body }) | 128 | logger.debug('Checking usersUpdate parameters', { parameters: req.body }) |
@@ -158,8 +163,7 @@ const usersUpdateMeValidator = [ | |||
158 | .end() | 163 | .end() |
159 | } | 164 | } |
160 | 165 | ||
161 | const user: UserModel = res.locals.oauth.token.User | 166 | const user = res.locals.oauth.token.User |
162 | |||
163 | if (await user.isPasswordMatch(req.body.currentPassword) !== true) { | 167 | if (await user.isPasswordMatch(req.body.currentPassword) !== true) { |
164 | return res.status(401) | 168 | return res.status(401) |
165 | .send({ error: 'currentPassword is invalid.' }) | 169 | .send({ error: 'currentPassword is invalid.' }) |
@@ -193,7 +197,7 @@ const usersVideoRatingValidator = [ | |||
193 | logger.debug('Checking usersVideoRating parameters', { parameters: req.params }) | 197 | logger.debug('Checking usersVideoRating parameters', { parameters: req.params }) |
194 | 198 | ||
195 | if (areValidationErrors(req, res)) return | 199 | if (areValidationErrors(req, res)) return |
196 | if (!await isVideoExist(req.params.videoId, res, 'id')) return | 200 | if (!await doesVideoExist(req.params.videoId, res, 'id')) return |
197 | 201 | ||
198 | return next() | 202 | return next() |
199 | } | 203 | } |
@@ -233,6 +237,7 @@ const usersAskResetPasswordValidator = [ | |||
233 | logger.debug('Checking usersAskResetPassword parameters', { parameters: req.body }) | 237 | logger.debug('Checking usersAskResetPassword parameters', { parameters: req.body }) |
234 | 238 | ||
235 | if (areValidationErrors(req, res)) return | 239 | if (areValidationErrors(req, res)) return |
240 | |||
236 | const exists = await checkUserEmailExist(req.body.email, res, false) | 241 | const exists = await checkUserEmailExist(req.body.email, res, false) |
237 | if (!exists) { | 242 | if (!exists) { |
238 | logger.debug('User with email %s does not exist (asking reset password).', req.body.email) | 243 | logger.debug('User with email %s does not exist (asking reset password).', req.body.email) |
@@ -255,7 +260,7 @@ const usersResetPasswordValidator = [ | |||
255 | if (areValidationErrors(req, res)) return | 260 | if (areValidationErrors(req, res)) return |
256 | if (!await checkUserIdExist(req.params.id, res)) return | 261 | if (!await checkUserIdExist(req.params.id, res)) return |
257 | 262 | ||
258 | const user = res.locals.user as UserModel | 263 | const user = res.locals.user |
259 | const redisVerificationString = await Redis.Instance.getResetPasswordLink(user.id) | 264 | const redisVerificationString = await Redis.Instance.getResetPasswordLink(user.id) |
260 | 265 | ||
261 | if (redisVerificationString !== req.body.verificationString) { | 266 | if (redisVerificationString !== req.body.verificationString) { |
@@ -297,7 +302,7 @@ const usersVerifyEmailValidator = [ | |||
297 | if (areValidationErrors(req, res)) return | 302 | if (areValidationErrors(req, res)) return |
298 | if (!await checkUserIdExist(req.params.id, res)) return | 303 | if (!await checkUserIdExist(req.params.id, res)) return |
299 | 304 | ||
300 | const user = res.locals.user as UserModel | 305 | const user = res.locals.user |
301 | const redisVerificationString = await Redis.Instance.getVerifyEmailLink(user.id) | 306 | const redisVerificationString = await Redis.Instance.getVerifyEmailLink(user.id) |
302 | 307 | ||
303 | if (redisVerificationString !== req.body.verificationString) { | 308 | if (redisVerificationString !== req.body.verificationString) { |
@@ -315,6 +320,20 @@ const userAutocompleteValidator = [ | |||
315 | param('search').isString().not().isEmpty().withMessage('Should have a search parameter') | 320 | param('search').isString().not().isEmpty().withMessage('Should have a search parameter') |
316 | ] | 321 | ] |
317 | 322 | ||
323 | const ensureAuthUserOwnsAccountValidator = [ | ||
324 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
325 | const user = res.locals.oauth.token.User | ||
326 | |||
327 | if (res.locals.account.id !== user.Account.id) { | ||
328 | return res.status(403) | ||
329 | .send({ error: 'Only owner can access ratings list.' }) | ||
330 | .end() | ||
331 | } | ||
332 | |||
333 | return next() | ||
334 | } | ||
335 | ] | ||
336 | |||
318 | // --------------------------------------------------------------------------- | 337 | // --------------------------------------------------------------------------- |
319 | 338 | ||
320 | export { | 339 | export { |
@@ -333,7 +352,8 @@ export { | |||
333 | usersResetPasswordValidator, | 352 | usersResetPasswordValidator, |
334 | usersAskSendVerifyEmailValidator, | 353 | usersAskSendVerifyEmailValidator, |
335 | usersVerifyEmailValidator, | 354 | usersVerifyEmailValidator, |
336 | userAutocompleteValidator | 355 | userAutocompleteValidator, |
356 | ensureAuthUserOwnsAccountValidator | ||
337 | } | 357 | } |
338 | 358 | ||
339 | // --------------------------------------------------------------------------- | 359 | // --------------------------------------------------------------------------- |
diff --git a/server/middlewares/validators/videos/video-abuses.ts b/server/middlewares/validators/videos/video-abuses.ts index be26ca16a..d1910a992 100644 --- a/server/middlewares/validators/videos/video-abuses.ts +++ b/server/middlewares/validators/videos/video-abuses.ts | |||
@@ -2,11 +2,11 @@ import * as express from 'express' | |||
2 | import 'express-validator' | 2 | import 'express-validator' |
3 | import { body, param } from 'express-validator/check' | 3 | import { body, param } from 'express-validator/check' |
4 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' |
5 | import { isVideoExist } from '../../../helpers/custom-validators/videos' | 5 | import { doesVideoExist } from '../../../helpers/custom-validators/videos' |
6 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
7 | import { areValidationErrors } from '../utils' | 7 | import { areValidationErrors } from '../utils' |
8 | import { | 8 | import { |
9 | isVideoAbuseExist, | 9 | doesVideoAbuseExist, |
10 | isVideoAbuseModerationCommentValid, | 10 | isVideoAbuseModerationCommentValid, |
11 | isVideoAbuseReasonValid, | 11 | isVideoAbuseReasonValid, |
12 | isVideoAbuseStateValid | 12 | isVideoAbuseStateValid |
@@ -20,7 +20,7 @@ const videoAbuseReportValidator = [ | |||
20 | logger.debug('Checking videoAbuseReport parameters', { parameters: req.body }) | 20 | logger.debug('Checking videoAbuseReport parameters', { parameters: req.body }) |
21 | 21 | ||
22 | if (areValidationErrors(req, res)) return | 22 | if (areValidationErrors(req, res)) return |
23 | if (!await isVideoExist(req.params.videoId, res)) return | 23 | if (!await doesVideoExist(req.params.videoId, res)) return |
24 | 24 | ||
25 | return next() | 25 | return next() |
26 | } | 26 | } |
@@ -34,8 +34,8 @@ const videoAbuseGetValidator = [ | |||
34 | logger.debug('Checking videoAbuseGetValidator parameters', { parameters: req.body }) | 34 | logger.debug('Checking videoAbuseGetValidator parameters', { parameters: req.body }) |
35 | 35 | ||
36 | if (areValidationErrors(req, res)) return | 36 | if (areValidationErrors(req, res)) return |
37 | if (!await isVideoExist(req.params.videoId, res)) return | 37 | if (!await doesVideoExist(req.params.videoId, res)) return |
38 | if (!await isVideoAbuseExist(req.params.id, res.locals.video.id, res)) return | 38 | if (!await doesVideoAbuseExist(req.params.id, res.locals.video.id, res)) return |
39 | 39 | ||
40 | return next() | 40 | return next() |
41 | } | 41 | } |
@@ -55,8 +55,8 @@ const videoAbuseUpdateValidator = [ | |||
55 | logger.debug('Checking videoAbuseUpdateValidator parameters', { parameters: req.body }) | 55 | logger.debug('Checking videoAbuseUpdateValidator parameters', { parameters: req.body }) |
56 | 56 | ||
57 | if (areValidationErrors(req, res)) return | 57 | if (areValidationErrors(req, res)) return |
58 | if (!await isVideoExist(req.params.videoId, res)) return | 58 | if (!await doesVideoExist(req.params.videoId, res)) return |
59 | if (!await isVideoAbuseExist(req.params.id, res.locals.video.id, res)) return | 59 | if (!await doesVideoAbuseExist(req.params.id, res.locals.video.id, res)) return |
60 | 60 | ||
61 | return next() | 61 | return next() |
62 | } | 62 | } |
diff --git a/server/middlewares/validators/videos/video-blacklist.ts b/server/middlewares/validators/videos/video-blacklist.ts index 2688f63ae..1d7ddb2e3 100644 --- a/server/middlewares/validators/videos/video-blacklist.ts +++ b/server/middlewares/validators/videos/video-blacklist.ts | |||
@@ -1,11 +1,14 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { body, param } from 'express-validator/check' | 2 | import { body, param, query } from 'express-validator/check' |
3 | import { isBooleanValid, isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' | 3 | import { isBooleanValid, isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' |
4 | import { isVideoExist } from '../../../helpers/custom-validators/videos' | 4 | import { doesVideoExist } from '../../../helpers/custom-validators/videos' |
5 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
6 | import { areValidationErrors } from '../utils' | 6 | import { areValidationErrors } from '../utils' |
7 | import { isVideoBlacklistExist, isVideoBlacklistReasonValid } from '../../../helpers/custom-validators/video-blacklist' | 7 | import { |
8 | import { VideoModel } from '../../../models/video/video' | 8 | doesVideoBlacklistExist, |
9 | isVideoBlacklistReasonValid, | ||
10 | isVideoBlacklistTypeValid | ||
11 | } from '../../../helpers/custom-validators/video-blacklist' | ||
9 | 12 | ||
10 | const videosBlacklistRemoveValidator = [ | 13 | const videosBlacklistRemoveValidator = [ |
11 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), | 14 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), |
@@ -14,8 +17,8 @@ const videosBlacklistRemoveValidator = [ | |||
14 | logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) | 17 | logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) |
15 | 18 | ||
16 | if (areValidationErrors(req, res)) return | 19 | if (areValidationErrors(req, res)) return |
17 | if (!await isVideoExist(req.params.videoId, res)) return | 20 | if (!await doesVideoExist(req.params.videoId, res)) return |
18 | if (!await isVideoBlacklistExist(res.locals.video.id, res)) return | 21 | if (!await doesVideoBlacklistExist(res.locals.video.id, res)) return |
19 | 22 | ||
20 | return next() | 23 | return next() |
21 | } | 24 | } |
@@ -35,9 +38,9 @@ const videosBlacklistAddValidator = [ | |||
35 | logger.debug('Checking videosBlacklistAdd parameters', { parameters: req.params }) | 38 | logger.debug('Checking videosBlacklistAdd parameters', { parameters: req.params }) |
36 | 39 | ||
37 | if (areValidationErrors(req, res)) return | 40 | if (areValidationErrors(req, res)) return |
38 | if (!await isVideoExist(req.params.videoId, res)) return | 41 | if (!await doesVideoExist(req.params.videoId, res)) return |
39 | 42 | ||
40 | const video: VideoModel = res.locals.video | 43 | const video = res.locals.video |
41 | if (req.body.unfederate === true && video.remote === true) { | 44 | if (req.body.unfederate === true && video.remote === true) { |
42 | return res | 45 | return res |
43 | .status(409) | 46 | .status(409) |
@@ -59,8 +62,22 @@ const videosBlacklistUpdateValidator = [ | |||
59 | logger.debug('Checking videosBlacklistUpdate parameters', { parameters: req.params }) | 62 | logger.debug('Checking videosBlacklistUpdate parameters', { parameters: req.params }) |
60 | 63 | ||
61 | if (areValidationErrors(req, res)) return | 64 | if (areValidationErrors(req, res)) return |
62 | if (!await isVideoExist(req.params.videoId, res)) return | 65 | if (!await doesVideoExist(req.params.videoId, res)) return |
63 | if (!await isVideoBlacklistExist(res.locals.video.id, res)) return | 66 | if (!await doesVideoBlacklistExist(res.locals.video.id, res)) return |
67 | |||
68 | return next() | ||
69 | } | ||
70 | ] | ||
71 | |||
72 | const videosBlacklistFiltersValidator = [ | ||
73 | query('type') | ||
74 | .optional() | ||
75 | .custom(isVideoBlacklistTypeValid).withMessage('Should have a valid video blacklist type attribute'), | ||
76 | |||
77 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
78 | logger.debug('Checking videos blacklist filters query', { parameters: req.query }) | ||
79 | |||
80 | if (areValidationErrors(req, res)) return | ||
64 | 81 | ||
65 | return next() | 82 | return next() |
66 | } | 83 | } |
@@ -71,5 +88,6 @@ const videosBlacklistUpdateValidator = [ | |||
71 | export { | 88 | export { |
72 | videosBlacklistAddValidator, | 89 | videosBlacklistAddValidator, |
73 | videosBlacklistRemoveValidator, | 90 | videosBlacklistRemoveValidator, |
74 | videosBlacklistUpdateValidator | 91 | videosBlacklistUpdateValidator, |
92 | videosBlacklistFiltersValidator | ||
75 | } | 93 | } |
diff --git a/server/middlewares/validators/videos/video-captions.ts b/server/middlewares/validators/videos/video-captions.ts index 63d84fbec..d857ac3ec 100644 --- a/server/middlewares/validators/videos/video-captions.ts +++ b/server/middlewares/validators/videos/video-captions.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { areValidationErrors } from '../utils' | 2 | import { areValidationErrors } from '../utils' |
3 | import { checkUserCanManageVideo, isVideoExist } from '../../../helpers/custom-validators/videos' | 3 | import { checkUserCanManageVideo, doesVideoExist } from '../../../helpers/custom-validators/videos' |
4 | import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' |
5 | import { body, param } from 'express-validator/check' | 5 | import { body, param } from 'express-validator/check' |
6 | import { CONSTRAINTS_FIELDS } from '../../../initializers' | 6 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' |
7 | import { UserRight } from '../../../../shared' | 7 | import { UserRight } from '../../../../shared' |
8 | import { logger } from '../../../helpers/logger' | 8 | import { logger } from '../../../helpers/logger' |
9 | import { isVideoCaptionExist, isVideoCaptionFile, isVideoCaptionLanguageValid } from '../../../helpers/custom-validators/video-captions' | 9 | import { doesVideoCaptionExist, isVideoCaptionFile, isVideoCaptionLanguageValid } from '../../../helpers/custom-validators/video-captions' |
10 | import { cleanUpReqFiles } from '../../../helpers/express-utils' | 10 | import { cleanUpReqFiles } from '../../../helpers/express-utils' |
11 | 11 | ||
12 | const addVideoCaptionValidator = [ | 12 | const addVideoCaptionValidator = [ |
@@ -22,7 +22,7 @@ const addVideoCaptionValidator = [ | |||
22 | logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) | 22 | logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) |
23 | 23 | ||
24 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | 24 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) |
25 | if (!await isVideoExist(req.params.videoId, res)) return cleanUpReqFiles(req) | 25 | if (!await doesVideoExist(req.params.videoId, res)) return cleanUpReqFiles(req) |
26 | 26 | ||
27 | // Check if the user who did the request is able to update the video | 27 | // Check if the user who did the request is able to update the video |
28 | const user = res.locals.oauth.token.User | 28 | const user = res.locals.oauth.token.User |
@@ -40,8 +40,8 @@ const deleteVideoCaptionValidator = [ | |||
40 | logger.debug('Checking deleteVideoCaption parameters', { parameters: req.params }) | 40 | logger.debug('Checking deleteVideoCaption parameters', { parameters: req.params }) |
41 | 41 | ||
42 | if (areValidationErrors(req, res)) return | 42 | if (areValidationErrors(req, res)) return |
43 | if (!await isVideoExist(req.params.videoId, res)) return | 43 | if (!await doesVideoExist(req.params.videoId, res)) return |
44 | if (!await isVideoCaptionExist(res.locals.video, req.params.captionLanguage, res)) return | 44 | if (!await doesVideoCaptionExist(res.locals.video, req.params.captionLanguage, res)) return |
45 | 45 | ||
46 | // Check if the user who did the request is able to update the video | 46 | // Check if the user who did the request is able to update the video |
47 | const user = res.locals.oauth.token.User | 47 | const user = res.locals.oauth.token.User |
@@ -58,7 +58,7 @@ const listVideoCaptionsValidator = [ | |||
58 | logger.debug('Checking listVideoCaptions parameters', { parameters: req.params }) | 58 | logger.debug('Checking listVideoCaptions parameters', { parameters: req.params }) |
59 | 59 | ||
60 | if (areValidationErrors(req, res)) return | 60 | if (areValidationErrors(req, res)) return |
61 | if (!await isVideoExist(req.params.videoId, res, 'id')) return | 61 | if (!await doesVideoExist(req.params.videoId, res, 'id')) return |
62 | 62 | ||
63 | return next() | 63 | return next() |
64 | } | 64 | } |
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts index f039794e0..4b26f0bc4 100644 --- a/server/middlewares/validators/videos/video-channels.ts +++ b/server/middlewares/validators/videos/video-channels.ts | |||
@@ -1,12 +1,11 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { body, param } from 'express-validator/check' | 2 | import { body, param } from 'express-validator/check' |
3 | import { UserRight } from '../../../../shared' | 3 | import { UserRight } from '../../../../shared' |
4 | import { isAccountNameWithHostExist } from '../../../helpers/custom-validators/accounts' | ||
5 | import { | 4 | import { |
6 | isLocalVideoChannelNameExist, | 5 | doesLocalVideoChannelNameExist, |
6 | doesVideoChannelNameWithHostExist, | ||
7 | isVideoChannelDescriptionValid, | 7 | isVideoChannelDescriptionValid, |
8 | isVideoChannelNameValid, | 8 | isVideoChannelNameValid, |
9 | isVideoChannelNameWithHostExist, | ||
10 | isVideoChannelSupportValid | 9 | isVideoChannelSupportValid |
11 | } from '../../../helpers/custom-validators/video-channels' | 10 | } from '../../../helpers/custom-validators/video-channels' |
12 | import { logger } from '../../../helpers/logger' | 11 | import { logger } from '../../../helpers/logger' |
@@ -16,19 +15,6 @@ import { areValidationErrors } from '../utils' | |||
16 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' | 15 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' |
17 | import { ActorModel } from '../../../models/activitypub/actor' | 16 | import { ActorModel } from '../../../models/activitypub/actor' |
18 | 17 | ||
19 | const listVideoAccountChannelsValidator = [ | ||
20 | param('accountName').exists().withMessage('Should have a valid account name'), | ||
21 | |||
22 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
23 | logger.debug('Checking listVideoAccountChannelsValidator parameters', { parameters: req.body }) | ||
24 | |||
25 | if (areValidationErrors(req, res)) return | ||
26 | if (!await isAccountNameWithHostExist(req.params.accountName, res)) return | ||
27 | |||
28 | return next() | ||
29 | } | ||
30 | ] | ||
31 | |||
32 | const videoChannelsAddValidator = [ | 18 | const videoChannelsAddValidator = [ |
33 | body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), | 19 | body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), |
34 | body('displayName').custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), | 20 | body('displayName').custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), |
@@ -62,7 +48,7 @@ const videoChannelsUpdateValidator = [ | |||
62 | logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) | 48 | logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) |
63 | 49 | ||
64 | if (areValidationErrors(req, res)) return | 50 | if (areValidationErrors(req, res)) return |
65 | if (!await isVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return | 51 | if (!await doesVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return |
66 | 52 | ||
67 | // We need to make additional checks | 53 | // We need to make additional checks |
68 | if (res.locals.videoChannel.Actor.isOwned() === false) { | 54 | if (res.locals.videoChannel.Actor.isOwned() === false) { |
@@ -88,7 +74,7 @@ const videoChannelsRemoveValidator = [ | |||
88 | logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params }) | 74 | logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params }) |
89 | 75 | ||
90 | if (areValidationErrors(req, res)) return | 76 | if (areValidationErrors(req, res)) return |
91 | if (!await isVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return | 77 | if (!await doesVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return |
92 | 78 | ||
93 | if (!checkUserCanDeleteVideoChannel(res.locals.oauth.token.User, res.locals.videoChannel, res)) return | 79 | if (!checkUserCanDeleteVideoChannel(res.locals.oauth.token.User, res.locals.videoChannel, res)) return |
94 | if (!await checkVideoChannelIsNotTheLastOne(res)) return | 80 | if (!await checkVideoChannelIsNotTheLastOne(res)) return |
@@ -105,7 +91,7 @@ const videoChannelsNameWithHostValidator = [ | |||
105 | 91 | ||
106 | if (areValidationErrors(req, res)) return | 92 | if (areValidationErrors(req, res)) return |
107 | 93 | ||
108 | if (!await isVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return | 94 | if (!await doesVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return |
109 | 95 | ||
110 | return next() | 96 | return next() |
111 | } | 97 | } |
@@ -118,7 +104,7 @@ const localVideoChannelValidator = [ | |||
118 | logger.debug('Checking localVideoChannelValidator parameters', { parameters: req.params }) | 104 | logger.debug('Checking localVideoChannelValidator parameters', { parameters: req.params }) |
119 | 105 | ||
120 | if (areValidationErrors(req, res)) return | 106 | if (areValidationErrors(req, res)) return |
121 | if (!await isLocalVideoChannelNameExist(req.params.name, res)) return | 107 | if (!await doesLocalVideoChannelNameExist(req.params.name, res)) return |
122 | 108 | ||
123 | return next() | 109 | return next() |
124 | } | 110 | } |
@@ -127,7 +113,6 @@ const localVideoChannelValidator = [ | |||
127 | // --------------------------------------------------------------------------- | 113 | // --------------------------------------------------------------------------- |
128 | 114 | ||
129 | export { | 115 | export { |
130 | listVideoAccountChannelsValidator, | ||
131 | videoChannelsAddValidator, | 116 | videoChannelsAddValidator, |
132 | videoChannelsUpdateValidator, | 117 | videoChannelsUpdateValidator, |
133 | videoChannelsRemoveValidator, | 118 | videoChannelsRemoveValidator, |
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts index 348d33082..ffde208b7 100644 --- a/server/middlewares/validators/videos/video-comments.ts +++ b/server/middlewares/validators/videos/video-comments.ts | |||
@@ -3,7 +3,7 @@ import { body, param } from 'express-validator/check' | |||
3 | import { UserRight } from '../../../../shared' | 3 | import { UserRight } from '../../../../shared' |
4 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' |
5 | import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments' | 5 | import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments' |
6 | import { isVideoExist } from '../../../helpers/custom-validators/videos' | 6 | import { doesVideoExist } from '../../../helpers/custom-validators/videos' |
7 | import { logger } from '../../../helpers/logger' | 7 | import { logger } from '../../../helpers/logger' |
8 | import { UserModel } from '../../../models/account/user' | 8 | import { UserModel } from '../../../models/account/user' |
9 | import { VideoModel } from '../../../models/video/video' | 9 | import { VideoModel } from '../../../models/video/video' |
@@ -17,7 +17,7 @@ const listVideoCommentThreadsValidator = [ | |||
17 | logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params }) | 17 | logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params }) |
18 | 18 | ||
19 | if (areValidationErrors(req, res)) return | 19 | if (areValidationErrors(req, res)) return |
20 | if (!await isVideoExist(req.params.videoId, res, 'only-video')) return | 20 | if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return |
21 | 21 | ||
22 | return next() | 22 | return next() |
23 | } | 23 | } |
@@ -31,8 +31,8 @@ const listVideoThreadCommentsValidator = [ | |||
31 | logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params }) | 31 | logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params }) |
32 | 32 | ||
33 | if (areValidationErrors(req, res)) return | 33 | if (areValidationErrors(req, res)) return |
34 | if (!await isVideoExist(req.params.videoId, res, 'only-video')) return | 34 | if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return |
35 | if (!await isVideoCommentThreadExist(req.params.threadId, res.locals.video, res)) return | 35 | if (!await doesVideoCommentThreadExist(req.params.threadId, res.locals.video, res)) return |
36 | 36 | ||
37 | return next() | 37 | return next() |
38 | } | 38 | } |
@@ -46,7 +46,7 @@ const addVideoCommentThreadValidator = [ | |||
46 | logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body }) | 46 | logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body }) |
47 | 47 | ||
48 | if (areValidationErrors(req, res)) return | 48 | if (areValidationErrors(req, res)) return |
49 | if (!await isVideoExist(req.params.videoId, res)) return | 49 | if (!await doesVideoExist(req.params.videoId, res)) return |
50 | if (!isVideoCommentsEnabled(res.locals.video, res)) return | 50 | if (!isVideoCommentsEnabled(res.locals.video, res)) return |
51 | 51 | ||
52 | return next() | 52 | return next() |
@@ -62,9 +62,9 @@ const addVideoCommentReplyValidator = [ | |||
62 | logger.debug('Checking addVideoCommentReply parameters.', { parameters: req.params, body: req.body }) | 62 | logger.debug('Checking addVideoCommentReply parameters.', { parameters: req.params, body: req.body }) |
63 | 63 | ||
64 | if (areValidationErrors(req, res)) return | 64 | if (areValidationErrors(req, res)) return |
65 | if (!await isVideoExist(req.params.videoId, res)) return | 65 | if (!await doesVideoExist(req.params.videoId, res)) return |
66 | if (!isVideoCommentsEnabled(res.locals.video, res)) return | 66 | if (!isVideoCommentsEnabled(res.locals.video, res)) return |
67 | if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return | 67 | if (!await doesVideoCommentExist(req.params.commentId, res.locals.video, res)) return |
68 | 68 | ||
69 | return next() | 69 | return next() |
70 | } | 70 | } |
@@ -78,8 +78,8 @@ const videoCommentGetValidator = [ | |||
78 | logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params }) | 78 | logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params }) |
79 | 79 | ||
80 | if (areValidationErrors(req, res)) return | 80 | if (areValidationErrors(req, res)) return |
81 | if (!await isVideoExist(req.params.videoId, res, 'id')) return | 81 | if (!await doesVideoExist(req.params.videoId, res, 'id')) return |
82 | if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return | 82 | if (!await doesVideoCommentExist(req.params.commentId, res.locals.video, res)) return |
83 | 83 | ||
84 | return next() | 84 | return next() |
85 | } | 85 | } |
@@ -93,8 +93,8 @@ const removeVideoCommentValidator = [ | |||
93 | logger.debug('Checking removeVideoCommentValidator parameters.', { parameters: req.params }) | 93 | logger.debug('Checking removeVideoCommentValidator parameters.', { parameters: req.params }) |
94 | 94 | ||
95 | if (areValidationErrors(req, res)) return | 95 | if (areValidationErrors(req, res)) return |
96 | if (!await isVideoExist(req.params.videoId, res)) return | 96 | if (!await doesVideoExist(req.params.videoId, res)) return |
97 | if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return | 97 | if (!await doesVideoCommentExist(req.params.commentId, res.locals.video, res)) return |
98 | 98 | ||
99 | // Check if the user who did the request is able to delete the video | 99 | // Check if the user who did the request is able to delete the video |
100 | if (!checkUserCanDeleteVideoComment(res.locals.oauth.token.User, res.locals.videoComment, res)) return | 100 | if (!checkUserCanDeleteVideoComment(res.locals.oauth.token.User, res.locals.videoComment, res)) return |
@@ -116,7 +116,7 @@ export { | |||
116 | 116 | ||
117 | // --------------------------------------------------------------------------- | 117 | // --------------------------------------------------------------------------- |
118 | 118 | ||
119 | async function isVideoCommentThreadExist (id: number, video: VideoModel, res: express.Response) { | 119 | async function doesVideoCommentThreadExist (id: number, video: VideoModel, res: express.Response) { |
120 | const videoComment = await VideoCommentModel.loadById(id) | 120 | const videoComment = await VideoCommentModel.loadById(id) |
121 | 121 | ||
122 | if (!videoComment) { | 122 | if (!videoComment) { |
@@ -147,7 +147,7 @@ async function isVideoCommentThreadExist (id: number, video: VideoModel, res: ex | |||
147 | return true | 147 | return true |
148 | } | 148 | } |
149 | 149 | ||
150 | async function isVideoCommentExist (id: number, video: VideoModel, res: express.Response) { | 150 | async function doesVideoCommentExist (id: number, video: VideoModel, res: express.Response) { |
151 | const videoComment = await VideoCommentModel.loadByIdAndPopulateVideoAndAccountAndReply(id) | 151 | const videoComment = await VideoCommentModel.loadByIdAndPopulateVideoAndAccountAndReply(id) |
152 | 152 | ||
153 | if (!videoComment) { | 153 | if (!videoComment) { |
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts index 48d20f904..452084a7c 100644 --- a/server/middlewares/validators/videos/video-imports.ts +++ b/server/middlewares/validators/videos/video-imports.ts | |||
@@ -3,14 +3,14 @@ import { body } from 'express-validator/check' | |||
3 | import { isIdValid } from '../../../helpers/custom-validators/misc' | 3 | import { isIdValid } from '../../../helpers/custom-validators/misc' |
4 | import { logger } from '../../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
5 | import { areValidationErrors } from '../utils' | 5 | import { areValidationErrors } from '../utils' |
6 | import { getCommonVideoAttributes } from './videos' | 6 | import { getCommonVideoEditAttributes } from './videos' |
7 | import { isVideoImportTargetUrlValid, isVideoImportTorrentFile } from '../../../helpers/custom-validators/video-imports' | 7 | import { isVideoImportTargetUrlValid, isVideoImportTorrentFile } from '../../../helpers/custom-validators/video-imports' |
8 | import { cleanUpReqFiles } from '../../../helpers/express-utils' | 8 | import { cleanUpReqFiles } from '../../../helpers/express-utils' |
9 | import { isVideoChannelOfAccountExist, isVideoMagnetUriValid, isVideoNameValid } from '../../../helpers/custom-validators/videos' | 9 | import { doesVideoChannelOfAccountExist, isVideoMagnetUriValid, isVideoNameValid } from '../../../helpers/custom-validators/videos' |
10 | import { CONFIG } from '../../../initializers/constants' | 10 | import { CONFIG } from '../../../initializers/config' |
11 | import { CONSTRAINTS_FIELDS } from '../../../initializers' | 11 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' |
12 | 12 | ||
13 | const videoImportAddValidator = getCommonVideoAttributes().concat([ | 13 | const videoImportAddValidator = getCommonVideoEditAttributes().concat([ |
14 | body('channelId') | 14 | body('channelId') |
15 | .toInt() | 15 | .toInt() |
16 | .custom(isIdValid).withMessage('Should have correct video channel id'), | 16 | .custom(isIdValid).withMessage('Should have correct video channel id'), |
@@ -51,7 +51,7 @@ const videoImportAddValidator = getCommonVideoAttributes().concat([ | |||
51 | .end() | 51 | .end() |
52 | } | 52 | } |
53 | 53 | ||
54 | if (!await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) | 54 | if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) |
55 | 55 | ||
56 | // Check we have at least 1 required param | 56 | // Check we have at least 1 required param |
57 | if (!req.body.targetUrl && !req.body.magnetUri && !torrentFile) { | 57 | if (!req.body.targetUrl && !req.body.magnetUri && !torrentFile) { |
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts new file mode 100644 index 000000000..2c3f7e542 --- /dev/null +++ b/server/middlewares/validators/videos/video-playlists.ts | |||
@@ -0,0 +1,408 @@ | |||
1 | import * as express from 'express' | ||
2 | import { body, param, query, ValidationChain } from 'express-validator/check' | ||
3 | import { UserRight, VideoPlaylistCreate, VideoPlaylistUpdate } from '../../../../shared' | ||
4 | import { logger } from '../../../helpers/logger' | ||
5 | import { UserModel } from '../../../models/account/user' | ||
6 | import { areValidationErrors } from '../utils' | ||
7 | import { doesVideoExist, isVideoImage } from '../../../helpers/custom-validators/videos' | ||
8 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' | ||
9 | import { isArrayOf, isIdOrUUIDValid, isIdValid, isUUIDValid, toIntArray, toValueOrNull } from '../../../helpers/custom-validators/misc' | ||
10 | import { | ||
11 | doesVideoPlaylistExist, | ||
12 | isVideoPlaylistDescriptionValid, | ||
13 | isVideoPlaylistNameValid, | ||
14 | isVideoPlaylistPrivacyValid, | ||
15 | isVideoPlaylistTimestampValid, | ||
16 | isVideoPlaylistTypeValid | ||
17 | } from '../../../helpers/custom-validators/video-playlists' | ||
18 | import { VideoPlaylistModel } from '../../../models/video/video-playlist' | ||
19 | import { cleanUpReqFiles } from '../../../helpers/express-utils' | ||
20 | import { doesVideoChannelIdExist } from '../../../helpers/custom-validators/video-channels' | ||
21 | import { VideoPlaylistElementModel } from '../../../models/video/video-playlist-element' | ||
22 | import { authenticatePromiseIfNeeded } from '../../oauth' | ||
23 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | ||
24 | import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' | ||
25 | |||
26 | const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([ | ||
27 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
28 | logger.debug('Checking videoPlaylistsAddValidator parameters', { parameters: req.body }) | ||
29 | |||
30 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | ||
31 | |||
32 | const body: VideoPlaylistCreate = req.body | ||
33 | if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req) | ||
34 | |||
35 | if (body.privacy === VideoPlaylistPrivacy.PUBLIC && !body.videoChannelId) { | ||
36 | cleanUpReqFiles(req) | ||
37 | return res.status(400) | ||
38 | .json({ error: 'Cannot set "public" a playlist that is not assigned to a channel.' }) | ||
39 | } | ||
40 | |||
41 | return next() | ||
42 | } | ||
43 | ]) | ||
44 | |||
45 | const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([ | ||
46 | param('playlistId') | ||
47 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | ||
48 | |||
49 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
50 | logger.debug('Checking videoPlaylistsUpdateValidator parameters', { parameters: req.body }) | ||
51 | |||
52 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | ||
53 | |||
54 | if (!await doesVideoPlaylistExist(req.params.playlistId, res, 'all')) return cleanUpReqFiles(req) | ||
55 | |||
56 | const videoPlaylist = res.locals.videoPlaylist | ||
57 | |||
58 | if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, res.locals.videoPlaylist, UserRight.REMOVE_ANY_VIDEO_PLAYLIST, res)) { | ||
59 | return cleanUpReqFiles(req) | ||
60 | } | ||
61 | |||
62 | const body: VideoPlaylistUpdate = req.body | ||
63 | |||
64 | if (videoPlaylist.privacy !== VideoPlaylistPrivacy.PRIVATE && body.privacy === VideoPlaylistPrivacy.PRIVATE) { | ||
65 | cleanUpReqFiles(req) | ||
66 | return res.status(400) | ||
67 | .json({ error: 'Cannot set "private" a video playlist that was not private.' }) | ||
68 | } | ||
69 | |||
70 | const newPrivacy = body.privacy || videoPlaylist.privacy | ||
71 | if (newPrivacy === VideoPlaylistPrivacy.PUBLIC && | ||
72 | ( | ||
73 | (!videoPlaylist.videoChannelId && !body.videoChannelId) || | ||
74 | body.videoChannelId === null | ||
75 | ) | ||
76 | ) { | ||
77 | cleanUpReqFiles(req) | ||
78 | return res.status(400) | ||
79 | .json({ error: 'Cannot set "public" a playlist that is not assigned to a channel.' }) | ||
80 | } | ||
81 | |||
82 | if (videoPlaylist.type === VideoPlaylistType.WATCH_LATER) { | ||
83 | cleanUpReqFiles(req) | ||
84 | return res.status(400) | ||
85 | .json({ error: 'Cannot update a watch later playlist.' }) | ||
86 | } | ||
87 | |||
88 | if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req) | ||
89 | |||
90 | return next() | ||
91 | } | ||
92 | ]) | ||
93 | |||
94 | const videoPlaylistsDeleteValidator = [ | ||
95 | param('playlistId') | ||
96 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | ||
97 | |||
98 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
99 | logger.debug('Checking videoPlaylistsDeleteValidator parameters', { parameters: req.params }) | ||
100 | |||
101 | if (areValidationErrors(req, res)) return | ||
102 | |||
103 | if (!await doesVideoPlaylistExist(req.params.playlistId, res)) return | ||
104 | |||
105 | const videoPlaylist = res.locals.videoPlaylist | ||
106 | if (videoPlaylist.type === VideoPlaylistType.WATCH_LATER) { | ||
107 | return res.status(400) | ||
108 | .json({ error: 'Cannot delete a watch later playlist.' }) | ||
109 | } | ||
110 | |||
111 | if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, res.locals.videoPlaylist, UserRight.REMOVE_ANY_VIDEO_PLAYLIST, res)) { | ||
112 | return | ||
113 | } | ||
114 | |||
115 | return next() | ||
116 | } | ||
117 | ] | ||
118 | |||
119 | const videoPlaylistsGetValidator = [ | ||
120 | param('playlistId') | ||
121 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | ||
122 | |||
123 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
124 | logger.debug('Checking videoPlaylistsGetValidator parameters', { parameters: req.params }) | ||
125 | |||
126 | if (areValidationErrors(req, res)) return | ||
127 | |||
128 | if (!await doesVideoPlaylistExist(req.params.playlistId, res)) return | ||
129 | |||
130 | const videoPlaylist = res.locals.videoPlaylist | ||
131 | |||
132 | // Video is unlisted, check we used the uuid to fetch it | ||
133 | if (videoPlaylist.privacy === VideoPlaylistPrivacy.UNLISTED) { | ||
134 | if (isUUIDValid(req.params.playlistId)) return next() | ||
135 | |||
136 | return res.status(404).end() | ||
137 | } | ||
138 | |||
139 | if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) { | ||
140 | await authenticatePromiseIfNeeded(req, res) | ||
141 | |||
142 | const user = res.locals.oauth ? res.locals.oauth.token.User : null | ||
143 | if ( | ||
144 | !user || | ||
145 | (videoPlaylist.OwnerAccount.userId !== user.id && !user.hasRight(UserRight.UPDATE_ANY_VIDEO_PLAYLIST)) | ||
146 | ) { | ||
147 | return res.status(403) | ||
148 | .json({ error: 'Cannot get this private video playlist.' }) | ||
149 | } | ||
150 | |||
151 | return next() | ||
152 | } | ||
153 | |||
154 | return next() | ||
155 | } | ||
156 | ] | ||
157 | |||
158 | const videoPlaylistsAddVideoValidator = [ | ||
159 | param('playlistId') | ||
160 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | ||
161 | body('videoId') | ||
162 | .custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'), | ||
163 | body('startTimestamp') | ||
164 | .optional() | ||
165 | .custom(isVideoPlaylistTimestampValid).withMessage('Should have a valid start timestamp'), | ||
166 | body('stopTimestamp') | ||
167 | .optional() | ||
168 | .custom(isVideoPlaylistTimestampValid).withMessage('Should have a valid stop timestamp'), | ||
169 | |||
170 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
171 | logger.debug('Checking videoPlaylistsAddVideoValidator parameters', { parameters: req.params }) | ||
172 | |||
173 | if (areValidationErrors(req, res)) return | ||
174 | |||
175 | if (!await doesVideoPlaylistExist(req.params.playlistId, res, 'all')) return | ||
176 | if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return | ||
177 | |||
178 | const videoPlaylist = res.locals.videoPlaylist | ||
179 | const video = res.locals.video | ||
180 | |||
181 | const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndVideo(videoPlaylist.id, video.id) | ||
182 | if (videoPlaylistElement) { | ||
183 | res.status(409) | ||
184 | .json({ error: 'This video in this playlist already exists' }) | ||
185 | .end() | ||
186 | |||
187 | return | ||
188 | } | ||
189 | |||
190 | if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, res.locals.videoPlaylist, UserRight.UPDATE_ANY_VIDEO_PLAYLIST, res)) { | ||
191 | return | ||
192 | } | ||
193 | |||
194 | return next() | ||
195 | } | ||
196 | ] | ||
197 | |||
198 | const videoPlaylistsUpdateOrRemoveVideoValidator = [ | ||
199 | param('playlistId') | ||
200 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | ||
201 | param('videoId') | ||
202 | .custom(isIdOrUUIDValid).withMessage('Should have an video id/uuid'), | ||
203 | body('startTimestamp') | ||
204 | .optional() | ||
205 | .custom(isVideoPlaylistTimestampValid).withMessage('Should have a valid start timestamp'), | ||
206 | body('stopTimestamp') | ||
207 | .optional() | ||
208 | .custom(isVideoPlaylistTimestampValid).withMessage('Should have a valid stop timestamp'), | ||
209 | |||
210 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
211 | logger.debug('Checking videoPlaylistsRemoveVideoValidator parameters', { parameters: req.params }) | ||
212 | |||
213 | if (areValidationErrors(req, res)) return | ||
214 | |||
215 | if (!await doesVideoPlaylistExist(req.params.playlistId, res, 'all')) return | ||
216 | if (!await doesVideoExist(req.params.videoId, res, 'id')) return | ||
217 | |||
218 | const videoPlaylist = res.locals.videoPlaylist | ||
219 | const video = res.locals.video | ||
220 | |||
221 | const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndVideo(videoPlaylist.id, video.id) | ||
222 | if (!videoPlaylistElement) { | ||
223 | res.status(404) | ||
224 | .json({ error: 'Video playlist element not found' }) | ||
225 | .end() | ||
226 | |||
227 | return | ||
228 | } | ||
229 | res.locals.videoPlaylistElement = videoPlaylistElement | ||
230 | |||
231 | if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.UPDATE_ANY_VIDEO_PLAYLIST, res)) return | ||
232 | |||
233 | return next() | ||
234 | } | ||
235 | ] | ||
236 | |||
237 | const videoPlaylistElementAPGetValidator = [ | ||
238 | param('playlistId') | ||
239 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | ||
240 | param('videoId') | ||
241 | .custom(isIdOrUUIDValid).withMessage('Should have an video id/uuid'), | ||
242 | |||
243 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
244 | logger.debug('Checking videoPlaylistElementAPGetValidator parameters', { parameters: req.params }) | ||
245 | |||
246 | if (areValidationErrors(req, res)) return | ||
247 | |||
248 | const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndVideoForAP(req.params.playlistId, req.params.videoId) | ||
249 | if (!videoPlaylistElement) { | ||
250 | res.status(404) | ||
251 | .json({ error: 'Video playlist element not found' }) | ||
252 | .end() | ||
253 | |||
254 | return | ||
255 | } | ||
256 | |||
257 | if (videoPlaylistElement.VideoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) { | ||
258 | return res.status(403).end() | ||
259 | } | ||
260 | |||
261 | res.locals.videoPlaylistElement = videoPlaylistElement | ||
262 | |||
263 | return next() | ||
264 | } | ||
265 | ] | ||
266 | |||
267 | const videoPlaylistsReorderVideosValidator = [ | ||
268 | param('playlistId') | ||
269 | .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), | ||
270 | body('startPosition') | ||
271 | .isInt({ min: 1 }).withMessage('Should have a valid start position'), | ||
272 | body('insertAfterPosition') | ||
273 | .isInt({ min: 0 }).withMessage('Should have a valid insert after position'), | ||
274 | body('reorderLength') | ||
275 | .optional() | ||
276 | .isInt({ min: 1 }).withMessage('Should have a valid range length'), | ||
277 | |||
278 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
279 | logger.debug('Checking videoPlaylistsReorderVideosValidator parameters', { parameters: req.params }) | ||
280 | |||
281 | if (areValidationErrors(req, res)) return | ||
282 | |||
283 | if (!await doesVideoPlaylistExist(req.params.playlistId, res, 'all')) return | ||
284 | |||
285 | const videoPlaylist = res.locals.videoPlaylist | ||
286 | if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.UPDATE_ANY_VIDEO_PLAYLIST, res)) return | ||
287 | |||
288 | const nextPosition = await VideoPlaylistElementModel.getNextPositionOf(videoPlaylist.id) | ||
289 | const startPosition: number = req.body.startPosition | ||
290 | const insertAfterPosition: number = req.body.insertAfterPosition | ||
291 | const reorderLength: number = req.body.reorderLength | ||
292 | |||
293 | if (startPosition >= nextPosition || insertAfterPosition >= nextPosition) { | ||
294 | res.status(400) | ||
295 | .json({ error: `Start position or insert after position exceed the playlist limits (max: ${nextPosition - 1})` }) | ||
296 | .end() | ||
297 | |||
298 | return | ||
299 | } | ||
300 | |||
301 | if (reorderLength && reorderLength + startPosition > nextPosition) { | ||
302 | res.status(400) | ||
303 | .json({ error: `Reorder length with this start position exceeds the playlist limits (max: ${nextPosition - startPosition})` }) | ||
304 | .end() | ||
305 | |||
306 | return | ||
307 | } | ||
308 | |||
309 | return next() | ||
310 | } | ||
311 | ] | ||
312 | |||
313 | const commonVideoPlaylistFiltersValidator = [ | ||
314 | query('playlistType') | ||
315 | .optional() | ||
316 | .custom(isVideoPlaylistTypeValid).withMessage('Should have a valid playlist type'), | ||
317 | |||
318 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
319 | logger.debug('Checking commonVideoPlaylistFiltersValidator parameters', { parameters: req.params }) | ||
320 | |||
321 | if (areValidationErrors(req, res)) return | ||
322 | |||
323 | return next() | ||
324 | } | ||
325 | ] | ||
326 | |||
327 | const doVideosInPlaylistExistValidator = [ | ||
328 | query('videoIds') | ||
329 | .customSanitizer(toIntArray) | ||
330 | .custom(v => isArrayOf(v, isIdValid)).withMessage('Should have a valid video ids array'), | ||
331 | |||
332 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
333 | logger.debug('Checking areVideosInPlaylistExistValidator parameters', { parameters: req.query }) | ||
334 | |||
335 | if (areValidationErrors(req, res)) return | ||
336 | |||
337 | return next() | ||
338 | } | ||
339 | ] | ||
340 | |||
341 | // --------------------------------------------------------------------------- | ||
342 | |||
343 | export { | ||
344 | videoPlaylistsAddValidator, | ||
345 | videoPlaylistsUpdateValidator, | ||
346 | videoPlaylistsDeleteValidator, | ||
347 | videoPlaylistsGetValidator, | ||
348 | |||
349 | videoPlaylistsAddVideoValidator, | ||
350 | videoPlaylistsUpdateOrRemoveVideoValidator, | ||
351 | videoPlaylistsReorderVideosValidator, | ||
352 | |||
353 | videoPlaylistElementAPGetValidator, | ||
354 | |||
355 | commonVideoPlaylistFiltersValidator, | ||
356 | |||
357 | doVideosInPlaylistExistValidator | ||
358 | } | ||
359 | |||
360 | // --------------------------------------------------------------------------- | ||
361 | |||
362 | function getCommonPlaylistEditAttributes () { | ||
363 | return [ | ||
364 | body('thumbnailfile') | ||
365 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | ||
366 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' | ||
367 | + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') | ||
368 | ), | ||
369 | |||
370 | body('displayName') | ||
371 | .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'), | ||
372 | body('description') | ||
373 | .optional() | ||
374 | .customSanitizer(toValueOrNull) | ||
375 | .custom(isVideoPlaylistDescriptionValid).withMessage('Should have a valid description'), | ||
376 | body('privacy') | ||
377 | .optional() | ||
378 | .toInt() | ||
379 | .custom(isVideoPlaylistPrivacyValid).withMessage('Should have correct playlist privacy'), | ||
380 | body('videoChannelId') | ||
381 | .optional() | ||
382 | .customSanitizer(toValueOrNull) | ||
383 | .toInt() | ||
384 | ] as (ValidationChain | express.Handler)[] | ||
385 | } | ||
386 | |||
387 | function checkUserCanManageVideoPlaylist (user: UserModel, videoPlaylist: VideoPlaylistModel, right: UserRight, res: express.Response) { | ||
388 | if (videoPlaylist.isOwned() === false) { | ||
389 | res.status(403) | ||
390 | .json({ error: 'Cannot manage video playlist of another server.' }) | ||
391 | .end() | ||
392 | |||
393 | return false | ||
394 | } | ||
395 | |||
396 | // Check if the user can manage the video playlist | ||
397 | // The user can delete it if s/he is an admin | ||
398 | // Or if s/he is the video playlist's owner | ||
399 | if (user.hasRight(right) === false && videoPlaylist.ownerAccountId !== user.Account.id) { | ||
400 | res.status(403) | ||
401 | .json({ error: 'Cannot manage video playlist of another user' }) | ||
402 | .end() | ||
403 | |||
404 | return false | ||
405 | } | ||
406 | |||
407 | return true | ||
408 | } | ||
diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts index 793354520..204b4a78d 100644 --- a/server/middlewares/validators/videos/video-rates.ts +++ b/server/middlewares/validators/videos/video-rates.ts | |||
@@ -1,8 +1,9 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import 'express-validator' | 2 | import 'express-validator' |
3 | import { body, param } from 'express-validator/check' | 3 | import { body, param, query } from 'express-validator/check' |
4 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' |
5 | import { isVideoExist, isVideoRatingTypeValid } from '../../../helpers/custom-validators/videos' | 5 | import { isRatingValid } from '../../../helpers/custom-validators/video-rates' |
6 | import { doesVideoExist, isVideoRatingTypeValid } from '../../../helpers/custom-validators/videos' | ||
6 | import { logger } from '../../../helpers/logger' | 7 | import { logger } from '../../../helpers/logger' |
7 | import { areValidationErrors } from '../utils' | 8 | import { areValidationErrors } from '../utils' |
8 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | 9 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' |
@@ -17,7 +18,7 @@ const videoUpdateRateValidator = [ | |||
17 | logger.debug('Checking videoRate parameters', { parameters: req.body }) | 18 | logger.debug('Checking videoRate parameters', { parameters: req.body }) |
18 | 19 | ||
19 | if (areValidationErrors(req, res)) return | 20 | if (areValidationErrors(req, res)) return |
20 | if (!await isVideoExist(req.params.id, res)) return | 21 | if (!await doesVideoExist(req.params.id, res)) return |
21 | 22 | ||
22 | return next() | 23 | return next() |
23 | } | 24 | } |
@@ -47,9 +48,22 @@ const getAccountVideoRateValidator = function (rateType: VideoRateType) { | |||
47 | ] | 48 | ] |
48 | } | 49 | } |
49 | 50 | ||
51 | const videoRatingValidator = [ | ||
52 | query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'), | ||
53 | |||
54 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
55 | logger.debug('Checking rating parameter', { parameters: req.params }) | ||
56 | |||
57 | if (areValidationErrors(req, res)) return | ||
58 | |||
59 | return next() | ||
60 | } | ||
61 | ] | ||
62 | |||
50 | // --------------------------------------------------------------------------- | 63 | // --------------------------------------------------------------------------- |
51 | 64 | ||
52 | export { | 65 | export { |
53 | videoUpdateRateValidator, | 66 | videoUpdateRateValidator, |
54 | getAccountVideoRateValidator | 67 | getAccountVideoRateValidator, |
68 | videoRatingValidator | ||
55 | } | 69 | } |
diff --git a/server/middlewares/validators/videos/video-shares.ts b/server/middlewares/validators/videos/video-shares.ts index 646d7acb1..d5cbdb03e 100644 --- a/server/middlewares/validators/videos/video-shares.ts +++ b/server/middlewares/validators/videos/video-shares.ts | |||
@@ -2,11 +2,10 @@ import * as express from 'express' | |||
2 | import 'express-validator' | 2 | import 'express-validator' |
3 | import { param } from 'express-validator/check' | 3 | import { param } from 'express-validator/check' |
4 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' |
5 | import { isVideoExist } from '../../../helpers/custom-validators/videos' | 5 | import { doesVideoExist } from '../../../helpers/custom-validators/videos' |
6 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
7 | import { VideoShareModel } from '../../../models/video/video-share' | 7 | import { VideoShareModel } from '../../../models/video/video-share' |
8 | import { areValidationErrors } from '../utils' | 8 | import { areValidationErrors } from '../utils' |
9 | import { VideoModel } from '../../../models/video/video' | ||
10 | 9 | ||
11 | const videosShareValidator = [ | 10 | const videosShareValidator = [ |
12 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 11 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
@@ -16,9 +15,9 @@ const videosShareValidator = [ | |||
16 | logger.debug('Checking videoShare parameters', { parameters: req.params }) | 15 | logger.debug('Checking videoShare parameters', { parameters: req.params }) |
17 | 16 | ||
18 | if (areValidationErrors(req, res)) return | 17 | if (areValidationErrors(req, res)) return |
19 | if (!await isVideoExist(req.params.id, res)) return | 18 | if (!await doesVideoExist(req.params.id, res)) return |
20 | 19 | ||
21 | const video: VideoModel = res.locals.video | 20 | const video = res.locals.video |
22 | 21 | ||
23 | const share = await VideoShareModel.load(req.params.actorId, video.id) | 22 | const share = await VideoShareModel.load(req.params.actorId, video.id) |
24 | if (!share) { | 23 | if (!share) { |
diff --git a/server/middlewares/validators/videos/video-watch.ts b/server/middlewares/validators/videos/video-watch.ts index c38ad8a10..a3a800d14 100644 --- a/server/middlewares/validators/videos/video-watch.ts +++ b/server/middlewares/validators/videos/video-watch.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | import { body, param } from 'express-validator/check' | 1 | import { body, param } from 'express-validator/check' |
2 | import * as express from 'express' | 2 | import * as express from 'express' |
3 | import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' | 3 | import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' |
4 | import { isVideoExist } from '../../../helpers/custom-validators/videos' | 4 | import { doesVideoExist } from '../../../helpers/custom-validators/videos' |
5 | import { areValidationErrors } from '../utils' | 5 | import { areValidationErrors } from '../utils' |
6 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
7 | import { UserModel } from '../../../models/account/user' | ||
8 | 7 | ||
9 | const videoWatchingValidator = [ | 8 | const videoWatchingValidator = [ |
10 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 9 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
@@ -16,9 +15,9 @@ const videoWatchingValidator = [ | |||
16 | logger.debug('Checking videoWatching parameters', { parameters: req.body }) | 15 | logger.debug('Checking videoWatching parameters', { parameters: req.body }) |
17 | 16 | ||
18 | if (areValidationErrors(req, res)) return | 17 | if (areValidationErrors(req, res)) return |
19 | if (!await isVideoExist(req.params.videoId, res, 'id')) return | 18 | if (!await doesVideoExist(req.params.videoId, res, 'id')) return |
20 | 19 | ||
21 | const user = res.locals.oauth.token.User as UserModel | 20 | const user = res.locals.oauth.token.User |
22 | if (user.videosHistoryEnabled === false) { | 21 | if (user.videosHistoryEnabled === false) { |
23 | logger.warn('Cannot set videos to watch by user %d: videos history is disabled.', user.id) | 22 | logger.warn('Cannot set videos to watch by user %d: videos history is disabled.', user.id) |
24 | return res.status(409).end() | 23 | return res.status(409).end() |
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 051a19e16..2b01f108d 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -14,38 +14,38 @@ import { | |||
14 | } from '../../../helpers/custom-validators/misc' | 14 | } from '../../../helpers/custom-validators/misc' |
15 | import { | 15 | import { |
16 | checkUserCanManageVideo, | 16 | checkUserCanManageVideo, |
17 | doesVideoChannelOfAccountExist, | ||
18 | doesVideoExist, | ||
17 | isScheduleVideoUpdatePrivacyValid, | 19 | isScheduleVideoUpdatePrivacyValid, |
18 | isVideoCategoryValid, | 20 | isVideoCategoryValid, |
19 | isVideoChannelOfAccountExist, | ||
20 | isVideoDescriptionValid, | 21 | isVideoDescriptionValid, |
21 | isVideoExist, | ||
22 | isVideoFile, | 22 | isVideoFile, |
23 | isVideoFilterValid, | 23 | isVideoFilterValid, |
24 | isVideoImage, | 24 | isVideoImage, |
25 | isVideoLanguageValid, | 25 | isVideoLanguageValid, |
26 | isVideoLicenceValid, | 26 | isVideoLicenceValid, |
27 | isVideoNameValid, | 27 | isVideoNameValid, |
28 | isVideoOriginallyPublishedAtValid, | ||
28 | isVideoPrivacyValid, | 29 | isVideoPrivacyValid, |
29 | isVideoSupportValid, | 30 | isVideoSupportValid, |
30 | isVideoTagsValid | 31 | isVideoTagsValid |
31 | } from '../../../helpers/custom-validators/videos' | 32 | } from '../../../helpers/custom-validators/videos' |
32 | import { getDurationFromVideoFile } from '../../../helpers/ffmpeg-utils' | 33 | import { getDurationFromVideoFile } from '../../../helpers/ffmpeg-utils' |
33 | import { logger } from '../../../helpers/logger' | 34 | import { logger } from '../../../helpers/logger' |
34 | import { CONFIG, CONSTRAINTS_FIELDS } from '../../../initializers' | 35 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' |
35 | import { authenticatePromiseIfNeeded } from '../../oauth' | 36 | import { authenticatePromiseIfNeeded } from '../../oauth' |
36 | import { areValidationErrors } from '../utils' | 37 | import { areValidationErrors } from '../utils' |
37 | import { cleanUpReqFiles } from '../../../helpers/express-utils' | 38 | import { cleanUpReqFiles } from '../../../helpers/express-utils' |
38 | import { VideoModel } from '../../../models/video/video' | 39 | import { VideoModel } from '../../../models/video/video' |
39 | import { UserModel } from '../../../models/account/user' | ||
40 | import { checkUserCanTerminateOwnershipChange, doesChangeVideoOwnershipExist } from '../../../helpers/custom-validators/video-ownership' | 40 | import { checkUserCanTerminateOwnershipChange, doesChangeVideoOwnershipExist } from '../../../helpers/custom-validators/video-ownership' |
41 | import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model' | 41 | import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model' |
42 | import { VideoChangeOwnershipModel } from '../../../models/video/video-change-ownership' | ||
43 | import { AccountModel } from '../../../models/account/account' | 42 | import { AccountModel } from '../../../models/account/account' |
44 | import { VideoFetchType } from '../../../helpers/video' | 43 | import { VideoFetchType } from '../../../helpers/video' |
45 | import { isNSFWQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search' | 44 | import { isNSFWQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search' |
46 | import { getServerActor } from '../../../helpers/utils' | 45 | import { getServerActor } from '../../../helpers/utils' |
46 | import { CONFIG } from '../../../initializers/config' | ||
47 | 47 | ||
48 | const videosAddValidator = getCommonVideoAttributes().concat([ | 48 | const videosAddValidator = getCommonVideoEditAttributes().concat([ |
49 | body('videofile') | 49 | body('videofile') |
50 | .custom((value, { req }) => isVideoFile(req.files)).withMessage( | 50 | .custom((value, { req }) => isVideoFile(req.files)).withMessage( |
51 | 'This file is not supported or too large. Please, make sure it is of the following type: ' | 51 | 'This file is not supported or too large. Please, make sure it is of the following type: ' |
@@ -65,9 +65,10 @@ const videosAddValidator = getCommonVideoAttributes().concat([ | |||
65 | const videoFile: Express.Multer.File = req.files['videofile'][0] | 65 | const videoFile: Express.Multer.File = req.files['videofile'][0] |
66 | const user = res.locals.oauth.token.User | 66 | const user = res.locals.oauth.token.User |
67 | 67 | ||
68 | if (!await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) | 68 | if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) |
69 | 69 | ||
70 | const isAble = await user.isAbleToUploadVideo(videoFile) | 70 | const isAble = await user.isAbleToUploadVideo(videoFile) |
71 | |||
71 | if (isAble === false) { | 72 | if (isAble === false) { |
72 | res.status(403) | 73 | res.status(403) |
73 | .json({ error: 'The user video quota is exceeded with this video.' }) | 74 | .json({ error: 'The user video quota is exceeded with this video.' }) |
@@ -93,7 +94,7 @@ const videosAddValidator = getCommonVideoAttributes().concat([ | |||
93 | } | 94 | } |
94 | ]) | 95 | ]) |
95 | 96 | ||
96 | const videosUpdateValidator = getCommonVideoAttributes().concat([ | 97 | const videosUpdateValidator = getCommonVideoEditAttributes().concat([ |
97 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 98 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
98 | body('name') | 99 | body('name') |
99 | .optional() | 100 | .optional() |
@@ -108,7 +109,7 @@ const videosUpdateValidator = getCommonVideoAttributes().concat([ | |||
108 | 109 | ||
109 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | 110 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) |
110 | if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req) | 111 | if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req) |
111 | if (!await isVideoExist(req.params.id, res)) return cleanUpReqFiles(req) | 112 | if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req) |
112 | 113 | ||
113 | const video = res.locals.video | 114 | const video = res.locals.video |
114 | 115 | ||
@@ -122,14 +123,14 @@ const videosUpdateValidator = getCommonVideoAttributes().concat([ | |||
122 | .json({ error: 'Cannot set "private" a video that was not private.' }) | 123 | .json({ error: 'Cannot set "private" a video that was not private.' }) |
123 | } | 124 | } |
124 | 125 | ||
125 | if (req.body.channelId && !await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) | 126 | if (req.body.channelId && !await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) |
126 | 127 | ||
127 | return next() | 128 | return next() |
128 | } | 129 | } |
129 | ]) | 130 | ]) |
130 | 131 | ||
131 | async function checkVideoFollowConstraints (req: express.Request, res: express.Response, next: express.NextFunction) { | 132 | async function checkVideoFollowConstraints (req: express.Request, res: express.Response, next: express.NextFunction) { |
132 | const video: VideoModel = res.locals.video | 133 | const video = res.locals.video |
133 | 134 | ||
134 | // Anybody can watch local videos | 135 | // Anybody can watch local videos |
135 | if (video.isOwned() === true) return next() | 136 | if (video.isOwned() === true) return next() |
@@ -161,15 +162,15 @@ const videosCustomGetValidator = (fetchType: VideoFetchType) => { | |||
161 | logger.debug('Checking videosGet parameters', { parameters: req.params }) | 162 | logger.debug('Checking videosGet parameters', { parameters: req.params }) |
162 | 163 | ||
163 | if (areValidationErrors(req, res)) return | 164 | if (areValidationErrors(req, res)) return |
164 | if (!await isVideoExist(req.params.id, res, fetchType)) return | 165 | if (!await doesVideoExist(req.params.id, res, fetchType)) return |
165 | 166 | ||
166 | const video: VideoModel = res.locals.video | 167 | const video = res.locals.video |
167 | 168 | ||
168 | // Video private or blacklisted | 169 | // Video private or blacklisted |
169 | if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) { | 170 | if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) { |
170 | await authenticatePromiseIfNeeded(req, res) | 171 | await authenticatePromiseIfNeeded(req, res) |
171 | 172 | ||
172 | const user: UserModel = res.locals.oauth ? res.locals.oauth.token.User : null | 173 | const user = res.locals.oauth ? res.locals.oauth.token.User : null |
173 | 174 | ||
174 | // Only the owner or a user that have blacklist rights can see the video | 175 | // Only the owner or a user that have blacklist rights can see the video |
175 | if ( | 176 | if ( |
@@ -206,7 +207,7 @@ const videosRemoveValidator = [ | |||
206 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) | 207 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) |
207 | 208 | ||
208 | if (areValidationErrors(req, res)) return | 209 | if (areValidationErrors(req, res)) return |
209 | if (!await isVideoExist(req.params.id, res)) return | 210 | if (!await doesVideoExist(req.params.id, res)) return |
210 | 211 | ||
211 | // Check if the user who did the request is able to delete the video | 212 | // Check if the user who did the request is able to delete the video |
212 | if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.video, UserRight.REMOVE_ANY_VIDEO, res)) return | 213 | if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.video, UserRight.REMOVE_ANY_VIDEO, res)) return |
@@ -222,7 +223,7 @@ const videosChangeOwnershipValidator = [ | |||
222 | logger.debug('Checking changeOwnership parameters', { parameters: req.params }) | 223 | logger.debug('Checking changeOwnership parameters', { parameters: req.params }) |
223 | 224 | ||
224 | if (areValidationErrors(req, res)) return | 225 | if (areValidationErrors(req, res)) return |
225 | if (!await isVideoExist(req.params.videoId, res)) return | 226 | if (!await doesVideoExist(req.params.videoId, res)) return |
226 | 227 | ||
227 | // Check if the user who did the request is able to change the ownership of the video | 228 | // Check if the user who did the request is able to change the ownership of the video |
228 | if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.video, UserRight.CHANGE_VIDEO_OWNERSHIP, res)) return | 229 | if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.video, UserRight.CHANGE_VIDEO_OWNERSHIP, res)) return |
@@ -255,7 +256,7 @@ const videosTerminateChangeOwnershipValidator = [ | |||
255 | return next() | 256 | return next() |
256 | }, | 257 | }, |
257 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 258 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
258 | const videoChangeOwnership = res.locals.videoChangeOwnership as VideoChangeOwnershipModel | 259 | const videoChangeOwnership = res.locals.videoChangeOwnership |
259 | 260 | ||
260 | if (videoChangeOwnership.status === VideoChangeOwnershipStatus.WAITING) { | 261 | if (videoChangeOwnership.status === VideoChangeOwnershipStatus.WAITING) { |
261 | return next() | 262 | return next() |
@@ -271,10 +272,10 @@ const videosTerminateChangeOwnershipValidator = [ | |||
271 | const videosAcceptChangeOwnershipValidator = [ | 272 | const videosAcceptChangeOwnershipValidator = [ |
272 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 273 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
273 | const body = req.body as VideoChangeOwnershipAccept | 274 | const body = req.body as VideoChangeOwnershipAccept |
274 | if (!await isVideoChannelOfAccountExist(body.channelId, res.locals.oauth.token.User, res)) return | 275 | if (!await doesVideoChannelOfAccountExist(body.channelId, res.locals.oauth.token.User, res)) return |
275 | 276 | ||
276 | const user = res.locals.oauth.token.User | 277 | const user = res.locals.oauth.token.User |
277 | const videoChangeOwnership = res.locals.videoChangeOwnership as VideoChangeOwnershipModel | 278 | const videoChangeOwnership = res.locals.videoChangeOwnership |
278 | const isAble = await user.isAbleToUploadVideo(videoChangeOwnership.Video.getOriginalFile()) | 279 | const isAble = await user.isAbleToUploadVideo(videoChangeOwnership.Video.getOriginalFile()) |
279 | if (isAble === false) { | 280 | if (isAble === false) { |
280 | res.status(403) | 281 | res.status(403) |
@@ -287,7 +288,7 @@ const videosAcceptChangeOwnershipValidator = [ | |||
287 | } | 288 | } |
288 | ] | 289 | ] |
289 | 290 | ||
290 | function getCommonVideoAttributes () { | 291 | function getCommonVideoEditAttributes () { |
291 | return [ | 292 | return [ |
292 | body('thumbnailfile') | 293 | body('thumbnailfile') |
293 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | 294 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( |
@@ -340,7 +341,14 @@ function getCommonVideoAttributes () { | |||
340 | .optional() | 341 | .optional() |
341 | .toBoolean() | 342 | .toBoolean() |
342 | .custom(isBooleanValid).withMessage('Should have comments enabled boolean'), | 343 | .custom(isBooleanValid).withMessage('Should have comments enabled boolean'), |
343 | 344 | body('downloadEnabled') | |
345 | .optional() | ||
346 | .toBoolean() | ||
347 | .custom(isBooleanValid).withMessage('Should have downloading enabled boolean'), | ||
348 | body('originallyPublishedAt') | ||
349 | .optional() | ||
350 | .customSanitizer(toValueOrNull) | ||
351 | .custom(isVideoOriginallyPublishedAtValid).withMessage('Should have a valid original publication date'), | ||
344 | body('scheduleUpdate') | 352 | body('scheduleUpdate') |
345 | .optional() | 353 | .optional() |
346 | .customSanitizer(toValueOrNull), | 354 | .customSanitizer(toValueOrNull), |
@@ -387,7 +395,7 @@ const commonVideosFiltersValidator = [ | |||
387 | 395 | ||
388 | if (areValidationErrors(req, res)) return | 396 | if (areValidationErrors(req, res)) return |
389 | 397 | ||
390 | const user: UserModel = res.locals.oauth ? res.locals.oauth.token.User : undefined | 398 | const user = res.locals.oauth ? res.locals.oauth.token.User : undefined |
391 | if (req.query.filter === 'all-local' && (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false)) { | 399 | if (req.query.filter === 'all-local' && (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false)) { |
392 | res.status(401) | 400 | res.status(401) |
393 | .json({ error: 'You are not allowed to see all local videos.' }) | 401 | .json({ error: 'You are not allowed to see all local videos.' }) |
@@ -413,7 +421,7 @@ export { | |||
413 | videosTerminateChangeOwnershipValidator, | 421 | videosTerminateChangeOwnershipValidator, |
414 | videosAcceptChangeOwnershipValidator, | 422 | videosAcceptChangeOwnershipValidator, |
415 | 423 | ||
416 | getCommonVideoAttributes, | 424 | getCommonVideoEditAttributes, |
417 | 425 | ||
418 | commonVideosFiltersValidator | 426 | commonVideosFiltersValidator |
419 | } | 427 | } |