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:
Julian Lam
2024-10-07 14:04:46 -04:00
parent 2b71434ef4
commit 8ef0df57e6
3 changed files with 30 additions and 11 deletions

View File

@@ -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

View File

@@ -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,
]; ];

View File

@@ -86,7 +86,7 @@ describe('Analytics', () => {
}, },
}, { sendStatus: () => {} }); }, { sendStatus: () => {} });
await middleware.activitypub.validate({ await middleware.activitypub.assertPayload({
body: { body: {
id, id,
type: 'Like', type: 'Like',