@interop/wallet-core 0.60.0 → 0.62.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/clientAnnex/forgetLast.d.ts +66 -19
- package/dist/clientAnnex/forgetLast.d.ts.map +1 -1
- package/dist/clientAnnex/forgetLast.js +120 -38
- package/dist/clientAnnex/forgetLast.js.map +1 -1
- package/dist/clientAnnex/heal.d.ts +64 -29
- package/dist/clientAnnex/heal.d.ts.map +1 -1
- package/dist/clientAnnex/heal.js +292 -54
- package/dist/clientAnnex/heal.js.map +1 -1
- package/dist/clientAnnex/index.d.ts +2 -2
- package/dist/clientAnnex/index.d.ts.map +1 -1
- package/dist/clientAnnex/index.js +2 -2
- package/dist/clientAnnex/index.js.map +1 -1
- package/dist/clientAnnex/ladder.d.ts +246 -18
- package/dist/clientAnnex/ladder.d.ts.map +1 -1
- package/dist/clientAnnex/ladder.js +742 -53
- package/dist/clientAnnex/ladder.js.map +1 -1
- package/dist/clientAnnex/ladderAnchored.d.ts +113 -6
- package/dist/clientAnnex/ladderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/ladderAnchored.js +208 -27
- package/dist/clientAnnex/ladderAnchored.js.map +1 -1
- package/dist/clientAnnex/log.d.ts +37 -1
- package/dist/clientAnnex/log.d.ts.map +1 -1
- package/dist/clientAnnex/log.js +34 -10
- package/dist/clientAnnex/log.js.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts +32 -7
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.js +124 -23
- package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -1
- package/dist/clientAnnex/zcap.js +2 -2
- package/dist/clientAnnex/zcap.js.map +1 -1
- package/dist/identity/agents.js +2 -2
- package/dist/identity/agents.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/userKeyRoster.d.ts +32 -2
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +40 -2
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/recovery/recoveryDelegation.d.ts +4 -1
- package/dist/recovery/recoveryDelegation.d.ts.map +1 -1
- package/dist/recovery/recoveryDelegation.js +9 -7
- package/dist/recovery/recoveryDelegation.js.map +1 -1
- package/dist/recovery/recoveryWebvh.d.ts +42 -2
- package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
- package/dist/recovery/recoveryWebvh.js +160 -18
- package/dist/recovery/recoveryWebvh.js.map +1 -1
- package/dist/unlock/index.d.ts +2 -2
- package/dist/unlock/index.d.ts.map +1 -1
- package/dist/unlock/index.js +1 -1
- package/dist/unlock/index.js.map +1 -1
- package/dist/unlock/retire.d.ts +62 -9
- package/dist/unlock/retire.d.ts.map +1 -1
- package/dist/unlock/retire.js +59 -5
- package/dist/unlock/retire.js.map +1 -1
- package/dist/unlock/standingWebvh.d.ts +131 -21
- package/dist/unlock/standingWebvh.d.ts.map +1 -1
- package/dist/unlock/standingWebvh.js +239 -54
- package/dist/unlock/standingWebvh.js.map +1 -1
- package/dist/webvh/didWebvh.d.ts +3 -2
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +7 -5
- package/dist/webvh/didWebvh.js.map +1 -1
- package/dist/webvh/index.d.ts +5 -4
- package/dist/webvh/index.d.ts.map +1 -1
- package/dist/webvh/index.js +4 -3
- package/dist/webvh/index.js.map +1 -1
- package/dist/webvh/keyAgreement.d.ts +25 -0
- package/dist/webvh/keyAgreement.d.ts.map +1 -1
- package/dist/webvh/keyAgreement.js +24 -0
- package/dist/webvh/keyAgreement.js.map +1 -1
- package/dist/webvh/listClients.d.ts +31 -18
- package/dist/webvh/listClients.d.ts.map +1 -1
- package/dist/webvh/listClients.js +60 -16
- package/dist/webvh/listClients.js.map +1 -1
- package/dist/webvh/revokeClient.d.ts +48 -0
- package/dist/webvh/revokeClient.d.ts.map +1 -1
- package/dist/webvh/revokeClient.js +85 -1
- package/dist/webvh/revokeClient.js.map +1 -1
- package/dist/webvh/zcap.js +3 -3
- package/dist/webvh/zcap.js.map +1 -1
- package/package.json +5 -5
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
* The client-annex generation ensure a TRANSIENT visit runs -- a session
|
|
6
6
|
* holding nothing but a standing unlock credential (its ladder seed, its
|
|
7
7
|
* `delegatedClients` sibling delegation, and the standing-client identity
|
|
8
|
-
* derived from the typed secret).
|
|
9
|
-
*
|
|
10
|
-
* `#DelegatedClients` pointer; the pointed
|
|
11
|
-
* or never minted); the embedded generation
|
|
12
|
-
* its renewal window, or signed by a key the
|
|
13
|
-
* record carries no sibling delegation, or its
|
|
14
|
-
*
|
|
8
|
+
* derived from the typed secret). Five durable states cut such a visit off
|
|
9
|
+
* from the annex, or from the account log the annex is pointed at: the
|
|
10
|
+
* account document carries no `#DelegatedClients` pointer; the pointed
|
|
11
|
+
* generation's log is gone (GC'd, or never minted); the embedded generation
|
|
12
|
+
* delegation is expired, inside its renewal window, or signed by a key the
|
|
13
|
+
* document no longer lists; the record carries no sibling delegation, or its
|
|
14
|
+
* sibling targets another Space; the record's bridge delegation is expired,
|
|
15
|
+
* inside its renewal window, or signed by a key the document no longer
|
|
16
|
+
* lists. On a ladder-anchored account -- the ladder VM a document
|
|
15
17
|
* verification method, the ladder's rungs the log's update keys -- the visit
|
|
16
|
-
* itself can mend all
|
|
18
|
+
* itself can mend all five, and this module is the orchestrator: a
|
|
17
19
|
* converging ensure that detects each state from durable state, mends it
|
|
18
20
|
* with the existing annex primitives, and reports what ran.
|
|
19
21
|
*
|
|
@@ -38,15 +40,25 @@
|
|
|
38
40
|
* ordering exactly (Space under the ladder VM's bare did:key, mint
|
|
39
41
|
* controller-tier, delegation embed while the Space still answers to the
|
|
40
42
|
* bootstrap key, controller flip, then the pointer entry).
|
|
43
|
+
* - The BRIDGE RENEWAL PRECEDES EVERY ARM: the record's bridge delegation is
|
|
44
|
+
* the credential's one write path into the account log, so a stale one is
|
|
45
|
+
* replaced before any arm runs and the caller's account-log store is built
|
|
46
|
+
* over the usable bridge (the `idStoreFor` factory). A pointer entry in
|
|
47
|
+
* either minting arm would otherwise ride a delegation the server refuses.
|
|
41
48
|
* - Pointer entries go through the caller's account-log store with
|
|
42
49
|
* `logOnly: true`: a bridge-delegated writer has no `did.json` projection
|
|
43
50
|
* rights, and the log is the source of truth.
|
|
44
51
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
52
|
+
* Both renewable record delegations -- the bridge, and the sibling (minted
|
|
53
|
+
* when the record carries none, when it targets another Space, or when it is
|
|
54
|
+
* stale) -- are handed back through the REQUIRED `onRebindRecord` seam after
|
|
55
|
+
* the generation and pointer are durable. The seam always receives BOTH
|
|
56
|
+
* usable delegations, whichever of them was freshly minted, so the caller
|
|
57
|
+
* re-seals the unlock record from one pair; a run torn before that re-seal
|
|
58
|
+
* re-derives everything from the ladder seed at the next visit. A re-seal
|
|
59
|
+
* that fails is fatal when the sibling was fresh and is reported on the
|
|
60
|
+
* outcome's `bridgeResealError` when only the bridge was, since the fresh
|
|
61
|
+
* bridge already served this visit and the next visit re-mints it.
|
|
50
62
|
*/
|
|
51
63
|
import type { IZcap } from '@interop/data-integrity-core';
|
|
52
64
|
import type { ZcapClient } from '@interop/ezcap';
|
|
@@ -59,16 +71,18 @@ import type { ICapabilityAgent } from '../webvh/zcap.js';
|
|
|
59
71
|
*
|
|
60
72
|
* `'ladder-vm-not-anchored'`: this credential's ladder VM is not a
|
|
61
73
|
* verification method of the account document, so nothing ladder-signed can
|
|
62
|
-
* verify.
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
74
|
+
* verify. A standing credential's VM stands for as long as the credential
|
|
75
|
+
* does -- enrollment leaves it alone -- so this is the backstop for a
|
|
76
|
+
* document that never carried it: a credential whose establishment was torn
|
|
77
|
+
* before its document entry, or a visit by a credential to an account
|
|
78
|
+
* another credential's ladder anchors (a passkey visiting an account the
|
|
79
|
+
* passphrase established).
|
|
68
80
|
*
|
|
69
|
-
* `'update-key-not-attributable'`: a pointer entry is needed, but
|
|
70
|
-
*
|
|
71
|
-
* entry could not
|
|
81
|
+
* `'update-key-not-attributable'`: a pointer entry is needed, but the account
|
|
82
|
+
* log carries no rung of this ladder at all -- no revealed key and no
|
|
83
|
+
* committed hash -- or the attribution is ambiguous, so the entry could not
|
|
84
|
+
* be signed. A merely committed rung is not this state: the pointer move
|
|
85
|
+
* reveals it first.
|
|
72
86
|
*/
|
|
73
87
|
export type ClientAnnexGenerationUnavailableReason = 'ladder-vm-not-anchored' | 'update-key-not-attributable';
|
|
74
88
|
/**
|
|
@@ -121,6 +135,11 @@ export declare function ladderSignedGenerationDelegationMinter({ accountDid, lad
|
|
|
121
135
|
export interface ClientAnnexGenerationEnsureOutcome {
|
|
122
136
|
clientAnnexDid: string;
|
|
123
137
|
generationDelegation: IZcap;
|
|
138
|
+
/**
|
|
139
|
+
* The usable bridge delegation -- the record's own, or the fresh one
|
|
140
|
+
* `onRebindRecord` was handed.
|
|
141
|
+
*/
|
|
142
|
+
delegation: IZcap;
|
|
124
143
|
/**
|
|
125
144
|
* The usable sibling delegation -- the record's own, or the fresh one
|
|
126
145
|
* `onRebindRecord` was handed.
|
|
@@ -130,6 +149,13 @@ export interface ClientAnnexGenerationEnsureOutcome {
|
|
|
130
149
|
spaceMinted: boolean;
|
|
131
150
|
delegationRenewed: boolean;
|
|
132
151
|
siblingReminted: boolean;
|
|
152
|
+
bridgeReminted: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Set when the re-seal of a renewed bridge failed and nothing else needed
|
|
155
|
+
* the re-seal; the fresh bridge still served this visit, and the next
|
|
156
|
+
* visit re-mints.
|
|
157
|
+
*/
|
|
158
|
+
bridgeResealError?: unknown;
|
|
133
159
|
}
|
|
134
160
|
/**
|
|
135
161
|
* Ensures a transient visit can reach a live client-annex generation with a
|
|
@@ -161,13 +187,18 @@ export interface ClientAnnexGenerationEnsureOutcome {
|
|
|
161
187
|
* -- the storage client for the fresh-Space arm, signing as the ladder
|
|
162
188
|
* VM's bare did:key (the caller wires the transport; the agent is derived
|
|
163
189
|
* here from the ladder seed)
|
|
164
|
-
* @param options.
|
|
165
|
-
*
|
|
166
|
-
*
|
|
190
|
+
* @param options.delegation {IZcap} the record's bridge delegation (PUT on
|
|
191
|
+
* the account's `did.jsonl`), renewed here when it is stale
|
|
192
|
+
* @param options.idStoreFor {Function}
|
|
193
|
+
* `({ delegation }) => WebvhIdStore` -- builds the ACCOUNT log's store over
|
|
194
|
+
* the usable bridge (a bridge-delegated store suffices: pointer entries
|
|
195
|
+
* publish with `logOnly: true`). Called once, after the bridge renewal, so
|
|
196
|
+
* a pointer entry never rides a lapsed delegation
|
|
167
197
|
* @param options.onRebindRecord {Function}
|
|
168
|
-
* `({ delegatedClients }) => Promise<void>` -- REQUIRED:
|
|
169
|
-
* unlock record with the
|
|
170
|
-
*
|
|
198
|
+
* `({ delegation, delegatedClients }) => Promise<void>` -- REQUIRED:
|
|
199
|
+
* re-seals the unlock record with the usable bridge and sibling
|
|
200
|
+
* delegations; called whenever either was freshly minted, after the
|
|
201
|
+
* generation and pointer are durable
|
|
171
202
|
* @param [options.delegatedClients] {IZcap} the record's sibling
|
|
172
203
|
* delegation, when the record carries one
|
|
173
204
|
* @param [options.pinStore] {ResourceLogPinStore} chain-head pins (a
|
|
@@ -188,8 +219,12 @@ export declare function ensureCredentialClientAnnexGeneration(options: {
|
|
|
188
219
|
bootstrapWasFor: (options: {
|
|
189
220
|
keyAgent: ICapabilityAgent;
|
|
190
221
|
}) => WasClient;
|
|
191
|
-
|
|
222
|
+
delegation: IZcap;
|
|
223
|
+
idStoreFor: (options: {
|
|
224
|
+
delegation: IZcap;
|
|
225
|
+
}) => WebvhIdStore;
|
|
192
226
|
onRebindRecord: (options: {
|
|
227
|
+
delegation: IZcap;
|
|
193
228
|
delegatedClients: IZcap;
|
|
194
229
|
}) => Promise<void>;
|
|
195
230
|
delegatedClients?: IZcap;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heal.d.ts","sourceRoot":"","sources":["../../src/clientAnnex/heal.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"heal.d.ts","sourceRoot":"","sources":["../../src/clientAnnex/heal.ts"],"names":[],"mappings":"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"}
|
package/dist/clientAnnex/heal.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { WasClient } from '@interop/was-client';
|
|
2
|
-
import { effectiveParameters, readPublishedLog } from '../webvh/didWebvh.js';
|
|
2
|
+
import { effectiveParameters, readPublishedLog, WebvhLogConflictError, withLogConflictRetry } from '../webvh/didWebvh.js';
|
|
3
3
|
import { delegationKeyInDocument, ladderVmIds } from '../webvh/listClients.js';
|
|
4
4
|
import { delegationProofKeyId, zcapExpiring } from '../webvh/standingZcap.js';
|
|
5
|
+
import { delegateLogWrite } from '../recovery/recoveryDelegation.js';
|
|
5
6
|
import { accountLogPinId } from '../webvh/verifyLog.js';
|
|
6
7
|
import { mintSpaceId } from '../genesis/accountGenesis.js';
|
|
7
8
|
import { attributeLadderRung, ladderRung, ladderVmKeyMultibase } from './ladder.js';
|
|
9
|
+
import { revealLadderRungWebvh } from './ladderAnchored.js';
|
|
8
10
|
import { ladderVmAgent, ladderVmZcapClient } from './zcap.js';
|
|
9
|
-
import { clientAnnexDidParts, clientAnnexLogPinId, clientAnnexLogStore, delegatedClientsDelegationSpaceId, delegatedClientsPointer, ensureGenerationDelegationCurrent, mintCredentialClientAnnexGeneration, mintDelegatedClientsDelegation, mintGenerationDelegation,
|
|
11
|
+
import { clientAnnexDidParts, clientAnnexLogPinId, clientAnnexLogStore, delegatedClientsDelegationSpaceId, delegatedClientsPointer, ensureGenerationDelegationCurrent, mintCredentialClientAnnexGeneration, mintDelegatedClientsDelegation, mintGenerationDelegation, setDelegatedClientsPointerOnce } from './log.js';
|
|
10
12
|
/**
|
|
11
13
|
* The typed refusal of {@link ensureCredentialClientAnnexGeneration}: the
|
|
12
14
|
* account is not in a shape this visit can mend, and nothing was written.
|
|
@@ -81,13 +83,18 @@ export function ladderSignedGenerationDelegationMinter({ accountDid, ladderSeed,
|
|
|
81
83
|
* -- the storage client for the fresh-Space arm, signing as the ladder
|
|
82
84
|
* VM's bare did:key (the caller wires the transport; the agent is derived
|
|
83
85
|
* here from the ladder seed)
|
|
84
|
-
* @param options.
|
|
85
|
-
*
|
|
86
|
-
*
|
|
86
|
+
* @param options.delegation {IZcap} the record's bridge delegation (PUT on
|
|
87
|
+
* the account's `did.jsonl`), renewed here when it is stale
|
|
88
|
+
* @param options.idStoreFor {Function}
|
|
89
|
+
* `({ delegation }) => WebvhIdStore` -- builds the ACCOUNT log's store over
|
|
90
|
+
* the usable bridge (a bridge-delegated store suffices: pointer entries
|
|
91
|
+
* publish with `logOnly: true`). Called once, after the bridge renewal, so
|
|
92
|
+
* a pointer entry never rides a lapsed delegation
|
|
87
93
|
* @param options.onRebindRecord {Function}
|
|
88
|
-
* `({ delegatedClients }) => Promise<void>` -- REQUIRED:
|
|
89
|
-
* unlock record with the
|
|
90
|
-
*
|
|
94
|
+
* `({ delegation, delegatedClients }) => Promise<void>` -- REQUIRED:
|
|
95
|
+
* re-seals the unlock record with the usable bridge and sibling
|
|
96
|
+
* delegations; called whenever either was freshly minted, after the
|
|
97
|
+
* generation and pointer are durable
|
|
91
98
|
* @param [options.delegatedClients] {IZcap} the record's sibling
|
|
92
99
|
* delegation, when the record carries one
|
|
93
100
|
* @param [options.pinStore] {ResourceLogPinStore} chain-head pins (a
|
|
@@ -101,7 +108,8 @@ export function ensureCredentialClientAnnexGeneration(options) {
|
|
|
101
108
|
// into the record would strand the very credential this ensure serves.
|
|
102
109
|
if (typeof options.onRebindRecord !== 'function') {
|
|
103
110
|
throw new TypeError('ensureCredentialClientAnnexGeneration requires onRebindRecord: a ' +
|
|
104
|
-
'fresh sibling delegation must be re-sealed into the
|
|
111
|
+
'fresh bridge or sibling delegation must be re-sealed into the ' +
|
|
112
|
+
'unlock record.');
|
|
105
113
|
}
|
|
106
114
|
return ensureCredentialClientAnnexGenerationChecked(options);
|
|
107
115
|
}
|
|
@@ -111,14 +119,17 @@ export function ensureCredentialClientAnnexGeneration(options) {
|
|
|
111
119
|
* @param options {object} see {@link ensureCredentialClientAnnexGeneration}
|
|
112
120
|
* @returns {Promise<ClientAnnexGenerationEnsureOutcome>}
|
|
113
121
|
*/
|
|
114
|
-
async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spaceId, account, ladderSeed, standingClient, bootstrapWasFor,
|
|
122
|
+
async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spaceId, account, ladderSeed, standingClient, bootstrapWasFor, delegation, idStoreFor, onRebindRecord, delegatedClients, pinStore, now }) {
|
|
115
123
|
// The gate: everything below signs as the ladder (the delegations as the
|
|
116
124
|
// ladder VM, the annex entries as its per-generation rung), so unless THIS
|
|
117
125
|
// ladder's VM stands in the document under the ladder-VM relation
|
|
118
126
|
// asymmetry (`capabilityDelegation` without `capabilityInvocation` -- the
|
|
119
127
|
// authority the mends actually exercise, which mere key presence says
|
|
120
128
|
// nothing about), every mend is unverifiable. The honest refusal, before
|
|
121
|
-
// anything is written.
|
|
129
|
+
// anything is written. A standing credential's VM stands whether or not the
|
|
130
|
+
// account has enrolled clients, so this fires only for a document that
|
|
131
|
+
// never carried it -- a torn establishment, or another credential's
|
|
132
|
+
// account.
|
|
122
133
|
const vmKey = await ladderVmKeyMultibase({ ladderSeed });
|
|
123
134
|
if (!ladderVmIds({ doc: account.doc }).includes(`${account.did}#${vmKey}`)) {
|
|
124
135
|
throw new ClientAnnexGenerationUnavailableError({
|
|
@@ -144,14 +155,70 @@ async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spac
|
|
|
144
155
|
spaceId,
|
|
145
156
|
...(now !== undefined ? { now } : {})
|
|
146
157
|
});
|
|
158
|
+
// THE BRIDGE RENEWAL, before any arm. The bridge is the credential's one
|
|
159
|
+
// write path into the account log, and both minting arms end in a pointer
|
|
160
|
+
// entry that rides it. A stale one is replaced with a ladder-VM-signed
|
|
161
|
+
// delegation (the gate above proved the VM a document verification
|
|
162
|
+
// method), and the caller's account-log store is built over whichever
|
|
163
|
+
// bridge is usable.
|
|
164
|
+
let bridgeReminted = false;
|
|
165
|
+
let usableBridge = delegation;
|
|
166
|
+
if (standingZcapStale({
|
|
167
|
+
zcap: delegation,
|
|
168
|
+
doc: account.doc,
|
|
169
|
+
...(now !== undefined ? { now } : {})
|
|
170
|
+
})) {
|
|
171
|
+
usableBridge = await delegateLogWrite({
|
|
172
|
+
zcapClient: ladderClient,
|
|
173
|
+
pointer: { did: account.did, spaceId, host: wasServerUrl },
|
|
174
|
+
recoveryClientDid: standingClient.did,
|
|
175
|
+
...(now !== undefined ? { now } : {})
|
|
176
|
+
});
|
|
177
|
+
bridgeReminted = true;
|
|
178
|
+
}
|
|
179
|
+
const idStore = idStoreFor({ delegation: usableBridge });
|
|
180
|
+
/**
|
|
181
|
+
* The record re-seal, through the required `onRebindRecord` seam: the one
|
|
182
|
+
* call site for every arm, run once the generation and pointer are
|
|
183
|
+
* durable. It fires whenever either recorded delegation was freshly
|
|
184
|
+
* minted, and grades a failure by which one that was. A fresh sibling
|
|
185
|
+
* nothing re-seals would strand the credential, so that throw propagates.
|
|
186
|
+
* A bridge-only renewal needs nothing from the re-seal: the fresh bridge
|
|
187
|
+
* is minted offline and already served this visit, so a lost re-seal
|
|
188
|
+
* leaves no wrong state behind and the next visit re-mints. It is reported
|
|
189
|
+
* on the outcome instead.
|
|
190
|
+
*
|
|
191
|
+
* @param options {object}
|
|
192
|
+
* @param options.delegatedClients {IZcap} the usable sibling delegation
|
|
193
|
+
* @param options.siblingReminted {boolean} whether that sibling is fresh
|
|
194
|
+
* @returns {Promise<object>} the outcome's `bridgeResealError` member,
|
|
195
|
+
* present only when a bridge-only re-seal failed
|
|
196
|
+
*/
|
|
197
|
+
async function resealRecord({ delegatedClients: usableSibling, siblingReminted }) {
|
|
198
|
+
if (!siblingReminted && !bridgeReminted) {
|
|
199
|
+
return {};
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
await onRebindRecord({
|
|
203
|
+
delegation: usableBridge,
|
|
204
|
+
delegatedClients: usableSibling
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
if (siblingReminted) {
|
|
209
|
+
throw err;
|
|
210
|
+
}
|
|
211
|
+
return { bridgeResealError: err };
|
|
212
|
+
}
|
|
213
|
+
return {};
|
|
214
|
+
}
|
|
147
215
|
if (annexSpaceId === undefined) {
|
|
148
216
|
// THE FRESH-SPACE ARM: neither the pointer nor a sibling names a Space.
|
|
149
|
-
// The pre-flight attribution runs before
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
});
|
|
217
|
+
// The pre-flight attribution runs before any generation or Space is
|
|
218
|
+
// minted (a bridge delegation mint writes nothing durable); the stage
|
|
219
|
+
// order mirrors the credential-anchored genesis exactly. A rung that is
|
|
220
|
+
// only committed passes here and is revealed at the pointer entry.
|
|
221
|
+
await assertPointerEntryAttributable({ ladderSeed, log: account.log });
|
|
155
222
|
const freshSpaceId = mintSpaceId();
|
|
156
223
|
const keyAgent = await ladderVmAgent({ ladderSeed });
|
|
157
224
|
const bootstrapWas = bootstrapWasFor({ keyAgent });
|
|
@@ -188,12 +255,11 @@ async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spac
|
|
|
188
255
|
await bootstrapWas
|
|
189
256
|
.space(freshSpaceId)
|
|
190
257
|
.configure({ controller: account.did, force: true });
|
|
191
|
-
await
|
|
258
|
+
await movePointerAsLadder({
|
|
192
259
|
idStore,
|
|
193
|
-
|
|
260
|
+
ladderSeed,
|
|
194
261
|
clientAnnexDid: minted.did,
|
|
195
|
-
|
|
196
|
-
logOnly: true,
|
|
262
|
+
accountDid: account.did,
|
|
197
263
|
...(pinStore !== undefined
|
|
198
264
|
? { pinStore, logId: accountLogPinId({ spaceId }) }
|
|
199
265
|
: {})
|
|
@@ -205,39 +271,39 @@ async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spac
|
|
|
205
271
|
controller: standingClient.did,
|
|
206
272
|
...(now !== undefined ? { now } : {})
|
|
207
273
|
});
|
|
208
|
-
await
|
|
274
|
+
const resealed = await resealRecord({
|
|
275
|
+
delegatedClients: sibling,
|
|
276
|
+
siblingReminted: true
|
|
277
|
+
});
|
|
209
278
|
return {
|
|
210
279
|
clientAnnexDid: minted.did,
|
|
211
280
|
generationDelegation: ensured.delegation,
|
|
281
|
+
delegation: usableBridge,
|
|
212
282
|
delegatedClients: sibling,
|
|
213
283
|
generationMinted: true,
|
|
214
284
|
spaceMinted: true,
|
|
215
285
|
delegationRenewed: false,
|
|
216
|
-
siblingReminted: true
|
|
286
|
+
siblingReminted: true,
|
|
287
|
+
bridgeReminted,
|
|
288
|
+
...resealed
|
|
217
289
|
};
|
|
218
290
|
}
|
|
219
291
|
// THE EXISTING-SPACE ARMS. A usable sibling first: absent, targeting a
|
|
220
292
|
// different Space than the resolved one, or stale on either of the
|
|
221
293
|
// standing-zcap axes -- expiry (past, or inside the renewal window) and
|
|
222
|
-
// signer death (its proof key no longer
|
|
223
|
-
// the current-key-set rule) -- a fresh
|
|
224
|
-
// signing, which verifies because the
|
|
225
|
-
// verification method) so every annex
|
|
294
|
+
// signer death (its proof key no longer under `capabilityDelegation` in
|
|
295
|
+
// the verified account document, the current-key-set rule) -- a fresh
|
|
296
|
+
// sibling is minted (local ladder-VM signing, which verifies because the
|
|
297
|
+
// gate above proved the VM a document verification method) so every annex
|
|
298
|
+
// request below can ride it.
|
|
226
299
|
let sibling = delegatedClients;
|
|
227
300
|
let siblingReminted = false;
|
|
228
301
|
const siblingStale = sibling !== undefined &&
|
|
229
|
-
(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
: {}),
|
|
302
|
+
standingZcapStale({
|
|
303
|
+
zcap: sibling,
|
|
304
|
+
doc: account.doc,
|
|
233
305
|
...(now !== undefined ? { now } : {})
|
|
234
|
-
})
|
|
235
|
-
!delegationKeyInDocument({
|
|
236
|
-
doc: account.doc,
|
|
237
|
-
...(delegationProofKeyId(sibling) !== undefined
|
|
238
|
-
? { delegationKeyId: delegationProofKeyId(sibling) }
|
|
239
|
-
: {})
|
|
240
|
-
}));
|
|
306
|
+
});
|
|
241
307
|
if (sibling === undefined ||
|
|
242
308
|
siblingSpaceId !== annexSpaceId ||
|
|
243
309
|
siblingStale) {
|
|
@@ -289,17 +355,21 @@ async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spac
|
|
|
289
355
|
...annexPin(parts.generationId),
|
|
290
356
|
...(now !== undefined ? { now } : {})
|
|
291
357
|
});
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
358
|
+
const resealed = await resealRecord({
|
|
359
|
+
delegatedClients: usableSibling,
|
|
360
|
+
siblingReminted
|
|
361
|
+
});
|
|
295
362
|
return {
|
|
296
363
|
clientAnnexDid: pointer,
|
|
297
364
|
generationDelegation: ensured.delegation,
|
|
365
|
+
delegation: usableBridge,
|
|
298
366
|
delegatedClients: usableSibling,
|
|
299
367
|
generationMinted: false,
|
|
300
368
|
spaceMinted: false,
|
|
301
369
|
delegationRenewed: ensured.renewed,
|
|
302
|
-
siblingReminted
|
|
370
|
+
siblingReminted,
|
|
371
|
+
bridgeReminted,
|
|
372
|
+
...resealed
|
|
303
373
|
};
|
|
304
374
|
}
|
|
305
375
|
catch (err) {
|
|
@@ -319,10 +389,7 @@ async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spac
|
|
|
319
389
|
// rung; other standing credentials' per-generation rungs are re-committed
|
|
320
390
|
// only by their own later ceremonies (a property of every generation
|
|
321
391
|
// swap).
|
|
322
|
-
|
|
323
|
-
ladderSeed,
|
|
324
|
-
log: account.log
|
|
325
|
-
});
|
|
392
|
+
await assertPointerEntryAttributable({ ladderSeed, log: account.log });
|
|
326
393
|
const minted = await mintCredentialClientAnnexGeneration({
|
|
327
394
|
was: standingWas,
|
|
328
395
|
wasServerUrl,
|
|
@@ -346,29 +413,59 @@ async function ensureCredentialClientAnnexGenerationChecked({ wasServerUrl, spac
|
|
|
346
413
|
// pointer move itself retires it on a conforming server -- the inspector
|
|
347
414
|
// clause compares the delegation's controller against the document's
|
|
348
415
|
// pointer -- and it otherwise rots on its TTL.
|
|
349
|
-
await
|
|
416
|
+
await movePointerAsLadder({
|
|
350
417
|
idStore,
|
|
351
|
-
|
|
418
|
+
ladderSeed,
|
|
352
419
|
clientAnnexDid: minted.did,
|
|
353
|
-
|
|
354
|
-
logOnly: true,
|
|
420
|
+
accountDid: account.did,
|
|
355
421
|
...(pinStore !== undefined
|
|
356
422
|
? { pinStore, logId: accountLogPinId({ spaceId }) }
|
|
357
423
|
: {})
|
|
358
424
|
});
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
425
|
+
const resealed = await resealRecord({
|
|
426
|
+
delegatedClients: usableSibling,
|
|
427
|
+
siblingReminted
|
|
428
|
+
});
|
|
362
429
|
return {
|
|
363
430
|
clientAnnexDid: minted.did,
|
|
364
431
|
generationDelegation: ensured.delegation,
|
|
432
|
+
delegation: usableBridge,
|
|
365
433
|
delegatedClients: usableSibling,
|
|
366
434
|
generationMinted: true,
|
|
367
435
|
spaceMinted: false,
|
|
368
436
|
delegationRenewed: false,
|
|
369
|
-
siblingReminted
|
|
437
|
+
siblingReminted,
|
|
438
|
+
bridgeReminted,
|
|
439
|
+
...resealed
|
|
370
440
|
};
|
|
371
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* The one staleness predicate for the standing recorded delegations this
|
|
444
|
+
* ensure may renew: the record's bridge delegation and its `delegatedClients`
|
|
445
|
+
* sibling. Two axes, the established pair -- expiry (past, or inside the
|
|
446
|
+
* renewal window) and signer death (the proof's verification method no longer
|
|
447
|
+
* under `capabilityDelegation` in the verified account document, the
|
|
448
|
+
* current-key-set rule). One helper rather than a copy per delegation, so the
|
|
449
|
+
* two can never drift onto different rules.
|
|
450
|
+
*
|
|
451
|
+
* @param options {object}
|
|
452
|
+
* @param options.zcap {IZcap} the recorded delegation
|
|
453
|
+
* @param options.doc {object} the VERIFIED account document
|
|
454
|
+
* @param [options.now] {number} epoch milliseconds, for tests
|
|
455
|
+
* @returns {boolean}
|
|
456
|
+
*/
|
|
457
|
+
function standingZcapStale({ zcap, doc, now }) {
|
|
458
|
+
const { expires } = zcap;
|
|
459
|
+
const delegationKeyId = delegationProofKeyId(zcap);
|
|
460
|
+
return (zcapExpiring({
|
|
461
|
+
...(expires !== undefined ? { expires } : {}),
|
|
462
|
+
...(now !== undefined ? { now } : {})
|
|
463
|
+
}) ||
|
|
464
|
+
!delegationKeyInDocument({
|
|
465
|
+
doc: doc,
|
|
466
|
+
...(delegationKeyId !== undefined ? { delegationKeyId } : {})
|
|
467
|
+
}));
|
|
468
|
+
}
|
|
372
469
|
/**
|
|
373
470
|
* The annex Space, in the settled resolution order: the account document's
|
|
374
471
|
* `#DelegatedClients` pointer names it; else the record's sibling
|
|
@@ -445,4 +542,145 @@ export async function pointerEntryUpdateKeys({ ladderSeed, log }) {
|
|
|
445
542
|
});
|
|
446
543
|
return { updateSeed: attributed.rung.seed, stagedSeed: staged.seed };
|
|
447
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* The pre-flight the pointer-moving arms run before minting anything: this
|
|
547
|
+
* ladder has a rung the pointer entry will be able to sign with, either
|
|
548
|
+
* standing in `updateKeys` already or committed in `nextKeyHashes` and
|
|
549
|
+
* revealable by {@link movePointerAsLadder}. A ladder the log carries no rung
|
|
550
|
+
* of at all, and an ambiguous attribution, refuse here with
|
|
551
|
+
* {@link ClientAnnexGenerationUnavailableError} before a generation or a
|
|
552
|
+
* Space is minted.
|
|
553
|
+
*
|
|
554
|
+
* @param options {object}
|
|
555
|
+
* @param options.ladderSeed {Uint8Array}
|
|
556
|
+
* @param options.log {DIDLog} the VERIFIED account log
|
|
557
|
+
* @returns {Promise<void>}
|
|
558
|
+
*/
|
|
559
|
+
async function assertPointerEntryAttributable({ ladderSeed, log }) {
|
|
560
|
+
const params = effectiveParameters(log);
|
|
561
|
+
const current = params[params.length - 1] ?? {
|
|
562
|
+
updateKeys: [],
|
|
563
|
+
nextKeyHashes: []
|
|
564
|
+
};
|
|
565
|
+
try {
|
|
566
|
+
await attributeLadderRung({ ladderSeed, published: current });
|
|
567
|
+
}
|
|
568
|
+
catch (err) {
|
|
569
|
+
if (err.name === 'LadderAttributionError') {
|
|
570
|
+
throw new ClientAnnexGenerationUnavailableError({
|
|
571
|
+
reason: 'update-key-not-attributable',
|
|
572
|
+
message: "The account log carries no rung of this credential's ladder, or " +
|
|
573
|
+
'the attribution is ambiguous; the pointer entry could not be ' +
|
|
574
|
+
'signed, so nothing is minted.'
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
throw err;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* The `#DelegatedClients` pointer move as a credential-only visit makes it:
|
|
582
|
+
* reveal this ladder's rung when only its hash stands committed, re-read, and
|
|
583
|
+
* write the pointer entry signed by the now-revealed rung.
|
|
584
|
+
*
|
|
585
|
+
* A self-enrollment's add entry spends the revealed rung, so on any account
|
|
586
|
+
* that has ever self-enrolled the rung is merely committed and the reveal is
|
|
587
|
+
* what makes the pointer entry signable at all.
|
|
588
|
+
*
|
|
589
|
+
* ACCEPTED CONSEQUENCE (design FW-356, finding R3): the reveal retires
|
|
590
|
+
* nothing, and the pointer entry re-states `updateKeys` verbatim, so the
|
|
591
|
+
* acting rung stands in the account log's `updateKeys` afterwards. The price
|
|
592
|
+
* of a pointer move is therefore a standing account update key in the
|
|
593
|
+
* credential's hand -- direct document-edit authority through the bridge with
|
|
594
|
+
* no further reveal -- retired at that credential's next self-enrollment
|
|
595
|
+
* (whose add entry drops the attributed rung) or at its retirement. This is
|
|
596
|
+
* documented rather than prevented.
|
|
597
|
+
*
|
|
598
|
+
* Both entries run inside ONE conflict retry, and every attempt re-reads the
|
|
599
|
+
* head and re-attributes the rung from it, so a racing ceremony that consumes
|
|
600
|
+
* the rung climbs to the winner's committed rung instead of refusing
|
|
601
|
+
* `update-key-not-attributable` on a rung that is no longer current.
|
|
602
|
+
*
|
|
603
|
+
* Three things make that hold. A rung the winner consumed between this
|
|
604
|
+
* attempt's reveal and its re-read reads back as
|
|
605
|
+
* `update-key-not-attributable`, which inside this loop is staleness rather
|
|
606
|
+
* than a refusal -- the pre-flight already found a rung -- so it is raised as
|
|
607
|
+
* a conflict and the next attempt reveals the winner's committed rung. The pointer entry runs as
|
|
608
|
+
* {@link setDelegatedClientsPointerOnce} rather than through its retrying
|
|
609
|
+
* wrapper: the wrapper's inner loop would re-invoke the attempt with the
|
|
610
|
+
* attribution's stale `updateKeys`, and a rung the racing winner consumed
|
|
611
|
+
* cannot become authorized by re-reading, so the attempt would end on the
|
|
612
|
+
* plain not-authorized refusal, which the outer loop does not retry. And the
|
|
613
|
+
* attempt is handed the very head this attempt attributed against, so a
|
|
614
|
+
* racing entry landing between the attribution and the PUT loses the CAS and
|
|
615
|
+
* surfaces as a `WebvhLogConflictError` -- the refusal the outer loop
|
|
616
|
+
* re-attributes from. The pre-flight guard
|
|
617
|
+
* ({@link assertPointerEntryAttributable}) therefore cannot fire from
|
|
618
|
+
* staleness here: it runs on the caller's snapshot before anything is minted,
|
|
619
|
+
* while every entry this function publishes is built on a head it read
|
|
620
|
+
* itself.
|
|
621
|
+
*
|
|
622
|
+
* @param options {object}
|
|
623
|
+
* @param options.idStore {WebvhIdStore} the account log's store, from the
|
|
624
|
+
* record's bridge delegation
|
|
625
|
+
* @param options.ladderSeed {Uint8Array} the credential's ladder seed
|
|
626
|
+
* @param options.clientAnnexDid {string} the generation to point at
|
|
627
|
+
* @param options.accountDid {string} the account DID the log must resolve to
|
|
628
|
+
* @param [options.pinStore] {ResourceLogPinStore} the visit's chain-head pins
|
|
629
|
+
* @param [options.logId] {string} the account log's pin slot; required
|
|
630
|
+
* whenever a `pinStore` is supplied
|
|
631
|
+
* @returns {Promise<void>}
|
|
632
|
+
*/
|
|
633
|
+
async function movePointerAsLadder({ idStore, ladderSeed, clientAnnexDid, accountDid, pinStore, logId }) {
|
|
634
|
+
const pin = pinStore !== undefined && logId !== undefined ? { pinStore, logId } : {};
|
|
635
|
+
await withLogConflictRetry(async () => {
|
|
636
|
+
await revealLadderRungWebvh({
|
|
637
|
+
store: idStore,
|
|
638
|
+
ladderSeed,
|
|
639
|
+
expectedDid: accountDid,
|
|
640
|
+
...pin
|
|
641
|
+
});
|
|
642
|
+
// The head the reveal entry just published (or the unchanged head, when
|
|
643
|
+
// the rung was revealed already), under the same pin.
|
|
644
|
+
const published = await readPublishedLog({
|
|
645
|
+
idStore,
|
|
646
|
+
expectedDid: accountDid,
|
|
647
|
+
...pin
|
|
648
|
+
});
|
|
649
|
+
if (published === undefined) {
|
|
650
|
+
throw new Error('did:webvh: did.jsonl is missing; nothing to point at a client annex.');
|
|
651
|
+
}
|
|
652
|
+
// A racing ceremony that consumed the rung between this reveal and this
|
|
653
|
+
// read leaves the ladder committed-only again, which the attribution
|
|
654
|
+
// reports as `update-key-not-attributable`. Inside this loop that is a
|
|
655
|
+
// staleness signal rather than a refusal -- the pre-flight already found
|
|
656
|
+
// a rung, and a fresh reveal is exactly what the next attempt does -- so
|
|
657
|
+
// it becomes a conflict for the retry to re-run.
|
|
658
|
+
let updateKeys;
|
|
659
|
+
try {
|
|
660
|
+
updateKeys = await pointerEntryUpdateKeys({
|
|
661
|
+
ladderSeed,
|
|
662
|
+
log: published.log
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
catch (err) {
|
|
666
|
+
if (err.name ===
|
|
667
|
+
'ClientAnnexGenerationUnavailableError' &&
|
|
668
|
+
err.reason ===
|
|
669
|
+
'update-key-not-attributable') {
|
|
670
|
+
throw new WebvhLogConflictError('did:webvh: a concurrent ceremony consumed the rung this pointer ' +
|
|
671
|
+
'move just revealed; the move re-runs from a fresh reveal.', { cause: err });
|
|
672
|
+
}
|
|
673
|
+
throw err;
|
|
674
|
+
}
|
|
675
|
+
await setDelegatedClientsPointerOnce({
|
|
676
|
+
idStore,
|
|
677
|
+
updateKeys,
|
|
678
|
+
clientAnnexDid,
|
|
679
|
+
expectedDid: accountDid,
|
|
680
|
+
logOnly: true,
|
|
681
|
+
published,
|
|
682
|
+
...pin
|
|
683
|
+
});
|
|
684
|
+
});
|
|
685
|
+
}
|
|
448
686
|
//# sourceMappingURL=heal.js.map
|