@interop/wallet-core 0.48.0 → 0.50.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 +5 -2
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts +118 -0
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts.map +1 -0
- package/dist/clientAnnex/credentialAnchoredGenesis.js +174 -0
- package/dist/clientAnnex/credentialAnchoredGenesis.js.map +1 -0
- package/dist/clientAnnex/forget.d.ts +138 -0
- package/dist/clientAnnex/forget.d.ts.map +1 -0
- package/dist/clientAnnex/forget.js +133 -0
- package/dist/clientAnnex/forget.js.map +1 -0
- package/dist/clientAnnex/forgetLast.d.ts +267 -0
- package/dist/clientAnnex/forgetLast.d.ts.map +1 -0
- package/dist/clientAnnex/forgetLast.js +374 -0
- package/dist/clientAnnex/forgetLast.js.map +1 -0
- package/dist/clientAnnex/gc.d.ts +255 -0
- package/dist/clientAnnex/gc.d.ts.map +1 -0
- package/dist/clientAnnex/gc.js +445 -0
- package/dist/clientAnnex/gc.js.map +1 -0
- package/dist/clientAnnex/index.d.ts +60 -0
- package/dist/clientAnnex/index.d.ts.map +1 -0
- package/dist/clientAnnex/index.js +60 -0
- package/dist/clientAnnex/index.js.map +1 -0
- package/dist/{unlock → clientAnnex}/ladder.d.ts +99 -23
- package/dist/clientAnnex/ladder.d.ts.map +1 -0
- package/dist/clientAnnex/ladder.js +474 -0
- package/dist/clientAnnex/ladder.js.map +1 -0
- package/dist/clientAnnex/ladderAnchored.d.ts +276 -0
- package/dist/clientAnnex/ladderAnchored.d.ts.map +1 -0
- package/dist/clientAnnex/ladderAnchored.js +631 -0
- package/dist/clientAnnex/ladderAnchored.js.map +1 -0
- package/dist/{webvh/companion.d.ts → clientAnnex/log.d.ts} +373 -152
- package/dist/clientAnnex/log.d.ts.map +1 -0
- package/dist/{webvh/companion.js → clientAnnex/log.js} +654 -261
- package/dist/clientAnnex/log.js.map +1 -0
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts +103 -0
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -0
- package/dist/clientAnnex/recoveryLadderAnchored.js +263 -0
- package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -0
- package/dist/{unlock → clientAnnex}/selfEnroll.d.ts +1 -1
- package/dist/clientAnnex/selfEnroll.d.ts.map +1 -0
- package/dist/{unlock → clientAnnex}/selfEnroll.js +1 -1
- package/dist/clientAnnex/selfEnroll.js.map +1 -0
- package/dist/clientAnnex/zcap.d.ts +49 -0
- package/dist/clientAnnex/zcap.d.ts.map +1 -0
- package/dist/clientAnnex/zcap.js +101 -0
- package/dist/clientAnnex/zcap.js.map +1 -0
- package/dist/clients/index.d.ts +9 -6
- package/dist/clients/index.d.ts.map +1 -1
- package/dist/clients/index.js +8 -5
- package/dist/clients/index.js.map +1 -1
- package/dist/clients/listing.d.ts +32 -0
- package/dist/clients/listing.d.ts.map +1 -1
- package/dist/clients/listing.js +47 -1
- package/dist/clients/listing.js.map +1 -1
- package/dist/clients/revocation.d.ts +33 -1
- package/dist/clients/revocation.d.ts.map +1 -1
- package/dist/clients/revocation.js +16 -4
- package/dist/clients/revocation.js.map +1 -1
- package/dist/enrollment/index.d.ts +6 -4
- package/dist/enrollment/index.d.ts.map +1 -1
- package/dist/enrollment/index.js +6 -4
- package/dist/enrollment/index.js.map +1 -1
- package/dist/enrollment/onboardingInvite.d.ts +5 -88
- package/dist/enrollment/onboardingInvite.d.ts.map +1 -1
- package/dist/enrollment/onboardingInvite.js +5 -168
- package/dist/enrollment/onboardingInvite.js.map +1 -1
- package/dist/genesis/index.d.ts +5 -0
- package/dist/genesis/index.d.ts.map +1 -1
- package/dist/genesis/index.js +5 -0
- package/dist/genesis/index.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/spaceEpochs.d.ts +7 -2
- package/dist/keys/spaceEpochs.d.ts.map +1 -1
- package/dist/keys/spaceEpochs.js +8 -2
- package/dist/keys/spaceEpochs.js.map +1 -1
- package/dist/keys/userKeyRoster.d.ts +39 -0
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +43 -1
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/recovery/index.d.ts +5 -3
- package/dist/recovery/index.d.ts.map +1 -1
- package/dist/recovery/index.js +4 -2
- package/dist/recovery/index.js.map +1 -1
- package/dist/recovery/recoveryDelegation.d.ts +35 -12
- package/dist/recovery/recoveryDelegation.d.ts.map +1 -1
- package/dist/recovery/recoveryDelegation.js +84 -86
- package/dist/recovery/recoveryDelegation.js.map +1 -1
- package/dist/recovery/recoveryWebvh.d.ts +32 -1
- package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
- package/dist/recovery/recoveryWebvh.js +2 -2
- package/dist/recovery/recoveryWebvh.js.map +1 -1
- package/dist/request/capabilityRequest.d.ts +33 -0
- package/dist/request/capabilityRequest.d.ts.map +1 -0
- package/dist/request/capabilityRequest.js +35 -0
- package/dist/request/capabilityRequest.js.map +1 -0
- package/dist/request/ephemeralExchange.d.ts +118 -0
- package/dist/request/ephemeralExchange.d.ts.map +1 -0
- package/dist/request/ephemeralExchange.js +224 -0
- package/dist/request/ephemeralExchange.js.map +1 -0
- package/dist/request/index.d.ts +6 -0
- package/dist/request/index.d.ts.map +1 -1
- package/dist/request/index.js +6 -0
- package/dist/request/index.js.map +1 -1
- package/dist/space/activity.d.ts +38 -0
- package/dist/space/activity.d.ts.map +1 -1
- package/dist/space/activity.js +41 -1
- package/dist/space/activity.js.map +1 -1
- package/dist/space/index.d.ts +1 -1
- package/dist/space/index.d.ts.map +1 -1
- package/dist/space/index.js +1 -1
- package/dist/space/index.js.map +1 -1
- package/dist/unlock/index.d.ts +11 -23
- package/dist/unlock/index.d.ts.map +1 -1
- package/dist/unlock/index.js +10 -21
- package/dist/unlock/index.js.map +1 -1
- package/dist/unlock/retire.d.ts +47 -3
- package/dist/unlock/retire.d.ts.map +1 -1
- package/dist/unlock/retire.js +21 -5
- package/dist/unlock/retire.js.map +1 -1
- package/dist/unlock/standingWebvh.d.ts +37 -82
- package/dist/unlock/standingWebvh.d.ts.map +1 -1
- package/dist/unlock/standingWebvh.js +64 -247
- package/dist/unlock/standingWebvh.js.map +1 -1
- package/dist/unlock/unlockRecord.d.ts +13 -6
- package/dist/unlock/unlockRecord.d.ts.map +1 -1
- package/dist/unlock/unlockRecord.js +14 -8
- package/dist/unlock/unlockRecord.js.map +1 -1
- package/dist/webvh/delegatedLogStore.d.ts +5 -5
- package/dist/webvh/delegatedLogStore.js +1 -1
- package/dist/webvh/didWebvh.d.ts +20 -10
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +17 -17
- package/dist/webvh/didWebvh.js.map +1 -1
- package/dist/webvh/index.d.ts +9 -23
- package/dist/webvh/index.d.ts.map +1 -1
- package/dist/webvh/index.js +9 -22
- package/dist/webvh/index.js.map +1 -1
- package/dist/webvh/revokeClient.d.ts +77 -5
- package/dist/webvh/revokeClient.d.ts.map +1 -1
- package/dist/webvh/revokeClient.js +154 -61
- package/dist/webvh/revokeClient.js.map +1 -1
- package/dist/webvh/standingZcap.d.ts +11 -1
- package/dist/webvh/standingZcap.d.ts.map +1 -1
- package/dist/webvh/standingZcap.js +13 -14
- package/dist/webvh/standingZcap.js.map +1 -1
- package/dist/webvh/wasIdStore.d.ts +13 -7
- package/dist/webvh/wasIdStore.d.ts.map +1 -1
- package/dist/webvh/wasIdStore.js +8 -4
- package/dist/webvh/wasIdStore.js.map +1 -1
- package/dist/webvh/zcap.d.ts +0 -24
- package/dist/webvh/zcap.d.ts.map +1 -1
- package/dist/webvh/zcap.js +0 -42
- package/dist/webvh/zcap.js.map +1 -1
- package/package.json +40 -34
- package/dist/unlock/ladder.d.ts.map +0 -1
- package/dist/unlock/ladder.js +0 -254
- package/dist/unlock/ladder.js.map +0 -1
- package/dist/unlock/selfEnroll.d.ts.map +0 -1
- package/dist/unlock/selfEnroll.js.map +0 -1
- package/dist/webvh/companion.d.ts.map +0 -1
- package/dist/webvh/companion.js.map +0 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The LAST durable client's forget: the two-entry transition ceremony that
|
|
6
|
+
* takes an account from one enrolled durable client to the client-less,
|
|
7
|
+
* ladder-anchored state -- the same state a credential-anchored signup and a
|
|
8
|
+
* transient recovery produce. Decision 0004's 2026-08-19 amendment fixes the
|
|
9
|
+
* entry order, and it is forced twice over: the server's revocation endpoint
|
|
10
|
+
* verifies a to-be-revoked capability's chain against the CURRENTLY resolved
|
|
11
|
+
* document (so a ladder-signed chain revokes only while the ladder VM is
|
|
12
|
+
* published), and the ladder VM carries no `capabilityInvocation` (so once
|
|
13
|
+
* the client's verification method is gone, nothing can sign the revocation
|
|
14
|
+
* POST at all). So:
|
|
15
|
+
*
|
|
16
|
+
* 1. **The install entry** ({@link installLadderVmWebvh}): the ladder VM
|
|
17
|
+
* joins the document while the client's whole footprint stays -- the
|
|
18
|
+
* both-present transitional state. This is the ceremony's
|
|
19
|
+
* posture-changing document version under the ceremony-tail license.
|
|
20
|
+
* 2. **The roster rotation**, ladder-signed, anchored at the install entry,
|
|
21
|
+
* HTTP-invoked under the still-standing client: the user key rotates off
|
|
22
|
+
* this client's wrap in ONE append (the license's one-shot shape), read
|
|
23
|
+
* back through the credential's standing wrap. Because the append's
|
|
24
|
+
* signer is the ladder VM -- a key the post-removal document still lists
|
|
25
|
+
* -- the roster log needs no seal completer afterwards, which matters on
|
|
26
|
+
* an account where no enrolled client's login sweep will ever run again.
|
|
27
|
+
* 3. **The collection fan-out**, still under this client's invocation
|
|
28
|
+
* authority: every encrypted collection re-epochs onto the fresh key.
|
|
29
|
+
* 4. **The generation-delegation replacement and revocations**: a fresh
|
|
30
|
+
* ladder-signed generation delegation replaces the embedded one
|
|
31
|
+
* unconditionally (the forced renewal), and then EVERY still-unexpired
|
|
32
|
+
* delegation the annex log's history ever embedded that this
|
|
33
|
+
* credential's ladder VM signed is revoked at the server (a renewal
|
|
34
|
+
* inside the 30-day window can leave two) -- closing the resurrection
|
|
35
|
+
* window a reinstalled derived-key VM would otherwise reopen. The
|
|
36
|
+
* replacement is what keeps the account transient-login-reachable after
|
|
37
|
+
* the transition; replace-before-revoke is what keeps a torn run from
|
|
38
|
+
* stranding the generation delegation-less.
|
|
39
|
+
* 5. **The other unlock methods' record re-mint** (`unlockMethods`): every
|
|
40
|
+
* other standing credential's and recovery code's bridge (and
|
|
41
|
+
* `delegatedClients` sibling, where the record carries one) is re-signed
|
|
42
|
+
* by the ladder VM and its record re-sealed through the entry's
|
|
43
|
+
* management zcap -- the revocation cascade's re-mint pass
|
|
44
|
+
* (`remintRecoveryDelegations`), run with the ladder VM as the delegating
|
|
45
|
+
* and record-signing key and the forgotten client named as retiring, so
|
|
46
|
+
* every delegation it signed counts as rotted ahead of the removal entry.
|
|
47
|
+
* Delegations the removed client had signed rot at that entry, and on a
|
|
48
|
+
* client-less account no durable login's refresh block will ever run
|
|
49
|
+
* again to heal them, so this is the one pass that reaches them. The
|
|
50
|
+
* HTTP side still invokes under the still-standing client (the
|
|
51
|
+
* management zcaps are granted to the account DID, which only an enrolled
|
|
52
|
+
* client can invoke) -- which is why the stage must run before the
|
|
53
|
+
* removal entry. Best-effort per entry, every entry's fate reported.
|
|
54
|
+
* 6. **The record re-bind seam** (`onBeforeRemoval`): the caller re-signs
|
|
55
|
+
* the LOGIN credential's bridge and `delegatedClients` sibling with the
|
|
56
|
+
* ladder VM and re-seals its unlock record with the credential in hand
|
|
57
|
+
* (a full re-wrap, proof verified rather than settled) -- the one record
|
|
58
|
+
* stage 5 need not reach.
|
|
59
|
+
* 7. **The removal entry** ({@link forgetLastWebvhClient}): the client's
|
|
60
|
+
* whole document footprint out while the installed ladder VM keeps the
|
|
61
|
+
* account anchored. The app's local wipe runs after this ceremony
|
|
62
|
+
* returns.
|
|
63
|
+
*
|
|
64
|
+
* Torn-state map: every stage detects completion from durable state, so a
|
|
65
|
+
* run torn anywhere before the removal entry reads as "not forgotten" and a
|
|
66
|
+
* re-run converges -- the install entry is idempotent, an already-rotated
|
|
67
|
+
* roster skips the append (no second ladder-signed append is ever
|
|
68
|
+
* attempted), the fan-out is staleness-driven, a re-POSTed revocation's 400
|
|
69
|
+
* already-revoked answer reads as success (decision 0006's resume contract),
|
|
70
|
+
* and the forced replacement re-mints (the prior run's fresh delegation is
|
|
71
|
+
* then revoked as history, so a re-run churns one delegation and strands
|
|
72
|
+
* nothing), and the record re-mint re-checks staleness per entry (a record
|
|
73
|
+
* already ladder-signed reads as current). Torn after the removal entry is
|
|
74
|
+
* the finish-the-wipe state the app's next login maps.
|
|
75
|
+
*
|
|
76
|
+
* The honest limitation is the cascade's, as everywhere: ciphertext this
|
|
77
|
+
* browser already fetched stays forensically recoverable from its storage,
|
|
78
|
+
* and old epochs stay open to keys it already held.
|
|
79
|
+
*/
|
|
80
|
+
import type { DIDLog } from '@interop/did-method-webvh';
|
|
81
|
+
import type { IKeyAgreementKey, IZcap } from '@interop/data-integrity-core';
|
|
82
|
+
import type { ZcapClient } from '@interop/ezcap';
|
|
83
|
+
import type { CollectionEncryption, IDelegatedZcap } from '@interop/was-client';
|
|
84
|
+
import type { EncryptionDescriptorStore } from '@interop/was-client/edv';
|
|
85
|
+
import { type RevokedClientKeys } from '../webvh/revokeClient.js';
|
|
86
|
+
import type { ResourceLogPinStore } from '../resourceLog/index.js';
|
|
87
|
+
import { type CascadeCollections, type UserKey, type UserKeyCascadeResult } from '../keys/index.js';
|
|
88
|
+
import type { UnlockLogStore } from '../unlock/standingWebvh.js';
|
|
89
|
+
import type { AccountPointer } from '../keyring/record.js';
|
|
90
|
+
import { type RecordRemintOutcome, type RecoveryDelegationEntry } from '../recovery/recoveryDelegation.js';
|
|
91
|
+
import { type ClientAnnexWriteStore } from './log.js';
|
|
92
|
+
/**
|
|
93
|
+
* What the ceremony's generation stage did: the revoked delegation ids, and
|
|
94
|
+
* whether the forced replacement landed. A `skipped` reason names the stage
|
|
95
|
+
* that could not run -- `no-pointer` (the account points at no generation:
|
|
96
|
+
* nothing to revoke or replace), `log-unreadable` (the pointed generation's
|
|
97
|
+
* `did.jsonl` is gone; the delegation bytes are unrecoverable, decision
|
|
98
|
+
* 0006's honest limit), `rung-uncommitted` (this credential cannot write the
|
|
99
|
+
* generation's log; the account lands delegation-less until a
|
|
100
|
+
* fresh-generation heal), `already-removed` (the whole ceremony completed on
|
|
101
|
+
* an earlier run; nothing here can still invoke) -- and a skip never fails
|
|
102
|
+
* the ceremony.
|
|
103
|
+
*/
|
|
104
|
+
export interface GenerationDelegationRetirement {
|
|
105
|
+
revoked: string[];
|
|
106
|
+
replaced: boolean;
|
|
107
|
+
skipped?: 'no-pointer' | 'log-unreadable' | 'rung-uncommitted' | 'already-removed';
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The other unlock methods' reach for the record re-mint stage: the registry
|
|
111
|
+
* entries to walk (the OTHER methods' -- the login credential's own record is
|
|
112
|
+
* the `onBeforeRemoval` seam's, re-wrapped with the credential in hand; an
|
|
113
|
+
* entry for it here is harmless but redundant), the unlock Spaces' storage
|
|
114
|
+
* server, the management-zcap client factory (invoking as the still-standing
|
|
115
|
+
* client), and the registry record-back seam. The shape is the revocation
|
|
116
|
+
* cascade's re-mint seams verbatim, so an app binds both from one place.
|
|
117
|
+
*/
|
|
118
|
+
export interface UnlockMethodsRemintReach<Entry extends RecoveryDelegationEntry = RecoveryDelegationEntry> {
|
|
119
|
+
entries: Entry[];
|
|
120
|
+
pointer: AccountPointer;
|
|
121
|
+
storageServerUrl: string;
|
|
122
|
+
managementZcapClient: (options: {
|
|
123
|
+
capability: IZcap;
|
|
124
|
+
}) => ZcapClient;
|
|
125
|
+
recordEntry: (options: {
|
|
126
|
+
entry: Entry;
|
|
127
|
+
}) => Promise<void>;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* What a completed last-client forget reports: whether the install entry ran
|
|
131
|
+
* on this call (`false` on a resumed run), whether the roster's wrap for the
|
|
132
|
+
* forgotten client was retired on this run, the per-collection fan-out
|
|
133
|
+
* result, the generation stage's report, the other unlock methods' record
|
|
134
|
+
* re-mint report (present when the caller supplied the reach: the counts and
|
|
135
|
+
* every entry's fate, so a record the pass could not reach is named rather
|
|
136
|
+
* than silently left with a rotted bridge), the document as the removal entry
|
|
137
|
+
* left it, and -- when the account has a roster -- the rotated key with the
|
|
138
|
+
* roster descriptor it was read from.
|
|
139
|
+
*/
|
|
140
|
+
export interface LastDurableClientForgetResult {
|
|
141
|
+
installed: boolean;
|
|
142
|
+
rotated: boolean;
|
|
143
|
+
collections: UserKeyCascadeResult;
|
|
144
|
+
generation: GenerationDelegationRetirement;
|
|
145
|
+
unlockMethods?: {
|
|
146
|
+
reminted: number;
|
|
147
|
+
skipped: number;
|
|
148
|
+
outcomes: RecordRemintOutcome[];
|
|
149
|
+
};
|
|
150
|
+
did: string;
|
|
151
|
+
document: object;
|
|
152
|
+
userKey?: UserKey;
|
|
153
|
+
rosterDescriptor?: CollectionEncryption;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Forgets the account's LAST enrolled durable client -- this browser's own
|
|
157
|
+
* -- transitioning the account to the client-less, ladder-anchored state.
|
|
158
|
+
* See the module doc for the stage order and the torn-state map. The caller
|
|
159
|
+
* runs the local wipe only after this resolves. An account with another
|
|
160
|
+
* enrolled durable client refuses: that forget is the ordinary ceremony
|
|
161
|
+
* (`forgetDurableClient`), reached first, whose `LastDurableClientForgetError`
|
|
162
|
+
* is what routes callers here.
|
|
163
|
+
*
|
|
164
|
+
* @param options {object}
|
|
165
|
+
* @param options.logStore {UnlockLogStore} the credential's delegated
|
|
166
|
+
* `did.jsonl` bridge store; also serves the ceremony's public reads. The
|
|
167
|
+
* caller is expected to have verified the account log under its own
|
|
168
|
+
* chain-head pins in the same session (the ceremony re-reads through the
|
|
169
|
+
* seam and checks `expectedDid`, but carries no account-log pin store
|
|
170
|
+
* itself)
|
|
171
|
+
* @param options.ladderSeed {Uint8Array} the login credential's ladder seed
|
|
172
|
+
* @param options.forgottenClient {RevokedClientKeys} this client's public
|
|
173
|
+
* halves; an `updateKeyMultibase` the log does not authorize (stale, or the
|
|
174
|
+
* staged key) is re-derived from the log
|
|
175
|
+
* @param options.forgottenKeyAgreementKeyMultibase {string} this client's
|
|
176
|
+
* identity key-agreement key (the X25519 twin), naming its roster wrap
|
|
177
|
+
* @param [options.knownLatentHashes] {string[]} standing latent commitments
|
|
178
|
+
* the caller vouches for (the recovery registry's update-key hashes),
|
|
179
|
+
* excluded from the staged-hash attribution
|
|
180
|
+
* @param options.expectedDid {string} the account DID from the caller's
|
|
181
|
+
* stored account pointer
|
|
182
|
+
* @param options.rosterStoreFor {Function} `({ did, log }) => store` --
|
|
183
|
+
* builds the `key-map/user-key.jsonl` roster store whose appends are
|
|
184
|
+
* SIGNED BY THE LADDER VM and whose controller view resolves from the
|
|
185
|
+
* supplied post-install log (the posture-changing anchor the ceremony-tail
|
|
186
|
+
* license admits), while its HTTP requests invoke under the still-standing
|
|
187
|
+
* client
|
|
188
|
+
* @param options.credentialKeyAgreementKey {IKeyAgreementKey} the standing
|
|
189
|
+
* credential's key-agreement key -- the recipient whose wrap survives the
|
|
190
|
+
* rotation, reading the fresh key back and unwrapping the generations for
|
|
191
|
+
* the fan-out
|
|
192
|
+
* @param [options.userKey] {UserKey} this client's cached user key
|
|
193
|
+
* @param [options.pinnedEpochId] {string} the locally pinned latest-seen
|
|
194
|
+
* roster epoch
|
|
195
|
+
* @param [options.onUserKeyAdopted] {Function} persists a rotated key:
|
|
196
|
+
* called with `{ userKey, latestEpochId, descriptor }` after the roster
|
|
197
|
+
* read and BEFORE the fan-out
|
|
198
|
+
* @param options.collections {CascadeCollections} the fan-out's work
|
|
199
|
+
* @param options.annex {object} the generation stage's reach:
|
|
200
|
+
* @param options.annex.storeFor {Function}
|
|
201
|
+
* `({ spaceId, generationId }) => ClientAnnexWriteStore` -- the pointed
|
|
202
|
+
* generation's log store, reading and writing under the still-standing
|
|
203
|
+
* client's authority
|
|
204
|
+
* @param options.annex.revoke {Function} `(delegation) => Promise<void>`
|
|
205
|
+
* -- POSTs a revocation (was-client's `WasClient#revoke`, bound by the
|
|
206
|
+
* caller; the invocation signs as the still-standing client)
|
|
207
|
+
* @param options.annex.wasServerUrl {string} the ACCOUNT Space's storage
|
|
208
|
+
* server (the fresh generation delegation's target host)
|
|
209
|
+
* @param options.annex.accountSpaceId {string} the ACCOUNT Space's id (the
|
|
210
|
+
* fresh delegation's target subtree)
|
|
211
|
+
* @param [options.annex.pinStore] {ResourceLogPinStore} chain-head pins
|
|
212
|
+
* for the pointed generation's read
|
|
213
|
+
* @param [options.unlockMethods] {UnlockMethodsRemintReach} the other
|
|
214
|
+
* unlock methods' record re-mint reach (stage 5): the registry entries
|
|
215
|
+
* whose bridge (and sibling) the ladder VM re-signs and whose records it
|
|
216
|
+
* re-seals through their management zcaps, invoked as the still-standing
|
|
217
|
+
* client. Omitted, the stage is skipped and the result carries no
|
|
218
|
+
* `unlockMethods` report -- the residue decision 0004's amendment stated
|
|
219
|
+
* @param [options.onBeforeRemoval] {Function}
|
|
220
|
+
* `({ did, doc, log }) => Promise<void>` -- the record re-bind seam: runs
|
|
221
|
+
* after the record re-mint stage, immediately before the removal entry,
|
|
222
|
+
* with the post-install published state. The caller re-signs the login
|
|
223
|
+
* credential's bridge and `delegatedClients` sibling with the ladder VM
|
|
224
|
+
* and re-seals its unlock record here. Must be idempotent (a resumed run
|
|
225
|
+
* invokes it again)
|
|
226
|
+
* @param [options.now] {number} epoch milliseconds, for tests
|
|
227
|
+
* @returns {Promise<LastDurableClientForgetResult>}
|
|
228
|
+
*/
|
|
229
|
+
export declare function forgetLastDurableClient({ logStore, ladderSeed, forgottenClient, forgottenKeyAgreementKeyMultibase, knownLatentHashes, expectedDid, rosterStoreFor, credentialKeyAgreementKey, userKey, pinnedEpochId, onUserKeyAdopted, collections, annex, unlockMethods, onBeforeRemoval, now }: {
|
|
230
|
+
logStore: UnlockLogStore;
|
|
231
|
+
ladderSeed: Uint8Array;
|
|
232
|
+
forgottenClient: RevokedClientKeys;
|
|
233
|
+
forgottenKeyAgreementKeyMultibase: string;
|
|
234
|
+
knownLatentHashes?: string[];
|
|
235
|
+
expectedDid: string;
|
|
236
|
+
rosterStoreFor: (options: {
|
|
237
|
+
did: string;
|
|
238
|
+
log: DIDLog;
|
|
239
|
+
}) => EncryptionDescriptorStore;
|
|
240
|
+
credentialKeyAgreementKey: IKeyAgreementKey;
|
|
241
|
+
userKey?: UserKey;
|
|
242
|
+
pinnedEpochId?: string | null;
|
|
243
|
+
onUserKeyAdopted?: (adopted: {
|
|
244
|
+
userKey: UserKey;
|
|
245
|
+
latestEpochId: string;
|
|
246
|
+
descriptor: CollectionEncryption;
|
|
247
|
+
}) => Promise<void>;
|
|
248
|
+
collections: CascadeCollections;
|
|
249
|
+
annex: {
|
|
250
|
+
storeFor: (options: {
|
|
251
|
+
spaceId: string;
|
|
252
|
+
generationId: string;
|
|
253
|
+
}) => ClientAnnexWriteStore;
|
|
254
|
+
revoke: (delegation: IDelegatedZcap) => Promise<void>;
|
|
255
|
+
wasServerUrl: string;
|
|
256
|
+
accountSpaceId: string;
|
|
257
|
+
pinStore?: ResourceLogPinStore;
|
|
258
|
+
};
|
|
259
|
+
unlockMethods?: UnlockMethodsRemintReach;
|
|
260
|
+
onBeforeRemoval?: (published: {
|
|
261
|
+
did: string;
|
|
262
|
+
doc: object;
|
|
263
|
+
log: DIDLog;
|
|
264
|
+
}) => Promise<void>;
|
|
265
|
+
now?: number;
|
|
266
|
+
}): Promise<LastDurableClientForgetResult>;
|
|
267
|
+
//# sourceMappingURL=forgetLast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forgetLast.d.ts","sourceRoot":"","sources":["../../src/clientAnnex/forgetLast.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { readPublishedLog, relationIds } from '../webvh/didWebvh.js';
|
|
2
|
+
import { clientRemovalTarget } from '../webvh/revokeClient.js';
|
|
3
|
+
import { delegationProofKeyId } from '../webvh/standingZcap.js';
|
|
4
|
+
import { vmFragmentOf } from '../resourceLog/index.js';
|
|
5
|
+
import { cascadeCollectionsToUserKey, readUserKeyRoster, rosterRecipientKid, rotateUserKeyRoster } from '../keys/index.js';
|
|
6
|
+
import { readLogOrThrow } from '../unlock/standingWebvh.js';
|
|
7
|
+
import { recordSignerFromAgent } from '../keyring/record.js';
|
|
8
|
+
import { remintRecoveryDelegations } from '../recovery/recoveryDelegation.js';
|
|
9
|
+
import { ladderVmKeyMultibase } from './ladder.js';
|
|
10
|
+
import { ladderVmAgent, ladderVmZcapClient } from './zcap.js';
|
|
11
|
+
import { forgetLastWebvhClient, installLadderVmWebvh } from './ladderAnchored.js';
|
|
12
|
+
import { clientAnnexDidParts, clientAnnexLogPinId, delegatedClientsDelegationMinter, delegatedClientsPointer, ensureGenerationDelegationCurrent, generationDelegationHistory, mintGenerationDelegation, revokeTreatingAlreadyRevokedAsSuccess } from './log.js';
|
|
13
|
+
/**
|
|
14
|
+
* Forgets the account's LAST enrolled durable client -- this browser's own
|
|
15
|
+
* -- transitioning the account to the client-less, ladder-anchored state.
|
|
16
|
+
* See the module doc for the stage order and the torn-state map. The caller
|
|
17
|
+
* runs the local wipe only after this resolves. An account with another
|
|
18
|
+
* enrolled durable client refuses: that forget is the ordinary ceremony
|
|
19
|
+
* (`forgetDurableClient`), reached first, whose `LastDurableClientForgetError`
|
|
20
|
+
* is what routes callers here.
|
|
21
|
+
*
|
|
22
|
+
* @param options {object}
|
|
23
|
+
* @param options.logStore {UnlockLogStore} the credential's delegated
|
|
24
|
+
* `did.jsonl` bridge store; also serves the ceremony's public reads. The
|
|
25
|
+
* caller is expected to have verified the account log under its own
|
|
26
|
+
* chain-head pins in the same session (the ceremony re-reads through the
|
|
27
|
+
* seam and checks `expectedDid`, but carries no account-log pin store
|
|
28
|
+
* itself)
|
|
29
|
+
* @param options.ladderSeed {Uint8Array} the login credential's ladder seed
|
|
30
|
+
* @param options.forgottenClient {RevokedClientKeys} this client's public
|
|
31
|
+
* halves; an `updateKeyMultibase` the log does not authorize (stale, or the
|
|
32
|
+
* staged key) is re-derived from the log
|
|
33
|
+
* @param options.forgottenKeyAgreementKeyMultibase {string} this client's
|
|
34
|
+
* identity key-agreement key (the X25519 twin), naming its roster wrap
|
|
35
|
+
* @param [options.knownLatentHashes] {string[]} standing latent commitments
|
|
36
|
+
* the caller vouches for (the recovery registry's update-key hashes),
|
|
37
|
+
* excluded from the staged-hash attribution
|
|
38
|
+
* @param options.expectedDid {string} the account DID from the caller's
|
|
39
|
+
* stored account pointer
|
|
40
|
+
* @param options.rosterStoreFor {Function} `({ did, log }) => store` --
|
|
41
|
+
* builds the `key-map/user-key.jsonl` roster store whose appends are
|
|
42
|
+
* SIGNED BY THE LADDER VM and whose controller view resolves from the
|
|
43
|
+
* supplied post-install log (the posture-changing anchor the ceremony-tail
|
|
44
|
+
* license admits), while its HTTP requests invoke under the still-standing
|
|
45
|
+
* client
|
|
46
|
+
* @param options.credentialKeyAgreementKey {IKeyAgreementKey} the standing
|
|
47
|
+
* credential's key-agreement key -- the recipient whose wrap survives the
|
|
48
|
+
* rotation, reading the fresh key back and unwrapping the generations for
|
|
49
|
+
* the fan-out
|
|
50
|
+
* @param [options.userKey] {UserKey} this client's cached user key
|
|
51
|
+
* @param [options.pinnedEpochId] {string} the locally pinned latest-seen
|
|
52
|
+
* roster epoch
|
|
53
|
+
* @param [options.onUserKeyAdopted] {Function} persists a rotated key:
|
|
54
|
+
* called with `{ userKey, latestEpochId, descriptor }` after the roster
|
|
55
|
+
* read and BEFORE the fan-out
|
|
56
|
+
* @param options.collections {CascadeCollections} the fan-out's work
|
|
57
|
+
* @param options.annex {object} the generation stage's reach:
|
|
58
|
+
* @param options.annex.storeFor {Function}
|
|
59
|
+
* `({ spaceId, generationId }) => ClientAnnexWriteStore` -- the pointed
|
|
60
|
+
* generation's log store, reading and writing under the still-standing
|
|
61
|
+
* client's authority
|
|
62
|
+
* @param options.annex.revoke {Function} `(delegation) => Promise<void>`
|
|
63
|
+
* -- POSTs a revocation (was-client's `WasClient#revoke`, bound by the
|
|
64
|
+
* caller; the invocation signs as the still-standing client)
|
|
65
|
+
* @param options.annex.wasServerUrl {string} the ACCOUNT Space's storage
|
|
66
|
+
* server (the fresh generation delegation's target host)
|
|
67
|
+
* @param options.annex.accountSpaceId {string} the ACCOUNT Space's id (the
|
|
68
|
+
* fresh delegation's target subtree)
|
|
69
|
+
* @param [options.annex.pinStore] {ResourceLogPinStore} chain-head pins
|
|
70
|
+
* for the pointed generation's read
|
|
71
|
+
* @param [options.unlockMethods] {UnlockMethodsRemintReach} the other
|
|
72
|
+
* unlock methods' record re-mint reach (stage 5): the registry entries
|
|
73
|
+
* whose bridge (and sibling) the ladder VM re-signs and whose records it
|
|
74
|
+
* re-seals through their management zcaps, invoked as the still-standing
|
|
75
|
+
* client. Omitted, the stage is skipped and the result carries no
|
|
76
|
+
* `unlockMethods` report -- the residue decision 0004's amendment stated
|
|
77
|
+
* @param [options.onBeforeRemoval] {Function}
|
|
78
|
+
* `({ did, doc, log }) => Promise<void>` -- the record re-bind seam: runs
|
|
79
|
+
* after the record re-mint stage, immediately before the removal entry,
|
|
80
|
+
* with the post-install published state. The caller re-signs the login
|
|
81
|
+
* credential's bridge and `delegatedClients` sibling with the ladder VM
|
|
82
|
+
* and re-seals its unlock record here. Must be idempotent (a resumed run
|
|
83
|
+
* invokes it again)
|
|
84
|
+
* @param [options.now] {number} epoch milliseconds, for tests
|
|
85
|
+
* @returns {Promise<LastDurableClientForgetResult>}
|
|
86
|
+
*/
|
|
87
|
+
export async function forgetLastDurableClient({ logStore, ladderSeed, forgottenClient, forgottenKeyAgreementKeyMultibase, knownLatentHashes, expectedDid, rosterStoreFor, credentialKeyAgreementKey, userKey, pinnedEpochId, onUserKeyAdopted, collections, annex, unlockMethods, onBeforeRemoval, now = Date.now() }) {
|
|
88
|
+
// The pre-install read and the two guards: a client with no remaining
|
|
89
|
+
// presence means the removal entry already landed (the finish-the-wipe
|
|
90
|
+
// state the app's next login maps -- nothing here can still invoke), and
|
|
91
|
+
// an account with another enrolled durable client belongs to the ordinary
|
|
92
|
+
// forget ceremony.
|
|
93
|
+
const before = await readLogOrThrow({ store: logStore, expectedDid });
|
|
94
|
+
const preTarget = await clientRemovalTarget({
|
|
95
|
+
published: before,
|
|
96
|
+
client: forgottenClient
|
|
97
|
+
});
|
|
98
|
+
if (!preTarget.present) {
|
|
99
|
+
return {
|
|
100
|
+
installed: false,
|
|
101
|
+
rotated: false,
|
|
102
|
+
collections: { outcomes: {}, failed: [] },
|
|
103
|
+
generation: { revoked: [], replaced: false, skipped: 'already-removed' },
|
|
104
|
+
did: before.did,
|
|
105
|
+
document: before.doc
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const signingVmId = `${before.did}#${forgottenClient.signingKeyMultibase}`;
|
|
109
|
+
const invocationIds = relationIds(before.doc.capabilityInvocation);
|
|
110
|
+
if (invocationIds.some(id => id !== signingVmId)) {
|
|
111
|
+
throw new Error('did:webvh: another enrolled durable client remains; the last-client ' +
|
|
112
|
+
'transition ceremony does not apply -- run the ordinary forget.');
|
|
113
|
+
}
|
|
114
|
+
// Stage 1: the install entry -- the ladder VM in, the client untouched.
|
|
115
|
+
const install = await installLadderVmWebvh({
|
|
116
|
+
store: logStore,
|
|
117
|
+
ladderSeed,
|
|
118
|
+
expectedDid
|
|
119
|
+
});
|
|
120
|
+
// Stage 2: the roster rotation off this client's wrap, ladder-signed and
|
|
121
|
+
// anchored at the install entry, then stage 3, the collection fan-out --
|
|
122
|
+
// both HTTP-invoked under this client's still-standing authority. An
|
|
123
|
+
// already-rotated roster skips the append entirely, so the one-shot
|
|
124
|
+
// license is never asked for a second append at the same anchor.
|
|
125
|
+
let rotated = false;
|
|
126
|
+
let read;
|
|
127
|
+
let cascade = { outcomes: {}, failed: [] };
|
|
128
|
+
const rosterStore = rosterStoreFor({ did: install.did, log: install.log });
|
|
129
|
+
const current = await rosterStore.read();
|
|
130
|
+
if (current !== null) {
|
|
131
|
+
const forgottenKid = rosterRecipientKid({
|
|
132
|
+
signingKeyMultibase: forgottenClient.signingKeyMultibase,
|
|
133
|
+
keyAgreementKeyMultibase: forgottenKeyAgreementKeyMultibase
|
|
134
|
+
});
|
|
135
|
+
let descriptor = current.descriptor;
|
|
136
|
+
const currentEpoch = (descriptor.epochs ?? []).find(epoch => epoch.id === descriptor.currentEpoch);
|
|
137
|
+
const wrapped = currentEpoch?.recipients.some(entry => entry.header.kid === forgottenKid);
|
|
138
|
+
if (wrapped) {
|
|
139
|
+
descriptor = await rotateUserKeyRoster({
|
|
140
|
+
store: rosterStore,
|
|
141
|
+
document: install.doc,
|
|
142
|
+
retireRecipientId: forgottenKid
|
|
143
|
+
});
|
|
144
|
+
rotated = true;
|
|
145
|
+
}
|
|
146
|
+
// The fresh key comes back through the credential's standing wrap -- this
|
|
147
|
+
// client's own is gone from the current epoch -- with the continuity and
|
|
148
|
+
// possession checks still running on the threaded descriptor.
|
|
149
|
+
const adopted = await readUserKeyRoster({
|
|
150
|
+
store: rosterStore,
|
|
151
|
+
descriptor,
|
|
152
|
+
...(userKey ? { userKey } : {}),
|
|
153
|
+
clientKeyAgreementKey: credentialKeyAgreementKey,
|
|
154
|
+
pinnedEpochId
|
|
155
|
+
});
|
|
156
|
+
if (adopted.rotated) {
|
|
157
|
+
await onUserKeyAdopted?.({
|
|
158
|
+
userKey: adopted.userKey,
|
|
159
|
+
latestEpochId: adopted.latestEpochId,
|
|
160
|
+
descriptor: adopted.descriptor
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
read = { userKey: adopted.userKey, descriptor: adopted.descriptor };
|
|
164
|
+
cascade = await cascadeCollectionsToUserKey({
|
|
165
|
+
collectionIds: typeof collections.collectionIds === 'function'
|
|
166
|
+
? await collections.collectionIds()
|
|
167
|
+
: collections.collectionIds,
|
|
168
|
+
storeFor: collections.storeFor,
|
|
169
|
+
...(collections.isEncrypted
|
|
170
|
+
? { isEncrypted: collections.isEncrypted }
|
|
171
|
+
: {}),
|
|
172
|
+
rosterDescriptor: adopted.descriptor,
|
|
173
|
+
clientKeyAgreementKey: credentialKeyAgreementKey,
|
|
174
|
+
userKey: adopted.userKey
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// Stage 4: the generation-delegation replacement and revocations.
|
|
178
|
+
const generation = await retireLadderGenerationDelegations({
|
|
179
|
+
doc: install.doc,
|
|
180
|
+
accountDid: install.did,
|
|
181
|
+
ladderSeed,
|
|
182
|
+
annex,
|
|
183
|
+
now
|
|
184
|
+
});
|
|
185
|
+
// Stage 5: the other unlock methods' record re-mint, ladder-signed, with
|
|
186
|
+
// the forgotten client named as retiring -- the post-install document
|
|
187
|
+
// still lists it, so without that axis every bridge it signed would read
|
|
188
|
+
// as standing and be left to rot at the removal entry.
|
|
189
|
+
let remint;
|
|
190
|
+
if (unlockMethods !== undefined) {
|
|
191
|
+
remint = await remintUnlockMethodRecordsAsLadder({
|
|
192
|
+
doc: install.doc,
|
|
193
|
+
accountDid: install.did,
|
|
194
|
+
ladderSeed,
|
|
195
|
+
retiringSigningKeyMultibase: forgottenClient.signingKeyMultibase,
|
|
196
|
+
reach: unlockMethods,
|
|
197
|
+
now
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// Stage 6: the record re-bind seam, while the removal has not landed (a
|
|
201
|
+
// ladder-VM-signed bridge verifies from the install entry on, and the old
|
|
202
|
+
// client-signed one keeps verifying until the removal -- so a tear on
|
|
203
|
+
// either side of this callback leaves a working login).
|
|
204
|
+
await onBeforeRemoval?.({
|
|
205
|
+
did: install.did,
|
|
206
|
+
doc: install.doc,
|
|
207
|
+
log: install.log
|
|
208
|
+
});
|
|
209
|
+
// Stage 7: the removal entry -- the client's whole footprint out, the
|
|
210
|
+
// installed ladder VM keeping the account anchored.
|
|
211
|
+
const removed = await forgetLastWebvhClient({
|
|
212
|
+
store: logStore,
|
|
213
|
+
ladderSeed,
|
|
214
|
+
forgottenClient,
|
|
215
|
+
...(knownLatentHashes ? { knownLatentHashes } : {}),
|
|
216
|
+
expectedDid
|
|
217
|
+
});
|
|
218
|
+
return {
|
|
219
|
+
installed: install.installed,
|
|
220
|
+
rotated,
|
|
221
|
+
collections: cascade,
|
|
222
|
+
generation,
|
|
223
|
+
...(remint ? { unlockMethods: remint } : {}),
|
|
224
|
+
did: removed.did,
|
|
225
|
+
document: removed.doc,
|
|
226
|
+
...(read
|
|
227
|
+
? { userKey: read.userKey, rosterDescriptor: read.descriptor }
|
|
228
|
+
: {})
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* The generation stage: reads the pointed generation's log, force-replaces
|
|
233
|
+
* the embedded delegation with a fresh ladder-signed one (so the account
|
|
234
|
+
* stays transient-login-reachable), then revokes every still-unexpired
|
|
235
|
+
* delegation the log's history embedded that this credential's ladder VM
|
|
236
|
+
* signed. Replace-before-revoke is the tear-safety order: the fresh
|
|
237
|
+
* delegation is never in the pre-replacement history, so the revocation loop
|
|
238
|
+
* cannot touch it, and a run torn between the two leaves the generation with
|
|
239
|
+
* a live delegation either way.
|
|
240
|
+
*
|
|
241
|
+
* @param options {object}
|
|
242
|
+
* @param options.doc {DIDDoc} the post-install account document
|
|
243
|
+
* @param options.accountDid {string}
|
|
244
|
+
* @param options.ladderSeed {Uint8Array}
|
|
245
|
+
* @param options.annex {object} see {@link forgetLastDurableClient}
|
|
246
|
+
* @param options.now {number}
|
|
247
|
+
* @returns {Promise<GenerationDelegationRetirement>}
|
|
248
|
+
*/
|
|
249
|
+
async function retireLadderGenerationDelegations({ doc, accountDid, ladderSeed, annex, now }) {
|
|
250
|
+
const pointedDid = delegatedClientsPointer({ doc });
|
|
251
|
+
if (pointedDid === undefined) {
|
|
252
|
+
return { revoked: [], replaced: false, skipped: 'no-pointer' };
|
|
253
|
+
}
|
|
254
|
+
const parts = clientAnnexDidParts({ did: pointedDid });
|
|
255
|
+
const store = annex.storeFor(parts);
|
|
256
|
+
const logId = clientAnnexLogPinId(parts);
|
|
257
|
+
// readPublishedLog only calls getIdResourceRaw, so the narrow seam is safe.
|
|
258
|
+
const published = await readPublishedLog({
|
|
259
|
+
idStore: store,
|
|
260
|
+
expectedDid: pointedDid,
|
|
261
|
+
...(annex.pinStore !== undefined ? { pinStore: annex.pinStore, logId } : {})
|
|
262
|
+
});
|
|
263
|
+
if (published === undefined) {
|
|
264
|
+
return { revoked: [], replaced: false, skipped: 'log-unreadable' };
|
|
265
|
+
}
|
|
266
|
+
// The doomed set, collected BEFORE the replacement so the fresh delegation
|
|
267
|
+
// can never join it: every delegation the history embedded whose proof key
|
|
268
|
+
// is this credential's ladder VM and whose expiry has not passed. An
|
|
269
|
+
// unparseable or absent expiry counts as unexpired -- fail-safe, since an
|
|
270
|
+
// unbounded delegation is the worst resurrection credential.
|
|
271
|
+
const ladderVmKey = await ladderVmKeyMultibase({ ladderSeed });
|
|
272
|
+
const doomed = generationDelegationHistory({ log: published.log }).filter(delegation => {
|
|
273
|
+
const proofKeyId = delegationProofKeyId(delegation);
|
|
274
|
+
const fragment = proofKeyId === undefined ? null : vmFragmentOf(proofKeyId);
|
|
275
|
+
if (fragment !== ladderVmKey) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
const expires = Date.parse(delegation.expires ?? '');
|
|
279
|
+
return Number.isNaN(expires) || expires > now;
|
|
280
|
+
});
|
|
281
|
+
// The forced replacement first: a ladder-signed fresh delegation under the
|
|
282
|
+
// reinstalled VM, the annex entry signed by this credential's committed
|
|
283
|
+
// annex rung. A credential the generation does not commit cannot write the
|
|
284
|
+
// entry -- the honest skip, leaving the generation delegation-less once
|
|
285
|
+
// the doomed set is revoked below.
|
|
286
|
+
let replaced = false;
|
|
287
|
+
const ladderClient = await ladderVmZcapClient({ accountDid, ladderSeed });
|
|
288
|
+
try {
|
|
289
|
+
await ensureGenerationDelegationCurrent({
|
|
290
|
+
store,
|
|
291
|
+
ladderSeed,
|
|
292
|
+
generationId: parts.generationId,
|
|
293
|
+
mintGenerationDelegation: async ({ clientAnnexDid }) => mintGenerationDelegation({
|
|
294
|
+
zcapClient: ladderClient,
|
|
295
|
+
wasServerUrl: annex.wasServerUrl,
|
|
296
|
+
spaceId: annex.accountSpaceId,
|
|
297
|
+
clientAnnexDid,
|
|
298
|
+
now
|
|
299
|
+
}),
|
|
300
|
+
expectedDid: pointedDid,
|
|
301
|
+
force: true,
|
|
302
|
+
...(annex.pinStore !== undefined
|
|
303
|
+
? { pinStore: annex.pinStore, logId }
|
|
304
|
+
: {}),
|
|
305
|
+
now
|
|
306
|
+
});
|
|
307
|
+
replaced = true;
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
if (err.name !== 'ClientAnnexRungUncommittedError') {
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// The revocations, blind and resumable (400 already-revoked as success).
|
|
315
|
+
const revoked = [];
|
|
316
|
+
for (const delegation of doomed) {
|
|
317
|
+
await revokeTreatingAlreadyRevokedAsSuccess({
|
|
318
|
+
revoke: annex.revoke,
|
|
319
|
+
delegation
|
|
320
|
+
});
|
|
321
|
+
const id = delegation.id;
|
|
322
|
+
if (typeof id === 'string') {
|
|
323
|
+
revoked.push(id);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return replaced
|
|
327
|
+
? { revoked, replaced }
|
|
328
|
+
: { revoked, replaced, skipped: 'rung-uncommitted' };
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* The record re-mint stage: the revocation cascade's re-mint pass over the
|
|
332
|
+
* other unlock methods' registry entries, with the ladder VM as both the
|
|
333
|
+
* delegating key (the fresh bridge and sibling) and the record-frame signer
|
|
334
|
+
* (`ladderVmAgent`'s did:key form, whose multibase the post-install document
|
|
335
|
+
* lists, so a reader settling the mixed-signer proof against the account
|
|
336
|
+
* document accepts it after the removal too -- `currentAccountRecordSigners`
|
|
337
|
+
* is that allowlist), and the forgotten client named as retiring. The sibling
|
|
338
|
+
* minter reads the annex pointer off the post-install document. The HTTP
|
|
339
|
+
* side rides the caller's management-zcap clients, still invocable here.
|
|
340
|
+
*
|
|
341
|
+
* @param options {object}
|
|
342
|
+
* @param options.doc {DIDDoc} the post-install account document
|
|
343
|
+
* @param options.accountDid {string}
|
|
344
|
+
* @param options.ladderSeed {Uint8Array}
|
|
345
|
+
* @param options.retiringSigningKeyMultibase {string} the forgotten
|
|
346
|
+
* client's signing key
|
|
347
|
+
* @param options.reach {UnlockMethodsRemintReach}
|
|
348
|
+
* @param options.now {number}
|
|
349
|
+
* @returns {Promise<object>} the pass's counts and per-entry outcomes
|
|
350
|
+
*/
|
|
351
|
+
async function remintUnlockMethodRecordsAsLadder({ doc, accountDid, ladderSeed, retiringSigningKeyMultibase, reach, now }) {
|
|
352
|
+
const ladderClient = await ladderVmZcapClient({ accountDid, ladderSeed });
|
|
353
|
+
const recordSigner = recordSignerFromAgent({
|
|
354
|
+
keyAgent: await ladderVmAgent({ ladderSeed })
|
|
355
|
+
});
|
|
356
|
+
return remintRecoveryDelegations({
|
|
357
|
+
doc,
|
|
358
|
+
entries: reach.entries,
|
|
359
|
+
pointer: reach.pointer,
|
|
360
|
+
storageServerUrl: reach.storageServerUrl,
|
|
361
|
+
zcapClient: ladderClient,
|
|
362
|
+
recordSigner,
|
|
363
|
+
managementZcapClient: reach.managementZcapClient,
|
|
364
|
+
recordEntry: reach.recordEntry,
|
|
365
|
+
mintDelegatedClientsDelegation: delegatedClientsDelegationMinter({
|
|
366
|
+
doc,
|
|
367
|
+
zcapClient: ladderClient,
|
|
368
|
+
wasServerUrl: reach.pointer.host
|
|
369
|
+
}),
|
|
370
|
+
retiringKeyMultibases: [retiringSigningKeyMultibase],
|
|
371
|
+
now
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
//# sourceMappingURL=forgetLast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forgetLast.js","sourceRoot":"","sources":["../../src/clientAnnex/forgetLast.ts"],"names":[],"mappings":"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"}
|