1
0
Fork 1
mirror of https://example.com synced 2024-11-22 11:56:38 +09:00

feat: accept more signature algorithms

enhances 8890902675

Co-authored-by: naskya <m@naskya.net>
This commit is contained in:
MeiMei 2024-01-07 19:53:07 +09:00 committed by naskya
parent 1ccf256b99
commit 85d5e7bd3b
Signed by: naskya
GPG key ID: 712D413B3A9FED5C
3 changed files with 74 additions and 23 deletions

View file

@ -40,6 +40,7 @@
## 細かい変更点
- 署名アルゴリズムとして ECDSA や Ed25519 なども受け入れる([github.com/mei23/misskey-v12](https://github.com/mei23/misskey-v12) から取り込み)
- Pleroma のチャットに対応Catodon から取り込み)
- 翻訳機能にて、投稿言語が指定されていない場合にのみ言語の自動検出を用いるように変更
- アップデート時に更新内容を確認できる機能を追加

View file

@ -10,8 +10,6 @@ import type { IncomingMessage } from "http";
import type { CacheableRemoteUser } from "@/models/entities/user.js";
import type { UserPublickey } from "@/models/entities/user-publickey.js";
import { verify } from "node:crypto";
import { toSingle } from "@/prelude/array.js";
import { createHash } from "node:crypto";
export async function hasSignature(req: IncomingMessage): Promise<string> {
const meta = await fetchMeta();
@ -158,20 +156,3 @@ export function verifySignature(
return false;
}
}
export function verifyDigest(
body: string,
digest: string | string[] | undefined,
): boolean {
digest = toSingle(digest);
if (
body == null ||
digest == null ||
!digest.toLowerCase().startsWith("sha-256=")
)
return false;
return (
createHash("sha256").update(body).digest("base64") === digest.substring(8)
);
}

View file

@ -23,7 +23,6 @@ import { getUserKeypair } from "@/misc/keypair-store.js";
import {
checkFetch,
getSignatureUser,
verifyDigest,
} from "@/remote/activitypub/check-fetch.js";
import { getInstanceActor } from "@/services/instance-actor.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
@ -35,6 +34,9 @@ import Outbox, { packActivity } from "./activitypub/outbox.js";
import { serverLogger } from "./index.js";
import config from "@/config/index.js";
import Koa from "koa";
import * as crypto from "node:crypto";
import { inspect } from "node:util";
import type { IActivity } from "@/remote/activitypub/type.js";
// Init router
const router = new Router();
@ -43,27 +45,94 @@ const router = new Router();
function inbox(ctx: Router.RouterContext) {
if (ctx.req.headers.host !== config.host) {
serverLogger.warn("inbox: Invalid Host");
ctx.status = 400;
ctx.message = "Invalid Host";
return;
}
let signature;
let signature: httpSignature.IParsedSignature;
try {
signature = httpSignature.parseRequest(ctx.req, {
headers: ["(request-target)", "digest", "host", "date"],
});
} catch (e) {
serverLogger.warn(`inbox: signature parse error: ${inspect(e)}`);
ctx.status = 401;
if (e instanceof Error) {
if (e.name === "ExpiredRequestError")
ctx.message = "Expired Request Error";
if (e.name === "MissingHeaderError")
ctx.message = "Missing Required Header";
}
return;
}
if (!verifyDigest(ctx.request.rawBody, ctx.headers.digest)) {
// Validate signature algorithm
if (
!signature.algorithm
.toLowerCase()
.match(/^((dsa|rsa|ecdsa)-(sha256|sha384|sha512)|ed25519-sha512|hs2019)$/)
) {
serverLogger.warn(
`inbox: invalid signature algorithm ${signature.algorithm}`,
);
ctx.status = 401;
ctx.message = "Invalid Signature Algorithm";
return;
// hs2019
// keyType=ED25519 => ed25519-sha512
// keyType=other => (keyType)-sha256
}
// Validate digest header
const digest = ctx.req.headers.digest;
if (typeof digest !== "string") {
serverLogger.warn(
"inbox: zero or more than one digest header(s) are present",
);
ctx.status = 401;
ctx.message = "Invalid Digest Header";
return;
}
processInbox(ctx.request.body, signature);
const match = digest.match(/^([0-9A-Za-z-]+)=(.+)$/);
if (match == null) {
serverLogger.warn("inbox: unrecognized digest header");
ctx.status = 401;
ctx.message = "Invalid Digest Header";
return;
}
const digestAlgo = match[1];
const expectedDigest = match[2];
if (digestAlgo.toUpperCase() !== "SHA-256") {
serverLogger.warn("inbox: unsupported digest algorithm");
ctx.status = 401;
ctx.message = "Unsupported Digest Algorithm";
return;
}
const actualDigest = crypto
.createHash("sha256")
.update(ctx.request.rawBody)
.digest("base64");
if (expectedDigest !== actualDigest) {
serverLogger.warn("inbox: Digest Mismatch");
ctx.status = 401;
ctx.message = "Digest Missmatch";
return;
}
processInbox(ctx.request.body as IActivity, signature);
ctx.status = 202;
}