@peac/protocol 0.10.6 → 0.10.8

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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Cryptographic utilities for PEAC verifiers
3
+ *
4
+ * @deprecated Use @peac/crypto directly instead. This re-export exists for backwards compatibility.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { base64urlDecode, base64urlEncode, bytesToHex, computeJwkThumbprint, hexToBytes, jwkToPublicKeyBytes, sha256Bytes, sha256Hex, } from '@peac/crypto';
9
+ //# sourceMappingURL=crypto-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-utils.d.ts","sourceRoot":"","sources":["../src/crypto-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,eAAe,EACf,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,SAAS,GACV,MAAM,cAAc,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Cryptographic utilities for PEAC verifiers
4
+ *
5
+ * @deprecated Use @peac/crypto directly instead. This re-export exists for backwards compatibility.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.sha256Hex = exports.sha256Bytes = exports.jwkToPublicKeyBytes = exports.hexToBytes = exports.computeJwkThumbprint = exports.bytesToHex = exports.base64urlEncode = exports.base64urlDecode = void 0;
11
+ // Re-export all crypto utilities from @peac/crypto for backwards compatibility
12
+ var crypto_1 = require("@peac/crypto");
13
+ Object.defineProperty(exports, "base64urlDecode", { enumerable: true, get: function () { return crypto_1.base64urlDecode; } });
14
+ Object.defineProperty(exports, "base64urlEncode", { enumerable: true, get: function () { return crypto_1.base64urlEncode; } });
15
+ Object.defineProperty(exports, "bytesToHex", { enumerable: true, get: function () { return crypto_1.bytesToHex; } });
16
+ Object.defineProperty(exports, "computeJwkThumbprint", { enumerable: true, get: function () { return crypto_1.computeJwkThumbprint; } });
17
+ Object.defineProperty(exports, "hexToBytes", { enumerable: true, get: function () { return crypto_1.hexToBytes; } });
18
+ Object.defineProperty(exports, "jwkToPublicKeyBytes", { enumerable: true, get: function () { return crypto_1.jwkToPublicKeyBytes; } });
19
+ Object.defineProperty(exports, "sha256Bytes", { enumerable: true, get: function () { return crypto_1.sha256Bytes; } });
20
+ Object.defineProperty(exports, "sha256Hex", { enumerable: true, get: function () { return crypto_1.sha256Hex; } });
21
+ //# sourceMappingURL=crypto-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-utils.js","sourceRoot":"","sources":["../src/crypto-utils.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,+EAA+E;AAC/E,uCASsB;AARpB,yGAAA,eAAe,OAAA;AACf,yGAAA,eAAe,OAAA;AACf,oGAAA,UAAU,OAAA;AACV,8GAAA,oBAAoB,OAAA;AACpB,oGAAA,UAAU,OAAA;AACV,6GAAA,mBAAmB,OAAA;AACnB,qGAAA,WAAW,OAAA;AACX,mGAAA,SAAS,OAAA"}
package/dist/index.d.ts CHANGED
@@ -7,5 +7,11 @@ export * from './verify';
7
7
  export * from './verify-local';
8
8
  export * from './headers';
9
9
  export * from './discovery';
10
- export { generateKeypair, verify } from '@peac/crypto';
10
+ export * from './verifier-types';
11
+ export * from './verifier-core';
12
+ export * from './verification-report';
13
+ export * from './ssrf-safe-fetch';
14
+ export * from './transport-profiles';
15
+ export * from './pointer-fetch';
16
+ export { base64urlDecode, base64urlEncode, computeJwkThumbprint, generateKeypair, jwkToPublicKeyBytes, sha256Bytes, sha256Hex, verify, } from '@peac/crypto';
11
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAG5B,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAG5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAGhC,OAAO,EACL,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,MAAM,GACP,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -18,14 +18,27 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
18
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.verify = exports.generateKeypair = void 0;
21
+ exports.verify = exports.sha256Hex = exports.sha256Bytes = exports.jwkToPublicKeyBytes = exports.generateKeypair = exports.computeJwkThumbprint = exports.base64urlEncode = exports.base64urlDecode = void 0;
22
22
  __exportStar(require("./issue"), exports);
23
23
  __exportStar(require("./verify"), exports);
24
24
  __exportStar(require("./verify-local"), exports);
25
25
  __exportStar(require("./headers"), exports);
26
26
  __exportStar(require("./discovery"), exports);
27
+ // Verifier core (v0.10.8+)
28
+ __exportStar(require("./verifier-types"), exports);
29
+ __exportStar(require("./verifier-core"), exports);
30
+ __exportStar(require("./verification-report"), exports);
31
+ __exportStar(require("./ssrf-safe-fetch"), exports);
32
+ __exportStar(require("./transport-profiles"), exports);
33
+ __exportStar(require("./pointer-fetch"), exports);
27
34
  // Re-export crypto utilities for single-package quickstart
28
35
  var crypto_1 = require("@peac/crypto");
36
+ Object.defineProperty(exports, "base64urlDecode", { enumerable: true, get: function () { return crypto_1.base64urlDecode; } });
37
+ Object.defineProperty(exports, "base64urlEncode", { enumerable: true, get: function () { return crypto_1.base64urlEncode; } });
38
+ Object.defineProperty(exports, "computeJwkThumbprint", { enumerable: true, get: function () { return crypto_1.computeJwkThumbprint; } });
29
39
  Object.defineProperty(exports, "generateKeypair", { enumerable: true, get: function () { return crypto_1.generateKeypair; } });
40
+ Object.defineProperty(exports, "jwkToPublicKeyBytes", { enumerable: true, get: function () { return crypto_1.jwkToPublicKeyBytes; } });
41
+ Object.defineProperty(exports, "sha256Bytes", { enumerable: true, get: function () { return crypto_1.sha256Bytes; } });
42
+ Object.defineProperty(exports, "sha256Hex", { enumerable: true, get: function () { return crypto_1.sha256Hex; } });
30
43
  Object.defineProperty(exports, "verify", { enumerable: true, get: function () { return crypto_1.verify; } });
31
44
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;AACxB,2CAAyB;AACzB,iDAA+B;AAC/B,4CAA0B;AAC1B,8CAA4B;AAE5B,2DAA2D;AAC3D,uCAAuD;AAA9C,yGAAA,eAAe,OAAA;AAAE,gGAAA,MAAM,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;AACxB,2CAAyB;AACzB,iDAA+B;AAC/B,4CAA0B;AAC1B,8CAA4B;AAE5B,2BAA2B;AAC3B,mDAAiC;AACjC,kDAAgC;AAChC,wDAAsC;AACtC,oDAAkC;AAClC,uDAAqC;AACrC,kDAAgC;AAEhC,2DAA2D;AAC3D,uCASsB;AARpB,yGAAA,eAAe,OAAA;AACf,yGAAA,eAAe,OAAA;AACf,8GAAA,oBAAoB,OAAA;AACpB,yGAAA,eAAe,OAAA;AACf,6GAAA,mBAAmB,OAAA;AACnB,qGAAA,WAAW,OAAA;AACX,mGAAA,SAAS,OAAA;AACT,gGAAA,MAAM,OAAA"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * PEAC Pointer Fetch with Digest Verification
3
+ *
4
+ * Implements secure receipt fetching via pointers per TRANSPORT-PROFILES.md:
5
+ * - SSRF-safe fetch
6
+ * - SHA-256 digest verification
7
+ * - Size limits
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ import { type SSRFFetchOptions } from './ssrf-safe-fetch.js';
12
+ /**
13
+ * Pointer fetch options
14
+ */
15
+ export interface PointerFetchOptions {
16
+ /** URL to fetch the receipt from */
17
+ url: string;
18
+ /** Expected SHA-256 digest (lowercase hex, 64 chars) */
19
+ expectedDigest: string;
20
+ /** Optional SSRF fetch options */
21
+ fetchOptions?: Omit<SSRFFetchOptions, 'maxBytes'>;
22
+ }
23
+ /**
24
+ * Successful pointer fetch result
25
+ */
26
+ export interface PointerFetchSuccess {
27
+ ok: true;
28
+ /** Fetched receipt (JWS compact serialization) */
29
+ receipt: string;
30
+ /** Actual SHA-256 digest of fetched content */
31
+ actualDigest: string;
32
+ /** Whether digest matched expected */
33
+ digestMatched: true;
34
+ /** Content-Type header (if present) */
35
+ contentType?: string;
36
+ /**
37
+ * Warning about unexpected Content-Type.
38
+ * Present when Content-Type is not application/jose, application/json, or text/plain.
39
+ * Does not cause rejection (for interoperability) but callers may want to log.
40
+ */
41
+ contentTypeWarning?: string;
42
+ }
43
+ /**
44
+ * Failed pointer fetch result
45
+ */
46
+ export interface PointerFetchError {
47
+ ok: false;
48
+ /** Error reason */
49
+ reason: 'pointer_fetch_blocked' | 'pointer_fetch_failed' | 'pointer_fetch_timeout' | 'pointer_fetch_too_large' | 'pointer_digest_mismatch' | 'malformed_receipt';
50
+ /** Error code for reports */
51
+ errorCode: string;
52
+ /** Human-readable error message */
53
+ message: string;
54
+ /** Actual digest if computed (for mismatch errors) */
55
+ actualDigest?: string;
56
+ /** Expected digest */
57
+ expectedDigest?: string;
58
+ }
59
+ /**
60
+ * Pointer fetch result
61
+ */
62
+ export type PointerFetchResult = PointerFetchSuccess | PointerFetchError;
63
+ /**
64
+ * Fetch a receipt via pointer with digest verification
65
+ *
66
+ * Per TRANSPORT-PROFILES.md:
67
+ * - Fetch the URL using SSRF-safe fetch
68
+ * - Compute SHA-256 digest of response
69
+ * - Verify digest matches expected value from header
70
+ * - Return receipt only if digest matches
71
+ *
72
+ * @param options - Pointer fetch options
73
+ * @returns Fetch result
74
+ */
75
+ export declare function fetchPointerWithDigest(options: PointerFetchOptions): Promise<PointerFetchResult>;
76
+ /**
77
+ * Verify a pointer header and fetch the receipt
78
+ *
79
+ * Combines parsing and fetching in a single operation.
80
+ *
81
+ * @param pointerHeader - PEAC-Receipt-Pointer header value
82
+ * @param fetchOptions - Optional SSRF fetch options
83
+ * @returns Fetch result
84
+ */
85
+ export declare function verifyAndFetchPointer(pointerHeader: string, fetchOptions?: Omit<SSRFFetchOptions, 'maxBytes'>): Promise<PointerFetchResult>;
86
+ //# sourceMappingURL=pointer-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer-fetch.d.ts","sourceRoot":"","sources":["../src/pointer-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAiB,KAAK,gBAAgB,EAAuB,MAAM,sBAAsB,CAAC;AAMjG;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,cAAc,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,YAAY,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,IAAI,CAAC;IACT,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,aAAa,EAAE,IAAI,CAAC;IACpB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,KAAK,CAAC;IACV,mBAAmB;IACnB,MAAM,EACF,uBAAuB,GACvB,sBAAsB,GACtB,uBAAuB,GACvB,yBAAyB,GACzB,yBAAyB,GACzB,mBAAmB,CAAC;IACxB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AAwDzE;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA4G7B;AAyGD;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAChD,OAAO,CAAC,kBAAkB,CAAC,CA6B7B"}
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ /**
3
+ * PEAC Pointer Fetch with Digest Verification
4
+ *
5
+ * Implements secure receipt fetching via pointers per TRANSPORT-PROFILES.md:
6
+ * - SSRF-safe fetch
7
+ * - SHA-256 digest verification
8
+ * - Size limits
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.fetchPointerWithDigest = fetchPointerWithDigest;
14
+ exports.verifyAndFetchPointer = verifyAndFetchPointer;
15
+ const crypto_1 = require("@peac/crypto");
16
+ const kernel_1 = require("@peac/kernel");
17
+ const ssrf_safe_fetch_js_1 = require("./ssrf-safe-fetch.js");
18
+ // ---------------------------------------------------------------------------
19
+ // Error Mapping
20
+ // ---------------------------------------------------------------------------
21
+ /**
22
+ * Map SSRF error reason to pointer error reason
23
+ */
24
+ function mapSsrfError(ssrfError) {
25
+ const reason = ssrfError.reason;
26
+ switch (reason) {
27
+ case 'not_https':
28
+ case 'private_ip':
29
+ case 'loopback':
30
+ case 'link_local':
31
+ case 'dns_failure':
32
+ case 'cross_origin_redirect':
33
+ return {
34
+ ok: false,
35
+ reason: 'pointer_fetch_blocked',
36
+ errorCode: 'E_VERIFY_POINTER_FETCH_BLOCKED',
37
+ message: ssrfError.message,
38
+ };
39
+ case 'timeout':
40
+ return {
41
+ ok: false,
42
+ reason: 'pointer_fetch_timeout',
43
+ errorCode: 'E_VERIFY_POINTER_FETCH_TIMEOUT',
44
+ message: ssrfError.message,
45
+ };
46
+ case 'response_too_large':
47
+ return {
48
+ ok: false,
49
+ reason: 'pointer_fetch_too_large',
50
+ errorCode: 'E_VERIFY_POINTER_FETCH_TOO_LARGE',
51
+ message: ssrfError.message,
52
+ };
53
+ default:
54
+ return {
55
+ ok: false,
56
+ reason: 'pointer_fetch_failed',
57
+ errorCode: 'E_VERIFY_POINTER_FETCH_FAILED',
58
+ message: ssrfError.message,
59
+ };
60
+ }
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Pointer Fetch
64
+ // ---------------------------------------------------------------------------
65
+ /**
66
+ * Fetch a receipt via pointer with digest verification
67
+ *
68
+ * Per TRANSPORT-PROFILES.md:
69
+ * - Fetch the URL using SSRF-safe fetch
70
+ * - Compute SHA-256 digest of response
71
+ * - Verify digest matches expected value from header
72
+ * - Return receipt only if digest matches
73
+ *
74
+ * @param options - Pointer fetch options
75
+ * @returns Fetch result
76
+ */
77
+ async function fetchPointerWithDigest(options) {
78
+ const { url, expectedDigest, fetchOptions = {} } = options;
79
+ // Validate expected digest format
80
+ const hexRegex = /^[0-9a-f]{64}$/;
81
+ if (!hexRegex.test(expectedDigest)) {
82
+ return {
83
+ ok: false,
84
+ reason: 'pointer_fetch_failed',
85
+ errorCode: 'E_VERIFY_POINTER_FETCH_FAILED',
86
+ message: 'Invalid expected digest: must be 64 lowercase hex characters',
87
+ };
88
+ }
89
+ // Validate URL is HTTPS (pre-check before fetch)
90
+ try {
91
+ const parsedUrl = new URL(url);
92
+ if (parsedUrl.protocol !== 'https:') {
93
+ return {
94
+ ok: false,
95
+ reason: 'pointer_fetch_blocked',
96
+ errorCode: 'E_VERIFY_POINTER_FETCH_BLOCKED',
97
+ message: 'Pointer URL must use HTTPS',
98
+ };
99
+ }
100
+ }
101
+ catch {
102
+ return {
103
+ ok: false,
104
+ reason: 'pointer_fetch_failed',
105
+ errorCode: 'E_VERIFY_POINTER_FETCH_FAILED',
106
+ message: 'Invalid pointer URL',
107
+ };
108
+ }
109
+ // Fetch with SSRF protection and DoS bounds
110
+ // - Size cap: maxReceiptBytes (prevents memory exhaustion)
111
+ // - No redirects: prevents redirect-based SSRF (pointer URL must be direct)
112
+ // - Timeout: prevents slow-loris style attacks
113
+ const fetchResult = await (0, ssrf_safe_fetch_js_1.ssrfSafeFetch)(url, {
114
+ ...fetchOptions,
115
+ maxBytes: kernel_1.VERIFIER_LIMITS.maxReceiptBytes,
116
+ allowRedirects: false, // Pointer URL must be direct - no redirects
117
+ timeoutMs: fetchOptions?.timeoutMs ?? kernel_1.VERIFIER_LIMITS.fetchTimeoutMs,
118
+ headers: {
119
+ Accept: 'application/jose, application/json, text/plain',
120
+ ...fetchOptions.headers,
121
+ },
122
+ });
123
+ if (!fetchResult.ok) {
124
+ return mapSsrfError(fetchResult);
125
+ }
126
+ const receipt = fetchResult.body;
127
+ // Validate Content-Type if present (warn but don't reject for interoperability)
128
+ // Expected: application/jose, application/json, or text/plain
129
+ const contentType = fetchResult.contentType;
130
+ const expectedContentTypes = ['application/jose', 'application/json', 'text/plain'];
131
+ const contentTypeWarning = contentType && !expectedContentTypes.some((expected) => contentType.startsWith(expected))
132
+ ? `Unexpected Content-Type: ${contentType}; expected application/jose, application/json, or text/plain`
133
+ : undefined;
134
+ // Validate: reject empty body
135
+ if (!receipt || receipt.trim().length === 0) {
136
+ return {
137
+ ok: false,
138
+ reason: 'malformed_receipt',
139
+ errorCode: 'E_VERIFY_MALFORMED_RECEIPT',
140
+ message: 'Pointer target returned empty content',
141
+ };
142
+ }
143
+ // Validate: content must look like JWS compact serialization (3 dot-separated segments)
144
+ const jwsValidation = validateJwsCompactStructure(receipt);
145
+ if (!jwsValidation.valid) {
146
+ return {
147
+ ok: false,
148
+ reason: 'malformed_receipt',
149
+ errorCode: 'E_VERIFY_MALFORMED_RECEIPT',
150
+ message: jwsValidation.message,
151
+ };
152
+ }
153
+ // Compute digest of fetched content (hash the raw string bytes)
154
+ const actualDigest = await (0, crypto_1.sha256Hex)(receipt);
155
+ // Verify digest matches
156
+ if (actualDigest !== expectedDigest) {
157
+ return {
158
+ ok: false,
159
+ reason: 'pointer_digest_mismatch',
160
+ errorCode: 'E_VERIFY_POINTER_DIGEST_MISMATCH',
161
+ message: 'Fetched receipt digest does not match expected digest',
162
+ actualDigest,
163
+ expectedDigest,
164
+ };
165
+ }
166
+ return {
167
+ ok: true,
168
+ receipt,
169
+ actualDigest,
170
+ digestMatched: true,
171
+ contentType: fetchResult.contentType,
172
+ ...(contentTypeWarning && { contentTypeWarning }),
173
+ };
174
+ }
175
+ /**
176
+ * Validate that a string looks like JWS compact serialization
177
+ *
178
+ * A valid JWS compact has exactly 3 dot-separated base64url segments.
179
+ *
180
+ * @param value - String to validate
181
+ * @returns Validation result
182
+ */
183
+ function validateJwsCompactStructure(value) {
184
+ const segments = value.split('.');
185
+ if (segments.length !== 3) {
186
+ return {
187
+ valid: false,
188
+ message: `Invalid JWS compact serialization: expected 3 segments, got ${segments.length}`,
189
+ };
190
+ }
191
+ // All segments must be non-empty and contain only base64url characters
192
+ const base64urlRegex = /^[A-Za-z0-9_-]+$/;
193
+ for (let i = 0; i < segments.length; i++) {
194
+ const segment = segments[i];
195
+ if (segment.length === 0) {
196
+ return {
197
+ valid: false,
198
+ message: `Invalid JWS compact serialization: segment ${i + 1} is empty`,
199
+ };
200
+ }
201
+ if (!base64urlRegex.test(segment)) {
202
+ return {
203
+ valid: false,
204
+ message: `Invalid JWS compact serialization: segment ${i + 1} contains invalid characters`,
205
+ };
206
+ }
207
+ }
208
+ return { valid: true };
209
+ }
210
+ /**
211
+ * Parse pointer header key=value pairs (ReDoS-safe)
212
+ *
213
+ * Handles both quoted and unquoted values without complex regex alternation.
214
+ */
215
+ function parsePointerHeader(input) {
216
+ const params = {};
217
+ let i = 0;
218
+ const len = input.length;
219
+ while (i < len) {
220
+ // Skip whitespace and commas
221
+ while (i < len && (input[i] === ' ' || input[i] === ',' || input[i] === '\t')) {
222
+ i++;
223
+ }
224
+ if (i >= len)
225
+ break;
226
+ // Parse key (word characters only)
227
+ const keyStart = i;
228
+ while (i < len && /\w/.test(input[i])) {
229
+ i++;
230
+ }
231
+ const key = input.slice(keyStart, i);
232
+ if (!key)
233
+ break;
234
+ // Skip whitespace before '='
235
+ while (i < len && input[i] === ' ')
236
+ i++;
237
+ // Expect '='
238
+ if (i >= len || input[i] !== '=')
239
+ break;
240
+ i++; // skip '='
241
+ // Skip whitespace after '='
242
+ while (i < len && input[i] === ' ')
243
+ i++;
244
+ // Parse value (quoted or unquoted)
245
+ let value;
246
+ if (input[i] === '"') {
247
+ // Quoted value - find closing quote
248
+ i++; // skip opening quote
249
+ const valueStart = i;
250
+ while (i < len && input[i] !== '"') {
251
+ i++;
252
+ }
253
+ value = input.slice(valueStart, i);
254
+ if (i < len)
255
+ i++; // skip closing quote
256
+ }
257
+ else {
258
+ // Unquoted value - read until comma or whitespace
259
+ const valueStart = i;
260
+ while (i < len && input[i] !== ',' && input[i] !== ' ' && input[i] !== '\t') {
261
+ i++;
262
+ }
263
+ value = input.slice(valueStart, i);
264
+ }
265
+ params[key] = value;
266
+ }
267
+ return params;
268
+ }
269
+ /**
270
+ * Verify a pointer header and fetch the receipt
271
+ *
272
+ * Combines parsing and fetching in a single operation.
273
+ *
274
+ * @param pointerHeader - PEAC-Receipt-Pointer header value
275
+ * @param fetchOptions - Optional SSRF fetch options
276
+ * @returns Fetch result
277
+ */
278
+ async function verifyAndFetchPointer(pointerHeader, fetchOptions) {
279
+ // Parse pointer header (RFC 8941 dictionary format)
280
+ // Format: sha256="<hex>", url="<url>"
281
+ // Using explicit parsing to avoid ReDoS in regex alternation
282
+ const params = parsePointerHeader(pointerHeader);
283
+ if (!params.sha256) {
284
+ return {
285
+ ok: false,
286
+ reason: 'pointer_fetch_failed',
287
+ errorCode: 'E_VERIFY_POINTER_FETCH_FAILED',
288
+ message: 'PEAC-Receipt-Pointer missing sha256 parameter',
289
+ };
290
+ }
291
+ if (!params.url) {
292
+ return {
293
+ ok: false,
294
+ reason: 'pointer_fetch_failed',
295
+ errorCode: 'E_VERIFY_POINTER_FETCH_FAILED',
296
+ message: 'PEAC-Receipt-Pointer missing url parameter',
297
+ };
298
+ }
299
+ return fetchPointerWithDigest({
300
+ url: params.url,
301
+ expectedDigest: params.sha256,
302
+ fetchOptions,
303
+ });
304
+ }
305
+ //# sourceMappingURL=pointer-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer-fetch.js","sourceRoot":"","sources":["../src/pointer-fetch.ts"],"names":[],"mappings":"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"}