@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
package/dist/next.cjs
CHANGED
|
@@ -6,9 +6,12 @@ var CRAWLER_SIGNATURES = [
|
|
|
6
6
|
{ name: "GPTBot", category: "ai", pattern: /GPTBot/i },
|
|
7
7
|
{ name: "OAI-SearchBot", category: "ai", pattern: /OAI-SearchBot/i },
|
|
8
8
|
{ name: "ChatGPT-User", category: "ai", pattern: /ChatGPT-User/i },
|
|
9
|
+
{ name: "Claude-User", category: "ai", pattern: /Claude-User/i },
|
|
10
|
+
{ name: "Claude-SearchBot", category: "ai", pattern: /Claude-SearchBot/i },
|
|
9
11
|
{ name: "ClaudeBot", category: "ai", pattern: /ClaudeBot/i },
|
|
10
12
|
{ name: "Claude-Web", category: "ai", pattern: /Claude-Web/i },
|
|
11
13
|
{ name: "anthropic-ai", category: "ai", pattern: /anthropic-ai/i },
|
|
14
|
+
{ name: "Perplexity-User", category: "ai", pattern: /Perplexity-User/i },
|
|
12
15
|
{ name: "PerplexityBot", category: "ai", pattern: /PerplexityBot/i },
|
|
13
16
|
{ name: "Google-Extended", category: "ai", pattern: /Google-Extended/i },
|
|
14
17
|
{ name: "Applebot-Extended", category: "ai", pattern: /Applebot-Extended/i },
|
|
@@ -26,6 +29,96 @@ var CRAWLER_SIGNATURES = [
|
|
|
26
29
|
{ name: "Applebot", category: "search", pattern: /Applebot/i }
|
|
27
30
|
];
|
|
28
31
|
|
|
32
|
+
// src/server/ipRanges.ts
|
|
33
|
+
var PUBLISHED_IP_RANGES = {
|
|
34
|
+
GPTBot: ["https://openai.com/gptbot.json"],
|
|
35
|
+
"OAI-SearchBot": ["https://openai.com/searchbot.json"],
|
|
36
|
+
"ChatGPT-User": ["https://openai.com/chatgpt-user.json"],
|
|
37
|
+
PerplexityBot: ["https://www.perplexity.ai/perplexitybot.json"],
|
|
38
|
+
"Perplexity-User": ["https://www.perplexity.ai/perplexity-user.json"],
|
|
39
|
+
Googlebot: ["https://developers.google.com/static/crawling/ipranges/common-crawlers.json"],
|
|
40
|
+
Bingbot: ["https://www.bing.com/toolbox/bingbot.json"],
|
|
41
|
+
DuckDuckBot: ["https://duckduckgo.com/duckduckbot.json"],
|
|
42
|
+
CCBot: ["https://index.commoncrawl.org/ccbot.json"]
|
|
43
|
+
};
|
|
44
|
+
var TTL_MS = 24 * 36e5;
|
|
45
|
+
var FAILED_TTL_MS = 10 * 6e4;
|
|
46
|
+
var cache = /* @__PURE__ */ new Map();
|
|
47
|
+
async function loadUrl(url, fetcher) {
|
|
48
|
+
const hit = cache.get(url);
|
|
49
|
+
if (hit && hit.until > Date.now()) return hit.cidrs;
|
|
50
|
+
try {
|
|
51
|
+
const res = await fetcher(url, { signal: AbortSignal.timeout(5e3), redirect: "follow" });
|
|
52
|
+
if (!res.ok) throw new Error(String(res.status));
|
|
53
|
+
const body = await res.json();
|
|
54
|
+
const cidrs = (body.prefixes ?? []).flatMap((p) => [p.ipv4Prefix, p.ipv6Prefix]).filter((c) => typeof c === "string");
|
|
55
|
+
cache.set(url, { cidrs, until: Date.now() + TTL_MS });
|
|
56
|
+
return cidrs;
|
|
57
|
+
} catch {
|
|
58
|
+
const cidrs = hit?.cidrs ?? [];
|
|
59
|
+
cache.set(url, { cidrs, until: Date.now() + FAILED_TTL_MS });
|
|
60
|
+
return cidrs;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function rangesFor(name, options = {}) {
|
|
64
|
+
const fixed = options.ipRanges?.[name];
|
|
65
|
+
if (fixed) return fixed;
|
|
66
|
+
const urls = PUBLISHED_IP_RANGES[name];
|
|
67
|
+
if (!urls) return null;
|
|
68
|
+
const fetcher = options.fetcher ?? fetch;
|
|
69
|
+
return (await Promise.all(urls.map((u) => loadUrl(u, fetcher)))).flat();
|
|
70
|
+
}
|
|
71
|
+
function v4ToBigInt(ip) {
|
|
72
|
+
const parts = ip.split(".");
|
|
73
|
+
if (parts.length !== 4) return null;
|
|
74
|
+
let n = 0n;
|
|
75
|
+
for (const p of parts) {
|
|
76
|
+
if (!/^\d{1,3}$/.test(p) || Number(p) > 255) return null;
|
|
77
|
+
n = n << 8n | BigInt(p);
|
|
78
|
+
}
|
|
79
|
+
return n;
|
|
80
|
+
}
|
|
81
|
+
function v6ToBigInt(ip) {
|
|
82
|
+
let s = ip.toLowerCase().replace(/^\[|\]$/g, "");
|
|
83
|
+
const zone = s.indexOf("%");
|
|
84
|
+
if (zone >= 0) s = s.slice(0, zone);
|
|
85
|
+
const v4 = s.match(/(\d+\.\d+\.\d+\.\d+)$/);
|
|
86
|
+
if (v4) {
|
|
87
|
+
const n2 = v4ToBigInt(v4[1]);
|
|
88
|
+
if (n2 === null) return null;
|
|
89
|
+
s = s.slice(0, -v4[1].length) + (n2 >> 16n & 0xffffn).toString(16) + ":" + (n2 & 0xffffn).toString(16);
|
|
90
|
+
}
|
|
91
|
+
const halves = s.split("::");
|
|
92
|
+
if (halves.length > 2) return null;
|
|
93
|
+
const head = halves[0] ? halves[0].split(":") : [];
|
|
94
|
+
const tail = halves.length === 2 && halves[1] ? halves[1].split(":") : [];
|
|
95
|
+
const missing = 8 - head.length - tail.length;
|
|
96
|
+
if (halves.length === 1 ? missing !== 0 : missing < 1) return null;
|
|
97
|
+
const groups = [...head, ...Array(halves.length === 2 ? missing : 0).fill("0"), ...tail];
|
|
98
|
+
let n = 0n;
|
|
99
|
+
for (const g of groups) {
|
|
100
|
+
if (!/^[0-9a-f]{1,4}$/.test(g)) return null;
|
|
101
|
+
n = n << 16n | BigInt(parseInt(g, 16));
|
|
102
|
+
}
|
|
103
|
+
return n;
|
|
104
|
+
}
|
|
105
|
+
function ipInCidr(ip, cidr) {
|
|
106
|
+
const [range, bitsRaw] = cidr.split("/");
|
|
107
|
+
if (!range) return false;
|
|
108
|
+
const isV6 = range.includes(":");
|
|
109
|
+
const mapped = ip.toLowerCase().match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
|
|
110
|
+
const candidate = !isV6 && mapped ? mapped[1] : ip;
|
|
111
|
+
const width = isV6 ? 128 : 32;
|
|
112
|
+
const bits = bitsRaw === void 0 ? width : Number(bitsRaw);
|
|
113
|
+
if (!Number.isInteger(bits) || bits < 0 || bits > width) return false;
|
|
114
|
+
const a = isV6 ? v6ToBigInt(candidate) : v4ToBigInt(candidate);
|
|
115
|
+
const b = isV6 ? v6ToBigInt(range) : v4ToBigInt(range);
|
|
116
|
+
if (a === null || b === null) return false;
|
|
117
|
+
const shift = BigInt(width - bits);
|
|
118
|
+
return a >> shift === b >> shift;
|
|
119
|
+
}
|
|
120
|
+
var ipInRanges = (ip, cidrs) => cidrs.some((c) => ipInCidr(ip, c));
|
|
121
|
+
|
|
29
122
|
// src/server/crawlers.ts
|
|
30
123
|
var RDNS_DOMAINS = {
|
|
31
124
|
Googlebot: ["googlebot.com", "google.com", "googleusercontent.com"],
|
|
@@ -64,14 +157,19 @@ async function nodeResolver() {
|
|
|
64
157
|
}
|
|
65
158
|
}
|
|
66
159
|
var rdnsCache = /* @__PURE__ */ new Map();
|
|
67
|
-
async function verifyCrawler(claim, ip, resolver) {
|
|
160
|
+
async function verifyCrawler(claim, ip, resolver, ranges = {}) {
|
|
68
161
|
const domains = RDNS_DOMAINS[claim.name];
|
|
69
|
-
|
|
162
|
+
const cidrs = await rangesFor(claim.name, ranges);
|
|
163
|
+
if (!domains && !cidrs) return { status: "unverified", name: claim.name, reason: "no_verification_method_for_vendor" };
|
|
70
164
|
if (!ip) return { status: "unverified", name: claim.name, reason: "client_ip_unknown" };
|
|
165
|
+
if (cidrs?.length && ipInRanges(ip, cidrs)) {
|
|
166
|
+
return { status: "verified", name: claim.name, host: ip, ip, via: "ip-range" };
|
|
167
|
+
}
|
|
168
|
+
if (!domains) return { status: "unverified", name: claim.name, reason: "ip_outside_published_ranges" };
|
|
71
169
|
const key = `${claim.name}|${ip}`;
|
|
72
170
|
const hit = rdnsCache.get(key);
|
|
73
171
|
if (hit && hit.until > Date.now()) {
|
|
74
|
-
return hit.ok ? { status: "verified", name: claim.name, host: hit.host, ip } : { status: "unverified", name: claim.name, reason: "rdns_mismatch" };
|
|
172
|
+
return hit.ok ? { status: "verified", name: claim.name, host: hit.host, ip, via: "rdns" } : { status: "unverified", name: claim.name, reason: "rdns_mismatch" };
|
|
75
173
|
}
|
|
76
174
|
const dns = resolver ?? await nodeResolver();
|
|
77
175
|
if (!dns) return { status: "unverified", name: claim.name, reason: "dns_unavailable_in_runtime" };
|
|
@@ -87,7 +185,7 @@ async function verifyCrawler(claim, ip, resolver) {
|
|
|
87
185
|
const forward = await dns.lookup(host);
|
|
88
186
|
if (forward.includes(ip)) {
|
|
89
187
|
remember(true, host);
|
|
90
|
-
return { status: "verified", name: claim.name, host, ip };
|
|
188
|
+
return { status: "verified", name: claim.name, host, ip, via: "rdns" };
|
|
91
189
|
}
|
|
92
190
|
}
|
|
93
191
|
remember(false);
|
|
@@ -320,6 +418,117 @@ function bytesToBase64(bytes) {
|
|
|
320
418
|
}
|
|
321
419
|
var bytesToBase64Url = (bytes) => bytesToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
322
420
|
|
|
421
|
+
// src/server/oauth.ts
|
|
422
|
+
var josePromise;
|
|
423
|
+
var loadJose = () => josePromise ??= import('jose');
|
|
424
|
+
var remoteSets = /* @__PURE__ */ new Map();
|
|
425
|
+
var ASYMMETRIC = ["RS256", "PS256", "ES256", "EdDSA"];
|
|
426
|
+
function unverifiedIssuer(token) {
|
|
427
|
+
try {
|
|
428
|
+
const payload = token.split(".")[1];
|
|
429
|
+
const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
430
|
+
const iss = JSON.parse(json).iss;
|
|
431
|
+
return typeof iss === "string" ? iss : null;
|
|
432
|
+
} catch {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
var str = (v) => typeof v === "string" && v ? v : void 0;
|
|
437
|
+
async function sha256B64u(text) {
|
|
438
|
+
const d = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
|
|
439
|
+
return bytesToBase64Url(new Uint8Array(d));
|
|
440
|
+
}
|
|
441
|
+
var htuOf = (url) => {
|
|
442
|
+
const u = new URL(url);
|
|
443
|
+
return `${u.origin}${u.pathname}`;
|
|
444
|
+
};
|
|
445
|
+
async function verifyDpopProof(jose, proof, token, jkt, request, replay) {
|
|
446
|
+
try {
|
|
447
|
+
const { payload, protectedHeader } = await jose.jwtVerify(proof, jose.EmbeddedJWK, {
|
|
448
|
+
typ: "dpop+jwt",
|
|
449
|
+
algorithms: ASYMMETRIC
|
|
450
|
+
});
|
|
451
|
+
const jwk = protectedHeader.jwk;
|
|
452
|
+
if (!jwk) return "dpop_missing_jwk";
|
|
453
|
+
if (await jose.calculateJwkThumbprint(jwk, "sha256") !== jkt) return "dpop_key_mismatch";
|
|
454
|
+
if (str(payload.htm)?.toUpperCase() !== request.method.toUpperCase()) return "dpop_htm_mismatch";
|
|
455
|
+
if (str(payload.htu) === void 0 || htuOf(str(payload.htu)) !== htuOf(request.url)) return "dpop_htu_mismatch";
|
|
456
|
+
const iat = typeof payload.iat === "number" ? payload.iat : NaN;
|
|
457
|
+
if (!Number.isFinite(iat) || Math.abs(Date.now() / 1e3 - iat) > 300) return "dpop_stale";
|
|
458
|
+
if (str(payload.ath) !== await sha256B64u(token)) return "dpop_ath_mismatch";
|
|
459
|
+
const jti = str(payload.jti);
|
|
460
|
+
if (!jti) return "dpop_missing_jti";
|
|
461
|
+
if (replay) {
|
|
462
|
+
const key = `dpop:${jkt}:${jti}`;
|
|
463
|
+
if (await replay.has(key)) return "dpop_replayed";
|
|
464
|
+
await replay.add(key, 600);
|
|
465
|
+
}
|
|
466
|
+
return null;
|
|
467
|
+
} catch (e) {
|
|
468
|
+
return `dpop_invalid:${e.code ?? e.message}`;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
async function verifyOAuthToken(token, o, ctx) {
|
|
472
|
+
const jose = await loadJose();
|
|
473
|
+
const keySet = o.jwks ? jose.createLocalJWKSet(o.jwks) : (() => {
|
|
474
|
+
const uri = o.jwksUri ?? `${o.issuer.replace(/\/$/, "")}/.well-known/jwks.json`;
|
|
475
|
+
let s = remoteSets.get(uri);
|
|
476
|
+
if (!s) {
|
|
477
|
+
s = jose.createRemoteJWKSet(new URL(uri), { cacheMaxAge: 36e5, cooldownDuration: 3e4 });
|
|
478
|
+
remoteSets.set(uri, s);
|
|
479
|
+
}
|
|
480
|
+
return s;
|
|
481
|
+
})();
|
|
482
|
+
let payload;
|
|
483
|
+
try {
|
|
484
|
+
;
|
|
485
|
+
({ payload } = await jose.jwtVerify(token, keySet, {
|
|
486
|
+
issuer: o.issuer,
|
|
487
|
+
audience: o.audience,
|
|
488
|
+
algorithms: o.algorithms ?? ASYMMETRIC,
|
|
489
|
+
clockTolerance: o.clockToleranceSec ?? 30
|
|
490
|
+
}));
|
|
491
|
+
} catch (e) {
|
|
492
|
+
return { error: `invalid_token:${e.code ?? e.message}` };
|
|
493
|
+
}
|
|
494
|
+
const jkt = str(payload.cnf?.jkt);
|
|
495
|
+
let dpop = false;
|
|
496
|
+
if (jkt) {
|
|
497
|
+
const proof = ctx.request.headers.get("dpop");
|
|
498
|
+
if (ctx.scheme !== "dpop" || !proof) return { error: "dpop_proof_required" };
|
|
499
|
+
const bad = await verifyDpopProof(jose, proof, token, jkt, ctx.request, ctx.replayCache);
|
|
500
|
+
if (bad) return { error: bad };
|
|
501
|
+
dpop = true;
|
|
502
|
+
} else if (o.requireDpop) {
|
|
503
|
+
return { error: "token_not_dpop_bound" };
|
|
504
|
+
}
|
|
505
|
+
if (o.requiredScopes?.length) {
|
|
506
|
+
const granted = new Set(String(payload.scope ?? payload.scp ?? "").split(/\s+/));
|
|
507
|
+
const missing = o.requiredScopes.filter((s) => !granted.has(s));
|
|
508
|
+
if (missing.length) return { error: `missing_scopes:${missing.join(",")}` };
|
|
509
|
+
}
|
|
510
|
+
const act = payload.act;
|
|
511
|
+
const clientId = str(payload.client_id) ?? str(payload.azp);
|
|
512
|
+
const sub = str(payload.sub);
|
|
513
|
+
const agentId = str(act?.client_id) ?? str(act?.sub) ?? clientId ?? sub;
|
|
514
|
+
if (!agentId) return { error: "token_has_no_client_id" };
|
|
515
|
+
const user = act ? sub : sub && clientId && sub !== clientId ? sub : void 0;
|
|
516
|
+
const agent = {
|
|
517
|
+
id: `oauth2:${agentId}`,
|
|
518
|
+
name: str(payload.agent_name) ?? str(payload.client_name) ?? agentId,
|
|
519
|
+
vendor: str(payload.agent_vendor) ?? null,
|
|
520
|
+
claims: { iss: payload.iss, sub, scope: payload.scope ?? payload.scp, ...act ? { act } : {} },
|
|
521
|
+
dpop
|
|
522
|
+
};
|
|
523
|
+
if (user) {
|
|
524
|
+
const onBehalfOf = { sub: user };
|
|
525
|
+
if (str(payload.email)) onBehalfOf.email = str(payload.email);
|
|
526
|
+
if (str(payload.name)) onBehalfOf.name = str(payload.name);
|
|
527
|
+
agent.onBehalfOf = onBehalfOf;
|
|
528
|
+
}
|
|
529
|
+
return agent;
|
|
530
|
+
}
|
|
531
|
+
|
|
323
532
|
// src/server/httpSignatures.ts
|
|
324
533
|
var SignatureError = class extends Error {
|
|
325
534
|
constructor(code, message) {
|
|
@@ -758,61 +967,15 @@ var KNOWN_SIGNERS = {
|
|
|
758
967
|
};
|
|
759
968
|
var GENERIC_AGENT_UA = /\b(bot|crawler|spider|agent|headless|scraper)\b/i;
|
|
760
969
|
var JWT_SHAPE = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*$/;
|
|
761
|
-
function
|
|
970
|
+
function credential(request) {
|
|
762
971
|
const h = request.headers.get("authorization");
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
function unverifiedJwtIssuer(token) {
|
|
766
|
-
try {
|
|
767
|
-
const payload = token.split(".")[1];
|
|
768
|
-
const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
769
|
-
const iss = JSON.parse(json).iss;
|
|
770
|
-
return typeof iss === "string" ? iss : null;
|
|
771
|
-
} catch {
|
|
772
|
-
return null;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
var josePromise;
|
|
776
|
-
var remoteSets = /* @__PURE__ */ new Map();
|
|
777
|
-
async function verifyOAuth2(token, o) {
|
|
778
|
-
josePromise ??= import('jose');
|
|
779
|
-
const jose = await josePromise;
|
|
780
|
-
const keySet = o.jwks ? jose.createLocalJWKSet(o.jwks) : (() => {
|
|
781
|
-
const uri = o.jwksUri ?? `${o.issuer.replace(/\/$/, "")}/.well-known/jwks.json`;
|
|
782
|
-
let s = remoteSets.get(uri);
|
|
783
|
-
if (!s) {
|
|
784
|
-
s = jose.createRemoteJWKSet(new URL(uri), { cacheMaxAge: 36e5, cooldownDuration: 3e4 });
|
|
785
|
-
remoteSets.set(uri, s);
|
|
786
|
-
}
|
|
787
|
-
return s;
|
|
788
|
-
})();
|
|
789
|
-
try {
|
|
790
|
-
const { payload } = await jose.jwtVerify(token, keySet, {
|
|
791
|
-
issuer: o.issuer,
|
|
792
|
-
audience: o.audience,
|
|
793
|
-
algorithms: o.algorithms ?? ["RS256", "PS256", "ES256", "EdDSA"],
|
|
794
|
-
clockTolerance: o.clockToleranceSec ?? 30
|
|
795
|
-
});
|
|
796
|
-
if (o.requiredScopes?.length) {
|
|
797
|
-
const granted = new Set(String(payload.scope ?? payload.scp ?? "").split(/\s+/));
|
|
798
|
-
const missing = o.requiredScopes.filter((s) => !granted.has(s));
|
|
799
|
-
if (missing.length) return { error: `missing_scopes:${missing.join(",")}` };
|
|
800
|
-
}
|
|
801
|
-
const clientId = String(payload.client_id ?? payload.azp ?? payload.sub ?? "");
|
|
802
|
-
if (!clientId) return { error: "token_has_no_client_id" };
|
|
803
|
-
return {
|
|
804
|
-
id: `oauth2:${clientId}`,
|
|
805
|
-
name: typeof payload.agent_name === "string" ? payload.agent_name : clientId,
|
|
806
|
-
vendor: typeof payload.agent_vendor === "string" ? payload.agent_vendor : null,
|
|
807
|
-
method: "oauth2",
|
|
808
|
-
claims: { sub: payload.sub, scope: payload.scope ?? payload.scp }
|
|
809
|
-
};
|
|
810
|
-
} catch (e) {
|
|
811
|
-
return { error: `invalid_token:${e.code ?? e.message}` };
|
|
812
|
-
}
|
|
972
|
+
const m = h?.match(/^(bearer|dpop)\s+(.+)$/i);
|
|
973
|
+
return m ? { token: m[2].trim(), scheme: m[1].toLowerCase() } : null;
|
|
813
974
|
}
|
|
814
975
|
function createAgentAuth(options = {}) {
|
|
815
|
-
const
|
|
976
|
+
const replayCache = options.replayCache ?? memoryReplayCache();
|
|
977
|
+
const wba = options.webBotAuth === false ? null : { replayCache, ...typeof options.webBotAuth === "object" ? options.webBotAuth : {} };
|
|
978
|
+
const issuers = options.oauth2 ? Array.isArray(options.oauth2) ? options.oauth2 : [options.oauth2] : [];
|
|
816
979
|
const crawlers = options.crawlers === false ? null : typeof options.crawlers === "object" ? options.crawlers : {};
|
|
817
980
|
const keyPrefix = options.apiKey?.prefix ?? "agk_";
|
|
818
981
|
async function authenticate(request) {
|
|
@@ -841,7 +1004,8 @@ function createAgentAuth(options = {}) {
|
|
|
841
1004
|
claimedName ??= r.agentUrl ? new URL(r.agentUrl).hostname : void 0;
|
|
842
1005
|
}
|
|
843
1006
|
}
|
|
844
|
-
const
|
|
1007
|
+
const cred = credential(request);
|
|
1008
|
+
const token = cred?.token ?? request.headers.get("x-agent-key");
|
|
845
1009
|
if (token && options.apiKey && token.startsWith(keyPrefix)) {
|
|
846
1010
|
attempted.push("api-key");
|
|
847
1011
|
const id = await options.apiKey.verify(token);
|
|
@@ -858,12 +1022,23 @@ function createAgentAuth(options = {}) {
|
|
|
858
1022
|
};
|
|
859
1023
|
}
|
|
860
1024
|
reasons.push("api-key:unknown_or_revoked");
|
|
861
|
-
} else if (
|
|
862
|
-
const iss =
|
|
863
|
-
|
|
1025
|
+
} else if (cred && issuers.length && JWT_SHAPE.test(cred.token)) {
|
|
1026
|
+
const iss = unverifiedIssuer(cred.token);
|
|
1027
|
+
const config = issuers.find((i) => i.issuer === iss);
|
|
1028
|
+
if (config) {
|
|
864
1029
|
attempted.push("oauth2");
|
|
865
|
-
const r = await
|
|
866
|
-
if (!("error" in r))
|
|
1030
|
+
const r = await verifyOAuthToken(cred.token, config, { request, scheme: cred.scheme, replayCache });
|
|
1031
|
+
if (!("error" in r)) {
|
|
1032
|
+
const agent = {
|
|
1033
|
+
id: r.id,
|
|
1034
|
+
name: r.name,
|
|
1035
|
+
vendor: r.vendor,
|
|
1036
|
+
method: "oauth2",
|
|
1037
|
+
claims: { ...r.claims, dpop: r.dpop }
|
|
1038
|
+
};
|
|
1039
|
+
if (r.onBehalfOf) agent.onBehalfOf = r.onBehalfOf;
|
|
1040
|
+
return { status: "verified", agent };
|
|
1041
|
+
}
|
|
867
1042
|
reasons.push(`oauth2:${r.error}`);
|
|
868
1043
|
}
|
|
869
1044
|
}
|
|
@@ -873,11 +1048,11 @@ function createAgentAuth(options = {}) {
|
|
|
873
1048
|
claimedName ??= claim.name;
|
|
874
1049
|
if (crawlers) {
|
|
875
1050
|
attempted.push("verified-crawler");
|
|
876
|
-
const v = await verifyCrawler(claim, clientIp(request, crawlers.clientIp), crawlers.resolver);
|
|
1051
|
+
const v = await verifyCrawler(claim, clientIp(request, crawlers.clientIp), crawlers.resolver, crawlers);
|
|
877
1052
|
if (v.status === "verified") {
|
|
878
1053
|
return {
|
|
879
1054
|
status: "verified",
|
|
880
|
-
agent: { id: `crawler:${claim.name}`, name: claim.name, vendor: null, method: "verified-crawler", claims: { host: v.host } }
|
|
1055
|
+
agent: { id: `crawler:${claim.name}`, name: claim.name, vendor: null, method: "verified-crawler", claims: { host: v.host, via: v.via } }
|
|
881
1056
|
};
|
|
882
1057
|
}
|
|
883
1058
|
reasons.push(`crawler:${v.reason}`);
|