fastmcp 4.16.13 → 4.17.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.
- package/dist/FastMCP.cjs +3 -3
- package/dist/FastMCP.d.cts +3 -2
- package/dist/FastMCP.d.ts +3 -2
- package/dist/FastMCP.js +2 -2
- package/dist/{OAuthProvider-Bvt5a7yr.d.cts → OAuthProvider-BWezdrAA.d.cts} +43 -1
- package/dist/{OAuthProvider-Bvt5a7yr.d.ts → OAuthProvider-BWezdrAA.d.ts} +43 -1
- package/dist/auth/index.cjs +2 -2
- package/dist/auth/index.d.cts +2 -2
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +1 -1
- package/dist/{chunk-QKDEME2F.cjs → chunk-BL2SWQWP.cjs} +252 -24
- package/dist/chunk-BL2SWQWP.cjs.map +1 -0
- package/dist/{chunk-QHGRXJLW.cjs → chunk-SYZRGVQX.cjs} +8 -1
- package/dist/chunk-SYZRGVQX.cjs.map +1 -0
- package/dist/{chunk-V5SKPW6E.js → chunk-UKKIJDLP.js} +243 -15
- package/dist/chunk-UKKIJDLP.js.map +1 -0
- package/dist/{chunk-CFPNOSVW.js → chunk-UODI5E6U.js} +8 -1
- package/dist/chunk-UODI5E6U.js.map +1 -0
- package/dist/examples/custom-routes.cjs +3 -3
- package/dist/examples/custom-routes.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-CFPNOSVW.js.map +0 -1
- package/dist/chunk-QHGRXJLW.cjs.map +0 -1
- package/dist/chunk-QKDEME2F.cjs.map +0 -1
- package/dist/chunk-V5SKPW6E.js.map +0 -1
|
@@ -72,6 +72,7 @@ var proxyDcrClientStorageSchema = _zod.z.object({
|
|
|
72
72
|
callbackUrl: _zod.z.string(),
|
|
73
73
|
clientId: _zod.z.string(),
|
|
74
74
|
clientSecret: _zod.z.string().optional(),
|
|
75
|
+
expiresAt: storedDateSchema.optional(),
|
|
75
76
|
metadata: dcrClientMetadataSchema.optional(),
|
|
76
77
|
redirectUris: _zod.z.array(_zod.z.string()),
|
|
77
78
|
registeredAt: storedDateSchema
|
|
@@ -172,10 +173,18 @@ var OAuthProxyStateStore = class {
|
|
|
172
173
|
`${STORAGE_KEY_PREFIX.transaction}${transactionId}`
|
|
173
174
|
);
|
|
174
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* A client carrying `expiresAt` is a cached resolution rather than a
|
|
178
|
+
* permanent registration (CIMD), so a lapsed copy is dropped and reported as
|
|
179
|
+
* a miss — the caller re-resolves it from the source of truth.
|
|
180
|
+
*/
|
|
175
181
|
async getRegisteredClientByClientId(clientId) {
|
|
176
182
|
const cached = this.registeredClientsByClientId.get(clientId);
|
|
177
183
|
if (cached) {
|
|
178
|
-
|
|
184
|
+
if (!cached.expiresAt || !this.isExpired(cached.expiresAt)) {
|
|
185
|
+
return cached;
|
|
186
|
+
}
|
|
187
|
+
this.registeredClientsByClientId.delete(clientId);
|
|
179
188
|
}
|
|
180
189
|
const stored = await this.tokenStorage.get(
|
|
181
190
|
`${STORAGE_KEY_PREFIX.client}${clientId}`
|
|
@@ -184,6 +193,10 @@ var OAuthProxyStateStore = class {
|
|
|
184
193
|
if (!parsed.success) {
|
|
185
194
|
return null;
|
|
186
195
|
}
|
|
196
|
+
if (parsed.data.expiresAt && this.isExpired(parsed.data.expiresAt)) {
|
|
197
|
+
await this.tokenStorage.delete(`${STORAGE_KEY_PREFIX.client}${clientId}`);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
187
200
|
this.cacheRegisteredClient(parsed.data);
|
|
188
201
|
return parsed.data;
|
|
189
202
|
}
|
|
@@ -205,12 +218,6 @@ var OAuthProxyStateStore = class {
|
|
|
205
218
|
}
|
|
206
219
|
return parsed.data;
|
|
207
220
|
}
|
|
208
|
-
async isTransactionCallbackRegistered(transaction) {
|
|
209
|
-
const registeredClient = await this.getRegisteredClientByClientId(
|
|
210
|
-
transaction.clientId
|
|
211
|
-
);
|
|
212
|
-
return _nullishCoalesce(_optionalChain([registeredClient, 'optionalAccess', _ => _.redirectUris, 'access', _2 => _2.includes, 'call', _3 => _3(transaction.clientCallbackUrl)]), () => ( false));
|
|
213
|
-
}
|
|
214
221
|
/**
|
|
215
222
|
* Record that an authorization code has been redeemed, so a later attempt
|
|
216
223
|
* gets "already used" rather than looking like an unknown code. Keyed and
|
|
@@ -233,7 +240,8 @@ var OAuthProxyStateStore = class {
|
|
|
233
240
|
async saveRegisteredClient(client) {
|
|
234
241
|
await this.tokenStorage.save(
|
|
235
242
|
`${STORAGE_KEY_PREFIX.client}${client.clientId}`,
|
|
236
|
-
client
|
|
243
|
+
client,
|
|
244
|
+
client.expiresAt ? this.getTtlSeconds(client.expiresAt) : void 0
|
|
237
245
|
);
|
|
238
246
|
}
|
|
239
247
|
async saveTransaction(transaction) {
|
|
@@ -276,6 +284,172 @@ var DEFAULT_AUTHORIZATION_CODE_TTL = 300;
|
|
|
276
284
|
var DEFAULT_TRANSACTION_TTL = 600;
|
|
277
285
|
var DEFAULT_UPSTREAM_REQUEST_TIMEOUT_MS = 1e4;
|
|
278
286
|
|
|
287
|
+
// src/auth/utils/cimd.ts
|
|
288
|
+
var CIMD_FETCH_TIMEOUT_MS = 5e3;
|
|
289
|
+
var CIMD_CLIENT_TTL_MS = 15 * 60 * 1e3;
|
|
290
|
+
var CIMD_MAX_RESPONSE_BYTES = 65536;
|
|
291
|
+
async function resolveCimdClient(clientId, requestedRedirectUri, validateRedirectUri) {
|
|
292
|
+
let url;
|
|
293
|
+
try {
|
|
294
|
+
url = new URL(clientId);
|
|
295
|
+
} catch (e) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
if (url.protocol !== "https:" || url.search) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
if (isPrivateOrLoopbackHost(url.hostname)) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
let response;
|
|
305
|
+
try {
|
|
306
|
+
response = await fetch(clientId, {
|
|
307
|
+
redirect: "error",
|
|
308
|
+
signal: AbortSignal.timeout(CIMD_FETCH_TIMEOUT_MS)
|
|
309
|
+
});
|
|
310
|
+
} catch (e2) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
if (!response.ok) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
const text = await readBoundedText(response);
|
|
317
|
+
if (text === null) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
let parsed;
|
|
321
|
+
try {
|
|
322
|
+
parsed = JSON.parse(text);
|
|
323
|
+
} catch (e3) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
const doc = parsed;
|
|
330
|
+
if (doc.client_id !== clientId) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
if (!isStringArray(doc.redirect_uris) || doc.redirect_uris.length === 0) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
const redirectUris = doc.redirect_uris;
|
|
337
|
+
if (requestedRedirectUri && !redirectUris.includes(requestedRedirectUri)) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
if (!redirectUris.every((uri) => validateRedirectUri(uri))) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
const metadata = {
|
|
344
|
+
client_name: optionalString(doc.client_name),
|
|
345
|
+
client_uri: optionalString(doc.client_uri),
|
|
346
|
+
logo_uri: optionalString(doc.logo_uri),
|
|
347
|
+
policy_uri: optionalString(doc.policy_uri),
|
|
348
|
+
scope: optionalString(doc.scope),
|
|
349
|
+
tos_uri: optionalString(doc.tos_uri)
|
|
350
|
+
};
|
|
351
|
+
return {
|
|
352
|
+
callbackUrl: redirectUris[0],
|
|
353
|
+
clientId,
|
|
354
|
+
// CIMD is a public-client mechanism secured by PKCE; there is no secret.
|
|
355
|
+
clientSecret: void 0,
|
|
356
|
+
expiresAt: new Date(Date.now() + CIMD_CLIENT_TTL_MS),
|
|
357
|
+
metadata,
|
|
358
|
+
redirectUris,
|
|
359
|
+
registeredAt: /* @__PURE__ */ new Date()
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function expandIPv6(host) {
|
|
363
|
+
const sides = host.split("::");
|
|
364
|
+
if (sides.length > 2) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
const head = sides[0] ? sides[0].split(":") : [];
|
|
368
|
+
const tail = sides.length === 2 && sides[1] ? sides[1].split(":") : [];
|
|
369
|
+
if (sides.length === 1 && head.length !== 8) {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
const missing = 8 - head.length - tail.length;
|
|
373
|
+
if (missing < 0) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
const parts = [...head, ...Array(missing).fill("0"), ...tail];
|
|
377
|
+
if (parts.length !== 8) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
const groups = parts.map((g) => Number.parseInt(g || "0", 16));
|
|
381
|
+
return groups.every((g) => !Number.isNaN(g)) ? groups : null;
|
|
382
|
+
}
|
|
383
|
+
function isPrivateOrLoopbackHost(hostname) {
|
|
384
|
+
const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
385
|
+
if (host === "localhost" || host === "0.0.0.0") {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
if (host.includes(":")) {
|
|
389
|
+
return isPrivateOrLoopbackIPv6(host);
|
|
390
|
+
}
|
|
391
|
+
return host === "127.0.0.1" || /^169\.254\./.test(host) || /^10\./.test(host) || /^192\.168\./.test(host) || /^172\.(1[6-9]|2\d|3[01])\./.test(host);
|
|
392
|
+
}
|
|
393
|
+
function isPrivateOrLoopbackIPv6(host) {
|
|
394
|
+
const groups = expandIPv6(host);
|
|
395
|
+
if (!groups) {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
if (groups.every((g) => g === 0)) {
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
if (groups.slice(0, 7).every((g) => g === 0) && groups[7] === 1) {
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
const [first] = groups;
|
|
405
|
+
if ((first & 65472) === 65152) {
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
if ((first & 65024) === 64512) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
if (groups[0] === 0 && groups[1] === 0 && groups[2] === 0 && groups[3] === 0 && groups[4] === 0 && (groups[5] === 0 || groups[5] === 65535)) {
|
|
412
|
+
const ipv4 = `${groups[6] >> 8}.${groups[6] & 255}.${groups[7] >> 8}.${groups[7] & 255}`;
|
|
413
|
+
return isPrivateOrLoopbackHost(ipv4);
|
|
414
|
+
}
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
function isStringArray(value) {
|
|
418
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
419
|
+
}
|
|
420
|
+
function optionalString(value) {
|
|
421
|
+
return typeof value === "string" ? value : void 0;
|
|
422
|
+
}
|
|
423
|
+
async function readBoundedText(response) {
|
|
424
|
+
const contentLength = response.headers.get("content-length");
|
|
425
|
+
if (contentLength && Number(contentLength) > CIMD_MAX_RESPONSE_BYTES) {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
const reader = _optionalChain([response, 'access', _ => _.body, 'optionalAccess', _2 => _2.getReader, 'call', _3 => _3()]);
|
|
429
|
+
if (!reader) {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
const chunks = [];
|
|
433
|
+
let totalBytes = 0;
|
|
434
|
+
try {
|
|
435
|
+
for (; ; ) {
|
|
436
|
+
const { done, value } = await reader.read();
|
|
437
|
+
if (done) {
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
totalBytes += value.byteLength;
|
|
441
|
+
if (totalBytes > CIMD_MAX_RESPONSE_BYTES) {
|
|
442
|
+
await reader.cancel();
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
chunks.push(value);
|
|
446
|
+
}
|
|
447
|
+
} catch (e4) {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
451
|
+
}
|
|
452
|
+
|
|
279
453
|
// src/auth/utils/claimsExtractor.ts
|
|
280
454
|
var ClaimsExtractor = (_class = class {
|
|
281
455
|
|
|
@@ -413,7 +587,7 @@ var ClaimsExtractor = (_class = class {
|
|
|
413
587
|
const stringified = JSON.stringify(value);
|
|
414
588
|
const maxSize = _nullishCoalesce(this.config.maxClaimValueSize, () => ( 2e3));
|
|
415
589
|
return stringified.length <= maxSize;
|
|
416
|
-
} catch (
|
|
590
|
+
} catch (e5) {
|
|
417
591
|
return false;
|
|
418
592
|
}
|
|
419
593
|
}
|
|
@@ -694,7 +868,7 @@ var ConsentManager = class {
|
|
|
694
868
|
return null;
|
|
695
869
|
}
|
|
696
870
|
return data;
|
|
697
|
-
} catch (
|
|
871
|
+
} catch (e6) {
|
|
698
872
|
return null;
|
|
699
873
|
}
|
|
700
874
|
}
|
|
@@ -1155,9 +1329,13 @@ var OAuthProxy = (_class4 = class {
|
|
|
1155
1329
|
__init7() {this.ownedTokenStorage = null}
|
|
1156
1330
|
/**
|
|
1157
1331
|
* Keyed by proxy-issued client_id for authorize/token-exchange lookups and
|
|
1158
|
-
* for the defence-in-depth callback checks. A registration never changes
|
|
1332
|
+
* for the defence-in-depth callback checks. A DCR registration never changes
|
|
1159
1333
|
* after it is written, so caching it locally cannot go stale; it is also
|
|
1160
1334
|
* persisted, so another instance can hydrate it.
|
|
1335
|
+
*
|
|
1336
|
+
* A CIMD client is not a registration but a snapshot of a document that can
|
|
1337
|
+
* change under us, so it is cached with an `expiresAt` and re-resolved once
|
|
1338
|
+
* that passes.
|
|
1161
1339
|
*/
|
|
1162
1340
|
__init8() {this.registeredClientsByClientId = /* @__PURE__ */ new Map()}
|
|
1163
1341
|
|
|
@@ -1167,6 +1345,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
1167
1345
|
allowPlainPkce: true,
|
|
1168
1346
|
authorizationCodeTtl: DEFAULT_AUTHORIZATION_CODE_TTL,
|
|
1169
1347
|
consentRequired: true,
|
|
1348
|
+
enableCimd: false,
|
|
1170
1349
|
enableTokenSwap: true,
|
|
1171
1350
|
// Enabled by default for security
|
|
1172
1351
|
redirectPath: "/oauth/callback",
|
|
@@ -1223,7 +1402,10 @@ var OAuthProxy = (_class4 = class {
|
|
|
1223
1402
|
"Only 'code' response type is supported"
|
|
1224
1403
|
);
|
|
1225
1404
|
}
|
|
1226
|
-
const registeredClient = await this.
|
|
1405
|
+
const registeredClient = await this.resolveClient(
|
|
1406
|
+
params.client_id,
|
|
1407
|
+
params.redirect_uri
|
|
1408
|
+
);
|
|
1227
1409
|
if (!registeredClient) {
|
|
1228
1410
|
throw new OAuthProxyError("invalid_client", "Unknown client_id");
|
|
1229
1411
|
}
|
|
@@ -1275,7 +1457,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
1275
1457
|
"Only authorization_code grant type is supported"
|
|
1276
1458
|
);
|
|
1277
1459
|
}
|
|
1278
|
-
const registeredClient = await this.
|
|
1460
|
+
const registeredClient = await this.resolveClient(request.client_id);
|
|
1279
1461
|
if (!registeredClient) {
|
|
1280
1462
|
throw new OAuthProxyError("invalid_client", "Unknown client_id");
|
|
1281
1463
|
}
|
|
@@ -1363,6 +1545,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
1363
1545
|
getAuthorizationServerMetadata() {
|
|
1364
1546
|
return {
|
|
1365
1547
|
authorizationEndpoint: `${this.config.baseUrl}/oauth/authorize`,
|
|
1548
|
+
...this.config.enableCimd ? { clientIdMetadataDocumentSupported: true } : {},
|
|
1366
1549
|
codeChallengeMethodsSupported: this.config.allowPlainPkce ? ["S256", "plain"] : ["S256"],
|
|
1367
1550
|
grantTypesSupported: ["authorization_code", "refresh_token"],
|
|
1368
1551
|
issuer: this.config.baseUrl,
|
|
@@ -1398,7 +1581,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
1398
1581
|
if (!transaction) {
|
|
1399
1582
|
throw new OAuthProxyError("invalid_request", "Invalid or expired state");
|
|
1400
1583
|
}
|
|
1401
|
-
if (!await this.
|
|
1584
|
+
if (!await this.isTransactionCallbackRegistered(transaction)) {
|
|
1402
1585
|
throw new OAuthProxyError(
|
|
1403
1586
|
"invalid_request",
|
|
1404
1587
|
"Transaction callback URL is not registered"
|
|
@@ -1444,7 +1627,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
1444
1627
|
}
|
|
1445
1628
|
if (action === "deny") {
|
|
1446
1629
|
await this.stateStore.deleteTransaction(transactionId);
|
|
1447
|
-
if (!await this.
|
|
1630
|
+
if (!await this.isTransactionCallbackRegistered(transaction)) {
|
|
1448
1631
|
throw new OAuthProxyError(
|
|
1449
1632
|
"invalid_request",
|
|
1450
1633
|
"Transaction callback URL is not registered"
|
|
@@ -1641,7 +1824,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
1641
1824
|
const error = await tokenResponse.json();
|
|
1642
1825
|
errorCode = error.error || "server_error";
|
|
1643
1826
|
errorDescription = error.error_description;
|
|
1644
|
-
} catch (
|
|
1827
|
+
} catch (e7) {
|
|
1645
1828
|
errorDescription = `Upstream returned HTTP ${tokenResponse.status} ${tokenResponse.statusText}`;
|
|
1646
1829
|
}
|
|
1647
1830
|
throw new OAuthProxyError(errorCode, errorDescription);
|
|
@@ -1805,7 +1988,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
1805
1988
|
const error = await tokenResponse.json();
|
|
1806
1989
|
errorCode = error.error || "invalid_grant";
|
|
1807
1990
|
errorDescription = error.error_description;
|
|
1808
|
-
} catch (
|
|
1991
|
+
} catch (e8) {
|
|
1809
1992
|
errorDescription = `Upstream returned HTTP ${tokenResponse.status} ${tokenResponse.statusText}`;
|
|
1810
1993
|
}
|
|
1811
1994
|
throw new OAuthProxyError(errorCode, errorDescription);
|
|
@@ -2030,6 +2213,21 @@ var OAuthProxy = (_class4 = class {
|
|
|
2030
2213
|
}
|
|
2031
2214
|
return response;
|
|
2032
2215
|
}
|
|
2216
|
+
/**
|
|
2217
|
+
* Defence in depth for the callback and consent-denial redirects: the
|
|
2218
|
+
* transaction's stored callback URL must still be registered for its client.
|
|
2219
|
+
*
|
|
2220
|
+
* Resolution goes through {@link resolveClient}, so a CIMD registration whose
|
|
2221
|
+
* cached copy lapsed mid-flow is re-fetched rather than mistaken for one that
|
|
2222
|
+
* was revoked.
|
|
2223
|
+
*/
|
|
2224
|
+
async isTransactionCallbackRegistered(transaction) {
|
|
2225
|
+
const registeredClient = await this.resolveClient(
|
|
2226
|
+
transaction.clientId,
|
|
2227
|
+
transaction.clientCallbackUrl
|
|
2228
|
+
);
|
|
2229
|
+
return _nullishCoalesce(_optionalChain([registeredClient, 'optionalAccess', _17 => _17.redirectUris, 'access', _18 => _18.includes, 'call', _19 => _19(transaction.clientCallbackUrl)]), () => ( false));
|
|
2230
|
+
}
|
|
2033
2231
|
/**
|
|
2034
2232
|
* Match URI against pattern (supports wildcards)
|
|
2035
2233
|
*/
|
|
@@ -2140,7 +2338,7 @@ var OAuthProxy = (_class4 = class {
|
|
|
2140
2338
|
const error = await tokenResponse.json();
|
|
2141
2339
|
errorCode = error.error || "invalid_grant";
|
|
2142
2340
|
errorDescription = error.error_description || "Upstream refresh failed";
|
|
2143
|
-
} catch (
|
|
2341
|
+
} catch (e9) {
|
|
2144
2342
|
errorDescription = `Upstream returned HTTP ${tokenResponse.status} ${tokenResponse.statusText}`;
|
|
2145
2343
|
}
|
|
2146
2344
|
throw new OAuthProxyError(errorCode, errorDescription);
|
|
@@ -2157,6 +2355,32 @@ var OAuthProxy = (_class4 = class {
|
|
|
2157
2355
|
tokenType: tokens.token_type || "Bearer"
|
|
2158
2356
|
};
|
|
2159
2357
|
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Resolve the client behind a `client_id`: a stored registration if there is
|
|
2360
|
+
* one, otherwise — when CIMD is enabled — the client's metadata document.
|
|
2361
|
+
*
|
|
2362
|
+
* A resolved CIMD client is cached like a DCR registration but carries the
|
|
2363
|
+
* `expiresAt` the resolver stamped on it, so the store drops it once it
|
|
2364
|
+
* lapses and the next call re-fetches the document. Every lookup goes
|
|
2365
|
+
* through here, so a lapse always means "re-resolve", never "unknown
|
|
2366
|
+
* client" mid-flow.
|
|
2367
|
+
*/
|
|
2368
|
+
async resolveClient(clientId, requestedRedirectUri) {
|
|
2369
|
+
const registeredClient = await this.stateStore.getRegisteredClientByClientId(clientId);
|
|
2370
|
+
if (registeredClient || !this.config.enableCimd) {
|
|
2371
|
+
return registeredClient;
|
|
2372
|
+
}
|
|
2373
|
+
const resolved = await resolveCimdClient(
|
|
2374
|
+
clientId,
|
|
2375
|
+
requestedRedirectUri,
|
|
2376
|
+
(uri) => this.validateRedirectUri(uri)
|
|
2377
|
+
);
|
|
2378
|
+
if (resolved) {
|
|
2379
|
+
this.stateStore.cacheRegisteredClient(resolved);
|
|
2380
|
+
await this.stateStore.saveRegisteredClient(resolved);
|
|
2381
|
+
}
|
|
2382
|
+
return resolved;
|
|
2383
|
+
}
|
|
2160
2384
|
/**
|
|
2161
2385
|
* Put a claimed refresh-token mapping back after a rotation failed, keeping
|
|
2162
2386
|
* whatever lifetime it had left.
|
|
@@ -2222,9 +2446,13 @@ var OAuthProxy = (_class4 = class {
|
|
|
2222
2446
|
* theft. Do not loosen the default beyond loopback addresses.
|
|
2223
2447
|
*/
|
|
2224
2448
|
validateRedirectUri(uri) {
|
|
2449
|
+
let parsed;
|
|
2225
2450
|
try {
|
|
2226
|
-
new URL(uri);
|
|
2227
|
-
} catch (
|
|
2451
|
+
parsed = new URL(uri);
|
|
2452
|
+
} catch (e10) {
|
|
2453
|
+
return false;
|
|
2454
|
+
}
|
|
2455
|
+
if (parsed.username !== "" || parsed.password !== "") {
|
|
2228
2456
|
return false;
|
|
2229
2457
|
}
|
|
2230
2458
|
const patterns = this.config.allowedRedirectUriPatterns;
|
|
@@ -2286,7 +2514,7 @@ var AuthProvider = class {
|
|
|
2286
2514
|
if (!request) {
|
|
2287
2515
|
return void 0;
|
|
2288
2516
|
}
|
|
2289
|
-
const authHeader = _optionalChain([request, 'access',
|
|
2517
|
+
const authHeader = _optionalChain([request, 'access', _20 => _20.headers, 'optionalAccess', _21 => _21.authorization]);
|
|
2290
2518
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
2291
2519
|
return void 0;
|
|
2292
2520
|
}
|
|
@@ -2522,7 +2750,7 @@ var DiskStore = (_class5 = class {
|
|
|
2522
2750
|
console.warn(`Failed to read/parse file ${file}, deleting:`, error);
|
|
2523
2751
|
try {
|
|
2524
2752
|
await _promises.rm.call(void 0, _path.join.call(void 0, this.directory, file));
|
|
2525
|
-
} catch (
|
|
2753
|
+
} catch (e11) {
|
|
2526
2754
|
}
|
|
2527
2755
|
}
|
|
2528
2756
|
}
|
|
@@ -2602,7 +2830,7 @@ var DiskStore = (_class5 = class {
|
|
|
2602
2830
|
await this.ensureDirectory();
|
|
2603
2831
|
const files = await _promises.readdir.call(void 0, this.directory);
|
|
2604
2832
|
return files.filter((f) => f.endsWith(this.fileExtension)).length;
|
|
2605
|
-
} catch (
|
|
2833
|
+
} catch (e12) {
|
|
2606
2834
|
return 0;
|
|
2607
2835
|
}
|
|
2608
2836
|
}
|
|
@@ -2826,4 +3054,4 @@ Original error: ${error.message}`
|
|
|
2826
3054
|
|
|
2827
3055
|
|
|
2828
3056
|
exports.getAuthSession = getAuthSession; exports.requireAll = requireAll; exports.requireAny = requireAny; exports.requireAuth = requireAuth; exports.requireRole = requireRole; exports.requireScopes = requireScopes; exports.DEFAULT_ACCESS_TOKEN_TTL = DEFAULT_ACCESS_TOKEN_TTL; exports.DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH = DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH; exports.DEFAULT_REFRESH_TOKEN_TTL = DEFAULT_REFRESH_TOKEN_TTL; exports.DEFAULT_AUTHORIZATION_CODE_TTL = DEFAULT_AUTHORIZATION_CODE_TTL; exports.DEFAULT_TRANSACTION_TTL = DEFAULT_TRANSACTION_TTL; exports.ConsentManager = ConsentManager; exports.JWTIssuer = JWTIssuer; exports.PKCEUtils = PKCEUtils; exports.EncryptedTokenStorage = EncryptedTokenStorage; exports.MemoryTokenStorage = MemoryTokenStorage; exports.OAuthProxy = OAuthProxy; exports.OAuthProxyError = OAuthProxyError; exports.AuthProvider = AuthProvider; exports.AzureProvider = AzureProvider; exports.GitHubProvider = GitHubProvider; exports.GoogleProvider = GoogleProvider; exports.OAuthProvider = OAuthProvider; exports.DiskStore = DiskStore; exports.JWKSVerifier = JWKSVerifier;
|
|
2829
|
-
//# sourceMappingURL=chunk-
|
|
3057
|
+
//# sourceMappingURL=chunk-BL2SWQWP.cjs.map
|