@agent-score/commerce 2.4.0 → 2.5.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/challenge/index.d.mts +5 -1
- package/dist/challenge/index.d.ts +5 -1
- package/dist/challenge/index.js +11 -4
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +11 -4
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/{checkout-B-MIzYzW.d.ts → checkout-McfNpZJf.d.ts} +72 -1
- package/dist/{checkout-Bn7ZKIBD.d.mts → checkout-o17dIxHi.d.mts} +72 -1
- package/dist/core.d.mts +23 -1
- package/dist/core.d.ts +23 -1
- package/dist/core.js +25 -11
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +25 -11
- package/dist/core.mjs.map +1 -1
- package/dist/discovery/index.d.mts +17 -2
- package/dist/discovery/index.d.ts +17 -2
- package/dist/discovery/index.js +14 -4
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +14 -4
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/gate-CWP10xPQ.d.mts +339 -0
- package/dist/gate-CWP10xPQ.d.ts +339 -0
- package/dist/identity/express.d.mts +26 -1
- package/dist/identity/express.d.ts +26 -1
- package/dist/identity/express.js +587 -13
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +583 -12
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +12 -2
- package/dist/identity/fastify.d.ts +12 -2
- package/dist/identity/fastify.js +595 -13
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +591 -12
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +26 -1
- package/dist/identity/hono.d.ts +26 -1
- package/dist/identity/hono.js +576 -13
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +572 -12
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.d.mts +3 -0
- package/dist/identity/nextjs.d.ts +3 -0
- package/dist/identity/nextjs.js +581 -13
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +577 -12
- package/dist/identity/nextjs.mjs.map +1 -1
- package/dist/identity/web.d.mts +24 -1
- package/dist/identity/web.d.ts +24 -1
- package/dist/identity/web.js +581 -13
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +577 -12
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.d.mts +119 -3
- package/dist/index.d.ts +119 -3
- package/dist/index.js +893 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +873 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -583,12 +583,12 @@ async function buildEnvSigningKey(opts) {
|
|
|
583
583
|
);
|
|
584
584
|
}
|
|
585
585
|
const canonicalPrivateJwk = detectedAlg === "EdDSA" ? { kty: jwkDict.kty, crv: jwkDict.crv, x: jwkDict.x, d: jwkDict.d } : { kty: jwkDict.kty, crv: jwkDict.crv, x: jwkDict.x, y: jwkDict.y, d: jwkDict.d };
|
|
586
|
-
const { importJWK } = await import("jose");
|
|
586
|
+
const { importJWK: importJWK3 } = await import("jose");
|
|
587
587
|
const { createPublicKey } = await import("crypto");
|
|
588
588
|
let privateKey;
|
|
589
589
|
let publicNodeKey;
|
|
590
590
|
try {
|
|
591
|
-
privateKey = await
|
|
591
|
+
privateKey = await importJWK3(
|
|
592
592
|
canonicalPrivateJwk,
|
|
593
593
|
detectedAlg
|
|
594
594
|
);
|
|
@@ -7951,13 +7951,13 @@ var init_schemas = __esm({
|
|
|
7951
7951
|
}
|
|
7952
7952
|
return propValues;
|
|
7953
7953
|
});
|
|
7954
|
-
const
|
|
7954
|
+
const isObject3 = isObject;
|
|
7955
7955
|
const catchall2 = def.catchall;
|
|
7956
7956
|
let value;
|
|
7957
7957
|
inst._zod.parse = (payload, ctx) => {
|
|
7958
7958
|
value ?? (value = _normalized.value);
|
|
7959
7959
|
const input = payload.value;
|
|
7960
|
-
if (!
|
|
7960
|
+
if (!isObject3(input)) {
|
|
7961
7961
|
payload.issues.push({
|
|
7962
7962
|
expected: "object",
|
|
7963
7963
|
code: "invalid_type",
|
|
@@ -8084,7 +8084,7 @@ var init_schemas = __esm({
|
|
|
8084
8084
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
8085
8085
|
};
|
|
8086
8086
|
let fastpass;
|
|
8087
|
-
const
|
|
8087
|
+
const isObject3 = isObject;
|
|
8088
8088
|
const jit = !globalConfig.jitless;
|
|
8089
8089
|
const allowsEval2 = allowsEval;
|
|
8090
8090
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -8093,7 +8093,7 @@ var init_schemas = __esm({
|
|
|
8093
8093
|
inst._zod.parse = (payload, ctx) => {
|
|
8094
8094
|
value ?? (value = _normalized.value);
|
|
8095
8095
|
const input = payload.value;
|
|
8096
|
-
if (!
|
|
8096
|
+
if (!isObject3(input)) {
|
|
8097
8097
|
payload.issues.push({
|
|
8098
8098
|
expected: "object",
|
|
8099
8099
|
code: "invalid_type",
|
|
@@ -20857,15 +20857,26 @@ var index_exports = {};
|
|
|
20857
20857
|
__export(index_exports, {
|
|
20858
20858
|
A2A_DEFAULT_TRANSPORT: () => A2A_DEFAULT_TRANSPORT,
|
|
20859
20859
|
A2A_PROTOCOL_VERSION: () => A2A_PROTOCOL_VERSION,
|
|
20860
|
+
AGENTSCORE_CANONICAL_ISSUER: () => AGENTSCORE_CANONICAL_ISSUER,
|
|
20860
20861
|
AGENTSCORE_UCP_CAPABILITY: () => AGENTSCORE_UCP_CAPABILITY,
|
|
20862
|
+
AGENT_IDENTITY_HEADER: () => AGENT_IDENTITY_HEADER,
|
|
20863
|
+
AIP_COVERED_COMPONENTS: () => AIP_COVERED_COMPONENTS,
|
|
20864
|
+
AIP_SIGNATURE_TAG: () => AIP_SIGNATURE_TAG,
|
|
20861
20865
|
Checkout: () => Checkout,
|
|
20862
20866
|
CheckoutValidationError: () => CheckoutValidationError,
|
|
20863
20867
|
FIXABLE_DENIAL_REASONS: () => FIXABLE_DENIAL_REASONS,
|
|
20868
|
+
HARD_MAX_CACHE_SECONDS: () => HARD_MAX_CACHE_SECONDS,
|
|
20869
|
+
JWKS_WELL_KNOWN_PATH: () => JWKS_WELL_KNOWN_PATH,
|
|
20870
|
+
JwksCache: () => JwksCache,
|
|
20864
20871
|
UCPSigningKey: () => UCPSigningKey,
|
|
20865
20872
|
UCPVerificationError: () => UCPVerificationError,
|
|
20866
20873
|
UCP_A2A_EXTENSION_URI: () => UCP_A2A_EXTENSION_URI,
|
|
20874
|
+
aipErrorCode: () => aipErrorCode,
|
|
20875
|
+
aipErrorStatus: () => aipErrorStatus,
|
|
20867
20876
|
buildA2AAgentCard: () => buildA2AAgentCard,
|
|
20868
20877
|
buildAgentMemoryHint: () => buildAgentMemoryHint,
|
|
20878
|
+
buildAipErrorBody: () => buildAipErrorBody,
|
|
20879
|
+
buildAipTrustedIssuers: () => buildAipTrustedIssuers,
|
|
20869
20880
|
buildContactSupportNextSteps: () => buildContactSupportNextSteps,
|
|
20870
20881
|
buildDefaultCheckoutRails: () => buildDefaultCheckoutRails,
|
|
20871
20882
|
buildGateFromPolicy: () => buildGateFromPolicy,
|
|
@@ -20874,6 +20885,8 @@ __export(index_exports, {
|
|
|
20874
20885
|
buildSignerMismatchBody: () => buildSignerMismatchBody,
|
|
20875
20886
|
buildUCPProfile: () => buildUCPProfile,
|
|
20876
20887
|
buildVerificationRequiredBody: () => buildVerificationRequiredBody,
|
|
20888
|
+
buildVerifyContextFromRequest: () => buildVerifyContextFromRequest,
|
|
20889
|
+
canonicalizeIssuer: () => canonicalizeIssuer,
|
|
20877
20890
|
computeFirstCheckout: () => computeFirstCheckout,
|
|
20878
20891
|
createDefaultOnDenied: () => createDefaultOnDenied,
|
|
20879
20892
|
createQuoteCache: () => createQuoteCache,
|
|
@@ -20887,10 +20900,12 @@ __export(index_exports, {
|
|
|
20887
20900
|
formatUsdCents: () => formatUsdCents,
|
|
20888
20901
|
generateUCPSigningKey: () => generateUCPSigningKey,
|
|
20889
20902
|
getIdentityStatus: () => getIdentityStatus,
|
|
20903
|
+
hasAgentIdentityHeader: () => hasAgentIdentityHeader,
|
|
20890
20904
|
hasMppxHeader: () => hasMppxHeader,
|
|
20891
20905
|
hasPaymentHeader: () => hasPaymentHeader,
|
|
20892
20906
|
hasX402Header: () => hasX402Header,
|
|
20893
20907
|
hashOperatorToken: () => hashOperatorToken,
|
|
20908
|
+
isAitShape: () => isAitShape,
|
|
20894
20909
|
isEvmNetwork: () => isEvmNetwork,
|
|
20895
20910
|
isFixableDenial: () => isFixableDenial,
|
|
20896
20911
|
isSolanaNetwork: () => isSolanaNetwork,
|
|
@@ -20903,9 +20918,11 @@ __export(index_exports, {
|
|
|
20903
20918
|
runGateWithEnforcement: () => runGateWithEnforcement,
|
|
20904
20919
|
shippingCountryAllowed: () => shippingCountryAllowed,
|
|
20905
20920
|
shippingStateAllowed: () => shippingStateAllowed,
|
|
20921
|
+
signMessage: () => signMessage,
|
|
20906
20922
|
signUCPProfile: () => signUCPProfile,
|
|
20907
20923
|
stripeSptPaymentHandler: () => stripeSptPaymentHandler,
|
|
20908
20924
|
ucpA2AExtension: () => ucpA2AExtension,
|
|
20925
|
+
validateAitPayload: () => validateAitPayload,
|
|
20909
20926
|
validateShippingAgainstPolicy: () => validateShippingAgainstPolicy,
|
|
20910
20927
|
validationEnvelope: () => validationEnvelope,
|
|
20911
20928
|
validationResponseExpress: () => validationResponseExpress,
|
|
@@ -20914,12 +20931,16 @@ __export(index_exports, {
|
|
|
20914
20931
|
validationResponseNextjs: () => validationResponseNextjs,
|
|
20915
20932
|
validationResponseWeb: () => validationResponseWeb,
|
|
20916
20933
|
verificationAgentInstructions: () => verificationAgentInstructions,
|
|
20934
|
+
verifyAit: () => verifyAit,
|
|
20935
|
+
verifyAitRequest: () => verifyAitRequest,
|
|
20936
|
+
verifyMessageSignature: () => verifyMessageSignature,
|
|
20917
20937
|
verifyUCPProfile: () => verifyUCPProfile,
|
|
20918
20938
|
x402PaymentHandler: () => x402PaymentHandler
|
|
20919
20939
|
});
|
|
20920
20940
|
module.exports = __toCommonJS(index_exports);
|
|
20921
20941
|
|
|
20922
20942
|
// src/core.ts
|
|
20943
|
+
var import_node_crypto = require("crypto");
|
|
20923
20944
|
var import_sdk = require("@agent-score/sdk");
|
|
20924
20945
|
|
|
20925
20946
|
// src/_denial.ts
|
|
@@ -21235,8 +21256,9 @@ var INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({
|
|
|
21235
21256
|
],
|
|
21236
21257
|
user_message: "The operator_token is not recognized. Use a different stored token, or restart the verification session flow to mint a new one."
|
|
21237
21258
|
});
|
|
21238
|
-
function buildAgentMemoryHint() {
|
|
21259
|
+
function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
21239
21260
|
const api = CANONICAL_AGENTSCORE_API;
|
|
21261
|
+
const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
|
|
21240
21262
|
return {
|
|
21241
21263
|
save_for_future_agentscore_gates: true,
|
|
21242
21264
|
pattern_summary: "AgentScore is a cross-merchant identity substrate for agent commerce. Any endpoint that returns 403 missing_identity / identity_verification_required or 402 challenges referencing AgentScore uses the same identity system. One KYC works across all AgentScore merchants \u2014 no re-verification per site. Save this pattern (and the endpoints below) to persistent memory so future AgentScore encounters skip the cold-start session flow.",
|
|
@@ -21244,8 +21266,12 @@ function buildAgentMemoryHint() {
|
|
|
21244
21266
|
identity_check_endpoint: `${api}/v1/credentials`,
|
|
21245
21267
|
identity_paths: {
|
|
21246
21268
|
wallet: "If paying from a crypto wallet you have used before on any AgentScore merchant, send `X-Wallet-Address: 0x...`. Shortest path; no token lifecycle to manage.",
|
|
21247
|
-
operator_token: "For any rail (Stripe SPT, card, or a wallet you have not linked yet), send `X-Operator-Token: opc_...`. Reusable across merchants until the token expires."
|
|
21269
|
+
operator_token: "For any rail (Stripe SPT, card, or a wallet you have not linked yet), send `X-Operator-Token: opc_...`. Reusable across merchants until the token expires.",
|
|
21270
|
+
...acceptsAip && {
|
|
21271
|
+
agent_identity: 'If you hold an AIP Agent Identity Token from a trusted issuer (see aip_trusted_issuers), present it: send the JWT in an `Agent-Identity` header plus an RFC 9421 HTTP Message Signature (Signature-Input + Signature over @method @authority @path agent-identity, tag="agent-identity") signed with the token-bound cnf key. The merchant verifies it and applies its policy \u2014 no separate AgentScore credential needed.'
|
|
21272
|
+
}
|
|
21248
21273
|
},
|
|
21274
|
+
...acceptsAip && { aip_trusted_issuers: aipTrustedIssuers },
|
|
21249
21275
|
bootstrap: "If you have neither a linked wallet nor a valid operator_token, follow the session/verify flow in the per-request `agent_instructions` block. This happens at most once per agent identity \u2014 after first verification, the operator_token and any subsequently used wallet are reusable everywhere.",
|
|
21250
21276
|
do_not_persist_in_memory: ["operator_token", "poll_secret"],
|
|
21251
21277
|
persist_in_credential_store: ["operator_token"]
|
|
@@ -21267,11 +21293,12 @@ function createAgentScoreCore(options) {
|
|
|
21267
21293
|
baseUrl: rawBaseUrl = "https://api.agentscore.sh",
|
|
21268
21294
|
chain: gateChain,
|
|
21269
21295
|
userAgent,
|
|
21270
|
-
createSessionOnMissing
|
|
21296
|
+
createSessionOnMissing,
|
|
21297
|
+
aipTrustedIssuers
|
|
21271
21298
|
} = options;
|
|
21272
21299
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
21273
|
-
const agentMemoryHint = buildAgentMemoryHint();
|
|
21274
|
-
const defaultUa = `@agent-score/commerce@${"2.
|
|
21300
|
+
const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
|
|
21301
|
+
const defaultUa = `@agent-score/commerce@${"2.5.0"}`;
|
|
21275
21302
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
21276
21303
|
const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
21277
21304
|
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
@@ -21289,6 +21316,7 @@ function createAgentScoreCore(options) {
|
|
|
21289
21316
|
return s;
|
|
21290
21317
|
}
|
|
21291
21318
|
const cache = new TTLCache(cacheSeconds * 1e3);
|
|
21319
|
+
const lastSignerRaw = /* @__PURE__ */ new Map();
|
|
21292
21320
|
async function tryMintSessionDenial(ctx) {
|
|
21293
21321
|
if (!createSessionOnMissing) return void 0;
|
|
21294
21322
|
try {
|
|
@@ -21346,13 +21374,18 @@ function createAgentScoreCore(options) {
|
|
|
21346
21374
|
}
|
|
21347
21375
|
}
|
|
21348
21376
|
async function evaluate(identity, ctx, signer) {
|
|
21349
|
-
if (!identity || !identity.address && !identity.operatorToken) {
|
|
21377
|
+
if (!identity || !identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim()) {
|
|
21350
21378
|
if (failOpen) return { kind: "allow" };
|
|
21351
21379
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
21352
21380
|
if (sessionReason) return { kind: "deny", reason: sessionReason };
|
|
21381
|
+
const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
|
|
21382
|
+
const aipStep = acceptsAip ? [
|
|
21383
|
+
`If you hold an AIP Agent Identity Token from a trusted issuer (${aipTrustedIssuers.join(", ")}): present it \u2014 send the JWT in an Agent-Identity header plus an RFC 9421 HTTP Message Signature (Signature-Input + Signature over @method @authority @path agent-identity, tag="agent-identity") signed with the token-bound cnf key. This satisfies identity in one round trip without an AgentScore credential.`
|
|
21384
|
+
] : [];
|
|
21353
21385
|
const missingIdentityInstructions = JSON.stringify({
|
|
21354
21386
|
action: "probe_identity_then_session",
|
|
21355
21387
|
steps: [
|
|
21388
|
+
...aipStep,
|
|
21356
21389
|
"If you have a wallet AND this merchant accepts a wallet-signing rail (Tempo MPP or x402 \u2014 see openapi.json x-payment-info): send X-Wallet-Address and retry. If the wallet is already linked to an AgentScore operator (via prior SIWE claim or prior captureWallet), this passes in one round trip. If the wallet is unlinked or the account has no KYC, the 403 will include a verify_url \u2014 share it with the user to claim the wallet + complete KYC, then retry.",
|
|
21357
21390
|
"If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
|
|
21358
21391
|
"If neither applies: retry with NO identity header. Merchants that auto-create verification sessions (most AgentScore merchants do) return verify_url + session_id + poll_secret in the 403 body \u2014 share verify_url with the user, then poll poll_url every 5s with the X-Poll-Secret header until status=verified (the poll returns a one-time operator_token). If the retry returns the same bare 403, this merchant does not support self-service session bootstrapping \u2014 direct the user to https://agentscore.sh/sign-up to create an AgentScore identity and mint an operator_token from their dashboard (https://agentscore.sh/dashboard/verify). The user hands the opc_... to you, and you retry with X-Operator-Token."
|
|
@@ -21368,7 +21401,7 @@ function createAgentScoreCore(options) {
|
|
|
21368
21401
|
}
|
|
21369
21402
|
};
|
|
21370
21403
|
}
|
|
21371
|
-
const cacheKey2 = identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
|
|
21404
|
+
const cacheKey2 = identity.aipToken ? `aip:${(0, import_node_crypto.createHash)("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
|
|
21372
21405
|
const cached2 = cache.get(cacheKey2);
|
|
21373
21406
|
if (cached2) {
|
|
21374
21407
|
if (cached2.allow) {
|
|
@@ -21413,7 +21446,7 @@ function createAgentScoreCore(options) {
|
|
|
21413
21446
|
// regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
|
|
21414
21447
|
...signer && { signer: { address: signer.address, network: signer.network } }
|
|
21415
21448
|
};
|
|
21416
|
-
const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
|
|
21449
|
+
const result = identity.aipToken ? await sdk.assess(null, { ...opts, aipToken: identity.aipToken }) : identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
|
|
21417
21450
|
data = result;
|
|
21418
21451
|
} catch (err) {
|
|
21419
21452
|
if (err instanceof import_sdk.PaymentRequiredError) {
|
|
@@ -21484,6 +21517,9 @@ function createAgentScoreCore(options) {
|
|
|
21484
21517
|
const decisionReasons = data.decision_reasons ?? [];
|
|
21485
21518
|
const allow = decision === "allow" || decision == null;
|
|
21486
21519
|
cache.set(cacheKey2, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
|
|
21520
|
+
if (identity.address !== void 0 && identity.operatorToken === void 0 && identity.aipToken === void 0 && (data.signer_match !== void 0 || data.signer_sanctions !== void 0)) {
|
|
21521
|
+
lastSignerRaw.set(normalizeAddress(identity.address), data);
|
|
21522
|
+
}
|
|
21487
21523
|
if (allow) {
|
|
21488
21524
|
const quota = data.quota;
|
|
21489
21525
|
return {
|
|
@@ -21548,9 +21584,7 @@ function createAgentScoreCore(options) {
|
|
|
21548
21584
|
}
|
|
21549
21585
|
function getSignerVerdict(claimedAddress) {
|
|
21550
21586
|
const claimedNorm = normalizeAddress(claimedAddress);
|
|
21551
|
-
const
|
|
21552
|
-
if (!cached2) return void 0;
|
|
21553
|
-
const raw = cached2.raw;
|
|
21587
|
+
const raw = lastSignerRaw.get(claimedNorm) ?? cache.get(claimedNorm)?.raw;
|
|
21554
21588
|
if (!raw) return void 0;
|
|
21555
21589
|
const rawMatch = raw.signer_match;
|
|
21556
21590
|
const rawSanctions = raw.signer_sanctions;
|
|
@@ -21813,7 +21847,7 @@ function validateShippingAgainstPolicy(opts) {
|
|
|
21813
21847
|
}
|
|
21814
21848
|
|
|
21815
21849
|
// src/identity/tokens.ts
|
|
21816
|
-
var
|
|
21850
|
+
var import_node_crypto2 = require("crypto");
|
|
21817
21851
|
|
|
21818
21852
|
// src/payment/payment_header.ts
|
|
21819
21853
|
function toTitleCase(name) {
|
|
@@ -21849,7 +21883,7 @@ function hasMppxHeader(input) {
|
|
|
21849
21883
|
|
|
21850
21884
|
// src/identity/tokens.ts
|
|
21851
21885
|
function hashOperatorToken(plaintext) {
|
|
21852
|
-
return (0,
|
|
21886
|
+
return (0, import_node_crypto2.createHash)("sha256").update(plaintext, "utf8").digest("hex");
|
|
21853
21887
|
}
|
|
21854
21888
|
function extractOwnerScope(input) {
|
|
21855
21889
|
const headers = asHeaders(input);
|
|
@@ -21862,7 +21896,7 @@ function extractOwnerScope(input) {
|
|
|
21862
21896
|
}
|
|
21863
21897
|
|
|
21864
21898
|
// src/checkout.ts
|
|
21865
|
-
var
|
|
21899
|
+
var import_node_crypto3 = require("crypto");
|
|
21866
21900
|
|
|
21867
21901
|
// src/_mppx_receipt.ts
|
|
21868
21902
|
function extractMppxReceiptHeaderFromRaw(raw) {
|
|
@@ -21902,6 +21936,710 @@ function warnMissingApiKeyOnce(label) {
|
|
|
21902
21936
|
);
|
|
21903
21937
|
}
|
|
21904
21938
|
|
|
21939
|
+
// src/aip/verify.ts
|
|
21940
|
+
var import_jose2 = require("jose");
|
|
21941
|
+
|
|
21942
|
+
// src/aip/http-signature.ts
|
|
21943
|
+
var import_jose = require("jose");
|
|
21944
|
+
var { subtle } = globalThis.crypto;
|
|
21945
|
+
var b64ToBytes = (b64) => {
|
|
21946
|
+
const bin = atob(b64);
|
|
21947
|
+
const out = new Uint8Array(bin.length);
|
|
21948
|
+
for (let i = 0; i < bin.length; i++) {
|
|
21949
|
+
out[i] = bin.charCodeAt(i);
|
|
21950
|
+
}
|
|
21951
|
+
return out;
|
|
21952
|
+
};
|
|
21953
|
+
var bytesToB64 = (bytes) => {
|
|
21954
|
+
let bin = "";
|
|
21955
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
21956
|
+
bin += String.fromCharCode(bytes[i]);
|
|
21957
|
+
}
|
|
21958
|
+
return btoa(bin);
|
|
21959
|
+
};
|
|
21960
|
+
var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
|
|
21961
|
+
var AIP_SIGNATURE_TAG = "agent-identity";
|
|
21962
|
+
var DEFAULT_MAX_SKEW_SECONDS = 60;
|
|
21963
|
+
var normalizeAuthority = (authority) => {
|
|
21964
|
+
const lower = authority.trim().toLowerCase();
|
|
21965
|
+
const colon = lower.lastIndexOf(":");
|
|
21966
|
+
if (colon === -1) {
|
|
21967
|
+
return lower;
|
|
21968
|
+
}
|
|
21969
|
+
if (lower.includes("]") && colon < lower.indexOf("]")) {
|
|
21970
|
+
return lower;
|
|
21971
|
+
}
|
|
21972
|
+
const host = lower.slice(0, colon);
|
|
21973
|
+
const port = lower.slice(colon + 1);
|
|
21974
|
+
if (port === "80" || port === "443") {
|
|
21975
|
+
return host;
|
|
21976
|
+
}
|
|
21977
|
+
return lower;
|
|
21978
|
+
};
|
|
21979
|
+
var componentValue = (name, input) => {
|
|
21980
|
+
switch (name) {
|
|
21981
|
+
case "@method":
|
|
21982
|
+
return input.method.toUpperCase();
|
|
21983
|
+
case "@authority":
|
|
21984
|
+
return normalizeAuthority(input.authority);
|
|
21985
|
+
case "@path":
|
|
21986
|
+
return input.path;
|
|
21987
|
+
case "agent-identity":
|
|
21988
|
+
return input.agentIdentity.trim();
|
|
21989
|
+
default:
|
|
21990
|
+
return input.extra?.[name] ?? null;
|
|
21991
|
+
}
|
|
21992
|
+
};
|
|
21993
|
+
var serializeComponentList = (components) => `(${components.map((c) => `"${c}"`).join(" ")})`;
|
|
21994
|
+
var serializeParams = (p) => {
|
|
21995
|
+
const parts = [];
|
|
21996
|
+
if (p.created !== void 0) {
|
|
21997
|
+
parts.push(`created=${p.created}`);
|
|
21998
|
+
}
|
|
21999
|
+
if (p.expires !== void 0) {
|
|
22000
|
+
parts.push(`expires=${p.expires}`);
|
|
22001
|
+
}
|
|
22002
|
+
if (p.keyid !== void 0) {
|
|
22003
|
+
parts.push(`keyid="${p.keyid}"`);
|
|
22004
|
+
}
|
|
22005
|
+
if (p.alg !== void 0) {
|
|
22006
|
+
parts.push(`alg="${p.alg}"`);
|
|
22007
|
+
}
|
|
22008
|
+
if (p.tag !== void 0) {
|
|
22009
|
+
parts.push(`tag="${p.tag}"`);
|
|
22010
|
+
}
|
|
22011
|
+
return parts.map((s) => `;${s}`).join("");
|
|
22012
|
+
};
|
|
22013
|
+
var buildSignatureBase = (params, input) => {
|
|
22014
|
+
const lines = [];
|
|
22015
|
+
for (const name of params.components) {
|
|
22016
|
+
const value = componentValue(name, input);
|
|
22017
|
+
if (value === null) {
|
|
22018
|
+
throw new MissingComponentError(name);
|
|
22019
|
+
}
|
|
22020
|
+
lines.push(`"${name}": ${value}`);
|
|
22021
|
+
}
|
|
22022
|
+
const paramsValue = serializeComponentList(params.components) + serializeParams(params);
|
|
22023
|
+
lines.push(`"@signature-params": ${paramsValue}`);
|
|
22024
|
+
return lines.join("\n");
|
|
22025
|
+
};
|
|
22026
|
+
var MissingComponentError = class extends Error {
|
|
22027
|
+
constructor(component) {
|
|
22028
|
+
super(`signature base missing covered component: ${component}`);
|
|
22029
|
+
this.component = component;
|
|
22030
|
+
this.name = "MissingComponentError";
|
|
22031
|
+
}
|
|
22032
|
+
component;
|
|
22033
|
+
};
|
|
22034
|
+
var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
|
|
22035
|
+
const members = splitDictionary(header);
|
|
22036
|
+
if (members.length === 0) {
|
|
22037
|
+
return null;
|
|
22038
|
+
}
|
|
22039
|
+
const parsed = members.map((m) => {
|
|
22040
|
+
const params = parseInnerListMember(m.value);
|
|
22041
|
+
return params ? { label: m.label, params } : null;
|
|
22042
|
+
}).filter((x) => x !== null);
|
|
22043
|
+
if (parsed.length === 0) {
|
|
22044
|
+
return null;
|
|
22045
|
+
}
|
|
22046
|
+
const tagged = parsed.find((p) => p.params.tag === tag);
|
|
22047
|
+
if (tagged) {
|
|
22048
|
+
return tagged;
|
|
22049
|
+
}
|
|
22050
|
+
if (parsed.length === 1 && parsed[0].params.tag === void 0) {
|
|
22051
|
+
return parsed[0];
|
|
22052
|
+
}
|
|
22053
|
+
return null;
|
|
22054
|
+
};
|
|
22055
|
+
var parseSignatureValue = (header, label) => {
|
|
22056
|
+
const members = splitDictionary(header);
|
|
22057
|
+
const member = members.find((m) => m.label === label);
|
|
22058
|
+
if (!member) {
|
|
22059
|
+
return null;
|
|
22060
|
+
}
|
|
22061
|
+
const v = member.value.trim();
|
|
22062
|
+
if (!v.startsWith(":") || !v.endsWith(":") || v.length < 2) {
|
|
22063
|
+
return null;
|
|
22064
|
+
}
|
|
22065
|
+
const b64 = v.slice(1, -1);
|
|
22066
|
+
try {
|
|
22067
|
+
return b64ToBytes(b64);
|
|
22068
|
+
} catch {
|
|
22069
|
+
return null;
|
|
22070
|
+
}
|
|
22071
|
+
};
|
|
22072
|
+
var splitDictionary = (header) => {
|
|
22073
|
+
const out = [];
|
|
22074
|
+
let depth = 0;
|
|
22075
|
+
let inBytes = false;
|
|
22076
|
+
let inString = false;
|
|
22077
|
+
let current = "";
|
|
22078
|
+
for (let i = 0; i < header.length; i++) {
|
|
22079
|
+
const ch = header[i];
|
|
22080
|
+
if (inString) {
|
|
22081
|
+
current += ch;
|
|
22082
|
+
if (ch === '"' && header[i - 1] !== "\\") {
|
|
22083
|
+
inString = false;
|
|
22084
|
+
}
|
|
22085
|
+
continue;
|
|
22086
|
+
}
|
|
22087
|
+
if (ch === '"') {
|
|
22088
|
+
inString = true;
|
|
22089
|
+
current += ch;
|
|
22090
|
+
continue;
|
|
22091
|
+
}
|
|
22092
|
+
if (ch === ":") {
|
|
22093
|
+
inBytes = !inBytes;
|
|
22094
|
+
current += ch;
|
|
22095
|
+
continue;
|
|
22096
|
+
}
|
|
22097
|
+
if (!inBytes && ch === "(") {
|
|
22098
|
+
depth++;
|
|
22099
|
+
current += ch;
|
|
22100
|
+
continue;
|
|
22101
|
+
}
|
|
22102
|
+
if (!inBytes && ch === ")") {
|
|
22103
|
+
depth = Math.max(0, depth - 1);
|
|
22104
|
+
current += ch;
|
|
22105
|
+
continue;
|
|
22106
|
+
}
|
|
22107
|
+
if (!inBytes && depth === 0 && ch === ",") {
|
|
22108
|
+
pushMember(out, current);
|
|
22109
|
+
current = "";
|
|
22110
|
+
continue;
|
|
22111
|
+
}
|
|
22112
|
+
current += ch;
|
|
22113
|
+
}
|
|
22114
|
+
pushMember(out, current);
|
|
22115
|
+
return out;
|
|
22116
|
+
};
|
|
22117
|
+
var pushMember = (out, raw) => {
|
|
22118
|
+
const trimmed = raw.trim();
|
|
22119
|
+
if (!trimmed) {
|
|
22120
|
+
return;
|
|
22121
|
+
}
|
|
22122
|
+
const eq = trimmed.indexOf("=");
|
|
22123
|
+
if (eq === -1) {
|
|
22124
|
+
return;
|
|
22125
|
+
}
|
|
22126
|
+
const label = trimmed.slice(0, eq).trim();
|
|
22127
|
+
const value = trimmed.slice(eq + 1).trim();
|
|
22128
|
+
if (label) {
|
|
22129
|
+
out.push({ label, value });
|
|
22130
|
+
}
|
|
22131
|
+
};
|
|
22132
|
+
var parseInnerListMember = (value) => {
|
|
22133
|
+
const open = value.indexOf("(");
|
|
22134
|
+
const close = value.indexOf(")", open + 1);
|
|
22135
|
+
if (open === -1 || close === -1) {
|
|
22136
|
+
return null;
|
|
22137
|
+
}
|
|
22138
|
+
const listBody = value.slice(open + 1, close).trim();
|
|
22139
|
+
const components = listBody.length === 0 ? [] : (listBody.match(/"[^"]*"/g) ?? []).map((s) => s.slice(1, -1));
|
|
22140
|
+
const params = { components };
|
|
22141
|
+
const paramStr = value.slice(close + 1);
|
|
22142
|
+
const re = /;\s*([a-zA-Z][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|-?\d+)/g;
|
|
22143
|
+
let match;
|
|
22144
|
+
while ((match = re.exec(paramStr)) !== null) {
|
|
22145
|
+
const key = match[1];
|
|
22146
|
+
const raw = match[2];
|
|
22147
|
+
const val = raw.startsWith('"') ? raw.slice(1, -1) : Number(raw);
|
|
22148
|
+
if (key === "created") {
|
|
22149
|
+
params.created = val;
|
|
22150
|
+
} else if (key === "expires") {
|
|
22151
|
+
params.expires = val;
|
|
22152
|
+
} else if (key === "keyid") {
|
|
22153
|
+
params.keyid = val;
|
|
22154
|
+
} else if (key === "tag") {
|
|
22155
|
+
params.tag = val;
|
|
22156
|
+
} else if (key === "alg") {
|
|
22157
|
+
params.alg = val;
|
|
22158
|
+
}
|
|
22159
|
+
}
|
|
22160
|
+
return params;
|
|
22161
|
+
};
|
|
22162
|
+
var verifyMessageSignature = async (input) => {
|
|
22163
|
+
const selected = parseSignatureInput(input.signatureInput);
|
|
22164
|
+
if (!selected) {
|
|
22165
|
+
return { ok: false, reason: "no_aip_signature" };
|
|
22166
|
+
}
|
|
22167
|
+
const { label, params } = selected;
|
|
22168
|
+
if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
|
|
22169
|
+
return { ok: false, reason: "unsupported_alg" };
|
|
22170
|
+
}
|
|
22171
|
+
for (const required3 of AIP_COVERED_COMPONENTS) {
|
|
22172
|
+
if (!params.components.includes(required3)) {
|
|
22173
|
+
return { ok: false, reason: "missing_covered_component" };
|
|
22174
|
+
}
|
|
22175
|
+
}
|
|
22176
|
+
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
22177
|
+
const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
|
|
22178
|
+
if (params.created !== void 0 && params.created > now + skew) {
|
|
22179
|
+
return { ok: false, reason: "created_in_future" };
|
|
22180
|
+
}
|
|
22181
|
+
if (params.expires !== void 0 && params.expires < now - skew) {
|
|
22182
|
+
return { ok: false, reason: "expired" };
|
|
22183
|
+
}
|
|
22184
|
+
if (!params.keyid) {
|
|
22185
|
+
return { ok: false, reason: "missing_keyid" };
|
|
22186
|
+
}
|
|
22187
|
+
const cnf = input.cnfJwk;
|
|
22188
|
+
if (cnf.kty !== "OKP" || cnf.crv !== "Ed25519" || typeof cnf.x !== "string" || cnf.x.length === 0) {
|
|
22189
|
+
return { ok: false, reason: "unsupported_cnf_key" };
|
|
22190
|
+
}
|
|
22191
|
+
let thumbprint;
|
|
22192
|
+
try {
|
|
22193
|
+
thumbprint = await (0, import_jose.calculateJwkThumbprint)(input.cnfJwk, "sha256");
|
|
22194
|
+
} catch {
|
|
22195
|
+
return { ok: false, reason: "unsupported_cnf_key" };
|
|
22196
|
+
}
|
|
22197
|
+
if (params.keyid !== thumbprint) {
|
|
22198
|
+
return { ok: false, reason: "keyid_mismatch" };
|
|
22199
|
+
}
|
|
22200
|
+
const sig = parseSignatureValue(input.signature, label);
|
|
22201
|
+
if (!sig) {
|
|
22202
|
+
return { ok: false, reason: "malformed_signature" };
|
|
22203
|
+
}
|
|
22204
|
+
let base;
|
|
22205
|
+
try {
|
|
22206
|
+
base = buildSignatureBase(params, {
|
|
22207
|
+
method: input.method,
|
|
22208
|
+
authority: input.authority,
|
|
22209
|
+
path: input.path,
|
|
22210
|
+
agentIdentity: input.agentIdentity,
|
|
22211
|
+
extra: input.extraComponents
|
|
22212
|
+
});
|
|
22213
|
+
} catch (err) {
|
|
22214
|
+
if (err instanceof MissingComponentError) {
|
|
22215
|
+
return { ok: false, reason: "missing_covered_component" };
|
|
22216
|
+
}
|
|
22217
|
+
throw err;
|
|
22218
|
+
}
|
|
22219
|
+
let valid;
|
|
22220
|
+
try {
|
|
22221
|
+
const key = await (0, import_jose.importJWK)(input.cnfJwk, "EdDSA");
|
|
22222
|
+
if (!(key instanceof CryptoKey)) {
|
|
22223
|
+
return { ok: false, reason: "signature_invalid" };
|
|
22224
|
+
}
|
|
22225
|
+
valid = await subtle.verify(
|
|
22226
|
+
{ name: "Ed25519" },
|
|
22227
|
+
key,
|
|
22228
|
+
sig,
|
|
22229
|
+
new TextEncoder().encode(base)
|
|
22230
|
+
);
|
|
22231
|
+
} catch {
|
|
22232
|
+
return { ok: false, reason: "signature_invalid" };
|
|
22233
|
+
}
|
|
22234
|
+
return valid ? { ok: true, params } : { ok: false, reason: "signature_invalid" };
|
|
22235
|
+
};
|
|
22236
|
+
var signMessage = async (input) => {
|
|
22237
|
+
const label = input.label ?? "ait";
|
|
22238
|
+
const components = input.components ?? [...AIP_COVERED_COMPONENTS];
|
|
22239
|
+
const created = input.created ?? Math.floor(Date.now() / 1e3);
|
|
22240
|
+
const keyid = await (0, import_jose.calculateJwkThumbprint)(input.publicJwk, "sha256");
|
|
22241
|
+
const params = {
|
|
22242
|
+
components,
|
|
22243
|
+
created,
|
|
22244
|
+
expires: input.expires,
|
|
22245
|
+
keyid,
|
|
22246
|
+
tag: AIP_SIGNATURE_TAG
|
|
22247
|
+
};
|
|
22248
|
+
const base = buildSignatureBase(params, {
|
|
22249
|
+
method: input.method,
|
|
22250
|
+
authority: input.authority,
|
|
22251
|
+
path: input.path,
|
|
22252
|
+
agentIdentity: input.agentIdentity,
|
|
22253
|
+
extra: input.extraComponents
|
|
22254
|
+
});
|
|
22255
|
+
const key = await (0, import_jose.importJWK)(input.privateJwk, "EdDSA");
|
|
22256
|
+
if (!(key instanceof CryptoKey)) {
|
|
22257
|
+
throw new Error("signMessage: expected an Ed25519 private CryptoKey");
|
|
22258
|
+
}
|
|
22259
|
+
const sigBytes = await subtle.sign(
|
|
22260
|
+
"Ed25519",
|
|
22261
|
+
key,
|
|
22262
|
+
new TextEncoder().encode(base)
|
|
22263
|
+
);
|
|
22264
|
+
const b64 = bytesToB64(new Uint8Array(sigBytes));
|
|
22265
|
+
const signatureInput = `${label}=${serializeComponentList(components)}${serializeParams(params)}`;
|
|
22266
|
+
const signature2 = `${label}=:${b64}:`;
|
|
22267
|
+
return { signatureInput, signature: signature2 };
|
|
22268
|
+
};
|
|
22269
|
+
|
|
22270
|
+
// src/aip/types.ts
|
|
22271
|
+
var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
22272
|
+
var isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
|
|
22273
|
+
var isAitShape = (payload) => isObject2(payload) && isObject2(payload.cnf) && isObject2(payload.agent);
|
|
22274
|
+
var validateAitPayload = (payload) => {
|
|
22275
|
+
if (!isObject2(payload)) {
|
|
22276
|
+
return { ok: false, reason: "not_an_object" };
|
|
22277
|
+
}
|
|
22278
|
+
if (!isNonEmptyString(payload.aip_version)) {
|
|
22279
|
+
return { ok: false, reason: "missing_aip_version" };
|
|
22280
|
+
}
|
|
22281
|
+
if (!isNonEmptyString(payload.iss)) {
|
|
22282
|
+
return { ok: false, reason: "missing_iss" };
|
|
22283
|
+
}
|
|
22284
|
+
if (!isNonEmptyString(payload.sub)) {
|
|
22285
|
+
return { ok: false, reason: "missing_sub" };
|
|
22286
|
+
}
|
|
22287
|
+
if (typeof payload.iat !== "number") {
|
|
22288
|
+
return { ok: false, reason: "missing_iat" };
|
|
22289
|
+
}
|
|
22290
|
+
if (typeof payload.exp !== "number") {
|
|
22291
|
+
return { ok: false, reason: "missing_exp" };
|
|
22292
|
+
}
|
|
22293
|
+
if (!isObject2(payload.cnf) || !isObject2(payload.cnf.jwk)) {
|
|
22294
|
+
return { ok: false, reason: "missing_cnf" };
|
|
22295
|
+
}
|
|
22296
|
+
if (!isObject2(payload.agent) || !isNonEmptyString(payload.agent.provider)) {
|
|
22297
|
+
return { ok: false, reason: "missing_agent_provider" };
|
|
22298
|
+
}
|
|
22299
|
+
if (payload.trust_level === "human_confirmed") {
|
|
22300
|
+
const auth = payload.auth;
|
|
22301
|
+
const amr = isObject2(auth) ? auth.amr : void 0;
|
|
22302
|
+
if (!Array.isArray(amr) || amr.length === 0) {
|
|
22303
|
+
return { ok: false, reason: "human_confirmed_without_amr" };
|
|
22304
|
+
}
|
|
22305
|
+
}
|
|
22306
|
+
return { ok: true, payload };
|
|
22307
|
+
};
|
|
22308
|
+
|
|
22309
|
+
// src/aip/verify.ts
|
|
22310
|
+
var AGENT_IDENTITY_HEADER = "agent-identity";
|
|
22311
|
+
var verifyAit = async (ctx, opts) => {
|
|
22312
|
+
if (ctx.agentIdentityHeaders.length === 0) {
|
|
22313
|
+
return { ok: false, reason: "no_token" };
|
|
22314
|
+
}
|
|
22315
|
+
if (!ctx.signatureInput || !ctx.signature) {
|
|
22316
|
+
return { ok: false, reason: "pop_signature_missing" };
|
|
22317
|
+
}
|
|
22318
|
+
let lastFailure = "malformed_token";
|
|
22319
|
+
for (const raw of ctx.agentIdentityHeaders) {
|
|
22320
|
+
const token = stripBearer(raw);
|
|
22321
|
+
let header;
|
|
22322
|
+
let payload;
|
|
22323
|
+
try {
|
|
22324
|
+
header = (0, import_jose2.decodeProtectedHeader)(token);
|
|
22325
|
+
payload = (0, import_jose2.decodeJwt)(token);
|
|
22326
|
+
} catch {
|
|
22327
|
+
lastFailure = "malformed_token";
|
|
22328
|
+
continue;
|
|
22329
|
+
}
|
|
22330
|
+
if (header.alg === void 0 || header.alg.toLowerCase() === "none") {
|
|
22331
|
+
lastFailure = "malformed_token";
|
|
22332
|
+
continue;
|
|
22333
|
+
}
|
|
22334
|
+
if (!isAitShape(payload)) {
|
|
22335
|
+
lastFailure = "malformed_token";
|
|
22336
|
+
continue;
|
|
22337
|
+
}
|
|
22338
|
+
const validated = validateAitPayload(payload);
|
|
22339
|
+
if (!validated.ok) {
|
|
22340
|
+
lastFailure = "invalid_claims";
|
|
22341
|
+
continue;
|
|
22342
|
+
}
|
|
22343
|
+
const claims = validated.payload;
|
|
22344
|
+
const keyLookup = await opts.jwks.getKey(claims.iss, header.kid);
|
|
22345
|
+
if (!keyLookup.ok) {
|
|
22346
|
+
lastFailure = keyLookup.reason === "untrusted_issuer" || keyLookup.reason === "insecure_issuer" ? "untrusted_issuer" : "key_unavailable";
|
|
22347
|
+
continue;
|
|
22348
|
+
}
|
|
22349
|
+
const jwtClockTolerance = opts.maxSkewSeconds ?? 60;
|
|
22350
|
+
try {
|
|
22351
|
+
const idpKey = await (0, import_jose2.importJWK)(keyLookup.key, normalizeAlg(header.alg));
|
|
22352
|
+
await (0, import_jose2.jwtVerify)(token, idpKey, {
|
|
22353
|
+
// Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
|
|
22354
|
+
// this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
|
|
22355
|
+
// non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
|
|
22356
|
+
// token that verifies. Matches the server-side allowlist in core/api aip-verify.
|
|
22357
|
+
algorithms: AIT_SIGNING_ALGS,
|
|
22358
|
+
clockTolerance: jwtClockTolerance,
|
|
22359
|
+
currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
|
|
22360
|
+
});
|
|
22361
|
+
} catch (err) {
|
|
22362
|
+
lastFailure = isExpiry(err) ? "expired_token" : "idp_signature_invalid";
|
|
22363
|
+
continue;
|
|
22364
|
+
}
|
|
22365
|
+
const nowSec = opts.now ?? Math.floor(Date.now() / 1e3);
|
|
22366
|
+
if (claims.iat > nowSec + jwtClockTolerance) {
|
|
22367
|
+
lastFailure = "expired_token";
|
|
22368
|
+
continue;
|
|
22369
|
+
}
|
|
22370
|
+
const popResult = await verifyMessageSignature({
|
|
22371
|
+
method: ctx.method,
|
|
22372
|
+
authority: ctx.authority,
|
|
22373
|
+
path: ctx.path,
|
|
22374
|
+
agentIdentity: raw,
|
|
22375
|
+
signatureInput: ctx.signatureInput,
|
|
22376
|
+
signature: ctx.signature,
|
|
22377
|
+
cnfJwk: claims.cnf.jwk,
|
|
22378
|
+
now: opts.now,
|
|
22379
|
+
maxSkewSeconds: opts.maxSkewSeconds
|
|
22380
|
+
});
|
|
22381
|
+
if (!popResult.ok) {
|
|
22382
|
+
lastFailure = "pop_signature_invalid";
|
|
22383
|
+
continue;
|
|
22384
|
+
}
|
|
22385
|
+
return { ok: true, ait: { payload: claims, iss: claims.iss, cnfJwk: claims.cnf.jwk, token } };
|
|
22386
|
+
}
|
|
22387
|
+
return { ok: false, reason: lastFailure };
|
|
22388
|
+
};
|
|
22389
|
+
var stripBearer = (value) => {
|
|
22390
|
+
const trimmed = value.trim();
|
|
22391
|
+
return /^bearer\s+/i.test(trimmed) ? trimmed.replace(/^bearer\s+/i, "") : trimmed;
|
|
22392
|
+
};
|
|
22393
|
+
var AIT_SIGNING_ALGS = ["EdDSA", "ES256"];
|
|
22394
|
+
var normalizeAlg = (alg) => alg.toLowerCase() === "eddsa" ? "EdDSA" : alg;
|
|
22395
|
+
var isExpiry = (err) => typeof err === "object" && err !== null && err.code === "ERR_JWT_EXPIRED";
|
|
22396
|
+
|
|
22397
|
+
// src/aip/request.ts
|
|
22398
|
+
var readAgentIdentityHeaders = (headers) => {
|
|
22399
|
+
const raw = headers.get(AGENT_IDENTITY_HEADER);
|
|
22400
|
+
if (!raw) {
|
|
22401
|
+
return [];
|
|
22402
|
+
}
|
|
22403
|
+
return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
22404
|
+
};
|
|
22405
|
+
var deriveAuthority = (req, url2) => req.headers.get("host") ?? url2.host;
|
|
22406
|
+
var buildVerifyContextFromRequest = (req) => {
|
|
22407
|
+
const url2 = new URL(req.url);
|
|
22408
|
+
return {
|
|
22409
|
+
method: req.method,
|
|
22410
|
+
authority: deriveAuthority(req, url2),
|
|
22411
|
+
path: url2.pathname,
|
|
22412
|
+
agentIdentityHeaders: readAgentIdentityHeaders(req.headers),
|
|
22413
|
+
signatureInput: req.headers.get("signature-input"),
|
|
22414
|
+
signature: req.headers.get("signature")
|
|
22415
|
+
};
|
|
22416
|
+
};
|
|
22417
|
+
var hasAgentIdentityHeader = (req) => readAgentIdentityHeaders(req.headers).length > 0;
|
|
22418
|
+
var readNodeHeader = (headers, name) => {
|
|
22419
|
+
const v = headers[name] ?? headers[name.toLowerCase()];
|
|
22420
|
+
if (v === void 0) {
|
|
22421
|
+
return void 0;
|
|
22422
|
+
}
|
|
22423
|
+
return Array.isArray(v) ? v.join(", ") : v;
|
|
22424
|
+
};
|
|
22425
|
+
var hasAgentIdentityHeaderNode = (headers) => {
|
|
22426
|
+
const raw = readNodeHeader(headers, "agent-identity");
|
|
22427
|
+
return raw !== void 0 && raw.split(",").some((s) => s.trim().length > 0);
|
|
22428
|
+
};
|
|
22429
|
+
var buildVerifyContextFromParts = (parts) => {
|
|
22430
|
+
const agentIdentityRaw = readNodeHeader(parts.headers, "agent-identity");
|
|
22431
|
+
const agentIdentityHeaders = agentIdentityRaw ? agentIdentityRaw.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : [];
|
|
22432
|
+
const host = parts.authority ?? readNodeHeader(parts.headers, "host") ?? "";
|
|
22433
|
+
let path;
|
|
22434
|
+
try {
|
|
22435
|
+
path = new URL(parts.url, host ? `http://${host}` : "http://localhost").pathname;
|
|
22436
|
+
} catch {
|
|
22437
|
+
const q = parts.url.indexOf("?");
|
|
22438
|
+
path = q === -1 ? parts.url : parts.url.slice(0, q);
|
|
22439
|
+
}
|
|
22440
|
+
return {
|
|
22441
|
+
method: parts.method,
|
|
22442
|
+
authority: host,
|
|
22443
|
+
path,
|
|
22444
|
+
agentIdentityHeaders,
|
|
22445
|
+
signatureInput: readNodeHeader(parts.headers, "signature-input") ?? null,
|
|
22446
|
+
signature: readNodeHeader(parts.headers, "signature") ?? null
|
|
22447
|
+
};
|
|
22448
|
+
};
|
|
22449
|
+
|
|
22450
|
+
// src/aip/gate.ts
|
|
22451
|
+
var verifyFromContext = async (ctx, opts) => {
|
|
22452
|
+
const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
|
|
22453
|
+
return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };
|
|
22454
|
+
};
|
|
22455
|
+
var verifyAitRequest = (req, opts) => verifyFromContext(buildVerifyContextFromRequest(req), opts);
|
|
22456
|
+
var verifyAitParts = (parts, opts) => verifyFromContext(buildVerifyContextFromParts(parts), opts);
|
|
22457
|
+
var aipErrorCode = (failure) => {
|
|
22458
|
+
switch (failure) {
|
|
22459
|
+
case "no_token":
|
|
22460
|
+
case "pop_signature_missing":
|
|
22461
|
+
return "agent_identity_required";
|
|
22462
|
+
case "untrusted_issuer":
|
|
22463
|
+
return "untrusted_issuer";
|
|
22464
|
+
case "expired_token":
|
|
22465
|
+
return "expired_token";
|
|
22466
|
+
case "invalid_claims":
|
|
22467
|
+
return "insufficient_claims";
|
|
22468
|
+
case "key_unavailable":
|
|
22469
|
+
return "idp_unavailable";
|
|
22470
|
+
case "malformed_token":
|
|
22471
|
+
case "idp_signature_invalid":
|
|
22472
|
+
case "pop_signature_invalid":
|
|
22473
|
+
return "invalid_signature";
|
|
22474
|
+
default:
|
|
22475
|
+
return "invalid_signature";
|
|
22476
|
+
}
|
|
22477
|
+
};
|
|
22478
|
+
var aipErrorStatus = (failure) => {
|
|
22479
|
+
switch (failure) {
|
|
22480
|
+
case "key_unavailable":
|
|
22481
|
+
return 503;
|
|
22482
|
+
case "untrusted_issuer":
|
|
22483
|
+
case "invalid_claims":
|
|
22484
|
+
return 403;
|
|
22485
|
+
default:
|
|
22486
|
+
return 401;
|
|
22487
|
+
}
|
|
22488
|
+
};
|
|
22489
|
+
var aipErrorDetail = (failure) => {
|
|
22490
|
+
switch (failure) {
|
|
22491
|
+
case "no_token":
|
|
22492
|
+
return "No Agent-Identity token was presented.";
|
|
22493
|
+
case "pop_signature_missing":
|
|
22494
|
+
return "The request is missing the RFC 9421 HTTP Message Signature that proves possession of the token-bound key.";
|
|
22495
|
+
case "untrusted_issuer":
|
|
22496
|
+
return "The token's issuer is not in this service's trusted-issuer list.";
|
|
22497
|
+
case "expired_token":
|
|
22498
|
+
return "The Agent Identity Token has expired.";
|
|
22499
|
+
case "invalid_claims":
|
|
22500
|
+
return "The token is missing required claims for this endpoint.";
|
|
22501
|
+
case "malformed_token":
|
|
22502
|
+
return "The Agent-Identity header could not be parsed as an Agent Identity Token.";
|
|
22503
|
+
case "idp_signature_invalid":
|
|
22504
|
+
return "The identity provider's signature on the token failed verification.";
|
|
22505
|
+
case "pop_signature_invalid":
|
|
22506
|
+
return "The request signature did not match the key bound to the token.";
|
|
22507
|
+
case "key_unavailable":
|
|
22508
|
+
return "The identity provider's signing key could not be resolved.";
|
|
22509
|
+
default:
|
|
22510
|
+
return "Token verification failed.";
|
|
22511
|
+
}
|
|
22512
|
+
};
|
|
22513
|
+
var buildAipErrorBody = (failure) => {
|
|
22514
|
+
const code = aipErrorCode(failure);
|
|
22515
|
+
return {
|
|
22516
|
+
type: `urn:aip:error:${code}`,
|
|
22517
|
+
title: code.replace(/_/g, " "),
|
|
22518
|
+
status: aipErrorStatus(failure),
|
|
22519
|
+
detail: aipErrorDetail(failure)
|
|
22520
|
+
};
|
|
22521
|
+
};
|
|
22522
|
+
|
|
22523
|
+
// src/aip/jwks.ts
|
|
22524
|
+
var JWKS_WELL_KNOWN_PATH = "/.well-known/agent-identity/jwks.json";
|
|
22525
|
+
var HARD_MAX_CACHE_SECONDS = 86400;
|
|
22526
|
+
var DEFAULT_CACHE_SECONDS = 300;
|
|
22527
|
+
var AGENTSCORE_CANONICAL_ISSUER = "https://agentscore.sh";
|
|
22528
|
+
var canonicalizeIssuer = (iss) => {
|
|
22529
|
+
let url2;
|
|
22530
|
+
try {
|
|
22531
|
+
url2 = new URL(iss.trim());
|
|
22532
|
+
} catch {
|
|
22533
|
+
return null;
|
|
22534
|
+
}
|
|
22535
|
+
const scheme = url2.protocol.toLowerCase();
|
|
22536
|
+
const host = url2.hostname.toLowerCase();
|
|
22537
|
+
const isDefaultPort = url2.port === "" || scheme === "https:" && url2.port === "443" || scheme === "http:" && url2.port === "80";
|
|
22538
|
+
const portPart = isDefaultPort ? "" : `:${url2.port}`;
|
|
22539
|
+
const path = url2.pathname === "/" ? "" : url2.pathname.replace(/\/$/, "");
|
|
22540
|
+
return `${scheme}//${host}${portPart}${path}`;
|
|
22541
|
+
};
|
|
22542
|
+
var resolveCacheSeconds = (cacheControl) => {
|
|
22543
|
+
if (!cacheControl) {
|
|
22544
|
+
return DEFAULT_CACHE_SECONDS;
|
|
22545
|
+
}
|
|
22546
|
+
if (/\bno-store\b/i.test(cacheControl) || /\bno-cache\b/i.test(cacheControl)) {
|
|
22547
|
+
return DEFAULT_CACHE_SECONDS;
|
|
22548
|
+
}
|
|
22549
|
+
const m = /\bmax-age\s*=\s*(\d+)/i.exec(cacheControl);
|
|
22550
|
+
if (!m) {
|
|
22551
|
+
return DEFAULT_CACHE_SECONDS;
|
|
22552
|
+
}
|
|
22553
|
+
const advertised = Number(m[1]);
|
|
22554
|
+
if (!Number.isFinite(advertised) || advertised <= 0) {
|
|
22555
|
+
return DEFAULT_CACHE_SECONDS;
|
|
22556
|
+
}
|
|
22557
|
+
return Math.min(advertised, HARD_MAX_CACHE_SECONDS);
|
|
22558
|
+
};
|
|
22559
|
+
var signingKeys = (keys) => keys.filter((k) => k.use === void 0 || k.use === "sig");
|
|
22560
|
+
var JwksCache = class {
|
|
22561
|
+
trusted;
|
|
22562
|
+
fetchImpl;
|
|
22563
|
+
now;
|
|
22564
|
+
userAgent;
|
|
22565
|
+
cache = /* @__PURE__ */ new Map();
|
|
22566
|
+
constructor(opts) {
|
|
22567
|
+
this.trusted = new Set(
|
|
22568
|
+
[AGENTSCORE_CANONICAL_ISSUER, ...opts.trustedIssuers ?? []].map(canonicalizeIssuer).filter((s) => s !== null)
|
|
22569
|
+
);
|
|
22570
|
+
this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
22571
|
+
this.now = opts.now ?? Date.now;
|
|
22572
|
+
this.userAgent = opts.userAgent ?? "@agentscore/commerce";
|
|
22573
|
+
}
|
|
22574
|
+
/** Is this issuer on the canonicalized trust list? */
|
|
22575
|
+
isTrusted(iss) {
|
|
22576
|
+
const canon = canonicalizeIssuer(iss);
|
|
22577
|
+
return canon !== null && this.trusted.has(canon);
|
|
22578
|
+
}
|
|
22579
|
+
/**
|
|
22580
|
+
* Resolve the signing key for `(iss, kid)`. Enforces trust + HTTPS, serves from cache when
|
|
22581
|
+
* fresh, and refetches once on a kid-miss before giving up.
|
|
22582
|
+
*/
|
|
22583
|
+
async getKey(iss, kid) {
|
|
22584
|
+
const canon = canonicalizeIssuer(iss);
|
|
22585
|
+
if (canon === null || !this.trusted.has(canon)) {
|
|
22586
|
+
return { ok: false, reason: "untrusted_issuer" };
|
|
22587
|
+
}
|
|
22588
|
+
if (!canon.startsWith("https://")) {
|
|
22589
|
+
return { ok: false, reason: "insecure_issuer" };
|
|
22590
|
+
}
|
|
22591
|
+
const cached2 = this.cache.get(canon);
|
|
22592
|
+
if (cached2 && this.now() < cached2.expiresAt) {
|
|
22593
|
+
const hit2 = this.select(cached2.keys, kid);
|
|
22594
|
+
if (hit2) {
|
|
22595
|
+
return { ok: true, key: hit2 };
|
|
22596
|
+
}
|
|
22597
|
+
}
|
|
22598
|
+
const refreshed = await this.refresh(canon);
|
|
22599
|
+
if (!refreshed.ok) {
|
|
22600
|
+
return refreshed;
|
|
22601
|
+
}
|
|
22602
|
+
const hit = this.select(refreshed.keys, kid);
|
|
22603
|
+
return hit ? { ok: true, key: hit } : { ok: false, reason: "key_not_found" };
|
|
22604
|
+
}
|
|
22605
|
+
select(keys, kid) {
|
|
22606
|
+
const candidates = signingKeys(keys);
|
|
22607
|
+
if (kid !== void 0) {
|
|
22608
|
+
const byKid = candidates.find((k) => k.kid === kid);
|
|
22609
|
+
if (byKid) {
|
|
22610
|
+
return byKid;
|
|
22611
|
+
}
|
|
22612
|
+
return void 0;
|
|
22613
|
+
}
|
|
22614
|
+
return candidates.length === 1 ? candidates[0] : void 0;
|
|
22615
|
+
}
|
|
22616
|
+
async refresh(canonIssuer) {
|
|
22617
|
+
const url2 = `${canonIssuer}${JWKS_WELL_KNOWN_PATH}`;
|
|
22618
|
+
let res;
|
|
22619
|
+
try {
|
|
22620
|
+
res = await this.fetchImpl(url2, { headers: { "User-Agent": this.userAgent, Accept: "application/jwk-set+json, application/json" } });
|
|
22621
|
+
} catch {
|
|
22622
|
+
return { ok: false, reason: "fetch_failed" };
|
|
22623
|
+
}
|
|
22624
|
+
if (!res.ok) {
|
|
22625
|
+
return { ok: false, reason: "fetch_failed" };
|
|
22626
|
+
}
|
|
22627
|
+
let body;
|
|
22628
|
+
try {
|
|
22629
|
+
body = await res.json();
|
|
22630
|
+
} catch {
|
|
22631
|
+
return { ok: false, reason: "malformed_jwks" };
|
|
22632
|
+
}
|
|
22633
|
+
if (typeof body !== "object" || body === null || !Array.isArray(body.keys)) {
|
|
22634
|
+
return { ok: false, reason: "malformed_jwks" };
|
|
22635
|
+
}
|
|
22636
|
+
const keys = body.keys;
|
|
22637
|
+
const ttlSeconds = resolveCacheSeconds(res.headers.get("cache-control"));
|
|
22638
|
+
this.cache.set(canonIssuer, { keys, expiresAt: this.now() + ttlSeconds * 1e3 });
|
|
22639
|
+
return { ok: true, keys };
|
|
22640
|
+
}
|
|
22641
|
+
};
|
|
22642
|
+
|
|
21905
22643
|
// src/payment/rail_spec.ts
|
|
21906
22644
|
init_usdc();
|
|
21907
22645
|
async function resolveRecipient(r) {
|
|
@@ -22054,10 +22792,11 @@ function buildAgentInstructions({
|
|
|
22054
22792
|
|
|
22055
22793
|
// src/challenge/agent_memory.ts
|
|
22056
22794
|
function firstEncounterAgentMemory({
|
|
22057
|
-
firstEncounter
|
|
22795
|
+
firstEncounter,
|
|
22796
|
+
aipTrustedIssuers
|
|
22058
22797
|
}) {
|
|
22059
22798
|
if (!firstEncounter) return void 0;
|
|
22060
|
-
return buildAgentMemoryHint();
|
|
22799
|
+
return buildAgentMemoryHint(aipTrustedIssuers);
|
|
22061
22800
|
}
|
|
22062
22801
|
|
|
22063
22802
|
// src/challenge/body.ts
|
|
@@ -23089,6 +23828,30 @@ function pickRail(rails2, key) {
|
|
|
23089
23828
|
const spec = rails2[key];
|
|
23090
23829
|
return spec === void 0 ? void 0 : spec;
|
|
23091
23830
|
}
|
|
23831
|
+
function buildAipTrustedIssuers(externalIssuers) {
|
|
23832
|
+
const out = [AGENTSCORE_CANONICAL_ISSUER, ...externalIssuers ?? []];
|
|
23833
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23834
|
+
const deduped = [];
|
|
23835
|
+
for (const iss of out) {
|
|
23836
|
+
const key = canonicalizeIssuer(iss) ?? iss;
|
|
23837
|
+
if (!seen.has(key)) {
|
|
23838
|
+
seen.add(key);
|
|
23839
|
+
deduped.push(iss);
|
|
23840
|
+
}
|
|
23841
|
+
}
|
|
23842
|
+
return deduped;
|
|
23843
|
+
}
|
|
23844
|
+
function aipTrustedIssuerSet(cfg) {
|
|
23845
|
+
return buildAipTrustedIssuers(cfg.trustedIssuers);
|
|
23846
|
+
}
|
|
23847
|
+
function resolveIssuerPolicy(issuerPolicies, iss) {
|
|
23848
|
+
const target = canonicalizeIssuer(iss);
|
|
23849
|
+
if (target === null) return void 0;
|
|
23850
|
+
for (const [key, policy] of Object.entries(issuerPolicies)) {
|
|
23851
|
+
if (canonicalizeIssuer(key) === target) return policy;
|
|
23852
|
+
}
|
|
23853
|
+
return void 0;
|
|
23854
|
+
}
|
|
23092
23855
|
var Checkout = class {
|
|
23093
23856
|
rails;
|
|
23094
23857
|
url;
|
|
@@ -23106,6 +23869,15 @@ var Checkout = class {
|
|
|
23106
23869
|
discoveryExtensions;
|
|
23107
23870
|
discoveryProbe;
|
|
23108
23871
|
_x402ServerGetter;
|
|
23872
|
+
/** Lazily-built JWKS cache for AIP verification, shared across requests so issuer keys
|
|
23873
|
+
* are fetched once and cached (per the verifier's hard 24h cap). Built on first AIT. */
|
|
23874
|
+
aipJwks;
|
|
23875
|
+
getAipJwks(cfg) {
|
|
23876
|
+
if (this.aipJwks === void 0) {
|
|
23877
|
+
this.aipJwks = new JwksCache(cfg.trustedIssuers !== void 0 ? { trustedIssuers: cfg.trustedIssuers } : {});
|
|
23878
|
+
}
|
|
23879
|
+
return this.aipJwks;
|
|
23880
|
+
}
|
|
23109
23881
|
/**
|
|
23110
23882
|
* True when the merchant has configured an identity-bearing policy flag —
|
|
23111
23883
|
* `require_kyc`, `require_sanctions_clear` (name screening on the KYC
|
|
@@ -23393,7 +24165,64 @@ var Checkout = class {
|
|
|
23393
24165
|
}
|
|
23394
24166
|
return result;
|
|
23395
24167
|
}
|
|
24168
|
+
const headers = normalizeHeadersToLowercase(ctx.request.headers);
|
|
24169
|
+
const walletAddress = headers["x-wallet-address"];
|
|
24170
|
+
const operatorToken = headers["x-operator-token"];
|
|
24171
|
+
let aipToken;
|
|
24172
|
+
let aipIssuer;
|
|
24173
|
+
if (gate.aip !== void 0 && hasAgentIdentityHeaderNode(headers)) {
|
|
24174
|
+
const aipResult = await verifyAitParts(
|
|
24175
|
+
{
|
|
24176
|
+
method: ctx.request.method,
|
|
24177
|
+
url: ctx.request.url,
|
|
24178
|
+
headers,
|
|
24179
|
+
...gate.aip.authority !== void 0 && { authority: gate.aip.authority }
|
|
24180
|
+
},
|
|
24181
|
+
{
|
|
24182
|
+
jwks: this.getAipJwks(gate.aip),
|
|
24183
|
+
...gate.aip.maxSkewSeconds !== void 0 && { maxSkewSeconds: gate.aip.maxSkewSeconds }
|
|
24184
|
+
}
|
|
24185
|
+
);
|
|
24186
|
+
if (!aipResult.ok) {
|
|
24187
|
+
const body2 = buildAipErrorBody(aipResult.failure);
|
|
24188
|
+
return {
|
|
24189
|
+
status: body2.status,
|
|
24190
|
+
body: body2,
|
|
24191
|
+
headers: {
|
|
24192
|
+
"content-type": "application/problem+json",
|
|
24193
|
+
// 503 = the IdP's JWKS was unreachable (transient infra, not a bad token). Hint a
|
|
24194
|
+
// short backoff so agents retry rather than uselessly re-signing.
|
|
24195
|
+
...body2.status === 503 && { "retry-after": "5" }
|
|
24196
|
+
}
|
|
24197
|
+
};
|
|
24198
|
+
}
|
|
24199
|
+
aipToken = aipResult.ait.token;
|
|
24200
|
+
aipIssuer = aipResult.ait.iss;
|
|
24201
|
+
}
|
|
24202
|
+
const issuerPolicy = aipIssuer !== void 0 && gate.aip?.issuerPolicies !== void 0 ? resolveIssuerPolicy(gate.aip.issuerPolicies, aipIssuer) : void 0;
|
|
24203
|
+
const effPolicy = issuerPolicy ?? {
|
|
24204
|
+
...gate.requireKyc !== void 0 && { requireKyc: gate.requireKyc },
|
|
24205
|
+
...gate.requireSanctionsClear !== void 0 && { requireSanctionsClear: gate.requireSanctionsClear },
|
|
24206
|
+
...gate.minAge !== void 0 && { minAge: gate.minAge },
|
|
24207
|
+
...gate.blockedJurisdictions !== void 0 && { blockedJurisdictions: gate.blockedJurisdictions },
|
|
24208
|
+
...gate.allowedJurisdictions !== void 0 && { allowedJurisdictions: gate.allowedJurisdictions }
|
|
24209
|
+
};
|
|
23396
24210
|
if (gate.apiKey === void 0) {
|
|
24211
|
+
if (aipToken !== void 0) {
|
|
24212
|
+
const hasPolicy = effPolicy.requireKyc || effPolicy.requireSanctionsClear || effPolicy.minAge != null || effPolicy.blockedJurisdictions !== void 0 || effPolicy.allowedJurisdictions !== void 0;
|
|
24213
|
+
if (hasPolicy) {
|
|
24214
|
+
return {
|
|
24215
|
+
status: 403,
|
|
24216
|
+
body: {
|
|
24217
|
+
error: {
|
|
24218
|
+
code: "aip_policy_requires_api_key",
|
|
24219
|
+
message: "This gate declares compliance policy (KYC / age / sanctions / jurisdiction) but has no AgentScore apiKey, so the Agent Identity Token\u2019s claims cannot be evaluated. Configure gate.apiKey to enable policy enforcement on AITs."
|
|
24220
|
+
}
|
|
24221
|
+
}
|
|
24222
|
+
};
|
|
24223
|
+
}
|
|
24224
|
+
return null;
|
|
24225
|
+
}
|
|
23397
24226
|
return this.runWalletSanctionsOnly(ctx);
|
|
23398
24227
|
}
|
|
23399
24228
|
let policyOverride;
|
|
@@ -23405,14 +24234,21 @@ var Checkout = class {
|
|
|
23405
24234
|
apiKey: gate.apiKey,
|
|
23406
24235
|
...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
|
|
23407
24236
|
...gate.userAgent !== void 0 && { userAgent: gate.userAgent },
|
|
23408
|
-
|
|
23409
|
-
|
|
23410
|
-
|
|
23411
|
-
|
|
23412
|
-
...
|
|
24237
|
+
// Compliance fields come from effPolicy — the per-issuer override for the verified AIT's
|
|
24238
|
+
// issuer when one is configured, else the gate defaults (see effPolicy above). A whole-
|
|
24239
|
+
// policy replacement: an issuer override of `{ requireKyc, minAge }` sends ONLY those,
|
|
24240
|
+
// so sanctions / jurisdiction are not enforced for that issuer.
|
|
24241
|
+
...effPolicy.requireKyc !== void 0 && { requireKyc: effPolicy.requireKyc },
|
|
24242
|
+
...effPolicy.requireSanctionsClear !== void 0 && { requireSanctionsClear: effPolicy.requireSanctionsClear },
|
|
24243
|
+
...effPolicy.minAge !== void 0 && { minAge: effPolicy.minAge },
|
|
24244
|
+
...effPolicy.blockedJurisdictions !== void 0 && { blockedJurisdictions: effPolicy.blockedJurisdictions },
|
|
24245
|
+
...effPolicy.allowedJurisdictions !== void 0 && { allowedJurisdictions: effPolicy.allowedJurisdictions },
|
|
23413
24246
|
...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
|
|
23414
24247
|
...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
|
|
23415
24248
|
...gate.chain !== void 0 && { chain: gate.chain },
|
|
24249
|
+
// Surface AIP acceptance in the missing-identity recovery instructions + agent_memory
|
|
24250
|
+
// hint so agents holding an AIT learn they can present it instead of bootstrapping.
|
|
24251
|
+
...gate.aip !== void 0 && { aipTrustedIssuers: aipTrustedIssuerSet(gate.aip) },
|
|
23416
24252
|
// Auto-default `createSessionOnMissing` from gate config when the merchant
|
|
23417
24253
|
// didn't supply one, so every gated route gets the bootstrap session-mint UX
|
|
23418
24254
|
// out of the box. Merchants who need custom session context or onBeforeSession
|
|
@@ -23426,10 +24262,7 @@ var Checkout = class {
|
|
|
23426
24262
|
...policyOverride ?? {}
|
|
23427
24263
|
};
|
|
23428
24264
|
const core = createAgentScoreCore(coreOpts);
|
|
23429
|
-
const
|
|
23430
|
-
const walletAddress = headers["x-wallet-address"];
|
|
23431
|
-
const operatorToken = headers["x-operator-token"];
|
|
23432
|
-
const identity = walletAddress !== void 0 || operatorToken !== void 0 ? {
|
|
24265
|
+
const identity = aipToken !== void 0 ? { aipToken } : walletAddress !== void 0 || operatorToken !== void 0 ? {
|
|
23433
24266
|
...walletAddress !== void 0 && { address: walletAddress },
|
|
23434
24267
|
...operatorToken !== void 0 && { operatorToken }
|
|
23435
24268
|
} : void 0;
|
|
@@ -23448,7 +24281,7 @@ var Checkout = class {
|
|
|
23448
24281
|
});
|
|
23449
24282
|
};
|
|
23450
24283
|
}
|
|
23451
|
-
if (walletAddress !== void 0) {
|
|
24284
|
+
if (aipToken === void 0 && walletAddress !== void 0) {
|
|
23452
24285
|
const verdict = core.getSignerVerdict(walletAddress);
|
|
23453
24286
|
const sm = verdict?.signer_match;
|
|
23454
24287
|
if (sm && sm.kind !== "pass") {
|
|
@@ -23570,7 +24403,7 @@ var Checkout = class {
|
|
|
23570
24403
|
return await this.buildSuccess(ctx, outcome);
|
|
23571
24404
|
}
|
|
23572
24405
|
async mintRefId(request) {
|
|
23573
|
-
if (this.mintReferenceId === void 0) return (0,
|
|
24406
|
+
if (this.mintReferenceId === void 0) return (0, import_node_crypto3.randomUUID)();
|
|
23574
24407
|
const seedCtx = { request, referenceId: "", pricing: null, recipients: {}, state: {} };
|
|
23575
24408
|
return await this.mintReferenceId(seedCtx);
|
|
23576
24409
|
}
|
|
@@ -23793,8 +24626,13 @@ var Checkout = class {
|
|
|
23793
24626
|
retryBody: ctx.request.body,
|
|
23794
24627
|
// Merchants without an identity-bearing gate get a clean 402: no
|
|
23795
24628
|
// AgentScore-identity bootstrap describing a verification flow they
|
|
23796
|
-
// don't run. Wallet OFAC (the always-on default) doesn't need it.
|
|
23797
|
-
|
|
24629
|
+
// don't run. Wallet OFAC (the always-on default) doesn't need it. When the
|
|
24630
|
+
// merchant accepts AIP, advertise the agent_identity path too (AgentScore's
|
|
24631
|
+
// own issuer is always trusted, so this fires even with no external issuers).
|
|
24632
|
+
agentMemory: firstEncounterAgentMemory({
|
|
24633
|
+
firstEncounter: this.hasIdentityGate(),
|
|
24634
|
+
...this.gate?.aip !== void 0 && { aipTrustedIssuers: aipTrustedIssuerSet(this.gate.aip) }
|
|
24635
|
+
}),
|
|
23798
24636
|
...ctx.pricing.product ? { product: ctx.pricing.product } : {},
|
|
23799
24637
|
...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
|
|
23800
24638
|
...x402Accepts.length > 0 ? {
|
|
@@ -24856,15 +25694,26 @@ function defaultReadOnlyOnDenied(reason) {
|
|
|
24856
25694
|
0 && (module.exports = {
|
|
24857
25695
|
A2A_DEFAULT_TRANSPORT,
|
|
24858
25696
|
A2A_PROTOCOL_VERSION,
|
|
25697
|
+
AGENTSCORE_CANONICAL_ISSUER,
|
|
24859
25698
|
AGENTSCORE_UCP_CAPABILITY,
|
|
25699
|
+
AGENT_IDENTITY_HEADER,
|
|
25700
|
+
AIP_COVERED_COMPONENTS,
|
|
25701
|
+
AIP_SIGNATURE_TAG,
|
|
24860
25702
|
Checkout,
|
|
24861
25703
|
CheckoutValidationError,
|
|
24862
25704
|
FIXABLE_DENIAL_REASONS,
|
|
25705
|
+
HARD_MAX_CACHE_SECONDS,
|
|
25706
|
+
JWKS_WELL_KNOWN_PATH,
|
|
25707
|
+
JwksCache,
|
|
24863
25708
|
UCPSigningKey,
|
|
24864
25709
|
UCPVerificationError,
|
|
24865
25710
|
UCP_A2A_EXTENSION_URI,
|
|
25711
|
+
aipErrorCode,
|
|
25712
|
+
aipErrorStatus,
|
|
24866
25713
|
buildA2AAgentCard,
|
|
24867
25714
|
buildAgentMemoryHint,
|
|
25715
|
+
buildAipErrorBody,
|
|
25716
|
+
buildAipTrustedIssuers,
|
|
24868
25717
|
buildContactSupportNextSteps,
|
|
24869
25718
|
buildDefaultCheckoutRails,
|
|
24870
25719
|
buildGateFromPolicy,
|
|
@@ -24873,6 +25722,8 @@ function defaultReadOnlyOnDenied(reason) {
|
|
|
24873
25722
|
buildSignerMismatchBody,
|
|
24874
25723
|
buildUCPProfile,
|
|
24875
25724
|
buildVerificationRequiredBody,
|
|
25725
|
+
buildVerifyContextFromRequest,
|
|
25726
|
+
canonicalizeIssuer,
|
|
24876
25727
|
computeFirstCheckout,
|
|
24877
25728
|
createDefaultOnDenied,
|
|
24878
25729
|
createQuoteCache,
|
|
@@ -24886,10 +25737,12 @@ function defaultReadOnlyOnDenied(reason) {
|
|
|
24886
25737
|
formatUsdCents,
|
|
24887
25738
|
generateUCPSigningKey,
|
|
24888
25739
|
getIdentityStatus,
|
|
25740
|
+
hasAgentIdentityHeader,
|
|
24889
25741
|
hasMppxHeader,
|
|
24890
25742
|
hasPaymentHeader,
|
|
24891
25743
|
hasX402Header,
|
|
24892
25744
|
hashOperatorToken,
|
|
25745
|
+
isAitShape,
|
|
24893
25746
|
isEvmNetwork,
|
|
24894
25747
|
isFixableDenial,
|
|
24895
25748
|
isSolanaNetwork,
|
|
@@ -24902,9 +25755,11 @@ function defaultReadOnlyOnDenied(reason) {
|
|
|
24902
25755
|
runGateWithEnforcement,
|
|
24903
25756
|
shippingCountryAllowed,
|
|
24904
25757
|
shippingStateAllowed,
|
|
25758
|
+
signMessage,
|
|
24905
25759
|
signUCPProfile,
|
|
24906
25760
|
stripeSptPaymentHandler,
|
|
24907
25761
|
ucpA2AExtension,
|
|
25762
|
+
validateAitPayload,
|
|
24908
25763
|
validateShippingAgainstPolicy,
|
|
24909
25764
|
validationEnvelope,
|
|
24910
25765
|
validationResponseExpress,
|
|
@@ -24913,6 +25768,9 @@ function defaultReadOnlyOnDenied(reason) {
|
|
|
24913
25768
|
validationResponseNextjs,
|
|
24914
25769
|
validationResponseWeb,
|
|
24915
25770
|
verificationAgentInstructions,
|
|
25771
|
+
verifyAit,
|
|
25772
|
+
verifyAitRequest,
|
|
25773
|
+
verifyMessageSignature,
|
|
24916
25774
|
verifyUCPProfile,
|
|
24917
25775
|
x402PaymentHandler
|
|
24918
25776
|
});
|