iso-ucan 0.5.0 → 0.5.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/dist/src/envelope.d.ts +1 -1
- package/dist/src/envelope.d.ts.map +1 -1
- package/dist/src/invocation.d.ts.map +1 -1
- package/dist/src/rpc/receipt.d.ts +2 -2
- package/dist/src/utils.d.ts +15 -0
- package/dist/src/utils.d.ts.map +1 -1
- package/license +9 -0
- package/package.json +13 -13
- package/readme.md +55 -18
- package/src/invocation.js +3 -2
- package/src/utils.js +19 -0
package/dist/src/envelope.d.ts
CHANGED
|
@@ -52,7 +52,7 @@ export function sign(options: EnvelopeSignOptions): Promise<{
|
|
|
52
52
|
* @param {EnvelopeEncodeOptions} options
|
|
53
53
|
*
|
|
54
54
|
*/
|
|
55
|
-
export function encode(options: EnvelopeEncodeOptions): ByteView<(Uint8Array<ArrayBufferLike> | SignaturePayload<unknown>)[]>;
|
|
55
|
+
export function encode(options: EnvelopeEncodeOptions): ByteView<(Uint8Array<ArrayBufferLike> | SignaturePayload<unknown>)[], ArrayBufferLike>;
|
|
56
56
|
/**
|
|
57
57
|
* Decode a UCAN envelope
|
|
58
58
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/envelope.js"],"names":[],"mappings":"AAYA;;;;;;;;GAQG;AACH,6CALG;IAA6B,IAAI,EAAzB,WAAW;IACM,OAAO,EAAxB,OAAO;IACU,OAAO;IAC8B,aAAa,EAAnE,OAAO,sBAAsB,EAAE,aAAa;CACtD,oBAgBA;AAED;;;;GAIG;AACH,8CAFW,UAAU;;;;EAkCpB;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;GAGG;AACH,8BAFW,mBAAmB;;;GAgB7B;AAED;;;;;;GAMG;AACH,gCAHW,qBAAqB,
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/envelope.js"],"names":[],"mappings":"AAYA;;;;;;;;GAQG;AACH,6CALG;IAA6B,IAAI,EAAzB,WAAW;IACM,OAAO,EAAxB,OAAO;IACU,OAAO;IAC8B,aAAa,EAAnE,OAAO,sBAAsB,EAAE,aAAa;CACtD,oBAgBA;AAED;;;;GAIG;AACH,8CAFW,UAAU;;;;EAkCpB;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;;;GAKG;AACH,6CAHW,OAAO,GACL,OAAO,IAAI,iBAAiB,CAIxC;AAED;;;GAGG;AACH,8BAFW,mBAAmB;;;GAgB7B;AAED;;;;;;GAMG;AACH,gCAHW,qBAAqB,0FAS/B;AAED;;;;;;;GAOG;AACH,uBAL2B,IAAI,SAAlB,WAAa,WAEf,qBAAqB,GACnB,gBAAgB,IAAI,CAAC,CAgCjC;AAtKD;;;GAGG;AAEH,cAAc;AACd,sBAAuB,YAAY,CAAA;iCALuK,YAAY;6BAAZ,YAAY;sCAAZ,YAAY;uCAAZ,YAAY;uCAAZ,YAAY;yCAAZ,YAAY;2CAAZ,YAAY;8BACzL,cAAc;2CAD+J,YAAY;qCAAZ,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invocation.d.ts","sourceRoot":"","sources":["../../src/invocation.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"invocation.d.ts","sourceRoot":"","sources":["../../src/invocation.js"],"names":[],"mappings":"AAsLA;;;;GAIG;AACH,sCAHW,OAAO,YAAY,EAAE,iBAAiB,UACtC,UAAU,EAAE,WA6DtB;AAtOD;;;GAGG;AAEH;;GAEG;AACH;IA0BE;;;OAGG;IACH,qBAFW,OAAO,YAAY,EAAE,qBAAqB,uBAgDpD;IAED;;OAEG;IACH,uBAFW,OAAO,YAAY,EAAE,iBAAiB,uBA0DhD;IA9HD;;;;;;OAMG;IACH,sBALW,OAAO,YAAY,EAAE,eAAe,CAAC,KAAK,CAAC,SAC3C,UAAU,OACV,GAAG,eACH,UAAU,EAAE,EAQtB;IAvBD;;OAEG;IACH,aAFU,UAAU,EAAE,CAEX;IAEX;;OAEG;IACH,KAFU,GAAG,CAEV;IAUD,sDAAwB;IACxB,gDAA+B;IAC/B,mCAAkB;CAqHrB;gCAjJ4B,iBAAiB;yBACxB,cAAc"}
|
|
@@ -75,7 +75,7 @@ export function receipt<Result extends z.ZodType, Error extends z.ZodType>(resul
|
|
|
75
75
|
* produces when serialized through `JSON.stringify`) and normalizes to a
|
|
76
76
|
* {@link CID}.
|
|
77
77
|
*/
|
|
78
|
-
export const cidSchema: z.ZodUnion<readonly [z.
|
|
78
|
+
export const cidSchema: z.ZodUnion<readonly [z.ZodInstanceOf<CID<unknown, number, number, import("multiformats").Version>>, z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodPipe<z.ZodObject<{
|
|
79
79
|
'/': z.ZodString;
|
|
80
80
|
}, z.core.$strip>, z.ZodTransform<string, {
|
|
81
81
|
'/': string;
|
|
@@ -100,7 +100,7 @@ export const receiptServerError: z.ZodObject<{
|
|
|
100
100
|
error: z.ZodObject<{
|
|
101
101
|
code: z.ZodLiteral<"SERVER_ERROR">;
|
|
102
102
|
message: z.ZodString;
|
|
103
|
-
cid: z.ZodOptional<z.ZodUnion<readonly [z.
|
|
103
|
+
cid: z.ZodOptional<z.ZodUnion<readonly [z.ZodInstanceOf<CID<unknown, number, number, import("multiformats").Version>>, z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodPipe<z.ZodObject<{
|
|
104
104
|
'/': z.ZodString;
|
|
105
105
|
}, z.core.$strip>, z.ZodTransform<string, {
|
|
106
106
|
'/': string;
|
package/dist/src/utils.d.ts
CHANGED
|
@@ -53,6 +53,21 @@ export function validateIssuerAndSignature(envelope: import("./types.js").Decode
|
|
|
53
53
|
* @param {import('iso-did').Resolver} [didResolver]
|
|
54
54
|
*/
|
|
55
55
|
export function verifySignature(envelope: import("./types.js").DecodedEnvelope<PayloadSpec>, signatureVerifierResolver: import("iso-signatures/verifiers/resolver.js").Resolver, didResolver?: import("iso-did").Resolver): Promise<boolean>;
|
|
56
|
+
/**
|
|
57
|
+
* Check if a command is covered by (equal to or a segment-wise child of) another command.
|
|
58
|
+
*
|
|
59
|
+
* Commands are compared by path segment, not by string prefix: `/crypto` covers
|
|
60
|
+
* `/crypto` and `/crypto/sign` but not `/cryptocurrency`. The command `/` covers
|
|
61
|
+
* every command.
|
|
62
|
+
*
|
|
63
|
+
* Both commands are expected to be valid per {@link assertIsValidCommand}, so
|
|
64
|
+
* `${parent}/` is always a real segment boundary.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} parent - The broader command, e.g. from a delegation.
|
|
67
|
+
* @param {string} child - The command that must be attenuated from `parent`.
|
|
68
|
+
* @returns {boolean}
|
|
69
|
+
*/
|
|
70
|
+
export function commandCovers(parent: string, child: string): boolean;
|
|
56
71
|
/**
|
|
57
72
|
* Asserts that a UCAN command string is syntactically valid.
|
|
58
73
|
* If the command is invalid, it throws a descriptive error.
|
package/dist/src/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.js"],"names":[],"mappings":"AASA;;GAEG;AAEH;;;;;GAKG;AACH,2CAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC;;;EAe3D;AAED,uCAEC;AAED;;;GAGG;AACH,8BAFW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,iCAW3D;AAED;;;;;GAKG;AACH,2CAHW,OAAO,eAAe,EAAE,aAAa,WACrC,OAAO,sBAAsB,EAAE,aAAa,WA+BtD;AAED;;;;;GAKG;AACH,sCAHW,MAAM,GAAG,IAAI,QACb,MAAM,QAchB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,QACN,MAAM,QAMhB;AAED;;;;;GAKG;AACH,qDAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,gBACjD,OAAO,SAAS,EAAE,QAAQ,gBAYpC;AAED;;;;;;GAMG;AACH,0CAJW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,6BACjD,OAAO,sCAAsC,EAAE,QAAQ,gBACvD,OAAO,SAAS,EAAE,QAAQ,oBAwBpC;AAED;;;;;;;;;;;;;GAaG;AACH,8CAJW,MAAM,GAEJ,IAAI,CAuChB;AAED;;;;;;;;;;;;;GAaG;AACH,mCAXW,OAAO,GAEL,IAAI,CAehB;AACD;;;;GAIG;AACH,iCAFW,OAAO,QASjB;AAED;;;;;;GAMG;AACH,iCAJW,OAAO,GAEL,IAAI,CAWhB;AAED;;;;;GAKG;AACH,sCAHW,OAAO,kBAAkB,EAAE,GAAG,gBAC9B,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,iBAQxC;AAED;;;;;;GAMG;AACH,uCAHG;IAAgC,GAAG;IACV,GAAG;CAAC,iBAU/B;AAgED;;GAEG;AACH,qCAFW,OAAO,QASjB;AAED;;;;;;GAMG;AACH,gCAJW,OAAO,GACL,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAKjD;AAnFD,iJAeI;AACJ,4KAAyD;AAEzD,oGAGE;AAEF;;GAEG;AAEH;;GAEG;AACH,mKA4BI;AAEJ,kLAA8C;uBApCjC,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.js"],"names":[],"mappings":"AASA;;GAEG;AAEH;;;;;GAKG;AACH,2CAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC;;;EAe3D;AAED,uCAEC;AAED;;;GAGG;AACH,8BAFW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,iCAW3D;AAED;;;;;GAKG;AACH,2CAHW,OAAO,eAAe,EAAE,aAAa,WACrC,OAAO,sBAAsB,EAAE,aAAa,WA+BtD;AAED;;;;;GAKG;AACH,sCAHW,MAAM,GAAG,IAAI,QACb,MAAM,QAchB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,QACN,MAAM,QAMhB;AAED;;;;;GAKG;AACH,qDAHW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,gBACjD,OAAO,SAAS,EAAE,QAAQ,gBAYpC;AAED;;;;;;GAMG;AACH,0CAJW,OAAO,YAAY,EAAE,eAAe,CAAC,WAAW,CAAC,6BACjD,OAAO,sCAAsC,EAAE,QAAQ,gBACvD,OAAO,SAAS,EAAE,QAAQ,oBAwBpC;AAED;;;;;;;;;;;;;GAaG;AACH,sCAJW,MAAM,SACN,MAAM,GACJ,OAAO,CAKnB;AAED;;;;;;;;;;;;;GAaG;AACH,8CAJW,MAAM,GAEJ,IAAI,CAuChB;AAED;;;;;;;;;;;;;GAaG;AACH,mCAXW,OAAO,GAEL,IAAI,CAehB;AACD;;;;GAIG;AACH,iCAFW,OAAO,QASjB;AAED;;;;;;GAMG;AACH,iCAJW,OAAO,GAEL,IAAI,CAWhB;AAED;;;;;GAKG;AACH,sCAHW,OAAO,kBAAkB,EAAE,GAAG,gBAC9B,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,iBAQxC;AAED;;;;;;GAMG;AACH,uCAHG;IAAgC,GAAG;IACV,GAAG;CAAC,iBAU/B;AAgED;;GAEG;AACH,qCAFW,OAAO,QASjB;AAED;;;;;;GAMG;AACH,gCAJW,OAAO,GACL,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAKjD;AAnFD,iJAeI;AACJ,4KAAyD;AAEzD,oGAGE;AAEF;;GAEG;AAEH;;GAEG;AACH,mKA4BI;AAEJ,kLAA8C;uBApCjC,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC;iCApVP,YAAY;oBARtB,kBAAkB;oBADlB,SAAS;kBAGX,QAAQ"}
|
package/license
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Hugo Dias <hugomrdias@gmail.com> (hugodias.me)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iso-ucan",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"description": "Isomorphic UCAN",
|
|
6
6
|
"author": "Hugo Dias <hugomrdias@gmail.com> (hugodias.me)",
|
|
7
7
|
"license": "MIT",
|
|
@@ -95,24 +95,24 @@
|
|
|
95
95
|
"dist/src/**/*.d.ts.map"
|
|
96
96
|
],
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@ipld/dag-cbor": "^
|
|
98
|
+
"@ipld/dag-cbor": "^10.0.2",
|
|
99
99
|
"@standard-schema/spec": "^1.1.0",
|
|
100
100
|
"@standard-schema/utils": "^0.3.0",
|
|
101
101
|
"iobuffer": "^6.0.1",
|
|
102
|
-
"iso-
|
|
103
|
-
"iso-
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
102
|
+
"iso-base": "^4.4.0",
|
|
103
|
+
"iso-did": "^3.0.0",
|
|
104
|
+
"iso-kv": "^3.2.0",
|
|
105
|
+
"iso-signatures": "^0.5.2",
|
|
106
|
+
"iso-web": "^4.0.0",
|
|
107
|
+
"it-merge": "^3.0.15",
|
|
108
|
+
"multiformats": "^14.0.5",
|
|
109
|
+
"zod": "^4.6.5"
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
|
-
"@types/node": "^
|
|
112
|
+
"@types/node": "^26.6.2",
|
|
113
113
|
"delay": "^7.0.0",
|
|
114
|
-
"playwright-test": "^
|
|
115
|
-
"typescript": "
|
|
114
|
+
"playwright-test": "^15.0.1",
|
|
115
|
+
"typescript": "^6.0.3"
|
|
116
116
|
},
|
|
117
117
|
"publishConfig": {
|
|
118
118
|
"provenance": true
|
package/readme.md
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# iso-ucan [](https://www.npmjs.com/package/iso-ucan) [](https://github.com/hugomrdias/iso-repo/blob/main/license) [](https://github.com/hugomrdias/iso-repo/actions/workflows/iso-ucan.yml)
|
|
2
2
|
|
|
3
|
-
> Isomorphic UCAN
|
|
3
|
+
> Isomorphic UCAN primitives for delegations, invocations, proof storage, and
|
|
4
|
+
> typed RPC.
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
UCAN is a local-first authorization model where permissions are
|
|
9
|
+
cryptographically signed, delegated, and verified without relying on a central
|
|
10
|
+
authority. See [ucan.xyz](https://ucan.xyz/) for more background.
|
|
11
|
+
|
|
12
|
+
`iso-ucan` provides:
|
|
13
|
+
|
|
14
|
+
- Typed capabilities backed by schema validation.
|
|
15
|
+
- Delegation and invocation builders for UCAN authorization flows.
|
|
16
|
+
- Proof storage with pluggable `iso-kv` drivers.
|
|
17
|
+
- Signer and verifier support through `iso-signatures`.
|
|
18
|
+
- EIP-191 wallet signing support through `iso-signatures` `EIP191Signer`.
|
|
19
|
+
- Filsnap-powered UCAN signature insights in MetaMask signature popups.
|
|
20
|
+
- A typed RPC layer for request/response APIs built on UCAN invocations.
|
|
4
21
|
|
|
5
22
|
## Install
|
|
6
23
|
|
|
@@ -43,39 +60,59 @@ const invoker = await EdDSASigner.generate()
|
|
|
43
60
|
const nowInSeconds = Math.floor(Date.now() / 1000)
|
|
44
61
|
|
|
45
62
|
const ownerDelegation = await AccountCap.delegate({
|
|
46
|
-
iss: owner,
|
|
47
|
-
aud: bob,
|
|
48
|
-
sub: owner,
|
|
49
|
-
pol: [],
|
|
50
|
-
exp: nowInSeconds + 1000,
|
|
63
|
+
iss: owner,
|
|
64
|
+
aud: bob,
|
|
65
|
+
sub: owner,
|
|
66
|
+
pol: [],
|
|
67
|
+
exp: nowInSeconds + 1000,
|
|
51
68
|
})
|
|
52
69
|
|
|
53
70
|
await store.set(ownerDelegation)
|
|
54
71
|
|
|
55
72
|
const bobDelegation = await AccountCap.delegate({
|
|
56
|
-
iss: bob,
|
|
57
|
-
aud: invoker,
|
|
58
|
-
sub: owner,
|
|
59
|
-
pol: [],
|
|
60
|
-
exp: nowInSeconds + 1000,
|
|
73
|
+
iss: bob,
|
|
74
|
+
aud: invoker,
|
|
75
|
+
sub: owner,
|
|
76
|
+
pol: [],
|
|
77
|
+
exp: nowInSeconds + 1000,
|
|
61
78
|
})
|
|
62
79
|
|
|
63
80
|
await store.set(bobDelegation)
|
|
64
81
|
|
|
65
82
|
const invocation = await AccountCreateCap.invoke({
|
|
66
|
-
iss: invoker,
|
|
67
|
-
sub: owner,
|
|
68
|
-
args: {
|
|
83
|
+
iss: invoker,
|
|
84
|
+
sub: owner,
|
|
85
|
+
args: {
|
|
69
86
|
type: 'account',
|
|
70
87
|
properties: {
|
|
71
|
-
|
|
88
|
+
name: 'John Doe',
|
|
72
89
|
},
|
|
73
|
-
},
|
|
74
|
-
store,
|
|
75
|
-
exp: nowInSeconds + 1000,
|
|
90
|
+
},
|
|
91
|
+
store,
|
|
92
|
+
exp: nowInSeconds + 1000,
|
|
76
93
|
})
|
|
77
94
|
```
|
|
78
95
|
|
|
96
|
+
## EIP-191 wallet signing
|
|
97
|
+
|
|
98
|
+
`iso-ucan` can use EIP-191 wallet signatures through `EIP191Signer` from
|
|
99
|
+
`iso-signatures`. That lets UCAN delegations and invocations be issued by an
|
|
100
|
+
Ethereum account exposed through an EIP-1193 provider, such as an injected
|
|
101
|
+
MetaMask wallet, while verification is handled by the matching EIP-191 verifier
|
|
102
|
+
from `iso-signatures`.
|
|
103
|
+
|
|
104
|
+
[`examples/eip191`](../../examples/eip191) shows this flow in a browser web
|
|
105
|
+
app. It uses `wagmi` to connect the wallet, wraps the provider in
|
|
106
|
+
`EIP191Signer`, then creates and verifies UCAN delegations and invocations
|
|
107
|
+
directly in the browser.
|
|
108
|
+
|
|
109
|
+
The example uses `filsnap-adapter` to install or enable
|
|
110
|
+
[Filsnap](https://github.com/filecoin-project/filsnap), the Filecoin Wallet
|
|
111
|
+
MetaMask Snap. Filsnap supports UCAN signature insights for EIP-191 signers, so
|
|
112
|
+
when the app asks MetaMask to sign a UCAN delegation, the MetaMask signature
|
|
113
|
+
popup can show a readable summary of the issuer, audience, subject, command,
|
|
114
|
+
expiration, and raw payload.
|
|
115
|
+
|
|
79
116
|
## RPC
|
|
80
117
|
|
|
81
118
|
`iso-ucan/rpc` is a small request/response layer on top of UCAN
|
package/src/invocation.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
assertMeta,
|
|
10
10
|
assertNonce,
|
|
11
11
|
cid,
|
|
12
|
+
commandCovers,
|
|
12
13
|
expOrTtl,
|
|
13
14
|
verifySignature,
|
|
14
15
|
} from './utils.js'
|
|
@@ -235,9 +236,9 @@ export function assertProofs(payload, proofs) {
|
|
|
235
236
|
)
|
|
236
237
|
}
|
|
237
238
|
|
|
238
|
-
if (!
|
|
239
|
+
if (!commandCovers(current.cmd, next.cmd)) {
|
|
239
240
|
throw new Error(
|
|
240
|
-
`UCAN Invocation command mismatch, expected ${current.cmd} to
|
|
241
|
+
`UCAN Invocation command mismatch, expected ${current.cmd} to cover ${next.cmd}`
|
|
241
242
|
)
|
|
242
243
|
}
|
|
243
244
|
}
|
package/src/utils.js
CHANGED
|
@@ -168,6 +168,25 @@ export async function verifySignature(
|
|
|
168
168
|
return true
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Check if a command is covered by (equal to or a segment-wise child of) another command.
|
|
173
|
+
*
|
|
174
|
+
* Commands are compared by path segment, not by string prefix: `/crypto` covers
|
|
175
|
+
* `/crypto` and `/crypto/sign` but not `/cryptocurrency`. The command `/` covers
|
|
176
|
+
* every command.
|
|
177
|
+
*
|
|
178
|
+
* Both commands are expected to be valid per {@link assertIsValidCommand}, so
|
|
179
|
+
* `${parent}/` is always a real segment boundary.
|
|
180
|
+
*
|
|
181
|
+
* @param {string} parent - The broader command, e.g. from a delegation.
|
|
182
|
+
* @param {string} child - The command that must be attenuated from `parent`.
|
|
183
|
+
* @returns {boolean}
|
|
184
|
+
*/
|
|
185
|
+
export function commandCovers(parent, child) {
|
|
186
|
+
if (parent === '/') return child.startsWith('/')
|
|
187
|
+
return child === parent || child.startsWith(`${parent}/`)
|
|
188
|
+
}
|
|
189
|
+
|
|
171
190
|
/**
|
|
172
191
|
* Asserts that a UCAN command string is syntactically valid.
|
|
173
192
|
* If the command is invalid, it throws a descriptive error.
|