aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/middlewares
diff options
context:
space:
mode:
Diffstat (limited to 'server/middlewares')
-rw-r--r--server/middlewares/activitypub.ts18
-rw-r--r--server/middlewares/csp.ts30
-rw-r--r--server/middlewares/dnt.ts3
-rw-r--r--server/middlewares/oauth.ts30
-rw-r--r--server/middlewares/sort.ts25
-rw-r--r--server/middlewares/validators/activitypub/activity.ts2
-rw-r--r--server/middlewares/validators/avatar.ts4
-rw-r--r--server/middlewares/validators/blocklist.ts9
-rw-r--r--server/middlewares/validators/config.ts6
-rw-r--r--server/middlewares/validators/feeds.ts8
-rw-r--r--server/middlewares/validators/follows.ts2
-rw-r--r--server/middlewares/validators/plugins.ts71
-rw-r--r--server/middlewares/validators/redundancy.ts74
-rw-r--r--server/middlewares/validators/server.ts5
-rw-r--r--server/middlewares/validators/sort.ts3
-rw-r--r--server/middlewares/validators/themes.ts2
-rw-r--r--server/middlewares/validators/user-subscriptions.ts1
-rw-r--r--server/middlewares/validators/users.ts19
-rw-r--r--server/middlewares/validators/videos/video-abuses.ts51
-rw-r--r--server/middlewares/validators/videos/video-blacklist.ts4
-rw-r--r--server/middlewares/validators/videos/video-captions.ts10
-rw-r--r--server/middlewares/validators/videos/video-channels.ts14
-rw-r--r--server/middlewares/validators/videos/video-comments.ts25
-rw-r--r--server/middlewares/validators/videos/video-imports.ts9
-rw-r--r--server/middlewares/validators/videos/video-playlists.ts9
-rw-r--r--server/middlewares/validators/videos/video-rates.ts6
-rw-r--r--server/middlewares/validators/videos/videos.ts79
-rw-r--r--server/middlewares/validators/webfinger.ts5
28 files changed, 355 insertions, 169 deletions
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts
index c6d8466ac..580606a68 100644
--- a/server/middlewares/activitypub.ts
+++ b/server/middlewares/activitypub.ts
@@ -1,10 +1,12 @@
1import { NextFunction, Request, Response } from 'express' 1import { NextFunction, Request, Response } from 'express'
2import { ActivityPubSignature } from '../../shared' 2import { ActivityDelete, ActivityPubSignature } from '../../shared'
3import { logger } from '../helpers/logger' 3import { logger } from '../helpers/logger'
4import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' 4import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto'
5import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' 5import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants'
6import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' 6import { getOrCreateActorAndServerAndModel } from '../lib/activitypub/actor'
7import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' 7import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger'
8import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor'
9import { getAPId } from '@server/helpers/activitypub'
8 10
9async function checkSignature (req: Request, res: Response, next: NextFunction) { 11async function checkSignature (req: Request, res: Response, next: NextFunction) {
10 try { 12 try {
@@ -15,7 +17,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction)
15 17
16 // Forwarded activity 18 // Forwarded activity
17 const bodyActor = req.body.actor 19 const bodyActor = req.body.actor
18 const bodyActorId = bodyActor && bodyActor.id ? bodyActor.id : bodyActor 20 const bodyActorId = getAPId(bodyActor)
19 if (bodyActorId && bodyActorId !== actor.url) { 21 if (bodyActorId && bodyActorId !== actor.url) {
20 const jsonLDSignatureChecked = await checkJsonLDSignature(req, res) 22 const jsonLDSignatureChecked = await checkJsonLDSignature(req, res)
21 if (jsonLDSignatureChecked !== true) return 23 if (jsonLDSignatureChecked !== true) return
@@ -23,14 +25,20 @@ async function checkSignature (req: Request, res: Response, next: NextFunction)
23 25
24 return next() 26 return next()
25 } catch (err) { 27 } catch (err) {
26 logger.error('Error in ActivityPub signature checker.', err) 28 const activity: ActivityDelete = req.body
29 if (isActorDeleteActivityValid(activity) && activity.object === activity.actor) {
30 logger.debug('Handling signature error on actor delete activity', { err })
31 return res.sendStatus(204)
32 }
33
34 logger.warn('Error in ActivityPub signature checker.', { err })
27 return res.sendStatus(403) 35 return res.sendStatus(403)
28 } 36 }
29} 37}
30 38
31function executeIfActivityPub (req: Request, res: Response, next: NextFunction) { 39function executeIfActivityPub (req: Request, res: Response, next: NextFunction) {
32 const accepted = req.accepts(ACCEPT_HEADERS) 40 const accepted = req.accepts(ACCEPT_HEADERS)
33 if (accepted === false || ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.indexOf(accepted) === -1) { 41 if (accepted === false || ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS.includes(accepted) === false) {
34 // Bypass this route 42 // Bypass this route
35 return next('route') 43 return next('route')
36 } 44 }
diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts
index d11d70790..f5de69603 100644
--- a/server/middlewares/csp.ts
+++ b/server/middlewares/csp.ts
@@ -3,20 +3,20 @@ import { CONFIG } from '../initializers/config'
3 3
4const baseDirectives = Object.assign({}, 4const baseDirectives = Object.assign({},
5 { 5 {
6 defaultSrc: ["'none'"], // by default, not specifying default-src = '*' 6 defaultSrc: [ '\'none\'' ], // by default, not specifying default-src = '*'
7 connectSrc: ['*', 'data:'], 7 connectSrc: [ '*', 'data:' ],
8 mediaSrc: ["'self'", 'https:', 'blob:'], 8 mediaSrc: [ '\'self\'', 'https:', 'blob:' ],
9 fontSrc: ["'self'", 'data:'], 9 fontSrc: [ '\'self\'', 'data:' ],
10 imgSrc: ["'self'", 'data:', 'blob:'], 10 imgSrc: [ '\'self\'', 'data:', 'blob:' ],
11 scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'", 'blob:'], 11 scriptSrc: [ '\'self\' \'unsafe-inline\' \'unsafe-eval\'', 'blob:' ],
12 styleSrc: ["'self' 'unsafe-inline'"], 12 styleSrc: [ '\'self\' \'unsafe-inline\'' ],
13 objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it 13 objectSrc: [ '\'none\'' ], // only define to allow plugins, else let defaultSrc 'none' block it
14 formAction: ["'self'"], 14 formAction: [ '\'self\'' ],
15 frameAncestors: ["'none'"], 15 frameAncestors: [ '\'none\'' ],
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'", 'blob:'] // instead of deprecated child-src 19 workerSrc: [ '\'self\'', 'blob:' ] // instead of deprecated child-src
20 }, 20 },
21 CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {}, 21 CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {},
22 CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} 22 CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {}
@@ -29,7 +29,7 @@ const baseCSP = helmet.contentSecurityPolicy({
29}) 29})
30 30
31const embedCSP = helmet.contentSecurityPolicy({ 31const embedCSP = helmet.contentSecurityPolicy({
32 directives: Object.assign({}, baseDirectives, { frameAncestors: ['*'] }), 32 directives: Object.assign({}, baseDirectives, { frameAncestors: [ '*' ] }),
33 browserSniff: false, // assumes a modern browser, but allows CDN in front 33 browserSniff: false, // assumes a modern browser, but allows CDN in front
34 reportOnly: CONFIG.CSP.REPORT_ONLY 34 reportOnly: CONFIG.CSP.REPORT_ONLY
35}) 35})
diff --git a/server/middlewares/dnt.ts b/server/middlewares/dnt.ts
index 607def855..dd88005dd 100644
--- a/server/middlewares/dnt.ts
+++ b/server/middlewares/dnt.ts
@@ -1,6 +1,3 @@
1import * as ipaddr from 'ipaddr.js'
2import { format } from 'util'
3
4const advertiseDoNotTrack = (_, res, next) => { 1const advertiseDoNotTrack = (_, res, next) => {
5 res.setHeader('Tk', 'N') 2 res.setHeader('Tk', 'N')
6 return next() 3 return next()
diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts
index 749f5cccd..9d0eaa51f 100644
--- a/server/middlewares/oauth.ts
+++ b/server/middlewares/oauth.ts
@@ -1,17 +1,8 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as OAuthServer from 'express-oauth-server'
3import { OAUTH_LIFETIME } from '../initializers/constants'
4import { logger } from '../helpers/logger' 2import { logger } from '../helpers/logger'
5import { Socket } from 'socket.io' 3import { Socket } from 'socket.io'
6import { getAccessToken } from '../lib/oauth-model' 4import { getAccessToken } from '../lib/oauth-model'
7 5import { oAuthServer } from '@server/lib/auth'
8const oAuthServer = new OAuthServer({
9 useErrorHandler: true,
10 accessTokenLifetime: OAUTH_LIFETIME.ACCESS_TOKEN,
11 refreshTokenLifetime: OAUTH_LIFETIME.REFRESH_TOKEN,
12 continueMiddleware: true,
13 model: require('../lib/oauth-model')
14})
15 6
16function authenticate (req: express.Request, res: express.Response, next: express.NextFunction, authenticateInQuery = false) { 7function authenticate (req: express.Request, res: express.Response, next: express.NextFunction, authenticateInQuery = false) {
17 const options = authenticateInQuery ? { allowBearerTokensInQueryString: true } : {} 8 const options = authenticateInQuery ? { allowBearerTokensInQueryString: true } : {}
@@ -51,6 +42,7 @@ function authenticateSocket (socket: Socket, next: (err?: any) => void) {
51 42
52 return next() 43 return next()
53 }) 44 })
45 .catch(err => logger.error('Cannot get access token.', { err }))
54} 46}
55 47
56function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) { 48function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) {
@@ -72,27 +64,11 @@ function optionalAuthenticate (req: express.Request, res: express.Response, next
72 return next() 64 return next()
73} 65}
74 66
75function token (req: express.Request, res: express.Response, next: express.NextFunction) {
76 return oAuthServer.token()(req, res, err => {
77 if (err) {
78 return res.status(err.status)
79 .json({
80 error: err.message,
81 code: err.name
82 })
83 .end()
84 }
85
86 return next()
87 })
88}
89
90// --------------------------------------------------------------------------- 67// ---------------------------------------------------------------------------
91 68
92export { 69export {
93 authenticate, 70 authenticate,
94 authenticateSocket, 71 authenticateSocket,
95 authenticatePromiseIfNeeded, 72 authenticatePromiseIfNeeded,
96 optionalAuthenticate, 73 optionalAuthenticate
97 token
98} 74}
diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts
index 8c27e8237..fcbb2902c 100644
--- a/server/middlewares/sort.ts
+++ b/server/middlewares/sort.ts
@@ -1,20 +1,14 @@
1import * as express from 'express' 1import * as express from 'express'
2import { SortType } from '../models/utils' 2import { SortType } from '../models/utils'
3 3
4function setDefaultSort (req: express.Request, res: express.Response, next: express.NextFunction) { 4const setDefaultSort = setDefaultSortFactory('-createdAt')
5 if (!req.query.sort) req.query.sort = '-createdAt'
6
7 return next()
8}
9 5
10function setDefaultSearchSort (req: express.Request, res: express.Response, next: express.NextFunction) { 6const setDefaultVideoRedundanciesSort = setDefaultSortFactory('name')
11 if (!req.query.sort) req.query.sort = '-match'
12 7
13 return next() 8const setDefaultSearchSort = setDefaultSortFactory('-match')
14}
15 9
16function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { 10function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
17 let newSort: SortType = { sortModel: undefined, sortValue: '' } 11 const newSort: SortType = { sortModel: undefined, sortValue: '' }
18 12
19 if (!req.query.sort) req.query.sort = '-createdAt' 13 if (!req.query.sort) req.query.sort = '-createdAt'
20 14
@@ -39,5 +33,16 @@ function setBlacklistSort (req: express.Request, res: express.Response, next: ex
39export { 33export {
40 setDefaultSort, 34 setDefaultSort,
41 setDefaultSearchSort, 35 setDefaultSearchSort,
36 setDefaultVideoRedundanciesSort,
42 setBlacklistSort 37 setBlacklistSort
43} 38}
39
40// ---------------------------------------------------------------------------
41
42function setDefaultSortFactory (sort: string) {
43 return (req: express.Request, res: express.Response, next: express.NextFunction) => {
44 if (!req.query.sort) req.query.sort = sort
45
46 return next()
47 }
48}
diff --git a/server/middlewares/validators/activitypub/activity.ts b/server/middlewares/validators/activitypub/activity.ts
index 7582f65e7..7350be5d5 100644
--- a/server/middlewares/validators/activitypub/activity.ts
+++ b/server/middlewares/validators/activitypub/activity.ts
@@ -1,7 +1,7 @@
1import * as express from 'express' 1import * as express from 'express'
2import { isRootActivityValid } from '../../../helpers/custom-validators/activitypub/activity' 2import { isRootActivityValid } from '../../../helpers/custom-validators/activitypub/activity'
3import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
4import { getServerActor } from '../../../helpers/utils' 4import { getServerActor } from '@server/models/application/application'
5 5
6async function activityPubValidator (req: express.Request, res: express.Response, next: express.NextFunction) { 6async function activityPubValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
7 logger.debug('Checking activity pub parameters') 7 logger.debug('Checking activity pub parameters')
diff --git a/server/middlewares/validators/avatar.ts b/server/middlewares/validators/avatar.ts
index 8623d07e8..2acb97483 100644
--- a/server/middlewares/validators/avatar.ts
+++ b/server/middlewares/validators/avatar.ts
@@ -8,8 +8,8 @@ import { cleanUpReqFiles } from '../../helpers/express-utils'
8 8
9const updateAvatarValidator = [ 9const updateAvatarValidator = [
10 body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( 10 body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage(
11 'This file is not supported or too large. Please, make sure it is of the following type : ' 11 'This file is not supported or too large. Please, make sure it is of the following type : ' +
12 + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') 12 CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ')
13 ), 13 ),
14 14
15 (req: express.Request, res: express.Response, next: express.NextFunction) => { 15 (req: express.Request, res: express.Response, next: express.NextFunction) => {
diff --git a/server/middlewares/validators/blocklist.ts b/server/middlewares/validators/blocklist.ts
index 47a0b1a1c..27224ff9b 100644
--- a/server/middlewares/validators/blocklist.ts
+++ b/server/middlewares/validators/blocklist.ts
@@ -6,9 +6,9 @@ import { AccountBlocklistModel } from '../../models/account/account-blocklist'
6import { isHostValid } from '../../helpers/custom-validators/servers' 6import { isHostValid } from '../../helpers/custom-validators/servers'
7import { ServerBlocklistModel } from '../../models/server/server-blocklist' 7import { ServerBlocklistModel } from '../../models/server/server-blocklist'
8import { ServerModel } from '../../models/server/server' 8import { ServerModel } from '../../models/server/server'
9import { getServerActor } from '../../helpers/utils'
10import { WEBSERVER } from '../../initializers/constants' 9import { WEBSERVER } from '../../initializers/constants'
11import { doesAccountNameWithHostExist } from '../../helpers/middlewares' 10import { doesAccountNameWithHostExist } from '../../helpers/middlewares'
11import { getServerActor } from '@server/models/application/application'
12 12
13const blockAccountValidator = [ 13const blockAccountValidator = [
14 body('accountName').exists().withMessage('Should have an account name with host'), 14 body('accountName').exists().withMessage('Should have an account name with host'),
@@ -84,12 +84,7 @@ const blockServerValidator = [
84 .end() 84 .end()
85 } 85 }
86 86
87 const server = await ServerModel.loadByHost(host) 87 const server = await ServerModel.loadOrCreateByHost(host)
88 if (!server) {
89 return res.status(404)
90 .send({ error: 'Server host not found.' })
91 .end()
92 }
93 88
94 res.locals.server = server 89 res.locals.server = server
95 90
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts
index 2d1f61947..dfa549e76 100644
--- a/server/middlewares/validators/config.ts
+++ b/server/middlewares/validators/config.ts
@@ -3,10 +3,10 @@ import { body } from 'express-validator'
3import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users' 3import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users'
4import { logger } from '../../helpers/logger' 4import { logger } from '../../helpers/logger'
5import { CustomConfig } from '../../../shared/models/server/custom-config.model' 5import { CustomConfig } from '../../../shared/models/server/custom-config.model'
6import { Emailer } from '../../lib/emailer'
7import { areValidationErrors } from './utils' 6import { areValidationErrors } from './utils'
8import { isThemeNameValid } from '../../helpers/custom-validators/plugins' 7import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
9import { isThemeRegistered } from '../../lib/plugins/theme-utils' 8import { isThemeRegistered } from '../../lib/plugins/theme-utils'
9import { isEmailEnabled } from '@server/initializers/config'
10 10
11const customConfigUpdateValidator = [ 11const customConfigUpdateValidator = [
12 body('instance.name').exists().withMessage('Should have a valid instance name'), 12 body('instance.name').exists().withMessage('Should have a valid instance name'),
@@ -55,7 +55,7 @@ const customConfigUpdateValidator = [
55 55
56 body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'), 56 body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'),
57 57
58 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 58 (req: express.Request, res: express.Response, next: express.NextFunction) => {
59 logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) 59 logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body })
60 60
61 if (areValidationErrors(req, res)) return 61 if (areValidationErrors(req, res)) return
@@ -73,7 +73,7 @@ export {
73} 73}
74 74
75function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) { 75function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) {
76 if (Emailer.isEnabled()) return true 76 if (isEmailEnabled()) return true
77 77
78 if (customConfig.signup.requiresEmailVerification === true) { 78 if (customConfig.signup.requiresEmailVerification === true) {
79 res.status(400) 79 res.status(400)
diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts
index 29f6c87be..f34c2b174 100644
--- a/server/middlewares/validators/feeds.ts
+++ b/server/middlewares/validators/feeds.ts
@@ -22,13 +22,13 @@ function setFeedFormatContentType (req: express.Request, res: express.Response,
22 22
23 let acceptableContentTypes: string[] 23 let acceptableContentTypes: string[]
24 if (format === 'atom' || format === 'atom1') { 24 if (format === 'atom' || format === 'atom1') {
25 acceptableContentTypes = ['application/atom+xml', 'application/xml', 'text/xml'] 25 acceptableContentTypes = [ 'application/atom+xml', 'application/xml', 'text/xml' ]
26 } else if (format === 'json' || format === 'json1') { 26 } else if (format === 'json' || format === 'json1') {
27 acceptableContentTypes = ['application/json'] 27 acceptableContentTypes = [ 'application/json' ]
28 } else if (format === 'rss' || format === 'rss2') { 28 } else if (format === 'rss' || format === 'rss2') {
29 acceptableContentTypes = ['application/rss+xml', 'application/xml', 'text/xml'] 29 acceptableContentTypes = [ 'application/rss+xml', 'application/xml', 'text/xml' ]
30 } else { 30 } else {
31 acceptableContentTypes = ['application/xml', 'text/xml'] 31 acceptableContentTypes = [ 'application/xml', 'text/xml' ]
32 } 32 }
33 33
34 if (req.accepts(acceptableContentTypes)) { 34 if (req.accepts(acceptableContentTypes)) {
diff --git a/server/middlewares/validators/follows.ts b/server/middlewares/validators/follows.ts
index a98d32d86..7808135f7 100644
--- a/server/middlewares/validators/follows.ts
+++ b/server/middlewares/validators/follows.ts
@@ -3,7 +3,6 @@ import { body, param, query } from 'express-validator'
3import { isTestInstance } from '../../helpers/core-utils' 3import { isTestInstance } from '../../helpers/core-utils'
4import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers' 4import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers'
5import { logger } from '../../helpers/logger' 5import { logger } from '../../helpers/logger'
6import { getServerActor } from '../../helpers/utils'
7import { SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants' 6import { SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants'
8import { ActorFollowModel } from '../../models/activitypub/actor-follow' 7import { ActorFollowModel } from '../../models/activitypub/actor-follow'
9import { areValidationErrors } from './utils' 8import { areValidationErrors } from './utils'
@@ -12,6 +11,7 @@ import { loadActorUrlOrGetFromWebfinger } from '../../helpers/webfinger'
12import { isActorTypeValid, isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' 11import { isActorTypeValid, isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor'
13import { MActorFollowActorsDefault } from '@server/typings/models' 12import { MActorFollowActorsDefault } from '@server/typings/models'
14import { isFollowStateValid } from '@server/helpers/custom-validators/follows' 13import { isFollowStateValid } from '@server/helpers/custom-validators/follows'
14import { getServerActor } from '@server/models/application/application'
15 15
16const listFollowsValidator = [ 16const listFollowsValidator = [
17 query('state') 17 query('state')
diff --git a/server/middlewares/validators/plugins.ts b/server/middlewares/validators/plugins.ts
index 910d03c29..2cb49ec43 100644
--- a/server/middlewares/validators/plugins.ts
+++ b/server/middlewares/validators/plugins.ts
@@ -1,33 +1,72 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param, query } from 'express-validator' 2import { body, param, query, ValidationChain } from 'express-validator'
3import { logger } from '../../helpers/logger' 3import { logger } from '../../helpers/logger'
4import { areValidationErrors } from './utils' 4import { areValidationErrors } from './utils'
5import { isNpmPluginNameValid, isPluginNameValid, isPluginTypeValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins' 5import { isNpmPluginNameValid, isPluginNameValid, isPluginTypeValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins'
6import { PluginManager } from '../../lib/plugins/plugin-manager' 6import { PluginManager } from '../../lib/plugins/plugin-manager'
7import { isBooleanValid, isSafePath, toBooleanOrNull } from '../../helpers/custom-validators/misc' 7import { isBooleanValid, isSafePath, toBooleanOrNull, exists } from '../../helpers/custom-validators/misc'
8import { PluginModel } from '../../models/server/plugin' 8import { PluginModel } from '../../models/server/plugin'
9import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/install-plugin.model' 9import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/install-plugin.model'
10import { PluginType } from '../../../shared/models/plugins/plugin.type' 10import { PluginType } from '../../../shared/models/plugins/plugin.type'
11import { CONFIG } from '../../initializers/config' 11import { CONFIG } from '../../initializers/config'
12 12
13const servePluginStaticDirectoryValidator = (pluginType: PluginType) => [ 13const getPluginValidator = (pluginType: PluginType, withVersion = true) => {
14 param('pluginName').custom(isPluginNameValid).withMessage('Should have a valid plugin name'), 14 const validators: (ValidationChain | express.Handler)[] = [
15 param('pluginVersion').custom(isPluginVersionValid).withMessage('Should have a valid plugin version'), 15 param('pluginName').custom(isPluginNameValid).withMessage('Should have a valid plugin name')
16 param('staticEndpoint').custom(isSafePath).withMessage('Should have a valid static endpoint'), 16 ]
17
18 if (withVersion) {
19 validators.push(
20 param('pluginVersion').custom(isPluginVersionValid).withMessage('Should have a valid plugin version')
21 )
22 }
23
24 return validators.concat([
25 (req: express.Request, res: express.Response, next: express.NextFunction) => {
26 logger.debug('Checking getPluginValidator parameters', { parameters: req.params })
27
28 if (areValidationErrors(req, res)) return
29
30 const npmName = PluginModel.buildNpmName(req.params.pluginName, pluginType)
31 const plugin = PluginManager.Instance.getRegisteredPluginOrTheme(npmName)
32
33 if (!plugin) return res.sendStatus(404)
34 if (withVersion && plugin.version !== req.params.pluginVersion) return res.sendStatus(404)
35
36 res.locals.registeredPlugin = plugin
37
38 return next()
39 }
40 ])
41}
42
43const getExternalAuthValidator = [
44 param('authName').custom(exists).withMessage('Should have a valid auth name'),
17 45
18 (req: express.Request, res: express.Response, next: express.NextFunction) => { 46 (req: express.Request, res: express.Response, next: express.NextFunction) => {
19 logger.debug('Checking servePluginStaticDirectory parameters', { parameters: req.params }) 47 logger.debug('Checking getExternalAuthValidator parameters', { parameters: req.params })
20 48
21 if (areValidationErrors(req, res)) return 49 if (areValidationErrors(req, res)) return
22 50
23 const npmName = PluginModel.buildNpmName(req.params.pluginName, pluginType) 51 const plugin = res.locals.registeredPlugin
24 const plugin = PluginManager.Instance.getRegisteredPluginOrTheme(npmName) 52 if (!plugin.registerHelpersStore) return res.sendStatus(404)
25 53
26 if (!plugin || plugin.version !== req.params.pluginVersion) { 54 const externalAuth = plugin.registerHelpersStore.getExternalAuths().find(a => a.authName === req.params.authName)
27 return res.sendStatus(404) 55 if (!externalAuth) return res.sendStatus(404)
28 } 56
57 res.locals.externalAuth = externalAuth
58
59 return next()
60 }
61]
29 62
30 res.locals.registeredPlugin = plugin 63const pluginStaticDirectoryValidator = [
64 param('staticEndpoint').custom(isSafePath).withMessage('Should have a valid static endpoint'),
65
66 (req: express.Request, res: express.Response, next: express.NextFunction) => {
67 logger.debug('Checking pluginStaticDirectoryValidator parameters', { parameters: req.params })
68
69 if (areValidationErrors(req, res)) return
31 70
32 return next() 71 return next()
33 } 72 }
@@ -149,11 +188,13 @@ const listAvailablePluginsValidator = [
149// --------------------------------------------------------------------------- 188// ---------------------------------------------------------------------------
150 189
151export { 190export {
152 servePluginStaticDirectoryValidator, 191 pluginStaticDirectoryValidator,
192 getPluginValidator,
153 updatePluginSettingsValidator, 193 updatePluginSettingsValidator,
154 uninstallPluginValidator, 194 uninstallPluginValidator,
155 listAvailablePluginsValidator, 195 listAvailablePluginsValidator,
156 existingPluginValidator, 196 existingPluginValidator,
157 installOrUpdatePluginValidator, 197 installOrUpdatePluginValidator,
158 listPluginsValidator 198 listPluginsValidator,
199 getExternalAuthValidator
159} 200}
diff --git a/server/middlewares/validators/redundancy.ts b/server/middlewares/validators/redundancy.ts
index 8098e3a44..8cd3bc33d 100644
--- a/server/middlewares/validators/redundancy.ts
+++ b/server/middlewares/validators/redundancy.ts
@@ -1,12 +1,13 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { exists, isBooleanValid, isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' 3import { exists, isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
4import { logger } from '../../helpers/logger' 4import { logger } from '../../helpers/logger'
5import { areValidationErrors } from './utils' 5import { areValidationErrors } from './utils'
6import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' 6import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy'
7import { isHostValid } from '../../helpers/custom-validators/servers' 7import { isHostValid } from '../../helpers/custom-validators/servers'
8import { ServerModel } from '../../models/server/server' 8import { ServerModel } from '../../models/server/server'
9import { doesVideoExist } from '../../helpers/middlewares' 9import { doesVideoExist } from '../../helpers/middlewares'
10import { isVideoRedundancyTarget } from '@server/helpers/custom-validators/video-redundancies'
10 11
11const videoFileRedundancyGetValidator = [ 12const videoFileRedundancyGetValidator = [
12 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'),
@@ -101,10 +102,77 @@ const updateServerRedundancyValidator = [
101 } 102 }
102] 103]
103 104
105const listVideoRedundanciesValidator = [
106 query('target')
107 .custom(isVideoRedundancyTarget).withMessage('Should have a valid video redundancies target'),
108
109 (req: express.Request, res: express.Response, next: express.NextFunction) => {
110 logger.debug('Checking listVideoRedundanciesValidator parameters', { parameters: req.query })
111
112 if (areValidationErrors(req, res)) return
113
114 return next()
115 }
116]
117
118const addVideoRedundancyValidator = [
119 body('videoId')
120 .custom(isIdValid)
121 .withMessage('Should have a valid video id'),
122
123 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
124 logger.debug('Checking addVideoRedundancyValidator parameters', { parameters: req.query })
125
126 if (areValidationErrors(req, res)) return
127
128 if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return
129
130 if (res.locals.onlyVideo.remote === false) {
131 return res.status(400)
132 .json({ error: 'Cannot create a redundancy on a local video' })
133 .end()
134 }
135
136 const alreadyExists = await VideoRedundancyModel.isLocalByVideoUUIDExists(res.locals.onlyVideo.uuid)
137 if (alreadyExists) {
138 return res.status(409)
139 .json({ error: 'This video is already duplicated by your instance.' })
140 }
141
142 return next()
143 }
144]
145
146const removeVideoRedundancyValidator = [
147 param('redundancyId')
148 .custom(isIdValid)
149 .withMessage('Should have a valid redundancy id'),
150
151 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
152 logger.debug('Checking removeVideoRedundancyValidator parameters', { parameters: req.query })
153
154 if (areValidationErrors(req, res)) return
155
156 const redundancy = await VideoRedundancyModel.loadByIdWithVideo(parseInt(req.params.redundancyId, 10))
157 if (!redundancy) {
158 return res.status(404)
159 .json({ error: 'Video redundancy not found' })
160 .end()
161 }
162
163 res.locals.videoRedundancy = redundancy
164
165 return next()
166 }
167]
168
104// --------------------------------------------------------------------------- 169// ---------------------------------------------------------------------------
105 170
106export { 171export {
107 videoFileRedundancyGetValidator, 172 videoFileRedundancyGetValidator,
108 videoPlaylistRedundancyGetValidator, 173 videoPlaylistRedundancyGetValidator,
109 updateServerRedundancyValidator 174 updateServerRedundancyValidator,
175 listVideoRedundanciesValidator,
176 addVideoRedundancyValidator,
177 removeVideoRedundancyValidator
110} 178}
diff --git a/server/middlewares/validators/server.ts b/server/middlewares/validators/server.ts
index f6812647b..6158c3363 100644
--- a/server/middlewares/validators/server.ts
+++ b/server/middlewares/validators/server.ts
@@ -5,9 +5,8 @@ import { isHostValid, isValidContactBody } from '../../helpers/custom-validators
5import { ServerModel } from '../../models/server/server' 5import { ServerModel } from '../../models/server/server'
6import { body } from 'express-validator' 6import { body } from 'express-validator'
7import { isUserDisplayNameValid } from '../../helpers/custom-validators/users' 7import { isUserDisplayNameValid } from '../../helpers/custom-validators/users'
8import { Emailer } from '../../lib/emailer'
9import { Redis } from '../../lib/redis' 8import { Redis } from '../../lib/redis'
10import { CONFIG } from '../../initializers/config' 9import { CONFIG, isEmailEnabled } from '../../initializers/config'
11 10
12const serverGetValidator = [ 11const serverGetValidator = [
13 body('host').custom(isHostValid).withMessage('Should have a valid host'), 12 body('host').custom(isHostValid).withMessage('Should have a valid host'),
@@ -50,7 +49,7 @@ const contactAdministratorValidator = [
50 .end() 49 .end()
51 } 50 }
52 51
53 if (Emailer.isEnabled() === false) { 52 if (isEmailEnabled() === false) {
54 return res 53 return res
55 .status(409) 54 .status(409)
56 .send({ error: 'Emailer is not enabled on this instance.' }) 55 .send({ error: 'Emailer is not enabled on this instance.' })
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts
index c75e701d6..b76dab722 100644
--- a/server/middlewares/validators/sort.ts
+++ b/server/middlewares/validators/sort.ts
@@ -23,6 +23,7 @@ const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUM
23const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) 23const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS)
24const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS) 24const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS)
25const SORTABLE_AVAILABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.AVAILABLE_PLUGINS) 25const SORTABLE_AVAILABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.AVAILABLE_PLUGINS)
26const SORTABLE_VIDEO_REDUNDANCIES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_REDUNDANCIES)
26 27
27const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) 28const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS)
28const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) 29const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS)
@@ -45,6 +46,7 @@ const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COL
45const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) 46const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS)
46const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS) 47const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS)
47const availablePluginsSortValidator = checkSort(SORTABLE_AVAILABLE_PLUGINS_COLUMNS) 48const availablePluginsSortValidator = checkSort(SORTABLE_AVAILABLE_PLUGINS_COLUMNS)
49const videoRedundanciesSortValidator = checkSort(SORTABLE_VIDEO_REDUNDANCIES_COLUMNS)
48 50
49// --------------------------------------------------------------------------- 51// ---------------------------------------------------------------------------
50 52
@@ -69,5 +71,6 @@ export {
69 serversBlocklistSortValidator, 71 serversBlocklistSortValidator,
70 userNotificationsSortValidator, 72 userNotificationsSortValidator,
71 videoPlaylistsSortValidator, 73 videoPlaylistsSortValidator,
74 videoRedundanciesSortValidator,
72 pluginsSortValidator 75 pluginsSortValidator
73} 76}
diff --git a/server/middlewares/validators/themes.ts b/server/middlewares/validators/themes.ts
index 24a9673f7..82794656d 100644
--- a/server/middlewares/validators/themes.ts
+++ b/server/middlewares/validators/themes.ts
@@ -16,7 +16,7 @@ const serveThemeCSSValidator = [
16 16
17 if (areValidationErrors(req, res)) return 17 if (areValidationErrors(req, res)) return
18 18
19 const theme = PluginManager.Instance.getRegisteredTheme(req.params.themeName) 19 const theme = PluginManager.Instance.getRegisteredThemeByShortName(req.params.themeName)
20 20
21 if (!theme || theme.version !== req.params.themeVersion) { 21 if (!theme || theme.version !== req.params.themeVersion) {
22 return res.sendStatus(404) 22 return res.sendStatus(404)
diff --git a/server/middlewares/validators/user-subscriptions.ts b/server/middlewares/validators/user-subscriptions.ts
index 9bc8c87e7..5d4cc94c5 100644
--- a/server/middlewares/validators/user-subscriptions.ts
+++ b/server/middlewares/validators/user-subscriptions.ts
@@ -53,7 +53,6 @@ const userSubscriptionGetValidator = [
53 .json({ 53 .json({
54 error: `Subscription ${req.params.uri} not found.` 54 error: `Subscription ${req.params.uri} not found.`
55 }) 55 })
56 .end()
57 } 56 }
58 57
59 res.locals.subscription = subscription 58 res.locals.subscription = subscription
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index c78c67a8c..840b9fc74 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -1,6 +1,6 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import * as express from 'express' 2import * as express from 'express'
3import { body, param } from 'express-validator' 3import { body, param, query } from 'express-validator'
4import { omit } from 'lodash' 4import { omit } from 'lodash'
5import { isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' 5import { isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
6import { 6import {
@@ -14,6 +14,7 @@ import {
14 isUserDisplayNameValid, 14 isUserDisplayNameValid,
15 isUserNSFWPolicyValid, 15 isUserNSFWPolicyValid,
16 isUserPasswordValid, 16 isUserPasswordValid,
17 isUserPasswordValidOrEmpty,
17 isUserRoleValid, 18 isUserRoleValid,
18 isUserUsernameValid, 19 isUserUsernameValid,
19 isUserVideoLanguages, 20 isUserVideoLanguages,
@@ -36,11 +37,10 @@ import { doesVideoExist } from '../../helpers/middlewares'
36import { UserRole } from '../../../shared/models/users' 37import { UserRole } from '../../../shared/models/users'
37import { MUserDefault } from '@server/typings/models' 38import { MUserDefault } from '@server/typings/models'
38import { Hooks } from '@server/lib/plugins/hooks' 39import { Hooks } from '@server/lib/plugins/hooks'
39import { isLocalVideoAccepted } from '@server/lib/moderation'
40 40
41const usersAddValidator = [ 41const usersAddValidator = [
42 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), 42 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
43 body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'), 43 body('password').custom(isUserPasswordValidOrEmpty).withMessage('Should have a valid password'),
44 body('email').isEmail().withMessage('Should have a valid email'), 44 body('email').isEmail().withMessage('Should have a valid email'),
45 body('videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), 45 body('videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'),
46 body('videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), 46 body('videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'),
@@ -149,7 +149,7 @@ const usersBlockingValidator = [
149] 149]
150 150
151const deleteMeValidator = [ 151const deleteMeValidator = [
152 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 152 (req: express.Request, res: express.Response, next: express.NextFunction) => {
153 const user = res.locals.oauth.token.User 153 const user = res.locals.oauth.token.User
154 if (user.username === 'root') { 154 if (user.username === 'root') {
155 return res.status(400) 155 return res.status(400)
@@ -256,12 +256,13 @@ const usersUpdateMeValidator = [
256 256
257const usersGetValidator = [ 257const usersGetValidator = [
258 param('id').isInt().not().isEmpty().withMessage('Should have a valid id'), 258 param('id').isInt().not().isEmpty().withMessage('Should have a valid id'),
259 query('withStats').optional().isBoolean().withMessage('Should have a valid stats flag'),
259 260
260 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 261 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
261 logger.debug('Checking usersGet parameters', { parameters: req.params }) 262 logger.debug('Checking usersGet parameters', { parameters: req.params })
262 263
263 if (areValidationErrors(req, res)) return 264 if (areValidationErrors(req, res)) return
264 if (!await checkUserIdExist(req.params.id, res)) return 265 if (!await checkUserIdExist(req.params.id, res, req.query.withStats)) return
265 266
266 return next() 267 return next()
267 } 268 }
@@ -303,7 +304,7 @@ const ensureUserRegistrationAllowed = [
303] 304]
304 305
305const ensureUserRegistrationAllowedForIP = [ 306const ensureUserRegistrationAllowedForIP = [
306 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 307 (req: express.Request, res: express.Response, next: express.NextFunction) => {
307 const allowed = isSignupAllowedForCurrentIP(req.ip) 308 const allowed = isSignupAllowedForCurrentIP(req.ip)
308 309
309 if (allowed === false) { 310 if (allowed === false) {
@@ -410,7 +411,7 @@ const userAutocompleteValidator = [
410] 411]
411 412
412const ensureAuthUserOwnsAccountValidator = [ 413const ensureAuthUserOwnsAccountValidator = [
413 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 414 (req: express.Request, res: express.Response, next: express.NextFunction) => {
414 const user = res.locals.oauth.token.User 415 const user = res.locals.oauth.token.User
415 416
416 if (res.locals.account.id !== user.Account.id) { 417 if (res.locals.account.id !== user.Account.id) {
@@ -460,9 +461,9 @@ export {
460 461
461// --------------------------------------------------------------------------- 462// ---------------------------------------------------------------------------
462 463
463function checkUserIdExist (idArg: number | string, res: express.Response) { 464function checkUserIdExist (idArg: number | string, res: express.Response, withStats = false) {
464 const id = parseInt(idArg + '', 10) 465 const id = parseInt(idArg + '', 10)
465 return checkUserExist(() => UserModel.loadById(id), res) 466 return checkUserExist(() => UserModel.loadById(id, withStats), res)
466} 467}
467 468
468function checkUserEmailExist (email: string, res: express.Response, abortResponse = true) { 469function checkUserEmailExist (email: string, res: express.Response, abortResponse = true) {
diff --git a/server/middlewares/validators/videos/video-abuses.ts b/server/middlewares/validators/videos/video-abuses.ts
index a4aef4024..901997bcb 100644
--- a/server/middlewares/validators/videos/video-abuses.ts
+++ b/server/middlewares/validators/videos/video-abuses.ts
@@ -1,14 +1,15 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' 3import { exists, isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc'
4import { logger } from '../../../helpers/logger'
5import { areValidationErrors } from '../utils'
6import { 4import {
5 isAbuseVideoIsValid,
7 isVideoAbuseModerationCommentValid, 6 isVideoAbuseModerationCommentValid,
8 isVideoAbuseReasonValid, 7 isVideoAbuseReasonValid,
9 isVideoAbuseStateValid 8 isVideoAbuseStateValid
10} from '../../../helpers/custom-validators/video-abuses' 9} from '../../../helpers/custom-validators/video-abuses'
10import { logger } from '../../../helpers/logger'
11import { doesVideoAbuseExist, doesVideoExist } from '../../../helpers/middlewares' 11import { doesVideoAbuseExist, doesVideoExist } from '../../../helpers/middlewares'
12import { areValidationErrors } from '../utils'
12 13
13const videoAbuseReportValidator = [ 14const videoAbuseReportValidator = [
14 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 15 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
@@ -32,8 +33,7 @@ const videoAbuseGetValidator = [
32 logger.debug('Checking videoAbuseGetValidator parameters', { parameters: req.body }) 33 logger.debug('Checking videoAbuseGetValidator parameters', { parameters: req.body })
33 34
34 if (areValidationErrors(req, res)) return 35 if (areValidationErrors(req, res)) return
35 if (!await doesVideoExist(req.params.videoId, res)) return 36 if (!await doesVideoAbuseExist(req.params.id, req.params.videoId, res)) return
36 if (!await doesVideoAbuseExist(req.params.id, res.locals.videoAll.id, res)) return
37 37
38 return next() 38 return next()
39 } 39 }
@@ -53,8 +53,42 @@ const videoAbuseUpdateValidator = [
53 logger.debug('Checking videoAbuseUpdateValidator parameters', { parameters: req.body }) 53 logger.debug('Checking videoAbuseUpdateValidator parameters', { parameters: req.body })
54 54
55 if (areValidationErrors(req, res)) return 55 if (areValidationErrors(req, res)) return
56 if (!await doesVideoExist(req.params.videoId, res)) return 56 if (!await doesVideoAbuseExist(req.params.id, req.params.videoId, res)) return
57 if (!await doesVideoAbuseExist(req.params.id, res.locals.videoAll.id, res)) return 57
58 return next()
59 }
60]
61
62const videoAbuseListValidator = [
63 query('id')
64 .optional()
65 .custom(isIdValid).withMessage('Should have a valid id'),
66 query('search')
67 .optional()
68 .custom(exists).withMessage('Should have a valid search'),
69 query('state')
70 .optional()
71 .custom(isVideoAbuseStateValid).withMessage('Should have a valid video abuse state'),
72 query('videoIs')
73 .optional()
74 .custom(isAbuseVideoIsValid).withMessage('Should have a valid "video is" attribute'),
75 query('searchReporter')
76 .optional()
77 .custom(exists).withMessage('Should have a valid reporter search'),
78 query('searchReportee')
79 .optional()
80 .custom(exists).withMessage('Should have a valid reportee search'),
81 query('searchVideo')
82 .optional()
83 .custom(exists).withMessage('Should have a valid video search'),
84 query('searchVideoChannel')
85 .optional()
86 .custom(exists).withMessage('Should have a valid video channel search'),
87
88 (req: express.Request, res: express.Response, next: express.NextFunction) => {
89 logger.debug('Checking videoAbuseListValidator parameters', { parameters: req.body })
90
91 if (areValidationErrors(req, res)) return
58 92
59 return next() 93 return next()
60 } 94 }
@@ -63,6 +97,7 @@ const videoAbuseUpdateValidator = [
63// --------------------------------------------------------------------------- 97// ---------------------------------------------------------------------------
64 98
65export { 99export {
100 videoAbuseListValidator,
66 videoAbuseReportValidator, 101 videoAbuseReportValidator,
67 videoAbuseGetValidator, 102 videoAbuseGetValidator,
68 videoAbuseUpdateValidator 103 videoAbuseUpdateValidator
diff --git a/server/middlewares/validators/videos/video-blacklist.ts b/server/middlewares/validators/videos/video-blacklist.ts
index 5440e57e7..4bd6a8333 100644
--- a/server/middlewares/validators/videos/video-blacklist.ts
+++ b/server/middlewares/validators/videos/video-blacklist.ts
@@ -69,6 +69,10 @@ const videosBlacklistFiltersValidator = [
69 query('type') 69 query('type')
70 .optional() 70 .optional()
71 .custom(isVideoBlacklistTypeValid).withMessage('Should have a valid video blacklist type attribute'), 71 .custom(isVideoBlacklistTypeValid).withMessage('Should have a valid video blacklist type attribute'),
72 query('search')
73 .optional()
74 .not()
75 .isEmpty().withMessage('Should have a valid search'),
72 76
73 (req: express.Request, res: express.Response, next: express.NextFunction) => { 77 (req: express.Request, res: express.Response, next: express.NextFunction) => {
74 logger.debug('Checking videos blacklist filters query', { parameters: req.query }) 78 logger.debug('Checking videos blacklist filters query', { parameters: req.query })
diff --git a/server/middlewares/validators/videos/video-captions.ts b/server/middlewares/validators/videos/video-captions.ts
index 7b0cd6f66..872d9c2ab 100644
--- a/server/middlewares/validators/videos/video-captions.ts
+++ b/server/middlewares/validators/videos/video-captions.ts
@@ -13,10 +13,12 @@ const addVideoCaptionValidator = [
13 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'),
14 param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), 14 param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
15 body('captionfile') 15 body('captionfile')
16 .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')).withMessage( 16 .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile'))
17 `This caption file is not supported or too large. Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` 17 .withMessage(
18 + Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ') 18 'This caption file is not supported or too large. ' +
19 ), 19 `Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` +
20 Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ')
21 ),
20 22
21 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 23 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
22 logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) 24 logger.debug('Checking addVideoCaption parameters', { parameters: req.body })
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts
index ebce14714..882fb2b84 100644
--- a/server/middlewares/validators/videos/video-channels.ts
+++ b/server/middlewares/validators/videos/video-channels.ts
@@ -1,5 +1,5 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { UserRight } from '../../../../shared' 3import { UserRight } from '../../../../shared'
4import { 4import {
5 isVideoChannelDescriptionValid, 5 isVideoChannelDescriptionValid,
@@ -128,6 +128,15 @@ const localVideoChannelValidator = [
128 } 128 }
129] 129]
130 130
131const videoChannelStatsValidator = [
132 query('withStats').optional().isBoolean().withMessage('Should have a valid stats flag'),
133
134 (req: express.Request, res: express.Response, next: express.NextFunction) => {
135 if (areValidationErrors(req, res)) return
136 return next()
137 }
138]
139
131// --------------------------------------------------------------------------- 140// ---------------------------------------------------------------------------
132 141
133export { 142export {
@@ -135,7 +144,8 @@ export {
135 videoChannelsUpdateValidator, 144 videoChannelsUpdateValidator,
136 videoChannelsRemoveValidator, 145 videoChannelsRemoveValidator,
137 videoChannelsNameWithHostValidator, 146 videoChannelsNameWithHostValidator,
138 localVideoChannelValidator 147 localVideoChannelValidator,
148 videoChannelStatsValidator
139} 149}
140 150
141// --------------------------------------------------------------------------- 151// ---------------------------------------------------------------------------
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts
index 77c5f940d..4846a5e9e 100644
--- a/server/middlewares/validators/videos/video-comments.ts
+++ b/server/middlewares/validators/videos/video-comments.ts
@@ -1,16 +1,16 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param } from 'express-validator' 2import { body, param } from 'express-validator'
3import { MUserAccountUrl } from '@server/typings/models'
3import { UserRight } from '../../../../shared' 4import { UserRight } from '../../../../shared'
4import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' 5import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc'
5import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments' 6import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments'
6import { logger } from '../../../helpers/logger' 7import { logger } from '../../../helpers/logger'
8import { doesVideoExist } from '../../../helpers/middlewares'
9import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation'
10import { Hooks } from '../../../lib/plugins/hooks'
7import { VideoCommentModel } from '../../../models/video/video-comment' 11import { VideoCommentModel } from '../../../models/video/video-comment'
12import { MCommentOwnerVideoReply, MVideo, MVideoFullLight, MVideoId } from '../../../typings/models/video'
8import { areValidationErrors } from '../utils' 13import { areValidationErrors } from '../utils'
9import { Hooks } from '../../../lib/plugins/hooks'
10import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation'
11import { doesVideoExist } from '../../../helpers/middlewares'
12import { MCommentOwner, MVideo, MVideoFullLight, MVideoId } from '../../../typings/models/video'
13import { MUser } from '@server/typings/models'
14 14
15const listVideoCommentThreadsValidator = [ 15const listVideoCommentThreadsValidator = [
16 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 16 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
@@ -50,7 +50,7 @@ const addVideoCommentThreadValidator = [
50 if (areValidationErrors(req, res)) return 50 if (areValidationErrors(req, res)) return
51 if (!await doesVideoExist(req.params.videoId, res)) return 51 if (!await doesVideoExist(req.params.videoId, res)) return
52 if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return 52 if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
53 if (!await isVideoCommentAccepted(req, res, res.locals.videoAll,false)) return 53 if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return
54 54
55 return next() 55 return next()
56 } 56 }
@@ -188,7 +188,7 @@ function isVideoCommentsEnabled (video: MVideo, res: express.Response) {
188 return true 188 return true
189} 189}
190 190
191function checkUserCanDeleteVideoComment (user: MUser, videoComment: MCommentOwner, res: express.Response) { 191function checkUserCanDeleteVideoComment (user: MUserAccountUrl, videoComment: MCommentOwnerVideoReply, res: express.Response) {
192 if (videoComment.isDeleted()) { 192 if (videoComment.isDeleted()) {
193 res.status(409) 193 res.status(409)
194 .json({ error: 'This comment is already deleted' }) 194 .json({ error: 'This comment is already deleted' })
@@ -196,11 +196,16 @@ function checkUserCanDeleteVideoComment (user: MUser, videoComment: MCommentOwne
196 return false 196 return false
197 } 197 }
198 198
199 const account = videoComment.Account 199 const userAccount = user.Account
200 if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) === false && account.userId !== user.id) { 200
201 if (
202 user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) === false && // Not a moderator
203 videoComment.accountId !== userAccount.id && // Not the comment owner
204 videoComment.Video.VideoChannel.accountId !== userAccount.id // Not the video owner
205 ) {
201 res.status(403) 206 res.status(403)
202 .json({ error: 'Cannot remove video comment of another user' }) 207 .json({ error: 'Cannot remove video comment of another user' })
203 .end() 208
204 return false 209 return false
205 } 210 }
206 211
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts
index 318dad100..5dc5db533 100644
--- a/server/middlewares/validators/videos/video-imports.ts
+++ b/server/middlewares/validators/videos/video-imports.ts
@@ -22,10 +22,11 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([
22 .optional() 22 .optional()
23 .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'), 23 .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'),
24 body('torrentfile') 24 body('torrentfile')
25 .custom((value, { req }) => isVideoImportTorrentFile(req.files)).withMessage( 25 .custom((value, { req }) => isVideoImportTorrentFile(req.files))
26 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' 26 .withMessage(
27 + CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ') 27 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' +
28 ), 28 CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ')
29 ),
29 body('name') 30 body('name')
30 .optional() 31 .optional()
31 .custom(isVideoNameValid).withMessage('Should have a valid name'), 32 .custom(isVideoNameValid).withMessage('Should have a valid name'),
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts
index 1d67e8666..6b15c5464 100644
--- a/server/middlewares/validators/videos/video-playlists.ts
+++ b/server/middlewares/validators/videos/video-playlists.ts
@@ -384,10 +384,11 @@ export {
384function getCommonPlaylistEditAttributes () { 384function getCommonPlaylistEditAttributes () {
385 return [ 385 return [
386 body('thumbnailfile') 386 body('thumbnailfile')
387 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( 387 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile'))
388 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' 388 .withMessage(
389 + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') 389 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' +
390 ), 390 CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ')
391 ),
391 392
392 body('description') 393 body('description')
393 .optional() 394 .optional()
diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts
index 4021cfecc..cbc144f69 100644
--- a/server/middlewares/validators/videos/video-rates.ts
+++ b/server/middlewares/validators/videos/video-rates.ts
@@ -24,7 +24,7 @@ const videoUpdateRateValidator = [
24 } 24 }
25] 25]
26 26
27const getAccountVideoRateValidator = function (rateType: VideoRateType) { 27const getAccountVideoRateValidatorFactory = function (rateType: VideoRateType) {
28 return [ 28 return [
29 param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'), 29 param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'),
30 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 30 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
@@ -51,7 +51,7 @@ const getAccountVideoRateValidator = function (rateType: VideoRateType) {
51const videoRatingValidator = [ 51const videoRatingValidator = [
52 query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'), 52 query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'),
53 53
54 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 54 (req: express.Request, res: express.Response, next: express.NextFunction) => {
55 logger.debug('Checking rating parameter', { parameters: req.params }) 55 logger.debug('Checking rating parameter', { parameters: req.params })
56 56
57 if (areValidationErrors(req, res)) return 57 if (areValidationErrors(req, res)) return
@@ -64,6 +64,6 @@ const videoRatingValidator = [
64 64
65export { 65export {
66 videoUpdateRateValidator, 66 videoUpdateRateValidator,
67 getAccountVideoRateValidator, 67 getAccountVideoRateValidatorFactory,
68 videoRatingValidator 68 videoRatingValidator
69} 69}
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts
index 6733d9dec..867c05fc1 100644
--- a/server/middlewares/validators/videos/videos.ts
+++ b/server/middlewares/validators/videos/videos.ts
@@ -29,7 +29,7 @@ import {
29} from '../../../helpers/custom-validators/videos' 29} from '../../../helpers/custom-validators/videos'
30import { getDurationFromVideoFile } from '../../../helpers/ffmpeg-utils' 30import { getDurationFromVideoFile } from '../../../helpers/ffmpeg-utils'
31import { logger } from '../../../helpers/logger' 31import { logger } from '../../../helpers/logger'
32import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' 32import { CONSTRAINTS_FIELDS, OVERVIEWS } from '../../../initializers/constants'
33import { authenticatePromiseIfNeeded } from '../../oauth' 33import { authenticatePromiseIfNeeded } from '../../oauth'
34import { areValidationErrors } from '../utils' 34import { areValidationErrors } from '../utils'
35import { cleanUpReqFiles } from '../../../helpers/express-utils' 35import { cleanUpReqFiles } from '../../../helpers/express-utils'
@@ -38,19 +38,24 @@ import { checkUserCanTerminateOwnershipChange, doesChangeVideoOwnershipExist } f
38import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model' 38import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model'
39import { AccountModel } from '../../../models/account/account' 39import { AccountModel } from '../../../models/account/account'
40import { isNSFWQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search' 40import { isNSFWQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search'
41import { getServerActor } from '../../../helpers/utils'
42import { CONFIG } from '../../../initializers/config' 41import { CONFIG } from '../../../initializers/config'
43import { isLocalVideoAccepted } from '../../../lib/moderation' 42import { isLocalVideoAccepted } from '../../../lib/moderation'
44import { Hooks } from '../../../lib/plugins/hooks' 43import { Hooks } from '../../../lib/plugins/hooks'
45import { checkUserCanManageVideo, doesVideoChannelOfAccountExist, doesVideoExist } from '../../../helpers/middlewares' 44import {
45 checkUserCanManageVideo,
46 doesVideoChannelOfAccountExist,
47 doesVideoExist,
48 doesVideoFileOfVideoExist
49} from '../../../helpers/middlewares'
46import { MVideoFullLight } from '@server/typings/models' 50import { MVideoFullLight } from '@server/typings/models'
47import { getVideoWithAttributes } from '../../../helpers/video' 51import { getVideoWithAttributes } from '../../../helpers/video'
52import { getServerActor } from '@server/models/application/application'
48 53
49const videosAddValidator = getCommonVideoEditAttributes().concat([ 54const videosAddValidator = getCommonVideoEditAttributes().concat([
50 body('videofile') 55 body('videofile')
51 .custom((value, { req }) => isVideoFile(req.files)).withMessage( 56 .custom((value, { req }) => isVideoFile(req.files)).withMessage(
52 'This file is not supported or too large. Please, make sure it is of the following type: ' 57 'This file is not supported or too large. Please, make sure it is of the following type: ' +
53 + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') 58 CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
54 ), 59 ),
55 body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), 60 body('name').custom(isVideoNameValid).withMessage('Should have a valid name'),
56 body('channelId') 61 body('channelId')
@@ -147,7 +152,10 @@ async function checkVideoFollowConstraints (req: express.Request, res: express.R
147 }) 152 })
148} 153}
149 154
150const videosCustomGetValidator = (fetchType: 'all' | 'only-video' | 'only-video-with-rights', authenticateInQuery = false) => { 155const videosCustomGetValidator = (
156 fetchType: 'all' | 'only-video' | 'only-video-with-rights' | 'only-immutable-attributes',
157 authenticateInQuery = false
158) => {
151 return [ 159 return [
152 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 160 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
153 161
@@ -157,6 +165,9 @@ const videosCustomGetValidator = (fetchType: 'all' | 'only-video' | 'only-video-
157 if (areValidationErrors(req, res)) return 165 if (areValidationErrors(req, res)) return
158 if (!await doesVideoExist(req.params.id, res, fetchType)) return 166 if (!await doesVideoExist(req.params.id, res, fetchType)) return
159 167
168 // Controllers does not need to check video rights
169 if (fetchType === 'only-immutable-attributes') return next()
170
160 const video = getVideoWithAttributes(res) 171 const video = getVideoWithAttributes(res)
161 const videoAll = video as MVideoFullLight 172 const videoAll = video as MVideoFullLight
162 173
@@ -192,6 +203,20 @@ const videosCustomGetValidator = (fetchType: 'all' | 'only-video' | 'only-video-
192const videosGetValidator = videosCustomGetValidator('all') 203const videosGetValidator = videosCustomGetValidator('all')
193const videosDownloadValidator = videosCustomGetValidator('all', true) 204const videosDownloadValidator = videosCustomGetValidator('all', true)
194 205
206const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
207 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
208 param('videoFileId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid videoFileId'),
209
210 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
211 logger.debug('Checking videoFileMetadataGet parameters', { parameters: req.params })
212
213 if (areValidationErrors(req, res)) return
214 if (!await doesVideoFileOfVideoExist(+req.params.videoFileId, req.params.id, res)) return
215
216 return next()
217 }
218])
219
195const videosRemoveValidator = [ 220const videosRemoveValidator = [
196 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 221 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
197 222
@@ -245,19 +270,15 @@ const videosTerminateChangeOwnershipValidator = [
245 // Check if the user who did the request is able to change the ownership of the video 270 // Check if the user who did the request is able to change the ownership of the video
246 if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return 271 if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
247 272
248 return next()
249 },
250 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
251 const videoChangeOwnership = res.locals.videoChangeOwnership 273 const videoChangeOwnership = res.locals.videoChangeOwnership
252 274
253 if (videoChangeOwnership.status === VideoChangeOwnershipStatus.WAITING) { 275 if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
254 return next()
255 } else {
256 res.status(403) 276 res.status(403)
257 .json({ error: 'Ownership already accepted or refused' }) 277 .json({ error: 'Ownership already accepted or refused' })
258
259 return 278 return
260 } 279 }
280
281 return next()
261 } 282 }
262] 283]
263 284
@@ -280,18 +301,31 @@ const videosAcceptChangeOwnershipValidator = [
280 } 301 }
281] 302]
282 303
304const videosOverviewValidator = [
305 query('page')
306 .optional()
307 .isInt({ min: 1, max: OVERVIEWS.VIDEOS.SAMPLES_COUNT })
308 .withMessage('Should have a valid pagination'),
309
310 (req: express.Request, res: express.Response, next: express.NextFunction) => {
311 if (areValidationErrors(req, res)) return
312
313 return next()
314 }
315]
316
283function getCommonVideoEditAttributes () { 317function getCommonVideoEditAttributes () {
284 return [ 318 return [
285 body('thumbnailfile') 319 body('thumbnailfile')
286 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( 320 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage(
287 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' 321 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' +
288 + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') 322 CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
289 ), 323 ),
290 body('previewfile') 324 body('previewfile')
291 .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( 325 .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage(
292 'This preview file is not supported or too large. Please, make sure it is of the following type: ' 326 'This preview file is not supported or too large. Please, make sure it is of the following type: ' +
293 + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') 327 CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
294 ), 328 ),
295 329
296 body('category') 330 body('category')
297 .optional() 331 .optional()
@@ -409,6 +443,7 @@ export {
409 videosAddValidator, 443 videosAddValidator,
410 videosUpdateValidator, 444 videosUpdateValidator,
411 videosGetValidator, 445 videosGetValidator,
446 videoFileMetadataGetValidator,
412 videosDownloadValidator, 447 videosDownloadValidator,
413 checkVideoFollowConstraints, 448 checkVideoFollowConstraints,
414 videosCustomGetValidator, 449 videosCustomGetValidator,
@@ -420,7 +455,9 @@ export {
420 455
421 getCommonVideoEditAttributes, 456 getCommonVideoEditAttributes,
422 457
423 commonVideosFiltersValidator 458 commonVideosFiltersValidator,
459
460 videosOverviewValidator
424} 461}
425 462
426// --------------------------------------------------------------------------- 463// ---------------------------------------------------------------------------
diff --git a/server/middlewares/validators/webfinger.ts b/server/middlewares/validators/webfinger.ts
index d50e6527f..5fe864f8b 100644
--- a/server/middlewares/validators/webfinger.ts
+++ b/server/middlewares/validators/webfinger.ts
@@ -18,15 +18,14 @@ const webfingerValidator = [
18 const nameWithHost = getHostWithPort(req.query.resource.substr(5)) 18 const nameWithHost = getHostWithPort(req.query.resource.substr(5))
19 const [ name ] = nameWithHost.split('@') 19 const [ name ] = nameWithHost.split('@')
20 20
21 // FIXME: we don't need the full actor 21 const actor = await ActorModel.loadLocalUrlByName(name)
22 const actor = await ActorModel.loadLocalByName(name)
23 if (!actor) { 22 if (!actor) {
24 return res.status(404) 23 return res.status(404)
25 .send({ error: 'Actor not found' }) 24 .send({ error: 'Actor not found' })
26 .end() 25 .end()
27 } 26 }
28 27
29 res.locals.actorFull = actor 28 res.locals.actorUrl = actor
30 return next() 29 return next()
31 } 30 }
32] 31]