@orangecheck/agent-core 2.1.0 → 2.2.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/index.mjs CHANGED
@@ -635,6 +635,12 @@ async function verifyAction(input) {
635
635
  "verifyAction requires `revocations` (fetch kind-30085 by #delegation for every link in the chain) or an explicit skipRevocationCheck:true"
636
636
  );
637
637
  }
638
+ let actionAnchor;
639
+ try {
640
+ actionAnchor = await verifiedAnchorHeight(a, input);
641
+ } catch (e) {
642
+ return err("E_MALFORMED", `anchor verifier threw: ${e.message}`);
643
+ }
638
644
  if (input.revocations && input.revocations.length > 0) {
639
645
  const allLinks = [rootHydrated, ...hydratedChain];
640
646
  for (const link of allLinks) {
@@ -647,9 +653,13 @@ async function verifyAction(input) {
647
653
  skipSignatureVerification: input.skipSignatureVerification
648
654
  });
649
655
  if (!rr.ok) continue;
650
- const effective = effectiveRevocationTime(rev, input.resolveAnchorBlockHeight);
651
- const actionTime = actionEffectiveTime(a, input.resolveAnchorBlockHeight);
652
- if (compareTimes(effective, actionTime) <= 0) {
656
+ let revAnchor;
657
+ try {
658
+ revAnchor = await verifiedAnchorHeight(rev, input);
659
+ } catch (e) {
660
+ return err("E_MALFORMED", `anchor verifier threw: ${e.message}`);
661
+ }
662
+ if (revocationPrecedes(rev, revAnchor, a, actionAnchor)) {
653
663
  return err("E_REVOKED", `chain link ${link.id} was revoked by ${rev.id} before action was signed`);
654
664
  }
655
665
  }
@@ -672,14 +682,7 @@ async function verifyAction(input) {
672
682
  if (h === null || hash === null) {
673
683
  return err("E_MALFORMED", "confirmed OTS proof missing block_height or block_hash");
674
684
  }
675
- let verified = false;
676
- if (input.verifyOtsAnchor) {
677
- try {
678
- verified = await input.verifyOtsAnchor(a.ots.proof, h, hash);
679
- } catch (e) {
680
- return err("E_MALFORMED", `anchor verifier threw: ${e.message}`);
681
- }
682
- }
685
+ const verified = actionAnchor !== null;
683
686
  anchor = { status: "confirmed", blockHeight: h, blockHash: hash, verified };
684
687
  }
685
688
  return {
@@ -749,9 +752,8 @@ async function verifyRevocation(input) {
749
752
  return err("E_DELEGATION_MISMATCH", `revocation.delegation_id (${env.delegation_id}) != delegation.id (${d.id})`);
750
753
  }
751
754
  const holders = d.revocation?.holders ?? ["principal"];
752
- const holderAddrs = /* @__PURE__ */ new Set();
753
- if (holders.includes("principal")) holderAddrs.add(d.principal.address);
754
- if (holders.includes("agent")) holderAddrs.add(d.agent.address);
755
+ const holderAddrs = /* @__PURE__ */ new Set([d.principal.address]);
756
+ if (Array.isArray(holders) && holders.includes("agent")) holderAddrs.add(d.agent.address);
755
757
  if (!holderAddrs.has(env.signer.address)) {
756
758
  return err("E_REVOKER_UNAUTHORIZED", `revocation signer ${env.signer.address} not in delegation holders`);
757
759
  }
@@ -951,25 +953,17 @@ async function verifySubdelegation(input) {
951
953
  }
952
954
  return r;
953
955
  }
954
- function actionEffectiveTime(a, resolve) {
955
- if (a.ots?.status === "confirmed") {
956
- const h = resolve ? resolve(a) : a.ots.block_height;
957
- if (h !== null && h !== void 0) return { kind: "anchor", blockHeight: h };
958
- }
959
- return { kind: "signed", ms: new Date(a.signed_at).getTime() };
956
+ async function verifiedAnchorHeight(env, input) {
957
+ if (env.ots?.status !== "confirmed" || !input.verifyOtsAnchor) return null;
958
+ const h = input.resolveAnchorBlockHeight ? input.resolveAnchorBlockHeight(env) : env.ots.block_height;
959
+ const hash = env.ots.block_hash;
960
+ if (h === null || h === void 0 || !Number.isInteger(h) || !hash) return null;
961
+ return await input.verifyOtsAnchor(env.ots.proof, h, hash, env.id) ? h : null;
960
962
  }
961
- function effectiveRevocationTime(r, resolve) {
962
- if (r.ots?.status === "confirmed") {
963
- const h = resolve ? resolve(r) : r.ots.block_height;
964
- if (h !== null && h !== void 0) return { kind: "anchor", blockHeight: h };
965
- }
966
- return { kind: "signed", ms: new Date(r.signed_at).getTime() };
967
- }
968
- function compareTimes(a, b) {
969
- if (a.kind === "anchor" && b.kind === "anchor") return a.blockHeight - b.blockHeight;
970
- if (a.kind === "anchor") return -1;
971
- if (b.kind === "anchor") return 1;
972
- return a.ms - b.ms;
963
+ function revocationPrecedes(rev, revAnchor, action, actionAnchor) {
964
+ if (revAnchor !== null && actionAnchor !== null) return revAnchor <= actionAnchor;
965
+ if (actionAnchor === null && rev.ots?.status === "confirmed") return true;
966
+ return new Date(rev.signed_at).getTime() <= new Date(action.signed_at).getTime();
973
967
  }
974
968
  function err(code, message) {
975
969
  return { ok: false, code, message };
@@ -1119,6 +1113,17 @@ async function verifyFederationRevocation(input) {
1119
1113
  return fail("E_MALFORMED", "reason must be a string \u2264128 bytes");
1120
1114
  }
1121
1115
  if (!ISO_UTC.test(env.signed_at)) return fail("E_MALFORMED", "signed_at must be ISO 8601 UTC");
1116
+ const d = input.delegation;
1117
+ if (!d || !HEX64.test(d.id ?? "")) return fail("E_MALFORMED", "the revoked delegation is required");
1118
+ if (env.delegation_id !== d.id) {
1119
+ return fail("E_DELEGATION_MISMATCH", `revocation.delegation_id (${env.delegation_id}) != delegation.id (${d.id})`);
1120
+ }
1121
+ if (d.principal?.alg !== "federation" || env.signer?.descriptor_id !== d.principal.descriptor_id) {
1122
+ return fail(
1123
+ "E_REVOKER_UNAUTHORIZED",
1124
+ `revoking federation (${env.signer?.descriptor_id}) is not the delegation's principal`
1125
+ );
1126
+ }
1122
1127
  const canonInput = {
1123
1128
  address: `federation:${env.signer?.descriptor_id ?? ""}`,
1124
1129
  delegation_id: env.delegation_id,