@interop/wallet-core 0.5.0 → 0.7.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/dist/enrollment/enrollment.d.ts +144 -0
- package/dist/enrollment/enrollment.d.ts.map +1 -0
- package/dist/enrollment/enrollment.js +296 -0
- package/dist/enrollment/enrollment.js.map +1 -0
- package/dist/enrollment/index.d.ts +20 -0
- package/dist/enrollment/index.d.ts.map +1 -0
- package/dist/enrollment/index.js +19 -0
- package/dist/enrollment/index.js.map +1 -0
- package/dist/identity/index.d.ts +0 -5
- package/dist/identity/index.d.ts.map +1 -1
- package/dist/identity/index.js +0 -4
- package/dist/identity/index.js.map +1 -1
- package/dist/index.d.ts +16 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -3
- package/dist/index.js.map +1 -1
- package/dist/keyring/fetch.d.ts +22 -0
- package/dist/keyring/fetch.d.ts.map +1 -0
- package/dist/keyring/fetch.js +35 -0
- package/dist/keyring/fetch.js.map +1 -0
- package/dist/keyring/index.d.ts +30 -0
- package/dist/keyring/index.d.ts.map +1 -0
- package/dist/keyring/index.js +28 -0
- package/dist/keyring/index.js.map +1 -0
- package/dist/keyring/kdf.d.ts +102 -0
- package/dist/keyring/kdf.d.ts.map +1 -0
- package/dist/keyring/kdf.js +148 -0
- package/dist/keyring/kdf.js.map +1 -0
- package/dist/keyring/record.d.ts +98 -0
- package/dist/keyring/record.d.ts.map +1 -0
- package/dist/keyring/record.js +119 -0
- package/dist/keyring/record.js.map +1 -0
- package/dist/keyring/unlockSpace.d.ts +101 -0
- package/dist/keyring/unlockSpace.d.ts.map +1 -0
- package/dist/keyring/unlockSpace.js +226 -0
- package/dist/keyring/unlockSpace.js.map +1 -0
- package/dist/keys/index.d.ts +24 -0
- package/dist/keys/index.d.ts.map +1 -0
- package/dist/keys/index.js +22 -0
- package/dist/keys/index.js.map +1 -0
- package/dist/keys/puk.d.ts +42 -0
- package/dist/keys/puk.d.ts.map +1 -0
- package/dist/keys/puk.js +56 -0
- package/dist/keys/puk.js.map +1 -0
- package/dist/keys/pukRoster.d.ts +210 -0
- package/dist/keys/pukRoster.d.ts.map +1 -0
- package/dist/keys/pukRoster.js +263 -0
- package/dist/keys/pukRoster.js.map +1 -0
- package/dist/keys/rosterStore.d.ts +18 -0
- package/dist/keys/rosterStore.d.ts.map +1 -0
- package/dist/keys/rosterStore.js +38 -0
- package/dist/keys/rosterStore.js.map +1 -0
- package/dist/markers/acquire.d.ts +107 -0
- package/dist/markers/acquire.d.ts.map +1 -0
- package/dist/markers/acquire.js +83 -0
- package/dist/markers/acquire.js.map +1 -0
- package/dist/markers/cipher.d.ts +56 -0
- package/dist/markers/cipher.d.ts.map +1 -0
- package/dist/markers/cipher.js +73 -0
- package/dist/markers/cipher.js.map +1 -0
- package/dist/markers/index.d.ts +30 -0
- package/dist/markers/index.d.ts.map +1 -0
- package/dist/markers/index.js +29 -0
- package/dist/markers/index.js.map +1 -0
- package/dist/markers/refresh.d.ts +60 -0
- package/dist/markers/refresh.d.ts.map +1 -0
- package/dist/markers/refresh.js +67 -0
- package/dist/markers/refresh.js.map +1 -0
- package/dist/recovery/index.d.ts +31 -0
- package/dist/recovery/index.d.ts.map +1 -0
- package/dist/recovery/index.js +28 -0
- package/dist/recovery/index.js.map +1 -0
- package/dist/recovery/recoveryCode.d.ts +105 -0
- package/dist/recovery/recoveryCode.d.ts.map +1 -0
- package/dist/recovery/recoveryCode.js +155 -0
- package/dist/recovery/recoveryCode.js.map +1 -0
- package/dist/recovery/recoveryRecord.d.ts +75 -0
- package/dist/recovery/recoveryRecord.d.ts.map +1 -0
- package/dist/recovery/recoveryRecord.js +89 -0
- package/dist/recovery/recoveryRecord.js.map +1 -0
- package/dist/recovery/recoveryWebvh.d.ts +126 -0
- package/dist/recovery/recoveryWebvh.d.ts.map +1 -0
- package/dist/recovery/recoveryWebvh.js +379 -0
- package/dist/recovery/recoveryWebvh.js.map +1 -0
- package/dist/space/collections.d.ts +57 -0
- package/dist/space/collections.d.ts.map +1 -1
- package/dist/space/collections.js +48 -0
- package/dist/space/collections.js.map +1 -1
- package/dist/space/index.d.ts +4 -0
- package/dist/space/index.d.ts.map +1 -1
- package/dist/space/index.js +4 -0
- package/dist/space/index.js.map +1 -1
- package/dist/webvh/didWeb.d.ts +41 -0
- package/dist/webvh/didWeb.d.ts.map +1 -0
- package/dist/webvh/didWeb.js +24 -0
- package/dist/webvh/didWeb.js.map +1 -0
- package/dist/webvh/didWebvh.d.ts +330 -0
- package/dist/webvh/didWebvh.d.ts.map +1 -0
- package/dist/webvh/didWebvh.js +775 -0
- package/dist/webvh/didWebvh.js.map +1 -0
- package/dist/webvh/index.d.ts +27 -0
- package/dist/webvh/index.d.ts.map +1 -0
- package/dist/webvh/index.js +24 -0
- package/dist/webvh/index.js.map +1 -0
- package/dist/webvh/zcap.d.ts +104 -0
- package/dist/webvh/zcap.d.ts.map +1 -0
- package/dist/webvh/zcap.js +117 -0
- package/dist/webvh/zcap.js.map +1 -0
- package/package.json +42 -4
- package/dist/identity/collectionKeys.d.ts +0 -36
- package/dist/identity/collectionKeys.d.ts.map +0 -1
- package/dist/identity/collectionKeys.js +0 -92
- package/dist/identity/collectionKeys.js.map +0 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { IKeyAgreementKey } from '@interop/data-integrity-core';
|
|
2
|
+
import type { MarkerStore } from '@interop/was-client/edv';
|
|
3
|
+
import type { ClientWebvhUpdateKeys, WebvhEnrollmentKeys, WebvhIdStore } from '../webvh/didWebvh.js';
|
|
4
|
+
import type { Puk } from '../keys/puk.js';
|
|
5
|
+
import type { AccountPointer } from '../keyring/record.js';
|
|
6
|
+
/**
|
|
7
|
+
* The public halves a connect code carries -- the same four multibases
|
|
8
|
+
* `enrollWebvhClient` publishes into the document, minted by the enrollee and
|
|
9
|
+
* verified point-to-point by the person running the ceremony.
|
|
10
|
+
*/
|
|
11
|
+
export type EnrollmentRequest = WebvhEnrollmentKeys;
|
|
12
|
+
/**
|
|
13
|
+
* Thrown by the enrollee's completion step while the enrolling side has not
|
|
14
|
+
* (yet) published the add entry -- the "not approved yet" state, retried by
|
|
15
|
+
* completing again once the other client finishes.
|
|
16
|
+
*/
|
|
17
|
+
export declare class EnrollmentPendingError extends Error {
|
|
18
|
+
constructor(message?: string);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Encodes an enrollment request as a connect code.
|
|
22
|
+
*
|
|
23
|
+
* @param options {object}
|
|
24
|
+
* @param options.request {EnrollmentRequest}
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
export declare function encodeEnrollmentRequest({ request }: {
|
|
28
|
+
request: EnrollmentRequest;
|
|
29
|
+
}): string;
|
|
30
|
+
/**
|
|
31
|
+
* Parses and validates a connect code: the prefix, the payload version, and
|
|
32
|
+
* the shape of each key (Ed25519 multibase for the signing and update keys,
|
|
33
|
+
* X25519 for the key-agreement key). Throws on anything malformed -- a code
|
|
34
|
+
* is typed or scanned, so a clear refusal beats a half-parsed ceremony.
|
|
35
|
+
*
|
|
36
|
+
* @param options {object}
|
|
37
|
+
* @param options.code {string} the pasted/scanned connect code
|
|
38
|
+
* @returns {EnrollmentRequest}
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseEnrollmentRequest({ code }: {
|
|
41
|
+
code: string;
|
|
42
|
+
}): EnrollmentRequest;
|
|
43
|
+
/**
|
|
44
|
+
* The did:key a connect code's signing key derives -- shown on BOTH screens
|
|
45
|
+
* so the person running the ceremony can compare them before approving (the
|
|
46
|
+
* point-to-point verification the wrap and the document VM then inherit).
|
|
47
|
+
*
|
|
48
|
+
* @param options {object}
|
|
49
|
+
* @param options.request {EnrollmentRequest}
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
export declare function enrollmentClientDid({ request }: {
|
|
53
|
+
request: EnrollmentRequest;
|
|
54
|
+
}): string;
|
|
55
|
+
/**
|
|
56
|
+
* The kid of the enrollee's roster entry: its key-agreement key's id exactly
|
|
57
|
+
* as `agentsFromSeed` will derive it at the enrollee's own logins
|
|
58
|
+
* (`did:key:<ed-multibase>#<x-multibase>`), so the wrap minted here is the
|
|
59
|
+
* one its first roster read looks for.
|
|
60
|
+
*
|
|
61
|
+
* @param options {object}
|
|
62
|
+
* @param options.request {EnrollmentRequest}
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
export declare function enrollmentRecipientKid({ request }: {
|
|
66
|
+
request: EnrollmentRequest;
|
|
67
|
+
}): string;
|
|
68
|
+
/**
|
|
69
|
+
* ENROLLEE, step one: mints the new client's whole key set locally and
|
|
70
|
+
* returns it alongside the connect code to display. The caller holds the
|
|
71
|
+
* seeds in memory until the completion step persists them -- nothing is
|
|
72
|
+
* durable before the ceremony succeeds, so abandoning it leaks at most an
|
|
73
|
+
* orphan wrap on the enrolling side.
|
|
74
|
+
*
|
|
75
|
+
* @returns {Promise<object>} the in-memory key set, the code, and the
|
|
76
|
+
* client did:key to display beside it for comparison
|
|
77
|
+
*/
|
|
78
|
+
export declare function mintEnrollmentRequest(): Promise<{
|
|
79
|
+
clientSeed: Uint8Array;
|
|
80
|
+
webvhUpdateKeys: ClientWebvhUpdateKeys;
|
|
81
|
+
code: string;
|
|
82
|
+
clientDid: string;
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* ENROLLING CLIENT: the whole approval, in the push order -- the PUK wrapped
|
|
86
|
+
* into the roster first (escrow: every epoch, so the new client reads
|
|
87
|
+
* pre-enrollment history), then the two log entries. Quorum-of-one: this
|
|
88
|
+
* client's own update key signs both entries. Idempotent at every stage, so
|
|
89
|
+
* re-approving the same code after any tear converges.
|
|
90
|
+
*
|
|
91
|
+
* @param options {object}
|
|
92
|
+
* @param options.request {EnrollmentRequest} the parsed connect code
|
|
93
|
+
* @param options.clientWebvhKeys {ClientWebvhUpdateKeys} the approving
|
|
94
|
+
* client's own did:webvh update-key seeds
|
|
95
|
+
* @param options.clientKeyAgreementKey {IKeyAgreementKey} the approving
|
|
96
|
+
* client's own (identity) key-agreement key, unwrapping each epoch for
|
|
97
|
+
* re-wrapping
|
|
98
|
+
* @param options.pukRosterStore {MarkerStore} the account's
|
|
99
|
+
* `key-map/puk.json` marker store
|
|
100
|
+
* @param options.idStore {WebvhIdStore} the account's `id` collection
|
|
101
|
+
* @returns {Promise<{ did: string }>} the account's did:webvh
|
|
102
|
+
*/
|
|
103
|
+
export declare function approveEnrollment({ request, clientWebvhKeys, clientKeyAgreementKey, pukRosterStore, idStore }: {
|
|
104
|
+
request: EnrollmentRequest;
|
|
105
|
+
clientWebvhKeys: ClientWebvhUpdateKeys;
|
|
106
|
+
clientKeyAgreementKey: IKeyAgreementKey;
|
|
107
|
+
pukRosterStore: MarkerStore;
|
|
108
|
+
idStore: WebvhIdStore;
|
|
109
|
+
}): Promise<{
|
|
110
|
+
did: string;
|
|
111
|
+
}>;
|
|
112
|
+
/**
|
|
113
|
+
* ENROLLEE, step two (after the other client approves): verifies the
|
|
114
|
+
* enrollment from the world-readable log and performs this client's first
|
|
115
|
+
* roster read -- signed with its just-published `<did:webvh>#<multibase>`
|
|
116
|
+
* key -- to obtain the PUK.
|
|
117
|
+
*
|
|
118
|
+
* The portable core of the completion step: the caller supplies the account
|
|
119
|
+
* pointer (from its own keyring lookup) and persists what comes back -- the
|
|
120
|
+
* PUK, the roster epoch to pin, and the key set itself -- under its own unlock
|
|
121
|
+
* layer. After that, an ordinary unlock finds an enrolled client.
|
|
122
|
+
*
|
|
123
|
+
* Throws `EnrollmentPendingError` while the add entry is not published yet
|
|
124
|
+
* (complete again once the other client finishes); any integrity failure
|
|
125
|
+
* (a log that resolves to a different DID than the account pointer names, a
|
|
126
|
+
* missing roster wrap) throws its own error.
|
|
127
|
+
*
|
|
128
|
+
* @param options {object}
|
|
129
|
+
* @param options.clientSeed {Uint8Array} from `mintEnrollmentRequest`
|
|
130
|
+
* @param options.webvhUpdateKeys {ClientWebvhUpdateKeys} from
|
|
131
|
+
* `mintEnrollmentRequest`
|
|
132
|
+
* @param options.pointer {AccountPointer} the account pointer the enrollee's
|
|
133
|
+
* keyring lookup recovered
|
|
134
|
+
* @returns {Promise<{ puk: Puk, latestEpochId: string }>}
|
|
135
|
+
*/
|
|
136
|
+
export declare function completeEnrollmentCore({ clientSeed, webvhUpdateKeys, pointer }: {
|
|
137
|
+
clientSeed: Uint8Array;
|
|
138
|
+
webvhUpdateKeys: ClientWebvhUpdateKeys;
|
|
139
|
+
pointer: AccountPointer;
|
|
140
|
+
}): Promise<{
|
|
141
|
+
puk: Puk;
|
|
142
|
+
latestEpochId: string;
|
|
143
|
+
}>;
|
|
144
|
+
//# sourceMappingURL=enrollment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrollment.d.ts","sourceRoot":"","sources":["../../src/enrollment/enrollment.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAS1D,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACb,MAAM,sBAAsB,CAAA;AAS7B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAa1D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,CAAA;AAEnD;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBAE7C,OAAO,SAC+C;CAKzD;AASD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,OAAO,EACR,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;CAC3B,GAAG,MAAM,CAKT;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACL,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,iBAAiB,CAwDpB;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,CAET;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;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,OAAO,EACP,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,OAAO,EACR,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAA;IAC1B,eAAe,EAAE,qBAAqB,CAAA;IACtC,qBAAqB,EAAE,gBAAgB,CAAA;IACvC,cAAc,EAAE,WAAW,CAAA;IAC3B,OAAO,EAAE,YAAY,CAAA;CACtB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB3B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,UAAU,EACV,eAAe,EACf,OAAO,EACR,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,eAAe,EAAE,qBAAqB,CAAA;IACtC,OAAO,EAAE,cAAc,CAAA;CACxB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CA2E/C"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The client enrollment ceremony: connecting a second wallet client (a fresh
|
|
6
|
+
* browser profile, another app install) to an existing account without any
|
|
7
|
+
* secret ever leaving either side. The new client mints its whole key set
|
|
8
|
+
* locally -- client seed, did:webvh update-key seeds -- and only PUBLIC halves
|
|
9
|
+
* travel, as a compact "connect code" carried point-to-point (pasted between
|
|
10
|
+
* two browsers in the room today; the same payload renders as a QR for a
|
|
11
|
+
* camera-holding wallet). Nothing travels back over the channel: the account
|
|
12
|
+
* pointer comes out of the keyring (the enrollee holds the unlock secret), and
|
|
13
|
+
* the PUK comes back through the wrap-set roster.
|
|
14
|
+
*
|
|
15
|
+
* Push, not pull, in the recovery-anchor order (decryption material before
|
|
16
|
+
* authorization): the enrolling client wraps the PUK to the new client's
|
|
17
|
+
* key-agreement key in `key-map/puk.json` FIRST, then writes the two
|
|
18
|
+
* did:webvh log entries (commit, then add-VMs-and-update-key). No
|
|
19
|
+
* authorized-but-blind window exists at any point, and both tear points
|
|
20
|
+
* resume by re-running the ceremony with the same code -- a tear after the
|
|
21
|
+
* roster write leaves an orphan wrap (invisible to authorization), a tear
|
|
22
|
+
* between the log entries is detected from the published commitments.
|
|
23
|
+
*
|
|
24
|
+
* The new client's first roster read happens post-enrollment, signed with its
|
|
25
|
+
* `<did:webvh>#<multibase>` key -- the server authorizes it under the
|
|
26
|
+
* current-key-set rule the moment the add entry publishes. Persisting the key
|
|
27
|
+
* set under the app's own unlock layer is the caller's job: this module hands
|
|
28
|
+
* back the PUK and the roster epoch to pin, and stops there.
|
|
29
|
+
*/
|
|
30
|
+
import { readLogFromString, resolveDIDFromLog } from '@interop/did-method-webvh';
|
|
31
|
+
import { base64urlnopad } from '@scure/base';
|
|
32
|
+
import { agentsFromSeed } from '../identity/agents.js';
|
|
33
|
+
import { DID_LOG_RESOURCE, ID_COLLECTION } from '../space/collections.js';
|
|
34
|
+
import { enrollWebvhClient, mintClientWebvhUpdateKeys, updateKeyMultibase } from '../webvh/didWebvh.js';
|
|
35
|
+
import { clientSigningKeyMultibase, isWebvhDid, webvhZcapClient } from '../webvh/zcap.js';
|
|
36
|
+
import { addPukRosterRecipient } from '../keys/pukRoster.js';
|
|
37
|
+
import { readPukRoster } from '../keys/pukRoster.js';
|
|
38
|
+
import { pukRosterMarkerStore } from '../keys/rosterStore.js';
|
|
39
|
+
/**
|
|
40
|
+
* The connect-code prefix; the payload after it is base64url(JSON) of an
|
|
41
|
+
* `EnrollmentRequest` plus a `v` version stamp.
|
|
42
|
+
*/
|
|
43
|
+
const CONNECT_CODE_PREFIX = 'freewallet-connect:';
|
|
44
|
+
/**
|
|
45
|
+
* The connect-code payload version this build mints and accepts.
|
|
46
|
+
*/
|
|
47
|
+
const CONNECT_CODE_VERSION = 1;
|
|
48
|
+
/**
|
|
49
|
+
* Thrown by the enrollee's completion step while the enrolling side has not
|
|
50
|
+
* (yet) published the add entry -- the "not approved yet" state, retried by
|
|
51
|
+
* completing again once the other client finishes.
|
|
52
|
+
*/
|
|
53
|
+
export class EnrollmentPendingError extends Error {
|
|
54
|
+
constructor(message = 'This browser is not enrolled yet; approve the connect code ' +
|
|
55
|
+
'from an already-connected browser, then try again.') {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = 'EnrollmentPendingError';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The multicodec multibase prefixes of the two key types a connect code
|
|
62
|
+
* carries: Ed25519 (`z6Mk`) and X25519 (`z6LS`) public keys.
|
|
63
|
+
*/
|
|
64
|
+
const ED25519_MULTIBASE_PREFIX = 'z6Mk';
|
|
65
|
+
const X25519_MULTIBASE_PREFIX = 'z6LS';
|
|
66
|
+
/**
|
|
67
|
+
* Encodes an enrollment request as a connect code.
|
|
68
|
+
*
|
|
69
|
+
* @param options {object}
|
|
70
|
+
* @param options.request {EnrollmentRequest}
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
export function encodeEnrollmentRequest({ request }) {
|
|
74
|
+
const payload = JSON.stringify({ v: CONNECT_CODE_VERSION, ...request });
|
|
75
|
+
return `${CONNECT_CODE_PREFIX}${base64urlnopad.encode(new TextEncoder().encode(payload))}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Parses and validates a connect code: the prefix, the payload version, and
|
|
79
|
+
* the shape of each key (Ed25519 multibase for the signing and update keys,
|
|
80
|
+
* X25519 for the key-agreement key). Throws on anything malformed -- a code
|
|
81
|
+
* is typed or scanned, so a clear refusal beats a half-parsed ceremony.
|
|
82
|
+
*
|
|
83
|
+
* @param options {object}
|
|
84
|
+
* @param options.code {string} the pasted/scanned connect code
|
|
85
|
+
* @returns {EnrollmentRequest}
|
|
86
|
+
*/
|
|
87
|
+
export function parseEnrollmentRequest({ code }) {
|
|
88
|
+
const trimmed = code.trim();
|
|
89
|
+
if (!trimmed.startsWith(CONNECT_CODE_PREFIX)) {
|
|
90
|
+
throw new Error('Not a wallet connect code.');
|
|
91
|
+
}
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(new TextDecoder().decode(base64urlnopad.decode(trimmed.slice(CONNECT_CODE_PREFIX.length))));
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
throw new Error('The connect code payload is malformed.', { cause: err });
|
|
98
|
+
}
|
|
99
|
+
if (parsed === null || typeof parsed !== 'object') {
|
|
100
|
+
throw new Error('The connect code payload is malformed.');
|
|
101
|
+
}
|
|
102
|
+
const { v, signingKeyMultibase, keyAgreementKeyMultibase, updateKeyMultibase: updateKey, stagedUpdateKeyMultibase } = parsed;
|
|
103
|
+
if (v !== CONNECT_CODE_VERSION) {
|
|
104
|
+
throw new Error(`Unsupported connect code version "${String(v)}".`);
|
|
105
|
+
}
|
|
106
|
+
const requireKey = (value, prefix, name) => {
|
|
107
|
+
if (typeof value !== 'string' || !value.startsWith(prefix)) {
|
|
108
|
+
throw new Error(`The connect code carries a malformed ${name}.`);
|
|
109
|
+
}
|
|
110
|
+
return value;
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
signingKeyMultibase: requireKey(signingKeyMultibase, ED25519_MULTIBASE_PREFIX, 'signing key'),
|
|
114
|
+
keyAgreementKeyMultibase: requireKey(keyAgreementKeyMultibase, X25519_MULTIBASE_PREFIX, 'key-agreement key'),
|
|
115
|
+
updateKeyMultibase: requireKey(updateKey, ED25519_MULTIBASE_PREFIX, 'update key'),
|
|
116
|
+
stagedUpdateKeyMultibase: requireKey(stagedUpdateKeyMultibase, ED25519_MULTIBASE_PREFIX, 'staged update key')
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The did:key a connect code's signing key derives -- shown on BOTH screens
|
|
121
|
+
* so the person running the ceremony can compare them before approving (the
|
|
122
|
+
* point-to-point verification the wrap and the document VM then inherit).
|
|
123
|
+
*
|
|
124
|
+
* @param options {object}
|
|
125
|
+
* @param options.request {EnrollmentRequest}
|
|
126
|
+
* @returns {string}
|
|
127
|
+
*/
|
|
128
|
+
export function enrollmentClientDid({ request }) {
|
|
129
|
+
return `did:key:${request.signingKeyMultibase}`;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The kid of the enrollee's roster entry: its key-agreement key's id exactly
|
|
133
|
+
* as `agentsFromSeed` will derive it at the enrollee's own logins
|
|
134
|
+
* (`did:key:<ed-multibase>#<x-multibase>`), so the wrap minted here is the
|
|
135
|
+
* one its first roster read looks for.
|
|
136
|
+
*
|
|
137
|
+
* @param options {object}
|
|
138
|
+
* @param options.request {EnrollmentRequest}
|
|
139
|
+
* @returns {string}
|
|
140
|
+
*/
|
|
141
|
+
export function enrollmentRecipientKid({ request }) {
|
|
142
|
+
return `${enrollmentClientDid({ request })}#${request.keyAgreementKeyMultibase}`;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* ENROLLEE, step one: mints the new client's whole key set locally and
|
|
146
|
+
* returns it alongside the connect code to display. The caller holds the
|
|
147
|
+
* seeds in memory until the completion step persists them -- nothing is
|
|
148
|
+
* durable before the ceremony succeeds, so abandoning it leaks at most an
|
|
149
|
+
* orphan wrap on the enrolling side.
|
|
150
|
+
*
|
|
151
|
+
* @returns {Promise<object>} the in-memory key set, the code, and the
|
|
152
|
+
* client did:key to display beside it for comparison
|
|
153
|
+
*/
|
|
154
|
+
export async function mintEnrollmentRequest() {
|
|
155
|
+
const clientSeed = crypto.getRandomValues(new Uint8Array(32));
|
|
156
|
+
const { keyAgent, keyAgreementKey } = await agentsFromSeed({
|
|
157
|
+
seed: clientSeed
|
|
158
|
+
});
|
|
159
|
+
const { publicKeyMultibase: keyAgreementKeyMultibase } = keyAgreementKey;
|
|
160
|
+
if (!keyAgreementKeyMultibase) {
|
|
161
|
+
throw new Error('The minted key-agreement key has no public multibase.');
|
|
162
|
+
}
|
|
163
|
+
const webvhUpdateKeys = await mintClientWebvhUpdateKeys();
|
|
164
|
+
const request = {
|
|
165
|
+
signingKeyMultibase: clientSigningKeyMultibase({ keyAgent }),
|
|
166
|
+
keyAgreementKeyMultibase,
|
|
167
|
+
updateKeyMultibase: await updateKeyMultibase({
|
|
168
|
+
seed: webvhUpdateKeys.updateSeed
|
|
169
|
+
}),
|
|
170
|
+
stagedUpdateKeyMultibase: await updateKeyMultibase({
|
|
171
|
+
seed: webvhUpdateKeys.stagedSeed
|
|
172
|
+
})
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
clientSeed,
|
|
176
|
+
webvhUpdateKeys,
|
|
177
|
+
code: encodeEnrollmentRequest({ request }),
|
|
178
|
+
clientDid: keyAgent.id
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* ENROLLING CLIENT: the whole approval, in the push order -- the PUK wrapped
|
|
183
|
+
* into the roster first (escrow: every epoch, so the new client reads
|
|
184
|
+
* pre-enrollment history), then the two log entries. Quorum-of-one: this
|
|
185
|
+
* client's own update key signs both entries. Idempotent at every stage, so
|
|
186
|
+
* re-approving the same code after any tear converges.
|
|
187
|
+
*
|
|
188
|
+
* @param options {object}
|
|
189
|
+
* @param options.request {EnrollmentRequest} the parsed connect code
|
|
190
|
+
* @param options.clientWebvhKeys {ClientWebvhUpdateKeys} the approving
|
|
191
|
+
* client's own did:webvh update-key seeds
|
|
192
|
+
* @param options.clientKeyAgreementKey {IKeyAgreementKey} the approving
|
|
193
|
+
* client's own (identity) key-agreement key, unwrapping each epoch for
|
|
194
|
+
* re-wrapping
|
|
195
|
+
* @param options.pukRosterStore {MarkerStore} the account's
|
|
196
|
+
* `key-map/puk.json` marker store
|
|
197
|
+
* @param options.idStore {WebvhIdStore} the account's `id` collection
|
|
198
|
+
* @returns {Promise<{ did: string }>} the account's did:webvh
|
|
199
|
+
*/
|
|
200
|
+
export async function approveEnrollment({ request, clientWebvhKeys, clientKeyAgreementKey, pukRosterStore, idStore }) {
|
|
201
|
+
// Decryption material before authorization: the wrap lands first, so no
|
|
202
|
+
// enrolled client is ever authorized but blind.
|
|
203
|
+
await addPukRosterRecipient({
|
|
204
|
+
store: pukRosterStore,
|
|
205
|
+
recipient: {
|
|
206
|
+
id: enrollmentRecipientKid({ request }),
|
|
207
|
+
publicKeyMultibase: request.keyAgreementKeyMultibase
|
|
208
|
+
},
|
|
209
|
+
ownerKeyAgreementKey: clientKeyAgreementKey
|
|
210
|
+
});
|
|
211
|
+
return enrollWebvhClient({
|
|
212
|
+
idStore,
|
|
213
|
+
updateKeys: clientWebvhKeys,
|
|
214
|
+
newClient: request
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* ENROLLEE, step two (after the other client approves): verifies the
|
|
219
|
+
* enrollment from the world-readable log and performs this client's first
|
|
220
|
+
* roster read -- signed with its just-published `<did:webvh>#<multibase>`
|
|
221
|
+
* key -- to obtain the PUK.
|
|
222
|
+
*
|
|
223
|
+
* The portable core of the completion step: the caller supplies the account
|
|
224
|
+
* pointer (from its own keyring lookup) and persists what comes back -- the
|
|
225
|
+
* PUK, the roster epoch to pin, and the key set itself -- under its own unlock
|
|
226
|
+
* layer. After that, an ordinary unlock finds an enrolled client.
|
|
227
|
+
*
|
|
228
|
+
* Throws `EnrollmentPendingError` while the add entry is not published yet
|
|
229
|
+
* (complete again once the other client finishes); any integrity failure
|
|
230
|
+
* (a log that resolves to a different DID than the account pointer names, a
|
|
231
|
+
* missing roster wrap) throws its own error.
|
|
232
|
+
*
|
|
233
|
+
* @param options {object}
|
|
234
|
+
* @param options.clientSeed {Uint8Array} from `mintEnrollmentRequest`
|
|
235
|
+
* @param options.webvhUpdateKeys {ClientWebvhUpdateKeys} from
|
|
236
|
+
* `mintEnrollmentRequest`
|
|
237
|
+
* @param options.pointer {AccountPointer} the account pointer the enrollee's
|
|
238
|
+
* keyring lookup recovered
|
|
239
|
+
* @returns {Promise<{ puk: Puk, latestEpochId: string }>}
|
|
240
|
+
*/
|
|
241
|
+
export async function completeEnrollmentCore({ clientSeed, webvhUpdateKeys, pointer }) {
|
|
242
|
+
const did = pointer.did;
|
|
243
|
+
if (!did || !isWebvhDid(did)) {
|
|
244
|
+
throw new Error('The account pointer names no did:webvh; only a promoted account can ' +
|
|
245
|
+
'enroll additional clients.');
|
|
246
|
+
}
|
|
247
|
+
const { keyAgent, keyAgreementKey } = await agentsFromSeed({
|
|
248
|
+
seed: clientSeed
|
|
249
|
+
});
|
|
250
|
+
// Verify the enrollment from the world-readable, self-certifying log: it
|
|
251
|
+
// must resolve to exactly the DID the account pointer names, and its
|
|
252
|
+
// document must list this client's keys -- the add entry has published.
|
|
253
|
+
const logUrl = new URL(`/space/${pointer.spaceId}/${ID_COLLECTION.id}/${DID_LOG_RESOURCE}`, pointer.host);
|
|
254
|
+
const response = await fetch(logUrl);
|
|
255
|
+
if (response.status === 404) {
|
|
256
|
+
throw new EnrollmentPendingError();
|
|
257
|
+
}
|
|
258
|
+
if (!response.ok) {
|
|
259
|
+
throw new Error(`Fetching the account's DID log failed (HTTP ${response.status}).`);
|
|
260
|
+
}
|
|
261
|
+
const resolved = await resolveDIDFromLog(readLogFromString(await response.text()));
|
|
262
|
+
if (resolved.meta.error || !resolved.did || !resolved.doc) {
|
|
263
|
+
throw new Error(`The account's DID log failed to resolve (${resolved.meta.error}).`);
|
|
264
|
+
}
|
|
265
|
+
if (resolved.did !== did) {
|
|
266
|
+
throw new Error('The published DID log resolves to a different DID than the account ' +
|
|
267
|
+
'pointer names.');
|
|
268
|
+
}
|
|
269
|
+
const signingMultibase = clientSigningKeyMultibase({ keyAgent });
|
|
270
|
+
const updateKey = await updateKeyMultibase({
|
|
271
|
+
seed: webvhUpdateKeys.updateSeed
|
|
272
|
+
});
|
|
273
|
+
const enrolled = (resolved.doc.verificationMethod ?? []).some(method => method.publicKeyMultibase === signingMultibase) && (resolved.meta.updateKeys ?? []).includes(updateKey);
|
|
274
|
+
if (!enrolled) {
|
|
275
|
+
throw new EnrollmentPendingError();
|
|
276
|
+
}
|
|
277
|
+
// The first roster read: signed with the `<did:webvh>#<multibase>` keyId
|
|
278
|
+
// the add entry just published, unwrapping the PUK the enrolling client
|
|
279
|
+
// escrowed to this client's key-agreement key.
|
|
280
|
+
const zcapClient = webvhZcapClient({ keyAgent, did });
|
|
281
|
+
const store = pukRosterMarkerStore({
|
|
282
|
+
storageServerUrl: pointer.host,
|
|
283
|
+
zcapClient,
|
|
284
|
+
spaceId: pointer.spaceId
|
|
285
|
+
});
|
|
286
|
+
const read = await readPukRoster({
|
|
287
|
+
store,
|
|
288
|
+
clientKeyAgreementKey: keyAgreementKey
|
|
289
|
+
});
|
|
290
|
+
if (!read) {
|
|
291
|
+
throw new Error('The account has no PUK roster; it must finish provisioning before ' +
|
|
292
|
+
'a client can be enrolled.');
|
|
293
|
+
}
|
|
294
|
+
return { puk: read.puk, latestEpochId: read.latestEpochId };
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=enrollment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrollment.js","sourceRoot":"","sources":["../../src/enrollment/enrollment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The `@interop/wallet-core/enrollment` subpath: the client enrollment
|
|
6
|
+
* ceremony -- connecting another wallet client to an existing account with
|
|
7
|
+
* only public halves travelling, point to point.
|
|
8
|
+
*
|
|
9
|
+
* - `mintEnrollmentRequest` / `encodeEnrollmentRequest` /
|
|
10
|
+
* `parseEnrollmentRequest` / `enrollmentClientDid` /
|
|
11
|
+
* `enrollmentRecipientKid` -- the connect-code channel layer.
|
|
12
|
+
* - `approveEnrollment` -- the enrolling client's half, in the push order
|
|
13
|
+
* (roster wrap, then the two did:webvh log entries).
|
|
14
|
+
* - `completeEnrollmentCore` -- the enrollee's half: verify from the published
|
|
15
|
+
* log, read the roster, hand back the PUK and the epoch to pin. Persisting
|
|
16
|
+
* the key set stays with the caller's own unlock layer.
|
|
17
|
+
*/
|
|
18
|
+
export { approveEnrollment, completeEnrollmentCore, encodeEnrollmentRequest, EnrollmentPendingError, enrollmentClientDid, enrollmentRecipientKid, mintEnrollmentRequest, parseEnrollmentRequest } from './enrollment.js';
|
|
19
|
+
export type { EnrollmentRequest } from './enrollment.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/enrollment/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The `@interop/wallet-core/enrollment` subpath: the client enrollment
|
|
6
|
+
* ceremony -- connecting another wallet client to an existing account with
|
|
7
|
+
* only public halves travelling, point to point.
|
|
8
|
+
*
|
|
9
|
+
* - `mintEnrollmentRequest` / `encodeEnrollmentRequest` /
|
|
10
|
+
* `parseEnrollmentRequest` / `enrollmentClientDid` /
|
|
11
|
+
* `enrollmentRecipientKid` -- the connect-code channel layer.
|
|
12
|
+
* - `approveEnrollment` -- the enrolling client's half, in the push order
|
|
13
|
+
* (roster wrap, then the two did:webvh log entries).
|
|
14
|
+
* - `completeEnrollmentCore` -- the enrollee's half: verify from the published
|
|
15
|
+
* log, read the roster, hand back the PUK and the epoch to pin. Persisting
|
|
16
|
+
* the key set stays with the caller's own unlock layer.
|
|
17
|
+
*/
|
|
18
|
+
export { approveEnrollment, completeEnrollmentCore, encodeEnrollmentRequest, EnrollmentPendingError, enrollmentClientDid, enrollmentRecipientKid, mintEnrollmentRequest, parseEnrollmentRequest } from './enrollment.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/enrollment/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,iBAAiB,CAAA"}
|
package/dist/identity/index.d.ts
CHANGED
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
* single-key resolver) under the fixed bootstrap handle / key name.
|
|
11
11
|
* - `singleKeyResolver` -- the one-key `IKeyResolver` factory (also used by
|
|
12
12
|
* app-side derivations such as a keyring unlock identity).
|
|
13
|
-
* - `deriveCollectionKeys` -- per-collection vault-key (KAK) derivation:
|
|
14
|
-
* `HKDF-SHA256(master seed, 'kak:v1:<collectionId>')` to a per-collection
|
|
15
|
-
* seed, then the Ed25519-to-X25519 key-agreement key plus its resolver.
|
|
16
13
|
*
|
|
17
14
|
* Kept out of the root export: this subpath pulls the webkms-client / ezcap /
|
|
18
15
|
* x25519 dependency graph (the same isolation pattern as `./request`).
|
|
@@ -20,6 +17,4 @@
|
|
|
20
17
|
export { BOOTSTRAP_HANDLE, BOOTSTRAP_KEY_NAME, agentsFromSecret, agentsFromSeed } from './agents.js';
|
|
21
18
|
export type { ProfileAgents } from './agents.js';
|
|
22
19
|
export { singleKeyResolver } from './keyResolver.js';
|
|
23
|
-
export { deriveCollectionKeys, DEFAULT_KAK_HANDLE } from './collectionKeys.js';
|
|
24
|
-
export type { CollectionKeys } from './collectionKeys.js';
|
|
25
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/identity/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/identity/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACf,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA"}
|
package/dist/identity/index.js
CHANGED
|
@@ -10,14 +10,10 @@
|
|
|
10
10
|
* single-key resolver) under the fixed bootstrap handle / key name.
|
|
11
11
|
* - `singleKeyResolver` -- the one-key `IKeyResolver` factory (also used by
|
|
12
12
|
* app-side derivations such as a keyring unlock identity).
|
|
13
|
-
* - `deriveCollectionKeys` -- per-collection vault-key (KAK) derivation:
|
|
14
|
-
* `HKDF-SHA256(master seed, 'kak:v1:<collectionId>')` to a per-collection
|
|
15
|
-
* seed, then the Ed25519-to-X25519 key-agreement key plus its resolver.
|
|
16
13
|
*
|
|
17
14
|
* Kept out of the root export: this subpath pulls the webkms-client / ezcap /
|
|
18
15
|
* x25519 dependency graph (the same isolation pattern as `./request`).
|
|
19
16
|
*/
|
|
20
17
|
export { BOOTSTRAP_HANDLE, BOOTSTRAP_KEY_NAME, agentsFromSecret, agentsFromSeed } from './agents.js';
|
|
21
18
|
export { singleKeyResolver } from './keyResolver.js';
|
|
22
|
-
export { deriveCollectionKeys, DEFAULT_KAK_HANDLE } from './collectionKeys.js';
|
|
23
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/identity/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/identity/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACf,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,11 +16,24 @@
|
|
|
16
16
|
* `interaction:` URL handling).
|
|
17
17
|
* - `@interop/wallet-core/display` -- pure VC derivation / display helpers and
|
|
18
18
|
* credential input parsing (raw values out; formatting stays in the UI).
|
|
19
|
+
* - `@interop/wallet-core/webvh` -- the account's did:webvh identity: the
|
|
20
|
+
* hosted DID log, its per-client update-key rotation, the client enrollment
|
|
21
|
+
* entries, and ZCap signing under the did:webvh verification-method id.
|
|
22
|
+
* - `@interop/wallet-core/keys` -- the per-user key (PUK) and its
|
|
23
|
+
* `key-map/puk.json` wrap-set roster.
|
|
24
|
+
* - `@interop/wallet-core/markers` -- collection-encryption marker
|
|
25
|
+
* acquisition (fetch / cache / offline fallback) and the unknown-epoch
|
|
26
|
+
* refresh policy, including a self-refreshing EDV document cipher.
|
|
27
|
+
* - `@interop/wallet-core/keyring` -- the unlock layer: the unlock derivation,
|
|
28
|
+
* the account-pointer record codec, and the unlock Space.
|
|
29
|
+
* - `@interop/wallet-core/enrollment` -- the client enrollment ceremony
|
|
30
|
+
* (connect code, approval, completion).
|
|
19
31
|
*
|
|
20
32
|
* This root re-exports `sync` and `space` for convenience. `identity`,
|
|
21
|
-
* `request`,
|
|
22
|
-
*
|
|
23
|
-
*
|
|
33
|
+
* `request`, `display`, `webvh`, `keys`, `markers`, `keyring`, and
|
|
34
|
+
* `enrollment` are deliberately NOT re-exported here, so plaintext consumers
|
|
35
|
+
* of the root never pull the signing / KMS / document-loader dependency graph
|
|
36
|
+
* (the was-client subpath-isolation pattern).
|
|
24
37
|
*/
|
|
25
38
|
export * from './sync/index.js';
|
|
26
39
|
export * from './space/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -16,11 +16,24 @@
|
|
|
16
16
|
* `interaction:` URL handling).
|
|
17
17
|
* - `@interop/wallet-core/display` -- pure VC derivation / display helpers and
|
|
18
18
|
* credential input parsing (raw values out; formatting stays in the UI).
|
|
19
|
+
* - `@interop/wallet-core/webvh` -- the account's did:webvh identity: the
|
|
20
|
+
* hosted DID log, its per-client update-key rotation, the client enrollment
|
|
21
|
+
* entries, and ZCap signing under the did:webvh verification-method id.
|
|
22
|
+
* - `@interop/wallet-core/keys` -- the per-user key (PUK) and its
|
|
23
|
+
* `key-map/puk.json` wrap-set roster.
|
|
24
|
+
* - `@interop/wallet-core/markers` -- collection-encryption marker
|
|
25
|
+
* acquisition (fetch / cache / offline fallback) and the unknown-epoch
|
|
26
|
+
* refresh policy, including a self-refreshing EDV document cipher.
|
|
27
|
+
* - `@interop/wallet-core/keyring` -- the unlock layer: the unlock derivation,
|
|
28
|
+
* the account-pointer record codec, and the unlock Space.
|
|
29
|
+
* - `@interop/wallet-core/enrollment` -- the client enrollment ceremony
|
|
30
|
+
* (connect code, approval, completion).
|
|
19
31
|
*
|
|
20
32
|
* This root re-exports `sync` and `space` for convenience. `identity`,
|
|
21
|
-
* `request`,
|
|
22
|
-
*
|
|
23
|
-
*
|
|
33
|
+
* `request`, `display`, `webvh`, `keys`, `markers`, `keyring`, and
|
|
34
|
+
* `enrollment` are deliberately NOT re-exported here, so plaintext consumers
|
|
35
|
+
* of the root never pull the signing / KMS / document-loader dependency graph
|
|
36
|
+
* (the was-client subpath-isolation pattern).
|
|
24
37
|
*/
|
|
25
38
|
export * from './sync/index.js';
|
|
26
39
|
export * from './space/index.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,cAAc,iBAAiB,CAAA;AAC/B,cAAc,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { UnlockKdf } from './kdf.js';
|
|
2
|
+
import type { KeyringRecordContents } from './record.js';
|
|
3
|
+
/**
|
|
4
|
+
* Fetches and unwraps the keyring record an unlock secret addresses, or
|
|
5
|
+
* resolves `null` when no record exists there (an unknown secret). The derived
|
|
6
|
+
* unlock Space id is returned alongside the contents -- it is already computed,
|
|
7
|
+
* and callers key their local state on it.
|
|
8
|
+
*
|
|
9
|
+
* @param options {object}
|
|
10
|
+
* @param options.secret {string | Uint8Array} the unlock secret
|
|
11
|
+
* @param [options.kdf] {UnlockKdf} the unlock method's parameter set
|
|
12
|
+
* @param options.storageServerUrl {string} the WAS server origin
|
|
13
|
+
* @returns {Promise<(KeyringRecordContents & { unlockSpaceId: string }) | null>}
|
|
14
|
+
*/
|
|
15
|
+
export declare function fetchKeyringRecord({ secret, kdf, storageServerUrl }: {
|
|
16
|
+
secret: string | Uint8Array;
|
|
17
|
+
kdf?: UnlockKdf;
|
|
18
|
+
storageServerUrl: string;
|
|
19
|
+
}): Promise<(KeyringRecordContents & {
|
|
20
|
+
unlockSpaceId: string;
|
|
21
|
+
}) | null>;
|
|
22
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/keyring/fetch.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAIzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAExD;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,MAAM,EACN,GAAiB,EACjB,gBAAgB,EACjB,EAAE;IACD,MAAM,EAAE,MAAM,GAAG,UAAU,CAAA;IAC3B,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,gBAAgB,EAAE,MAAM,CAAA;CACzB,GAAG,OAAO,CAAC,CAAC,qBAAqB,GAAG;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC,CAkBtE"}
|