mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 08:36:12 +01:00
refactor: check HTTP signatures on all activitypub requests
- `validate` is now renamed `assertPayload` - HTTP signature checking is now in new middleware `verify` - `verify` is now called on all routes in activitypub controller - Rejects on signature failure for POST requests
This commit is contained in:
@@ -28,7 +28,33 @@ middleware.assertS2S = async function (req, res, next) {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
middleware.validate = async function (req, res, next) {
|
middleware.verify = async function (req, res, next) {
|
||||||
|
// Verifies the HTTP Signature if present (required for POST)
|
||||||
|
const passthrough = [/\/actor/, /\/uid\/\d+/];
|
||||||
|
if (req.method === 'GET' && passthrough.some(regex => regex.test(req.path))) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const verified = await activitypub.verify(req);
|
||||||
|
if (!verified && req.method === 'POST') {
|
||||||
|
// winston.verbose('[middleware/activitypub] HTTP signature verification failed.');
|
||||||
|
return res.sendStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set calling user
|
||||||
|
if (req.headers.signature) {
|
||||||
|
const keyId = req.headers.signature.split(',').filter(line => line.startsWith('keyId="'));
|
||||||
|
if (keyId.length) {
|
||||||
|
req.uid = keyId.shift().slice(7, -1).replace(/#.*$/, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// winston.verbose('[middleware/activitypub] HTTP signature verification passed.');
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
middleware.assertPayload = async function (req, res, next) {
|
||||||
|
// Checks the validity of the incoming payload against the sender and rejects on failure
|
||||||
// winston.verbose('[middleware/activitypub] Validating incoming payload...');
|
// winston.verbose('[middleware/activitypub] Validating incoming payload...');
|
||||||
|
|
||||||
// Sanity-check payload schema
|
// Sanity-check payload schema
|
||||||
@@ -46,14 +72,6 @@ middleware.validate = async function (req, res, next) {
|
|||||||
return res.sendStatus(200);
|
return res.sendStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks the validity of the incoming payload against the sender and rejects on failure
|
|
||||||
const verified = await activitypub.verify(req);
|
|
||||||
if (!verified) {
|
|
||||||
// winston.verbose('[middleware/activitypub] HTTP signature verification failed.');
|
|
||||||
return res.sendStatus(400);
|
|
||||||
}
|
|
||||||
// winston.verbose('[middleware/activitypub] HTTP signature verification passed.');
|
|
||||||
|
|
||||||
let { actor, object } = req.body;
|
let { actor, object } = req.body;
|
||||||
|
|
||||||
// Actor normalization
|
// Actor normalization
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ module.exports = function (app, middleware, controllers) {
|
|||||||
const middlewares = [
|
const middlewares = [
|
||||||
middleware.activitypub.enabled,
|
middleware.activitypub.enabled,
|
||||||
middleware.activitypub.assertS2S,
|
middleware.activitypub.assertS2S,
|
||||||
|
middleware.activitypub.verify,
|
||||||
middleware.activitypub.configureResponse,
|
middleware.activitypub.configureResponse,
|
||||||
];
|
];
|
||||||
|
|
||||||
const inboxMiddlewares = [
|
const inboxMiddlewares = [
|
||||||
middleware.activitypub.validate,
|
middleware.activitypub.assertPayload,
|
||||||
middleware.activitypub.resolveObjects,
|
middleware.activitypub.resolveObjects,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ describe('Analytics', () => {
|
|||||||
},
|
},
|
||||||
}, { sendStatus: () => {} });
|
}, { sendStatus: () => {} });
|
||||||
|
|
||||||
await middleware.activitypub.validate({
|
await middleware.activitypub.assertPayload({
|
||||||
body: {
|
body: {
|
||||||
id,
|
id,
|
||||||
type: 'Like',
|
type: 'Like',
|
||||||
|
|||||||
Reference in New Issue
Block a user