@orangecheck/agent-core 2.7.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 +1 -1
- package/dist/index.js +5 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/federation.test.ts +3 -3
- package/src/federation.ts +3 -8
- package/src/revocation-authority.test.ts +17 -15
- package/src/verify.ts +8 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orangecheck/agent-core",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"description": "OC Agent canonical messages, envelope formats (delegation/action/revocation), scope grammar, and verification. See https://github.com/orangecheck/oc-agent-protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bitcoin",
|
package/src/federation.test.ts
CHANGED
|
@@ -245,7 +245,7 @@ d('federation delegation revocation check', () => {
|
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
it('honours
|
|
248
|
+
it('honours the agent’s own revocation whatever holders says', async () => {
|
|
249
249
|
const dv = await load('v19-federation-delegation-3of5-valid.json');
|
|
250
250
|
const del = dv.expected.envelope as FederationDelegationEnvelope;
|
|
251
251
|
const principalOnly = { ...del, revocation: { holders: ['principal' as const], ref: null } };
|
|
@@ -253,12 +253,12 @@ d('federation delegation revocation check', () => {
|
|
|
253
253
|
...del,
|
|
254
254
|
revocation: { holders: ['principal' as const, 'agent' as const], ref: null },
|
|
255
255
|
};
|
|
256
|
-
const
|
|
256
|
+
const revokedToo = await verifyFederationDelegation({
|
|
257
257
|
envelope: principalOnly,
|
|
258
258
|
revocations: [agentRevocation(principalOnly)],
|
|
259
259
|
...base,
|
|
260
260
|
});
|
|
261
|
-
expect(
|
|
261
|
+
expect(revokedToo.ok === false && revokedToo.code).toBe('E_REVOKED');
|
|
262
262
|
const revoked = await verifyFederationDelegation({
|
|
263
263
|
envelope: withAgent,
|
|
264
264
|
revocations: [agentRevocation(withAgent)],
|
package/src/federation.ts
CHANGED
|
@@ -230,7 +230,7 @@ export interface VerifyFederationDelegationInput extends VerifyFederationBase {
|
|
|
230
230
|
envelope: FederationDelegationEnvelope;
|
|
231
231
|
/**
|
|
232
232
|
* Revocations to check (kind-30085 by `#t` with the delegation id, SPEC §9.4): federation revocations,
|
|
233
|
-
* and agent
|
|
233
|
+
* and the agent's own revocations.
|
|
234
234
|
* Required unless `skipRevocationCheck` states that revocation is not checked.
|
|
235
235
|
*/
|
|
236
236
|
revocations?: Array<FederationRevocationEnvelope | RevocationEnvelope>;
|
|
@@ -316,9 +316,8 @@ export async function verifyFederationDelegation(
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
/**
|
|
319
|
-
* FEDERATION.md §4: the federation (M-of-N) may always revoke
|
|
320
|
-
*
|
|
321
|
-
* includes "agent".
|
|
319
|
+
* FEDERATION.md §4: the federation (M-of-N) may always revoke, and so may the
|
|
320
|
+
* agent with its own BIP-322 signature, whatever `revocation.holders` says.
|
|
322
321
|
*/
|
|
323
322
|
async function verifyRevocationOf(
|
|
324
323
|
d: FederationDelegationEnvelope,
|
|
@@ -334,10 +333,6 @@ async function verifyRevocationOf(
|
|
|
334
333
|
});
|
|
335
334
|
}
|
|
336
335
|
const v1 = rev as RevocationEnvelope;
|
|
337
|
-
const holders = d.revocation?.holders ?? ['principal'];
|
|
338
|
-
if (!Array.isArray(holders) || !holders.includes('agent')) {
|
|
339
|
-
return fail('E_REVOKER_UNAUTHORIZED', 'only the federation may revoke this delegation');
|
|
340
|
-
}
|
|
341
336
|
if (v1.kind !== 'agent-revocation' || v1.signer?.address !== d.agent.address) {
|
|
342
337
|
return fail('E_REVOKER_UNAUTHORIZED', 'a single-address revocation must be signed by the agent');
|
|
343
338
|
}
|
|
@@ -117,22 +117,24 @@ describe('revocation authority always includes the principal', () => {
|
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
delegation
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
120
|
+
// A copy of the delegation presented with holders ["principal"] has the same
|
|
121
|
+
// id and signature as one with the agent listed, so it must not undo the
|
|
122
|
+
// agent's own revocation (SPEC §9.5).
|
|
123
|
+
for (const holders of [['principal', 'agent'], ['principal'], [], undefined]) {
|
|
124
|
+
it(`the agent's revocation is honoured with holders=${JSON.stringify(holders)}`, async () => {
|
|
125
|
+
const d = delegation(holders);
|
|
126
|
+
const rev = revocation(d, AGENT, '2026-04-23T00:00:00Z');
|
|
127
|
+
const rr = await verifyRevocation({ envelope: rev, delegation: d, skipSignatureVerification: true });
|
|
128
|
+
expect(rr.ok).toBe(true);
|
|
129
|
+
const dr = await verifyDelegation({
|
|
130
|
+
envelope: d,
|
|
131
|
+
revocations: [rev],
|
|
132
|
+
skipSignatureVerification: true,
|
|
133
|
+
now: AT,
|
|
134
|
+
});
|
|
135
|
+
expect(dr.ok === false && dr.code).toBe('E_REVOKED');
|
|
133
136
|
});
|
|
134
|
-
|
|
135
|
-
});
|
|
137
|
+
}
|
|
136
138
|
|
|
137
139
|
it('a third party is never an authorised revoker', async () => {
|
|
138
140
|
const d = delegation(['principal', 'agent']);
|
package/src/verify.ts
CHANGED
|
@@ -717,13 +717,14 @@ export async function verifyRevocation(input: VerifyRevocationInput): Promise<Ve
|
|
|
717
717
|
return err('E_DELEGATION_MISMATCH', `revocation.delegation_id (${env.delegation_id}) != delegation.id (${d.id})`);
|
|
718
718
|
}
|
|
719
719
|
|
|
720
|
-
// The principal may always revoke (SPEC §9.5).
|
|
721
|
-
//
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
720
|
+
// The principal and the agent may always revoke (SPEC §9.5). Revoking only
|
|
721
|
+
// removes authority, and `revocation.holders` is outside the delegation's
|
|
722
|
+
// signature, so no copy of it decides who may.
|
|
723
|
+
if (env.signer.address !== d.principal.address && env.signer.address !== d.agent.address) {
|
|
724
|
+
return err(
|
|
725
|
+
'E_REVOKER_UNAUTHORIZED',
|
|
726
|
+
`revocation signer ${env.signer.address} is neither the principal nor the agent`
|
|
727
|
+
);
|
|
727
728
|
}
|
|
728
729
|
|
|
729
730
|
const canonInput = {
|