Skip to content

Commit

Permalink
validate signed headers (#2497)
Browse files Browse the repository at this point in the history
* validate signed headers

* リクエストホスト

Co-authored-by: perillamint <[email protected]>
Co-authored-by: yunochi <[email protected]>
Co-authored-by: Laura Hausmann <[email protected]>
  • Loading branch information
4 people authored Nov 27, 2023
1 parent 39cc374 commit 5e385d5
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 42 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"cbor": "8.1.0",
"chalk": "4.1.2",
"cli-highlight": "2.1.11",
"co-body": "6.1.0",
"content-disposition": "0.5.4",
"crc-32": "1.2.2",
"cropperjs": "1.5.13",
Expand Down Expand Up @@ -101,7 +102,6 @@
"koa": "2.13.4",
"koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0",
"koa-json-body": "5.3.0",
"koa-logger": "3.2.1",
"koa-mount": "4.0.0",
"koa-send": "5.0.1",
Expand Down Expand Up @@ -201,6 +201,7 @@
"@types/bcryptjs": "2.4.2",
"@types/bull": "4.10.0",
"@types/cbor": "6.0.0",
"@types/co-body": "6.1.3",
"@types/dateformat": "3.0.1",
"@types/double-ended-queue": "2.1.2",
"@types/escape-regexp": "0.0.1",
Expand Down
32 changes: 13 additions & 19 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 0 additions & 15 deletions src/@types/koa-json-body.d.ts

This file was deleted.

69 changes: 62 additions & 7 deletions src/server/activitypub.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import * as Router from '@koa/router';
import * as json from 'koa-json-body';
import config from '../config';
import * as coBody from 'co-body';
import * as crypto from 'crypto';
import { IActivity } from '../remote/activitypub/type';
import * as httpSignature from 'http-signature';
import Logger from '../services/logger';
import { inspect } from 'util';

import { renderActivity } from '../remote/activitypub/renderer';
import renderNote from '../remote/activitypub/renderer/note';
Expand All @@ -18,22 +23,72 @@ import { ILocalUser, User } from '../models/entities/user';
import { In } from 'typeorm';
import { ensure } from '../prelude/ensure';

const logger = new Logger('activitypub');

// Init router
const router = new Router();

//#region Routing

function inbox(ctx: Router.RouterContext) {
let signature;
async function inbox(ctx: Router.RouterContext) {
if (ctx.req.headers.host !== config.host) {
ctx.status = 400;
return;
}

// parse body
const { parsed, raw } = await coBody.json(ctx, {
limit: '64kb',
returnRawBody: true,
});
ctx.request.body = parsed;

let signature: httpSignature.IParsedSignature;

try {
signature = httpSignature.parseRequest(ctx.req, { 'headers': [] });
signature = httpSignature.parseRequest(ctx.req, { 'headers': ['(request-target)', 'digest', 'host', 'date'] });
} catch (e) {
logger.warn(`inbox: signature parse error: ${inspect(e)}`);
ctx.status = 401;
return;
}

// Digestヘッダーの検証
const digest = ctx.req.headers.digest;

// 無いとか複数あるとかダメ!
if (typeof digest !== 'string') {
logger.warn(`inbox: unrecognized digest header 1`);
ctx.status = 401;
return;
}

const match = digest.match(/^([0-9A-Za-z-]+)=(.+)$/);

if (match == null) {
logger.warn(`inbox: unrecognized digest header 2`);
ctx.status = 401;
return;
}

const digestAlgo = match[1];
const digestExpected = match[2];

if (digestAlgo.toUpperCase() !== 'SHA-256') {
logger.warn(`inbox: unsupported algorithm`);
ctx.status = 401;
return;
}

const digestActual = crypto.createHash('sha256').update(raw).digest('base64');

if (digestExpected !== digestActual) {
logger.warn(`inbox: digest missmatch`);
ctx.status = 401;
return;
}

processInbox(ctx.request.body, signature);
processInbox(ctx.request.body as IActivity, signature);

ctx.status = 202;
}
Expand All @@ -59,8 +114,8 @@ export function setResponseType(ctx: Router.RouterContext) {
}

// inbox
router.post('/inbox', json({ limit: '64kb' }), inbox);
router.post('/users/:user/inbox', json({ limit: '64kb' }), inbox);
router.post('/inbox', inbox);
router.post('/users/:user/inbox', inbox);

// note
router.get('/notes/:note', async (ctx, next) => {
Expand Down

0 comments on commit 5e385d5

Please sign in to comment.