@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 +23 -0
- package/dist/base.d.ts +20 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +143 -0
- package/dist/base.js.map +1 -0
- package/dist/errors.d.ts +37 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +51 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +38 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +253 -0
- package/dist/parser.js.map +1 -0
- package/dist/types.d.ts +90 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/verify.d.ts +49 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +144 -0
- package/dist/verify.js.map +1 -0
- package/package.json +47 -0
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
|
package/dist/base.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/parser.d.ts
ADDED
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
package/dist/verify.d.ts
ADDED
|
@@ -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
|
+
}
|