@interop/wallet-core 0.41.0 → 0.43.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 +17 -4
- package/dist/clients/rosterPolicy.d.ts +28 -16
- package/dist/clients/rosterPolicy.d.ts.map +1 -1
- package/dist/clients/rosterPolicy.js +51 -26
- package/dist/clients/rosterPolicy.js.map +1 -1
- package/dist/descriptors/index.d.ts +1 -1
- package/dist/descriptors/index.d.ts.map +1 -1
- package/dist/descriptors/index.js +1 -1
- package/dist/descriptors/index.js.map +1 -1
- package/dist/descriptors/logSource.d.ts +58 -6
- package/dist/descriptors/logSource.d.ts.map +1 -1
- package/dist/descriptors/logSource.js +57 -15
- package/dist/descriptors/logSource.js.map +1 -1
- package/dist/enrollment/enrollment.d.ts.map +1 -1
- package/dist/enrollment/enrollment.js +14 -26
- package/dist/enrollment/enrollment.js.map +1 -1
- package/dist/keyring/fetch.d.ts +12 -0
- package/dist/keyring/fetch.d.ts.map +1 -1
- package/dist/keyring/fetch.js +0 -2
- package/dist/keyring/fetch.js.map +1 -1
- package/dist/keyring/index.d.ts +1 -1
- package/dist/keyring/index.d.ts.map +1 -1
- package/dist/keyring/index.js +1 -1
- package/dist/keyring/index.js.map +1 -1
- package/dist/keyring/kdf.d.ts +22 -6
- package/dist/keyring/kdf.d.ts.map +1 -1
- package/dist/keyring/kdf.js +9 -14
- package/dist/keyring/kdf.js.map +1 -1
- package/dist/keys/index.d.ts +1 -1
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +1 -1
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/rosterLogStore.d.ts +4 -1
- package/dist/keys/rosterLogStore.d.ts.map +1 -1
- package/dist/keys/rosterLogStore.js +13 -16
- package/dist/keys/rosterLogStore.js.map +1 -1
- package/dist/keys/rosterStore.d.ts +13 -1
- package/dist/keys/rosterStore.d.ts.map +1 -1
- package/dist/keys/rosterStore.js +18 -0
- package/dist/keys/rosterStore.js.map +1 -1
- package/dist/keys/userKeyRoster.d.ts +17 -5
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +38 -13
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/recovery/index.d.ts +14 -12
- package/dist/recovery/index.d.ts.map +1 -1
- package/dist/recovery/index.js +13 -11
- package/dist/recovery/index.js.map +1 -1
- package/dist/recovery/recoveryCode.d.ts +5 -17
- package/dist/recovery/recoveryCode.d.ts.map +1 -1
- package/dist/recovery/recoveryCode.js +4 -14
- package/dist/recovery/recoveryCode.js.map +1 -1
- package/dist/recovery/recoveryDelegation.d.ts +50 -19
- package/dist/recovery/recoveryDelegation.d.ts.map +1 -1
- package/dist/recovery/recoveryDelegation.js +86 -41
- package/dist/recovery/recoveryDelegation.js.map +1 -1
- package/dist/recovery/recoveryWebvh.d.ts +13 -22
- package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
- package/dist/recovery/recoveryWebvh.js +37 -129
- package/dist/recovery/recoveryWebvh.js.map +1 -1
- package/dist/resourceLog/append.d.ts +12 -3
- package/dist/resourceLog/append.d.ts.map +1 -1
- package/dist/resourceLog/append.js +17 -10
- package/dist/resourceLog/append.js.map +1 -1
- package/dist/resourceLog/index.d.ts +1 -1
- package/dist/resourceLog/index.d.ts.map +1 -1
- package/dist/resourceLog/index.js +1 -1
- package/dist/resourceLog/index.js.map +1 -1
- package/dist/resourceLog/pin.d.ts +46 -8
- package/dist/resourceLog/pin.d.ts.map +1 -1
- package/dist/resourceLog/pin.js +32 -7
- package/dist/resourceLog/pin.js.map +1 -1
- package/dist/resourceLog/seal.d.ts +4 -1
- package/dist/resourceLog/seal.d.ts.map +1 -1
- package/dist/resourceLog/seal.js +6 -2
- package/dist/resourceLog/seal.js.map +1 -1
- package/dist/unlock/index.d.ts +40 -0
- package/dist/unlock/index.d.ts.map +1 -0
- package/dist/unlock/index.js +36 -0
- package/dist/unlock/index.js.map +1 -0
- package/dist/unlock/ladder.d.ts +100 -0
- package/dist/unlock/ladder.d.ts.map +1 -0
- package/dist/unlock/ladder.js +144 -0
- package/dist/unlock/ladder.js.map +1 -0
- package/dist/unlock/selfEnroll.d.ts +83 -0
- package/dist/unlock/selfEnroll.d.ts.map +1 -0
- package/dist/unlock/selfEnroll.js +126 -0
- package/dist/unlock/selfEnroll.js.map +1 -0
- package/dist/unlock/standingClient.d.ts +68 -0
- package/dist/unlock/standingClient.d.ts.map +1 -0
- package/dist/unlock/standingClient.js +81 -0
- package/dist/unlock/standingClient.js.map +1 -0
- package/dist/unlock/standingWebvh.d.ts +153 -0
- package/dist/unlock/standingWebvh.d.ts.map +1 -0
- package/dist/unlock/standingWebvh.js +370 -0
- package/dist/unlock/standingWebvh.js.map +1 -0
- package/dist/unlock/unlockRecord.d.ts +207 -0
- package/dist/unlock/unlockRecord.d.ts.map +1 -0
- package/dist/unlock/unlockRecord.js +435 -0
- package/dist/unlock/unlockRecord.js.map +1 -0
- package/dist/webvh/didWebvh.d.ts +94 -6
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +175 -19
- package/dist/webvh/didWebvh.js.map +1 -1
- package/dist/webvh/index.d.ts +7 -2
- package/dist/webvh/index.d.ts.map +1 -1
- package/dist/webvh/index.js +7 -2
- package/dist/webvh/index.js.map +1 -1
- package/dist/webvh/keyAgreement.d.ts +22 -6
- package/dist/webvh/keyAgreement.d.ts.map +1 -1
- package/dist/webvh/keyAgreement.js +1 -1
- package/dist/webvh/keyAgreement.js.map +1 -1
- package/dist/webvh/verifyLog.d.ts +15 -2
- package/dist/webvh/verifyLog.d.ts.map +1 -1
- package/dist/webvh/verifyLog.js +22 -3
- package/dist/webvh/verifyLog.js.map +1 -1
- package/package.json +11 -5
- package/dist/recovery/recoveryRecord.d.ts +0 -172
- package/dist/recovery/recoveryRecord.d.ts.map +0 -1
- package/dist/recovery/recoveryRecord.js +0 -288
- package/dist/recovery/recoveryRecord.js.map +0 -1
package/README.md
CHANGED
|
@@ -140,11 +140,24 @@ The subpaths:
|
|
|
140
140
|
heals by re-running. The keyring bind is deliberately not a stage, so a wallet
|
|
141
141
|
with no unlock method bound at creation drives the same ceremony.
|
|
142
142
|
|
|
143
|
+
- **`@interop/wallet-core/unlock`** -- standing unlock credentials: every unlock
|
|
144
|
+
method (passphrase, passkey PRF, recovery code) as a standing credential in
|
|
145
|
+
the recovery-code posture, with self-enrolling login. The credential-derived
|
|
146
|
+
client identity and binding MAC key, the update-key ladder
|
|
147
|
+
(latent-and-consumed did:webvh update authority from a random seed carried in
|
|
148
|
+
the unlock record, the current rung recovered from the log itself), the unlock
|
|
149
|
+
record codec (shell / bridge delegation / ladder members under a
|
|
150
|
+
credential-authenticated binding, with the bridge-only re-mint), the merged
|
|
151
|
+
document-posture edit (a verbatim `keyAgreement` entry or a
|
|
152
|
+
`publicKeyCommitment` entry for a low-entropy-derived key), and the
|
|
153
|
+
self-enrolling continuation with its composed completion.
|
|
154
|
+
|
|
143
155
|
- **`@interop/wallet-core/recovery`** -- recovery codes on the roster identity
|
|
144
|
-
model: a code as a minimal always-enrolled wallet
|
|
145
|
-
|
|
146
|
-
recovery, the pre-minted `did.jsonl`
|
|
147
|
-
cascade's
|
|
156
|
+
model, over the `unlock` machinery: a code as a minimal always-enrolled wallet
|
|
157
|
+
client (format and derivation, the document half of issuance / revocation /
|
|
158
|
+
recovery with its spend-on-use continuation, the pre-minted `did.jsonl`
|
|
159
|
+
delegation builder and the revocation cascade's bridge re-mint core; the
|
|
160
|
+
record codec is the `unlock` subpath's, re-exported here).
|
|
148
161
|
|
|
149
162
|
## Install
|
|
150
163
|
|
|
@@ -15,13 +15,19 @@
|
|
|
15
15
|
* roster is authenticated and checked against the locally pinned latest-seen
|
|
16
16
|
* epoch either way.
|
|
17
17
|
*
|
|
18
|
-
* **Failure semantics.** The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
18
|
+
* **Failure semantics.** The roster refusals -- a fabricated or
|
|
19
|
+
* discontinuous roster log, a rolled-back or replayed epoch configuration,
|
|
20
|
+
* one that fails authentication, and a current epoch this client cannot
|
|
21
|
+
* unwrap -- rethrow and refuse the session: they are the same continuity
|
|
22
|
+
* class as a substituted account pointer, and proceeding would mean acting
|
|
23
|
+
* under a key nobody vouched for. The one carve-out is the chain-head pin's
|
|
24
|
+
* continuity reason `rollback` (see {@link isRosterRefusal}), which lands in
|
|
25
|
+
* the transport class instead. Anything in that class (an unreachable
|
|
26
|
+
* server, a transport hiccup, the rollback) is warned about and resolves
|
|
27
|
+
* `null`, so the start keeps working from the cached key. A throw from the
|
|
28
|
+
* app's adoption callback is a third class of its own: the read succeeded
|
|
29
|
+
* but the adopted key and epoch pin did not persist, so it propagates
|
|
30
|
+
* verbatim rather than degrading to the cached key.
|
|
25
31
|
*
|
|
26
32
|
* - {@link convergeUserKeyRosterToAccount} -- the roster stage of the
|
|
27
33
|
* cascade-completion sweep, which the collection fan-out then runs behind. A
|
|
@@ -70,10 +76,12 @@ export interface AdoptedUserKey {
|
|
|
70
76
|
* Every read traces to the account document through the log-governed store
|
|
71
77
|
* itself: the roster resolves only from the roster log's verified head, whose
|
|
72
78
|
* entry proofs are checked against the locally verified account log. A log
|
|
73
|
-
* that cannot be fetched
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
79
|
+
* that cannot be fetched, and a served log the chain-head pin reports as a
|
|
80
|
+
* rollback, land in the transport-failure class -- the session carries on
|
|
81
|
+
* under the cached key, WITHOUT adopting an unverifiable (or rolled-back)
|
|
82
|
+
* rotation -- while a roster no enrolled client signed onto the log, and a
|
|
83
|
+
* log the pin reports as a fork or an SCID/method switch, are refusals like
|
|
84
|
+
* the other three.
|
|
77
85
|
*
|
|
78
86
|
* @param options {object}
|
|
79
87
|
* @param options.store {EncryptionDescriptorStore} the roster's descriptor
|
|
@@ -88,7 +96,9 @@ export interface AdoptedUserKey {
|
|
|
88
96
|
* @param [options.onRosterRead] {Function} called with the
|
|
89
97
|
* {@link AdoptedUserKey} of every successful read (whether or not it rotated),
|
|
90
98
|
* so the epoch pin advances to the epoch just authenticated; the key and the
|
|
91
|
-
* pin must persist atomically
|
|
99
|
+
* pin must persist atomically. A throw from this callback propagates to the
|
|
100
|
+
* caller verbatim -- it means the adopted key and pin did NOT persist, which
|
|
101
|
+
* is neither a transport hiccup nor a roster refusal
|
|
92
102
|
* @returns {Promise<UserKeyRosterReadResult | null>} the read, or `null` when
|
|
93
103
|
* the account has no roster yet or the server could not be reached
|
|
94
104
|
*/
|
|
@@ -111,8 +121,9 @@ export declare function checkUserKeyRosterAtLogin({ store, userKey, clientKeyAgr
|
|
|
111
121
|
* to a fresh key, that key is readable only from the roster, so a failed
|
|
112
122
|
* adoption throws rather than reporting `rotated: false` with the retired key
|
|
113
123
|
* and descriptor (which would skip `onUserKeyAdopted` and fan the collections
|
|
114
|
-
* out onto the pre-rotation epoch). The
|
|
115
|
-
*
|
|
124
|
+
* out onto the pre-rotation epoch). The roster refusals rethrow throughout,
|
|
125
|
+
* exactly as {@link checkUserKeyRosterAtLogin} rethrows them, under the same
|
|
126
|
+
* rollback carve-out.
|
|
116
127
|
*
|
|
117
128
|
* @param options {object}
|
|
118
129
|
* @param options.pointer {AccountLogPointer} where the account log lives
|
|
@@ -125,8 +136,9 @@ export declare function checkUserKeyRosterAtLogin({ store, userKey, clientKeyAgr
|
|
|
125
136
|
* @param [options.pinnedEpochId] {string} the locally pinned latest-seen
|
|
126
137
|
* roster epoch
|
|
127
138
|
* @param [options.accountLogPinStore] {ResourceLogPinStore} this client's
|
|
128
|
-
* chain-head pin for the account log; a served log
|
|
129
|
-
* is a refusal like the
|
|
139
|
+
* chain-head pin for the account log; a served log the pin reports as a
|
|
140
|
+
* fork or an SCID/method switch is a refusal like the others, while a
|
|
141
|
+
* rollback resolves to the unchanged input under the carve-out
|
|
130
142
|
* @param [options.onUserKeyAdopted] {Function} called with the
|
|
131
143
|
* {@link AdoptedUserKey} of a rotation, before the fan-out runs
|
|
132
144
|
* @returns {Promise<object>} whether the roster rotated on this call,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rosterPolicy.d.ts","sourceRoot":"","sources":["../../src/clients/rosterPolicy.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"rosterPolicy.d.ts","sourceRoot":"","sources":["../../src/clients/rosterPolicy.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,uBAAuB,EAC7B,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAErD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,oBAAoB,CAAA;CACjC;AA2CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,KAAK,EACL,OAAO,EACP,qBAAqB,EACrB,aAAa,EACb,YAAY,EACb,EAAE;IACD,KAAK,EAAE,yBAAyB,CAAA;IAChC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qBAAqB,EAAE,gBAAgB,CAAA;IACvC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1D,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAoC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAsB,8BAA8B,CAAC,EACnD,OAAO,EACP,KAAK,EACL,OAAO,EACP,UAAU,EACV,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EACjB,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;IAC1B,KAAK,EAAE,yBAAyB,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,oBAAoB,CAAA;IAChC,qBAAqB,EAAE,gBAAgB,CAAA;IACvC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,kBAAkB,CAAC,EAAE,mBAAmB,CAAA;IACxC,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9D,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,oBAAoB,CAAA;CACjC,CAAC,CAwGD"}
|
|
@@ -2,11 +2,22 @@ import { convergeUserKeyRosterToDocument, isSealableDescriptorStore, readUserKey
|
|
|
2
2
|
import { verifyAccountLog } from '../webvh/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Whether a thrown error is one of the roster refusals -- a fabricated or
|
|
5
|
-
* discontinuous roster log, a rolled-back or replayed
|
|
6
|
-
* configuration that fails authentication, and a current epoch this
|
|
7
|
-
* cannot unwrap. They are the continuity class that refuses a session
|
|
8
|
-
* than degrading it, so both entry points rethrow them instead of
|
|
9
|
-
* carrying on.
|
|
5
|
+
* discontinuous roster log, a rolled-back or replayed epoch configuration, an
|
|
6
|
+
* epoch configuration that fails authentication, and a current epoch this
|
|
7
|
+
* client cannot unwrap. They are the continuity class that refuses a session
|
|
8
|
+
* rather than degrading it, so both entry points rethrow them instead of
|
|
9
|
+
* warning and carrying on.
|
|
10
|
+
*
|
|
11
|
+
* The one carve-out is the chain-head pin's continuity reason `rollback` --
|
|
12
|
+
* reconcilable divergence (possibly replication lag, retryable per the
|
|
13
|
+
* profile's log-pin rules), the same carve-out `descriptors/acquire.ts` makes
|
|
14
|
+
* on the collection-descriptor path and the account-log pin makes for the
|
|
15
|
+
* account document: nothing rolled back is adopted and the pin never
|
|
16
|
+
* regresses, so a lagging replica degrades the start to the cached user key
|
|
17
|
+
* instead of hard-refusing a healthy account's login. The epoch pin's own
|
|
18
|
+
* `UserKeyRosterContinuityError` stays a refusal: with no chain to compare it
|
|
19
|
+
* cannot tell a rollback from a fork, and it is the guard that remains when
|
|
20
|
+
* the chain-head pin was lost with a reinstall.
|
|
10
21
|
*
|
|
11
22
|
* Matched on `err.name` rather than `instanceof`: the errors are raised inside
|
|
12
23
|
* the app-injected descriptor store, which can resolve to a different copy of
|
|
@@ -19,8 +30,10 @@ import { verifyAccountLog } from '../webvh/index.js';
|
|
|
19
30
|
*/
|
|
20
31
|
function isRosterRefusal(err) {
|
|
21
32
|
const name = err?.name;
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
if (name === 'ResourceLogContinuityError') {
|
|
34
|
+
return err.reason !== 'rollback';
|
|
35
|
+
}
|
|
36
|
+
return (name === 'ResourceLogIntegrityError' ||
|
|
24
37
|
name === 'UserKeyRosterContinuityError' ||
|
|
25
38
|
name === 'UserKeyRosterIntegrityError' ||
|
|
26
39
|
name === 'UserKeyRosterUnwrapError');
|
|
@@ -31,10 +44,12 @@ function isRosterRefusal(err) {
|
|
|
31
44
|
* Every read traces to the account document through the log-governed store
|
|
32
45
|
* itself: the roster resolves only from the roster log's verified head, whose
|
|
33
46
|
* entry proofs are checked against the locally verified account log. A log
|
|
34
|
-
* that cannot be fetched
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
47
|
+
* that cannot be fetched, and a served log the chain-head pin reports as a
|
|
48
|
+
* rollback, land in the transport-failure class -- the session carries on
|
|
49
|
+
* under the cached key, WITHOUT adopting an unverifiable (or rolled-back)
|
|
50
|
+
* rotation -- while a roster no enrolled client signed onto the log, and a
|
|
51
|
+
* log the pin reports as a fork or an SCID/method switch, are refusals like
|
|
52
|
+
* the other three.
|
|
38
53
|
*
|
|
39
54
|
* @param options {object}
|
|
40
55
|
* @param options.store {EncryptionDescriptorStore} the roster's descriptor
|
|
@@ -49,27 +64,21 @@ function isRosterRefusal(err) {
|
|
|
49
64
|
* @param [options.onRosterRead] {Function} called with the
|
|
50
65
|
* {@link AdoptedUserKey} of every successful read (whether or not it rotated),
|
|
51
66
|
* so the epoch pin advances to the epoch just authenticated; the key and the
|
|
52
|
-
* pin must persist atomically
|
|
67
|
+
* pin must persist atomically. A throw from this callback propagates to the
|
|
68
|
+
* caller verbatim -- it means the adopted key and pin did NOT persist, which
|
|
69
|
+
* is neither a transport hiccup nor a roster refusal
|
|
53
70
|
* @returns {Promise<UserKeyRosterReadResult | null>} the read, or `null` when
|
|
54
71
|
* the account has no roster yet or the server could not be reached
|
|
55
72
|
*/
|
|
56
73
|
export async function checkUserKeyRosterAtLogin({ store, userKey, clientKeyAgreementKey, pinnedEpochId, onRosterRead }) {
|
|
74
|
+
let read;
|
|
57
75
|
try {
|
|
58
|
-
|
|
76
|
+
read = await readUserKeyRoster({
|
|
59
77
|
store,
|
|
60
78
|
...(userKey ? { userKey } : {}),
|
|
61
79
|
clientKeyAgreementKey,
|
|
62
80
|
pinnedEpochId
|
|
63
81
|
});
|
|
64
|
-
if (!read) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
await onRosterRead?.({
|
|
68
|
-
userKey: read.userKey,
|
|
69
|
-
latestEpochId: read.latestEpochId,
|
|
70
|
-
descriptor: read.descriptor
|
|
71
|
-
});
|
|
72
|
-
return read;
|
|
73
82
|
}
|
|
74
83
|
catch (err) {
|
|
75
84
|
if (isRosterRefusal(err)) {
|
|
@@ -81,6 +90,20 @@ export async function checkUserKeyRosterAtLogin({ store, userKey, clientKeyAgree
|
|
|
81
90
|
'user key:', err);
|
|
82
91
|
return null;
|
|
83
92
|
}
|
|
93
|
+
if (!read) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
// The adoption callback runs OUTSIDE the transport catch: the roster read
|
|
97
|
+
// itself succeeded, so a throw here is the app failing to persist the
|
|
98
|
+
// adopted key and epoch pin, and swallowing it into the warn-and-null path
|
|
99
|
+
// would report a broken persist as an offline start (the session would
|
|
100
|
+
// proceed on the retired cached key with the pin never advanced).
|
|
101
|
+
await onRosterRead?.({
|
|
102
|
+
userKey: read.userKey,
|
|
103
|
+
latestEpochId: read.latestEpochId,
|
|
104
|
+
descriptor: read.descriptor
|
|
105
|
+
});
|
|
106
|
+
return read;
|
|
84
107
|
}
|
|
85
108
|
/**
|
|
86
109
|
* Converges the roster onto the account's locally verified did:webvh document,
|
|
@@ -94,8 +117,9 @@ export async function checkUserKeyRosterAtLogin({ store, userKey, clientKeyAgree
|
|
|
94
117
|
* to a fresh key, that key is readable only from the roster, so a failed
|
|
95
118
|
* adoption throws rather than reporting `rotated: false` with the retired key
|
|
96
119
|
* and descriptor (which would skip `onUserKeyAdopted` and fan the collections
|
|
97
|
-
* out onto the pre-rotation epoch). The
|
|
98
|
-
*
|
|
120
|
+
* out onto the pre-rotation epoch). The roster refusals rethrow throughout,
|
|
121
|
+
* exactly as {@link checkUserKeyRosterAtLogin} rethrows them, under the same
|
|
122
|
+
* rollback carve-out.
|
|
99
123
|
*
|
|
100
124
|
* @param options {object}
|
|
101
125
|
* @param options.pointer {AccountLogPointer} where the account log lives
|
|
@@ -108,8 +132,9 @@ export async function checkUserKeyRosterAtLogin({ store, userKey, clientKeyAgree
|
|
|
108
132
|
* @param [options.pinnedEpochId] {string} the locally pinned latest-seen
|
|
109
133
|
* roster epoch
|
|
110
134
|
* @param [options.accountLogPinStore] {ResourceLogPinStore} this client's
|
|
111
|
-
* chain-head pin for the account log; a served log
|
|
112
|
-
* is a refusal like the
|
|
135
|
+
* chain-head pin for the account log; a served log the pin reports as a
|
|
136
|
+
* fork or an SCID/method switch is a refusal like the others, while a
|
|
137
|
+
* rollback resolves to the unchanged input under the carve-out
|
|
113
138
|
* @param [options.onUserKeyAdopted] {Function} called with the
|
|
114
139
|
* {@link AdoptedUserKey} of a rotation, before the fan-out runs
|
|
115
140
|
* @returns {Promise<object>} whether the roster rotated on this call,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rosterPolicy.js","sourceRoot":"","sources":["../../src/clients/rosterPolicy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rosterPolicy.js","sourceRoot":"","sources":["../../src/clients/rosterPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*/
|
|
39
39
|
export { acquireDescriptor, acquireDescriptors, wasDescriptorSource } from './acquire.js';
|
|
40
40
|
export type { EncryptionDescriptorCache, EncryptionDescriptorSource } from './acquire.js';
|
|
41
|
-
export { EPOCH_CONFIGURATION_STATE_TYPE, logGovernedDescriptorSource } from './logSource.js';
|
|
41
|
+
export { EPOCH_CONFIGURATION_STATE_TYPE, logGovernedDescriptorSource, readGovernedEpochConfiguration } from './logSource.js';
|
|
42
42
|
export { DescriptorRefreshPolicy } from './refresh.js';
|
|
43
43
|
export { createRefreshingEdvDocCipher } from './cipher.js';
|
|
44
44
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/descriptors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC3B,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/descriptors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC3B,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,8BAA8B,EAC/B,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAEtD,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* instance.
|
|
38
38
|
*/
|
|
39
39
|
export { acquireDescriptor, acquireDescriptors, wasDescriptorSource } from './acquire.js';
|
|
40
|
-
export { EPOCH_CONFIGURATION_STATE_TYPE, logGovernedDescriptorSource } from './logSource.js';
|
|
40
|
+
export { EPOCH_CONFIGURATION_STATE_TYPE, logGovernedDescriptorSource, readGovernedEpochConfiguration } from './logSource.js';
|
|
41
41
|
export { DescriptorRefreshPolicy } from './refresh.js';
|
|
42
42
|
export { createRefreshingEdvDocCipher } from './cipher.js';
|
|
43
43
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/descriptors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,cAAc,CAAA;AAMrB,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/descriptors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,cAAc,CAAA;AAMrB,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,8BAA8B,EAC/B,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAEtD,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -1,11 +1,60 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The log-governed {@link EncryptionDescriptorSource}: descriptor acquisition
|
|
6
|
+
* for a collection whose encryption descriptor is governed by a resource log
|
|
7
|
+
* (the Resource Log Profile) rather than by its Collection Description. Every
|
|
8
|
+
* read -- including the unknown-epoch refresh's re-read -- resolves to the
|
|
9
|
+
* log's VERIFIED head state: chain, proofs, external authorization against
|
|
10
|
+
* the independently verified controller document, and the chain-head pin all
|
|
11
|
+
* checked before any descriptor is handed out, so a refresh re-verifies the
|
|
12
|
+
* log rather than adopting whatever the host serves. A verified head whose
|
|
13
|
+
* state is not an epoch configuration is refused fail-closed rather than
|
|
14
|
+
* handed out as a descriptor.
|
|
15
|
+
*/
|
|
16
|
+
import type { CollectionEncryption } from '@interop/was-client';
|
|
1
17
|
import { type ResourceLogStore } from '@interop/was-client/log';
|
|
2
|
-
import { type ResourceLogController, type ResourceLogPinStore } from '../resourceLog/index.js';
|
|
18
|
+
import { type ResourceLogController, type ResourceLogPinStore, type VerifiedResourceLog } from '../resourceLog/index.js';
|
|
3
19
|
import type { EncryptionDescriptorSource } from './acquire.js';
|
|
4
20
|
/**
|
|
5
21
|
* The state-document schema identifier an encryption descriptor carries in a
|
|
6
22
|
* governed log entry, per WAS-EC.
|
|
7
23
|
*/
|
|
8
24
|
export declare const EPOCH_CONFIGURATION_STATE_TYPE = "WasEpochConfiguration";
|
|
25
|
+
/**
|
|
26
|
+
* The one governed epoch-configuration read: the fail-closed boundary that
|
|
27
|
+
* decides whether a served log state may be treated as an encryption
|
|
28
|
+
* descriptor. Resolves the controller view, reads and fully verifies the log
|
|
29
|
+
* (chain, proofs, external authorization, and the chain-head pin, via
|
|
30
|
+
* `readResourceLog`), and refuses a verified head whose state is not a
|
|
31
|
+
* `WasEpochConfiguration` rather than handing it out as a descriptor.
|
|
32
|
+
* Resolves `null` for an absent log (the pre-genesis state). Both governed
|
|
33
|
+
* descriptor consumers -- the log-governed descriptor source below and the
|
|
34
|
+
* roster's log-governed descriptor store -- read through this helper, so a
|
|
35
|
+
* hardening applied here reaches every trusted descriptor read.
|
|
36
|
+
*
|
|
37
|
+
* @param options {object}
|
|
38
|
+
* @param options.store {ResourceLogStore} the log's transport seam
|
|
39
|
+
* @param options.resolveController {function}
|
|
40
|
+
* `() => Promise<ResourceLogController>` -- the caller's currently verified
|
|
41
|
+
* controller view, resolved per operation
|
|
42
|
+
* @param options.pinStore {ResourceLogPinStore} this client's chain-head
|
|
43
|
+
* pin for this log
|
|
44
|
+
* @param options.logId {string} the pin-slot key for this log, from
|
|
45
|
+
* `resourceLogPinId`
|
|
46
|
+
* @returns {Promise<{ verified: VerifiedResourceLog; descriptor: CollectionEncryption; etag?: string } | null>}
|
|
47
|
+
*/
|
|
48
|
+
export declare function readGovernedEpochConfiguration({ store, resolveController, pinStore, logId }: {
|
|
49
|
+
store: ResourceLogStore;
|
|
50
|
+
resolveController: () => Promise<ResourceLogController>;
|
|
51
|
+
pinStore: ResourceLogPinStore;
|
|
52
|
+
logId: string;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
verified: VerifiedResourceLog;
|
|
55
|
+
descriptor: CollectionEncryption;
|
|
56
|
+
etag?: string;
|
|
57
|
+
} | null>;
|
|
9
58
|
/**
|
|
10
59
|
* Builds the {@link EncryptionDescriptorSource} over per-collection resource
|
|
11
60
|
* logs. An absent log resolves `undefined` exactly like an absent
|
|
@@ -20,14 +69,17 @@ export declare const EPOCH_CONFIGURATION_STATE_TYPE = "WasEpochConfiguration";
|
|
|
20
69
|
* @param options.resolveController {function}
|
|
21
70
|
* `() => Promise<ResourceLogController>` -- the caller's currently verified
|
|
22
71
|
* controller view, resolved per operation
|
|
23
|
-
* @param options.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
72
|
+
* @param options.pinStore {ResourceLogPinStore} this client's chain-head
|
|
73
|
+
* pins, keyed per log
|
|
74
|
+
* @param options.logIdFor {function} `(collectionId) => string` -- the
|
|
75
|
+
* collection's descriptor log's pin-slot key, typically built with
|
|
76
|
+
* `resourceLogPinId`
|
|
26
77
|
* @returns {EncryptionDescriptorSource}
|
|
27
78
|
*/
|
|
28
|
-
export declare function logGovernedDescriptorSource({ logFor, resolveController,
|
|
79
|
+
export declare function logGovernedDescriptorSource({ logFor, resolveController, pinStore, logIdFor }: {
|
|
29
80
|
logFor: (collectionId: string) => ResourceLogStore;
|
|
30
81
|
resolveController: () => Promise<ResourceLogController>;
|
|
31
|
-
|
|
82
|
+
pinStore: ResourceLogPinStore;
|
|
83
|
+
logIdFor: (collectionId: string) => string;
|
|
32
84
|
}): EncryptionDescriptorSource;
|
|
33
85
|
//# sourceMappingURL=logSource.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logSource.d.ts","sourceRoot":"","sources":["../../src/descriptors/logSource.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logSource.d.ts","sourceRoot":"","sources":["../../src/descriptors/logSource.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,8BAA8B,0BAA0B,CAAA;AAErE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,8BAA8B,CAAC,EACnD,KAAK,EACL,iBAAiB,EACjB,QAAQ,EACR,KAAK,EACN,EAAE;IACD,KAAK,EAAE,gBAAgB,CAAA;IACvB,iBAAiB,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACvD,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,KAAK,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC;IACV,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,UAAU,EAAE,oBAAoB,CAAA;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,IAAI,CAAC,CAwBR;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,2BAA2B,CAAC,EAC1C,MAAM,EACN,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACT,EAAE;IACD,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,gBAAgB,CAAA;IAClD,iBAAiB,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACvD,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;CAC3C,GAAG,0BAA0B,CAe7B"}
|
|
@@ -5,6 +5,52 @@ import { readResourceLog, ResourceLogIntegrityError } from '../resourceLog/index
|
|
|
5
5
|
* governed log entry, per WAS-EC.
|
|
6
6
|
*/
|
|
7
7
|
export const EPOCH_CONFIGURATION_STATE_TYPE = 'WasEpochConfiguration';
|
|
8
|
+
/**
|
|
9
|
+
* The one governed epoch-configuration read: the fail-closed boundary that
|
|
10
|
+
* decides whether a served log state may be treated as an encryption
|
|
11
|
+
* descriptor. Resolves the controller view, reads and fully verifies the log
|
|
12
|
+
* (chain, proofs, external authorization, and the chain-head pin, via
|
|
13
|
+
* `readResourceLog`), and refuses a verified head whose state is not a
|
|
14
|
+
* `WasEpochConfiguration` rather than handing it out as a descriptor.
|
|
15
|
+
* Resolves `null` for an absent log (the pre-genesis state). Both governed
|
|
16
|
+
* descriptor consumers -- the log-governed descriptor source below and the
|
|
17
|
+
* roster's log-governed descriptor store -- read through this helper, so a
|
|
18
|
+
* hardening applied here reaches every trusted descriptor read.
|
|
19
|
+
*
|
|
20
|
+
* @param options {object}
|
|
21
|
+
* @param options.store {ResourceLogStore} the log's transport seam
|
|
22
|
+
* @param options.resolveController {function}
|
|
23
|
+
* `() => Promise<ResourceLogController>` -- the caller's currently verified
|
|
24
|
+
* controller view, resolved per operation
|
|
25
|
+
* @param options.pinStore {ResourceLogPinStore} this client's chain-head
|
|
26
|
+
* pin for this log
|
|
27
|
+
* @param options.logId {string} the pin-slot key for this log, from
|
|
28
|
+
* `resourceLogPinId`
|
|
29
|
+
* @returns {Promise<{ verified: VerifiedResourceLog; descriptor: CollectionEncryption; etag?: string } | null>}
|
|
30
|
+
*/
|
|
31
|
+
export async function readGovernedEpochConfiguration({ store, resolveController, pinStore, logId }) {
|
|
32
|
+
const controller = await resolveController();
|
|
33
|
+
const current = await readResourceLog({
|
|
34
|
+
store,
|
|
35
|
+
controller,
|
|
36
|
+
expectedMethod: RESOURCE_LOG_METHOD,
|
|
37
|
+
pinStore,
|
|
38
|
+
logId
|
|
39
|
+
});
|
|
40
|
+
if (current === null) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const state = current.verified.state;
|
|
44
|
+
if (state.type !== EPOCH_CONFIGURATION_STATE_TYPE) {
|
|
45
|
+
throw new ResourceLogIntegrityError(`The governed descriptor log carries state of type ` +
|
|
46
|
+
`"${state.type}", not "${EPOCH_CONFIGURATION_STATE_TYPE}".`);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
verified: current.verified,
|
|
50
|
+
descriptor: state,
|
|
51
|
+
etag: current.etag
|
|
52
|
+
};
|
|
53
|
+
}
|
|
8
54
|
/**
|
|
9
55
|
* Builds the {@link EncryptionDescriptorSource} over per-collection resource
|
|
10
56
|
* logs. An absent log resolves `undefined` exactly like an absent
|
|
@@ -19,30 +65,26 @@ export const EPOCH_CONFIGURATION_STATE_TYPE = 'WasEpochConfiguration';
|
|
|
19
65
|
* @param options.resolveController {function}
|
|
20
66
|
* `() => Promise<ResourceLogController>` -- the caller's currently verified
|
|
21
67
|
* controller view, resolved per operation
|
|
22
|
-
* @param options.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
68
|
+
* @param options.pinStore {ResourceLogPinStore} this client's chain-head
|
|
69
|
+
* pins, keyed per log
|
|
70
|
+
* @param options.logIdFor {function} `(collectionId) => string` -- the
|
|
71
|
+
* collection's descriptor log's pin-slot key, typically built with
|
|
72
|
+
* `resourceLogPinId`
|
|
25
73
|
* @returns {EncryptionDescriptorSource}
|
|
26
74
|
*/
|
|
27
|
-
export function logGovernedDescriptorSource({ logFor, resolveController,
|
|
75
|
+
export function logGovernedDescriptorSource({ logFor, resolveController, pinStore, logIdFor }) {
|
|
28
76
|
return {
|
|
29
77
|
async collectionEncryption({ collectionId }) {
|
|
30
|
-
const
|
|
31
|
-
const current = await readResourceLog({
|
|
78
|
+
const current = await readGovernedEpochConfiguration({
|
|
32
79
|
store: logFor(collectionId),
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
80
|
+
resolveController,
|
|
81
|
+
pinStore,
|
|
82
|
+
logId: logIdFor(collectionId)
|
|
36
83
|
});
|
|
37
84
|
if (current === null) {
|
|
38
85
|
return undefined;
|
|
39
86
|
}
|
|
40
|
-
|
|
41
|
-
if (state.type !== EPOCH_CONFIGURATION_STATE_TYPE) {
|
|
42
|
-
throw new ResourceLogIntegrityError(`The governed descriptor log carries state of type ` +
|
|
43
|
-
`"${state.type}", not "${EPOCH_CONFIGURATION_STATE_TYPE}".`);
|
|
44
|
-
}
|
|
45
|
-
return state;
|
|
87
|
+
return current.descriptor;
|
|
46
88
|
}
|
|
47
89
|
};
|
|
48
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logSource.js","sourceRoot":"","sources":["../../src/descriptors/logSource.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,mBAAmB,EAEpB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,eAAe,EACf,yBAAyB,
|
|
1
|
+
{"version":3,"file":"logSource.js","sourceRoot":"","sources":["../../src/descriptors/logSource.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,mBAAmB,EAEpB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,eAAe,EACf,yBAAyB,EAI1B,MAAM,yBAAyB,CAAA;AAGhC;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,uBAAuB,CAAA;AAErE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,EACnD,KAAK,EACL,iBAAiB,EACjB,QAAQ,EACR,KAAK,EAMN;IAKC,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAA;IAC5C,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC;QACpC,KAAK;QACL,UAAU;QACV,cAAc,EAAE,mBAAmB;QACnC,QAAQ;QACR,KAAK;KACN,CAAC,CAAA;IACF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAA;IACpC,IAAI,KAAK,CAAC,IAAI,KAAK,8BAA8B,EAAE,CAAC;QAClD,MAAM,IAAI,yBAAyB,CACjC,oDAAoD;YAClD,IAAI,KAAK,CAAC,IAAI,WAAW,8BAA8B,IAAI,CAC9D,CAAA;IACH,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,UAAU,EAAE,KAA6B;QACzC,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,2BAA2B,CAAC,EAC1C,MAAM,EACN,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EAMT;IACC,OAAO;QACL,KAAK,CAAC,oBAAoB,CAAC,EAAE,YAAY,EAAE;YACzC,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAAC;gBACnD,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC;gBAC3B,iBAAiB;gBACjB,QAAQ;gBACR,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC;aAC9B,CAAC,CAAA;YACF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,OAAO,SAAS,CAAA;YAClB,CAAC;YACD,OAAO,OAAO,CAAC,UAAU,CAAA;QAC3B,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrollment.d.ts","sourceRoot":"","sources":["../../src/enrollment/enrollment.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAaxE,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACb,MAAM,sBAAsB,CAAA;AAc7B,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAQ1D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,CAAA;AAEnD;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBAE7C,OAAO,SAC+C;CAKzD;
|
|
1
|
+
{"version":3,"file":"enrollment.d.ts","sourceRoot":"","sources":["../../src/enrollment/enrollment.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAaxE,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACb,MAAM,sBAAsB,CAAA;AAc7B,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAQ1D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,CAAA;AAEnD;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBAE7C,OAAO,SAC+C;CAKzD;AAiDD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,OAAO,EACR,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;CAC3B,GAAG,MAAM,CAKT;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACL,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,iBAAiB,CAwDpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,6BAA6B,CAAC,EAC5C,OAAO,EACR,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;CAC3B,GAAG,IAAI,CAYP;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACR,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;CAC3B,GAAG,MAAM,CAET;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACR,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;CAC3B,GAAG,MAAM,CAKT;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC;IACrD,UAAU,EAAE,UAAU,CAAA;IACtB,eAAe,EAAE,qBAAqB,CAAA;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB,CAAC,CA2BD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,OAAO,EACP,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,OAAO,EACR,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;IAC1B,eAAe,EAAE,qBAAqB,CAAA;IACtC,qBAAqB,EAAE,gBAAgB,CAAA;IACvC,kBAAkB,EAAE,yBAAyB,CAAA;IAC7C,OAAO,EAAE,YAAY,CAAA;CACtB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC,CA2B3E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,UAAU,EACV,eAAe,EACf,OAAO,EACP,kBAAkB,EACnB,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,eAAe,EAAE,qBAAqB,CAAA;IACtC,OAAO,EAAE,cAAc,CAAA;IACvB,kBAAkB,CAAC,EAAE,mBAAmB,CAAA;CACzC,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAyEvD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { decodeMultikey, MultikeyCodec } from '@interop/data-integrity-core/multihash';
|
|
1
2
|
import { base64urlnopad } from '@scure/base';
|
|
2
|
-
import { multibaseDecode, MULTICODEC_X25519_PUB_HEADER } from '@interop/x25519-key-agreement-key';
|
|
3
3
|
import { agentsFromSeed } from '../identity/agents.js';
|
|
4
4
|
import { enrollWebvhClient, keyAgreementTwinMultibase, mintClientWebvhUpdateKeys, updateKeyMultibase } from '../webvh/didWebvh.js';
|
|
5
5
|
import { clientSigningKeyMultibase, isWebvhDid, webvhZcapClient } from '../webvh/zcap.js';
|
|
@@ -31,46 +31,34 @@ export class EnrollmentPendingError extends Error {
|
|
|
31
31
|
*/
|
|
32
32
|
const ED25519_MULTIBASE_PREFIX = 'z6Mk';
|
|
33
33
|
const X25519_MULTIBASE_PREFIX = 'z6LS';
|
|
34
|
-
/**
|
|
35
|
-
* The multicodec varint header of an `ed25519-pub` value, the registry
|
|
36
|
-
* constant the `z6Mk` prefix renders. The X25519 counterpart is imported from
|
|
37
|
-
* the key suite that owns it; there is no exported Ed25519 equivalent.
|
|
38
|
-
*/
|
|
39
|
-
const MULTICODEC_ED25519_PUB_HEADER = new Uint8Array([0xed, 0x01]);
|
|
40
|
-
/**
|
|
41
|
-
* The byte length of both public key types a connect code carries.
|
|
42
|
-
*/
|
|
43
|
-
const PUBLIC_KEY_BYTES = 32;
|
|
44
34
|
/**
|
|
45
35
|
* Validates one connect-code key all the way down to its bytes: the multibase
|
|
46
|
-
* prefix, a real base58btc decode
|
|
47
|
-
* The prefix alone is worth nothing here
|
|
48
|
-
* append-only did:webvh log, where a key
|
|
49
|
-
* published forever.
|
|
36
|
+
* prefix, then a real base58btc decode with the multicodec header and key
|
|
37
|
+
* length enforced by `decodeMultikey`. The prefix alone is worth nothing here
|
|
38
|
+
* -- these keys are signed into an append-only did:webvh log, where a key
|
|
39
|
+
* that only LOOKS like a multibase is published forever. The prefix check
|
|
40
|
+
* stays alongside the decode: it is a stricter, deliberate spelling
|
|
41
|
+
* constraint (`z6Mk` / `z6LS` exactly) the codec-level decode does not cover.
|
|
50
42
|
*
|
|
51
43
|
* @param options {object}
|
|
52
44
|
* @param options.value {unknown} the payload member
|
|
53
45
|
* @param options.prefix {string} the expected multibase prefix
|
|
54
|
-
* @param options.
|
|
46
|
+
* @param options.expectedCodec {MultikeyCodec} the expected multicodec
|
|
55
47
|
* @param options.name {string} the key's name, for the error message
|
|
56
48
|
* @returns {string} the key, verbatim
|
|
57
49
|
*/
|
|
58
|
-
function requireConnectCodeKey({ value, prefix,
|
|
50
|
+
function requireConnectCodeKey({ value, prefix, expectedCodec, name }) {
|
|
59
51
|
if (typeof value !== 'string' || !value.startsWith(prefix)) {
|
|
60
52
|
throw new Error(`The connect code carries a malformed ${name}.`);
|
|
61
53
|
}
|
|
62
|
-
let bytes;
|
|
63
54
|
try {
|
|
64
|
-
|
|
55
|
+
decodeMultikey({ multikey: value, expectedCodec });
|
|
65
56
|
}
|
|
66
57
|
catch (err) {
|
|
67
58
|
throw new Error(`The connect code carries a malformed ${name}.`, {
|
|
68
59
|
cause: err
|
|
69
60
|
});
|
|
70
61
|
}
|
|
71
|
-
if (bytes.length !== PUBLIC_KEY_BYTES) {
|
|
72
|
-
throw new Error(`The connect code carries a malformed ${name}.`);
|
|
73
|
-
}
|
|
74
62
|
return value;
|
|
75
63
|
}
|
|
76
64
|
/**
|
|
@@ -122,25 +110,25 @@ export function parseEnrollmentRequest({ code }) {
|
|
|
122
110
|
signingKeyMultibase: requireConnectCodeKey({
|
|
123
111
|
value: signingKeyMultibase,
|
|
124
112
|
prefix: ED25519_MULTIBASE_PREFIX,
|
|
125
|
-
|
|
113
|
+
expectedCodec: MultikeyCodec.ED25519_PUB,
|
|
126
114
|
name: 'signing key'
|
|
127
115
|
}),
|
|
128
116
|
keyAgreementKeyMultibase: requireConnectCodeKey({
|
|
129
117
|
value: keyAgreementKeyMultibase,
|
|
130
118
|
prefix: X25519_MULTIBASE_PREFIX,
|
|
131
|
-
|
|
119
|
+
expectedCodec: MultikeyCodec.X25519_PUB,
|
|
132
120
|
name: 'key-agreement key'
|
|
133
121
|
}),
|
|
134
122
|
updateKeyMultibase: requireConnectCodeKey({
|
|
135
123
|
value: updateKey,
|
|
136
124
|
prefix: ED25519_MULTIBASE_PREFIX,
|
|
137
|
-
|
|
125
|
+
expectedCodec: MultikeyCodec.ED25519_PUB,
|
|
138
126
|
name: 'update key'
|
|
139
127
|
}),
|
|
140
128
|
stagedUpdateKeyMultibase: requireConnectCodeKey({
|
|
141
129
|
value: stagedUpdateKeyMultibase,
|
|
142
130
|
prefix: ED25519_MULTIBASE_PREFIX,
|
|
143
|
-
|
|
131
|
+
expectedCodec: MultikeyCodec.ED25519_PUB,
|
|
144
132
|
name: 'staged update key'
|
|
145
133
|
})
|
|
146
134
|
};
|