@orangecheck/agent-core 2.1.0 → 2.3.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 +41 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +41 -33
- package/dist/index.mjs.map +1 -1
- package/dist/scope.js +4 -1
- package/dist/scope.js.map +1 -1
- package/dist/scope.mjs +4 -1
- 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/scope.test.ts +25 -0
- package/src/scope.ts +3 -0
- package/src/verify.ts +61 -49
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,9 @@ var REGISTERED_SCOPES = {
|
|
|
15
15
|
"nostr:publish": { keys: ["kind", "relay", "max_bytes"] },
|
|
16
16
|
"http:request": { keys: ["origin", "method", "max_rps", "max_bytes_out"] },
|
|
17
17
|
"ln:send": { keys: ["max_sats", "node", "max_fee_sats"] },
|
|
18
|
-
"mcp:invoke": { keys: ["server", "tool", "max_invocations"] }
|
|
18
|
+
"mcp:invoke": { keys: ["server", "tool", "max_invocations"] },
|
|
19
|
+
// oc-pledge-protocol SPEC §7.3.
|
|
20
|
+
"pledge:create": { keys: ["max_bond_sats", "mechanism", "counterparty"] }
|
|
19
21
|
};
|
|
20
22
|
var NUMERIC_KEYS = /* @__PURE__ */ new Set([
|
|
21
23
|
"max_bytes",
|
|
@@ -26,6 +28,7 @@ var NUMERIC_KEYS = /* @__PURE__ */ new Set([
|
|
|
26
28
|
"max_sats",
|
|
27
29
|
"max_fee_sats",
|
|
28
30
|
"max_invocations",
|
|
31
|
+
"max_bond_sats",
|
|
29
32
|
"kind"
|
|
30
33
|
]);
|
|
31
34
|
var IDENT_RE = /^[a-z][a-z0-9_]*$/;
|
|
@@ -635,6 +638,12 @@ async function verifyAction(input) {
|
|
|
635
638
|
"verifyAction requires `revocations` (fetch kind-30085 by #delegation for every link in the chain) or an explicit skipRevocationCheck:true"
|
|
636
639
|
);
|
|
637
640
|
}
|
|
641
|
+
let actionAnchor;
|
|
642
|
+
try {
|
|
643
|
+
actionAnchor = await verifiedAnchorHeight(a, input);
|
|
644
|
+
} catch (e) {
|
|
645
|
+
return err("E_MALFORMED", `anchor verifier threw: ${e.message}`);
|
|
646
|
+
}
|
|
638
647
|
if (input.revocations && input.revocations.length > 0) {
|
|
639
648
|
const allLinks = [rootHydrated, ...hydratedChain];
|
|
640
649
|
for (const link of allLinks) {
|
|
@@ -647,9 +656,13 @@ async function verifyAction(input) {
|
|
|
647
656
|
skipSignatureVerification: input.skipSignatureVerification
|
|
648
657
|
});
|
|
649
658
|
if (!rr.ok) continue;
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
659
|
+
let revAnchor;
|
|
660
|
+
try {
|
|
661
|
+
revAnchor = await verifiedAnchorHeight(rev, input);
|
|
662
|
+
} catch (e) {
|
|
663
|
+
return err("E_MALFORMED", `anchor verifier threw: ${e.message}`);
|
|
664
|
+
}
|
|
665
|
+
if (revocationPrecedes(rev, revAnchor, a, actionAnchor)) {
|
|
653
666
|
return err("E_REVOKED", `chain link ${link.id} was revoked by ${rev.id} before action was signed`);
|
|
654
667
|
}
|
|
655
668
|
}
|
|
@@ -672,14 +685,7 @@ async function verifyAction(input) {
|
|
|
672
685
|
if (h === null || hash === null) {
|
|
673
686
|
return err("E_MALFORMED", "confirmed OTS proof missing block_height or block_hash");
|
|
674
687
|
}
|
|
675
|
-
|
|
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
|
-
}
|
|
688
|
+
const verified = actionAnchor !== null;
|
|
683
689
|
anchor = { status: "confirmed", blockHeight: h, blockHash: hash, verified };
|
|
684
690
|
}
|
|
685
691
|
return {
|
|
@@ -749,9 +755,8 @@ async function verifyRevocation(input) {
|
|
|
749
755
|
return err("E_DELEGATION_MISMATCH", `revocation.delegation_id (${env.delegation_id}) != delegation.id (${d.id})`);
|
|
750
756
|
}
|
|
751
757
|
const holders = d.revocation?.holders ?? ["principal"];
|
|
752
|
-
const holderAddrs = /* @__PURE__ */ new Set();
|
|
753
|
-
if (holders.includes("
|
|
754
|
-
if (holders.includes("agent")) holderAddrs.add(d.agent.address);
|
|
758
|
+
const holderAddrs = /* @__PURE__ */ new Set([d.principal.address]);
|
|
759
|
+
if (Array.isArray(holders) && holders.includes("agent")) holderAddrs.add(d.agent.address);
|
|
755
760
|
if (!holderAddrs.has(env.signer.address)) {
|
|
756
761
|
return err("E_REVOKER_UNAUTHORIZED", `revocation signer ${env.signer.address} not in delegation holders`);
|
|
757
762
|
}
|
|
@@ -951,25 +956,17 @@ async function verifySubdelegation(input) {
|
|
|
951
956
|
}
|
|
952
957
|
return r;
|
|
953
958
|
}
|
|
954
|
-
function
|
|
955
|
-
if (
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
return
|
|
959
|
+
async function verifiedAnchorHeight(env, input) {
|
|
960
|
+
if (env.ots?.status !== "confirmed" || !input.verifyOtsAnchor) return null;
|
|
961
|
+
const h = input.resolveAnchorBlockHeight ? input.resolveAnchorBlockHeight(env) : env.ots.block_height;
|
|
962
|
+
const hash = env.ots.block_hash;
|
|
963
|
+
if (h === null || h === void 0 || !Number.isInteger(h) || !hash) return null;
|
|
964
|
+
return await input.verifyOtsAnchor(env.ots.proof, h, hash, env.id) ? h : null;
|
|
960
965
|
}
|
|
961
|
-
function
|
|
962
|
-
if (
|
|
963
|
-
|
|
964
|
-
|
|
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;
|
|
966
|
+
function revocationPrecedes(rev, revAnchor, action, actionAnchor) {
|
|
967
|
+
if (revAnchor !== null && actionAnchor !== null) return revAnchor <= actionAnchor;
|
|
968
|
+
if (actionAnchor === null && rev.ots?.status === "confirmed") return true;
|
|
969
|
+
return new Date(rev.signed_at).getTime() <= new Date(action.signed_at).getTime();
|
|
973
970
|
}
|
|
974
971
|
function err(code, message) {
|
|
975
972
|
return { ok: false, code, message };
|
|
@@ -1119,6 +1116,17 @@ async function verifyFederationRevocation(input) {
|
|
|
1119
1116
|
return fail("E_MALFORMED", "reason must be a string \u2264128 bytes");
|
|
1120
1117
|
}
|
|
1121
1118
|
if (!ISO_UTC.test(env.signed_at)) return fail("E_MALFORMED", "signed_at must be ISO 8601 UTC");
|
|
1119
|
+
const d = input.delegation;
|
|
1120
|
+
if (!d || !HEX64.test(d.id ?? "")) return fail("E_MALFORMED", "the revoked delegation is required");
|
|
1121
|
+
if (env.delegation_id !== d.id) {
|
|
1122
|
+
return fail("E_DELEGATION_MISMATCH", `revocation.delegation_id (${env.delegation_id}) != delegation.id (${d.id})`);
|
|
1123
|
+
}
|
|
1124
|
+
if (d.principal?.alg !== "federation" || env.signer?.descriptor_id !== d.principal.descriptor_id) {
|
|
1125
|
+
return fail(
|
|
1126
|
+
"E_REVOKER_UNAUTHORIZED",
|
|
1127
|
+
`revoking federation (${env.signer?.descriptor_id}) is not the delegation's principal`
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1122
1130
|
const canonInput = {
|
|
1123
1131
|
address: `federation:${env.signer?.descriptor_id ?? ""}`,
|
|
1124
1132
|
delegation_id: env.delegation_id,
|