From e4f97babf701481b55cc10fb3448feab5f97c867 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 9 Nov 2017 17:51:58 +0100 Subject: Begin activitypub --- server/middlewares/activitypub.ts | 57 ++++++++++++++++++++ server/middlewares/index.ts | 2 +- server/middlewares/secure.ts | 55 ------------------- server/middlewares/validators/account.ts | 53 +++++++++++++++++++ server/middlewares/validators/activitypub/index.ts | 3 ++ server/middlewares/validators/activitypub/pods.ts | 38 ++++++++++++++ .../validators/activitypub/signature.ts | 30 +++++++++++ .../middlewares/validators/activitypub/videos.ts | 61 ++++++++++++++++++++++ server/middlewares/validators/index.ts | 3 +- server/middlewares/validators/remote/index.ts | 3 -- server/middlewares/validators/remote/pods.ts | 38 -------------- server/middlewares/validators/remote/signature.ts | 22 -------- server/middlewares/validators/remote/videos.ts | 61 ---------------------- 13 files changed, 245 insertions(+), 181 deletions(-) create mode 100644 server/middlewares/activitypub.ts delete mode 100644 server/middlewares/secure.ts create mode 100644 server/middlewares/validators/account.ts create mode 100644 server/middlewares/validators/activitypub/index.ts create mode 100644 server/middlewares/validators/activitypub/pods.ts create mode 100644 server/middlewares/validators/activitypub/signature.ts create mode 100644 server/middlewares/validators/activitypub/videos.ts delete mode 100644 server/middlewares/validators/remote/index.ts delete mode 100644 server/middlewares/validators/remote/pods.ts delete mode 100644 server/middlewares/validators/remote/signature.ts delete mode 100644 server/middlewares/validators/remote/videos.ts (limited to 'server/middlewares') diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts new file mode 100644 index 000000000..6cf8eea6f --- /dev/null +++ b/server/middlewares/activitypub.ts @@ -0,0 +1,57 @@ +import { Request, Response, NextFunction } from 'express' + +import { database as db } from '../initializers' +import { + logger, + getAccountFromWebfinger, + isSignatureVerified +} from '../helpers' +import { ActivityPubSignature } from '../../shared' + +async function checkSignature (req: Request, res: Response, next: NextFunction) { + const signatureObject: ActivityPubSignature = req.body.signature + + logger.debug('Checking signature of account %s...', signatureObject.creator) + + let account = await db.Account.loadByUrl(signatureObject.creator) + + // We don't have this account in our database, fetch it on remote + if (!account) { + account = await getAccountFromWebfinger(signatureObject.creator) + + if (!account) { + return res.sendStatus(403) + } + + // Save our new account in database + await account.save() + } + + const verified = await isSignatureVerified(account, req.body) + if (verified === false) return res.sendStatus(403) + + res.locals.signature.account = account + + return next() +} + +function executeIfActivityPub (fun: any | any[]) { + return (req: Request, res: Response, next: NextFunction) => { + if (req.header('Accept') !== 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"') { + return next() + } + + if (Array.isArray(fun) === true) { + fun[0](req, res, next) // FIXME: doesn't work + } + + return fun(req, res, next) + } +} + +// --------------------------------------------------------------------------- + +export { + checkSignature, + executeIfActivityPub +} diff --git a/server/middlewares/index.ts b/server/middlewares/index.ts index cec3e0b2a..40480450b 100644 --- a/server/middlewares/index.ts +++ b/server/middlewares/index.ts @@ -1,9 +1,9 @@ export * from './validators' +export * from './activitypub' export * from './async' export * from './oauth' export * from './pagination' export * from './pods' export * from './search' -export * from './secure' export * from './sort' export * from './user-right' diff --git a/server/middlewares/secure.ts b/server/middlewares/secure.ts deleted file mode 100644 index 5dd809f15..000000000 --- a/server/middlewares/secure.ts +++ /dev/null @@ -1,55 +0,0 @@ -import 'express-validator' -import * as express from 'express' - -import { database as db } from '../initializers' -import { - logger, - checkSignature as peertubeCryptoCheckSignature -} from '../helpers' -import { PodSignature } from '../../shared' - -async function checkSignature (req: express.Request, res: express.Response, next: express.NextFunction) { - const signatureObject: PodSignature = req.body.signature - const host = signatureObject.host - - try { - const pod = await db.Pod.loadByHost(host) - if (pod === null) { - logger.error('Unknown pod %s.', host) - return res.sendStatus(403) - } - - logger.debug('Checking signature from %s.', host) - - let signatureShouldBe - // If there is data in the body the sender used it for its signature - // If there is no data we just use its host as signature - if (req.body.data) { - signatureShouldBe = req.body.data - } else { - signatureShouldBe = host - } - - const signatureOk = peertubeCryptoCheckSignature(pod.publicKey, signatureShouldBe, signatureObject.signature) - - if (signatureOk === true) { - res.locals.secure = { - pod - } - - return next() - } - - logger.error('Signature is not okay in body for %s.', signatureObject.host) - return res.sendStatus(403) - } catch (err) { - logger.error('Cannot get signed host in body.', { error: err.stack, signature: signatureObject.signature }) - return res.sendStatus(500) - } -} - -// --------------------------------------------------------------------------- - -export { - checkSignature -} diff --git a/server/middlewares/validators/account.ts b/server/middlewares/validators/account.ts new file mode 100644 index 000000000..5abe942d6 --- /dev/null +++ b/server/middlewares/validators/account.ts @@ -0,0 +1,53 @@ +import { param } from 'express-validator/check' +import * as express from 'express' + +import { database as db } from '../../initializers/database' +import { checkErrors } from './utils' +import { + logger, + isUserUsernameValid, + isUserPasswordValid, + isUserVideoQuotaValid, + isUserDisplayNSFWValid, + isUserRoleValid, + isAccountNameValid +} from '../../helpers' +import { AccountInstance } from '../../models' + +const localAccountValidator = [ + param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking localAccountValidator parameters', { parameters: req.params }) + + checkErrors(req, res, () => { + checkLocalAccountExists(req.params.name, res, next) + }) + } +] + +// --------------------------------------------------------------------------- + +export { + localAccountValidator +} + +// --------------------------------------------------------------------------- + +function checkLocalAccountExists (name: string, res: express.Response, callback: (err: Error, account: AccountInstance) => void) { + db.Account.loadLocalAccountByName(name) + .then(account => { + if (!account) { + return res.status(404) + .send({ error: 'Account not found' }) + .end() + } + + res.locals.account = account + return callback(null, account) + }) + .catch(err => { + logger.error('Error in account request validator.', err) + return res.sendStatus(500) + }) +} diff --git a/server/middlewares/validators/activitypub/index.ts b/server/middlewares/validators/activitypub/index.ts new file mode 100644 index 000000000..f1f26043e --- /dev/null +++ b/server/middlewares/validators/activitypub/index.ts @@ -0,0 +1,3 @@ +export * from './pods' +export * from './signature' +export * from './videos' diff --git a/server/middlewares/validators/activitypub/pods.ts b/server/middlewares/validators/activitypub/pods.ts new file mode 100644 index 000000000..f917b61ee --- /dev/null +++ b/server/middlewares/validators/activitypub/pods.ts @@ -0,0 +1,38 @@ +import { body } from 'express-validator/check' +import * as express from 'express' + +import { database as db } from '../../../initializers' +import { isHostValid, logger } from '../../../helpers' +import { checkErrors } from '../utils' + +const remotePodsAddValidator = [ + body('host').custom(isHostValid).withMessage('Should have a host'), + body('email').isEmail().withMessage('Should have an email'), + body('publicKey').not().isEmpty().withMessage('Should have a public key'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking podsAdd parameters', { parameters: req.body }) + + checkErrors(req, res, () => { + db.Pod.loadByHost(req.body.host) + .then(pod => { + // Pod with this host already exists + if (pod) { + return res.sendStatus(409) + } + + return next() + }) + .catch(err => { + logger.error('Cannot load pod by host.', err) + res.sendStatus(500) + }) + }) + } +] + +// --------------------------------------------------------------------------- + +export { + remotePodsAddValidator +} diff --git a/server/middlewares/validators/activitypub/signature.ts b/server/middlewares/validators/activitypub/signature.ts new file mode 100644 index 000000000..0ce15c1f6 --- /dev/null +++ b/server/middlewares/validators/activitypub/signature.ts @@ -0,0 +1,30 @@ +import { body } from 'express-validator/check' +import * as express from 'express' + +import { + logger, + isDateValid, + isSignatureTypeValid, + isSignatureCreatorValid, + isSignatureValueValid +} from '../../../helpers' +import { checkErrors } 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'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking activitypub signature parameter', { parameters: { signature: req.body.signature } }) + + checkErrors(req, res, next) + } +] + +// --------------------------------------------------------------------------- + +export { + signatureValidator +} diff --git a/server/middlewares/validators/activitypub/videos.ts b/server/middlewares/validators/activitypub/videos.ts new file mode 100644 index 000000000..497320cc1 --- /dev/null +++ b/server/middlewares/validators/activitypub/videos.ts @@ -0,0 +1,61 @@ +import { body } from 'express-validator/check' +import * as express from 'express' + +import { + logger, + isArray, + removeBadRequestVideos, + removeBadRequestVideosQadu, + removeBadRequestVideosEvents +} from '../../../helpers' +import { checkErrors } from '../utils' + +const remoteVideosValidator = [ + body('data').custom(isArray), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking remoteVideos parameters', { parameters: req.body }) + + checkErrors(req, res, () => { + removeBadRequestVideos(req.body.data) + + return next() + }) + } +] + +const remoteQaduVideosValidator = [ + body('data').custom(isArray), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking remoteQaduVideos parameters', { parameters: req.body }) + + checkErrors(req, res, () => { + removeBadRequestVideosQadu(req.body.data) + + return next() + }) + } +] + +const remoteEventsVideosValidator = [ + body('data').custom(isArray), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking remoteEventsVideos parameters', { parameters: req.body }) + + checkErrors(req, res, () => { + removeBadRequestVideosEvents(req.body.data) + + return next() + }) + } +] + +// --------------------------------------------------------------------------- + +export { + remoteVideosValidator, + remoteQaduVideosValidator, + remoteEventsVideosValidator +} diff --git a/server/middlewares/validators/index.ts b/server/middlewares/validators/index.ts index 247f6039e..46c00d679 100644 --- a/server/middlewares/validators/index.ts +++ b/server/middlewares/validators/index.ts @@ -1,5 +1,6 @@ +export * from './account' export * from './oembed' -export * from './remote' +export * from './activitypub' export * from './pagination' export * from './pods' export * from './sort' diff --git a/server/middlewares/validators/remote/index.ts b/server/middlewares/validators/remote/index.ts deleted file mode 100644 index f1f26043e..000000000 --- a/server/middlewares/validators/remote/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './pods' -export * from './signature' -export * from './videos' diff --git a/server/middlewares/validators/remote/pods.ts b/server/middlewares/validators/remote/pods.ts deleted file mode 100644 index f917b61ee..000000000 --- a/server/middlewares/validators/remote/pods.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { body } from 'express-validator/check' -import * as express from 'express' - -import { database as db } from '../../../initializers' -import { isHostValid, logger } from '../../../helpers' -import { checkErrors } from '../utils' - -const remotePodsAddValidator = [ - body('host').custom(isHostValid).withMessage('Should have a host'), - body('email').isEmail().withMessage('Should have an email'), - body('publicKey').not().isEmpty().withMessage('Should have a public key'), - - (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking podsAdd parameters', { parameters: req.body }) - - checkErrors(req, res, () => { - db.Pod.loadByHost(req.body.host) - .then(pod => { - // Pod with this host already exists - if (pod) { - return res.sendStatus(409) - } - - return next() - }) - .catch(err => { - logger.error('Cannot load pod by host.', err) - res.sendStatus(500) - }) - }) - } -] - -// --------------------------------------------------------------------------- - -export { - remotePodsAddValidator -} diff --git a/server/middlewares/validators/remote/signature.ts b/server/middlewares/validators/remote/signature.ts deleted file mode 100644 index d3937b515..000000000 --- a/server/middlewares/validators/remote/signature.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { body } from 'express-validator/check' -import * as express from 'express' - -import { logger, isHostValid } from '../../../helpers' -import { checkErrors } from '../utils' - -const signatureValidator = [ - body('signature.host').custom(isHostValid).withMessage('Should have a signature host'), - body('signature.signature').not().isEmpty().withMessage('Should have a signature'), - - (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking signature parameters', { parameters: { signature: req.body.signature } }) - - checkErrors(req, res, next) - } -] - -// --------------------------------------------------------------------------- - -export { - signatureValidator -} diff --git a/server/middlewares/validators/remote/videos.ts b/server/middlewares/validators/remote/videos.ts deleted file mode 100644 index 497320cc1..000000000 --- a/server/middlewares/validators/remote/videos.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { body } from 'express-validator/check' -import * as express from 'express' - -import { - logger, - isArray, - removeBadRequestVideos, - removeBadRequestVideosQadu, - removeBadRequestVideosEvents -} from '../../../helpers' -import { checkErrors } from '../utils' - -const remoteVideosValidator = [ - body('data').custom(isArray), - - (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking remoteVideos parameters', { parameters: req.body }) - - checkErrors(req, res, () => { - removeBadRequestVideos(req.body.data) - - return next() - }) - } -] - -const remoteQaduVideosValidator = [ - body('data').custom(isArray), - - (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking remoteQaduVideos parameters', { parameters: req.body }) - - checkErrors(req, res, () => { - removeBadRequestVideosQadu(req.body.data) - - return next() - }) - } -] - -const remoteEventsVideosValidator = [ - body('data').custom(isArray), - - (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking remoteEventsVideos parameters', { parameters: req.body }) - - checkErrors(req, res, () => { - removeBadRequestVideosEvents(req.body.data) - - return next() - }) - } -] - -// --------------------------------------------------------------------------- - -export { - remoteVideosValidator, - remoteQaduVideosValidator, - remoteEventsVideosValidator -} -- cgit v1.2.3