Skip to content

Commit 8286028

Browse files
committed
draftがWeb Crypto APIで動作するように
0.0.0-alpha.15
1 parent 15ae1e5 commit 8286028

26 files changed

+896
-1047
lines changed

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
@misskey-dev/node-http-message-signatures
22
----
33

4-
(WIP) Implementation of [HTTP Signatures "Draft", RFC 9421](https://datatracker.ietf.org/doc/rfc9421/), [RFC 3230](https://datatracker.ietf.org/doc/rfc3230/) and [RFC 9530](https://datatracker.ietf.org/doc/rfc9530/) for Node.js.
4+
(WIP) Implementation of [HTTP Signatures "Draft", RFC 9421](https://datatracker.ietf.org/doc/rfc9421/), [RFC 3230](https://datatracker.ietf.org/doc/rfc3230/) and [RFC 9530](https://datatracker.ietf.org/doc/rfc9530/) for JavaScript.
55

66
It is created for Misskey's ActivityPub implementation.
77

8+
We initially started working on it with the intention of using it in Node.js, but since we rewrote it to Web Crypto API, it may also work in browsers and edge workers.
9+
810
## Context
911
### HTTP Signatures "Draft" and RFC 9421
1012
[RFC 9421](https://datatracker.ietf.org/doc/rfc9421/) is the standard used for signing HTTP communications, but has been used since draft in the world of ActivityPub server-to-server communications with Misskey, Mastodon, and others.
@@ -117,8 +119,8 @@ fastify.post('/inbox', { config: { rawBody: true } }, async (request, reply) =>
117119
return;
118120
}
119121

120-
// Verify
121-
const verifyResult = verifyDraftSignature(parsed!.value, keys.rsa4096.publicKey, errorLogger);
122+
// Verify Signature
123+
const verifyResult = await verifyDraftSignature(parsed!.value, keys.rsa4096.publicKey, errorLogger);
122124
if (!verifyResult) {
123125
reply.code(401);
124126
return;
@@ -147,7 +149,7 @@ function targetSupportsRFC9421(url) {
147149

148150
const includeHeaders = ['(request-target)', 'date', 'host', 'digest'];
149151

150-
export function send(url: string, body: string, keyId: string) {
152+
export async function send(url: string, body: string, keyId: string) {
151153
const privateKeyPem = privateKeyMap.get(keyId);
152154
const u = new URL(url);
153155

@@ -168,7 +170,7 @@ export function send(url: string, body: string, keyId: string) {
168170
// Draft
169171
request.headers['Digest'] = genRFC3230DigestHeader(body);
170172

171-
signAsDraftToRequest(request, { keyId, privateKeyPem }, includeHeaders);
173+
await signAsDraftToRequest(request, { keyId, privateKeyPem }, includeHeaders);
172174

173175
fetch(u, {
174176
method: request.method,

dist/draft/const.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Draftのalgorithm用
3+
*/
4+
export declare const keyHashAlgosForDraftEncofing: {
5+
readonly SHA: "sha1";
6+
readonly 'SHA-1': "sha1";
7+
readonly 'SHA-256': "sha256";
8+
readonly 'SHA-384': "sha384";
9+
readonly 'SHA-512': "sha512";
10+
readonly MD5: "md5";
11+
};
12+
/**
13+
* Draftのalgorithm用
14+
*/
15+
export declare const keyHashAlgosForDraftDecoding: {
16+
readonly sha1: "SHA";
17+
readonly sha256: "SHA-256";
18+
readonly sha384: "SHA-384";
19+
readonly sha512: "SHA-512";
20+
readonly md5: "MD5";
21+
};

dist/draft/parse.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/**
2+
* Parse Request
3+
*/
14
import { RequestParseOptions } from "../parse.js";
25
import type { ParsedDraftSignature, IncomingRequest } from '../types.js';
36
export declare const DraftSignatureHeaderKeys: readonly ["keyId", "algorithm", "created", "expires", "opaque", "headers", "signature"];

dist/draft/sign.d.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
1-
import type { PrivateKey, RequestLike, SignatureHashAlgorithm } from '../types.js';
1+
/// <reference types="node" />
2+
import type { webcrypto as crypto } from 'node:crypto';
3+
import type { PrivateKey, RequestLike, SignInfo, SignatureHashAlgorithmUpperSnake } from '../types.js';
4+
export declare function getDraftAlgoString(algorithm: SignInfo): string;
25
export declare function genDraftSigningString(request: RequestLike, includeHeaders: string[], additional?: {
36
keyId: string;
47
algorithm: string;
58
created?: string;
69
expires?: string;
710
opaque?: string;
811
}): string;
9-
export declare function genDraftSignature(signingString: string, privateKey: string, hashAlgorithm: SignatureHashAlgorithm | null): string;
12+
export declare function genDraftSignature(privateKey: crypto.CryptoKey, signingString: string): Promise<string>;
1013
export declare function genDraftSignatureHeader(includeHeaders: string[], keyId: string, signature: string, algorithm: string): string;
1114
export declare function signAsDraftToRequest(request: RequestLike, key: PrivateKey, includeHeaders: string[], opts?: {
12-
hashAlgorithm?: SignatureHashAlgorithm;
13-
web?: boolean;
14-
}): {
15-
signingString: string;
16-
signature: string;
17-
signatureHeader: string;
18-
};
19-
export declare function signAsDraftToRequestWeb(request: RequestLike, key: PrivateKey, includeHeaders: string[], opts?: {
20-
hashAlgorithm?: SignatureHashAlgorithm;
15+
hashAlgorithm?: SignatureHashAlgorithmUpperSnake;
2116
}): Promise<{
2217
signingString: string;
2318
signature: string;

dist/draft/verify.d.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1-
import type { ParsedDraftSignature } from '../types.js';
2-
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, errorLogger?: ((message: any) => any)): boolean;
31
/**
4-
* Experimental
5-
* @experimental Testing Web Crypto API
2+
* Verify Request (Parsed)
63
*/
7-
export declare function webVerifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, errorLogger?: ((message: any) => any)): Promise<boolean>;
4+
import type { ParsedDraftSignature, SignInfo } from '../types.js';
5+
import { ParsedAlgorithmIdentifier } from '../pem/spki.js';
6+
export declare class DraftKeyHashValidationError extends Error {
7+
constructor(message: string);
8+
}
9+
/**
10+
* 鍵のアルゴリズムとDraft仕様のalgorithmをもとに、キーとハッシュアルゴリズムをまとめる
11+
* 呼び出しの公開鍵の種類が提供されたものと一致しない場合はエラーを投げる
12+
* @param algorithm ヘッダーのアルゴリズム(Draft仕様)
13+
* @param publicKey 実際の公開鍵
14+
*/
15+
export declare function genSignInfoDraft(algorithm: string | undefined, parsed: ParsedAlgorithmIdentifier, errorLogger?: ((message: any) => any)): SignInfo;
16+
/**
17+
* Verify a draft signature
18+
*/
19+
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, errorLogger?: ((message: any) => any)): Promise<boolean>;

0 commit comments

Comments
 (0)