@interop/wallet-core 0.17.1 → 0.18.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 +13 -13
- package/dist/clients/index.d.ts +4 -3
- package/dist/clients/index.d.ts.map +1 -1
- package/dist/clients/index.js +3 -2
- package/dist/clients/index.js.map +1 -1
- package/dist/clients/policy.d.ts +3 -3
- package/dist/clients/policy.d.ts.map +1 -1
- package/dist/clients/policy.js +1 -1
- package/dist/clients/revocation.d.ts +15 -15
- package/dist/clients/revocation.d.ts.map +1 -1
- package/dist/clients/revocation.js +19 -19
- package/dist/clients/revocation.js.map +1 -1
- package/dist/clients/rosterPolicy.d.ts +26 -25
- package/dist/clients/rosterPolicy.d.ts.map +1 -1
- package/dist/clients/rosterPolicy.js +29 -29
- package/dist/clients/rosterPolicy.js.map +1 -1
- package/dist/enrollment/enrollment.d.ts +16 -16
- package/dist/enrollment/enrollment.d.ts.map +1 -1
- package/dist/enrollment/enrollment.js +19 -19
- package/dist/enrollment/enrollment.js.map +1 -1
- package/dist/enrollment/index.d.ts +1 -1
- package/dist/enrollment/index.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/keys/clientKeyRecord.d.ts +16 -16
- package/dist/keys/clientKeyRecord.d.ts.map +1 -1
- package/dist/keys/clientKeyRecord.js +39 -35
- package/dist/keys/clientKeyRecord.js.map +1 -1
- package/dist/keys/index.d.ts +19 -17
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +16 -14
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/rosterStore.d.ts +3 -3
- package/dist/keys/rosterStore.d.ts.map +1 -1
- package/dist/keys/rosterStore.js +13 -13
- package/dist/keys/rosterStore.js.map +1 -1
- package/dist/keys/userKey.d.ts +43 -0
- package/dist/keys/userKey.d.ts.map +1 -0
- package/dist/keys/{puk.js → userKey.js} +23 -21
- package/dist/keys/userKey.js.map +1 -0
- package/dist/keys/{pukCascade.d.ts → userKeyCascade.d.ts} +69 -69
- package/dist/keys/userKeyCascade.d.ts.map +1 -0
- package/dist/keys/{pukCascade.js → userKeyCascade.js} +67 -64
- package/dist/keys/userKeyCascade.js.map +1 -0
- package/dist/keys/{pukRoster.d.ts → userKeyRoster.d.ts} +73 -74
- package/dist/keys/userKeyRoster.d.ts.map +1 -0
- package/dist/keys/{pukRoster.js → userKeyRoster.js} +86 -83
- package/dist/keys/userKeyRoster.js.map +1 -0
- package/dist/recovery/index.d.ts +1 -1
- package/dist/recovery/index.js +1 -1
- package/dist/recovery/recoveryCode.d.ts +1 -1
- package/dist/recovery/recoveryCode.js +6 -6
- package/dist/recovery/recoveryRecord.d.ts +1 -1
- package/dist/recovery/recoveryWebvh.d.ts +1 -1
- package/dist/recovery/recoveryWebvh.js +1 -1
- package/dist/space/activity.d.ts +1 -1
- package/dist/space/activity.js +1 -1
- package/dist/space/collections.d.ts +17 -17
- package/dist/space/collections.d.ts.map +1 -1
- package/dist/space/collections.js +16 -16
- package/dist/space/collections.js.map +1 -1
- package/dist/space/index.d.ts +2 -2
- package/dist/space/index.d.ts.map +1 -1
- package/dist/space/index.js +2 -2
- package/dist/space/index.js.map +1 -1
- package/dist/webvh/didWebvh.d.ts +1 -1
- package/dist/webvh/didWebvh.js +6 -6
- package/package.json +1 -1
- package/dist/keys/puk.d.ts +0 -42
- package/dist/keys/puk.d.ts.map +0 -1
- package/dist/keys/puk.js.map +0 -1
- package/dist/keys/pukCascade.d.ts.map +0 -1
- package/dist/keys/pukCascade.js.map +0 -1
- package/dist/keys/pukRoster.d.ts.map +0 -1
- package/dist/keys/pukRoster.js.map +0 -1
|
@@ -8,10 +8,10 @@ import { clientSigningKeyMultibase } from '../webvh/zcap.js';
|
|
|
8
8
|
* names no epoch in its own list. The server (or whoever can write to it) has
|
|
9
9
|
* produced a configuration no enrolled client authenticated.
|
|
10
10
|
*/
|
|
11
|
-
export class
|
|
11
|
+
export class UserKeyRosterIntegrityError extends Error {
|
|
12
12
|
constructor(message) {
|
|
13
13
|
super(message);
|
|
14
|
-
this.name = '
|
|
14
|
+
this.name = 'UserKeyRosterIntegrityError';
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
@@ -21,25 +21,25 @@ export class PukRosterIntegrityError extends Error {
|
|
|
21
21
|
* an older consistent configuration, which a valid `epochsMac` alone cannot
|
|
22
22
|
* catch; refused rather than followed.
|
|
23
23
|
*/
|
|
24
|
-
export class
|
|
24
|
+
export class UserKeyRosterContinuityError extends Error {
|
|
25
25
|
pinnedEpochId;
|
|
26
26
|
constructor({ pinnedEpochId }) {
|
|
27
|
-
super('The
|
|
27
|
+
super('The user key roster no longer carries the epoch this client has pinned -- ' +
|
|
28
28
|
'a rolled-back or replayed roster.');
|
|
29
|
-
this.name = '
|
|
29
|
+
this.name = 'UserKeyRosterContinuityError';
|
|
30
30
|
this.pinnedEpochId = pinnedEpochId;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Thrown when this client holds no usable wrap in the roster's current epoch
|
|
35
35
|
* (no recipient entry for its key-agreement key, or the entry fails to
|
|
36
|
-
* unwrap). The client cannot obtain the current
|
|
36
|
+
* unwrap). The client cannot obtain the current user key -- it may have been
|
|
37
37
|
* rotated off the roster.
|
|
38
38
|
*/
|
|
39
|
-
export class
|
|
39
|
+
export class UserKeyRosterUnwrapError extends Error {
|
|
40
40
|
constructor(message) {
|
|
41
41
|
super(message);
|
|
42
|
-
this.name = '
|
|
42
|
+
this.name = 'UserKeyRosterUnwrapError';
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
@@ -63,7 +63,7 @@ const EPOCHS_SIG_ALG = 'EdDSA';
|
|
|
63
63
|
* agent (the `keyAgent` of `agentsFromSeed`)
|
|
64
64
|
* @returns {EpochsSigner} the `signEpochs` hook for roster writes
|
|
65
65
|
*/
|
|
66
|
-
export function
|
|
66
|
+
export function userKeyRosterEpochsSigner({ keyAgent }) {
|
|
67
67
|
const kid = clientSigningKeyMultibase({ keyAgent });
|
|
68
68
|
const signer = keyAgent.getSigner();
|
|
69
69
|
return async function signEpochs({ payload }) {
|
|
@@ -82,7 +82,7 @@ export function pukRosterEpochsSigner({ keyAgent }) {
|
|
|
82
82
|
* signature must be present and supported, its `kid` must be the public
|
|
83
83
|
* multibase of one of the document's verification methods (an enrolled
|
|
84
84
|
* client's signing key), and it must verify over the canonical
|
|
85
|
-
* epoch-configuration payload. Throws {@link
|
|
85
|
+
* epoch-configuration payload. Throws {@link UserKeyRosterIntegrityError}
|
|
86
86
|
* otherwise: a configuration no enrolled client signed.
|
|
87
87
|
*
|
|
88
88
|
* @param options {object}
|
|
@@ -91,16 +91,16 @@ export function pukRosterEpochsSigner({ keyAgent }) {
|
|
|
91
91
|
* did:webvh document (never a server-supplied roster field)
|
|
92
92
|
* @returns {Promise<void>}
|
|
93
93
|
*/
|
|
94
|
-
export async function
|
|
94
|
+
export async function verifyUserKeyRosterEpochsSig({ descriptor, document }) {
|
|
95
95
|
const epochsSig = descriptor.epochsSig;
|
|
96
96
|
if (!epochsSig ||
|
|
97
97
|
epochsSig.v !== EPOCHS_SIG_V ||
|
|
98
98
|
epochsSig.alg !== EPOCHS_SIG_ALG) {
|
|
99
|
-
throw new
|
|
99
|
+
throw new UserKeyRosterIntegrityError('The user key roster carries no supported epoch-configuration signature.');
|
|
100
100
|
}
|
|
101
101
|
const backed = (document.verificationMethod ?? []).some(method => method.publicKeyMultibase === epochsSig.kid);
|
|
102
102
|
if (!backed) {
|
|
103
|
-
throw new
|
|
103
|
+
throw new UserKeyRosterIntegrityError('The user key roster epoch configuration is signed by a key the account ' +
|
|
104
104
|
'document does not back.');
|
|
105
105
|
}
|
|
106
106
|
let signature;
|
|
@@ -108,7 +108,7 @@ export async function verifyPukRosterEpochsSig({ descriptor, document }) {
|
|
|
108
108
|
signature = base64urlnopad.decode(epochsSig.sig);
|
|
109
109
|
}
|
|
110
110
|
catch {
|
|
111
|
-
throw new
|
|
111
|
+
throw new UserKeyRosterIntegrityError('The user key roster epoch-configuration signature is malformed.');
|
|
112
112
|
}
|
|
113
113
|
const verifier = new Ed25519VerificationKey({
|
|
114
114
|
controller: `did:key:${epochsSig.kid}`,
|
|
@@ -119,7 +119,7 @@ export async function verifyPukRosterEpochsSig({ descriptor, document }) {
|
|
|
119
119
|
signature
|
|
120
120
|
});
|
|
121
121
|
if (!verified) {
|
|
122
|
-
throw new
|
|
122
|
+
throw new UserKeyRosterIntegrityError('The user key roster epoch-configuration signature failed verification.');
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
@@ -167,7 +167,7 @@ function multibaseFragmentOf(id) {
|
|
|
167
167
|
* did:webvh document (never a server-supplied roster field)
|
|
168
168
|
* @returns {function} a `resolveRecipientKey` for `removeRecipient`
|
|
169
169
|
*/
|
|
170
|
-
export function
|
|
170
|
+
export function userKeyRosterRecipientResolver({ document }) {
|
|
171
171
|
// Materialize the document's keyAgreement VMs once: embedded VMs verbatim,
|
|
172
172
|
// string references resolved against `verificationMethod`.
|
|
173
173
|
const byId = new Map();
|
|
@@ -199,25 +199,25 @@ export function pukRosterRecipientResolver({ document }) {
|
|
|
199
199
|
};
|
|
200
200
|
}
|
|
201
201
|
/**
|
|
202
|
-
* Ensures the roster exists, create-if-absent: an absent roster is
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
202
|
+
* Ensures the roster exists, create-if-absent: an absent roster is initialized
|
|
203
|
+
* with the account's existing user key installed as the first epoch, wrapped to
|
|
204
|
+
* this client's key-agreement key; an existing roster is returned as-is
|
|
205
|
+
* (authentication is the read path's job, and provisioning must never clobber
|
|
206
|
+
* an established roster). Idempotent -- losing the guarded-create race to a
|
|
207
|
+
* concurrent first init converges on the winner's roster.
|
|
208
208
|
*
|
|
209
209
|
* @param options {object}
|
|
210
210
|
* @param options.store {EncryptionDescriptorStore} the roster's descriptor
|
|
211
211
|
* store
|
|
212
|
-
* @param options.
|
|
212
|
+
* @param options.userKey {UserKey} the account's user key
|
|
213
213
|
* @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
|
|
214
214
|
* (identity) key-agreement key -- the roster recipient
|
|
215
215
|
* @param options.signEpochs {EpochsSigner} this client's epoch-configuration
|
|
216
|
-
* signer ({@link
|
|
216
|
+
* signer ({@link userKeyRosterEpochsSigner}), so the first configuration is
|
|
217
217
|
* vouched for by an enrollable key rather than only its own MAC
|
|
218
218
|
* @returns {Promise<CollectionEncryption>} the roster descriptor
|
|
219
219
|
*/
|
|
220
|
-
export async function
|
|
220
|
+
export async function ensureUserKeyRoster({ store, userKey, clientKeyAgreementKey, signEpochs }) {
|
|
221
221
|
const current = await store.read();
|
|
222
222
|
if (current !== null) {
|
|
223
223
|
return current.descriptor;
|
|
@@ -225,12 +225,12 @@ export async function ensurePukRoster({ store, puk, clientKeyAgreementKey, signE
|
|
|
225
225
|
return initRecipients({
|
|
226
226
|
store,
|
|
227
227
|
recipients: [ownerRecipient({ keyAgreementKey: clientKeyAgreementKey })],
|
|
228
|
-
epoch: { epochId:
|
|
228
|
+
epoch: { epochId: userKey.id, secret: userKey.secret },
|
|
229
229
|
signEpochs
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
232
|
/**
|
|
233
|
-
* Wraps the
|
|
233
|
+
* Wraps the user key to a client being enrolled -- the roster half of the
|
|
234
234
|
* enrollment ceremony, and deliberately its FIRST write (decryption material
|
|
235
235
|
* before authorization, the push order): the wrap lands before the did:webvh
|
|
236
236
|
* log entries, so no enrolled client is ever authorized but blind, and a tear
|
|
@@ -255,10 +255,10 @@ export async function ensurePukRoster({ store, puk, clientKeyAgreementKey, signE
|
|
|
255
255
|
* re-wrapping
|
|
256
256
|
* @returns {Promise<CollectionEncryption>} the refreshed roster descriptor
|
|
257
257
|
*/
|
|
258
|
-
export async function
|
|
258
|
+
export async function addUserKeyRosterRecipient({ store, recipient, ownerKeyAgreementKey }) {
|
|
259
259
|
const current = await store.read();
|
|
260
260
|
if (current === null) {
|
|
261
|
-
throw new Error('The
|
|
261
|
+
throw new Error('The user key roster does not exist yet; the account must finish ' +
|
|
262
262
|
'provisioning before a client can be enrolled.');
|
|
263
263
|
}
|
|
264
264
|
const descriptor = current.descriptor;
|
|
@@ -277,16 +277,16 @@ export async function addPukRosterRecipient({ store, recipient, ownerKeyAgreemen
|
|
|
277
277
|
});
|
|
278
278
|
}
|
|
279
279
|
/**
|
|
280
|
-
* Rotates the
|
|
281
|
-
* enrolled wallet client or a recovery code. A thin, deliberate composition
|
|
280
|
+
* Rotates the user key roster off one recipient -- the roster half of revoking
|
|
281
|
+
* an enrolled wallet client or a recovery code. A thin, deliberate composition
|
|
282
282
|
* of was-client's `removeRecipient` with the two roster-specific choices
|
|
283
|
-
* spelled once: the remaining recipients are resolved from the locally
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
283
|
+
* spelled once: the remaining recipients are resolved from the locally verified
|
|
284
|
+
* did:webvh document ("the roster delivers, never sources" -- an entry with no
|
|
285
|
+
* matching `keyAgreement` verification method is dropped and never receives a
|
|
286
|
+
* wrap), and the pull axis is a no-op, because for a roster recipient the pull
|
|
287
|
+
* axis IS the document edit the caller performed first -- under the
|
|
288
|
+
* current-key-set rule the removed party's server-side access died the moment
|
|
289
|
+
* its verification method left the document.
|
|
290
290
|
*
|
|
291
291
|
* @param options {object}
|
|
292
292
|
* @param options.store {EncryptionDescriptorStore} the roster's descriptor
|
|
@@ -296,15 +296,15 @@ export async function addPukRosterRecipient({ store, recipient, ownerKeyAgreemen
|
|
|
296
296
|
* @param options.retireRecipientId {string} the removed recipient's roster
|
|
297
297
|
* kid
|
|
298
298
|
* @param options.signEpochs {EpochsSigner} the rotating client's
|
|
299
|
-
* epoch-configuration signer ({@link
|
|
299
|
+
* epoch-configuration signer ({@link userKeyRosterEpochsSigner}), vouching for
|
|
300
300
|
* the fresh epoch so other clients' rotated reads accept it
|
|
301
301
|
* @returns {Promise<CollectionEncryption>} the rotated roster descriptor
|
|
302
302
|
*/
|
|
303
|
-
export async function
|
|
303
|
+
export async function rotateUserKeyRoster({ store, document, retireRecipientId, signEpochs }) {
|
|
304
304
|
return removeRecipient({
|
|
305
305
|
store,
|
|
306
306
|
recipientId: retireRecipientId,
|
|
307
|
-
resolveRecipientKey:
|
|
307
|
+
resolveRecipientKey: userKeyRosterRecipientResolver({ document }),
|
|
308
308
|
pull: async () => { },
|
|
309
309
|
signEpochs
|
|
310
310
|
});
|
|
@@ -313,7 +313,7 @@ export async function rotatePukRoster({ store, document, retireRecipientId, sign
|
|
|
313
313
|
* Converges the roster onto the account document: the standing detector for a
|
|
314
314
|
* revocation cascade torn between its two halves. The cascade edits the
|
|
315
315
|
* document first and rotates the roster second, so a client that crashes in
|
|
316
|
-
* between leaves a roster that keeps wrapping the CURRENT
|
|
316
|
+
* between leaves a roster that keeps wrapping the CURRENT user key to a
|
|
317
317
|
* recipient the document no longer keys -- durable, silent, and permanent,
|
|
318
318
|
* since the revoked client's document edit will never be re-run.
|
|
319
319
|
*
|
|
@@ -321,7 +321,7 @@ export async function rotatePukRoster({ store, document, retireRecipientId, sign
|
|
|
321
321
|
* document-backed resolver cannot answer for is exactly a recipient the
|
|
322
322
|
* document no longer keys, so a healthy account reads the descriptor and
|
|
323
323
|
* writes nothing. When any such recipient is found the roster is rotated away
|
|
324
|
-
* from ALL of them at once -- a single {@link
|
|
324
|
+
* from ALL of them at once -- a single {@link rotateUserKeyRoster} suffices,
|
|
325
325
|
* because the resolver drops every unbacked entry from the fresh epoch, not
|
|
326
326
|
* just the one named as retiring.
|
|
327
327
|
*
|
|
@@ -330,8 +330,8 @@ export async function rotatePukRoster({ store, document, retireRecipientId, sign
|
|
|
330
330
|
* account), not a cascade to finish, and completing it would lock every
|
|
331
331
|
* client out of the account.
|
|
332
332
|
*
|
|
333
|
-
* The fresh
|
|
334
|
-
* ordinary way, by re-reading the roster ({@link
|
|
333
|
+
* The fresh user key itself is not returned: the caller adopts it the
|
|
334
|
+
* ordinary way, by re-reading the roster ({@link readUserKeyRoster}) once
|
|
335
335
|
* `rotated` says there is something to adopt, and then runs the collection
|
|
336
336
|
* fan-out.
|
|
337
337
|
*
|
|
@@ -344,13 +344,13 @@ export async function rotatePukRoster({ store, document, retireRecipientId, sign
|
|
|
344
344
|
* has just read (a login-time roster read), to save a re-read; omitted, the
|
|
345
345
|
* roster is read fresh
|
|
346
346
|
* @param options.signEpochs {EpochsSigner} the converging client's
|
|
347
|
-
* epoch-configuration signer ({@link
|
|
347
|
+
* epoch-configuration signer ({@link userKeyRosterEpochsSigner}), for the
|
|
348
348
|
* rotation this call may perform
|
|
349
349
|
* @returns {Promise<object>} whether the roster rotated on this call, the
|
|
350
350
|
* stale recipient kids found, and the roster descriptor as it now stands
|
|
351
351
|
* (`null` when the account has no roster yet)
|
|
352
352
|
*/
|
|
353
|
-
export async function
|
|
353
|
+
export async function convergeUserKeyRosterToDocument({ store, document, descriptor, signEpochs }) {
|
|
354
354
|
let roster = descriptor;
|
|
355
355
|
if (!roster) {
|
|
356
356
|
const read = await store.read();
|
|
@@ -362,9 +362,9 @@ export async function convergePukRosterToDocument({ store, document, descriptor,
|
|
|
362
362
|
const currentEpochId = roster.currentEpoch;
|
|
363
363
|
const currentEpoch = (roster.epochs ?? []).find(epoch => epoch.id === currentEpochId);
|
|
364
364
|
if (!currentEpoch) {
|
|
365
|
-
throw new
|
|
365
|
+
throw new UserKeyRosterIntegrityError('The user key roster names no current epoch in its own epoch list.');
|
|
366
366
|
}
|
|
367
|
-
const resolveRecipientKey =
|
|
367
|
+
const resolveRecipientKey = userKeyRosterRecipientResolver({ document });
|
|
368
368
|
const staleRecipientIds = [];
|
|
369
369
|
let backed = 0;
|
|
370
370
|
for (const entry of currentEpoch.recipients) {
|
|
@@ -380,12 +380,12 @@ export async function convergePukRosterToDocument({ store, document, descriptor,
|
|
|
380
380
|
return { rotated: false, staleRecipientIds, descriptor: roster };
|
|
381
381
|
}
|
|
382
382
|
if (backed === 0) {
|
|
383
|
-
throw new
|
|
383
|
+
throw new UserKeyRosterIntegrityError('No user key roster recipient is keyed by the account document; refusing ' +
|
|
384
384
|
'to rotate the roster onto no one.');
|
|
385
385
|
}
|
|
386
386
|
// One rotation retires them all: the fresh epoch is wrapped only to the
|
|
387
387
|
// recipients the resolver answers for.
|
|
388
|
-
const rotated = await
|
|
388
|
+
const rotated = await rotateUserKeyRoster({
|
|
389
389
|
store,
|
|
390
390
|
document,
|
|
391
391
|
retireRecipientId: staleRecipientIds[0],
|
|
@@ -400,39 +400,39 @@ export async function convergePukRosterToDocument({ store, document, descriptor,
|
|
|
400
400
|
*
|
|
401
401
|
* 1. **Continuity**: the served epochs must contain the pinned latest-seen
|
|
402
402
|
* epoch, and `currentEpoch` must not precede it in the append-only list
|
|
403
|
-
* (`
|
|
404
|
-
* 2. **Possession**: `currentEpoch ===
|
|
403
|
+
* (`UserKeyRosterContinuityError` -- the rollback/replay refusal).
|
|
404
|
+
* 2. **Possession**: `currentEpoch === userKey.id` confirms the cached user key
|
|
405
405
|
* current; otherwise the current epoch was rotated by another client and
|
|
406
406
|
* this client's wrap is unwrapped with its own key-agreement key
|
|
407
|
-
* (`
|
|
407
|
+
* (`UserKeyRosterUnwrapError` when it holds none).
|
|
408
408
|
* 3. **Provenance** (the rotated/first-read path only): the epoch
|
|
409
409
|
* configuration's `epochsSig` is verified against the locally verified
|
|
410
|
-
* did:webvh document ({@link
|
|
410
|
+
* did:webvh document ({@link verifyUserKeyRosterEpochsSig}) BEFORE the epoch
|
|
411
411
|
* it delivers is adopted. On this path the `epochsMac` alone proves
|
|
412
412
|
* nothing against the host -- its key is unwrapped from the served
|
|
413
413
|
* descriptor itself -- so an epoch no enrolled client signed is refused
|
|
414
|
-
* (`
|
|
414
|
+
* (`UserKeyRosterIntegrityError`). The cached-current path needs no signature:
|
|
415
415
|
* there the MAC is keyed by a secret this client already trusts.
|
|
416
416
|
* 4. **Authentication**: the descriptor's `epochsMac` is verified under the
|
|
417
|
-
* current epoch's secret (`
|
|
417
|
+
* current epoch's secret (`UserKeyRosterIntegrityError` on any mismatch -- a
|
|
418
418
|
* fabricated configuration).
|
|
419
419
|
*
|
|
420
|
-
* A rotated read returns the fresh
|
|
420
|
+
* A rotated read returns the fresh user key; its Ed25519 signing seed does not
|
|
421
421
|
* travel through the roster (the roster wraps the key-agreement secret
|
|
422
|
-
* alone), so the returned
|
|
422
|
+
* alone), so the returned user key carries none.
|
|
423
423
|
*
|
|
424
|
-
* A caller with no cached
|
|
425
|
-
* first post-enrollment read -- omits `
|
|
426
|
-
* the result's `rotated` is then true (the
|
|
427
|
-
* Every unwrap-path caller must therefore supply the account document
|
|
428
|
-
* way to resolve it): `document` when it already holds a verified copy,
|
|
429
|
-
* `resolveDocument` to fetch-and-verify lazily, only when the read actually
|
|
424
|
+
* A caller with no cached user key at all -- a freshly enrolled client making
|
|
425
|
+
* its first post-enrollment read -- omits `userKey` and always takes the unwrap
|
|
426
|
+
* path; the result's `rotated` is then true (the user key was adopted from the
|
|
427
|
+
* roster). Every unwrap-path caller must therefore supply the account document
|
|
428
|
+
* (or a way to resolve it): `document` when it already holds a verified copy,
|
|
429
|
+
* or `resolveDocument` to fetch-and-verify lazily, only when the read actually
|
|
430
430
|
* rotates.
|
|
431
431
|
*
|
|
432
432
|
* @param options {object}
|
|
433
433
|
* @param options.store {EncryptionDescriptorStore} the roster's descriptor
|
|
434
434
|
* store
|
|
435
|
-
* @param [options.
|
|
435
|
+
* @param [options.userKey] {UserKey} this client's cached user key, when it holds one
|
|
436
436
|
* @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
|
|
437
437
|
* (identity) key-agreement key, unwrapping a rotated epoch
|
|
438
438
|
* @param [options.pinnedEpochId] {string} the locally pinned latest-seen
|
|
@@ -442,9 +442,9 @@ export async function convergePukRosterToDocument({ store, document, descriptor,
|
|
|
442
442
|
* @param [options.resolveDocument] {function} resolves the locally verified
|
|
443
443
|
* did:webvh document on demand; called only when the read takes the
|
|
444
444
|
* rotated/first-read path
|
|
445
|
-
* @returns {Promise<
|
|
445
|
+
* @returns {Promise<UserKeyRosterReadResult | null>}
|
|
446
446
|
*/
|
|
447
|
-
export async function
|
|
447
|
+
export async function readUserKeyRoster({ store, userKey, clientKeyAgreementKey, pinnedEpochId, document, resolveDocument }) {
|
|
448
448
|
const current = await store.read();
|
|
449
449
|
if (current === null) {
|
|
450
450
|
return null;
|
|
@@ -455,23 +455,23 @@ export async function readPukRoster({ store, puk, clientKeyAgreementKey, pinnedE
|
|
|
455
455
|
? epochIds.indexOf(descriptor.currentEpoch)
|
|
456
456
|
: -1;
|
|
457
457
|
if (currentIndex === -1) {
|
|
458
|
-
throw new
|
|
458
|
+
throw new UserKeyRosterIntegrityError('The user key roster names no current epoch in its own epoch list.');
|
|
459
459
|
}
|
|
460
460
|
if (pinnedEpochId) {
|
|
461
461
|
const pinnedIndex = epochIds.indexOf(pinnedEpochId);
|
|
462
462
|
if (pinnedIndex === -1 || currentIndex < pinnedIndex) {
|
|
463
|
-
throw new
|
|
463
|
+
throw new UserKeyRosterContinuityError({ pinnedEpochId });
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
466
|
// The epochsMac construction's own version/alg are the caller's to check.
|
|
467
467
|
const epochsMac = descriptor.epochsMac;
|
|
468
468
|
if (!epochsMac || epochsMac.v !== 1 || epochsMac.alg !== 'HS256') {
|
|
469
|
-
throw new
|
|
469
|
+
throw new UserKeyRosterIntegrityError('The user key roster carries no supported epoch-configuration MAC.');
|
|
470
470
|
}
|
|
471
|
-
let
|
|
471
|
+
let currentUserKey;
|
|
472
472
|
let rotated;
|
|
473
|
-
if (
|
|
474
|
-
|
|
473
|
+
if (userKey && descriptor.currentEpoch === userKey.id) {
|
|
474
|
+
currentUserKey = userKey;
|
|
475
475
|
rotated = false;
|
|
476
476
|
}
|
|
477
477
|
else {
|
|
@@ -483,35 +483,38 @@ export async function readPukRoster({ store, puk, clientKeyAgreementKey, pinnedE
|
|
|
483
483
|
// itself.
|
|
484
484
|
const accountDocument = document ?? (resolveDocument ? await resolveDocument() : undefined);
|
|
485
485
|
if (!accountDocument) {
|
|
486
|
-
throw new Error('A
|
|
486
|
+
throw new Error('A user key roster read that adopts an epoch from the roster needs the ' +
|
|
487
487
|
'account document (pass `document` or `resolveDocument`) to verify ' +
|
|
488
488
|
'the epoch configuration signature.');
|
|
489
489
|
}
|
|
490
|
-
await
|
|
490
|
+
await verifyUserKeyRosterEpochsSig({
|
|
491
|
+
descriptor,
|
|
492
|
+
document: accountDocument
|
|
493
|
+
});
|
|
491
494
|
// Unwrap this client's entry in the current epoch with its own
|
|
492
495
|
// key-agreement key (rotation delivery).
|
|
493
496
|
const entry = descriptor.epochs[currentIndex].recipients.find(recipient => recipient.header.kid === clientKeyAgreementKey.id);
|
|
494
497
|
if (!entry) {
|
|
495
|
-
throw new
|
|
498
|
+
throw new UserKeyRosterUnwrapError('The user key roster current epoch carries no wrap for this client.');
|
|
496
499
|
}
|
|
497
500
|
const secret = await unwrapEpochSecret({
|
|
498
501
|
entry,
|
|
499
502
|
keyAgreementKey: clientKeyAgreementKey
|
|
500
503
|
});
|
|
501
504
|
if (!secret) {
|
|
502
|
-
throw new
|
|
505
|
+
throw new UserKeyRosterUnwrapError("This client's user key roster entry failed to unwrap.");
|
|
503
506
|
}
|
|
504
|
-
|
|
507
|
+
currentUserKey = { id: descriptor.currentEpoch, secret };
|
|
505
508
|
rotated = true;
|
|
506
509
|
}
|
|
507
|
-
if (!(await verifyEpochsMac({ descriptor, epochSecret:
|
|
508
|
-
throw new
|
|
510
|
+
if (!(await verifyEpochsMac({ descriptor, epochSecret: currentUserKey.secret }))) {
|
|
511
|
+
throw new UserKeyRosterIntegrityError('The user key roster epoch configuration failed authentication.');
|
|
509
512
|
}
|
|
510
513
|
return {
|
|
511
514
|
descriptor,
|
|
512
|
-
|
|
515
|
+
userKey: currentUserKey,
|
|
513
516
|
rotated,
|
|
514
517
|
latestEpochId: descriptor.currentEpoch
|
|
515
518
|
};
|
|
516
519
|
}
|
|
517
|
-
//# sourceMappingURL=
|
|
520
|
+
//# sourceMappingURL=userKeyRoster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userKeyRoster.js","sourceRoot":"","sources":["../../src/keys/userKeyRoster.ts"],"names":[],"mappings":"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"}
|
package/dist/recovery/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* single did:webvh update key whose hash stands pre-committed.
|
|
15
15
|
* - `wrapRecoveryRecord` / `unwrapRecoveryRecord` -- the keyring-record
|
|
16
16
|
* sibling carrying the account pointer plus the pre-minted
|
|
17
|
-
* PUT-on-`did.jsonl` delegation (never a seed, never a
|
|
17
|
+
* PUT-on-`did.jsonl` delegation (never a seed, never a user key wrap).
|
|
18
18
|
* - `publishRecoveryKey` / `removeRecoveryKey` / `recoverWebvhClient` -- the
|
|
19
19
|
* document half: issuance's split posture, revocation's removal, and the
|
|
20
20
|
* self-enrolling recovery continuation.
|
package/dist/recovery/index.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* single did:webvh update key whose hash stands pre-committed.
|
|
15
15
|
* - `wrapRecoveryRecord` / `unwrapRecoveryRecord` -- the keyring-record
|
|
16
16
|
* sibling carrying the account pointer plus the pre-minted
|
|
17
|
-
* PUT-on-`did.jsonl` delegation (never a seed, never a
|
|
17
|
+
* PUT-on-`did.jsonl` delegation (never a seed, never a user key wrap).
|
|
18
18
|
* - `publishRecoveryKey` / `removeRecoveryKey` / `recoverWebvhClient` -- the
|
|
19
19
|
* document half: issuance's split posture, revocation's removal, and the
|
|
20
20
|
* self-enrolling recovery continuation.
|
|
@@ -83,7 +83,7 @@ export interface RecoveryClient {
|
|
|
83
83
|
keyAgreementKeyMultibase: string;
|
|
84
84
|
updateKeyMultibase: string;
|
|
85
85
|
/**
|
|
86
|
-
* The kid of the code's
|
|
86
|
+
* The kid of the code's user-key-roster entry -- its key-agreement key's id
|
|
87
87
|
* exactly as `agentsFromSeed` derives it (`did:key:<ed>#<x>`), so the wrap
|
|
88
88
|
* minted at issuance is the one the recovery flow's roster read looks for.
|
|
89
89
|
*/
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
* The recovery-code format layer and its deterministic derivations. A recovery
|
|
6
6
|
* code is 16 random bytes rendered as base58 (Bitcoin alphabet), shown to the
|
|
7
7
|
* user exactly once at issuance. Under the roster identity model the code is a
|
|
8
|
-
* **minimal always-enrolled wallet client**: everything the code needs to
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* **minimal always-enrolled wallet client**: everything the code needs to act
|
|
9
|
+
* -- the unlock identity that locates its keyring record, the client key set
|
|
10
|
+
* behind its `keyAgreement` verification method and user-key-roster wrap, and
|
|
11
|
+
* the did:webvh update key whose hash stands pre-committed in `nextKeyHashes`
|
|
12
|
+
* -- derives deterministically from the code's bytes, so the key material
|
|
13
|
+
* exists nowhere until the code is typed.
|
|
14
14
|
*
|
|
15
15
|
* The derivations are wire-level: two wallet apps must produce byte-identical
|
|
16
16
|
* output for the same code, or a code issued in one could not recover in the
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* is the ordinary keyring record's (controller, email, account pointer) PLUS
|
|
8
8
|
* the pre-minted PUT-on-`did.jsonl` delegation -- the narrow zcap bridge that
|
|
9
9
|
* lets the code-derived client write its self-enrolling log continuation. It
|
|
10
|
-
* carries **no key material of any kind**: never a seed, never a
|
|
10
|
+
* carries **no key material of any kind**: never a seed, never a user key wrap
|
|
11
11
|
* (wraps live doc-and-roster only), so the record stays a pure pointer.
|
|
12
12
|
*
|
|
13
13
|
* The wrap reuses the keyring cipher context verbatim, so a recovery record
|
|
@@ -64,7 +64,7 @@ export declare function publishRecoveryKey({ idStore, updateKeys, recovery }: {
|
|
|
64
64
|
* REVOCATION (run by an enrolled client, root authority): removes a recovery
|
|
65
65
|
* code's posture from the document -- its `keyAgreement` verification method
|
|
66
66
|
* and its committed update-key hash -- in one entry. Idempotent. The
|
|
67
|
-
* roster-side half (rotating the
|
|
67
|
+
* roster-side half (rotating the user key epoch off the code's wrap) is the
|
|
68
68
|
* caller's, and runs after this so the resolver's document no longer backs
|
|
69
69
|
* the removed entry.
|
|
70
70
|
*
|
|
@@ -165,7 +165,7 @@ export async function publishRecoveryKey({ idStore, updateKeys, recovery }) {
|
|
|
165
165
|
* REVOCATION (run by an enrolled client, root authority): removes a recovery
|
|
166
166
|
* code's posture from the document -- its `keyAgreement` verification method
|
|
167
167
|
* and its committed update-key hash -- in one entry. Idempotent. The
|
|
168
|
-
* roster-side half (rotating the
|
|
168
|
+
* roster-side half (rotating the user key epoch off the code's wrap) is the
|
|
169
169
|
* caller's, and runs after this so the resolver's document no longer backs
|
|
170
170
|
* the removed entry.
|
|
171
171
|
*
|
package/dist/space/activity.d.ts
CHANGED
|
@@ -179,7 +179,7 @@ export declare function addHistoryLogin({ user, origin, grants, appConnect, id,
|
|
|
179
179
|
/**
|
|
180
180
|
* The ClientRevoke activity: the user disconnected an enrolled wallet client
|
|
181
181
|
* -- its verification methods and update key left the did:webvh document, the
|
|
182
|
-
*
|
|
182
|
+
* user key rotated, and the encrypted collections re-epoch'd (the revocation
|
|
183
183
|
* cascade).
|
|
184
184
|
*
|
|
185
185
|
* @param options {object}
|
package/dist/space/activity.js
CHANGED
|
@@ -207,7 +207,7 @@ export function addHistoryLogin({ user, origin, grants, appConnect, id, created
|
|
|
207
207
|
/**
|
|
208
208
|
* The ClientRevoke activity: the user disconnected an enrolled wallet client
|
|
209
209
|
* -- its verification methods and update key left the did:webvh document, the
|
|
210
|
-
*
|
|
210
|
+
* user key rotated, and the encrypted collections re-epoch'd (the revocation
|
|
211
211
|
* cascade).
|
|
212
212
|
*
|
|
213
213
|
* @param options {object}
|
|
@@ -82,7 +82,7 @@ export declare const WALLET_SPACE_COLLECTION_SPECS: SpaceCollectionSpec[];
|
|
|
82
82
|
* document, so the did:web id is `did:web:<host>:space:<spaceId>:id` and
|
|
83
83
|
* resolves to `https://<host>/space/<spaceId>/id/did.json`.
|
|
84
84
|
* - `key-map` -- private and capability-gated: the key-id map (`keys.json`)
|
|
85
|
-
* and the
|
|
85
|
+
* and the user key wrap-set roster (`user-key.json`). Kept separate from `id` exactly
|
|
86
86
|
* so `id` can be made world-readable without ever exposing key material.
|
|
87
87
|
* - `keyring` -- the unlock Space's single collection, holding the one
|
|
88
88
|
* keyring record (`keyring.json`). It lives in the minimal unlock Space
|
|
@@ -119,22 +119,22 @@ export declare const DID_LOG_RESOURCE = "did.jsonl";
|
|
|
119
119
|
*/
|
|
120
120
|
export declare const DID_KEYS_RESOURCE = "keys.json";
|
|
121
121
|
/**
|
|
122
|
-
* The per-user-key (
|
|
123
|
-
* private `key-map` collection: a `CollectionEncryption` descriptor stored
|
|
124
|
-
* verbatim as the resource body, whose current epoch IS the current
|
|
125
|
-
* epoch id is the
|
|
126
|
-
* wrapped to each enrolled client's key-agreement key). Read directly
|
|
127
|
-
* compare-and-swap etag -- never replicated.
|
|
128
|
-
*/
|
|
129
|
-
export declare const
|
|
130
|
-
/**
|
|
131
|
-
* The enrolled-client display labels, sibling of `keys.json` and
|
|
132
|
-
* in the same private `key-map` collection: a plain-JSON map
|
|
133
|
-
* signing-key multibase to its human-chosen label. Display
|
|
134
|
-
* the did:webvh document carries key material, never labels --
|
|
135
|
-
* by the collection's convention: the storage host can read the
|
|
136
|
-
* it already serves the world-readable log that names every client
|
|
137
|
-
* label adds only the display name.
|
|
122
|
+
* The per-user-key (user key) wrap-set roster, sibling of `keys.json` in the
|
|
123
|
+
* same private `key-map` collection: a `CollectionEncryption` descriptor stored
|
|
124
|
+
* verbatim as the resource body, whose current epoch IS the current user key
|
|
125
|
+
* (the epoch id is the user key's did:key; the wrapped secret is the user key's
|
|
126
|
+
* raw key, wrapped to each enrolled client's key-agreement key). Read directly
|
|
127
|
+
* with a compare-and-swap etag -- never replicated.
|
|
128
|
+
*/
|
|
129
|
+
export declare const USER_KEY_ROSTER_RESOURCE = "user-key.json";
|
|
130
|
+
/**
|
|
131
|
+
* The enrolled-client display labels, sibling of `keys.json` and
|
|
132
|
+
* `user-key.json` in the same private `key-map` collection: a plain-JSON map
|
|
133
|
+
* from a client's signing-key multibase to its human-chosen label. Display
|
|
134
|
+
* metadata only -- the did:webvh document carries key material, never labels --
|
|
135
|
+
* and plaintext by the collection's convention: the storage host can read the
|
|
136
|
+
* labels, but it already serves the world-readable log that names every client
|
|
137
|
+
* key, so a label adds only the display name.
|
|
138
138
|
*/
|
|
139
139
|
export declare const CLIENT_LABELS_RESOURCE = "client-labels.json";
|
|
140
140
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/space/collections.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AAEH;;GAEG;AACH,eAAO,MAAM,8BAA8B,wBAAwB,CAAA;AACnE;;GAEG;AACH,eAAO,MAAM,6BAA6B,uBAAuB,CAAA;AACjE;;GAEG;AACH,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,SAAS,GAAG,QAAQ,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,KAAK,GAAG,WAAW,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,mCAAmC,EAAE,mBAMjD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,mBAMhD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE,mBAM7C,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,6BAA6B,EAAE,mBAAmB,EAI9D,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,aAAa;;;CAAiC,CAAA;AAC3D,eAAO,MAAM,kBAAkB;;;CAAqC,CAAA;AACpE,eAAO,MAAM,kBAAkB;;;CAAqC,CAAA;AAEpE;;GAEG;AACH,eAAO,MAAM,qBAAqB,aAAa,CAAA;AAC/C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,cAAc,CAAA;AAC3C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,cAAc,CAAA;AAC5C;;;;;;;GAOG;AACH,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/space/collections.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AAEH;;GAEG;AACH,eAAO,MAAM,8BAA8B,wBAAwB,CAAA;AACnE;;GAEG;AACH,eAAO,MAAM,6BAA6B,uBAAuB,CAAA;AACjE;;GAEG;AACH,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,SAAS,GAAG,QAAQ,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,KAAK,GAAG,WAAW,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,mCAAmC,EAAE,mBAMjD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,mBAMhD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE,mBAM7C,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,6BAA6B,EAAE,mBAAmB,EAI9D,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,aAAa;;;CAAiC,CAAA;AAC3D,eAAO,MAAM,kBAAkB;;;CAAqC,CAAA;AACpE,eAAO,MAAM,kBAAkB;;;CAAqC,CAAA;AAEpE;;GAEG;AACH,eAAO,MAAM,qBAAqB,aAAa,CAAA;AAC/C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,cAAc,CAAA;AAC3C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,cAAc,CAAA;AAC5C;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,kBAAkB,CAAA;AACvD;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,uBAAuB,CAAA;AAC1D;;GAEG;AACH,eAAO,MAAM,gBAAgB,iBAAiB,CAAA"}
|