From 9ccff23877ec8d740fcd5a9254fcd2424b62d2c8 Mon Sep 17 00:00:00 2001 From: Lucas Declercq Date: Wed, 10 Oct 2018 08:57:00 +0200 Subject: Add explicit error message that changing video ownership only works with local accounts (#1214) * Add explicit error message that changing video ownership only works with local accounts * Remove superfluous logger * Remove unneeded end() to error responses * Add a message on client side to prevent transfering ownership to a remote account --- server/middlewares/validators/videos/videos.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index d6b8aa725..1d0a64bb1 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -69,7 +69,6 @@ const videosAddValidator = getCommonVideoAttributes().concat([ if (isAble === false) { res.status(403) .json({ error: 'The user video quota is exceeded with this video.' }) - .end() return cleanUpReqFiles(req) } @@ -82,7 +81,6 @@ const videosAddValidator = getCommonVideoAttributes().concat([ logger.error('Invalid input file in videosAddValidator.', { err }) res.status(400) .json({ error: 'Invalid input file.' }) - .end() return cleanUpReqFiles(req) } @@ -120,7 +118,6 @@ const videosUpdateValidator = getCommonVideoAttributes().concat([ cleanUpReqFiles(req) return res.status(409) .json({ error: 'Cannot set "private" a video that was not private.' }) - .end() } if (req.body.channelId && !await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) @@ -150,7 +147,6 @@ const videosCustomGetValidator = (fetchType: VideoFetchType) => { if (video.VideoChannel.Account.userId !== user.id && !user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) { return res.status(403) .json({ error: 'Cannot get this private or blacklisted video.' }) - .end() } return next() @@ -239,8 +235,8 @@ const videosChangeOwnershipValidator = [ const nextOwner = await AccountModel.loadLocalByName(req.body.username) if (!nextOwner) { res.status(400) - .type('json') - .end() + .json({ error: 'Changing video ownership to a remote account is not supported yet' }) + return } res.locals.nextOwner = nextOwner @@ -271,7 +267,7 @@ const videosTerminateChangeOwnershipValidator = [ } else { res.status(403) .json({ error: 'Ownership already accepted or refused' }) - .end() + return } } @@ -288,7 +284,7 @@ const videosAcceptChangeOwnershipValidator = [ if (isAble === false) { res.status(403) .json({ error: 'The user video quota is exceeded with this video.' }) - .end() + return } @@ -389,7 +385,6 @@ function areErrorsInScheduleUpdate (req: express.Request, res: express.Response) if (!req.body.scheduleUpdate.updateAt) { res.status(400) .json({ error: 'Schedule update at is mandatory.' }) - .end() return true } -- cgit v1.2.3 From 1cd3facc3de899ac864e979cd6d6a704b712cce3 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 10 Oct 2018 11:46:50 +0200 Subject: Add ability to list all local videos Including private/unlisted for moderators/admins --- server/middlewares/validators/search.ts | 38 +----------------- server/middlewares/validators/videos/videos.ts | 54 +++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 39 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/search.ts b/server/middlewares/validators/search.ts index 8baf643a5..6a95d6095 100644 --- a/server/middlewares/validators/search.ts +++ b/server/middlewares/validators/search.ts @@ -2,8 +2,7 @@ import * as express from 'express' import { areValidationErrors } from './utils' import { logger } from '../../helpers/logger' import { query } from 'express-validator/check' -import { isNumberArray, isStringArray, isNSFWQueryValid } from '../../helpers/custom-validators/search' -import { isBooleanValid, isDateValid, toArray } from '../../helpers/custom-validators/misc' +import { isDateValid } from '../../helpers/custom-validators/misc' const videosSearchValidator = [ query('search').optional().not().isEmpty().withMessage('Should have a valid search'), @@ -35,44 +34,9 @@ const videoChannelsSearchValidator = [ } ] -const commonVideosFiltersValidator = [ - query('categoryOneOf') - .optional() - .customSanitizer(toArray) - .custom(isNumberArray).withMessage('Should have a valid one of category array'), - query('licenceOneOf') - .optional() - .customSanitizer(toArray) - .custom(isNumberArray).withMessage('Should have a valid one of licence array'), - query('languageOneOf') - .optional() - .customSanitizer(toArray) - .custom(isStringArray).withMessage('Should have a valid one of language array'), - query('tagsOneOf') - .optional() - .customSanitizer(toArray) - .custom(isStringArray).withMessage('Should have a valid one of tags array'), - query('tagsAllOf') - .optional() - .customSanitizer(toArray) - .custom(isStringArray).withMessage('Should have a valid all of tags array'), - query('nsfw') - .optional() - .custom(isNSFWQueryValid).withMessage('Should have a valid NSFW attribute'), - - (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking commons video filters query', { parameters: req.query }) - - if (areValidationErrors(req, res)) return - - return next() - } -] - // --------------------------------------------------------------------------- export { - commonVideosFiltersValidator, videoChannelsSearchValidator, videosSearchValidator } diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 1d0a64bb1..9dc52a134 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -1,6 +1,6 @@ import * as express from 'express' import 'express-validator' -import { body, param, ValidationChain } from 'express-validator/check' +import { body, param, query, ValidationChain } from 'express-validator/check' import { UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared' import { isBooleanValid, @@ -8,6 +8,7 @@ import { isIdOrUUIDValid, isIdValid, isUUIDValid, + toArray, toIntOrNull, toValueOrNull } from '../../../helpers/custom-validators/misc' @@ -19,6 +20,7 @@ import { isVideoDescriptionValid, isVideoExist, isVideoFile, + isVideoFilterValid, isVideoImage, isVideoLanguageValid, isVideoLicenceValid, @@ -42,6 +44,7 @@ import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/vid import { VideoChangeOwnershipModel } from '../../../models/video/video-change-ownership' import { AccountModel } from '../../../models/account/account' import { VideoFetchType } from '../../../helpers/video' +import { isNSFWQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search' const videosAddValidator = getCommonVideoAttributes().concat([ body('videofile') @@ -359,6 +362,51 @@ function getCommonVideoAttributes () { ] as (ValidationChain | express.Handler)[] } +const commonVideosFiltersValidator = [ + query('categoryOneOf') + .optional() + .customSanitizer(toArray) + .custom(isNumberArray).withMessage('Should have a valid one of category array'), + query('licenceOneOf') + .optional() + .customSanitizer(toArray) + .custom(isNumberArray).withMessage('Should have a valid one of licence array'), + query('languageOneOf') + .optional() + .customSanitizer(toArray) + .custom(isStringArray).withMessage('Should have a valid one of language array'), + query('tagsOneOf') + .optional() + .customSanitizer(toArray) + .custom(isStringArray).withMessage('Should have a valid one of tags array'), + query('tagsAllOf') + .optional() + .customSanitizer(toArray) + .custom(isStringArray).withMessage('Should have a valid all of tags array'), + query('nsfw') + .optional() + .custom(isNSFWQueryValid).withMessage('Should have a valid NSFW attribute'), + query('filter') + .optional() + .custom(isVideoFilterValid).withMessage('Should have a valid filter attribute'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking commons video filters query', { parameters: req.query }) + + if (areValidationErrors(req, res)) return + + const user: UserModel = res.locals.oauth ? res.locals.oauth.token.User : undefined + if (req.query.filter === 'all-local' && (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false)) { + res.status(401) + .json({ error: 'You are not allowed to see all local videos.' }) + + return + } + + return next() + } +] + // --------------------------------------------------------------------------- export { @@ -375,7 +423,9 @@ export { videosTerminateChangeOwnershipValidator, videosAcceptChangeOwnershipValidator, - getCommonVideoAttributes + getCommonVideoAttributes, + + commonVideosFiltersValidator } // --------------------------------------------------------------------------- -- cgit v1.2.3 From 7ad9b9846c44d198a736183fb186c2039f5236b5 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 12 Oct 2018 15:26:04 +0200 Subject: Add ability for users to block an account/instance on server side --- server/middlewares/validators/blocklist.ts | 94 ++++++++++++++++++++++++++++++ server/middlewares/validators/index.ts | 2 + server/middlewares/validators/server.ts | 33 +++++++++++ server/middlewares/validators/sort.ts | 8 ++- 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 server/middlewares/validators/blocklist.ts create mode 100644 server/middlewares/validators/server.ts (limited to 'server/middlewares') diff --git a/server/middlewares/validators/blocklist.ts b/server/middlewares/validators/blocklist.ts new file mode 100644 index 000000000..9dbd5e512 --- /dev/null +++ b/server/middlewares/validators/blocklist.ts @@ -0,0 +1,94 @@ +import { param, body } from 'express-validator/check' +import * as express from 'express' +import { logger } from '../../helpers/logger' +import { areValidationErrors } from './utils' +import { isAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' +import { UserModel } from '../../models/account/user' +import { AccountBlocklistModel } from '../../models/account/account-blocklist' +import { isHostValid } from '../../helpers/custom-validators/servers' +import { ServerBlocklistModel } from '../../models/server/server-blocklist' + +const blockAccountByAccountValidator = [ + body('accountName').exists().withMessage('Should have an account name with host'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking blockAccountByAccountValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + if (!await isAccountNameWithHostExist(req.body.accountName, res)) return + + return next() + } +] + +const unblockAccountByAccountValidator = [ + param('accountName').exists().withMessage('Should have an account name with host'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking unblockAccountByAccountValidator parameters', { parameters: req.params }) + + if (areValidationErrors(req, res)) return + if (!await isAccountNameWithHostExist(req.params.accountName, res)) return + + const user = res.locals.oauth.token.User as UserModel + const targetAccount = res.locals.account + if (!await isUnblockAccountExists(user.Account.id, targetAccount.id, res)) return + + return next() + } +] + +const unblockServerByAccountValidator = [ + param('host').custom(isHostValid).withMessage('Should have an account name with host'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking unblockServerByAccountValidator parameters', { parameters: req.params }) + + if (areValidationErrors(req, res)) return + + const user = res.locals.oauth.token.User as UserModel + if (!await isUnblockServerExists(user.Account.id, req.params.host, res)) return + + return next() + } +] + +// --------------------------------------------------------------------------- + +export { + blockAccountByAccountValidator, + unblockAccountByAccountValidator, + unblockServerByAccountValidator +} + +// --------------------------------------------------------------------------- + +async function isUnblockAccountExists (accountId: number, targetAccountId: number, res: express.Response) { + const accountBlock = await AccountBlocklistModel.loadByAccountAndTarget(accountId, targetAccountId) + if (!accountBlock) { + res.status(404) + .send({ error: 'Account block entry not found.' }) + .end() + + return false + } + + res.locals.accountBlock = accountBlock + + return true +} + +async function isUnblockServerExists (accountId: number, host: string, res: express.Response) { + const serverBlock = await ServerBlocklistModel.loadByAccountAndHost(accountId, host) + if (!serverBlock) { + res.status(404) + .send({ error: 'Server block entry not found.' }) + .end() + + return false + } + + res.locals.serverBlock = serverBlock + + return true +} diff --git a/server/middlewares/validators/index.ts b/server/middlewares/validators/index.ts index 17226614c..46c7f0f3a 100644 --- a/server/middlewares/validators/index.ts +++ b/server/middlewares/validators/index.ts @@ -1,4 +1,5 @@ export * from './account' +export * from './blocklist' export * from './oembed' export * from './activitypub' export * from './pagination' @@ -10,3 +11,4 @@ export * from './user-subscriptions' export * from './videos' export * from './webfinger' export * from './search' +export * from './server' diff --git a/server/middlewares/validators/server.ts b/server/middlewares/validators/server.ts new file mode 100644 index 000000000..a491dfeb3 --- /dev/null +++ b/server/middlewares/validators/server.ts @@ -0,0 +1,33 @@ +import * as express from 'express' +import { logger } from '../../helpers/logger' +import { areValidationErrors } from './utils' +import { isHostValid } from '../../helpers/custom-validators/servers' +import { ServerModel } from '../../models/server/server' +import { body } from 'express-validator/check' + +const serverGetValidator = [ + body('host').custom(isHostValid).withMessage('Should have a valid host'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking serverGetValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + + const server = await ServerModel.loadByHost(req.body.host) + if (!server) { + return res.status(404) + .send({ error: 'Server host not found.' }) + .end() + } + + res.locals.server = server + + return next() + } +] + +// --------------------------------------------------------------------------- + +export { + serverGetValidator +} diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index 08dcc2680..4c0577d8f 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts @@ -16,6 +16,8 @@ const SORTABLE_VIDEO_CHANNELS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.V const SORTABLE_FOLLOWERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.FOLLOWERS) const SORTABLE_FOLLOWING_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.FOLLOWING) const SORTABLE_USER_SUBSCRIPTIONS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USER_SUBSCRIPTIONS) +const SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.ACCOUNTS_BLOCKLIST) +const SORTABLE_SERVERS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.SERVERS_BLOCKLIST) const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) @@ -31,6 +33,8 @@ const videoChannelsSortValidator = checkSort(SORTABLE_VIDEO_CHANNELS_COLUMNS) const followersSortValidator = checkSort(SORTABLE_FOLLOWERS_COLUMNS) const followingSortValidator = checkSort(SORTABLE_FOLLOWING_COLUMNS) const userSubscriptionsSortValidator = checkSort(SORTABLE_USER_SUBSCRIPTIONS_COLUMNS) +const accountsBlocklistSortValidator = checkSort(SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS) +const serversBlocklistSortValidator = checkSort(SORTABLE_SERVERS_BLOCKLIST_COLUMNS) // --------------------------------------------------------------------------- @@ -48,5 +52,7 @@ export { jobsSortValidator, videoCommentThreadsSortValidator, userSubscriptionsSortValidator, - videoChannelsSearchSortValidator + videoChannelsSearchSortValidator, + accountsBlocklistSortValidator, + serversBlocklistSortValidator } -- cgit v1.2.3 From af5767ffae41b2d5604e41ba9a7225c623dd6735 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 12 Oct 2018 17:26:40 +0200 Subject: Add user/instance block by users in the client --- server/middlewares/validators/blocklist.ts | 45 +++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/blocklist.ts b/server/middlewares/validators/blocklist.ts index 9dbd5e512..25c054d6b 100644 --- a/server/middlewares/validators/blocklist.ts +++ b/server/middlewares/validators/blocklist.ts @@ -1,4 +1,4 @@ -import { param, body } from 'express-validator/check' +import { body, param } from 'express-validator/check' import * as express from 'express' import { logger } from '../../helpers/logger' import { areValidationErrors } from './utils' @@ -7,6 +7,8 @@ import { UserModel } from '../../models/account/user' import { AccountBlocklistModel } from '../../models/account/account-blocklist' import { isHostValid } from '../../helpers/custom-validators/servers' import { ServerBlocklistModel } from '../../models/server/server-blocklist' +import { ServerModel } from '../../models/server/server' +import { CONFIG } from '../../initializers' const blockAccountByAccountValidator = [ body('accountName').exists().withMessage('Should have an account name with host'), @@ -17,6 +19,17 @@ const blockAccountByAccountValidator = [ if (areValidationErrors(req, res)) return if (!await isAccountNameWithHostExist(req.body.accountName, res)) return + const user = res.locals.oauth.token.User as UserModel + const accountToBlock = res.locals.account + + if (user.Account.id === accountToBlock.id) { + res.status(409) + .send({ error: 'You cannot block yourself.' }) + .end() + + return + } + return next() } ] @@ -38,6 +51,35 @@ const unblockAccountByAccountValidator = [ } ] +const blockServerByAccountValidator = [ + body('host').custom(isHostValid).withMessage('Should have a valid host'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking serverGetValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + + const host: string = req.body.host + + if (host === CONFIG.WEBSERVER.HOST) { + return res.status(409) + .send({ error: 'You cannot block your own server.' }) + .end() + } + + const server = await ServerModel.loadByHost(host) + if (!server) { + return res.status(404) + .send({ error: 'Server host not found.' }) + .end() + } + + res.locals.server = server + + return next() + } +] + const unblockServerByAccountValidator = [ param('host').custom(isHostValid).withMessage('Should have an account name with host'), @@ -56,6 +98,7 @@ const unblockServerByAccountValidator = [ // --------------------------------------------------------------------------- export { + blockServerByAccountValidator, blockAccountByAccountValidator, unblockAccountByAccountValidator, unblockServerByAccountValidator -- cgit v1.2.3 From b44164bb567fe7c9f65f1ac2908d44990a8ccc8e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 15 Oct 2018 13:03:04 +0200 Subject: Add ability to mute a user/instance by server in server api --- server/middlewares/validators/blocklist.ts | 45 ++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/blocklist.ts b/server/middlewares/validators/blocklist.ts index 25c054d6b..109276c63 100644 --- a/server/middlewares/validators/blocklist.ts +++ b/server/middlewares/validators/blocklist.ts @@ -9,8 +9,9 @@ import { isHostValid } from '../../helpers/custom-validators/servers' import { ServerBlocklistModel } from '../../models/server/server-blocklist' import { ServerModel } from '../../models/server/server' import { CONFIG } from '../../initializers' +import { getServerActor } from '../../helpers/utils' -const blockAccountByAccountValidator = [ +const blockAccountValidator = [ body('accountName').exists().withMessage('Should have an account name with host'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { @@ -51,7 +52,24 @@ const unblockAccountByAccountValidator = [ } ] -const blockServerByAccountValidator = [ +const unblockAccountByServerValidator = [ + param('accountName').exists().withMessage('Should have an account name with host'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking unblockAccountByServerValidator parameters', { parameters: req.params }) + + if (areValidationErrors(req, res)) return + if (!await isAccountNameWithHostExist(req.params.accountName, res)) return + + const serverActor = await getServerActor() + const targetAccount = res.locals.account + if (!await isUnblockAccountExists(serverActor.Account.id, targetAccount.id, res)) return + + return next() + } +] + +const blockServerValidator = [ body('host').custom(isHostValid).withMessage('Should have a valid host'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { @@ -95,13 +113,30 @@ const unblockServerByAccountValidator = [ } ] +const unblockServerByServerValidator = [ + param('host').custom(isHostValid).withMessage('Should have an account name with host'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking unblockServerByServerValidator parameters', { parameters: req.params }) + + if (areValidationErrors(req, res)) return + + const serverActor = await getServerActor() + if (!await isUnblockServerExists(serverActor.Account.id, req.params.host, res)) return + + return next() + } +] + // --------------------------------------------------------------------------- export { - blockServerByAccountValidator, - blockAccountByAccountValidator, + blockServerValidator, + blockAccountValidator, unblockAccountByAccountValidator, - unblockServerByAccountValidator + unblockServerByAccountValidator, + unblockAccountByServerValidator, + unblockServerByServerValidator } // --------------------------------------------------------------------------- -- cgit v1.2.3 From 41f2ebae4f970932fb62d2d8923b1f776f0b1494 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 19 Oct 2018 11:41:19 +0200 Subject: Add HTTP signature check before linked signature It's faster, and will allow us to use RSA signature 2018 (with upstream jsonld-signature module) without too much incompatibilities in the peertube federation --- server/middlewares/activitypub.ts | 94 +++++++++++++++++----- .../validators/activitypub/signature.ts | 16 +++- 2 files changed, 88 insertions(+), 22 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index d7f59be8c..1ec888477 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts @@ -2,34 +2,32 @@ import { eachSeries } from 'async' import { NextFunction, Request, RequestHandler, Response } from 'express' import { ActivityPubSignature } from '../../shared' import { logger } from '../helpers/logger' -import { isSignatureVerified } from '../helpers/peertube-crypto' -import { ACCEPT_HEADERS, ACTIVITY_PUB } from '../initializers' +import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' +import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers' import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' import { ActorModel } from '../models/activitypub/actor' +import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' async function checkSignature (req: Request, res: Response, next: NextFunction) { - const signatureObject: ActivityPubSignature = req.body.signature + try { + const httpSignatureChecked = await checkHttpSignature(req, res) + if (httpSignatureChecked !== true) return - const [ creator ] = signatureObject.creator.split('#') + const actor: ActorModel = res.locals.signature.actor - logger.debug('Checking signature of actor %s...', creator) + // Forwarded activity + const bodyActor = req.body.actor + const bodyActorId = bodyActor && bodyActor.id ? bodyActor.id : bodyActor + if (bodyActorId && bodyActorId !== actor.url) { + const jsonLDSignatureChecked = await checkJsonLDSignature(req, res) + if (jsonLDSignatureChecked !== true) return + } - let actor: ActorModel - try { - actor = await getOrCreateActorAndServerAndModel(creator) + return next() } catch (err) { - logger.warn('Cannot create remote actor %s and check signature.', creator, { err }) + logger.error('Error in ActivityPub signature checker.', err) return res.sendStatus(403) } - - const verified = await isSignatureVerified(actor, req.body) - if (verified === false) return res.sendStatus(403) - - res.locals.signature = { - actor - } - - return next() } function executeIfActivityPub (fun: RequestHandler | RequestHandler[]) { @@ -57,3 +55,63 @@ export { checkSignature, executeIfActivityPub } + +// --------------------------------------------------------------------------- + +async function checkHttpSignature (req: Request, res: Response) { + // FIXME: mastodon does not include the Signature scheme + const sig = req.headers[HTTP_SIGNATURE.HEADER_NAME] as string + if (sig && sig.startsWith('Signature ') === false) req.headers[HTTP_SIGNATURE.HEADER_NAME] = 'Signature ' + sig + + const parsed = parseHTTPSignature(req) + + const keyId = parsed.keyId + if (!keyId) { + res.sendStatus(403) + return false + } + + logger.debug('Checking HTTP signature of actor %s...', keyId) + + let [ actorUrl ] = keyId.split('#') + if (actorUrl.startsWith('acct:')) { + actorUrl = await loadActorUrlOrGetFromWebfinger(actorUrl.replace(/^acct:/, '')) + } + + const actor = await getOrCreateActorAndServerAndModel(actorUrl) + + const verified = isHTTPSignatureVerified(parsed, actor) + if (verified !== true) { + res.sendStatus(403) + return false + } + + res.locals.signature = { actor } + + return true +} + +async function checkJsonLDSignature (req: Request, res: Response) { + const signatureObject: ActivityPubSignature = req.body.signature + + if (!signatureObject.creator) { + res.sendStatus(403) + return false + } + + const [ creator ] = signatureObject.creator.split('#') + + logger.debug('Checking JsonLD signature of actor %s...', creator) + + const actor = await getOrCreateActorAndServerAndModel(creator) + const verified = await isJsonLDSignatureVerified(actor, req.body) + + if (verified !== true) { + res.sendStatus(403) + return false + } + + res.locals.signature = { actor } + + return true +} diff --git a/server/middlewares/validators/activitypub/signature.ts b/server/middlewares/validators/activitypub/signature.ts index 4efe9aafa..be14e92ea 100644 --- a/server/middlewares/validators/activitypub/signature.ts +++ b/server/middlewares/validators/activitypub/signature.ts @@ -9,10 +9,18 @@ import { logger } from '../../../helpers/logger' import { areValidationErrors } from '../utils' const signatureValidator = [ - body('signature.type').custom(isSignatureTypeValid).withMessage('Should have a valid signature type'), - body('signature.created').custom(isDateValid).withMessage('Should have a valid signature created date'), - body('signature.creator').custom(isSignatureCreatorValid).withMessage('Should have a valid signature creator'), - body('signature.signatureValue').custom(isSignatureValueValid).withMessage('Should have a valid signature value'), + body('signature.type') + .optional() + .custom(isSignatureTypeValid).withMessage('Should have a valid signature type'), + body('signature.created') + .optional() + .custom(isDateValid).withMessage('Should have a valid signature created date'), + body('signature.creator') + .optional() + .custom(isSignatureCreatorValid).withMessage('Should have a valid signature creator'), + body('signature.signatureValue') + .optional() + .custom(isSignatureValueValid).withMessage('Should have a valid signature value'), (req: express.Request, res: express.Response, next: express.NextFunction) => { logger.debug('Checking activitypub signature parameter', { parameters: { signature: req.body.signature } }) -- cgit v1.2.3 From df66d81583e07ce049daeeef1edc6a87b57b3684 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 23 Oct 2018 11:38:48 +0200 Subject: Add compatibility with other Linked Signature algorithms --- server/middlewares/activitypub.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index 1ec888477..01e5dd24e 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts @@ -53,7 +53,8 @@ function executeIfActivityPub (fun: RequestHandler | RequestHandler[]) { export { checkSignature, - executeIfActivityPub + executeIfActivityPub, + checkHttpSignature } // --------------------------------------------------------------------------- @@ -94,7 +95,7 @@ async function checkHttpSignature (req: Request, res: Response) { async function checkJsonLDSignature (req: Request, res: Response) { const signatureObject: ActivityPubSignature = req.body.signature - if (!signatureObject.creator) { + if (!signatureObject || !signatureObject.creator) { res.sendStatus(403) return false } -- cgit v1.2.3 From 5c6d985faeef1d6793d3f44ca6374f1a9b722806 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 14 Nov 2018 15:01:28 +0100 Subject: Check activities host --- server/middlewares/validators/videos/index.ts | 2 + .../middlewares/validators/videos/video-rates.ts | 55 ++++++++++++++++++++++ .../middlewares/validators/videos/video-shares.ts | 38 +++++++++++++++ server/middlewares/validators/videos/videos.ts | 40 ---------------- 4 files changed, 95 insertions(+), 40 deletions(-) create mode 100644 server/middlewares/validators/videos/video-rates.ts create mode 100644 server/middlewares/validators/videos/video-shares.ts (limited to 'server/middlewares') diff --git a/server/middlewares/validators/videos/index.ts b/server/middlewares/validators/videos/index.ts index 294783d85..a0d585b93 100644 --- a/server/middlewares/validators/videos/index.ts +++ b/server/middlewares/validators/videos/index.ts @@ -5,4 +5,6 @@ export * from './video-channels' export * from './video-comments' export * from './video-imports' export * from './video-watch' +export * from './video-rates' +export * from './video-shares' export * from './videos' diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts new file mode 100644 index 000000000..793354520 --- /dev/null +++ b/server/middlewares/validators/videos/video-rates.ts @@ -0,0 +1,55 @@ +import * as express from 'express' +import 'express-validator' +import { body, param } from 'express-validator/check' +import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' +import { isVideoExist, isVideoRatingTypeValid } from '../../../helpers/custom-validators/videos' +import { logger } from '../../../helpers/logger' +import { areValidationErrors } from '../utils' +import { AccountVideoRateModel } from '../../../models/account/account-video-rate' +import { VideoRateType } from '../../../../shared/models/videos' +import { isAccountNameValid } from '../../../helpers/custom-validators/accounts' + +const videoUpdateRateValidator = [ + param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), + body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking videoRate parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + if (!await isVideoExist(req.params.id, res)) return + + return next() + } +] + +const getAccountVideoRateValidator = function (rateType: VideoRateType) { + return [ + param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'), + param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params }) + + if (areValidationErrors(req, res)) return + + const rate = await AccountVideoRateModel.loadLocalAndPopulateVideo(rateType, req.params.name, req.params.videoId) + if (!rate) { + return res.status(404) + .json({ error: 'Video rate not found' }) + .end() + } + + res.locals.accountVideoRate = rate + + return next() + } + ] +} + +// --------------------------------------------------------------------------- + +export { + videoUpdateRateValidator, + getAccountVideoRateValidator +} diff --git a/server/middlewares/validators/videos/video-shares.ts b/server/middlewares/validators/videos/video-shares.ts new file mode 100644 index 000000000..646d7acb1 --- /dev/null +++ b/server/middlewares/validators/videos/video-shares.ts @@ -0,0 +1,38 @@ +import * as express from 'express' +import 'express-validator' +import { param } from 'express-validator/check' +import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' +import { isVideoExist } from '../../../helpers/custom-validators/videos' +import { logger } from '../../../helpers/logger' +import { VideoShareModel } from '../../../models/video/video-share' +import { areValidationErrors } from '../utils' +import { VideoModel } from '../../../models/video/video' + +const videosShareValidator = [ + param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), + param('actorId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid actor id'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking videoShare parameters', { parameters: req.params }) + + if (areValidationErrors(req, res)) return + if (!await isVideoExist(req.params.id, res)) return + + const video: VideoModel = res.locals.video + + const share = await VideoShareModel.load(req.params.actorId, video.id) + if (!share) { + return res.status(404) + .end() + } + + res.locals.videoShare = share + return next() + } +] + +// --------------------------------------------------------------------------- + +export { + videosShareValidator +} diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 9dc52a134..656d161d8 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -26,14 +26,12 @@ import { isVideoLicenceValid, isVideoNameValid, isVideoPrivacyValid, - isVideoRatingTypeValid, isVideoSupportValid, isVideoTagsValid } from '../../../helpers/custom-validators/videos' import { getDurationFromVideoFile } from '../../../helpers/ffmpeg-utils' import { logger } from '../../../helpers/logger' import { CONSTRAINTS_FIELDS } from '../../../initializers' -import { VideoShareModel } from '../../../models/video/video-share' import { authenticate } from '../../oauth' import { areValidationErrors } from '../utils' import { cleanUpReqFiles } from '../../../helpers/express-utils' @@ -188,41 +186,6 @@ const videosRemoveValidator = [ } ] -const videoRateValidator = [ - param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), - body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'), - - async (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking videoRate parameters', { parameters: req.body }) - - if (areValidationErrors(req, res)) return - if (!await isVideoExist(req.params.id, res)) return - - return next() - } -] - -const videosShareValidator = [ - param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), - param('accountId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid account id'), - - async (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking videoShare parameters', { parameters: req.params }) - - if (areValidationErrors(req, res)) return - if (!await isVideoExist(req.params.id, res)) return - - const share = await VideoShareModel.load(req.params.accountId, res.locals.video.id, undefined) - if (!share) { - return res.status(404) - .end() - } - - res.locals.videoShare = share - return next() - } -] - const videosChangeOwnershipValidator = [ param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), @@ -415,9 +378,6 @@ export { videosGetValidator, videosCustomGetValidator, videosRemoveValidator, - videosShareValidator, - - videoRateValidator, videosChangeOwnershipValidator, videosTerminateChangeOwnershipValidator, -- cgit v1.2.3 From 7373507fa830b0f18cb4cd95dfd923b1600e501d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Nov 2018 10:05:25 +0100 Subject: Improve video upload error handling --- server/middlewares/validators/videos/videos.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 656d161d8..bf21bca8c 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -393,6 +393,8 @@ export { function areErrorsInScheduleUpdate (req: express.Request, res: express.Response) { if (req.body.scheduleUpdate) { if (!req.body.scheduleUpdate.updateAt) { + logger.warn('Invalid parameters: scheduleUpdate.updateAt is mandatory.') + res.status(400) .json({ error: 'Schedule update at is mandatory.' }) -- cgit v1.2.3 From 8d1fa36ad22a21a9b0fb6bf51a27d09954220013 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Nov 2018 11:18:13 +0100 Subject: Do not host remote AP objects --- server/middlewares/cache.ts | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'server/middlewares') diff --git a/server/middlewares/cache.ts b/server/middlewares/cache.ts index 1e00fc731..8ffe75700 100644 --- a/server/middlewares/cache.ts +++ b/server/middlewares/cache.ts @@ -19,6 +19,7 @@ function cacheRoute (lifetimeArg: string | number) { logger.debug('No cached results for route %s.', req.originalUrl) const sendSave = res.send.bind(res) + const redirectSave = res.redirect.bind(res) res.send = (body) => { if (res.statusCode >= 200 && res.statusCode < 400) { @@ -38,6 +39,12 @@ function cacheRoute (lifetimeArg: string | number) { return sendSave(body) } + res.redirect = url => { + done() + + return redirectSave(url) + } + return next() } -- cgit v1.2.3 From 8d4273463fb19d503b1aa0a32dc289f292ed614e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Nov 2018 15:02:48 +0100 Subject: Check follow constraints when getting a video --- server/middlewares/oauth.ts | 16 ++++++++ server/middlewares/validators/videos/videos.ts | 52 ++++++++++++++++++++------ 2 files changed, 57 insertions(+), 11 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 5233b66bd..8c1df2c3e 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts @@ -28,9 +28,24 @@ function authenticate (req: express.Request, res: express.Response, next: expres }) } +function authenticatePromiseIfNeeded (req: express.Request, res: express.Response) { + return new Promise(resolve => { + // Already authenticated? (or tried to) + if (res.locals.oauth && res.locals.oauth.token.User) return resolve() + + if (res.locals.authenticated === false) return res.sendStatus(401) + + authenticate(req, res, () => { + return resolve() + }) + }) +} + function optionalAuthenticate (req: express.Request, res: express.Response, next: express.NextFunction) { if (req.header('authorization')) return authenticate(req, res, next) + res.locals.authenticated = false + return next() } @@ -53,6 +68,7 @@ function token (req: express.Request, res: express.Response, next: express.NextF export { authenticate, + authenticatePromiseIfNeeded, optionalAuthenticate, token } diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index bf21bca8c..051a19e16 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -31,8 +31,8 @@ import { } from '../../../helpers/custom-validators/videos' import { getDurationFromVideoFile } from '../../../helpers/ffmpeg-utils' import { logger } from '../../../helpers/logger' -import { CONSTRAINTS_FIELDS } from '../../../initializers' -import { authenticate } from '../../oauth' +import { CONFIG, CONSTRAINTS_FIELDS } from '../../../initializers' +import { authenticatePromiseIfNeeded } from '../../oauth' import { areValidationErrors } from '../utils' import { cleanUpReqFiles } from '../../../helpers/express-utils' import { VideoModel } from '../../../models/video/video' @@ -43,6 +43,7 @@ import { VideoChangeOwnershipModel } from '../../../models/video/video-change-ow import { AccountModel } from '../../../models/account/account' import { VideoFetchType } from '../../../helpers/video' import { isNSFWQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search' +import { getServerActor } from '../../../helpers/utils' const videosAddValidator = getCommonVideoAttributes().concat([ body('videofile') @@ -127,6 +128,31 @@ const videosUpdateValidator = getCommonVideoAttributes().concat([ } ]) +async function checkVideoFollowConstraints (req: express.Request, res: express.Response, next: express.NextFunction) { + const video: VideoModel = res.locals.video + + // Anybody can watch local videos + if (video.isOwned() === true) return next() + + // Logged user + if (res.locals.oauth) { + // Users can search or watch remote videos + if (CONFIG.SEARCH.REMOTE_URI.USERS === true) return next() + } + + // Anybody can search or watch remote videos + if (CONFIG.SEARCH.REMOTE_URI.ANONYMOUS === true) return next() + + // Check our instance follows an actor that shared this video + const serverActor = await getServerActor() + if (await VideoModel.checkVideoHasInstanceFollow(video.id, serverActor.id) === true) return next() + + return res.status(403) + .json({ + error: 'Cannot get this video regarding follow constraints.' + }) +} + const videosCustomGetValidator = (fetchType: VideoFetchType) => { return [ param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), @@ -141,17 +167,20 @@ const videosCustomGetValidator = (fetchType: VideoFetchType) => { // Video private or blacklisted if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) { - return authenticate(req, res, () => { - const user: UserModel = res.locals.oauth.token.User + await authenticatePromiseIfNeeded(req, res) + + const user: UserModel = res.locals.oauth ? res.locals.oauth.token.User : null - // Only the owner or a user that have blacklist rights can see the video - if (video.VideoChannel.Account.userId !== user.id && !user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) { - return res.status(403) - .json({ error: 'Cannot get this private or blacklisted video.' }) - } + // Only the owner or a user that have blacklist rights can see the video + if ( + !user || + (video.VideoChannel.Account.userId !== user.id && !user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) + ) { + return res.status(403) + .json({ error: 'Cannot get this private or blacklisted video.' }) + } - return next() - }) + return next() } // Video is public, anyone can access it @@ -376,6 +405,7 @@ export { videosAddValidator, videosUpdateValidator, videosGetValidator, + checkVideoFollowConstraints, videosCustomGetValidator, videosRemoveValidator, -- cgit v1.2.3 From fc2ec87a8c4dcfbb91a1a62cf4c07a2a8e6a50fe Mon Sep 17 00:00:00 2001 From: Josh Morel Date: Wed, 21 Nov 2018 02:48:29 -0500 Subject: enable email verification by admin (#1348) * enable email verification by admin * rename/label to set email as verified to be more explicit that admin is not sending another email to confirm * add update user emailVerified check-params test * make user.model emailVerified property required --- server/middlewares/validators/users.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 61297120a..ccaf2eeb6 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts @@ -114,6 +114,7 @@ const deleteMeValidator = [ const usersUpdateValidator = [ param('id').isInt().not().isEmpty().withMessage('Should have a valid id'), body('email').optional().isEmail().withMessage('Should have a valid email attribute'), + body('emailVerified').optional().isBoolean().withMessage('Should have a valid email verified attribute'), body('videoQuota').optional().custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), body('videoQuotaDaily').optional().custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), body('role').optional().custom(isUserRoleValid).withMessage('Should have a valid role'), -- cgit v1.2.3 From 5e755fff9d70a7fd3c4f85bb524f1b774dd85b25 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Thu, 13 Dec 2018 09:49:45 +0100 Subject: add Content Security Policy (#1252) * add Content Security Policy * remove reflect-metadata on production builds to get rid of unsafe-eval * fix baseCSP usage * add SRI to CSP * add blob: to media-src * remove SRI * CSP set to reportOnly * adding data: to connect-src CSP * remove block-all-mixed-content * add report-uri support --- server/middlewares/csp.ts | 45 +++++++++++++++++++++++++++++++++++++++++++++ server/middlewares/dnt.ts | 2 +- server/middlewares/index.ts | 2 ++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 server/middlewares/csp.ts (limited to 'server/middlewares') diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts new file mode 100644 index 000000000..a0ed3710b --- /dev/null +++ b/server/middlewares/csp.ts @@ -0,0 +1,45 @@ +import * as helmet from 'helmet' +import { CONFIG } from '../initializers/constants' + +const baseDirectives = Object.assign({}, + { + defaultSrc: ["'none'"], // by default, not specifying default-src = '*' + connectSrc: ['*', 'data:'], + mediaSrc: ["'self'", 'https:', 'blob:'], + fontSrc: ["'self'", 'data:'], + imgSrc: ["'self'", 'data:'], + scriptSrc: ["'self' 'unsafe-inline'"], + styleSrc: ["'self' 'unsafe-inline'"], + // objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it + formAction: ["'self'"], + frameAncestors: ["'none'"], + baseUri: ["'self'"], + pluginTypes: ["'none'"], + manifestSrc: ["'self'"], + frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed + workerSrc: ["'self'"], // instead of deprecated child-src + upgradeInsecureRequests: true + }, + (CONFIG.SERVICES['CSP-LOGGER'] != null) ? { reportUri: CONFIG.SERVICES['CSP-LOGGER'] } : {} +) + +const baseCSP = helmet.contentSecurityPolicy({ + directives: baseDirectives, + browserSniff: false, + reportOnly: true +}) + +const embedCSP = helmet.contentSecurityPolicy({ + directives: Object.assign(baseDirectives, { + frameAncestors: ['*'] + }), + browserSniff: false, // assumes a modern browser, but allows CDN in front + reportOnly: true +}) + +// --------------------------------------------------------------------------- + +export { + baseCSP, + embedCSP +} diff --git a/server/middlewares/dnt.ts b/server/middlewares/dnt.ts index cabad39c6..607def855 100644 --- a/server/middlewares/dnt.ts +++ b/server/middlewares/dnt.ts @@ -10,4 +10,4 @@ const advertiseDoNotTrack = (_, res, next) => { export { advertiseDoNotTrack - } +} diff --git a/server/middlewares/index.ts b/server/middlewares/index.ts index 0cef26953..b758a8586 100644 --- a/server/middlewares/index.ts +++ b/server/middlewares/index.ts @@ -6,3 +6,5 @@ export * from './pagination' export * from './servers' export * from './sort' export * from './user-right' +export * from './dnt' +export * from './csp' -- cgit v1.2.3 From 8fc58cb580994efe8f5167739568afadfe9850d7 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 17 Dec 2018 09:42:28 +0100 Subject: Fix CSP on dev mode --- server/middlewares/csp.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts index a0ed3710b..8b919af0d 100644 --- a/server/middlewares/csp.ts +++ b/server/middlewares/csp.ts @@ -8,19 +8,18 @@ const baseDirectives = Object.assign({}, mediaSrc: ["'self'", 'https:', 'blob:'], fontSrc: ["'self'", 'data:'], imgSrc: ["'self'", 'data:'], - scriptSrc: ["'self' 'unsafe-inline'"], + scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'"], styleSrc: ["'self' 'unsafe-inline'"], - // objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it + objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it formAction: ["'self'"], frameAncestors: ["'none'"], baseUri: ["'self'"], - pluginTypes: ["'none'"], manifestSrc: ["'self'"], frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed - workerSrc: ["'self'"], // instead of deprecated child-src - upgradeInsecureRequests: true + workerSrc: ["'self'"] // instead of deprecated child-src }, - (CONFIG.SERVICES['CSP-LOGGER'] != null) ? { reportUri: CONFIG.SERVICES['CSP-LOGGER'] } : {} + CONFIG.SERVICES['CSP-LOGGER'] ? { reportUri: CONFIG.SERVICES['CSP-LOGGER'] } : {}, + CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} ) const baseCSP = helmet.contentSecurityPolicy({ -- cgit v1.2.3 From 8b9a525a180cc9f3a98c334cc052dcfc8f36dcd4 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 17 Dec 2018 15:52:38 +0100 Subject: Add history on server side Add ability to disable, clear and list user videos history --- server/middlewares/validators/index.ts | 1 + server/middlewares/validators/user-history.ts | 30 ++++++++++++++++++++++ .../middlewares/validators/videos/video-watch.ts | 7 +++++ 3 files changed, 38 insertions(+) create mode 100644 server/middlewares/validators/user-history.ts (limited to 'server/middlewares') diff --git a/server/middlewares/validators/index.ts b/server/middlewares/validators/index.ts index 46c7f0f3a..65dd00335 100644 --- a/server/middlewares/validators/index.ts +++ b/server/middlewares/validators/index.ts @@ -12,3 +12,4 @@ export * from './videos' export * from './webfinger' export * from './search' export * from './server' +export * from './user-history' diff --git a/server/middlewares/validators/user-history.ts b/server/middlewares/validators/user-history.ts new file mode 100644 index 000000000..3c8971ea1 --- /dev/null +++ b/server/middlewares/validators/user-history.ts @@ -0,0 +1,30 @@ +import * as express from 'express' +import 'express-validator' +import { body, param, query } from 'express-validator/check' +import { logger } from '../../helpers/logger' +import { areValidationErrors } from './utils' +import { ActorFollowModel } from '../../models/activitypub/actor-follow' +import { areValidActorHandles, isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' +import { UserModel } from '../../models/account/user' +import { CONFIG } from '../../initializers' +import { isDateValid, toArray } from '../../helpers/custom-validators/misc' + +const userHistoryRemoveValidator = [ + body('beforeDate') + .optional() + .custom(isDateValid).withMessage('Should have a valid before date'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking userHistoryRemoveValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + + return next() + } +] + +// --------------------------------------------------------------------------- + +export { + userHistoryRemoveValidator +} diff --git a/server/middlewares/validators/videos/video-watch.ts b/server/middlewares/validators/videos/video-watch.ts index bca64662f..c38ad8a10 100644 --- a/server/middlewares/validators/videos/video-watch.ts +++ b/server/middlewares/validators/videos/video-watch.ts @@ -4,6 +4,7 @@ import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' import { isVideoExist } from '../../../helpers/custom-validators/videos' import { areValidationErrors } from '../utils' import { logger } from '../../../helpers/logger' +import { UserModel } from '../../../models/account/user' const videoWatchingValidator = [ param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), @@ -17,6 +18,12 @@ const videoWatchingValidator = [ if (areValidationErrors(req, res)) return if (!await isVideoExist(req.params.videoId, res, 'id')) return + const user = res.locals.oauth.token.User as UserModel + if (user.videosHistoryEnabled === false) { + logger.warn('Cannot set videos to watch by user %d: videos history is disabled.', user.id) + return res.status(409).end() + } + return next() } ] -- cgit v1.2.3 From 1a12adcd1e938a405e5caeaaaf5711f197cc6cf4 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 18 Dec 2018 17:18:25 +0100 Subject: Fix users update me param validation --- server/middlewares/validators/users.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index ccaf2eeb6..1bb0bfb1b 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts @@ -5,15 +5,16 @@ import { body, param } from 'express-validator/check' import { omit } from 'lodash' import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' import { - isUserAutoPlayVideoValid, isUserBlockedReasonValid, + isUserAutoPlayVideoValid, + isUserBlockedReasonValid, isUserDescriptionValid, isUserDisplayNameValid, isUserNSFWPolicyValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid, - isUserVideoQuotaValid, - isUserVideoQuotaDailyValid + isUserVideoQuotaDailyValid, + isUserVideoQuotaValid, isUserVideosHistoryEnabledValid } from '../../helpers/custom-validators/users' import { isVideoExist } from '../../helpers/custom-validators/videos' import { logger } from '../../helpers/logger' @@ -22,7 +23,6 @@ import { Redis } from '../../lib/redis' import { UserModel } from '../../models/account/user' import { areValidationErrors } from './utils' import { ActorModel } from '../../models/activitypub/actor' -import { comparePassword } from '../../helpers/peertube-crypto' const usersAddValidator = [ body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), @@ -144,6 +144,9 @@ const usersUpdateMeValidator = [ body('email').optional().isEmail().withMessage('Should have a valid email attribute'), body('nsfwPolicy').optional().custom(isUserNSFWPolicyValid).withMessage('Should have a valid display Not Safe For Work policy'), body('autoPlayVideo').optional().custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'), + body('videosHistoryEnabled') + .optional() + .custom(isUserVideosHistoryEnabledValid).withMessage('Should have a valid videos history enabled attribute'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') }) -- cgit v1.2.3 From cef534ed53e4518fe0acf581bfe880788d42fc36 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 26 Dec 2018 10:36:24 +0100 Subject: Add user notification base code --- server/middlewares/oauth.ts | 22 +++++++++++ server/middlewares/validators/sort.ts | 5 ++- server/middlewares/validators/user-history.ts | 8 +--- .../middlewares/validators/user-notifications.ts | 46 ++++++++++++++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 server/middlewares/validators/user-notifications.ts (limited to 'server/middlewares') diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 8c1df2c3e..1d193d467 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts @@ -3,6 +3,8 @@ import * as OAuthServer from 'express-oauth-server' import 'express-validator' import { OAUTH_LIFETIME } from '../initializers' import { logger } from '../helpers/logger' +import { Socket } from 'socket.io' +import { getAccessToken } from '../lib/oauth-model' const oAuthServer = new OAuthServer({ useErrorHandler: true, @@ -28,6 +30,25 @@ function authenticate (req: express.Request, res: express.Response, next: expres }) } +function authenticateSocket (socket: Socket, next: (err?: any) => void) { + const accessToken = socket.handshake.query.accessToken + + logger.debug('Checking socket access token %s.', accessToken) + + getAccessToken(accessToken) + .then(tokenDB => { + const now = new Date() + + if (!tokenDB || tokenDB.accessTokenExpiresAt < now || tokenDB.refreshTokenExpiresAt < now) { + return next(new Error('Invalid access token.')) + } + + socket.handshake.query.user = tokenDB.User + + return next() + }) +} + function authenticatePromiseIfNeeded (req: express.Request, res: express.Response) { return new Promise(resolve => { // Already authenticated? (or tried to) @@ -68,6 +89,7 @@ function token (req: express.Request, res: express.Response, next: express.NextF export { authenticate, + authenticateSocket, authenticatePromiseIfNeeded, optionalAuthenticate, token diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index 4c0577d8f..5ceda845f 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts @@ -18,6 +18,7 @@ const SORTABLE_FOLLOWING_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.FOLLOW const SORTABLE_USER_SUBSCRIPTIONS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USER_SUBSCRIPTIONS) const SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.ACCOUNTS_BLOCKLIST) const SORTABLE_SERVERS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.SERVERS_BLOCKLIST) +const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USER_NOTIFICATIONS) const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) @@ -35,6 +36,7 @@ const followingSortValidator = checkSort(SORTABLE_FOLLOWING_COLUMNS) const userSubscriptionsSortValidator = checkSort(SORTABLE_USER_SUBSCRIPTIONS_COLUMNS) const accountsBlocklistSortValidator = checkSort(SORTABLE_ACCOUNTS_BLOCKLIST_COLUMNS) const serversBlocklistSortValidator = checkSort(SORTABLE_SERVERS_BLOCKLIST_COLUMNS) +const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COLUMNS) // --------------------------------------------------------------------------- @@ -54,5 +56,6 @@ export { userSubscriptionsSortValidator, videoChannelsSearchSortValidator, accountsBlocklistSortValidator, - serversBlocklistSortValidator + serversBlocklistSortValidator, + userNotificationsSortValidator } diff --git a/server/middlewares/validators/user-history.ts b/server/middlewares/validators/user-history.ts index 3c8971ea1..418313d09 100644 --- a/server/middlewares/validators/user-history.ts +++ b/server/middlewares/validators/user-history.ts @@ -1,13 +1,9 @@ import * as express from 'express' import 'express-validator' -import { body, param, query } from 'express-validator/check' +import { body } from 'express-validator/check' import { logger } from '../../helpers/logger' import { areValidationErrors } from './utils' -import { ActorFollowModel } from '../../models/activitypub/actor-follow' -import { areValidActorHandles, isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' -import { UserModel } from '../../models/account/user' -import { CONFIG } from '../../initializers' -import { isDateValid, toArray } from '../../helpers/custom-validators/misc' +import { isDateValid } from '../../helpers/custom-validators/misc' const userHistoryRemoveValidator = [ body('beforeDate') diff --git a/server/middlewares/validators/user-notifications.ts b/server/middlewares/validators/user-notifications.ts new file mode 100644 index 000000000..8202f307e --- /dev/null +++ b/server/middlewares/validators/user-notifications.ts @@ -0,0 +1,46 @@ +import * as express from 'express' +import 'express-validator' +import { body } from 'express-validator/check' +import { logger } from '../../helpers/logger' +import { areValidationErrors } from './utils' +import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' +import { isIntArray } from '../../helpers/custom-validators/misc' + +const updateNotificationSettingsValidator = [ + body('newVideoFromSubscription') + .custom(isUserNotificationSettingValid).withMessage('Should have a valid new video from subscription notification setting'), + body('newCommentOnMyVideo') + .custom(isUserNotificationSettingValid).withMessage('Should have a valid new comment on my video notification setting'), + body('videoAbuseAsModerator') + .custom(isUserNotificationSettingValid).withMessage('Should have a valid new video abuse as moderator notification setting'), + body('blacklistOnMyVideo') + .custom(isUserNotificationSettingValid).withMessage('Should have a valid new blacklist on my video notification setting'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking updateNotificationSettingsValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + + return next() + } +] + +const markAsReadUserNotificationsValidator = [ + body('ids') + .custom(isIntArray).withMessage('Should have a valid notification ids to mark as read'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking markAsReadUserNotificationsValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + + return next() + } +] + +// --------------------------------------------------------------------------- + +export { + updateNotificationSettingsValidator, + markAsReadUserNotificationsValidator +} -- cgit v1.2.3 From dc13348070d808d0ba3feb56a435b835c2e7e791 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 2 Jan 2019 16:37:43 +0100 Subject: Add import finished and video published notifs --- server/middlewares/validators/user-notifications.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/user-notifications.ts b/server/middlewares/validators/user-notifications.ts index 8202f307e..1c31f0a73 100644 --- a/server/middlewares/validators/user-notifications.ts +++ b/server/middlewares/validators/user-notifications.ts @@ -1,11 +1,26 @@ import * as express from 'express' import 'express-validator' -import { body } from 'express-validator/check' +import { body, query } from 'express-validator/check' import { logger } from '../../helpers/logger' import { areValidationErrors } from './utils' import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' import { isIntArray } from '../../helpers/custom-validators/misc' +const listUserNotificationsValidator = [ + query('unread') + .optional() + .toBoolean() + .isBoolean().withMessage('Should have a valid unread boolean'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking listUserNotificationsValidator parameters', { parameters: req.query }) + + if (areValidationErrors(req, res)) return + + return next() + } +] + const updateNotificationSettingsValidator = [ body('newVideoFromSubscription') .custom(isUserNotificationSettingValid).withMessage('Should have a valid new video from subscription notification setting'), @@ -41,6 +56,7 @@ const markAsReadUserNotificationsValidator = [ // --------------------------------------------------------------------------- export { + listUserNotificationsValidator, updateNotificationSettingsValidator, markAsReadUserNotificationsValidator } -- cgit v1.2.3 From 2f1548fda32c3ba9e53913270394eedfacd55986 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 8 Jan 2019 11:26:41 +0100 Subject: Add notifications in the client --- server/middlewares/validators/user-notifications.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/user-notifications.ts b/server/middlewares/validators/user-notifications.ts index 1c31f0a73..46486e081 100644 --- a/server/middlewares/validators/user-notifications.ts +++ b/server/middlewares/validators/user-notifications.ts @@ -4,7 +4,7 @@ import { body, query } from 'express-validator/check' import { logger } from '../../helpers/logger' import { areValidationErrors } from './utils' import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' -import { isIntArray } from '../../helpers/custom-validators/misc' +import { isNotEmptyIntArray } from '../../helpers/custom-validators/misc' const listUserNotificationsValidator = [ query('unread') @@ -42,7 +42,8 @@ const updateNotificationSettingsValidator = [ const markAsReadUserNotificationsValidator = [ body('ids') - .custom(isIntArray).withMessage('Should have a valid notification ids to mark as read'), + .optional() + .custom(isNotEmptyIntArray).withMessage('Should have a valid notification ids to mark as read'), (req: express.Request, res: express.Response, next: express.NextFunction) => { logger.debug('Checking markAsReadUserNotificationsValidator parameters', { parameters: req.body }) -- cgit v1.2.3 From a4101923e699e49ceb9ff36e971c75417fafc9f0 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 9 Jan 2019 15:14:29 +0100 Subject: Implement contact form on server side --- server/middlewares/validators/config.ts | 19 +++++++++++-- server/middlewares/validators/server.ts | 49 +++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 4 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index f3f257d57..90108fa82 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts @@ -1,29 +1,44 @@ import * as express from 'express' import { body } from 'express-validator/check' -import { isUserNSFWPolicyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users' +import { isUserNSFWPolicyValid, isUserVideoQuotaValid, isUserVideoQuotaDailyValid } from '../../helpers/custom-validators/users' import { logger } from '../../helpers/logger' import { areValidationErrors } from './utils' const customConfigUpdateValidator = [ body('instance.name').exists().withMessage('Should have a valid instance name'), + body('instance.shortDescription').exists().withMessage('Should have a valid instance short description'), body('instance.description').exists().withMessage('Should have a valid instance description'), body('instance.terms').exists().withMessage('Should have a valid instance terms'), body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'), body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid).withMessage('Should have a valid NSFW policy'), body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'), body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'), - body('cache.previews.size').isInt().withMessage('Should have a valid previews size'), + + body('services.twitter.username').exists().withMessage('Should have a valid twitter username'), + body('services.twitter.whitelisted').isBoolean().withMessage('Should have a valid twitter whitelisted boolean'), + + body('cache.previews.size').isInt().withMessage('Should have a valid previews cache size'), + body('cache.captions.size').isInt().withMessage('Should have a valid captions cache size'), + body('signup.enabled').isBoolean().withMessage('Should have a valid signup enabled boolean'), body('signup.limit').isInt().withMessage('Should have a valid signup limit'), + body('signup.requiresEmailVerification').isBoolean().withMessage('Should have a valid requiresEmailVerification boolean'), + body('admin.email').isEmail().withMessage('Should have a valid administrator email'), + body('contactForm.enabled').isBoolean().withMessage('Should have a valid contact form enabled boolean'), + body('user.videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid video quota'), + body('user.videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily video quota'), + body('transcoding.enabled').isBoolean().withMessage('Should have a valid transcoding enabled boolean'), + body('transcoding.allowAdditionalExtensions').isBoolean().withMessage('Should have a valid additional extensions boolean'), body('transcoding.threads').isInt().withMessage('Should have a valid transcoding threads number'), body('transcoding.resolutions.240p').isBoolean().withMessage('Should have a valid transcoding 240p resolution enabled boolean'), body('transcoding.resolutions.360p').isBoolean().withMessage('Should have a valid transcoding 360p resolution enabled boolean'), body('transcoding.resolutions.480p').isBoolean().withMessage('Should have a valid transcoding 480p resolution enabled boolean'), body('transcoding.resolutions.720p').isBoolean().withMessage('Should have a valid transcoding 720p resolution enabled boolean'), body('transcoding.resolutions.1080p').isBoolean().withMessage('Should have a valid transcoding 1080p resolution enabled boolean'), + body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), body('import.videos.torrent.enabled').isBoolean().withMessage('Should have a valid import video torrent enabled boolean'), diff --git a/server/middlewares/validators/server.ts b/server/middlewares/validators/server.ts index a491dfeb3..d82e19230 100644 --- a/server/middlewares/validators/server.ts +++ b/server/middlewares/validators/server.ts @@ -1,9 +1,13 @@ import * as express from 'express' import { logger } from '../../helpers/logger' import { areValidationErrors } from './utils' -import { isHostValid } from '../../helpers/custom-validators/servers' +import { isHostValid, isValidContactBody } from '../../helpers/custom-validators/servers' import { ServerModel } from '../../models/server/server' import { body } from 'express-validator/check' +import { isUserDisplayNameValid } from '../../helpers/custom-validators/users' +import { Emailer } from '../../lib/emailer' +import { Redis } from '../../lib/redis' +import { CONFIG } from '../../initializers/constants' const serverGetValidator = [ body('host').custom(isHostValid).withMessage('Should have a valid host'), @@ -26,8 +30,49 @@ const serverGetValidator = [ } ] +const contactAdministratorValidator = [ + body('fromName') + .custom(isUserDisplayNameValid).withMessage('Should have a valid name'), + body('fromEmail') + .isEmail().withMessage('Should have a valid email'), + body('body') + .custom(isValidContactBody).withMessage('Should have a valid body'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking contactAdministratorValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + + if (CONFIG.CONTACT_FORM.ENABLED === false) { + return res + .status(409) + .send({ error: 'Contact form is not enabled on this instance.' }) + .end() + } + + if (Emailer.Instance.isEnabled() === false) { + return res + .status(409) + .send({ error: 'Emailer is not enabled on this instance.' }) + .end() + } + + if (await Redis.Instance.isContactFormIpExists(req.ip)) { + logger.info('Refusing a contact form by %s: already sent one recently.', req.ip) + + return res + .status(403) + .send({ error: 'You already sent a contact form recently.' }) + .end() + } + + return next() + } +] + // --------------------------------------------------------------------------- export { - serverGetValidator + serverGetValidator, + contactAdministratorValidator } -- cgit v1.2.3 From d3e56c0c4b307c99e83fbafb7f2c5884cbc20055 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 10 Jan 2019 11:12:41 +0100 Subject: Implement contact form in the client --- server/middlewares/validators/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/server.ts b/server/middlewares/validators/server.ts index d82e19230..d85afc2ff 100644 --- a/server/middlewares/validators/server.ts +++ b/server/middlewares/validators/server.ts @@ -50,7 +50,7 @@ const contactAdministratorValidator = [ .end() } - if (Emailer.Instance.isEnabled() === false) { + if (Emailer.isEnabled() === false) { return res .status(409) .send({ error: 'Emailer is not enabled on this instance.' }) -- cgit v1.2.3 From 5abb9fbbd12e7097e348d6a38622d364b1fa47ed Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 10 Jan 2019 15:39:51 +0100 Subject: Add ability to unfederate a local video (on blacklist) --- server/middlewares/validators/videos/video-blacklist.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/videos/video-blacklist.ts b/server/middlewares/validators/videos/video-blacklist.ts index 13da7acff..2688f63ae 100644 --- a/server/middlewares/validators/videos/video-blacklist.ts +++ b/server/middlewares/validators/videos/video-blacklist.ts @@ -1,10 +1,11 @@ import * as express from 'express' import { body, param } from 'express-validator/check' -import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' +import { isBooleanValid, isIdOrUUIDValid } from '../../../helpers/custom-validators/misc' import { isVideoExist } from '../../../helpers/custom-validators/videos' import { logger } from '../../../helpers/logger' import { areValidationErrors } from '../utils' import { isVideoBlacklistExist, isVideoBlacklistReasonValid } from '../../../helpers/custom-validators/video-blacklist' +import { VideoModel } from '../../../models/video/video' const videosBlacklistRemoveValidator = [ param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), @@ -22,6 +23,10 @@ const videosBlacklistRemoveValidator = [ const videosBlacklistAddValidator = [ param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), + body('unfederate') + .optional() + .toBoolean() + .custom(isBooleanValid).withMessage('Should have a valid unfederate boolean'), body('reason') .optional() .custom(isVideoBlacklistReasonValid).withMessage('Should have a valid reason'), @@ -32,6 +37,14 @@ const videosBlacklistAddValidator = [ if (areValidationErrors(req, res)) return if (!await isVideoExist(req.params.videoId, res)) return + const video: VideoModel = res.locals.video + if (req.body.unfederate === true && video.remote === true) { + return res + .status(409) + .send({ error: 'You cannot unfederate a remote video.' }) + .end() + } + return next() } ] -- cgit v1.2.3 From 2adfc7ea9a1f858db874df9fe322e7ae833db77c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 23 Jan 2019 15:36:45 +0100 Subject: Refractor videojs player Add fake p2p-media-loader plugin --- server/middlewares/csp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'server/middlewares') diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts index 8b919af0d..5fa9d1ab5 100644 --- a/server/middlewares/csp.ts +++ b/server/middlewares/csp.ts @@ -16,7 +16,7 @@ const baseDirectives = Object.assign({}, baseUri: ["'self'"], manifestSrc: ["'self'"], frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed - workerSrc: ["'self'"] // instead of deprecated child-src + workerSrc: ["'self'", 'blob:'] // instead of deprecated child-src }, CONFIG.SERVICES['CSP-LOGGER'] ? { reportUri: CONFIG.SERVICES['CSP-LOGGER'] } : {}, CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} -- cgit v1.2.3 From 092092969633bbcf6d4891a083ea497a7d5c3154 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 29 Jan 2019 08:37:25 +0100 Subject: Add hls support on server --- server/middlewares/validators/redundancy.ts | 33 +++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/redundancy.ts b/server/middlewares/validators/redundancy.ts index c72ab78b2..329322509 100644 --- a/server/middlewares/validators/redundancy.ts +++ b/server/middlewares/validators/redundancy.ts @@ -13,7 +13,7 @@ import { ActorFollowModel } from '../../models/activitypub/actor-follow' import { SERVER_ACTOR_NAME } from '../../initializers' import { ServerModel } from '../../models/server/server' -const videoRedundancyGetValidator = [ +const videoFileRedundancyGetValidator = [ param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), param('resolution') .customSanitizer(toIntOrNull) @@ -24,7 +24,7 @@ const videoRedundancyGetValidator = [ .custom(exists).withMessage('Should have a valid fps'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking videoRedundancyGetValidator parameters', { parameters: req.params }) + logger.debug('Checking videoFileRedundancyGetValidator parameters', { parameters: req.params }) if (areValidationErrors(req, res)) return if (!await isVideoExist(req.params.videoId, res)) return @@ -38,7 +38,31 @@ const videoRedundancyGetValidator = [ res.locals.videoFile = videoFile const videoRedundancy = await VideoRedundancyModel.loadLocalByFileId(videoFile.id) - if (!videoRedundancy)return res.status(404).json({ error: 'Video redundancy not found.' }) + if (!videoRedundancy) return res.status(404).json({ error: 'Video redundancy not found.' }) + res.locals.videoRedundancy = videoRedundancy + + return next() + } +] + +const videoPlaylistRedundancyGetValidator = [ + param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), + param('streamingPlaylistType').custom(exists).withMessage('Should have a valid streaming playlist type'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking videoPlaylistRedundancyGetValidator parameters', { parameters: req.params }) + + if (areValidationErrors(req, res)) return + if (!await isVideoExist(req.params.videoId, res)) return + + const video: VideoModel = res.locals.video + const videoStreamingPlaylist = video.VideoStreamingPlaylists.find(p => p === req.params.streamingPlaylistType) + + if (!videoStreamingPlaylist) return res.status(404).json({ error: 'Video playlist not found.' }) + res.locals.videoStreamingPlaylist = videoStreamingPlaylist + + const videoRedundancy = await VideoRedundancyModel.loadLocalByStreamingPlaylistId(videoStreamingPlaylist.id) + if (!videoRedundancy) return res.status(404).json({ error: 'Video redundancy not found.' }) res.locals.videoRedundancy = videoRedundancy return next() @@ -75,6 +99,7 @@ const updateServerRedundancyValidator = [ // --------------------------------------------------------------------------- export { - videoRedundancyGetValidator, + videoFileRedundancyGetValidator, + videoPlaylistRedundancyGetValidator, updateServerRedundancyValidator } -- cgit v1.2.3 From b426edd4854adc6e65844d8c54b8998e792b5778 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 11 Feb 2019 09:30:29 +0100 Subject: Cleanup reset user password by admin And add some tests --- server/middlewares/validators/users.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'server/middlewares') diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 1bb0bfb1b..a52e3060a 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts @@ -113,6 +113,7 @@ const deleteMeValidator = [ const usersUpdateValidator = [ param('id').isInt().not().isEmpty().withMessage('Should have a valid id'), + body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'), body('email').optional().isEmail().withMessage('Should have a valid email attribute'), body('emailVerified').optional().isBoolean().withMessage('Should have a valid email verified attribute'), body('videoQuota').optional().custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), @@ -233,6 +234,7 @@ const usersAskResetPasswordValidator = [ logger.debug('Checking usersAskResetPassword parameters', { parameters: req.body }) if (areValidationErrors(req, res)) return + const exists = await checkUserEmailExist(req.body.email, res, false) if (!exists) { logger.debug('User with email %s does not exist (asking reset password).', req.body.email) -- cgit v1.2.3