@shipfox/api-auth 19.0.0 → 20.0.0

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.
Files changed (86) hide show
  1. package/.turbo/turbo-build.log +17 -2
  2. package/CHANGELOG.md +13 -0
  3. package/dist/core/cimd.d.ts +39 -0
  4. package/dist/core/cimd.d.ts.map +1 -0
  5. package/dist/core/cimd.js +392 -0
  6. package/dist/core/cimd.js.map +1 -0
  7. package/dist/core/errors.d.ts +14 -0
  8. package/dist/core/errors.d.ts.map +1 -1
  9. package/dist/core/errors.js +26 -0
  10. package/dist/core/errors.js.map +1 -1
  11. package/dist/core/oauth-client-resolver.d.ts +54 -0
  12. package/dist/core/oauth-client-resolver.d.ts.map +1 -0
  13. package/dist/core/oauth-client-resolver.js +154 -0
  14. package/dist/core/oauth-client-resolver.js.map +1 -0
  15. package/dist/core/oauth-client.d.ts +39 -0
  16. package/dist/core/oauth-client.d.ts.map +1 -0
  17. package/dist/core/oauth-client.js +236 -0
  18. package/dist/core/oauth-client.js.map +1 -0
  19. package/dist/db/agent-access-retention.d.ts +10 -0
  20. package/dist/db/agent-access-retention.d.ts.map +1 -0
  21. package/dist/db/agent-access-retention.js +11 -0
  22. package/dist/db/agent-access-retention.js.map +1 -0
  23. package/dist/db/agent-access.d.ts +100 -4
  24. package/dist/db/agent-access.d.ts.map +1 -1
  25. package/dist/db/agent-access.js +483 -45
  26. package/dist/db/agent-access.js.map +1 -1
  27. package/dist/index.d.ts +9 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +25 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/metrics/instance.d.ts +1 -1
  32. package/dist/metrics/instance.d.ts.map +1 -1
  33. package/dist/metrics/instance.js.map +1 -1
  34. package/dist/presentation/routes/oauth.d.ts +9 -0
  35. package/dist/presentation/routes/oauth.d.ts.map +1 -0
  36. package/dist/presentation/routes/oauth.js +150 -0
  37. package/dist/presentation/routes/oauth.js.map +1 -0
  38. package/dist/presentation/routes/rate-limit.d.ts.map +1 -1
  39. package/dist/presentation/routes/rate-limit.js +24 -0
  40. package/dist/presentation/routes/rate-limit.js.map +1 -1
  41. package/dist/temporal/activities/agent-access-retention.d.ts +13 -0
  42. package/dist/temporal/activities/agent-access-retention.d.ts.map +1 -0
  43. package/dist/temporal/activities/agent-access-retention.js +58 -0
  44. package/dist/temporal/activities/agent-access-retention.js.map +1 -0
  45. package/dist/temporal/activities/index.d.ts +5 -0
  46. package/dist/temporal/activities/index.d.ts.map +1 -0
  47. package/dist/temporal/activities/index.js +8 -0
  48. package/dist/temporal/activities/index.js.map +1 -0
  49. package/dist/temporal/constants.d.ts +2 -0
  50. package/dist/temporal/constants.d.ts.map +1 -0
  51. package/dist/temporal/constants.js +3 -0
  52. package/dist/temporal/constants.js.map +1 -0
  53. package/dist/temporal/workflows/agent-access-retention-cron.d.ts +2 -0
  54. package/dist/temporal/workflows/agent-access-retention-cron.d.ts.map +1 -0
  55. package/dist/temporal/workflows/agent-access-retention-cron.js +22 -0
  56. package/dist/temporal/workflows/agent-access-retention-cron.js.map +1 -0
  57. package/dist/temporal/workflows/index.bundle.js +25227 -0
  58. package/dist/temporal/workflows/index.bundle.meta.json +1 -0
  59. package/dist/temporal/workflows/index.d.ts +2 -0
  60. package/dist/temporal/workflows/index.d.ts.map +1 -0
  61. package/dist/temporal/workflows/index.js +3 -0
  62. package/dist/temporal/workflows/index.js.map +1 -0
  63. package/dist/tsconfig.test.tsbuildinfo +1 -1
  64. package/package.json +7 -4
  65. package/src/core/cimd.test.ts +213 -0
  66. package/src/core/cimd.ts +532 -0
  67. package/src/core/errors.ts +41 -0
  68. package/src/core/oauth-client-resolver.test.ts +198 -0
  69. package/src/core/oauth-client-resolver.ts +253 -0
  70. package/src/core/oauth-client.test.ts +157 -0
  71. package/src/core/oauth-client.ts +331 -0
  72. package/src/db/agent-access-retention.ts +10 -0
  73. package/src/db/agent-access.test.ts +697 -3
  74. package/src/db/agent-access.ts +953 -91
  75. package/src/index.test.ts +27 -0
  76. package/src/index.ts +76 -0
  77. package/src/metrics/instance.ts +5 -1
  78. package/src/presentation/routes/oauth.test.ts +133 -0
  79. package/src/presentation/routes/oauth.ts +144 -0
  80. package/src/presentation/routes/rate-limit.ts +12 -0
  81. package/src/temporal/activities/agent-access-retention.ts +76 -0
  82. package/src/temporal/activities/index.ts +5 -0
  83. package/src/temporal/constants.ts +1 -0
  84. package/src/temporal/workflows/agent-access-retention-cron.ts +23 -0
  85. package/src/temporal/workflows/index.ts +1 -0
  86. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,2 +1,17 @@
1
- $ shipfox-swc
2
- Successfully compiled: 71 files with swc (374.15ms)
1
+ $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
+ Successfully compiled: 81 files with swc (682.49ms)
3
+ 2026-09-01T17:20:29.875Z [INFO] asset workflow-bundle-ae57bfa63e4e4f961c52.js 3.17 MiB [emitted] [immutable] (name: main)
4
+ orphan modules 33.5 KiB [orphan] 21 modules
5
+ runtime modules 1.13 KiB 5 modules
6
+ modules by path ../../../node_modules/.pnpm/ 970 KiB 196 modules
7
+ modules by path ./dist/temporal/workflows/ 1.73 KiB
8
+ ./dist/temporal/workflows/index-autogenerated-entrypoint.cjs 929 bytes [built] [code generated]
9
+ ./dist/temporal/workflows/index.js 78 bytes [built] [code generated]
10
+ ./dist/temporal/workflows/agent-access-retention-cron.js 760 bytes [built] [code generated]
11
+ optional modules 30 bytes [optional]
12
+ __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
13
+ __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
14
+ ../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
15
+ webpack 5.107.2 compiled successfully in 6621 ms
16
+ 2026-09-01T17:20:29.910Z [INFO] Workflow bundle created { size: '3.17MB' }
17
+ /home/runner/work/shipfox/shipfox/libs/api/auth/dist/temporal/workflows/index.js: 3320534 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @shipfox/api-auth
2
2
 
3
+ ## 20.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9113421: Add MCP OAuth discovery, public-client registration, and Client ID Metadata Document resolution for the read-only profile.
8
+ - 05dc593: Add agent credential rotation, grant lifecycle transitions, and bounded credential retention.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [9113421]
13
+ - @shipfox/api-auth-dto@20.0.0
14
+ - @shipfox/api-auth-context@20.0.0
15
+
3
16
  ## 19.0.0
4
17
 
5
18
  ### Minor Changes
@@ -0,0 +1,39 @@
1
+ import type { ValidatedOAuthClientMetadata } from './oauth-client.js';
2
+ export declare const OAUTH_CIMD_MAX_BODY_BYTES: number;
3
+ export declare const OAUTH_CIMD_FETCH_TIMEOUT_MS = 5000;
4
+ export interface CimdAddress {
5
+ address: string;
6
+ family: 4 | 6;
7
+ }
8
+ export interface CimdHttpResponse {
9
+ statusCode: number;
10
+ headers: Record<string, string | string[] | undefined>;
11
+ body: Uint8Array;
12
+ }
13
+ export type CimdAddressResolver = (hostname: string) => Promise<readonly CimdAddress[]>;
14
+ export type CimdHttpRequester = (params: {
15
+ url: URL;
16
+ address: CimdAddress;
17
+ timeoutMs: number;
18
+ maxBodyBytes: number;
19
+ signal?: AbortSignal;
20
+ }) => Promise<CimdHttpResponse>;
21
+ export interface FetchedCimdMetadata {
22
+ metadata: ValidatedOAuthClientMetadata;
23
+ cacheMaxAgeSeconds: number;
24
+ }
25
+ /** Returns true only for a globally routable unicast address. */
26
+ export declare function isPublicUnicastAddress(address: string, family?: 4 | 6): boolean;
27
+ export interface FetchCimdMetadataOptions {
28
+ resolveAddress?: CimdAddressResolver;
29
+ request?: CimdHttpRequester;
30
+ timeoutMs?: number;
31
+ maxBodyBytes?: number;
32
+ }
33
+ /**
34
+ * Fetches a Client ID Metadata Document after resolving and pinning a public
35
+ * address. This deliberately does not share the general egress helper: CIMD
36
+ * has stricter public-only, no-redirect, and no-credential requirements.
37
+ */
38
+ export declare function fetchClientIdMetadata(clientId: string, options?: FetchCimdMetadataOptions): Promise<FetchedCimdMetadata>;
39
+ //# sourceMappingURL=cimd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cimd.d.ts","sourceRoot":"","sources":["../../src/core/cimd.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,mBAAmB,CAAC;AAOpE,eAAO,MAAM,yBAAyB,QAAa,CAAC;AACpD,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AAYjD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAAC;AACxF,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IACvC,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAEhC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,4BAA4B,CAAC;IACvC,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AA6HD,iEAAiE;AACjE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAM/E;AAoSD,MAAM,WAAW,wBAAwB;IACvC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,mBAAmB,CAAC,CA2C9B"}
@@ -0,0 +1,392 @@
1
+ import { promises as dnsPromises } from 'node:dns';
2
+ import { request as httpsRequest } from 'node:https';
3
+ import { isIP } from 'node:net';
4
+ import { oauthClientMetadataDocumentSchema } from '@shipfox/api-auth-dto';
5
+ import { InvalidOAuthClientMetadataError, OAuthMetadataFetchError } from './errors.js';
6
+ import { OAUTH_CIMD_CACHE_MAX_AGE_SECONDS, validateOAuthClientId, validateOAuthClientMetadataDocument } from './oauth-client.js';
7
+ export const OAUTH_CIMD_MAX_BODY_BYTES = 256 * 1024;
8
+ export const OAUTH_CIMD_FETCH_TIMEOUT_MS = 5_000;
9
+ const DECIMAL_RE = /^\d+$/u;
10
+ const IPV6_GROUP_RE = /^[0-9a-f]{1,4}$/u;
11
+ let CimdTimeoutError = class CimdTimeoutError extends Error {
12
+ constructor(){
13
+ super('CIMD fetch timed out');
14
+ this.name = 'CimdTimeoutError';
15
+ }
16
+ };
17
+ function metadataFetchError(reason, cause) {
18
+ return new OAuthMetadataFetchError(reason, cause);
19
+ }
20
+ function ipv4ToNumber(value) {
21
+ const parts = value.split('.');
22
+ if (parts.length !== 4) return undefined;
23
+ let result = 0;
24
+ for (const part of parts){
25
+ if (!DECIMAL_RE.test(part)) return undefined;
26
+ const octet = Number(part);
27
+ if (!Number.isInteger(octet) || octet > 255) return undefined;
28
+ result = result * 256 + octet;
29
+ }
30
+ return result >>> 0;
31
+ }
32
+ function inIpv4Range(value, start, end) {
33
+ return value >= start && value <= end;
34
+ }
35
+ function isPublicIpv4(value) {
36
+ const address = ipv4ToNumber(value);
37
+ if (address === undefined) return false;
38
+ return !(inIpv4Range(address, 0x00000000, 0x00ffffff) || // 0.0.0.0/8
39
+ inIpv4Range(address, 0x0a000000, 0x0affffff) || // 10.0.0.0/8
40
+ inIpv4Range(address, 0x64400000, 0x647fffff) || // 100.64.0.0/10
41
+ inIpv4Range(address, 0x7f000000, 0x7fffffff) || // 127.0.0.0/8
42
+ inIpv4Range(address, 0xa9fe0000, 0xa9feffff) || // 169.254.0.0/16
43
+ inIpv4Range(address, 0xac100000, 0xac1fffff) || // 172.16.0.0/12
44
+ inIpv4Range(address, 0xc0000000, 0xc00000ff) || // 192.0.0.0/24
45
+ inIpv4Range(address, 0xc0000200, 0xc00002ff) || // 192.0.2.0/24
46
+ inIpv4Range(address, 0xc01fc400, 0xc01fc4ff) || // 192.31.196.0/24
47
+ inIpv4Range(address, 0xc034c100, 0xc034c1ff) || // 192.52.193.0/24
48
+ inIpv4Range(address, 0xc0586300, 0xc05863ff) || // 192.88.99.0/24
49
+ inIpv4Range(address, 0xc0a80000, 0xc0a8ffff) || // 192.168.0.0/16
50
+ inIpv4Range(address, 0xc0af3000, 0xc0af30ff) || // 192.175.48.0/24
51
+ inIpv4Range(address, 0xc6120000, 0xc613ffff) || // 198.18.0.0/15
52
+ inIpv4Range(address, 0xc6336400, 0xc63364ff) || // 198.51.100.0/24
53
+ inIpv4Range(address, 0xcb007100, 0xcb0071ff) || // 203.0.113.0/24
54
+ inIpv4Range(address, 0xe0000000, 0xffffffff) // multicast, reserved, broadcast
55
+ );
56
+ }
57
+ function parseIpv6(value) {
58
+ if (value.includes('%')) return undefined;
59
+ const input = expandEmbeddedIpv4(value.toLowerCase());
60
+ if (input === undefined) return undefined;
61
+ const parts = splitIpv6Groups(input);
62
+ if (parts === undefined) return undefined;
63
+ const { left, right, hasCompression } = parts;
64
+ const groups = hasCompression ? [
65
+ ...left,
66
+ ...Array(8 - left.length - right.length).fill('0'),
67
+ ...right
68
+ ] : [
69
+ ...left,
70
+ ...right
71
+ ];
72
+ if (groups.length !== 8) return undefined;
73
+ return groups.map((part)=>BigInt(`0x${part}`));
74
+ }
75
+ function expandEmbeddedIpv4(value) {
76
+ if (!value.includes('.')) return value;
77
+ const lastColon = value.lastIndexOf(':');
78
+ if (lastColon < 0) return undefined;
79
+ const ipv4 = ipv4ToNumber(value.slice(lastColon + 1));
80
+ if (ipv4 === undefined) return undefined;
81
+ const high = (ipv4 >>> 16 & 0xffff).toString(16);
82
+ const low = (ipv4 & 0xffff).toString(16);
83
+ return `${value.slice(0, lastColon)}:${high}:${low}`;
84
+ }
85
+ function splitIpv6Groups(value) {
86
+ const compressionStart = value.indexOf('::');
87
+ if (compressionStart !== -1 && compressionStart !== value.lastIndexOf('::')) {
88
+ return undefined;
89
+ }
90
+ const hasCompression = compressionStart !== -1;
91
+ const [leftText, rightText = ''] = value.split('::');
92
+ const left = leftText ? leftText.split(':') : [];
93
+ const right = rightText ? rightText.split(':') : [];
94
+ if (left.some((part)=>!IPV6_GROUP_RE.test(part))) return undefined;
95
+ if (right.some((part)=>!IPV6_GROUP_RE.test(part))) return undefined;
96
+ if (!hasCompression && left.length + right.length !== 8) return undefined;
97
+ if (hasCompression && left.length + right.length >= 8) return undefined;
98
+ return {
99
+ hasCompression,
100
+ left,
101
+ right
102
+ };
103
+ }
104
+ function isPublicIpv6(value) {
105
+ const groups = parseIpv6(value);
106
+ if (!groups) return false;
107
+ const first = Number(groups[0]);
108
+ if (first < 0x2000 || first > 0x3fff) return false;
109
+ // Keep documentation, benchmarking, transition, and other special-use
110
+ // prefixes out of a fetch path even when a resolver returns a routable one.
111
+ if (first === 0x2001) {
112
+ const second = Number(groups[1]);
113
+ if (second === 0x0000 || second === 0x0002 || second >= 0x0010 && second <= 0x002f || second >= 0x0db8 && second <= 0x0dbf) {
114
+ return false;
115
+ }
116
+ }
117
+ if (first === 0x2002 || first === 0x3fff) return false;
118
+ return true;
119
+ }
120
+ /** Returns true only for a globally routable unicast address. */ export function isPublicUnicastAddress(address, family) {
121
+ const normalized = address.replace(/^\[|\]$/gu, '');
122
+ const detectedFamily = family ?? isIP(normalized);
123
+ if (detectedFamily === 4) return isPublicIpv4(normalized);
124
+ if (detectedFamily === 6) return isPublicIpv6(normalized);
125
+ return false;
126
+ }
127
+ function normalizeHostname(url) {
128
+ return url.hostname.replace(/^\[|\]$/gu, '');
129
+ }
130
+ async function resolvePublicAddress(hostname) {
131
+ if (isIP(hostname) === 4 || isIP(hostname) === 6) {
132
+ const family = isIP(hostname);
133
+ if (!isPublicUnicastAddress(hostname, family)) {
134
+ throw metadataFetchError('private-address');
135
+ }
136
+ return [
137
+ {
138
+ address: hostname,
139
+ family
140
+ }
141
+ ];
142
+ }
143
+ let resolved;
144
+ try {
145
+ resolved = await dnsPromises.lookup(hostname, {
146
+ all: true,
147
+ verbatim: true
148
+ });
149
+ } catch (error) {
150
+ throw metadataFetchError('dns-failed', error);
151
+ }
152
+ if (resolved.length === 0) throw metadataFetchError('dns-failed');
153
+ const addresses = resolved.map((entry)=>({
154
+ address: entry.address,
155
+ family: entry.family
156
+ }));
157
+ if (addresses.some((entry)=>entry.family !== 4 && entry.family !== 6 || !isPublicUnicastAddress(entry.address, entry.family))) {
158
+ throw metadataFetchError('private-address');
159
+ }
160
+ return addresses;
161
+ }
162
+ function headerValue(headers, name) {
163
+ const normalizedName = name.toLowerCase();
164
+ const headerName = Object.keys(headers).find((key)=>key.toLowerCase() === normalizedName);
165
+ const value = headerName === undefined ? undefined : headers[headerName];
166
+ if (Array.isArray(value)) return value.join(', ');
167
+ return value;
168
+ }
169
+ function parseCacheMaxAge(headers) {
170
+ const cacheControl = headerValue(headers, 'cache-control');
171
+ if (!cacheControl) return OAUTH_CIMD_CACHE_MAX_AGE_SECONDS;
172
+ let maxAge;
173
+ for (const directive of cacheControl.split(',')){
174
+ const [rawName, rawValue] = directive.trim().split('=', 2);
175
+ const name = rawName?.trim().toLowerCase();
176
+ if (name === 'no-store' || name === 'no-cache') return 0;
177
+ if (name === 'max-age' && rawValue !== undefined && DECIMAL_RE.test(rawValue.trim())) {
178
+ maxAge = Number(rawValue.trim());
179
+ }
180
+ }
181
+ return Math.min(maxAge ?? OAUTH_CIMD_CACHE_MAX_AGE_SECONDS, OAUTH_CIMD_CACHE_MAX_AGE_SECONDS);
182
+ }
183
+ function withTimeout(promise, timeoutMs, onTimeout) {
184
+ return new Promise((resolve, reject)=>{
185
+ let settled = false;
186
+ const timer = setTimeout(()=>{
187
+ if (settled) return;
188
+ settled = true;
189
+ onTimeout?.();
190
+ reject(new CimdTimeoutError());
191
+ }, timeoutMs);
192
+ promise.then((value)=>{
193
+ if (settled) return;
194
+ settled = true;
195
+ clearTimeout(timer);
196
+ resolve(value);
197
+ }, (error)=>{
198
+ if (settled) return;
199
+ settled = true;
200
+ clearTimeout(timer);
201
+ reject(error);
202
+ });
203
+ });
204
+ }
205
+ function requestPinnedHttps(params) {
206
+ return new Promise((resolve, reject)=>{
207
+ const hostname = normalizeHostname(params.url);
208
+ let settled = false;
209
+ const fail = (error)=>{
210
+ if (settled) return;
211
+ settled = true;
212
+ reject(error);
213
+ };
214
+ const succeed = (response)=>{
215
+ if (settled) return;
216
+ settled = true;
217
+ resolve(response);
218
+ };
219
+ if (params.url.protocol !== 'https:' || params.url.username || params.url.password) {
220
+ fail(metadataFetchError('invalid-url'));
221
+ return;
222
+ }
223
+ const request = httpsRequest({
224
+ hostname,
225
+ port: params.url.port || 443,
226
+ path: `${params.url.pathname || '/'}${params.url.search}`,
227
+ method: 'GET',
228
+ headers: {
229
+ accept: 'application/json'
230
+ },
231
+ rejectUnauthorized: true,
232
+ servername: hostname,
233
+ timeout: params.timeoutMs,
234
+ signal: params.signal,
235
+ // The address was resolved before this request and is the only value
236
+ // the TLS connection is allowed to use.
237
+ lookup: (_lookupHostname, _options, callback)=>{
238
+ callback(null, params.address.address, params.address.family);
239
+ }
240
+ }, (response)=>{
241
+ handleCimdResponse(response, params.maxBodyBytes, fail, succeed);
242
+ });
243
+ request.once('error', (error)=>fail(error));
244
+ request.once('timeout', ()=>{
245
+ request.destroy();
246
+ fail(metadataFetchError('timeout'));
247
+ });
248
+ request.end();
249
+ });
250
+ }
251
+ function responseHeaderError(statusCode, headers, maxBodyBytes) {
252
+ if (statusCode !== undefined && statusCode >= 300 && statusCode < 400) {
253
+ return metadataFetchError('redirected');
254
+ }
255
+ const contentLength = headerValue(headers, 'content-length');
256
+ if (contentLength !== undefined) {
257
+ if (!DECIMAL_RE.test(contentLength.trim())) return metadataFetchError('invalid-response');
258
+ if (Number(contentLength) > maxBodyBytes) return metadataFetchError('response-too-large');
259
+ }
260
+ const contentEncoding = headerValue(headers, 'content-encoding');
261
+ if (contentEncoding && contentEncoding.toLowerCase() !== 'identity') {
262
+ return metadataFetchError('invalid-response');
263
+ }
264
+ return undefined;
265
+ }
266
+ function readCimdResponseBody(response, maxBodyBytes) {
267
+ return new Promise((resolve, reject)=>{
268
+ const chunks = [];
269
+ let size = 0;
270
+ response.on('data', (chunk)=>{
271
+ const buffer = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
272
+ size += buffer.byteLength;
273
+ if (size > maxBodyBytes) {
274
+ response.destroy();
275
+ reject(metadataFetchError('response-too-large'));
276
+ return;
277
+ }
278
+ chunks.push(buffer);
279
+ });
280
+ response.once('error', reject);
281
+ response.once('end', ()=>resolve(Buffer.concat(chunks)));
282
+ });
283
+ }
284
+ function handleCimdResponse(response, maxBodyBytes, fail, succeed) {
285
+ const headers = response.headers;
286
+ const headerError = responseHeaderError(response.statusCode, headers, maxBodyBytes);
287
+ if (headerError) {
288
+ response.destroy();
289
+ fail(headerError);
290
+ return;
291
+ }
292
+ void readCimdResponseBody(response, maxBodyBytes).then((body)=>succeed({
293
+ statusCode: response.statusCode ?? 0,
294
+ headers,
295
+ body
296
+ }), fail);
297
+ }
298
+ function parseCimdDocument(body, clientId) {
299
+ let parsed;
300
+ try {
301
+ parsed = JSON.parse(Buffer.from(body).toString('utf8'));
302
+ } catch {
303
+ throw new InvalidOAuthClientMetadataError();
304
+ }
305
+ const result = oauthClientMetadataDocumentSchema.safeParse(parsed);
306
+ if (!result.success) throw new InvalidOAuthClientMetadataError();
307
+ return validateOAuthClientMetadataDocument(result.data, clientId);
308
+ }
309
+ async function resolvePinnedAddresses(hostname, resolveAddress, timeoutMs) {
310
+ let resolved;
311
+ try {
312
+ resolved = await withTimeout(resolveAddress(hostname), timeoutMs);
313
+ } catch (error) {
314
+ if (error instanceof OAuthMetadataFetchError) throw error;
315
+ if (error instanceof CimdTimeoutError) throw metadataFetchError('timeout', error);
316
+ throw metadataFetchError('dns-failed', error);
317
+ }
318
+ if (resolved.length === 0) throw metadataFetchError('dns-failed');
319
+ if (resolved.some((entry)=>entry.family !== 4 && entry.family !== 6 || !isPublicUnicastAddress(entry.address, entry.family))) {
320
+ throw metadataFetchError('private-address');
321
+ }
322
+ return resolved;
323
+ }
324
+ async function requestCimdResponse(params) {
325
+ const abortController = new AbortController();
326
+ try {
327
+ return await withTimeout(params.request({
328
+ url: params.url,
329
+ address: params.address,
330
+ timeoutMs: params.timeoutMs,
331
+ maxBodyBytes: params.maxBodyBytes,
332
+ signal: abortController.signal
333
+ }), params.timeoutMs, ()=>abortController.abort());
334
+ } catch (error) {
335
+ if (error instanceof OAuthMetadataFetchError) throw error;
336
+ if (error instanceof CimdTimeoutError) throw metadataFetchError('timeout', error);
337
+ throw metadataFetchError('connection-failed', error);
338
+ }
339
+ }
340
+ function remainingTimeout(deadlineMs) {
341
+ const timeoutMs = deadlineMs - Date.now();
342
+ if (timeoutMs <= 0) throw metadataFetchError('timeout');
343
+ return timeoutMs;
344
+ }
345
+ function assertCimdResponse(response, maxBodyBytes) {
346
+ const headerError = responseHeaderError(response.statusCode, response.headers, maxBodyBytes);
347
+ if (headerError) throw headerError;
348
+ if (response.statusCode !== 200) throw metadataFetchError('invalid-response');
349
+ if (response.body.byteLength > maxBodyBytes) {
350
+ throw metadataFetchError('response-too-large');
351
+ }
352
+ }
353
+ /**
354
+ * Fetches a Client ID Metadata Document after resolving and pinning a public
355
+ * address. This deliberately does not share the general egress helper: CIMD
356
+ * has stricter public-only, no-redirect, and no-credential requirements.
357
+ */ export async function fetchClientIdMetadata(clientId, options = {}) {
358
+ const url = validateOAuthClientId(clientId);
359
+ const timeoutMs = options.timeoutMs ?? OAUTH_CIMD_FETCH_TIMEOUT_MS;
360
+ const maxBodyBytes = options.maxBodyBytes ?? OAUTH_CIMD_MAX_BODY_BYTES;
361
+ const resolveAddress = options.resolveAddress ?? resolvePublicAddress;
362
+ const request = options.request ?? requestPinnedHttps;
363
+ const hostname = normalizeHostname(url);
364
+ const deadlineMs = Date.now() + timeoutMs;
365
+ const addresses = await resolvePinnedAddresses(hostname, resolveAddress, remainingTimeout(deadlineMs));
366
+ let lastConnectionError;
367
+ for (const [index, address] of addresses.entries()){
368
+ try {
369
+ const response = await requestCimdResponse({
370
+ url,
371
+ address,
372
+ request,
373
+ timeoutMs: remainingTimeout(deadlineMs),
374
+ maxBodyBytes
375
+ });
376
+ assertCimdResponse(response, maxBodyBytes);
377
+ return {
378
+ metadata: parseCimdDocument(response.body, clientId),
379
+ cacheMaxAgeSeconds: parseCacheMaxAge(response.headers)
380
+ };
381
+ } catch (error) {
382
+ if (error instanceof OAuthMetadataFetchError && error.reason === 'connection-failed' && index < addresses.length - 1) {
383
+ lastConnectionError = error;
384
+ continue;
385
+ }
386
+ throw error;
387
+ }
388
+ }
389
+ throw lastConnectionError ?? metadataFetchError('connection-failed');
390
+ }
391
+
392
+ //# sourceMappingURL=cimd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/cimd.ts"],"sourcesContent":["import {promises as dnsPromises} from 'node:dns';\nimport type {IncomingMessage} from 'node:http';\nimport {request as httpsRequest} from 'node:https';\nimport {isIP} from 'node:net';\nimport {oauthClientMetadataDocumentSchema} from '@shipfox/api-auth-dto';\nimport {InvalidOAuthClientMetadataError, OAuthMetadataFetchError} from './errors.js';\nimport type {ValidatedOAuthClientMetadata} from './oauth-client.js';\nimport {\n OAUTH_CIMD_CACHE_MAX_AGE_SECONDS,\n validateOAuthClientId,\n validateOAuthClientMetadataDocument,\n} from './oauth-client.js';\n\nexport const OAUTH_CIMD_MAX_BODY_BYTES = 256 * 1024;\nexport const OAUTH_CIMD_FETCH_TIMEOUT_MS = 5_000;\n\nconst DECIMAL_RE = /^\\d+$/u;\nconst IPV6_GROUP_RE = /^[0-9a-f]{1,4}$/u;\n\nclass CimdTimeoutError extends Error {\n constructor() {\n super('CIMD fetch timed out');\n this.name = 'CimdTimeoutError';\n }\n}\n\nexport interface CimdAddress {\n address: string;\n family: 4 | 6;\n}\n\nexport interface CimdHttpResponse {\n statusCode: number;\n headers: Record<string, string | string[] | undefined>;\n body: Uint8Array;\n}\n\nexport type CimdAddressResolver = (hostname: string) => Promise<readonly CimdAddress[]>;\nexport type CimdHttpRequester = (params: {\n url: URL;\n address: CimdAddress;\n timeoutMs: number;\n maxBodyBytes: number;\n signal?: AbortSignal;\n}) => Promise<CimdHttpResponse>;\n\nexport interface FetchedCimdMetadata {\n metadata: ValidatedOAuthClientMetadata;\n cacheMaxAgeSeconds: number;\n}\n\nfunction metadataFetchError(\n reason: OAuthMetadataFetchError['reason'],\n cause?: unknown,\n): OAuthMetadataFetchError {\n return new OAuthMetadataFetchError(reason, cause);\n}\n\nfunction ipv4ToNumber(value: string): number | undefined {\n const parts = value.split('.');\n if (parts.length !== 4) return undefined;\n let result = 0;\n for (const part of parts) {\n if (!DECIMAL_RE.test(part)) return undefined;\n const octet = Number(part);\n if (!Number.isInteger(octet) || octet > 255) return undefined;\n result = result * 256 + octet;\n }\n return result >>> 0;\n}\n\nfunction inIpv4Range(value: number, start: number, end: number): boolean {\n return value >= start && value <= end;\n}\n\nfunction isPublicIpv4(value: string): boolean {\n const address = ipv4ToNumber(value);\n if (address === undefined) return false;\n return !(\n (\n inIpv4Range(address, 0x00000000, 0x00ffffff) || // 0.0.0.0/8\n inIpv4Range(address, 0x0a000000, 0x0affffff) || // 10.0.0.0/8\n inIpv4Range(address, 0x64400000, 0x647fffff) || // 100.64.0.0/10\n inIpv4Range(address, 0x7f000000, 0x7fffffff) || // 127.0.0.0/8\n inIpv4Range(address, 0xa9fe0000, 0xa9feffff) || // 169.254.0.0/16\n inIpv4Range(address, 0xac100000, 0xac1fffff) || // 172.16.0.0/12\n inIpv4Range(address, 0xc0000000, 0xc00000ff) || // 192.0.0.0/24\n inIpv4Range(address, 0xc0000200, 0xc00002ff) || // 192.0.2.0/24\n inIpv4Range(address, 0xc01fc400, 0xc01fc4ff) || // 192.31.196.0/24\n inIpv4Range(address, 0xc034c100, 0xc034c1ff) || // 192.52.193.0/24\n inIpv4Range(address, 0xc0586300, 0xc05863ff) || // 192.88.99.0/24\n inIpv4Range(address, 0xc0a80000, 0xc0a8ffff) || // 192.168.0.0/16\n inIpv4Range(address, 0xc0af3000, 0xc0af30ff) || // 192.175.48.0/24\n inIpv4Range(address, 0xc6120000, 0xc613ffff) || // 198.18.0.0/15\n inIpv4Range(address, 0xc6336400, 0xc63364ff) || // 198.51.100.0/24\n inIpv4Range(address, 0xcb007100, 0xcb0071ff) || // 203.0.113.0/24\n inIpv4Range(address, 0xe0000000, 0xffffffff)\n ) // multicast, reserved, broadcast\n );\n}\n\nfunction parseIpv6(value: string): bigint[] | undefined {\n if (value.includes('%')) return undefined;\n const input = expandEmbeddedIpv4(value.toLowerCase());\n if (input === undefined) return undefined;\n\n const parts = splitIpv6Groups(input);\n if (parts === undefined) return undefined;\n const {left, right, hasCompression} = parts;\n\n const groups = hasCompression\n ? [...left, ...Array(8 - left.length - right.length).fill('0'), ...right]\n : [...left, ...right];\n if (groups.length !== 8) return undefined;\n return groups.map((part) => BigInt(`0x${part}`));\n}\n\nfunction expandEmbeddedIpv4(value: string): string | undefined {\n if (!value.includes('.')) return value;\n const lastColon = value.lastIndexOf(':');\n if (lastColon < 0) return undefined;\n const ipv4 = ipv4ToNumber(value.slice(lastColon + 1));\n if (ipv4 === undefined) return undefined;\n const high = ((ipv4 >>> 16) & 0xffff).toString(16);\n const low = (ipv4 & 0xffff).toString(16);\n return `${value.slice(0, lastColon)}:${high}:${low}`;\n}\n\nfunction splitIpv6Groups(value: string):\n | {\n hasCompression: boolean;\n left: string[];\n right: string[];\n }\n | undefined {\n const compressionStart = value.indexOf('::');\n if (compressionStart !== -1 && compressionStart !== value.lastIndexOf('::')) {\n return undefined;\n }\n\n const hasCompression = compressionStart !== -1;\n const [leftText, rightText = ''] = value.split('::');\n const left = leftText ? leftText.split(':') : [];\n const right = rightText ? rightText.split(':') : [];\n if (left.some((part) => !IPV6_GROUP_RE.test(part))) return undefined;\n if (right.some((part) => !IPV6_GROUP_RE.test(part))) return undefined;\n if (!hasCompression && left.length + right.length !== 8) return undefined;\n if (hasCompression && left.length + right.length >= 8) return undefined;\n return {hasCompression, left, right};\n}\n\nfunction isPublicIpv6(value: string): boolean {\n const groups = parseIpv6(value);\n if (!groups) return false;\n const first = Number(groups[0]);\n if (first < 0x2000 || first > 0x3fff) return false;\n\n // Keep documentation, benchmarking, transition, and other special-use\n // prefixes out of a fetch path even when a resolver returns a routable one.\n if (first === 0x2001) {\n const second = Number(groups[1]);\n if (\n second === 0x0000 ||\n second === 0x0002 ||\n (second >= 0x0010 && second <= 0x002f) ||\n (second >= 0x0db8 && second <= 0x0dbf)\n ) {\n return false;\n }\n }\n if (first === 0x2002 || first === 0x3fff) return false;\n return true;\n}\n\n/** Returns true only for a globally routable unicast address. */\nexport function isPublicUnicastAddress(address: string, family?: 4 | 6): boolean {\n const normalized = address.replace(/^\\[|\\]$/gu, '');\n const detectedFamily = family ?? (isIP(normalized) as 4 | 6 | 0);\n if (detectedFamily === 4) return isPublicIpv4(normalized);\n if (detectedFamily === 6) return isPublicIpv6(normalized);\n return false;\n}\n\nfunction normalizeHostname(url: URL): string {\n return url.hostname.replace(/^\\[|\\]$/gu, '');\n}\n\nasync function resolvePublicAddress(hostname: string): Promise<readonly CimdAddress[]> {\n if (isIP(hostname) === 4 || isIP(hostname) === 6) {\n const family = isIP(hostname) as 4 | 6;\n if (!isPublicUnicastAddress(hostname, family)) {\n throw metadataFetchError('private-address');\n }\n return [{address: hostname, family}];\n }\n\n let resolved: Array<{address: string; family: number}>;\n try {\n resolved = await dnsPromises.lookup(hostname, {all: true, verbatim: true});\n } catch (error) {\n throw metadataFetchError('dns-failed', error);\n }\n if (resolved.length === 0) throw metadataFetchError('dns-failed');\n\n const addresses = resolved.map((entry) => ({\n address: entry.address,\n family: entry.family as 4 | 6,\n }));\n if (\n addresses.some(\n (entry) =>\n (entry.family !== 4 && entry.family !== 6) ||\n !isPublicUnicastAddress(entry.address, entry.family),\n )\n ) {\n throw metadataFetchError('private-address');\n }\n return addresses;\n}\n\nfunction headerValue(\n headers: Record<string, string | string[] | undefined>,\n name: string,\n): string | undefined {\n const normalizedName = name.toLowerCase();\n const headerName = Object.keys(headers).find((key) => key.toLowerCase() === normalizedName);\n const value = headerName === undefined ? undefined : headers[headerName];\n if (Array.isArray(value)) return value.join(', ');\n return value;\n}\n\nfunction parseCacheMaxAge(headers: Record<string, string | string[] | undefined>): number {\n const cacheControl = headerValue(headers, 'cache-control');\n if (!cacheControl) return OAUTH_CIMD_CACHE_MAX_AGE_SECONDS;\n\n let maxAge: number | undefined;\n for (const directive of cacheControl.split(',')) {\n const [rawName, rawValue] = directive.trim().split('=', 2);\n const name = rawName?.trim().toLowerCase();\n if (name === 'no-store' || name === 'no-cache') return 0;\n if (name === 'max-age' && rawValue !== undefined && DECIMAL_RE.test(rawValue.trim())) {\n maxAge = Number(rawValue.trim());\n }\n }\n return Math.min(maxAge ?? OAUTH_CIMD_CACHE_MAX_AGE_SECONDS, OAUTH_CIMD_CACHE_MAX_AGE_SECONDS);\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n onTimeout?: () => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n onTimeout?.();\n reject(new CimdTimeoutError());\n }, timeoutMs);\n promise.then(\n (value) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(value);\n },\n (error: unknown) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\nfunction requestPinnedHttps(params: {\n url: URL;\n address: CimdAddress;\n timeoutMs: number;\n maxBodyBytes: number;\n signal?: AbortSignal;\n}): Promise<CimdHttpResponse> {\n return new Promise((resolve, reject) => {\n const hostname = normalizeHostname(params.url);\n let settled = false;\n\n const fail = (error: unknown) => {\n if (settled) return;\n settled = true;\n reject(error);\n };\n const succeed = (response: CimdHttpResponse) => {\n if (settled) return;\n settled = true;\n resolve(response);\n };\n\n if (params.url.protocol !== 'https:' || params.url.username || params.url.password) {\n fail(metadataFetchError('invalid-url'));\n return;\n }\n\n const request = httpsRequest(\n {\n hostname,\n port: params.url.port || 443,\n path: `${params.url.pathname || '/'}${params.url.search}`,\n method: 'GET',\n headers: {accept: 'application/json'},\n rejectUnauthorized: true,\n servername: hostname,\n timeout: params.timeoutMs,\n signal: params.signal,\n // The address was resolved before this request and is the only value\n // the TLS connection is allowed to use.\n lookup: (_lookupHostname, _options, callback) => {\n callback(null, params.address.address, params.address.family);\n },\n },\n (response) => {\n handleCimdResponse(response, params.maxBodyBytes, fail, succeed);\n },\n );\n request.once('error', (error) => fail(error));\n request.once('timeout', () => {\n request.destroy();\n fail(metadataFetchError('timeout'));\n });\n request.end();\n });\n}\n\nfunction responseHeaderError(\n statusCode: number | undefined,\n headers: Record<string, string | string[] | undefined>,\n maxBodyBytes: number,\n): OAuthMetadataFetchError | undefined {\n if (statusCode !== undefined && statusCode >= 300 && statusCode < 400) {\n return metadataFetchError('redirected');\n }\n const contentLength = headerValue(headers, 'content-length');\n if (contentLength !== undefined) {\n if (!DECIMAL_RE.test(contentLength.trim())) return metadataFetchError('invalid-response');\n if (Number(contentLength) > maxBodyBytes) return metadataFetchError('response-too-large');\n }\n const contentEncoding = headerValue(headers, 'content-encoding');\n if (contentEncoding && contentEncoding.toLowerCase() !== 'identity') {\n return metadataFetchError('invalid-response');\n }\n return undefined;\n}\n\nfunction readCimdResponseBody(response: IncomingMessage, maxBodyBytes: number): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n response.on('data', (chunk: Buffer | string) => {\n const buffer = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;\n size += buffer.byteLength;\n if (size > maxBodyBytes) {\n response.destroy();\n reject(metadataFetchError('response-too-large'));\n return;\n }\n chunks.push(buffer);\n });\n response.once('error', reject);\n response.once('end', () => resolve(Buffer.concat(chunks)));\n });\n}\n\nfunction handleCimdResponse(\n response: IncomingMessage,\n maxBodyBytes: number,\n fail: (error: unknown) => void,\n succeed: (response: CimdHttpResponse) => void,\n): void {\n const headers: Record<string, string | string[] | undefined> = response.headers;\n const headerError = responseHeaderError(response.statusCode, headers, maxBodyBytes);\n if (headerError) {\n response.destroy();\n fail(headerError);\n return;\n }\n void readCimdResponseBody(response, maxBodyBytes).then(\n (body) => succeed({statusCode: response.statusCode ?? 0, headers, body}),\n fail,\n );\n}\n\nfunction parseCimdDocument(body: Uint8Array, clientId: string): ValidatedOAuthClientMetadata {\n let parsed: unknown;\n try {\n parsed = JSON.parse(Buffer.from(body).toString('utf8'));\n } catch {\n throw new InvalidOAuthClientMetadataError();\n }\n\n const result = oauthClientMetadataDocumentSchema.safeParse(parsed);\n if (!result.success) throw new InvalidOAuthClientMetadataError();\n return validateOAuthClientMetadataDocument(result.data, clientId);\n}\n\nasync function resolvePinnedAddresses(\n hostname: string,\n resolveAddress: CimdAddressResolver,\n timeoutMs: number,\n): Promise<readonly CimdAddress[]> {\n let resolved: readonly CimdAddress[];\n try {\n resolved = await withTimeout(resolveAddress(hostname), timeoutMs);\n } catch (error) {\n if (error instanceof OAuthMetadataFetchError) throw error;\n if (error instanceof CimdTimeoutError) throw metadataFetchError('timeout', error);\n throw metadataFetchError('dns-failed', error);\n }\n if (resolved.length === 0) throw metadataFetchError('dns-failed');\n if (\n resolved.some(\n (entry) =>\n (entry.family !== 4 && entry.family !== 6) ||\n !isPublicUnicastAddress(entry.address, entry.family),\n )\n ) {\n throw metadataFetchError('private-address');\n }\n return resolved;\n}\n\nasync function requestCimdResponse(params: {\n url: URL;\n address: CimdAddress;\n request: CimdHttpRequester;\n timeoutMs: number;\n maxBodyBytes: number;\n}): Promise<CimdHttpResponse> {\n const abortController = new AbortController();\n try {\n return await withTimeout(\n params.request({\n url: params.url,\n address: params.address,\n timeoutMs: params.timeoutMs,\n maxBodyBytes: params.maxBodyBytes,\n signal: abortController.signal,\n }),\n params.timeoutMs,\n () => abortController.abort(),\n );\n } catch (error) {\n if (error instanceof OAuthMetadataFetchError) throw error;\n if (error instanceof CimdTimeoutError) throw metadataFetchError('timeout', error);\n throw metadataFetchError('connection-failed', error);\n }\n}\n\nfunction remainingTimeout(deadlineMs: number): number {\n const timeoutMs = deadlineMs - Date.now();\n if (timeoutMs <= 0) throw metadataFetchError('timeout');\n return timeoutMs;\n}\n\nfunction assertCimdResponse(response: CimdHttpResponse, maxBodyBytes: number): void {\n const headerError = responseHeaderError(response.statusCode, response.headers, maxBodyBytes);\n if (headerError) throw headerError;\n if (response.statusCode !== 200) throw metadataFetchError('invalid-response');\n if (response.body.byteLength > maxBodyBytes) {\n throw metadataFetchError('response-too-large');\n }\n}\n\nexport interface FetchCimdMetadataOptions {\n resolveAddress?: CimdAddressResolver;\n request?: CimdHttpRequester;\n timeoutMs?: number;\n maxBodyBytes?: number;\n}\n\n/**\n * Fetches a Client ID Metadata Document after resolving and pinning a public\n * address. This deliberately does not share the general egress helper: CIMD\n * has stricter public-only, no-redirect, and no-credential requirements.\n */\nexport async function fetchClientIdMetadata(\n clientId: string,\n options: FetchCimdMetadataOptions = {},\n): Promise<FetchedCimdMetadata> {\n const url = validateOAuthClientId(clientId);\n const timeoutMs = options.timeoutMs ?? OAUTH_CIMD_FETCH_TIMEOUT_MS;\n const maxBodyBytes = options.maxBodyBytes ?? OAUTH_CIMD_MAX_BODY_BYTES;\n const resolveAddress = options.resolveAddress ?? resolvePublicAddress;\n const request = options.request ?? requestPinnedHttps;\n const hostname = normalizeHostname(url);\n const deadlineMs = Date.now() + timeoutMs;\n\n const addresses = await resolvePinnedAddresses(\n hostname,\n resolveAddress,\n remainingTimeout(deadlineMs),\n );\n let lastConnectionError: OAuthMetadataFetchError | undefined;\n for (const [index, address] of addresses.entries()) {\n try {\n const response = await requestCimdResponse({\n url,\n address,\n request,\n timeoutMs: remainingTimeout(deadlineMs),\n maxBodyBytes,\n });\n assertCimdResponse(response, maxBodyBytes);\n\n return {\n metadata: parseCimdDocument(response.body, clientId),\n cacheMaxAgeSeconds: parseCacheMaxAge(response.headers),\n };\n } catch (error) {\n if (\n error instanceof OAuthMetadataFetchError &&\n error.reason === 'connection-failed' &&\n index < addresses.length - 1\n ) {\n lastConnectionError = error;\n continue;\n }\n throw error;\n }\n }\n throw lastConnectionError ?? metadataFetchError('connection-failed');\n}\n"],"names":["promises","dnsPromises","request","httpsRequest","isIP","oauthClientMetadataDocumentSchema","InvalidOAuthClientMetadataError","OAuthMetadataFetchError","OAUTH_CIMD_CACHE_MAX_AGE_SECONDS","validateOAuthClientId","validateOAuthClientMetadataDocument","OAUTH_CIMD_MAX_BODY_BYTES","OAUTH_CIMD_FETCH_TIMEOUT_MS","DECIMAL_RE","IPV6_GROUP_RE","CimdTimeoutError","Error","name","metadataFetchError","reason","cause","ipv4ToNumber","value","parts","split","length","undefined","result","part","test","octet","Number","isInteger","inIpv4Range","start","end","isPublicIpv4","address","parseIpv6","includes","input","expandEmbeddedIpv4","toLowerCase","splitIpv6Groups","left","right","hasCompression","groups","Array","fill","map","BigInt","lastColon","lastIndexOf","ipv4","slice","high","toString","low","compressionStart","indexOf","leftText","rightText","some","isPublicIpv6","first","second","isPublicUnicastAddress","family","normalized","replace","detectedFamily","normalizeHostname","url","hostname","resolvePublicAddress","resolved","lookup","all","verbatim","error","addresses","entry","headerValue","headers","normalizedName","headerName","Object","keys","find","key","isArray","join","parseCacheMaxAge","cacheControl","maxAge","directive","rawName","rawValue","trim","Math","min","withTimeout","promise","timeoutMs","onTimeout","Promise","resolve","reject","settled","timer","setTimeout","then","clearTimeout","requestPinnedHttps","params","fail","succeed","response","protocol","username","password","port","path","pathname","search","method","accept","rejectUnauthorized","servername","timeout","signal","_lookupHostname","_options","callback","handleCimdResponse","maxBodyBytes","once","destroy","responseHeaderError","statusCode","contentLength","contentEncoding","readCimdResponseBody","chunks","size","on","chunk","buffer","Buffer","from","byteLength","push","concat","headerError","body","parseCimdDocument","clientId","parsed","JSON","parse","safeParse","success","data","resolvePinnedAddresses","resolveAddress","requestCimdResponse","abortController","AbortController","abort","remainingTimeout","deadlineMs","Date","now","assertCimdResponse","fetchClientIdMetadata","options","lastConnectionError","index","entries","metadata","cacheMaxAgeSeconds"],"mappings":"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"}
@@ -96,4 +96,18 @@ export declare class InvitationEmailMismatchError extends Error {
96
96
  export declare class OpenInvitationExistsError extends Error {
97
97
  constructor(email: string);
98
98
  }
99
+ export declare class InvalidOAuthClientMetadataError extends Error {
100
+ constructor();
101
+ }
102
+ export declare class OAuthRedirectUriNotRegisteredError extends Error {
103
+ constructor();
104
+ }
105
+ export declare class OAuthMetadataFetchError extends Error {
106
+ readonly reason: 'invalid-url' | 'private-address' | 'dns-failed' | 'connection-failed' | 'redirected' | 'timeout' | 'response-too-large' | 'invalid-response';
107
+ readonly cause: unknown;
108
+ constructor(reason: OAuthMetadataFetchError['reason'], cause?: unknown);
109
+ }
110
+ export declare class InvalidOAuthConfigurationError extends Error {
111
+ constructor();
112
+ }
99
113
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,YAAY,CAAC;AAE1D,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,WAAW,EAAE,MAAM,EAG9B;CACF;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,EAAE,EAAE,MAAM,EAGrB;CACF;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,YAAY,EAAE,EAAE,MAAM,EAGrB;CACF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,cAGC;CACF;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,YAAY,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAG9C;CACF;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,SAAS,EAAE,MAAM,EAG5B;CACF;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,KAAK,EAAE,MAAM,EAGxB;CACF;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG5C,QAAQ,CAAC,MAAM,CAAC,EAAE,yBAAyB;IAF7C,YACE,OAAO,EAAE,MAAM,EACN,MAAM,CAAC,EAAE,yBAAyB,YAAA,EAI5C;CACF;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,cAGC;CACF;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,cAGC;CACF;AAED,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,SAAkB,KAAK,EAAE,OAAO,CAAC;IAEjC,YAAY,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAK7C;CACF;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,WAAW,EAAE,OAAO,uBAAuB,EAAE,SAAS,CAAC;IAEhE,YAAY,WAAW,EAAE,OAAO,uBAAuB,EAAE,SAAS,EAIjE;CACF;AAED,qBAAa,4CAA6C,SAAQ,KAAK;IACrE,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,cAGC;CACF;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,cAGC;CACF;AAED,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,cAGC;CACF;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,cAGC;CACF;AAED,qBAAa,+BAAgC,SAAQ,KAAK;IACxD,cAGC;CACF;AAED,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,cAGC;CACF;AAED,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,cAGC;CACF;AAED,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,cAGC;CACF;AAED,qBAAa,mCAAoC,SAAQ,KAAK;IAC5D,cAGC;CACF;AAED,qBAAa,iCAAkC,SAAQ,KAAK;IAC1D,cAGC;CACF;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,cAGC;CACF;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,MAAM,CAAC,EAAE,MAAM,EAG1B;CACF;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,cAGC;CACF;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,cAGC;CACF;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,YAAY,WAAW,EAAE,MAAM,EAG9B;CACF;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,WAAW,EAAE,MAAM,EAG9B;CACF;AAED,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,cAGC;CACF;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,YAAY,KAAK,EAAE,MAAM,EAGxB;CACF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
@@ -187,5 +187,31 @@ export class OpenInvitationExistsError extends Error {
187
187
  this.name = 'OpenInvitationExistsError';
188
188
  }
189
189
  }
190
+ export class InvalidOAuthClientMetadataError extends Error {
191
+ constructor(){
192
+ super('OAuth client metadata is invalid');
193
+ this.name = 'InvalidOAuthClientMetadataError';
194
+ }
195
+ }
196
+ export class OAuthRedirectUriNotRegisteredError extends Error {
197
+ constructor(){
198
+ super('OAuth redirect URI is not registered');
199
+ this.name = 'OAuthRedirectUriNotRegisteredError';
200
+ }
201
+ }
202
+ export class OAuthMetadataFetchError extends Error {
203
+ constructor(reason, cause){
204
+ super('OAuth client metadata could not be fetched');
205
+ this.name = 'OAuthMetadataFetchError';
206
+ this.reason = reason;
207
+ this.cause = cause;
208
+ }
209
+ }
210
+ export class InvalidOAuthConfigurationError extends Error {
211
+ constructor(){
212
+ super('OAuth public URL configuration is invalid');
213
+ this.name = 'InvalidOAuthConfigurationError';
214
+ }
215
+ }
190
216
 
191
217
  //# sourceMappingURL=errors.js.map