@peac/http-signatures 0.9.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # @peac/http-signatures
2
+
3
+ RFC 9421 HTTP Message Signatures parsing and verification
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @peac/http-signatures
9
+ ```
10
+
11
+ ## Documentation
12
+
13
+ See [peacprotocol.org](https://peacprotocol.org) for full documentation.
14
+
15
+ ## License
16
+
17
+ Apache-2.0
18
+
19
+ ---
20
+
21
+ PEAC Protocol is an open source project stewarded by Originary and community contributors.
22
+
23
+ [Originary](https://www.originary.xyz) | [Docs](https://peacprotocol.org) | [GitHub](https://github.com/peacprotocol/peac)
package/dist/base.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Signature base construction per RFC 9421 Section 2.5.
3
+ *
4
+ * The signature base is a canonical string constructed from
5
+ * covered components and signature parameters.
6
+ */
7
+ import { ParsedSignatureParams, SignatureRequest } from './types.js';
8
+ /**
9
+ * Build signature base string for verification.
10
+ *
11
+ * @param request - Request data
12
+ * @param params - Parsed signature parameters
13
+ * @returns Signature base string
14
+ */
15
+ export declare function buildSignatureBase(request: SignatureRequest, params: ParsedSignatureParams): string;
16
+ /**
17
+ * Convert signature base string to bytes for cryptographic verification.
18
+ */
19
+ export declare function signatureBaseToBytes(signatureBase: string): Uint8Array;
20
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,qBAAqB,GAC5B,MAAM,CAcR;AA+HD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,UAAU,CAGtE"}
package/dist/base.js ADDED
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Signature base construction per RFC 9421 Section 2.5.
3
+ *
4
+ * The signature base is a canonical string constructed from
5
+ * covered components and signature parameters.
6
+ */
7
+ /**
8
+ * Build signature base string for verification.
9
+ *
10
+ * @param request - Request data
11
+ * @param params - Parsed signature parameters
12
+ * @returns Signature base string
13
+ */
14
+ export function buildSignatureBase(request, params) {
15
+ const lines = [];
16
+ // Add each covered component
17
+ for (const component of params.coveredComponents) {
18
+ const value = getComponentValue(request, component);
19
+ lines.push(`"${component}": ${value}`);
20
+ }
21
+ // Add signature params line
22
+ const paramsLine = buildSignatureParamsLine(params);
23
+ lines.push(`"@signature-params": ${paramsLine}`);
24
+ return lines.join('\n');
25
+ }
26
+ /**
27
+ * Get the canonical value for a component identifier.
28
+ */
29
+ function getComponentValue(request, component) {
30
+ // Derived components start with @
31
+ if (component.startsWith('@')) {
32
+ return getDerivedComponentValue(request, component);
33
+ }
34
+ // Otherwise it's a header field
35
+ return getHeaderValue(request.headers, component);
36
+ }
37
+ /**
38
+ * Get derived component value.
39
+ */
40
+ function getDerivedComponentValue(request, component) {
41
+ switch (component) {
42
+ case '@method':
43
+ return request.method.toUpperCase();
44
+ case '@target-uri':
45
+ return request.url;
46
+ case '@authority': {
47
+ try {
48
+ const url = new URL(request.url);
49
+ return url.host;
50
+ }
51
+ catch {
52
+ // If URL parsing fails, try to extract from headers
53
+ return getHeaderValue(request.headers, 'host');
54
+ }
55
+ }
56
+ case '@scheme': {
57
+ try {
58
+ const url = new URL(request.url);
59
+ return url.protocol.replace(':', '');
60
+ }
61
+ catch {
62
+ return 'https';
63
+ }
64
+ }
65
+ case '@request-target': {
66
+ try {
67
+ const url = new URL(request.url);
68
+ return url.pathname + url.search;
69
+ }
70
+ catch {
71
+ // If not a full URL, assume it's already a path
72
+ return request.url;
73
+ }
74
+ }
75
+ case '@path': {
76
+ try {
77
+ const url = new URL(request.url);
78
+ return url.pathname;
79
+ }
80
+ catch {
81
+ const pathMatch = request.url.match(/^[^?]*/);
82
+ return pathMatch ? pathMatch[0] : request.url;
83
+ }
84
+ }
85
+ case '@query': {
86
+ try {
87
+ const url = new URL(request.url);
88
+ return url.search || '?';
89
+ }
90
+ catch {
91
+ const queryMatch = request.url.match(/\?.*/);
92
+ return queryMatch ? queryMatch[0] : '?';
93
+ }
94
+ }
95
+ default:
96
+ // Unknown derived component - return empty
97
+ return '';
98
+ }
99
+ }
100
+ /**
101
+ * Get header value by name (case-insensitive).
102
+ */
103
+ function getHeaderValue(headers, name) {
104
+ const lowerName = name.toLowerCase();
105
+ for (const [key, value] of Object.entries(headers)) {
106
+ if (key.toLowerCase() === lowerName) {
107
+ return value;
108
+ }
109
+ }
110
+ return '';
111
+ }
112
+ /**
113
+ * Build the signature-params line value.
114
+ *
115
+ * Format: ("component1" "component2");created=123;keyid="key";alg="ed25519"
116
+ */
117
+ function buildSignatureParamsLine(params) {
118
+ // Build inner list of components
119
+ const components = params.coveredComponents.map((c) => `"${c}"`).join(' ');
120
+ let line = `(${components})`;
121
+ // Add required parameters in canonical order
122
+ line += `;created=${params.created}`;
123
+ if (params.expires !== undefined) {
124
+ line += `;expires=${params.expires}`;
125
+ }
126
+ if (params.nonce !== undefined) {
127
+ line += `;nonce="${params.nonce}"`;
128
+ }
129
+ line += `;keyid="${params.keyid}"`;
130
+ line += `;alg="${params.alg}"`;
131
+ if (params.tag !== undefined) {
132
+ line += `;tag="${params.tag}"`;
133
+ }
134
+ return line;
135
+ }
136
+ /**
137
+ * Convert signature base string to bytes for cryptographic verification.
138
+ */
139
+ export function signatureBaseToBytes(signatureBase) {
140
+ const encoder = new TextEncoder();
141
+ return encoder.encode(signatureBase);
142
+ }
143
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * HTTP Signature error codes per execution pack specification.
3
+ */
4
+ export declare const ErrorCodes: {
5
+ /** Signature-Input header parse failed */
6
+ readonly SIGNATURE_INPUT_MALFORMED: "E_SIGNATURE_INPUT_MALFORMED";
7
+ /** No Signature header present */
8
+ readonly SIGNATURE_MISSING: "E_SIGNATURE_MISSING";
9
+ /** Required param (created/keyid/alg) missing */
10
+ readonly SIGNATURE_PARAM_MISSING: "E_SIGNATURE_PARAM_MISSING";
11
+ /** Algorithm not ed25519 */
12
+ readonly SIGNATURE_ALGORITHM_UNSUPPORTED: "E_SIGNATURE_ALGORITHM_UNSUPPORTED";
13
+ /** Signature expired (now > expires) */
14
+ readonly SIGNATURE_EXPIRED: "E_SIGNATURE_EXPIRED";
15
+ /** Signature from future (created > now + skew) */
16
+ readonly SIGNATURE_FUTURE: "E_SIGNATURE_FUTURE";
17
+ /** Cryptographic verification failed */
18
+ readonly SIGNATURE_INVALID: "E_SIGNATURE_INVALID";
19
+ /** Ed25519 WebCrypto not supported */
20
+ readonly WEBCRYPTO_UNAVAILABLE: "E_WEBCRYPTO_UNAVAILABLE";
21
+ /** Key not found by resolver */
22
+ readonly KEY_NOT_FOUND: "E_KEY_NOT_FOUND";
23
+ };
24
+ export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
25
+ /**
26
+ * HTTP status codes for each error.
27
+ */
28
+ export declare const ErrorHttpStatus: Record<ErrorCode, number>;
29
+ /**
30
+ * HTTP Signature error with code and HTTP status.
31
+ */
32
+ export declare class HttpSignatureError extends Error {
33
+ readonly code: ErrorCode;
34
+ readonly httpStatus: number;
35
+ constructor(code: ErrorCode, message: string);
36
+ }
37
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,UAAU;IACrB,0CAA0C;;IAE1C,kCAAkC;;IAElC,iDAAiD;;IAEjD,4BAA4B;;IAE5B,wCAAwC;;IAExC,mDAAmD;;IAEnD,wCAAwC;;IAExC,sCAAsC;;IAEtC,gCAAgC;;CAExB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAErE;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAUrD,CAAC;AAEF;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM;CAM7C"}
package/dist/errors.js ADDED
@@ -0,0 +1,51 @@
1
+ /**
2
+ * HTTP Signature error codes per execution pack specification.
3
+ */
4
+ export const ErrorCodes = {
5
+ /** Signature-Input header parse failed */
6
+ SIGNATURE_INPUT_MALFORMED: 'E_SIGNATURE_INPUT_MALFORMED',
7
+ /** No Signature header present */
8
+ SIGNATURE_MISSING: 'E_SIGNATURE_MISSING',
9
+ /** Required param (created/keyid/alg) missing */
10
+ SIGNATURE_PARAM_MISSING: 'E_SIGNATURE_PARAM_MISSING',
11
+ /** Algorithm not ed25519 */
12
+ SIGNATURE_ALGORITHM_UNSUPPORTED: 'E_SIGNATURE_ALGORITHM_UNSUPPORTED',
13
+ /** Signature expired (now > expires) */
14
+ SIGNATURE_EXPIRED: 'E_SIGNATURE_EXPIRED',
15
+ /** Signature from future (created > now + skew) */
16
+ SIGNATURE_FUTURE: 'E_SIGNATURE_FUTURE',
17
+ /** Cryptographic verification failed */
18
+ SIGNATURE_INVALID: 'E_SIGNATURE_INVALID',
19
+ /** Ed25519 WebCrypto not supported */
20
+ WEBCRYPTO_UNAVAILABLE: 'E_WEBCRYPTO_UNAVAILABLE',
21
+ /** Key not found by resolver */
22
+ KEY_NOT_FOUND: 'E_KEY_NOT_FOUND',
23
+ };
24
+ /**
25
+ * HTTP status codes for each error.
26
+ */
27
+ export const ErrorHttpStatus = {
28
+ [ErrorCodes.SIGNATURE_INPUT_MALFORMED]: 400,
29
+ [ErrorCodes.SIGNATURE_MISSING]: 401,
30
+ [ErrorCodes.SIGNATURE_PARAM_MISSING]: 400,
31
+ [ErrorCodes.SIGNATURE_ALGORITHM_UNSUPPORTED]: 400,
32
+ [ErrorCodes.SIGNATURE_EXPIRED]: 401,
33
+ [ErrorCodes.SIGNATURE_FUTURE]: 401,
34
+ [ErrorCodes.SIGNATURE_INVALID]: 401,
35
+ [ErrorCodes.WEBCRYPTO_UNAVAILABLE]: 500,
36
+ [ErrorCodes.KEY_NOT_FOUND]: 401,
37
+ };
38
+ /**
39
+ * HTTP Signature error with code and HTTP status.
40
+ */
41
+ export class HttpSignatureError extends Error {
42
+ code;
43
+ httpStatus;
44
+ constructor(code, message) {
45
+ super(message);
46
+ this.name = 'HttpSignatureError';
47
+ this.code = code;
48
+ this.httpStatus = ErrorHttpStatus[code];
49
+ }
50
+ }
51
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,0CAA0C;IAC1C,yBAAyB,EAAE,6BAA6B;IACxD,kCAAkC;IAClC,iBAAiB,EAAE,qBAAqB;IACxC,iDAAiD;IACjD,uBAAuB,EAAE,2BAA2B;IACpD,4BAA4B;IAC5B,+BAA+B,EAAE,mCAAmC;IACpE,wCAAwC;IACxC,iBAAiB,EAAE,qBAAqB;IACxC,mDAAmD;IACnD,gBAAgB,EAAE,oBAAoB;IACtC,wCAAwC;IACxC,iBAAiB,EAAE,qBAAqB;IACxC,sCAAsC;IACtC,qBAAqB,EAAE,yBAAyB;IAChD,gCAAgC;IAChC,aAAa,EAAE,iBAAiB;CACxB,CAAC;AAIX;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAA8B;IACxD,CAAC,UAAU,CAAC,yBAAyB,CAAC,EAAE,GAAG;IAC3C,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,GAAG;IACnC,CAAC,UAAU,CAAC,uBAAuB,CAAC,EAAE,GAAG;IACzC,CAAC,UAAU,CAAC,+BAA+B,CAAC,EAAE,GAAG;IACjD,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,GAAG;IACnC,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,GAAG;IAClC,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,GAAG;IACnC,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,GAAG;IACvC,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,GAAG;CAChC,CAAC;AAEF;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,CAAY;IAChB,UAAU,CAAS;IAE5B,YAAY,IAAe,EAAE,OAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @peac/http-signatures
3
+ *
4
+ * RFC 9421 HTTP Message Signatures parsing and verification.
5
+ * Runtime-neutral - no DOM dependencies in public API.
6
+ */
7
+ export type { SignatureVerifier, KeyResolver, ParsedSignatureParams, ParsedSignature, VerificationResult, SignatureRequest, VerifyOptions, } from './types.js';
8
+ export { parseSignatureInput, parseSignatureHeader, parseSignature } from './parser.js';
9
+ export { buildSignatureBase, signatureBaseToBytes } from './base.js';
10
+ export { verifySignature, isExpired, isCreatedInFuture, isEd25519WebCryptoSupported, createWebCryptoVerifier, } from './verify.js';
11
+ export { ErrorCodes, ErrorHttpStatus, HttpSignatureError } from './errors.js';
12
+ export type { ErrorCode } from './errors.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGxF,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGrE,OAAO,EACL,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC9E,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @peac/http-signatures
3
+ *
4
+ * RFC 9421 HTTP Message Signatures parsing and verification.
5
+ * Runtime-neutral - no DOM dependencies in public API.
6
+ */
7
+ // Parser
8
+ export { parseSignatureInput, parseSignatureHeader, parseSignature } from './parser.js';
9
+ // Signature base
10
+ export { buildSignatureBase, signatureBaseToBytes } from './base.js';
11
+ // Verification
12
+ export { verifySignature, isExpired, isCreatedInFuture, isEd25519WebCryptoSupported, createWebCryptoVerifier, } from './verify.js';
13
+ // Errors
14
+ export { ErrorCodes, ErrorHttpStatus, HttpSignatureError } from './errors.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,SAAS;AACT,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAExF,iBAAiB;AACjB,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAErE,eAAe;AACf,OAAO,EACL,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAErB,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Parser for RFC 9421 Signature-Input and Signature headers.
3
+ *
4
+ * Implements minimal RFC 8941 Structured Fields parsing for
5
+ * Dictionary and Inner List types as needed by HTTP Signatures.
6
+ */
7
+ import { ParsedSignatureParams, ParsedSignature } from './types.js';
8
+ /**
9
+ * Parse Signature-Input header value into structured parameters.
10
+ *
11
+ * Format: label=("component1" "component2");param1=value1;param2=value2
12
+ *
13
+ * @param headerValue - Raw Signature-Input header value
14
+ * @returns Map of label to parsed parameters
15
+ */
16
+ export declare function parseSignatureInput(headerValue: string): Map<string, ParsedSignatureParams>;
17
+ /**
18
+ * Parse Signature header value into raw signature bytes.
19
+ *
20
+ * Format: label=:base64signature:
21
+ *
22
+ * @param headerValue - Raw Signature header value
23
+ * @returns Map of label to signature bytes
24
+ */
25
+ export declare function parseSignatureHeader(headerValue: string): Map<string, {
26
+ bytes: Uint8Array;
27
+ base64: string;
28
+ }>;
29
+ /**
30
+ * Parse complete signature from both headers.
31
+ *
32
+ * @param signatureInput - Signature-Input header value
33
+ * @param signature - Signature header value
34
+ * @param label - Optional specific label to parse (defaults to first)
35
+ * @returns Parsed signature or throws HttpSignatureError
36
+ */
37
+ export declare function parseSignature(signatureInput: string, signature: string, label?: string): ParsedSignature;
38
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGpE;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAc3F;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,GAClB,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAuBpD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,eAAe,CAwEjB"}
package/dist/parser.js ADDED
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Parser for RFC 9421 Signature-Input and Signature headers.
3
+ *
4
+ * Implements minimal RFC 8941 Structured Fields parsing for
5
+ * Dictionary and Inner List types as needed by HTTP Signatures.
6
+ */
7
+ import { ErrorCodes, HttpSignatureError } from './errors.js';
8
+ /**
9
+ * Parse Signature-Input header value into structured parameters.
10
+ *
11
+ * Format: label=("component1" "component2");param1=value1;param2=value2
12
+ *
13
+ * @param headerValue - Raw Signature-Input header value
14
+ * @returns Map of label to parsed parameters
15
+ */
16
+ export function parseSignatureInput(headerValue) {
17
+ const results = new Map();
18
+ // Split by comma for multiple signatures (outer dictionary members)
19
+ const members = splitDictionaryMembers(headerValue);
20
+ for (const member of members) {
21
+ const parsed = parseDictionaryMember(member.trim());
22
+ if (parsed) {
23
+ results.set(parsed.label, parsed.params);
24
+ }
25
+ }
26
+ return results;
27
+ }
28
+ /**
29
+ * Parse Signature header value into raw signature bytes.
30
+ *
31
+ * Format: label=:base64signature:
32
+ *
33
+ * @param headerValue - Raw Signature header value
34
+ * @returns Map of label to signature bytes
35
+ */
36
+ export function parseSignatureHeader(headerValue) {
37
+ const results = new Map();
38
+ const members = splitDictionaryMembers(headerValue);
39
+ for (const member of members) {
40
+ const [label, value] = splitKeyValue(member.trim());
41
+ if (!label || !value)
42
+ continue;
43
+ // Extract base64 from :...: byte sequence format
44
+ const match = value.match(/^:([A-Za-z0-9+/=_-]+):$/);
45
+ if (!match)
46
+ continue;
47
+ const base64 = match[1];
48
+ try {
49
+ const bytes = base64ToBytes(base64);
50
+ results.set(label, { bytes, base64 });
51
+ }
52
+ catch {
53
+ // Skip invalid base64
54
+ }
55
+ }
56
+ return results;
57
+ }
58
+ /**
59
+ * Parse complete signature from both headers.
60
+ *
61
+ * @param signatureInput - Signature-Input header value
62
+ * @param signature - Signature header value
63
+ * @param label - Optional specific label to parse (defaults to first)
64
+ * @returns Parsed signature or throws HttpSignatureError
65
+ */
66
+ export function parseSignature(signatureInput, signature, label) {
67
+ if (!signatureInput) {
68
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_INPUT_MALFORMED, 'Missing Signature-Input header');
69
+ }
70
+ if (!signature) {
71
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_MISSING, 'Missing Signature header');
72
+ }
73
+ const inputMap = parseSignatureInput(signatureInput);
74
+ const sigMap = parseSignatureHeader(signature);
75
+ if (inputMap.size === 0) {
76
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_INPUT_MALFORMED, 'Failed to parse Signature-Input header');
77
+ }
78
+ // Use specified label or first available
79
+ const targetLabel = label ?? inputMap.keys().next().value;
80
+ if (!targetLabel) {
81
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_INPUT_MALFORMED, 'No signature label found');
82
+ }
83
+ const params = inputMap.get(targetLabel);
84
+ if (!params) {
85
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_INPUT_MALFORMED, `Signature label "${targetLabel}" not found in Signature-Input`);
86
+ }
87
+ const sigData = sigMap.get(targetLabel);
88
+ if (!sigData) {
89
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_MISSING, `Signature label "${targetLabel}" not found in Signature header`);
90
+ }
91
+ // Validate required parameters
92
+ if (!params.keyid) {
93
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_PARAM_MISSING, 'Missing required parameter: keyid');
94
+ }
95
+ if (!params.alg) {
96
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_PARAM_MISSING, 'Missing required parameter: alg');
97
+ }
98
+ if (params.created === undefined || params.created === null) {
99
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_PARAM_MISSING, 'Missing required parameter: created');
100
+ }
101
+ return {
102
+ label: targetLabel,
103
+ params,
104
+ signatureBytes: sigData.bytes,
105
+ signatureBase64: sigData.base64,
106
+ };
107
+ }
108
+ // --- Internal parsing helpers ---
109
+ /**
110
+ * Split dictionary members by comma, respecting inner lists and strings.
111
+ */
112
+ function splitDictionaryMembers(value) {
113
+ const members = [];
114
+ let current = '';
115
+ let depth = 0;
116
+ let inString = false;
117
+ let inByteSeq = false;
118
+ for (let i = 0; i < value.length; i++) {
119
+ const char = value[i];
120
+ if (char === '"' && !inByteSeq) {
121
+ inString = !inString;
122
+ current += char;
123
+ }
124
+ else if (char === ':' && !inString) {
125
+ inByteSeq = !inByteSeq;
126
+ current += char;
127
+ }
128
+ else if (char === '(' && !inString && !inByteSeq) {
129
+ depth++;
130
+ current += char;
131
+ }
132
+ else if (char === ')' && !inString && !inByteSeq) {
133
+ depth--;
134
+ current += char;
135
+ }
136
+ else if (char === ',' && depth === 0 && !inString && !inByteSeq) {
137
+ if (current.trim()) {
138
+ members.push(current.trim());
139
+ }
140
+ current = '';
141
+ }
142
+ else {
143
+ current += char;
144
+ }
145
+ }
146
+ if (current.trim()) {
147
+ members.push(current.trim());
148
+ }
149
+ return members;
150
+ }
151
+ /**
152
+ * Split a dictionary member into key=value pair.
153
+ */
154
+ function splitKeyValue(member) {
155
+ const eqIndex = member.indexOf('=');
156
+ if (eqIndex === -1) {
157
+ return [member, ''];
158
+ }
159
+ return [member.slice(0, eqIndex), member.slice(eqIndex + 1)];
160
+ }
161
+ /**
162
+ * Parse a single dictionary member (label=inner-list;params).
163
+ */
164
+ function parseDictionaryMember(member) {
165
+ const [label, rest] = splitKeyValue(member);
166
+ if (!label || !rest)
167
+ return null;
168
+ // Parse inner list and parameters
169
+ // Format: ("component1" "component2");param1=value1;param2=value2
170
+ const innerListMatch = rest.match(/^\(([^)]*)\)(.*)$/);
171
+ if (!innerListMatch)
172
+ return null;
173
+ const innerListContent = innerListMatch[1];
174
+ const paramsString = innerListMatch[2];
175
+ // Parse covered components from inner list
176
+ const coveredComponents = parseInnerList(innerListContent);
177
+ // Parse parameters
178
+ const rawParams = parseParameters(paramsString);
179
+ const params = {
180
+ keyid: String(rawParams.keyid ?? ''),
181
+ alg: String(rawParams.alg ?? ''),
182
+ created: rawParams.created !== undefined ? Number(rawParams.created) : 0,
183
+ coveredComponents,
184
+ };
185
+ if (rawParams.expires !== undefined) {
186
+ params.expires = Number(rawParams.expires);
187
+ }
188
+ if (rawParams.nonce !== undefined) {
189
+ params.nonce = String(rawParams.nonce);
190
+ }
191
+ if (rawParams.tag !== undefined) {
192
+ params.tag = String(rawParams.tag);
193
+ }
194
+ return { label, params };
195
+ }
196
+ /**
197
+ * Parse inner list content (space-separated quoted strings).
198
+ */
199
+ function parseInnerList(content) {
200
+ const items = [];
201
+ const regex = /"([^"]*)"/g;
202
+ let match;
203
+ while ((match = regex.exec(content)) !== null) {
204
+ items.push(match[1]);
205
+ }
206
+ return items;
207
+ }
208
+ /**
209
+ * Parse parameters from ;key=value;key2=value2 format.
210
+ */
211
+ function parseParameters(paramsString) {
212
+ const params = {};
213
+ // Split by semicolon
214
+ const parts = paramsString.split(';').filter((p) => p.trim());
215
+ for (const part of parts) {
216
+ const [key, value] = splitKeyValue(part.trim());
217
+ if (!key)
218
+ continue;
219
+ // Parse value - could be integer, string, or token
220
+ if (!value) {
221
+ params[key] = true;
222
+ }
223
+ else if (value.startsWith('"') && value.endsWith('"')) {
224
+ // Quoted string
225
+ params[key] = value.slice(1, -1);
226
+ }
227
+ else if (/^-?\d+$/.test(value)) {
228
+ // Integer
229
+ params[key] = parseInt(value, 10);
230
+ }
231
+ else {
232
+ // Token or other
233
+ params[key] = value;
234
+ }
235
+ }
236
+ return params;
237
+ }
238
+ /**
239
+ * Decode base64 (standard or URL-safe) to bytes.
240
+ */
241
+ function base64ToBytes(base64) {
242
+ // Handle URL-safe base64
243
+ const normalized = base64.replace(/-/g, '+').replace(/_/g, '/');
244
+ // Add padding if needed
245
+ const padded = normalized.padEnd(normalized.length + ((4 - (normalized.length % 4)) % 4), '=');
246
+ const binary = atob(padded);
247
+ const bytes = new Uint8Array(binary.length);
248
+ for (let i = 0; i < binary.length; i++) {
249
+ bytes[i] = binary.charCodeAt(i);
250
+ }
251
+ return bytes;
252
+ }
253
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @peac/http-signatures - RFC 9421 HTTP Message Signatures
3
+ *
4
+ * Runtime-neutral types. No DOM dependencies (CryptoKey, Headers, etc.)
5
+ * in public API surface.
6
+ */
7
+ /**
8
+ * Ed25519 signature verifier function (runtime-neutral).
9
+ * Takes raw data and signature bytes, returns verification result.
10
+ */
11
+ export type SignatureVerifier = (data: Uint8Array, signature: Uint8Array) => Promise<boolean>;
12
+ /**
13
+ * Key resolver function type (runtime-neutral).
14
+ * Given a key ID, returns a SignatureVerifier or null if key not found.
15
+ */
16
+ export type KeyResolver = (keyid: string) => Promise<SignatureVerifier | null>;
17
+ /**
18
+ * Parsed parameters from Signature-Input header.
19
+ * All fields exposed for TAP and other higher-level protocol enforcement.
20
+ */
21
+ export interface ParsedSignatureParams {
22
+ /** Key identifier */
23
+ keyid: string;
24
+ /** Algorithm (must be "ed25519" for PEAC) */
25
+ alg: string;
26
+ /** Unix timestamp when signature was created */
27
+ created: number;
28
+ /** Unix timestamp when signature expires (optional) */
29
+ expires?: number;
30
+ /** Nonce for replay prevention (optional) */
31
+ nonce?: string;
32
+ /** Tag for interaction type (e.g., "agent-browser-auth") (optional) */
33
+ tag?: string;
34
+ /** Covered component identifiers */
35
+ coveredComponents: string[];
36
+ }
37
+ /**
38
+ * Complete parsed signature with raw signature bytes.
39
+ */
40
+ export interface ParsedSignature {
41
+ /** Signature label from Signature-Input header */
42
+ label: string;
43
+ /** Parsed parameters */
44
+ params: ParsedSignatureParams;
45
+ /** Raw signature bytes (decoded from base64) */
46
+ signatureBytes: Uint8Array;
47
+ /** Original base64-encoded signature */
48
+ signatureBase64: string;
49
+ }
50
+ /**
51
+ * Verification result with detailed information.
52
+ */
53
+ export interface VerificationResult {
54
+ /** Whether the signature is valid */
55
+ valid: boolean;
56
+ /** Parsed signature (if parsing succeeded) */
57
+ signature?: ParsedSignature;
58
+ /** Error code if verification failed */
59
+ errorCode?: string;
60
+ /** Human-readable error message */
61
+ errorMessage?: string;
62
+ }
63
+ /**
64
+ * Request-like object for signature verification.
65
+ * Uses Record<string, string> instead of Headers for runtime neutrality.
66
+ */
67
+ export interface SignatureRequest {
68
+ /** HTTP method */
69
+ method: string;
70
+ /** Request URL (full or path) */
71
+ url: string;
72
+ /** Request headers as Record */
73
+ headers: Record<string, string>;
74
+ /** Request body (optional, for content-digest) */
75
+ body?: string | ArrayBuffer | Uint8Array;
76
+ }
77
+ /**
78
+ * Options for signature verification.
79
+ */
80
+ export interface VerifyOptions {
81
+ /** Key resolver function */
82
+ keyResolver: KeyResolver;
83
+ /** Current timestamp (defaults to Date.now() / 1000) */
84
+ now?: number;
85
+ /** Clock skew tolerance in seconds (defaults to 60) */
86
+ clockSkewSeconds?: number;
87
+ /** Signature label to verify (defaults to first available) */
88
+ label?: string;
89
+ }
90
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9F;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;AAE/E;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,gDAAgD;IAChD,cAAc,EAAE,UAAU,CAAC;IAC3B,wCAAwC;IACxC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,8CAA8C;IAC9C,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,4BAA4B;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @peac/http-signatures - RFC 9421 HTTP Message Signatures
3
+ *
4
+ * Runtime-neutral types. No DOM dependencies (CryptoKey, Headers, etc.)
5
+ * in public API surface.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * HTTP Message Signature verification.
3
+ *
4
+ * Runtime-neutral verification using SignatureVerifier function type.
5
+ * WebCrypto is used internally but NOT exposed in public API.
6
+ */
7
+ import { SignatureVerifier, SignatureRequest, VerifyOptions, VerificationResult, ParsedSignatureParams } from './types.js';
8
+ /**
9
+ * Verify an HTTP Message Signature.
10
+ *
11
+ * @param request - Request data with headers
12
+ * @param options - Verification options including key resolver
13
+ * @returns Verification result
14
+ */
15
+ export declare function verifySignature(request: SignatureRequest, options: VerifyOptions): Promise<VerificationResult>;
16
+ /**
17
+ * Check if signature is expired.
18
+ *
19
+ * @param params - Parsed signature parameters
20
+ * @param now - Current Unix timestamp (defaults to current time)
21
+ * @returns true if signature is expired
22
+ */
23
+ export declare function isExpired(params: ParsedSignatureParams, now?: number): boolean;
24
+ /**
25
+ * Check if signature was created in the future (accounting for clock skew).
26
+ *
27
+ * @param params - Parsed signature parameters
28
+ * @param now - Current Unix timestamp (defaults to current time)
29
+ * @param skewSeconds - Allowed clock skew in seconds (defaults to 60)
30
+ * @returns true if signature is from the future
31
+ */
32
+ export declare function isCreatedInFuture(params: ParsedSignatureParams, now?: number, skewSeconds?: number): boolean;
33
+ /**
34
+ * Check if Ed25519 WebCrypto is supported in current runtime.
35
+ *
36
+ * @returns true if Ed25519 WebCrypto is available
37
+ */
38
+ export declare function isEd25519WebCryptoSupported(): Promise<boolean>;
39
+ /**
40
+ * Create a SignatureVerifier from a WebCrypto CryptoKey.
41
+ *
42
+ * This is a helper for consumers who have CryptoKey objects.
43
+ * The function is runtime-neutral as it accepts unknown and casts internally.
44
+ *
45
+ * @param key - WebCrypto CryptoKey (passed as unknown for runtime neutrality)
46
+ * @returns SignatureVerifier function
47
+ */
48
+ export declare function createWebCryptoVerifier(key: unknown): SignatureVerifier;
49
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,iBAAiB,EAEjB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAKpB;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,kBAAkB,CAAC,CAwD7B;AA2BD;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsC,GAC1C,OAAO,CAKT;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsC,EAC3C,WAAW,GAAE,MAAW,GACvB,OAAO,CAET;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,OAAO,CAAC,CAWpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAWvE"}
package/dist/verify.js ADDED
@@ -0,0 +1,144 @@
1
+ /**
2
+ * HTTP Message Signature verification.
3
+ *
4
+ * Runtime-neutral verification using SignatureVerifier function type.
5
+ * WebCrypto is used internally but NOT exposed in public API.
6
+ */
7
+ import { parseSignature } from './parser.js';
8
+ import { buildSignatureBase, signatureBaseToBytes } from './base.js';
9
+ import { ErrorCodes, HttpSignatureError } from './errors.js';
10
+ /**
11
+ * Verify an HTTP Message Signature.
12
+ *
13
+ * @param request - Request data with headers
14
+ * @param options - Verification options including key resolver
15
+ * @returns Verification result
16
+ */
17
+ export async function verifySignature(request, options) {
18
+ const { keyResolver, now = Math.floor(Date.now() / 1000), clockSkewSeconds = 60 } = options;
19
+ try {
20
+ // Get signature headers
21
+ const signatureInput = getHeader(request.headers, 'signature-input');
22
+ const signature = getHeader(request.headers, 'signature');
23
+ // Parse signature
24
+ const parsed = parseSignature(signatureInput, signature, options.label);
25
+ // Validate algorithm
26
+ if (parsed.params.alg !== 'ed25519') {
27
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_ALGORITHM_UNSUPPORTED, `Unsupported algorithm: ${parsed.params.alg} (only ed25519 is supported)`);
28
+ }
29
+ // Validate time constraints
30
+ validateTimeConstraints(parsed.params, now, clockSkewSeconds);
31
+ // Resolve key
32
+ const verifier = await keyResolver(parsed.params.keyid);
33
+ if (!verifier) {
34
+ throw new HttpSignatureError(ErrorCodes.KEY_NOT_FOUND, `Key not found: ${parsed.params.keyid}`);
35
+ }
36
+ // Build signature base
37
+ const signatureBase = buildSignatureBase(request, parsed.params);
38
+ const signatureBaseBytes = signatureBaseToBytes(signatureBase);
39
+ // Verify signature
40
+ const valid = await verifier(signatureBaseBytes, parsed.signatureBytes);
41
+ if (!valid) {
42
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_INVALID, 'Signature verification failed');
43
+ }
44
+ return {
45
+ valid: true,
46
+ signature: parsed,
47
+ };
48
+ }
49
+ catch (error) {
50
+ if (error instanceof HttpSignatureError) {
51
+ return {
52
+ valid: false,
53
+ errorCode: error.code,
54
+ errorMessage: error.message,
55
+ };
56
+ }
57
+ throw error;
58
+ }
59
+ }
60
+ /**
61
+ * Validate time constraints on signature parameters.
62
+ */
63
+ function validateTimeConstraints(params, now, clockSkewSeconds) {
64
+ // Check if signature is from the future (with skew tolerance)
65
+ if (isCreatedInFuture(params, now, clockSkewSeconds)) {
66
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_FUTURE, `Signature created in future: ${params.created} > ${now + clockSkewSeconds}`);
67
+ }
68
+ // Check if signature is expired
69
+ if (isExpired(params, now)) {
70
+ throw new HttpSignatureError(ErrorCodes.SIGNATURE_EXPIRED, `Signature expired: ${params.expires} < ${now}`);
71
+ }
72
+ }
73
+ /**
74
+ * Check if signature is expired.
75
+ *
76
+ * @param params - Parsed signature parameters
77
+ * @param now - Current Unix timestamp (defaults to current time)
78
+ * @returns true if signature is expired
79
+ */
80
+ export function isExpired(params, now = Math.floor(Date.now() / 1000)) {
81
+ if (params.expires === undefined) {
82
+ return false;
83
+ }
84
+ return now > params.expires;
85
+ }
86
+ /**
87
+ * Check if signature was created in the future (accounting for clock skew).
88
+ *
89
+ * @param params - Parsed signature parameters
90
+ * @param now - Current Unix timestamp (defaults to current time)
91
+ * @param skewSeconds - Allowed clock skew in seconds (defaults to 60)
92
+ * @returns true if signature is from the future
93
+ */
94
+ export function isCreatedInFuture(params, now = Math.floor(Date.now() / 1000), skewSeconds = 60) {
95
+ return params.created > now + skewSeconds;
96
+ }
97
+ /**
98
+ * Check if Ed25519 WebCrypto is supported in current runtime.
99
+ *
100
+ * @returns true if Ed25519 WebCrypto is available
101
+ */
102
+ export async function isEd25519WebCryptoSupported() {
103
+ try {
104
+ // Try to generate a key pair to test support
105
+ const keyPair = await globalThis.crypto.subtle.generateKey('Ed25519', false, [
106
+ 'sign',
107
+ 'verify',
108
+ ]);
109
+ return keyPair !== null;
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ }
115
+ /**
116
+ * Create a SignatureVerifier from a WebCrypto CryptoKey.
117
+ *
118
+ * This is a helper for consumers who have CryptoKey objects.
119
+ * The function is runtime-neutral as it accepts unknown and casts internally.
120
+ *
121
+ * @param key - WebCrypto CryptoKey (passed as unknown for runtime neutrality)
122
+ * @returns SignatureVerifier function
123
+ */
124
+ export function createWebCryptoVerifier(key) {
125
+ return async (data, signature) => {
126
+ // Create proper ArrayBuffer views to satisfy TypeScript
127
+ const sigBuffer = new Uint8Array(signature).buffer;
128
+ const dataBuffer = new Uint8Array(data).buffer;
129
+ return globalThis.crypto.subtle.verify('Ed25519', key, sigBuffer, dataBuffer);
130
+ };
131
+ }
132
+ /**
133
+ * Get header value by name (case-insensitive).
134
+ */
135
+ function getHeader(headers, name) {
136
+ const lowerName = name.toLowerCase();
137
+ for (const [key, value] of Object.entries(headers)) {
138
+ if (key.toLowerCase() === lowerName) {
139
+ return value;
140
+ }
141
+ }
142
+ return '';
143
+ }
144
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@peac/http-signatures",
3
+ "version": "0.9.18",
4
+ "description": "RFC 9421 HTTP Message Signatures parsing and verification",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest"
21
+ },
22
+ "keywords": [
23
+ "http",
24
+ "signatures",
25
+ "rfc9421",
26
+ "ed25519",
27
+ "peac"
28
+ ],
29
+ "author": "PEAC Protocol Contributors",
30
+ "license": "Apache-2.0",
31
+ "bugs": {
32
+ "url": "https://github.com/peacprotocol/peac/issues"
33
+ },
34
+ "homepage": "https://peacprotocol.org",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/peacprotocol/peac.git",
38
+ "directory": "packages/http-signatures"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "devDependencies": {
44
+ "typescript": "^5.3.0",
45
+ "vitest": "^2.0.0"
46
+ }
47
+ }