@agentronics/sdk 0.6.0 → 0.7.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/chunk-3WPDIMJP.js +18 -0
- package/dist/chunk-3WPDIMJP.js.map +1 -0
- package/dist/{chunk-X7NFMFN6.js → chunk-6QQS26AP.js} +264 -69
- package/dist/chunk-6QQS26AP.js.map +1 -0
- package/dist/chunk-BPDWJCPY.js +2 -0
- package/dist/chunk-BPDWJCPY.js.map +1 -0
- package/dist/index.cjs +8 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -7
- package/dist/index.d.ts +39 -7
- package/dist/index.global.js +8 -7
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{init-only-7f8_LQAI.d.ts → init-only-C80qhujz.d.ts} +227 -30
- package/dist/{init-only-Cwll8MGz.d.cts → init-only-s9E9bVC0.d.cts} +227 -30
- package/dist/init-only.cjs +8 -7
- package/dist/init-only.cjs.map +1 -1
- package/dist/init-only.d.cts +2 -2
- package/dist/init-only.d.ts +2 -2
- package/dist/init-only.global.js +8 -7
- package/dist/init-only.global.js.map +1 -1
- package/dist/init-only.js +1 -1
- package/dist/lite.cjs +1 -1
- package/dist/lite.cjs.map +1 -1
- package/dist/lite.d.cts +2 -2
- package/dist/lite.d.ts +2 -2
- package/dist/lite.global.js +1 -1
- package/dist/lite.global.js.map +1 -1
- package/dist/lite.js +1 -1
- package/dist/middleware-Dd2T772u.d.cts +429 -0
- package/dist/middleware-Dd2T772u.d.ts +429 -0
- package/dist/next.cjs +239 -64
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +2 -2
- package/dist/next.d.ts +2 -2
- package/dist/next.js +2 -2
- package/dist/server.cjs +361 -66
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +103 -308
- package/dist/server.d.ts +103 -308
- package/dist/server.js +93 -1
- package/dist/server.js.map +1 -1
- package/dist/webmcp-BgKzHeQ3.d.cts +97 -0
- package/dist/webmcp-BgKzHeQ3.d.ts +97 -0
- package/package.json +4 -4
- package/dist/chunk-LLD3Y2LZ.js +0 -2
- package/dist/chunk-LLD3Y2LZ.js.map +0 -1
- package/dist/chunk-X7NFMFN6.js.map +0 -1
- package/dist/chunk-Y7JYD5RA.js +0 -17
- package/dist/chunk-Y7JYD5RA.js.map +0 -1
- package/dist/webmcp-C4ikhM4g.d.cts +0 -12
- package/dist/webmcp-C4ikhM4g.d.ts +0 -12
|
@@ -1,12 +1,105 @@
|
|
|
1
|
+
// src/server/ipRanges.ts
|
|
2
|
+
var PUBLISHED_IP_RANGES = {
|
|
3
|
+
GPTBot: ["https://openai.com/gptbot.json"],
|
|
4
|
+
"OAI-SearchBot": ["https://openai.com/searchbot.json"],
|
|
5
|
+
"ChatGPT-User": ["https://openai.com/chatgpt-user.json"],
|
|
6
|
+
PerplexityBot: ["https://www.perplexity.ai/perplexitybot.json"],
|
|
7
|
+
"Perplexity-User": ["https://www.perplexity.ai/perplexity-user.json"],
|
|
8
|
+
Googlebot: ["https://developers.google.com/static/crawling/ipranges/common-crawlers.json"],
|
|
9
|
+
Bingbot: ["https://www.bing.com/toolbox/bingbot.json"],
|
|
10
|
+
DuckDuckBot: ["https://duckduckgo.com/duckduckbot.json"],
|
|
11
|
+
CCBot: ["https://index.commoncrawl.org/ccbot.json"]
|
|
12
|
+
};
|
|
13
|
+
var TTL_MS = 24 * 36e5;
|
|
14
|
+
var FAILED_TTL_MS = 10 * 6e4;
|
|
15
|
+
var cache = /* @__PURE__ */ new Map();
|
|
16
|
+
async function loadUrl(url, fetcher) {
|
|
17
|
+
const hit = cache.get(url);
|
|
18
|
+
if (hit && hit.until > Date.now()) return hit.cidrs;
|
|
19
|
+
try {
|
|
20
|
+
const res = await fetcher(url, { signal: AbortSignal.timeout(5e3), redirect: "follow" });
|
|
21
|
+
if (!res.ok) throw new Error(String(res.status));
|
|
22
|
+
const body = await res.json();
|
|
23
|
+
const cidrs = (body.prefixes ?? []).flatMap((p) => [p.ipv4Prefix, p.ipv6Prefix]).filter((c) => typeof c === "string");
|
|
24
|
+
cache.set(url, { cidrs, until: Date.now() + TTL_MS });
|
|
25
|
+
return cidrs;
|
|
26
|
+
} catch {
|
|
27
|
+
const cidrs = hit?.cidrs ?? [];
|
|
28
|
+
cache.set(url, { cidrs, until: Date.now() + FAILED_TTL_MS });
|
|
29
|
+
return cidrs;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function rangesFor(name, options = {}) {
|
|
33
|
+
const fixed = options.ipRanges?.[name];
|
|
34
|
+
if (fixed) return fixed;
|
|
35
|
+
const urls = PUBLISHED_IP_RANGES[name];
|
|
36
|
+
if (!urls) return null;
|
|
37
|
+
const fetcher = options.fetcher ?? fetch;
|
|
38
|
+
return (await Promise.all(urls.map((u) => loadUrl(u, fetcher)))).flat();
|
|
39
|
+
}
|
|
40
|
+
function v4ToBigInt(ip) {
|
|
41
|
+
const parts = ip.split(".");
|
|
42
|
+
if (parts.length !== 4) return null;
|
|
43
|
+
let n = 0n;
|
|
44
|
+
for (const p of parts) {
|
|
45
|
+
if (!/^\d{1,3}$/.test(p) || Number(p) > 255) return null;
|
|
46
|
+
n = n << 8n | BigInt(p);
|
|
47
|
+
}
|
|
48
|
+
return n;
|
|
49
|
+
}
|
|
50
|
+
function v6ToBigInt(ip) {
|
|
51
|
+
let s = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
52
|
+
const zone = s.indexOf("%");
|
|
53
|
+
if (zone >= 0) s = s.slice(0, zone);
|
|
54
|
+
const v4 = s.match(/(\d+\.\d+\.\d+\.\d+)$/);
|
|
55
|
+
if (v4) {
|
|
56
|
+
const n2 = v4ToBigInt(v4[1]);
|
|
57
|
+
if (n2 === null) return null;
|
|
58
|
+
s = s.slice(0, -v4[1].length) + (n2 >> 16n & 0xffffn).toString(16) + ":" + (n2 & 0xffffn).toString(16);
|
|
59
|
+
}
|
|
60
|
+
const halves = s.split("::");
|
|
61
|
+
if (halves.length > 2) return null;
|
|
62
|
+
const head = halves[0] ? halves[0].split(":") : [];
|
|
63
|
+
const tail = halves.length === 2 && halves[1] ? halves[1].split(":") : [];
|
|
64
|
+
const missing = 8 - head.length - tail.length;
|
|
65
|
+
if (halves.length === 1 ? missing !== 0 : missing < 1) return null;
|
|
66
|
+
const groups = [...head, ...Array(halves.length === 2 ? missing : 0).fill("0"), ...tail];
|
|
67
|
+
let n = 0n;
|
|
68
|
+
for (const g of groups) {
|
|
69
|
+
if (!/^[0-9a-f]{1,4}$/.test(g)) return null;
|
|
70
|
+
n = n << 16n | BigInt(parseInt(g, 16));
|
|
71
|
+
}
|
|
72
|
+
return n;
|
|
73
|
+
}
|
|
74
|
+
function ipInCidr(ip, cidr) {
|
|
75
|
+
const [range, bitsRaw] = cidr.split("/");
|
|
76
|
+
if (!range) return false;
|
|
77
|
+
const isV6 = range.includes(":");
|
|
78
|
+
const mapped = ip.toLowerCase().match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
|
|
79
|
+
const candidate = !isV6 && mapped ? mapped[1] : ip;
|
|
80
|
+
const width = isV6 ? 128 : 32;
|
|
81
|
+
const bits = bitsRaw === void 0 ? width : Number(bitsRaw);
|
|
82
|
+
if (!Number.isInteger(bits) || bits < 0 || bits > width) return false;
|
|
83
|
+
const a = isV6 ? v6ToBigInt(candidate) : v4ToBigInt(candidate);
|
|
84
|
+
const b = isV6 ? v6ToBigInt(range) : v4ToBigInt(range);
|
|
85
|
+
if (a === null || b === null) return false;
|
|
86
|
+
const shift = BigInt(width - bits);
|
|
87
|
+
return a >> shift === b >> shift;
|
|
88
|
+
}
|
|
89
|
+
var ipInRanges = (ip, cidrs) => cidrs.some((c) => ipInCidr(ip, c));
|
|
90
|
+
|
|
1
91
|
// src/detection/crawler.ts
|
|
2
92
|
var CRAWLER_SIGNATURES = [
|
|
3
93
|
// AI / LLM crawlers
|
|
4
94
|
{ name: "GPTBot", category: "ai", pattern: /GPTBot/i },
|
|
5
95
|
{ name: "OAI-SearchBot", category: "ai", pattern: /OAI-SearchBot/i },
|
|
6
96
|
{ name: "ChatGPT-User", category: "ai", pattern: /ChatGPT-User/i },
|
|
97
|
+
{ name: "Claude-User", category: "ai", pattern: /Claude-User/i },
|
|
98
|
+
{ name: "Claude-SearchBot", category: "ai", pattern: /Claude-SearchBot/i },
|
|
7
99
|
{ name: "ClaudeBot", category: "ai", pattern: /ClaudeBot/i },
|
|
8
100
|
{ name: "Claude-Web", category: "ai", pattern: /Claude-Web/i },
|
|
9
101
|
{ name: "anthropic-ai", category: "ai", pattern: /anthropic-ai/i },
|
|
102
|
+
{ name: "Perplexity-User", category: "ai", pattern: /Perplexity-User/i },
|
|
10
103
|
{ name: "PerplexityBot", category: "ai", pattern: /PerplexityBot/i },
|
|
11
104
|
{ name: "Google-Extended", category: "ai", pattern: /Google-Extended/i },
|
|
12
105
|
{ name: "Applebot-Extended", category: "ai", pattern: /Applebot-Extended/i },
|
|
@@ -62,14 +155,19 @@ async function nodeResolver() {
|
|
|
62
155
|
}
|
|
63
156
|
}
|
|
64
157
|
var rdnsCache = /* @__PURE__ */ new Map();
|
|
65
|
-
async function verifyCrawler(claim, ip, resolver) {
|
|
158
|
+
async function verifyCrawler(claim, ip, resolver, ranges = {}) {
|
|
66
159
|
const domains = RDNS_DOMAINS[claim.name];
|
|
67
|
-
|
|
160
|
+
const cidrs = await rangesFor(claim.name, ranges);
|
|
161
|
+
if (!domains && !cidrs) return { status: "unverified", name: claim.name, reason: "no_verification_method_for_vendor" };
|
|
68
162
|
if (!ip) return { status: "unverified", name: claim.name, reason: "client_ip_unknown" };
|
|
163
|
+
if (cidrs?.length && ipInRanges(ip, cidrs)) {
|
|
164
|
+
return { status: "verified", name: claim.name, host: ip, ip, via: "ip-range" };
|
|
165
|
+
}
|
|
166
|
+
if (!domains) return { status: "unverified", name: claim.name, reason: "ip_outside_published_ranges" };
|
|
69
167
|
const key = `${claim.name}|${ip}`;
|
|
70
168
|
const hit = rdnsCache.get(key);
|
|
71
169
|
if (hit && hit.until > Date.now()) {
|
|
72
|
-
return hit.ok ? { status: "verified", name: claim.name, host: hit.host, ip } : { status: "unverified", name: claim.name, reason: "rdns_mismatch" };
|
|
170
|
+
return hit.ok ? { status: "verified", name: claim.name, host: hit.host, ip, via: "rdns" } : { status: "unverified", name: claim.name, reason: "rdns_mismatch" };
|
|
73
171
|
}
|
|
74
172
|
const dns = resolver ?? await nodeResolver();
|
|
75
173
|
if (!dns) return { status: "unverified", name: claim.name, reason: "dns_unavailable_in_runtime" };
|
|
@@ -85,7 +183,7 @@ async function verifyCrawler(claim, ip, resolver) {
|
|
|
85
183
|
const forward = await dns.lookup(host);
|
|
86
184
|
if (forward.includes(ip)) {
|
|
87
185
|
remember(true, host);
|
|
88
|
-
return { status: "verified", name: claim.name, host, ip };
|
|
186
|
+
return { status: "verified", name: claim.name, host, ip, via: "rdns" };
|
|
89
187
|
}
|
|
90
188
|
}
|
|
91
189
|
remember(false);
|
|
@@ -318,6 +416,135 @@ function bytesToBase64(bytes) {
|
|
|
318
416
|
}
|
|
319
417
|
var bytesToBase64Url = (bytes) => bytesToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
320
418
|
|
|
419
|
+
// src/server/oauth.ts
|
|
420
|
+
var josePromise;
|
|
421
|
+
var loadJose = () => josePromise ??= import('jose');
|
|
422
|
+
var remoteSets = /* @__PURE__ */ new Map();
|
|
423
|
+
var ASYMMETRIC = ["RS256", "PS256", "ES256", "EdDSA"];
|
|
424
|
+
function unverifiedIssuer(token) {
|
|
425
|
+
try {
|
|
426
|
+
const payload = token.split(".")[1];
|
|
427
|
+
const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
428
|
+
const iss = JSON.parse(json).iss;
|
|
429
|
+
return typeof iss === "string" ? iss : null;
|
|
430
|
+
} catch {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
var str = (v) => typeof v === "string" && v ? v : void 0;
|
|
435
|
+
async function sha256B64u(text) {
|
|
436
|
+
const d = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
|
|
437
|
+
return bytesToBase64Url(new Uint8Array(d));
|
|
438
|
+
}
|
|
439
|
+
var htuOf = (url) => {
|
|
440
|
+
const u = new URL(url);
|
|
441
|
+
return `${u.origin}${u.pathname}`;
|
|
442
|
+
};
|
|
443
|
+
async function verifyDpopProof(jose, proof, token, jkt, request, replay) {
|
|
444
|
+
try {
|
|
445
|
+
const { payload, protectedHeader } = await jose.jwtVerify(proof, jose.EmbeddedJWK, {
|
|
446
|
+
typ: "dpop+jwt",
|
|
447
|
+
algorithms: ASYMMETRIC
|
|
448
|
+
});
|
|
449
|
+
const jwk = protectedHeader.jwk;
|
|
450
|
+
if (!jwk) return "dpop_missing_jwk";
|
|
451
|
+
if (await jose.calculateJwkThumbprint(jwk, "sha256") !== jkt) return "dpop_key_mismatch";
|
|
452
|
+
if (str(payload.htm)?.toUpperCase() !== request.method.toUpperCase()) return "dpop_htm_mismatch";
|
|
453
|
+
if (str(payload.htu) === void 0 || htuOf(str(payload.htu)) !== htuOf(request.url)) return "dpop_htu_mismatch";
|
|
454
|
+
const iat = typeof payload.iat === "number" ? payload.iat : NaN;
|
|
455
|
+
if (!Number.isFinite(iat) || Math.abs(Date.now() / 1e3 - iat) > 300) return "dpop_stale";
|
|
456
|
+
if (str(payload.ath) !== await sha256B64u(token)) return "dpop_ath_mismatch";
|
|
457
|
+
const jti = str(payload.jti);
|
|
458
|
+
if (!jti) return "dpop_missing_jti";
|
|
459
|
+
if (replay) {
|
|
460
|
+
const key = `dpop:${jkt}:${jti}`;
|
|
461
|
+
if (await replay.has(key)) return "dpop_replayed";
|
|
462
|
+
await replay.add(key, 600);
|
|
463
|
+
}
|
|
464
|
+
return null;
|
|
465
|
+
} catch (e) {
|
|
466
|
+
return `dpop_invalid:${e.code ?? e.message}`;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
async function verifyOAuthToken(token, o, ctx) {
|
|
470
|
+
const jose = await loadJose();
|
|
471
|
+
const keySet = o.jwks ? jose.createLocalJWKSet(o.jwks) : (() => {
|
|
472
|
+
const uri = o.jwksUri ?? `${o.issuer.replace(/\/$/, "")}/.well-known/jwks.json`;
|
|
473
|
+
let s = remoteSets.get(uri);
|
|
474
|
+
if (!s) {
|
|
475
|
+
s = jose.createRemoteJWKSet(new URL(uri), { cacheMaxAge: 36e5, cooldownDuration: 3e4 });
|
|
476
|
+
remoteSets.set(uri, s);
|
|
477
|
+
}
|
|
478
|
+
return s;
|
|
479
|
+
})();
|
|
480
|
+
let payload;
|
|
481
|
+
try {
|
|
482
|
+
;
|
|
483
|
+
({ payload } = await jose.jwtVerify(token, keySet, {
|
|
484
|
+
issuer: o.issuer,
|
|
485
|
+
audience: o.audience,
|
|
486
|
+
algorithms: o.algorithms ?? ASYMMETRIC,
|
|
487
|
+
clockTolerance: o.clockToleranceSec ?? 30
|
|
488
|
+
}));
|
|
489
|
+
} catch (e) {
|
|
490
|
+
return { error: `invalid_token:${e.code ?? e.message}` };
|
|
491
|
+
}
|
|
492
|
+
const jkt = str(payload.cnf?.jkt);
|
|
493
|
+
let dpop = false;
|
|
494
|
+
if (jkt) {
|
|
495
|
+
const proof = ctx.request.headers.get("dpop");
|
|
496
|
+
if (ctx.scheme !== "dpop" || !proof) return { error: "dpop_proof_required" };
|
|
497
|
+
const bad = await verifyDpopProof(jose, proof, token, jkt, ctx.request, ctx.replayCache);
|
|
498
|
+
if (bad) return { error: bad };
|
|
499
|
+
dpop = true;
|
|
500
|
+
} else if (o.requireDpop) {
|
|
501
|
+
return { error: "token_not_dpop_bound" };
|
|
502
|
+
}
|
|
503
|
+
if (o.requiredScopes?.length) {
|
|
504
|
+
const granted = new Set(String(payload.scope ?? payload.scp ?? "").split(/\s+/));
|
|
505
|
+
const missing = o.requiredScopes.filter((s) => !granted.has(s));
|
|
506
|
+
if (missing.length) return { error: `missing_scopes:${missing.join(",")}` };
|
|
507
|
+
}
|
|
508
|
+
const act = payload.act;
|
|
509
|
+
const clientId = str(payload.client_id) ?? str(payload.azp);
|
|
510
|
+
const sub = str(payload.sub);
|
|
511
|
+
const agentId = str(act?.client_id) ?? str(act?.sub) ?? clientId ?? sub;
|
|
512
|
+
if (!agentId) return { error: "token_has_no_client_id" };
|
|
513
|
+
const user = act ? sub : sub && clientId && sub !== clientId ? sub : void 0;
|
|
514
|
+
const agent = {
|
|
515
|
+
id: `oauth2:${agentId}`,
|
|
516
|
+
name: str(payload.agent_name) ?? str(payload.client_name) ?? agentId,
|
|
517
|
+
vendor: str(payload.agent_vendor) ?? null,
|
|
518
|
+
claims: { iss: payload.iss, sub, scope: payload.scope ?? payload.scp, ...act ? { act } : {} },
|
|
519
|
+
dpop
|
|
520
|
+
};
|
|
521
|
+
if (user) {
|
|
522
|
+
const onBehalfOf = { sub: user };
|
|
523
|
+
if (str(payload.email)) onBehalfOf.email = str(payload.email);
|
|
524
|
+
if (str(payload.name)) onBehalfOf.name = str(payload.name);
|
|
525
|
+
agent.onBehalfOf = onBehalfOf;
|
|
526
|
+
}
|
|
527
|
+
return agent;
|
|
528
|
+
}
|
|
529
|
+
var PROTECTED_RESOURCE_PATH = "/.well-known/oauth-protected-resource";
|
|
530
|
+
function protectedResourceMetadata(o) {
|
|
531
|
+
return {
|
|
532
|
+
resource: o.resource,
|
|
533
|
+
authorization_servers: o.authorizationServers,
|
|
534
|
+
bearer_methods_supported: ["header"],
|
|
535
|
+
...o.scopesSupported ? { scopes_supported: o.scopesSupported } : {},
|
|
536
|
+
...o.resourceName ? { resource_name: o.resourceName } : {},
|
|
537
|
+
...o.dpop === false ? {} : { dpop_signing_alg_values_supported: ["ES256", "EdDSA", "RS256", "PS256"] }
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function oauthChallenge(resource, opts = {}) {
|
|
541
|
+
const meta = `${resource.replace(/\/$/, "")}${PROTECTED_RESOURCE_PATH}`;
|
|
542
|
+
const parts = [`resource_metadata="${meta}"`];
|
|
543
|
+
if (opts.error) parts.push(`error="${opts.error}"`);
|
|
544
|
+
if (opts.scope) parts.push(`scope="${opts.scope}"`);
|
|
545
|
+
return `Bearer ${parts.join(", ")}`;
|
|
546
|
+
}
|
|
547
|
+
|
|
321
548
|
// src/server/httpSignatures.ts
|
|
322
549
|
var SignatureError = class extends Error {
|
|
323
550
|
constructor(code, message) {
|
|
@@ -756,61 +983,15 @@ var KNOWN_SIGNERS = {
|
|
|
756
983
|
};
|
|
757
984
|
var GENERIC_AGENT_UA = /\b(bot|crawler|spider|agent|headless|scraper)\b/i;
|
|
758
985
|
var JWT_SHAPE = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*$/;
|
|
759
|
-
function
|
|
986
|
+
function credential(request) {
|
|
760
987
|
const h = request.headers.get("authorization");
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
-
function unverifiedJwtIssuer(token) {
|
|
764
|
-
try {
|
|
765
|
-
const payload = token.split(".")[1];
|
|
766
|
-
const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
767
|
-
const iss = JSON.parse(json).iss;
|
|
768
|
-
return typeof iss === "string" ? iss : null;
|
|
769
|
-
} catch {
|
|
770
|
-
return null;
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
var josePromise;
|
|
774
|
-
var remoteSets = /* @__PURE__ */ new Map();
|
|
775
|
-
async function verifyOAuth2(token, o) {
|
|
776
|
-
josePromise ??= import('jose');
|
|
777
|
-
const jose = await josePromise;
|
|
778
|
-
const keySet = o.jwks ? jose.createLocalJWKSet(o.jwks) : (() => {
|
|
779
|
-
const uri = o.jwksUri ?? `${o.issuer.replace(/\/$/, "")}/.well-known/jwks.json`;
|
|
780
|
-
let s = remoteSets.get(uri);
|
|
781
|
-
if (!s) {
|
|
782
|
-
s = jose.createRemoteJWKSet(new URL(uri), { cacheMaxAge: 36e5, cooldownDuration: 3e4 });
|
|
783
|
-
remoteSets.set(uri, s);
|
|
784
|
-
}
|
|
785
|
-
return s;
|
|
786
|
-
})();
|
|
787
|
-
try {
|
|
788
|
-
const { payload } = await jose.jwtVerify(token, keySet, {
|
|
789
|
-
issuer: o.issuer,
|
|
790
|
-
audience: o.audience,
|
|
791
|
-
algorithms: o.algorithms ?? ["RS256", "PS256", "ES256", "EdDSA"],
|
|
792
|
-
clockTolerance: o.clockToleranceSec ?? 30
|
|
793
|
-
});
|
|
794
|
-
if (o.requiredScopes?.length) {
|
|
795
|
-
const granted = new Set(String(payload.scope ?? payload.scp ?? "").split(/\s+/));
|
|
796
|
-
const missing = o.requiredScopes.filter((s) => !granted.has(s));
|
|
797
|
-
if (missing.length) return { error: `missing_scopes:${missing.join(",")}` };
|
|
798
|
-
}
|
|
799
|
-
const clientId = String(payload.client_id ?? payload.azp ?? payload.sub ?? "");
|
|
800
|
-
if (!clientId) return { error: "token_has_no_client_id" };
|
|
801
|
-
return {
|
|
802
|
-
id: `oauth2:${clientId}`,
|
|
803
|
-
name: typeof payload.agent_name === "string" ? payload.agent_name : clientId,
|
|
804
|
-
vendor: typeof payload.agent_vendor === "string" ? payload.agent_vendor : null,
|
|
805
|
-
method: "oauth2",
|
|
806
|
-
claims: { sub: payload.sub, scope: payload.scope ?? payload.scp }
|
|
807
|
-
};
|
|
808
|
-
} catch (e) {
|
|
809
|
-
return { error: `invalid_token:${e.code ?? e.message}` };
|
|
810
|
-
}
|
|
988
|
+
const m = h?.match(/^(bearer|dpop)\s+(.+)$/i);
|
|
989
|
+
return m ? { token: m[2].trim(), scheme: m[1].toLowerCase() } : null;
|
|
811
990
|
}
|
|
812
991
|
function createAgentAuth(options = {}) {
|
|
813
|
-
const
|
|
992
|
+
const replayCache = options.replayCache ?? memoryReplayCache();
|
|
993
|
+
const wba = options.webBotAuth === false ? null : { replayCache, ...typeof options.webBotAuth === "object" ? options.webBotAuth : {} };
|
|
994
|
+
const issuers = options.oauth2 ? Array.isArray(options.oauth2) ? options.oauth2 : [options.oauth2] : [];
|
|
814
995
|
const crawlers = options.crawlers === false ? null : typeof options.crawlers === "object" ? options.crawlers : {};
|
|
815
996
|
const keyPrefix = options.apiKey?.prefix ?? "agk_";
|
|
816
997
|
async function authenticate(request) {
|
|
@@ -839,7 +1020,8 @@ function createAgentAuth(options = {}) {
|
|
|
839
1020
|
claimedName ??= r.agentUrl ? new URL(r.agentUrl).hostname : void 0;
|
|
840
1021
|
}
|
|
841
1022
|
}
|
|
842
|
-
const
|
|
1023
|
+
const cred = credential(request);
|
|
1024
|
+
const token = cred?.token ?? request.headers.get("x-agent-key");
|
|
843
1025
|
if (token && options.apiKey && token.startsWith(keyPrefix)) {
|
|
844
1026
|
attempted.push("api-key");
|
|
845
1027
|
const id = await options.apiKey.verify(token);
|
|
@@ -856,12 +1038,23 @@ function createAgentAuth(options = {}) {
|
|
|
856
1038
|
};
|
|
857
1039
|
}
|
|
858
1040
|
reasons.push("api-key:unknown_or_revoked");
|
|
859
|
-
} else if (
|
|
860
|
-
const iss =
|
|
861
|
-
|
|
1041
|
+
} else if (cred && issuers.length && JWT_SHAPE.test(cred.token)) {
|
|
1042
|
+
const iss = unverifiedIssuer(cred.token);
|
|
1043
|
+
const config = issuers.find((i) => i.issuer === iss);
|
|
1044
|
+
if (config) {
|
|
862
1045
|
attempted.push("oauth2");
|
|
863
|
-
const r = await
|
|
864
|
-
if (!("error" in r))
|
|
1046
|
+
const r = await verifyOAuthToken(cred.token, config, { request, scheme: cred.scheme, replayCache });
|
|
1047
|
+
if (!("error" in r)) {
|
|
1048
|
+
const agent = {
|
|
1049
|
+
id: r.id,
|
|
1050
|
+
name: r.name,
|
|
1051
|
+
vendor: r.vendor,
|
|
1052
|
+
method: "oauth2",
|
|
1053
|
+
claims: { ...r.claims, dpop: r.dpop }
|
|
1054
|
+
};
|
|
1055
|
+
if (r.onBehalfOf) agent.onBehalfOf = r.onBehalfOf;
|
|
1056
|
+
return { status: "verified", agent };
|
|
1057
|
+
}
|
|
865
1058
|
reasons.push(`oauth2:${r.error}`);
|
|
866
1059
|
}
|
|
867
1060
|
}
|
|
@@ -871,11 +1064,11 @@ function createAgentAuth(options = {}) {
|
|
|
871
1064
|
claimedName ??= claim.name;
|
|
872
1065
|
if (crawlers) {
|
|
873
1066
|
attempted.push("verified-crawler");
|
|
874
|
-
const v = await verifyCrawler(claim, clientIp(request, crawlers.clientIp), crawlers.resolver);
|
|
1067
|
+
const v = await verifyCrawler(claim, clientIp(request, crawlers.clientIp), crawlers.resolver, crawlers);
|
|
875
1068
|
if (v.status === "verified") {
|
|
876
1069
|
return {
|
|
877
1070
|
status: "verified",
|
|
878
|
-
agent: { id: `crawler:${claim.name}`, name: claim.name, vendor: null, method: "verified-crawler", claims: { host: v.host } }
|
|
1071
|
+
agent: { id: `crawler:${claim.name}`, name: claim.name, vendor: null, method: "verified-crawler", claims: { host: v.host, via: v.via } }
|
|
879
1072
|
};
|
|
880
1073
|
}
|
|
881
1074
|
reasons.push(`crawler:${v.reason}`);
|
|
@@ -936,6 +1129,7 @@ function toTraceEvent(result, ctx) {
|
|
|
936
1129
|
if (result.status === "none") return null;
|
|
937
1130
|
const url = new URL(ctx.request.url);
|
|
938
1131
|
const verified = result.status === "verified";
|
|
1132
|
+
const delegated = verified && Boolean(result.agent.onBehalfOf);
|
|
939
1133
|
return {
|
|
940
1134
|
id: `evt_${crypto.randomUUID()}`,
|
|
941
1135
|
siteId: ctx.siteId,
|
|
@@ -944,12 +1138,13 @@ function toTraceEvent(result, ctx) {
|
|
|
944
1138
|
type: "auth.identity_presented",
|
|
945
1139
|
agent: {
|
|
946
1140
|
class: "crawler",
|
|
947
|
-
|
|
1141
|
+
// Unverified claims stay "declared"; a token acting for a signed-in user is "linked".
|
|
1142
|
+
trust: delegated ? "linked" : verified ? "verified" : "declared",
|
|
948
1143
|
confidence: verified ? 1 : 0.5,
|
|
949
1144
|
vendor: verified ? result.agent.vendor ?? result.agent.name : result.claimedName ?? null,
|
|
950
1145
|
userAgent: ctx.request.headers.get("user-agent"),
|
|
951
1146
|
detectionVersion: "2026.09",
|
|
952
|
-
signals: { surface: "server" }
|
|
1147
|
+
signals: { surface: "server", ...verified ? { method: result.agent.method } : {} }
|
|
953
1148
|
},
|
|
954
1149
|
outcome: verified ? "success" : "error",
|
|
955
1150
|
...verified ? {} : { error: result.reason },
|
|
@@ -1000,6 +1195,6 @@ function expressAgentAuth(options = {}) {
|
|
|
1000
1195
|
};
|
|
1001
1196
|
}
|
|
1002
1197
|
|
|
1003
|
-
export { AGENT_HEADERS, DIRECTORY_PATH, RDNS_DOMAINS, WEB_BOT_AUTH_TAG, classifyUserAgent, clientIp, createAgentAuth, createAgentAuthHandler, expressAgentAuth, generateAgentKey, hashAgentKey, jwkThumbprint, memoryReplayCache, readAgentHeaders, signatureBase, staticKeyVerifier, toTraceEvent, verifyCrawler, verifyWebBotAuth, withAgentHeaders };
|
|
1004
|
-
//# sourceMappingURL=chunk-
|
|
1005
|
-
//# sourceMappingURL=chunk-
|
|
1198
|
+
export { AGENT_HEADERS, DIRECTORY_PATH, PROTECTED_RESOURCE_PATH, PUBLISHED_IP_RANGES, RDNS_DOMAINS, WEB_BOT_AUTH_TAG, classifyUserAgent, clientIp, createAgentAuth, createAgentAuthHandler, expressAgentAuth, generateAgentKey, hashAgentKey, ipInCidr, ipInRanges, jwkThumbprint, memoryReplayCache, oauthChallenge, protectedResourceMetadata, rangesFor, readAgentHeaders, signatureBase, staticKeyVerifier, toTraceEvent, verifyCrawler, verifyOAuthToken, verifyWebBotAuth, withAgentHeaders };
|
|
1199
|
+
//# sourceMappingURL=chunk-6QQS26AP.js.map
|
|
1200
|
+
//# sourceMappingURL=chunk-6QQS26AP.js.map
|