@interop/wallet-core 0.41.0 → 0.42.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 +22 -15
- package/dist/clients/rosterPolicy.d.ts.map +1 -1
- package/dist/clients/rosterPolicy.js +32 -15
- 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/dist/resourceLog/pin.js
CHANGED
|
@@ -11,21 +11,46 @@
|
|
|
11
11
|
* adopted. Storage is the app's concern (freewallet: beside its other pins in
|
|
12
12
|
* localStorage; DCW: a table row), so only the seam lives here, plus an
|
|
13
13
|
* in-memory implementation for tests and single-session use.
|
|
14
|
+
*
|
|
15
|
+
* The seam is keyed: every read and write names the log it concerns with a
|
|
16
|
+
* `logId`, so one store instance serves every log a wallet holds. Wallet-core
|
|
17
|
+
* supplies the key at every call, built by {@link resourceLogPinId} (or one of
|
|
18
|
+
* the named builders over it), so an app implements one keyed store and never
|
|
19
|
+
* chooses keys itself.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* The pin-slot key for one log: an opaque per-log identity key for pin
|
|
23
|
+
* storage, not a fetchable path or URL.
|
|
24
|
+
*
|
|
25
|
+
* It is deliberately host-free. The `spaceId` is the account's stable random
|
|
26
|
+
* id, so a log served from a claimed new host lands in the SAME pin slot and
|
|
27
|
+
* is checked against the pin already held, rather than opening a fresh
|
|
28
|
+
* trust-on-first-use slate (the mirror-fork concern).
|
|
29
|
+
*
|
|
30
|
+
* @param options {object}
|
|
31
|
+
* @param options.spaceId {string} the Space the log lives in
|
|
32
|
+
* @param options.collectionId {string} the collection holding the log
|
|
33
|
+
* @param options.resourceId {string} the log resource's id
|
|
34
|
+
* @returns {string}
|
|
14
35
|
*/
|
|
36
|
+
export function resourceLogPinId({ spaceId, collectionId, resourceId }) {
|
|
37
|
+
return `space/${spaceId}/${collectionId}/${resourceId}`;
|
|
38
|
+
}
|
|
15
39
|
/**
|
|
16
|
-
* An in-memory pin store: continuity within one session only
|
|
17
|
-
*
|
|
40
|
+
* An in-memory pin store: continuity within one session only, keyed by
|
|
41
|
+
* `logId` like any other implementation, so one instance serves several logs.
|
|
42
|
+
* Tests use it as the seam's reference implementation; apps persist for real.
|
|
18
43
|
*
|
|
19
44
|
* @returns {ResourceLogPinStore}
|
|
20
45
|
*/
|
|
21
46
|
export function memoryResourceLogPinStore() {
|
|
22
|
-
|
|
47
|
+
const pins = new Map();
|
|
23
48
|
return {
|
|
24
|
-
async read() {
|
|
25
|
-
return
|
|
49
|
+
async read({ logId }) {
|
|
50
|
+
return pins.get(logId) ?? null;
|
|
26
51
|
},
|
|
27
|
-
async write(
|
|
28
|
-
pin
|
|
52
|
+
async write({ logId, pin }) {
|
|
53
|
+
pins.set(logId, pin);
|
|
29
54
|
}
|
|
30
55
|
};
|
|
31
56
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pin.js","sourceRoot":"","sources":["../../src/resourceLog/pin.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"pin.js","sourceRoot":"","sources":["../../src/resourceLog/pin.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;GAgBG;AAgCH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,OAAO,EACP,YAAY,EACZ,UAAU,EAKX;IACC,OAAO,SAAS,OAAO,IAAI,YAAY,IAAI,UAAU,EAAE,CAAA;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAA8B,CAAA;IAClD,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE;YAClB,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAA;QAChC,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;YACxB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACtB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -67,6 +67,8 @@ export declare function latestAssertionRemovalIndex({ controller }: {
|
|
|
67
67
|
* @param options.expectedMethod {string} the format identifier expected
|
|
68
68
|
* @param options.pinStore {ResourceLogPinStore} this client's chain-head
|
|
69
69
|
* pin for this log
|
|
70
|
+
* @param options.logId {string} the pin-slot key for this log, from
|
|
71
|
+
* `resourceLogPinId`
|
|
70
72
|
* @param options.signer {ResourceLogSigner} this client's enrolled signing
|
|
71
73
|
* key
|
|
72
74
|
* @param [options.versionTime] {string} RFC3339 UTC; defaults to now
|
|
@@ -79,11 +81,12 @@ export declare function latestAssertionRemovalIndex({ controller }: {
|
|
|
79
81
|
* anything is written
|
|
80
82
|
* @returns {Promise<{ sealed: boolean, verified: VerifiedResourceLog | null }>}
|
|
81
83
|
*/
|
|
82
|
-
export declare function sealResourceLog({ store, controller, expectedMethod, pinStore, signer, versionTime, verified: knownVerified }: {
|
|
84
|
+
export declare function sealResourceLog({ store, controller, expectedMethod, pinStore, logId, signer, versionTime, verified: knownVerified }: {
|
|
83
85
|
store: ResourceLogStore;
|
|
84
86
|
controller: ResourceLogController;
|
|
85
87
|
expectedMethod: string;
|
|
86
88
|
pinStore: ResourceLogPinStore;
|
|
89
|
+
logId: string;
|
|
87
90
|
signer: ResourceLogSigner;
|
|
88
91
|
versionTime?: string;
|
|
89
92
|
verified?: VerifiedResourceLog;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../src/resourceLog/seal.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEtD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,2BAA2B,CAAC,EAChD,UAAU,EACX,EAAE;IACD,UAAU,EAAE,qBAAqB,CAAA;CAClC,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBlB;AAED
|
|
1
|
+
{"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../src/resourceLog/seal.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEtD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,2BAA2B,CAAC,EAChD,UAAU,EACX,EAAE;IACD,UAAU,EAAE,qBAAqB,CAAA;CAClC,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBlB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,eAAe,CAAC,EACpC,KAAK,EACL,UAAU,EACV,cAAc,EACd,QAAQ,EACR,KAAK,EACL,MAAM,EACN,WAAW,EACX,QAAQ,EAAE,aAAa,EACxB,EAAE;IACD,KAAK,EAAE,gBAAgB,CAAA;IACvB,UAAU,EAAE,qBAAqB,CAAA;IACjC,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,iBAAiB,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,mBAAmB,CAAA;CAC/B,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAAE,CAAC,CA6CrE"}
|
package/dist/resourceLog/seal.js
CHANGED
|
@@ -53,6 +53,8 @@ export async function latestAssertionRemovalIndex({ controller }) {
|
|
|
53
53
|
* @param options.expectedMethod {string} the format identifier expected
|
|
54
54
|
* @param options.pinStore {ResourceLogPinStore} this client's chain-head
|
|
55
55
|
* pin for this log
|
|
56
|
+
* @param options.logId {string} the pin-slot key for this log, from
|
|
57
|
+
* `resourceLogPinId`
|
|
56
58
|
* @param options.signer {ResourceLogSigner} this client's enrolled signing
|
|
57
59
|
* key
|
|
58
60
|
* @param [options.versionTime] {string} RFC3339 UTC; defaults to now
|
|
@@ -65,7 +67,7 @@ export async function latestAssertionRemovalIndex({ controller }) {
|
|
|
65
67
|
* anything is written
|
|
66
68
|
* @returns {Promise<{ sealed: boolean, verified: VerifiedResourceLog | null }>}
|
|
67
69
|
*/
|
|
68
|
-
export async function sealResourceLog({ store, controller, expectedMethod, pinStore, signer, versionTime, verified: knownVerified }) {
|
|
70
|
+
export async function sealResourceLog({ store, controller, expectedMethod, pinStore, logId, signer, versionTime, verified: knownVerified }) {
|
|
69
71
|
if (controller.versionIds.length === 0) {
|
|
70
72
|
return { sealed: false, verified: null };
|
|
71
73
|
}
|
|
@@ -79,7 +81,8 @@ export async function sealResourceLog({ store, controller, expectedMethod, pinSt
|
|
|
79
81
|
store,
|
|
80
82
|
controller,
|
|
81
83
|
expectedMethod,
|
|
82
|
-
pinStore
|
|
84
|
+
pinStore,
|
|
85
|
+
logId
|
|
83
86
|
});
|
|
84
87
|
if (current === null) {
|
|
85
88
|
return { sealed: false, verified: null };
|
|
@@ -95,6 +98,7 @@ export async function sealResourceLog({ store, controller, expectedMethod, pinSt
|
|
|
95
98
|
controller,
|
|
96
99
|
expectedMethod,
|
|
97
100
|
pinStore,
|
|
101
|
+
logId,
|
|
98
102
|
signer,
|
|
99
103
|
// The rebase hook doubles as the convergence check: a concurrent writer
|
|
100
104
|
// whose entry already anchors past the removal sealed the log for us.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seal.js","sourceRoot":"","sources":["../../src/resourceLog/seal.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAMhE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,EAChD,UAAU,EAGX;IACC,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,IAAI,QAAQ,GAAuB,IAAI,CAAA;IACvC,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;QACxD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACnB,YAAY,GAAG,KAAK,CAAA;oBACpB,MAAK;gBACP,CAAC;YACH,CAAC;QACH,CAAC;QACD,QAAQ,GAAG,IAAI,CAAA;IACjB,CAAC;IACD,OAAO,YAAY,CAAA;AACrB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"seal.js","sourceRoot":"","sources":["../../src/resourceLog/seal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The `@interop/wallet-core/unlock` subpath: standing unlock credentials --
|
|
6
|
+
* every unlock method (passphrase, passkey PRF, recovery code) as a standing
|
|
7
|
+
* credential in the recovery-code posture, with self-enrolling login. The
|
|
8
|
+
* recovery subpath's spend-on-use flows sit on top of the machinery here.
|
|
9
|
+
*
|
|
10
|
+
* - `standingClientFromUnlockSeed` / `unlockClientIdentityFromSeed` -- the
|
|
11
|
+
* deterministic client identity a credential derives (roster wrap target,
|
|
12
|
+
* binding MAC key), shared with the recovery-code derivation.
|
|
13
|
+
* - `generateLadderSeed` / `ladderRung` / `attributeLadderRung` -- the
|
|
14
|
+
* update-key ladder: latent-and-consumed did:webvh update authority from a
|
|
15
|
+
* random seed carried in the unlock record, current rung recovered from the
|
|
16
|
+
* log itself, ambiguity failing closed.
|
|
17
|
+
* - `wrapUnlockRecord` / `unwrapUnlockRecord` / `remintUnlockRecordBridge` --
|
|
18
|
+
* the unlock record codec: the credential-authenticated shell-and-core
|
|
19
|
+
* layout (controller, email, pointer under the binding MAC; the bridge
|
|
20
|
+
* delegation re-mintable; the ladder seed sealed and carried verbatim).
|
|
21
|
+
* - `publishUnlockKey` / `removeUnlockKey` -- the merged document posture
|
|
22
|
+
* edit, parameterized by credential class: a verbatim `keyAgreement` entry,
|
|
23
|
+
* or a `MultikeyCommitment` entry for a low-entropy-derived key.
|
|
24
|
+
* - `selfEnrollWebvhClient` / `selfEnrollClientCore` -- the self-enrolling
|
|
25
|
+
* continuation (reveal a rung, add an ordinary client, retire the rung) and
|
|
26
|
+
* the composed completion a fresh browser runs end to end.
|
|
27
|
+
*
|
|
28
|
+
* Kept out of the root export: this subpath pulls the webkms-client / ezcap /
|
|
29
|
+
* was-client dependency graph (the same isolation pattern as `./keyring`).
|
|
30
|
+
*/
|
|
31
|
+
export { standingClientFromUnlockSeed, STANDING_CLIENT_SALT, unlockClientIdentityFromSeed } from './standingClient.js';
|
|
32
|
+
export type { StandingUnlockClient, UnlockClientIdentity } from './standingClient.js';
|
|
33
|
+
export { attributeLadderRung, generateLadderSeed, LADDER_MAX_SCAN, LADDER_SEED_BYTES, LadderAttributionError, ladderRung, ladderRungSeed } from './ladder.js';
|
|
34
|
+
export type { LadderRung, LadderRungState } from './ladder.js';
|
|
35
|
+
export { computeUnlockBinding, remintUnlockRecordBridge, UnlockBindingError, unlockRecordBinding, unwrapUnlockRecord, wrapUnlockRecord } from './unlockRecord.js';
|
|
36
|
+
export type { SealedRecordMember, SignedUnlockRecord, UnlockRecordContents, UnlockRecordProofState } from './unlockRecord.js';
|
|
37
|
+
export { publishUnlockKey, removeUnlockKey, selfEnrollWebvhClient, unlockKeyVerificationMethod, unlockKeyVmId } from './standingWebvh.js';
|
|
38
|
+
export type { StandingUnlockKeys, UnlockKeyAgreementPublication, UnlockLogStore } from './standingWebvh.js';
|
|
39
|
+
export { selfEnrollClientCore } from './selfEnroll.js';
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/unlock/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,4BAA4B,EAC7B,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,cAAc,EACf,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE9D,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,2BAA2B,EAC3B,aAAa,EACd,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,kBAAkB,EAClB,6BAA6B,EAC7B,cAAc,EACf,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The `@interop/wallet-core/unlock` subpath: standing unlock credentials --
|
|
6
|
+
* every unlock method (passphrase, passkey PRF, recovery code) as a standing
|
|
7
|
+
* credential in the recovery-code posture, with self-enrolling login. The
|
|
8
|
+
* recovery subpath's spend-on-use flows sit on top of the machinery here.
|
|
9
|
+
*
|
|
10
|
+
* - `standingClientFromUnlockSeed` / `unlockClientIdentityFromSeed` -- the
|
|
11
|
+
* deterministic client identity a credential derives (roster wrap target,
|
|
12
|
+
* binding MAC key), shared with the recovery-code derivation.
|
|
13
|
+
* - `generateLadderSeed` / `ladderRung` / `attributeLadderRung` -- the
|
|
14
|
+
* update-key ladder: latent-and-consumed did:webvh update authority from a
|
|
15
|
+
* random seed carried in the unlock record, current rung recovered from the
|
|
16
|
+
* log itself, ambiguity failing closed.
|
|
17
|
+
* - `wrapUnlockRecord` / `unwrapUnlockRecord` / `remintUnlockRecordBridge` --
|
|
18
|
+
* the unlock record codec: the credential-authenticated shell-and-core
|
|
19
|
+
* layout (controller, email, pointer under the binding MAC; the bridge
|
|
20
|
+
* delegation re-mintable; the ladder seed sealed and carried verbatim).
|
|
21
|
+
* - `publishUnlockKey` / `removeUnlockKey` -- the merged document posture
|
|
22
|
+
* edit, parameterized by credential class: a verbatim `keyAgreement` entry,
|
|
23
|
+
* or a `MultikeyCommitment` entry for a low-entropy-derived key.
|
|
24
|
+
* - `selfEnrollWebvhClient` / `selfEnrollClientCore` -- the self-enrolling
|
|
25
|
+
* continuation (reveal a rung, add an ordinary client, retire the rung) and
|
|
26
|
+
* the composed completion a fresh browser runs end to end.
|
|
27
|
+
*
|
|
28
|
+
* Kept out of the root export: this subpath pulls the webkms-client / ezcap /
|
|
29
|
+
* was-client dependency graph (the same isolation pattern as `./keyring`).
|
|
30
|
+
*/
|
|
31
|
+
export { standingClientFromUnlockSeed, STANDING_CLIENT_SALT, unlockClientIdentityFromSeed } from './standingClient.js';
|
|
32
|
+
export { attributeLadderRung, generateLadderSeed, LADDER_MAX_SCAN, LADDER_SEED_BYTES, LadderAttributionError, ladderRung, ladderRungSeed } from './ladder.js';
|
|
33
|
+
export { computeUnlockBinding, remintUnlockRecordBridge, UnlockBindingError, unlockRecordBinding, unwrapUnlockRecord, wrapUnlockRecord } from './unlockRecord.js';
|
|
34
|
+
export { publishUnlockKey, removeUnlockKey, selfEnrollWebvhClient, unlockKeyVerificationMethod, unlockKeyVmId } from './standingWebvh.js';
|
|
35
|
+
export { selfEnrollClientCore } from './selfEnroll.js';
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/unlock/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,4BAA4B,EAC7B,MAAM,qBAAqB,CAAA;AAM5B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,cAAc,EACf,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,mBAAmB,CAAA;AAQ1B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,2BAA2B,EAC3B,aAAa,EACd,MAAM,oBAAoB,CAAA;AAO3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The byte length of a ladder seed: 32 random bytes, minted at bind time and
|
|
3
|
+
* carried only inside the unlock record's sealed ladder member.
|
|
4
|
+
*/
|
|
5
|
+
export declare const LADDER_SEED_BYTES = 32;
|
|
6
|
+
/**
|
|
7
|
+
* How many rungs {@link attributeLadderRung} derives before concluding the
|
|
8
|
+
* log commits none of them. Generous: one rung is consumed per
|
|
9
|
+
* self-enrollment, so a real ladder's standing commitment sits at the number
|
|
10
|
+
* of self-enrollments the credential has ever performed.
|
|
11
|
+
*/
|
|
12
|
+
export declare const LADDER_MAX_SCAN = 128;
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when the published log's standing parameters match no derivable rung
|
|
15
|
+
* -- the credential's posture was revoked (or never published), the ladder
|
|
16
|
+
* seed does not belong to this account, or the scan bound was exceeded -- or
|
|
17
|
+
* when they match more than one rung in the same role, which no legitimate
|
|
18
|
+
* history produces. Self-enrollment refuses loudly rather than guessing.
|
|
19
|
+
*/
|
|
20
|
+
export declare class LadderAttributionError extends Error {
|
|
21
|
+
constructor(message: string);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generates a fresh random ladder seed.
|
|
25
|
+
*
|
|
26
|
+
* @returns {Uint8Array}
|
|
27
|
+
*/
|
|
28
|
+
export declare function generateLadderSeed(): Uint8Array;
|
|
29
|
+
/**
|
|
30
|
+
* One rung of the ladder: its index, the 32-byte Ed25519 seed behind it, and
|
|
31
|
+
* the update key's public multibase as the log carries it.
|
|
32
|
+
*/
|
|
33
|
+
export interface LadderRung {
|
|
34
|
+
index: number;
|
|
35
|
+
seed: Uint8Array;
|
|
36
|
+
keyMultibase: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Derives the 32-byte update-key seed of rung `index`.
|
|
40
|
+
*
|
|
41
|
+
* @param options {object}
|
|
42
|
+
* @param options.ladderSeed {Uint8Array}
|
|
43
|
+
* @param options.index {number} the rung index, from 0
|
|
44
|
+
* @returns {Uint8Array}
|
|
45
|
+
*/
|
|
46
|
+
export declare function ladderRungSeed({ ladderSeed, index }: {
|
|
47
|
+
ladderSeed: Uint8Array;
|
|
48
|
+
index: number;
|
|
49
|
+
}): Uint8Array;
|
|
50
|
+
/**
|
|
51
|
+
* Derives rung `index` in full: seed and public multibase.
|
|
52
|
+
*
|
|
53
|
+
* @param options {object}
|
|
54
|
+
* @param options.ladderSeed {Uint8Array}
|
|
55
|
+
* @param options.index {number} the rung index, from 0
|
|
56
|
+
* @returns {Promise<LadderRung>}
|
|
57
|
+
*/
|
|
58
|
+
export declare function ladderRung({ ladderSeed, index }: {
|
|
59
|
+
ladderSeed: Uint8Array;
|
|
60
|
+
index: number;
|
|
61
|
+
}): Promise<LadderRung>;
|
|
62
|
+
/**
|
|
63
|
+
* Where an attributed rung stands in the published log: `'committed'` (the
|
|
64
|
+
* steady state -- only its hash stands in `nextKeyHashes`) or `'revealed'` (a
|
|
65
|
+
* torn self-enrollment published the reveal entry but not the add entry, so
|
|
66
|
+
* the rung sits in `updateKeys` awaiting the resumed add).
|
|
67
|
+
*/
|
|
68
|
+
export type LadderRungState = 'committed' | 'revealed';
|
|
69
|
+
/**
|
|
70
|
+
* Recovers the ladder's current rung from the published log's standing
|
|
71
|
+
* parameters -- the counter recovery that replaces any stored counter. Scans
|
|
72
|
+
* rungs `0..maxScan - 1`; a rung whose key stands in `updateKeys` is a torn
|
|
73
|
+
* self-enrollment to resume (`'revealed'`), else a rung whose hash stands in
|
|
74
|
+
* `nextKeyHashes` is the standing commitment (`'committed'`). Exactly one
|
|
75
|
+
* revealed rung, or exactly one committed rung beside it, is legitimate --
|
|
76
|
+
* the reveal entry keeps the spent rung's hash committed so a resumed run can
|
|
77
|
+
* re-state it, which is why a revealed rung wins over a committed one.
|
|
78
|
+
* Anything else fails closed with {@link LadderAttributionError}.
|
|
79
|
+
*
|
|
80
|
+
* @param options {object}
|
|
81
|
+
* @param options.ladderSeed {Uint8Array}
|
|
82
|
+
* @param options.published {object} the resolved log's standing parameters
|
|
83
|
+
* @param options.published.updateKeys {string[]}
|
|
84
|
+
* @param options.published.nextKeyHashes {string[]}
|
|
85
|
+
* @param [options.maxScan] {number} how many rungs to derive before giving
|
|
86
|
+
* up; defaults to {@link LADDER_MAX_SCAN}
|
|
87
|
+
* @returns {Promise<{ rung: LadderRung, state: LadderRungState }>}
|
|
88
|
+
*/
|
|
89
|
+
export declare function attributeLadderRung({ ladderSeed, published, maxScan }: {
|
|
90
|
+
ladderSeed: Uint8Array;
|
|
91
|
+
published: {
|
|
92
|
+
updateKeys: string[];
|
|
93
|
+
nextKeyHashes: string[];
|
|
94
|
+
};
|
|
95
|
+
maxScan?: number;
|
|
96
|
+
}): Promise<{
|
|
97
|
+
rung: LadderRung;
|
|
98
|
+
state: LadderRungState;
|
|
99
|
+
}>;
|
|
100
|
+
//# sourceMappingURL=ladder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ladder.d.ts","sourceRoot":"","sources":["../../src/unlock/ladder.ts"],"names":[],"mappings":"AAiCA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAUnC;;;;;GAKG;AACH,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC;;;;;;GAMG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,KAAK,EACN,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;CACd,GAAG,UAAU,CAWb;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,EAC/B,UAAU,EACV,KAAK,EACN,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,UAAU,CAAC,CAGtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,UAAU,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,UAAU,EACV,SAAS,EACT,OAAyB,EAC1B,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAAE,CAAC,CA+BxD"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The update-key ladder: a standing unlock credential's latent-and-consumed
|
|
6
|
+
* did:webvh update authority. Rungs derive deterministically from a random
|
|
7
|
+
* 32-byte ladder seed carried inside the credential's unlock record -- never
|
|
8
|
+
* from the unlock secret itself, because a revealed rung lives verbatim in
|
|
9
|
+
* the world-readable `updateKeys` forever, where no hash commitment can
|
|
10
|
+
* protect it, so a secret-derived rung would be a standing offline grind
|
|
11
|
+
* oracle against the credential.
|
|
12
|
+
*
|
|
13
|
+
* Between uses only `hash(rung i)` stands in the document's `nextKeyHashes`;
|
|
14
|
+
* each self-enrollment is one loud reveal-and-commit entry signing with rung
|
|
15
|
+
* `i` and committing `hash(rung i + 1)`, after which the add entry retires
|
|
16
|
+
* the spent rung. The credential never holds a standing `updateKeys` member.
|
|
17
|
+
*
|
|
18
|
+
* There is no stored counter: which rung is current is recovered by
|
|
19
|
+
* re-deriving and scanning the published log's standing parameters
|
|
20
|
+
* ({@link attributeLadderRung}), and ambiguity fails closed rather than
|
|
21
|
+
* guessing -- the clients-listing attribution precedent. A lost
|
|
22
|
+
* compare-and-swap race resolves by determinism: the winner's entry commits
|
|
23
|
+
* `hash(rung i + 1)`, which IS the loser's retry key, so a re-run
|
|
24
|
+
* re-attributes and climbs one rung.
|
|
25
|
+
*
|
|
26
|
+
* The rung derivation is wire-level (both wallet apps must climb the same
|
|
27
|
+
* ladder from the same seed), so the salt and info labels are permanent.
|
|
28
|
+
*/
|
|
29
|
+
import { deriveNextKeyHash } from '@interop/did-method-webvh';
|
|
30
|
+
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
31
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
32
|
+
import { updateKeyMultibase } from '../webvh/didWebvh.js';
|
|
33
|
+
/**
|
|
34
|
+
* The byte length of a ladder seed: 32 random bytes, minted at bind time and
|
|
35
|
+
* carried only inside the unlock record's sealed ladder member.
|
|
36
|
+
*/
|
|
37
|
+
export const LADDER_SEED_BYTES = 32;
|
|
38
|
+
/**
|
|
39
|
+
* The HKDF salt for rung derivation and the per-rung info prefix (the rung
|
|
40
|
+
* index in decimal follows it). Both permanent -- changing either orphans
|
|
41
|
+
* every bound credential's ladder.
|
|
42
|
+
*/
|
|
43
|
+
const LADDER_SALT = 'freewallet/unlock/update-ladder/v1';
|
|
44
|
+
const LADDER_RUNG_INFO_PREFIX = 'rung/';
|
|
45
|
+
/**
|
|
46
|
+
* How many rungs {@link attributeLadderRung} derives before concluding the
|
|
47
|
+
* log commits none of them. Generous: one rung is consumed per
|
|
48
|
+
* self-enrollment, so a real ladder's standing commitment sits at the number
|
|
49
|
+
* of self-enrollments the credential has ever performed.
|
|
50
|
+
*/
|
|
51
|
+
export const LADDER_MAX_SCAN = 128;
|
|
52
|
+
/**
|
|
53
|
+
* Thrown when the published log's standing parameters match no derivable rung
|
|
54
|
+
* -- the credential's posture was revoked (or never published), the ladder
|
|
55
|
+
* seed does not belong to this account, or the scan bound was exceeded -- or
|
|
56
|
+
* when they match more than one rung in the same role, which no legitimate
|
|
57
|
+
* history produces. Self-enrollment refuses loudly rather than guessing.
|
|
58
|
+
*/
|
|
59
|
+
export class LadderAttributionError extends Error {
|
|
60
|
+
constructor(message) {
|
|
61
|
+
super(message);
|
|
62
|
+
this.name = 'LadderAttributionError';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generates a fresh random ladder seed.
|
|
67
|
+
*
|
|
68
|
+
* @returns {Uint8Array}
|
|
69
|
+
*/
|
|
70
|
+
export function generateLadderSeed() {
|
|
71
|
+
return crypto.getRandomValues(new Uint8Array(LADDER_SEED_BYTES));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Derives the 32-byte update-key seed of rung `index`.
|
|
75
|
+
*
|
|
76
|
+
* @param options {object}
|
|
77
|
+
* @param options.ladderSeed {Uint8Array}
|
|
78
|
+
* @param options.index {number} the rung index, from 0
|
|
79
|
+
* @returns {Uint8Array}
|
|
80
|
+
*/
|
|
81
|
+
export function ladderRungSeed({ ladderSeed, index }) {
|
|
82
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
83
|
+
throw new Error(`Invalid ladder rung index "${String(index)}".`);
|
|
84
|
+
}
|
|
85
|
+
return hkdf(sha256, ladderSeed, new TextEncoder().encode(LADDER_SALT), new TextEncoder().encode(`${LADDER_RUNG_INFO_PREFIX}${index}`), 32);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Derives rung `index` in full: seed and public multibase.
|
|
89
|
+
*
|
|
90
|
+
* @param options {object}
|
|
91
|
+
* @param options.ladderSeed {Uint8Array}
|
|
92
|
+
* @param options.index {number} the rung index, from 0
|
|
93
|
+
* @returns {Promise<LadderRung>}
|
|
94
|
+
*/
|
|
95
|
+
export async function ladderRung({ ladderSeed, index }) {
|
|
96
|
+
const seed = ladderRungSeed({ ladderSeed, index });
|
|
97
|
+
return { index, seed, keyMultibase: await updateKeyMultibase({ seed }) };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Recovers the ladder's current rung from the published log's standing
|
|
101
|
+
* parameters -- the counter recovery that replaces any stored counter. Scans
|
|
102
|
+
* rungs `0..maxScan - 1`; a rung whose key stands in `updateKeys` is a torn
|
|
103
|
+
* self-enrollment to resume (`'revealed'`), else a rung whose hash stands in
|
|
104
|
+
* `nextKeyHashes` is the standing commitment (`'committed'`). Exactly one
|
|
105
|
+
* revealed rung, or exactly one committed rung beside it, is legitimate --
|
|
106
|
+
* the reveal entry keeps the spent rung's hash committed so a resumed run can
|
|
107
|
+
* re-state it, which is why a revealed rung wins over a committed one.
|
|
108
|
+
* Anything else fails closed with {@link LadderAttributionError}.
|
|
109
|
+
*
|
|
110
|
+
* @param options {object}
|
|
111
|
+
* @param options.ladderSeed {Uint8Array}
|
|
112
|
+
* @param options.published {object} the resolved log's standing parameters
|
|
113
|
+
* @param options.published.updateKeys {string[]}
|
|
114
|
+
* @param options.published.nextKeyHashes {string[]}
|
|
115
|
+
* @param [options.maxScan] {number} how many rungs to derive before giving
|
|
116
|
+
* up; defaults to {@link LADDER_MAX_SCAN}
|
|
117
|
+
* @returns {Promise<{ rung: LadderRung, state: LadderRungState }>}
|
|
118
|
+
*/
|
|
119
|
+
export async function attributeLadderRung({ ladderSeed, published, maxScan = LADDER_MAX_SCAN }) {
|
|
120
|
+
const revealed = [];
|
|
121
|
+
const committed = [];
|
|
122
|
+
for (let index = 0; index < maxScan; index++) {
|
|
123
|
+
const rung = await ladderRung({ ladderSeed, index });
|
|
124
|
+
if (published.updateKeys.includes(rung.keyMultibase)) {
|
|
125
|
+
revealed.push(rung);
|
|
126
|
+
}
|
|
127
|
+
else if (published.nextKeyHashes.includes(await deriveNextKeyHash(rung.keyMultibase))) {
|
|
128
|
+
committed.push(rung);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (revealed.length > 1 || committed.length > 1) {
|
|
132
|
+
throw new LadderAttributionError('The published log commits more than one rung of this ladder in the ' +
|
|
133
|
+
'same role; refusing to self-enroll on an ambiguous attribution.');
|
|
134
|
+
}
|
|
135
|
+
if (revealed.length === 1) {
|
|
136
|
+
return { rung: revealed[0], state: 'revealed' };
|
|
137
|
+
}
|
|
138
|
+
if (committed.length === 1) {
|
|
139
|
+
return { rung: committed[0], state: 'committed' };
|
|
140
|
+
}
|
|
141
|
+
throw new LadderAttributionError('The published log commits no rung of this ladder; the credential has ' +
|
|
142
|
+
'been revoked, was never published, or does not belong to this account.');
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=ladder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ladder.js","sourceRoot":"","sources":["../../src/unlock/ladder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The self-enrollment completion core: what a fresh browser runs once its
|
|
6
|
+
* typed credential has located the account, proven the unlock record genuine,
|
|
7
|
+
* and handed over the bridge delegation and the ladder seed. One call turns
|
|
8
|
+
* the credential's latent authority into an ordinary enrolled client, with no
|
|
9
|
+
* second party involved:
|
|
10
|
+
*
|
|
11
|
+
* 1. Mint the new client's whole key set locally (client seed, did:webvh
|
|
12
|
+
* update-key seeds). Nothing is durable before the ceremony succeeds.
|
|
13
|
+
* 2. Write the self-enrolling continuation through the delegated `did.jsonl`
|
|
14
|
+
* bridge ({@link selfEnrollWebvhClient}): the reveal-and-commit entry
|
|
15
|
+
* signed by the attributed ladder rung, then the add entry that publishes
|
|
16
|
+
* the new client and retires the rung. Loud by construction -- the
|
|
17
|
+
* world-readable, hash-chained log extends before a single byte can be
|
|
18
|
+
* read.
|
|
19
|
+
* 3. Verify the account log locally and perform the first roster read,
|
|
20
|
+
* signed with the just-published `<did:webvh>#<multibase>` key and
|
|
21
|
+
* unwrapping the user key from the CREDENTIAL's standing wrap (escrowed
|
|
22
|
+
* into every epoch at bind time, kept alive by rotation fan-out).
|
|
23
|
+
* 4. Escrow the new client into the roster as its own recipient
|
|
24
|
+
* (`addUserKeyRosterRecipient`, epochs unwrapped with the credential's
|
|
25
|
+
* key-agreement key), so later logins on this browser read the roster the
|
|
26
|
+
* ordinary enrolled way.
|
|
27
|
+
*
|
|
28
|
+
* Persisting the key set under the app's own unlock layer is the caller's
|
|
29
|
+
* job, exactly as with the enrollment ceremony's completion: this module
|
|
30
|
+
* hands back the key set, the user key, and the roster epoch to pin, and
|
|
31
|
+
* stops there. Every stage is idempotent, so a torn run converges by
|
|
32
|
+
* re-running with the same credential (step 2 resumes from the standing
|
|
33
|
+
* commitments; a re-run after completion mints a fresh client, which is the
|
|
34
|
+
* ordinary next self-enrollment).
|
|
35
|
+
*/
|
|
36
|
+
import type { IKeyAgreementKey } from '@interop/data-integrity-core';
|
|
37
|
+
import type { UserKey } from '../keys/userKey.js';
|
|
38
|
+
import type { AccountPointer } from '../keyring/record.js';
|
|
39
|
+
import { type ResourceLogPinStore } from '../resourceLog/index.js';
|
|
40
|
+
import type { ClientWebvhUpdateKeys } from '../webvh/didWebvh.js';
|
|
41
|
+
import type { UnlockLogStore } from './standingWebvh.js';
|
|
42
|
+
/**
|
|
43
|
+
* Runs the whole self-enrollment described in the module doc. The caller has
|
|
44
|
+
* already unwrapped the credential's unlock record (so it holds the
|
|
45
|
+
* credential-authenticated pointer, the bridge delegation behind `logStore`,
|
|
46
|
+
* and the ladder seed) and derived the credential's client identity (so it
|
|
47
|
+
* holds the key-agreement key with its secret half).
|
|
48
|
+
*
|
|
49
|
+
* @param options {object}
|
|
50
|
+
* @param options.pointer {AccountPointer} the credential-authenticated
|
|
51
|
+
* account pointer; must name a did:webvh
|
|
52
|
+
* @param options.ladderSeed {Uint8Array} the credential's update-key ladder
|
|
53
|
+
* seed, from its unlock record
|
|
54
|
+
* @param options.credentialKeyAgreementKey {IKeyAgreementKey} the
|
|
55
|
+
* credential's own key-agreement key (secret half included) -- its roster
|
|
56
|
+
* entry, which the user key is unwrapped from and every epoch re-wrapped
|
|
57
|
+
* with
|
|
58
|
+
* @param options.logStore {UnlockLogStore} the public log read plus the
|
|
59
|
+
* delegated `did.jsonl` PUT, built by the app around the record's bridge
|
|
60
|
+
* delegation
|
|
61
|
+
* @param [options.accountLogPinStore] {ResourceLogPinStore} this client's
|
|
62
|
+
* chain-head pin for the account log. A fresh browser normally has none
|
|
63
|
+
* (this is its first contact), which is exactly the pin's
|
|
64
|
+
* trust-on-first-use establishment
|
|
65
|
+
* @returns {Promise<object>} the new client's key set (for the caller to
|
|
66
|
+
* persist under its unlock layer), its did:key, the account DID, the user
|
|
67
|
+
* key, and the roster epoch to pin
|
|
68
|
+
*/
|
|
69
|
+
export declare function selfEnrollClientCore({ pointer, ladderSeed, credentialKeyAgreementKey, logStore, accountLogPinStore }: {
|
|
70
|
+
pointer: AccountPointer;
|
|
71
|
+
ladderSeed: Uint8Array;
|
|
72
|
+
credentialKeyAgreementKey: IKeyAgreementKey;
|
|
73
|
+
logStore: UnlockLogStore;
|
|
74
|
+
accountLogPinStore?: ResourceLogPinStore;
|
|
75
|
+
}): Promise<{
|
|
76
|
+
clientSeed: Uint8Array;
|
|
77
|
+
webvhUpdateKeys: ClientWebvhUpdateKeys;
|
|
78
|
+
clientDid: string;
|
|
79
|
+
did: string;
|
|
80
|
+
userKey: UserKey;
|
|
81
|
+
latestEpochId: string;
|
|
82
|
+
}>;
|
|
83
|
+
//# sourceMappingURL=selfEnroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selfEnroll.d.ts","sourceRoot":"","sources":["../../src/unlock/selfEnroll.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AASpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAA;AAKhC,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,sBAAsB,CAAA;AAQ7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,OAAO,EACP,UAAU,EACV,yBAAyB,EACzB,QAAQ,EACR,kBAAkB,EACnB,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,UAAU,CAAA;IACtB,yBAAyB,EAAE,gBAAgB,CAAA;IAC3C,QAAQ,EAAE,cAAc,CAAA;IACxB,kBAAkB,CAAC,EAAE,mBAAmB,CAAA;CACzC,GAAG,OAAO,CAAC;IACV,UAAU,EAAE,UAAU,CAAA;IACtB,eAAe,EAAE,qBAAqB,CAAA;IACtC,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAC,CAqGD"}
|