@orangecheck/agent-core 2.0.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/README.md +3 -1
- package/dist/canonical.js.map +1 -1
- package/dist/canonical.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +44 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -34
- package/dist/index.mjs.map +1 -1
- package/dist/scope.js +7 -2
- package/dist/scope.js.map +1 -1
- package/dist/scope.mjs +7 -2
- package/dist/scope.mjs.map +1 -1
- package/package.json +1 -1
- package/src/federation.test.ts +26 -0
- package/src/federation.ts +14 -0
- package/src/revocation-authority.test.ts +258 -0
- package/src/revocation-failclosed.test.ts +19 -8
- package/src/scope.test.ts +44 -0
- package/src/scope.ts +17 -2
- package/src/verify.ts +61 -49
package/dist/index.mjs
CHANGED
|
@@ -223,10 +223,15 @@ function rangeSubset(ex, g) {
|
|
|
223
223
|
if (!exRange || !gRange) return false;
|
|
224
224
|
return gRange.lo <= exRange.lo && exRange.hi <= gRange.hi;
|
|
225
225
|
}
|
|
226
|
+
function parseDecimalInteger(value) {
|
|
227
|
+
if (!/^-?\d+$/.test(value)) return null;
|
|
228
|
+
const n = Number(value);
|
|
229
|
+
return Number.isSafeInteger(n) ? n : null;
|
|
230
|
+
}
|
|
226
231
|
function opToRange(c) {
|
|
227
232
|
if (c.value === void 0) return null;
|
|
228
|
-
const n =
|
|
229
|
-
if (
|
|
233
|
+
const n = parseDecimalInteger(c.value);
|
|
234
|
+
if (n === null) return null;
|
|
230
235
|
switch (c.op) {
|
|
231
236
|
case "=":
|
|
232
237
|
return { lo: n, hi: n };
|
|
@@ -630,6 +635,12 @@ async function verifyAction(input) {
|
|
|
630
635
|
"verifyAction requires `revocations` (fetch kind-30085 by #delegation for every link in the chain) or an explicit skipRevocationCheck:true"
|
|
631
636
|
);
|
|
632
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
|
+
}
|
|
633
644
|
if (input.revocations && input.revocations.length > 0) {
|
|
634
645
|
const allLinks = [rootHydrated, ...hydratedChain];
|
|
635
646
|
for (const link of allLinks) {
|
|
@@ -642,9 +653,13 @@ async function verifyAction(input) {
|
|
|
642
653
|
skipSignatureVerification: input.skipSignatureVerification
|
|
643
654
|
});
|
|
644
655
|
if (!rr.ok) continue;
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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)) {
|
|
648
663
|
return err("E_REVOKED", `chain link ${link.id} was revoked by ${rev.id} before action was signed`);
|
|
649
664
|
}
|
|
650
665
|
}
|
|
@@ -667,14 +682,7 @@ async function verifyAction(input) {
|
|
|
667
682
|
if (h === null || hash === null) {
|
|
668
683
|
return err("E_MALFORMED", "confirmed OTS proof missing block_height or block_hash");
|
|
669
684
|
}
|
|
670
|
-
|
|
671
|
-
if (input.verifyOtsAnchor) {
|
|
672
|
-
try {
|
|
673
|
-
verified = await input.verifyOtsAnchor(a.ots.proof, h, hash);
|
|
674
|
-
} catch (e) {
|
|
675
|
-
return err("E_MALFORMED", `anchor verifier threw: ${e.message}`);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
685
|
+
const verified = actionAnchor !== null;
|
|
678
686
|
anchor = { status: "confirmed", blockHeight: h, blockHash: hash, verified };
|
|
679
687
|
}
|
|
680
688
|
return {
|
|
@@ -744,9 +752,8 @@ async function verifyRevocation(input) {
|
|
|
744
752
|
return err("E_DELEGATION_MISMATCH", `revocation.delegation_id (${env.delegation_id}) != delegation.id (${d.id})`);
|
|
745
753
|
}
|
|
746
754
|
const holders = d.revocation?.holders ?? ["principal"];
|
|
747
|
-
const holderAddrs = /* @__PURE__ */ new Set();
|
|
748
|
-
if (holders.includes("
|
|
749
|
-
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);
|
|
750
757
|
if (!holderAddrs.has(env.signer.address)) {
|
|
751
758
|
return err("E_REVOKER_UNAUTHORIZED", `revocation signer ${env.signer.address} not in delegation holders`);
|
|
752
759
|
}
|
|
@@ -946,25 +953,17 @@ async function verifySubdelegation(input) {
|
|
|
946
953
|
}
|
|
947
954
|
return r;
|
|
948
955
|
}
|
|
949
|
-
function
|
|
950
|
-
if (
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
return
|
|
955
|
-
}
|
|
956
|
-
function effectiveRevocationTime(r, resolve) {
|
|
957
|
-
if (r.ots?.status === "confirmed") {
|
|
958
|
-
const h = resolve ? resolve(r) : r.ots.block_height;
|
|
959
|
-
if (h !== null && h !== void 0) return { kind: "anchor", blockHeight: h };
|
|
960
|
-
}
|
|
961
|
-
return { kind: "signed", ms: new Date(r.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;
|
|
962
962
|
}
|
|
963
|
-
function
|
|
964
|
-
if (
|
|
965
|
-
if (
|
|
966
|
-
|
|
967
|
-
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();
|
|
968
967
|
}
|
|
969
968
|
function err(code, message) {
|
|
970
969
|
return { ok: false, code, message };
|
|
@@ -1114,6 +1113,17 @@ async function verifyFederationRevocation(input) {
|
|
|
1114
1113
|
return fail("E_MALFORMED", "reason must be a string \u2264128 bytes");
|
|
1115
1114
|
}
|
|
1116
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
|
+
}
|
|
1117
1127
|
const canonInput = {
|
|
1118
1128
|
address: `federation:${env.signer?.descriptor_id ?? ""}`,
|
|
1119
1129
|
delegation_id: env.delegation_id,
|