@astrasyncai/verification-gateway 2.4.11 → 2.4.14
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/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +129 -36
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +129 -36
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +26 -4
- package/dist/adapters/mcp.d.ts +26 -4
- package/dist/adapters/mcp.js +94 -28
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +94 -28
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +75 -29
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +75 -29
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +45 -22
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +45 -22
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js +29 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +29 -0
- package/dist/agent/index.mjs.map +1 -1
- package/dist/browser/background.js +86 -24
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +86 -24
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +86 -24
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +86 -24
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/{express-C1ePFB7n.d.ts → express-CrfwoNAR.d.ts} +1 -1
- package/dist/{express-4WStX3PV.d.mts → express-ienhAXps.d.mts} +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +86 -24
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +86 -24
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-ChPX4WHl.d.mts → index-B5e2IDWU.d.mts} +1 -1
- package/dist/{index-CzJMCgEy.d.ts → index-CCdZxvAr.d.ts} +71 -6
- package/dist/{index-D8IEntil.d.mts → index-CEg_WG6y.d.mts} +71 -6
- package/dist/{index-Cjm-zBeZ.d.ts → index-DC5f8eoQ.d.ts} +1 -1
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +344 -73
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +344 -73
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/local-evaluator/evaluator.js +12 -2
- package/dist/local-evaluator/evaluator.js.map +1 -1
- package/dist/local-evaluator/evaluator.mjs +12 -2
- package/dist/local-evaluator/evaluator.mjs.map +1 -1
- package/dist/{nextjs-BIORS__0.d.ts → nextjs-66R1KW8e.d.ts} +1 -1
- package/dist/{nextjs-CjzHdaXA.d.mts → nextjs-DSpisQst.d.mts} +1 -1
- package/dist/{sdk-Chhz-FcT.d.mts → sdk-5U_CBRpr.d.mts} +1 -1
- package/dist/{sdk-CqTEQAc6.d.ts → sdk-Bm8np66n.d.ts} +1 -1
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js +146 -28
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +146 -28
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-L15pYd2c.d.mts → types-B3USs-Kx.d.mts} +42 -1
- package/dist/{types-L15pYd2c.d.ts → types-B3USs-Kx.d.ts} +42 -1
- package/dist/{types-DNK2BgIf.d.mts → types-CgDCUfo8.d.mts} +1 -1
- package/dist/{types-DoWIuzfj.d.ts → types-R5N4ET6x.d.ts} +1 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/transport/index.mjs
CHANGED
|
@@ -410,12 +410,45 @@ function bufferToBase64(bytes) {
|
|
|
410
410
|
|
|
411
411
|
// src/transport/rfc9421-verify.ts
|
|
412
412
|
import { httpbis } from "http-message-signatures";
|
|
413
|
+
|
|
414
|
+
// src/transport/nonce-store.ts
|
|
415
|
+
var InMemoryNonceStore = class {
|
|
416
|
+
constructor(capacity = 1e4) {
|
|
417
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
418
|
+
this.lastSweepMs = 0;
|
|
419
|
+
this.capacity = capacity;
|
|
420
|
+
}
|
|
421
|
+
seen(key, expiresAtMs) {
|
|
422
|
+
const nowMs = Date.now();
|
|
423
|
+
if (nowMs - this.lastSweepMs > 1e3) {
|
|
424
|
+
for (const [k, exp] of this.entries) {
|
|
425
|
+
if (exp <= nowMs) this.entries.delete(k);
|
|
426
|
+
}
|
|
427
|
+
this.lastSweepMs = nowMs;
|
|
428
|
+
}
|
|
429
|
+
const existing = this.entries.get(key);
|
|
430
|
+
if (existing !== void 0 && existing > nowMs) {
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
if (this.entries.size >= this.capacity) {
|
|
434
|
+
const oldest = this.entries.keys().next().value;
|
|
435
|
+
if (oldest !== void 0) this.entries.delete(oldest);
|
|
436
|
+
}
|
|
437
|
+
this.entries.set(key, expiresAtMs);
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
var defaultNonceStore = new InMemoryNonceStore();
|
|
442
|
+
|
|
443
|
+
// src/transport/rfc9421-verify.ts
|
|
413
444
|
async function verifyRFC9421(request, options) {
|
|
414
445
|
const { resolver } = options;
|
|
415
|
-
const tolerance = options.clockSkewSec ??
|
|
446
|
+
const tolerance = options.clockSkewSec ?? 60;
|
|
416
447
|
const nowSec = options.now ? options.now() : Math.floor(Date.now() / 1e3);
|
|
448
|
+
const nonceStore = options.nonceStore ?? defaultNonceStore;
|
|
417
449
|
let resolvedKid;
|
|
418
450
|
let resolvedAlg;
|
|
451
|
+
let replayDetected = false;
|
|
419
452
|
const keyLookup = async (parameters) => {
|
|
420
453
|
const kid = typeof parameters.keyid === "string" ? parameters.keyid : void 0;
|
|
421
454
|
if (!kid) return null;
|
|
@@ -429,6 +462,14 @@ async function verifyRFC9421(request, options) {
|
|
|
429
462
|
const expires = toUnixSeconds(parameters.expires);
|
|
430
463
|
if (created !== void 0 && Math.abs(nowSec - created) > tolerance) return null;
|
|
431
464
|
if (expires !== void 0 && nowSec > expires + tolerance) return null;
|
|
465
|
+
const nonce = typeof parameters.nonce === "string" ? parameters.nonce : void 0;
|
|
466
|
+
if (nonce) {
|
|
467
|
+
const expiresAtMs = (expires !== void 0 ? expires + tolerance : nowSec + tolerance) * 1e3;
|
|
468
|
+
if (nonceStore.seen(`rfc9421:${kid}:${nonce}`, expiresAtMs)) {
|
|
469
|
+
replayDetected = true;
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
432
473
|
return jwkToVerifyingKey(kid, jwk, alg);
|
|
433
474
|
};
|
|
434
475
|
try {
|
|
@@ -451,7 +492,7 @@ async function verifyRFC9421(request, options) {
|
|
|
451
492
|
kid: resolvedKid,
|
|
452
493
|
registry: resolver.name,
|
|
453
494
|
algorithm: resolvedAlg,
|
|
454
|
-
error: result === false ? "signature invalid" : "no signature found"
|
|
495
|
+
error: replayDetected ? "RFC9421 signature replay \u2014 already seen within tolerance window" : result === false ? "signature invalid" : "no signature found"
|
|
455
496
|
};
|
|
456
497
|
} catch (err) {
|
|
457
498
|
return {
|
|
@@ -1276,14 +1317,26 @@ function sha256Sync2(data) {
|
|
|
1276
1317
|
function verifyAP2Chain(input) {
|
|
1277
1318
|
const { triple } = input;
|
|
1278
1319
|
const errors = [];
|
|
1320
|
+
const toleranceSec = input.clockSkewSec ?? 60;
|
|
1321
|
+
const nonceStore = input.nonceStore ?? defaultNonceStore;
|
|
1279
1322
|
const intentPresent = triple.intent !== void 0;
|
|
1280
1323
|
const cartRefOk = checkCartRef(triple, errors);
|
|
1281
1324
|
const paymentRefOk = checkPaymentRef(triple, errors);
|
|
1282
1325
|
const { ok: agentIdContinuity, agentId } = checkAgentContinuity(triple, errors);
|
|
1283
1326
|
const paymentMethodAllowed = checkPaymentMethod(triple, errors);
|
|
1284
1327
|
const totalsConsistent = checkTotals(triple, errors);
|
|
1285
|
-
const expiryOk = checkExpiries(triple,
|
|
1286
|
-
|
|
1328
|
+
const expiryOk = checkExpiries(triple, toleranceSec, input.now, errors);
|
|
1329
|
+
let replayOk = true;
|
|
1330
|
+
const replayId = triple.payment?.raw?.id ?? triple.cart?.raw?.id;
|
|
1331
|
+
if (typeof replayId === "string" && replayId.length > 0) {
|
|
1332
|
+
const now = input.now ? input.now() : Math.floor(Date.now() / 1e3);
|
|
1333
|
+
const expiresAt = (now + toleranceSec) * 1e3;
|
|
1334
|
+
if (nonceStore.seen(`ap2:${replayId}`, expiresAt)) {
|
|
1335
|
+
errors.push(`AP2 chain replay \u2014 mandate ${replayId} already seen within tolerance window`);
|
|
1336
|
+
replayOk = false;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
const ok = cartRefOk && paymentRefOk && agentIdContinuity && paymentMethodAllowed && totalsConsistent && expiryOk && replayOk;
|
|
1287
1340
|
return {
|
|
1288
1341
|
ok,
|
|
1289
1342
|
checks: {
|
|
@@ -1329,7 +1382,10 @@ function checkAgentContinuity(triple, errors) {
|
|
|
1329
1382
|
const ids = [triple.intent?.agent_id, triple.cart?.agent_id, triple.payment?.agent_id].filter(
|
|
1330
1383
|
(id) => typeof id === "string" && id.length > 0
|
|
1331
1384
|
);
|
|
1332
|
-
if (ids.length === 0)
|
|
1385
|
+
if (ids.length === 0) {
|
|
1386
|
+
errors.push("agent_id missing across all three mandates (intent/cart/payment)");
|
|
1387
|
+
return { ok: false };
|
|
1388
|
+
}
|
|
1333
1389
|
const unique = new Set(ids);
|
|
1334
1390
|
if (unique.size > 1) {
|
|
1335
1391
|
errors.push(`agent_id mismatch across mandates: ${Array.from(unique).join(", ")}`);
|
|
@@ -1338,9 +1394,16 @@ function checkAgentContinuity(triple, errors) {
|
|
|
1338
1394
|
return { ok: true, agentId: ids[0] };
|
|
1339
1395
|
}
|
|
1340
1396
|
function checkPaymentMethod(triple, errors) {
|
|
1341
|
-
const paymentMethod = triple.payment?.payment_method;
|
|
1342
1397
|
const allowed = triple.intent?.paymentMethods;
|
|
1343
|
-
if (!
|
|
1398
|
+
if (!allowed || allowed.length === 0) return true;
|
|
1399
|
+
if (!triple.payment) return true;
|
|
1400
|
+
const paymentMethod = triple.payment.payment_method;
|
|
1401
|
+
if (!paymentMethod) {
|
|
1402
|
+
errors.push(
|
|
1403
|
+
`payment.payment_method missing but intent declares allowlist [${allowed.join(", ")}]`
|
|
1404
|
+
);
|
|
1405
|
+
return false;
|
|
1406
|
+
}
|
|
1344
1407
|
if (!allowed.includes(paymentMethod)) {
|
|
1345
1408
|
errors.push(
|
|
1346
1409
|
`payment_method "${paymentMethod}" not in intent.paymentMethods [${allowed.join(", ")}]`
|
|
@@ -1374,19 +1437,24 @@ function checkTotals(triple, errors) {
|
|
|
1374
1437
|
function checkExpiries(triple, toleranceSec, nowFn, errors) {
|
|
1375
1438
|
const now = nowFn ? nowFn() : Math.floor(Date.now() / 1e3);
|
|
1376
1439
|
let ok = true;
|
|
1377
|
-
|
|
1378
|
-
["intent", triple.intent],
|
|
1379
|
-
["cart", triple.cart]
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1440
|
+
const layers = [
|
|
1441
|
+
["intent", triple.intent?.expires],
|
|
1442
|
+
["cart", triple.cart?.expires],
|
|
1443
|
+
[
|
|
1444
|
+
"payment",
|
|
1445
|
+
typeof triple.payment?.raw?.expires === "string" ? triple.payment.raw.expires : typeof triple.payment?.raw?.exp === "string" ? triple.payment.raw.exp : void 0
|
|
1446
|
+
]
|
|
1447
|
+
];
|
|
1448
|
+
for (const [name, expires] of layers) {
|
|
1449
|
+
if (!expires) continue;
|
|
1450
|
+
const parsed = parseExpiry(expires);
|
|
1383
1451
|
if (parsed === null) {
|
|
1384
1452
|
errors.push(`${name}.expires unparseable`);
|
|
1385
1453
|
ok = false;
|
|
1386
1454
|
continue;
|
|
1387
1455
|
}
|
|
1388
1456
|
if (now > parsed + toleranceSec) {
|
|
1389
|
-
errors.push(`${name} mandate expired at ${
|
|
1457
|
+
errors.push(`${name} mandate expired at ${expires}`);
|
|
1390
1458
|
ok = false;
|
|
1391
1459
|
}
|
|
1392
1460
|
}
|
|
@@ -1413,10 +1481,21 @@ async function verifyACPSignature(input) {
|
|
|
1413
1481
|
if (!input.signatureHeader) {
|
|
1414
1482
|
return { ok: false, error: "missing Signature header" };
|
|
1415
1483
|
}
|
|
1416
|
-
const
|
|
1484
|
+
const tolerance = input.clockSkewSec ?? 60;
|
|
1485
|
+
const nonceStore = input.nonceStore ?? defaultNonceStore;
|
|
1486
|
+
const freshness = checkTimestamp(input.timestampHeader, tolerance, input.now);
|
|
1417
1487
|
if (!freshness.ok) {
|
|
1418
1488
|
return { ok: false, error: freshness.error, timestampStale: true };
|
|
1419
1489
|
}
|
|
1490
|
+
const nowSec = input.now ? input.now() : Math.floor(Date.now() / 1e3);
|
|
1491
|
+
const expiresAtMs = (nowSec + tolerance) * 1e3;
|
|
1492
|
+
const replayKey = `acp:${input.signatureHeader}:${input.timestampHeader ?? ""}`;
|
|
1493
|
+
if (nonceStore.seen(replayKey, expiresAtMs)) {
|
|
1494
|
+
return {
|
|
1495
|
+
ok: false,
|
|
1496
|
+
error: "ACP signature replay \u2014 already seen within tolerance window"
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1420
1499
|
const signatureBytes = decodeBase64(input.signatureHeader);
|
|
1421
1500
|
if (!signatureBytes) {
|
|
1422
1501
|
return { ok: false, error: "signature header is not valid base64" };
|
|
@@ -1634,8 +1713,9 @@ function coerceString6(v) {
|
|
|
1634
1713
|
import { BodyDigest } from "mppx";
|
|
1635
1714
|
function verifyMPP(input) {
|
|
1636
1715
|
const { context } = input;
|
|
1637
|
-
const tolerance = input.clockSkewSec ??
|
|
1716
|
+
const tolerance = input.clockSkewSec ?? 60;
|
|
1638
1717
|
const nowSec = input.now ? input.now() : Math.floor(Date.now() / 1e3);
|
|
1718
|
+
const nonceStore = input.nonceStore ?? defaultNonceStore;
|
|
1639
1719
|
const challenge = context.credential?.challenge ?? (context.challenges && context.challenges[0]);
|
|
1640
1720
|
const source = context.credential?.source;
|
|
1641
1721
|
const method = challenge?.method;
|
|
@@ -1658,21 +1738,38 @@ function verifyMPP(input) {
|
|
|
1658
1738
|
}
|
|
1659
1739
|
}
|
|
1660
1740
|
let bodyDigestOk = null;
|
|
1661
|
-
if (
|
|
1662
|
-
|
|
1663
|
-
|
|
1741
|
+
if (input.rawBody !== void 0) {
|
|
1742
|
+
if (!challenge?.digest) {
|
|
1743
|
+
bodyDigestOk = false;
|
|
1744
|
+
} else {
|
|
1745
|
+
try {
|
|
1746
|
+
if (!/^sha-256=/.test(challenge.digest)) {
|
|
1747
|
+
bodyDigestOk = false;
|
|
1748
|
+
} else {
|
|
1749
|
+
bodyDigestOk = BodyDigest.verify(challenge.digest, input.rawBody);
|
|
1750
|
+
}
|
|
1751
|
+
} catch {
|
|
1664
1752
|
bodyDigestOk = false;
|
|
1665
|
-
} else {
|
|
1666
|
-
bodyDigestOk = BodyDigest.verify(challenge.digest, input.rawBody);
|
|
1667
1753
|
}
|
|
1668
|
-
} catch {
|
|
1669
|
-
bodyDigestOk = false;
|
|
1670
1754
|
}
|
|
1671
1755
|
}
|
|
1672
|
-
|
|
1756
|
+
let replayOk = true;
|
|
1757
|
+
if (challenge?.digest && expiryOk) {
|
|
1758
|
+
const replayKey = `mpp:${challenge.digest}:${challenge.nonce ?? ""}`;
|
|
1759
|
+
const expiresAt = (nowSec + tolerance) * 1e3;
|
|
1760
|
+
if (nonceStore.seen(replayKey, expiresAt)) {
|
|
1761
|
+
replayOk = false;
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
const ok = expiryOk && (bodyDigestOk === null || bodyDigestOk === true) && replayOk;
|
|
1673
1765
|
const errors = [];
|
|
1674
1766
|
if (!expiryOk) errors.push("challenge expired");
|
|
1675
|
-
if (bodyDigestOk === false)
|
|
1767
|
+
if (bodyDigestOk === false) {
|
|
1768
|
+
errors.push(
|
|
1769
|
+
input.rawBody !== void 0 && !challenge?.digest ? "body digest required when rawBody present" : "body digest mismatch"
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
if (!replayOk) errors.push("MPP challenge replay \u2014 already seen within tolerance window");
|
|
1676
1773
|
return {
|
|
1677
1774
|
ok,
|
|
1678
1775
|
expiryOk,
|
|
@@ -1836,14 +1933,32 @@ function readHeader4(headers, name) {
|
|
|
1836
1933
|
import { createHash as createHash3, webcrypto } from "crypto";
|
|
1837
1934
|
async function verifyVIChain(input) {
|
|
1838
1935
|
const errors = [];
|
|
1839
|
-
const tolerance = input.clockSkewSec ??
|
|
1936
|
+
const tolerance = input.clockSkewSec ?? 60;
|
|
1840
1937
|
const now = input.now ? input.now() : Math.floor(Date.now() / 1e3);
|
|
1841
1938
|
const { l1, l2, l3a, l3b } = input.layers;
|
|
1939
|
+
const nonceStore = input.nonceStore ?? defaultNonceStore;
|
|
1940
|
+
if (!l1) {
|
|
1941
|
+
if (!input.allowUnboundChain) {
|
|
1942
|
+
errors.push(
|
|
1943
|
+
"L1 missing \u2014 chain root unbound (set allowUnboundChain + expectedL2Key to override)"
|
|
1944
|
+
);
|
|
1945
|
+
} else if (!input.expectedL2Key) {
|
|
1946
|
+
errors.push("allowUnboundChain set but expectedL2Key missing");
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1842
1949
|
const l1SigOk = l1 ? await input.verifySignature(l1, null) : null;
|
|
1843
1950
|
if (l1 && !l1SigOk) errors.push("L1 signature invalid");
|
|
1844
1951
|
const l1Cnf = extractCnfJwk(l1?.payload);
|
|
1845
|
-
const
|
|
1952
|
+
const l2ExpectedKey = l1Cnf ?? input.expectedL2Key ?? null;
|
|
1953
|
+
const l2SigOk = await input.verifySignature(l2, l2ExpectedKey);
|
|
1846
1954
|
if (!l2SigOk) errors.push("L2 signature invalid");
|
|
1955
|
+
if (l2SigOk) {
|
|
1956
|
+
const replayKey = `vi:l2:${l2.compact}`;
|
|
1957
|
+
const expiresAt = now * 1e3 + tolerance * 1e3;
|
|
1958
|
+
if (nonceStore.seen(replayKey, expiresAt)) {
|
|
1959
|
+
errors.push("L2 signature replay \u2014 already seen within tolerance window");
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1847
1962
|
const l2Cnf = extractCnfJwk(l2.payload);
|
|
1848
1963
|
const l3aSigOk = l3a ? await input.verifySignature(l3a, l2Cnf ?? null) : null;
|
|
1849
1964
|
if (l3a && !l3aSigOk) errors.push("L3a signature invalid");
|
|
@@ -1887,7 +2002,10 @@ async function verifyVIChain(input) {
|
|
|
1887
2002
|
}
|
|
1888
2003
|
}
|
|
1889
2004
|
const expiryOk = checkExpiryAcross([l1, l2, l3a, l3b], tolerance, now, errors);
|
|
1890
|
-
const
|
|
2005
|
+
const noUnboundChainOrReplayErrors = !errors.some(
|
|
2006
|
+
(e) => e.startsWith("L1 missing") || e.startsWith("allowUnboundChain set") || e.startsWith("L2 signature replay")
|
|
2007
|
+
);
|
|
2008
|
+
const ok = l1SigOk !== false && l2SigOk && l3aSigOk !== false && l3bSigOk !== false && l1BindsL2 && l2BindsL3 && l3aL3bTxnIdMatch !== false && checkoutHashOk !== false && expiryOk && noUnboundChainOrReplayErrors;
|
|
1891
2009
|
return {
|
|
1892
2010
|
ok,
|
|
1893
2011
|
checks: {
|