@orangecheck/agent-core 2.6.0 → 2.7.1
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 +4 -2
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +52 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +50 -11
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.mts +9 -1
- package/dist/types.d.ts +9 -1
- package/dist/types.js.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
- package/src/federation.test.ts +3 -3
- package/src/federation.ts +3 -8
- package/src/index.ts +4 -0
- package/src/live-time.test.ts +151 -0
- package/src/revocation-authority.test.ts +32 -28
- package/src/revocation-failclosed.test.ts +1 -1
- package/src/test-vectors.test.ts +43 -8
- package/src/types.ts +9 -0
- package/src/verify.ts +108 -7
package/dist/index.mjs
CHANGED
|
@@ -410,6 +410,7 @@ function hasPrivateScopes(envelope) {
|
|
|
410
410
|
|
|
411
411
|
// src/verify.ts
|
|
412
412
|
var DEFAULT_MAX_CHAIN_DEPTH = 5;
|
|
413
|
+
var DEFAULT_MAX_SKEW_MS = 12e4;
|
|
413
414
|
var AgentError = class extends Error {
|
|
414
415
|
constructor(code, message) {
|
|
415
416
|
super(message);
|
|
@@ -544,6 +545,12 @@ async function verifyDelegation(input) {
|
|
|
544
545
|
};
|
|
545
546
|
}
|
|
546
547
|
async function verifyAction(input) {
|
|
548
|
+
return verifyActionAt(input, input.now ?? /* @__PURE__ */ new Date());
|
|
549
|
+
}
|
|
550
|
+
async function verifyActionAsOfSignedAt(input) {
|
|
551
|
+
return verifyActionAt(input, null);
|
|
552
|
+
}
|
|
553
|
+
async function verifyActionAt(input, now) {
|
|
547
554
|
const a = input.action;
|
|
548
555
|
const d = input.delegation;
|
|
549
556
|
const chain = input.subdelegationChain ?? [];
|
|
@@ -621,6 +628,17 @@ async function verifyAction(input) {
|
|
|
621
628
|
if (signed < issued || signed >= expires) {
|
|
622
629
|
return err("E_OUT_OF_WINDOW", `action.signed_at ${a.signed_at} is outside leaf window [${leaf.issued_at}, ${leaf.expires_at})`);
|
|
623
630
|
}
|
|
631
|
+
if (now) {
|
|
632
|
+
const t = now.getTime();
|
|
633
|
+
for (const link of [rootHydrated, ...hydratedChain]) {
|
|
634
|
+
if (t < new Date(link.issued_at).getTime()) {
|
|
635
|
+
return err("E_NOT_YET_VALID", `${link.id} is not valid until ${link.issued_at}`);
|
|
636
|
+
}
|
|
637
|
+
if (t >= new Date(link.expires_at).getTime()) {
|
|
638
|
+
return err("E_EXPIRED", `${link.id} expired at ${link.expires_at}`);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
624
642
|
if (!leaf.scopes) {
|
|
625
643
|
return err("E_SCOPES_NEITHER_PROVIDED", "leaf has no plaintext scopes after hydration");
|
|
626
644
|
}
|
|
@@ -669,9 +687,21 @@ async function verifyAction(input) {
|
|
|
669
687
|
if (revocationPrecedes(rev, revAnchor, a, actionAnchor)) {
|
|
670
688
|
return err("E_REVOKED", `chain link ${link.id} was revoked by ${rev.id} before action was signed`);
|
|
671
689
|
}
|
|
690
|
+
if (now && (revAnchor !== null || new Date(rev.signed_at).getTime() <= now.getTime())) {
|
|
691
|
+
return err("E_REVOKED", `chain link ${link.id} was revoked by ${rev.id}`);
|
|
692
|
+
}
|
|
672
693
|
}
|
|
673
694
|
}
|
|
674
695
|
}
|
|
696
|
+
if (now) {
|
|
697
|
+
const maxSkew = input.maxSkewMs ?? DEFAULT_MAX_SKEW_MS;
|
|
698
|
+
if (Math.abs(now.getTime() - signed) > maxSkew) {
|
|
699
|
+
return err(
|
|
700
|
+
"E_STALE",
|
|
701
|
+
`action.signed_at ${a.signed_at} is more than ${maxSkew} ms from the time of verification ${now.toISOString()}`
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
675
705
|
if (input.content) {
|
|
676
706
|
const actualHash = "sha256:" + hexEncode(sha256(input.content));
|
|
677
707
|
if (actualHash !== a.content.hash) {
|
|
@@ -699,7 +729,20 @@ async function verifyAction(input) {
|
|
|
699
729
|
delegation: rootHydrated,
|
|
700
730
|
chain: hydratedChain,
|
|
701
731
|
scopeExercised: exercised,
|
|
702
|
-
anchor
|
|
732
|
+
anchor,
|
|
733
|
+
asOf: now ? { basis: "now", now: now.toISOString() } : { basis: "signed_at", signedAt: a.signed_at, anchored: actionAnchor !== null }
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function createReplayGuard(maxSkewMs = DEFAULT_MAX_SKEW_MS) {
|
|
737
|
+
const keepUntil = /* @__PURE__ */ new Map();
|
|
738
|
+
return {
|
|
739
|
+
firstUse(action, now = /* @__PURE__ */ new Date()) {
|
|
740
|
+
const t = now.getTime();
|
|
741
|
+
for (const [id, until] of keepUntil) if (until <= t) keepUntil.delete(id);
|
|
742
|
+
if (keepUntil.has(action.id)) return false;
|
|
743
|
+
keepUntil.set(action.id, new Date(action.signed_at).getTime() + maxSkewMs);
|
|
744
|
+
return true;
|
|
745
|
+
}
|
|
703
746
|
};
|
|
704
747
|
}
|
|
705
748
|
async function hydrateSubdelegationScopes(sub, input) {
|
|
@@ -757,11 +800,11 @@ async function verifyRevocation(input) {
|
|
|
757
800
|
if (env.delegation_id !== d.id) {
|
|
758
801
|
return err("E_DELEGATION_MISMATCH", `revocation.delegation_id (${env.delegation_id}) != delegation.id (${d.id})`);
|
|
759
802
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
803
|
+
if (env.signer.address !== d.principal.address && env.signer.address !== d.agent.address) {
|
|
804
|
+
return err(
|
|
805
|
+
"E_REVOKER_UNAUTHORIZED",
|
|
806
|
+
`revocation signer ${env.signer.address} is neither the principal nor the agent`
|
|
807
|
+
);
|
|
765
808
|
}
|
|
766
809
|
const canonInput = {
|
|
767
810
|
address: env.signer.address,
|
|
@@ -1144,10 +1187,6 @@ async function verifyRevocationOf(d, rev, input) {
|
|
|
1144
1187
|
});
|
|
1145
1188
|
}
|
|
1146
1189
|
const v1 = rev;
|
|
1147
|
-
const holders = d.revocation?.holders ?? ["principal"];
|
|
1148
|
-
if (!Array.isArray(holders) || !holders.includes("agent")) {
|
|
1149
|
-
return fail("E_REVOKER_UNAUTHORIZED", "only the federation may revoke this delegation");
|
|
1150
|
-
}
|
|
1151
1190
|
if (v1.kind !== "agent-revocation" || v1.signer?.address !== d.agent.address) {
|
|
1152
1191
|
return fail("E_REVOKER_UNAUTHORIZED", "a single-address revocation must be signed by the agent");
|
|
1153
1192
|
}
|
|
@@ -1239,6 +1278,6 @@ function assertScopeGranted(delegation, scopeExercised, fnName) {
|
|
|
1239
1278
|
}
|
|
1240
1279
|
}
|
|
1241
1280
|
|
|
1242
|
-
export { AgentError, DEFAULT_MAX_CHAIN_DEPTH, ENVELOPE_VERSION, REGISTERED_SCOPES, ScopeNotGrantedError, ScopeParseError, actionCanonicalBytes, actionCanonicalMessage, assertScopeGranted, canonicalActionBytes, canonicalDelegationBytes, canonicalRevocationBytes, canonicalizeAction, canonicalizeDelegation, canonicalizeRevocation, canonicalizeScope, canonicalizeScopeString, canonicalizeScopes, computeActionId, computeDelegationId, computeFederationDescriptorId, computeRevocationId, computeSubdelegationId, decodeScopesPayload, delegationCanonicalBytes, delegationCanonicalMessage, encodeScopesPayload, federationDescriptorCanonicalMessage, hasPrivateScopes, isSubScope, parseAndCanonicalizeScopes, parseScope, revocationCanonicalBytes, revocationCanonicalMessage, sealScopes, sha256Hex, subdelegationCanonicalBytes, subdelegationCanonicalMessage, unsealScopes, validateScope, verifyAction, verifyDelegation, verifyFederationDelegation, verifyFederationRevocation, verifyRevocation, verifySubdelegation };
|
|
1281
|
+
export { AgentError, DEFAULT_MAX_CHAIN_DEPTH, DEFAULT_MAX_SKEW_MS, ENVELOPE_VERSION, REGISTERED_SCOPES, ScopeNotGrantedError, ScopeParseError, actionCanonicalBytes, actionCanonicalMessage, assertScopeGranted, canonicalActionBytes, canonicalDelegationBytes, canonicalRevocationBytes, canonicalizeAction, canonicalizeDelegation, canonicalizeRevocation, canonicalizeScope, canonicalizeScopeString, canonicalizeScopes, computeActionId, computeDelegationId, computeFederationDescriptorId, computeRevocationId, computeSubdelegationId, createReplayGuard, decodeScopesPayload, delegationCanonicalBytes, delegationCanonicalMessage, encodeScopesPayload, federationDescriptorCanonicalMessage, hasPrivateScopes, isSubScope, parseAndCanonicalizeScopes, parseScope, revocationCanonicalBytes, revocationCanonicalMessage, sealScopes, sha256Hex, subdelegationCanonicalBytes, subdelegationCanonicalMessage, unsealScopes, validateScope, verifyAction, verifyActionAsOfSignedAt, verifyDelegation, verifyFederationDelegation, verifyFederationRevocation, verifyRevocation, verifySubdelegation };
|
|
1243
1282
|
//# sourceMappingURL=index.mjs.map
|
|
1244
1283
|
//# sourceMappingURL=index.mjs.map
|