@interop/wallet-core 0.66.0 → 0.67.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 +12 -8
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts +5 -4
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts.map +1 -1
- package/dist/clientAnnex/credentialAnchoredGenesis.js +32 -50
- package/dist/clientAnnex/credentialAnchoredGenesis.js.map +1 -1
- package/dist/clientAnnex/establish.d.ts +46 -18
- package/dist/clientAnnex/establish.d.ts.map +1 -1
- package/dist/clientAnnex/establish.js +112 -65
- package/dist/clientAnnex/establish.js.map +1 -1
- package/dist/clientAnnex/forget.d.ts.map +1 -1
- package/dist/clientAnnex/forget.js +5 -6
- package/dist/clientAnnex/forget.js.map +1 -1
- package/dist/clientAnnex/forgetLast.d.ts +26 -113
- package/dist/clientAnnex/forgetLast.d.ts.map +1 -1
- package/dist/clientAnnex/forgetLast.js +26 -150
- package/dist/clientAnnex/forgetLast.js.map +1 -1
- package/dist/clientAnnex/heal.d.ts +79 -13
- package/dist/clientAnnex/heal.d.ts.map +1 -1
- package/dist/clientAnnex/heal.js +67 -122
- package/dist/clientAnnex/heal.js.map +1 -1
- package/dist/clientAnnex/index.d.ts +6 -6
- package/dist/clientAnnex/index.d.ts.map +1 -1
- package/dist/clientAnnex/index.js +4 -4
- package/dist/clientAnnex/index.js.map +1 -1
- package/dist/clientAnnex/ladder.d.ts +51 -4
- package/dist/clientAnnex/ladder.d.ts.map +1 -1
- package/dist/clientAnnex/ladder.js +283 -47
- package/dist/clientAnnex/ladder.js.map +1 -1
- package/dist/clientAnnex/ladderAnchored.d.ts +37 -3
- package/dist/clientAnnex/ladderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/ladderAnchored.js +69 -34
- package/dist/clientAnnex/ladderAnchored.js.map +1 -1
- package/dist/clientAnnex/log.d.ts +68 -57
- package/dist/clientAnnex/log.d.ts.map +1 -1
- package/dist/clientAnnex/log.js +96 -126
- package/dist/clientAnnex/log.js.map +1 -1
- package/dist/clientAnnex/mend.js +44 -20
- package/dist/clientAnnex/mend.js.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts +20 -1
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.js +77 -294
- package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -1
- package/dist/clientAnnex/rosterDeliveredEpochs.d.ts +13 -5
- package/dist/clientAnnex/rosterDeliveredEpochs.d.ts.map +1 -1
- package/dist/clientAnnex/rosterDeliveredEpochs.js +18 -9
- package/dist/clientAnnex/rosterDeliveredEpochs.js.map +1 -1
- package/dist/clientAnnex/selfEnroll.js +1 -1
- package/dist/clientAnnex/selfEnroll.js.map +1 -1
- package/dist/clientAnnex/zcap.d.ts +19 -0
- package/dist/clientAnnex/zcap.d.ts.map +1 -1
- package/dist/clientAnnex/zcap.js +80 -12
- package/dist/clientAnnex/zcap.js.map +1 -1
- package/dist/clients/index.d.ts +3 -2
- 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/listing.d.ts.map +1 -1
- package/dist/clients/listing.js +33 -15
- package/dist/clients/listing.js.map +1 -1
- package/dist/clients/policy.d.ts +18 -0
- package/dist/clients/policy.d.ts.map +1 -1
- package/dist/clients/policy.js +22 -8
- package/dist/clients/policy.js.map +1 -1
- package/dist/clients/revocation.d.ts +18 -30
- package/dist/clients/revocation.d.ts.map +1 -1
- package/dist/clients/revocation.js +12 -27
- package/dist/clients/revocation.js.map +1 -1
- package/dist/clients/rosterPolicy.d.ts +6 -1
- package/dist/clients/rosterPolicy.d.ts.map +1 -1
- package/dist/clients/rosterPolicy.js +27 -30
- package/dist/clients/rosterPolicy.js.map +1 -1
- package/dist/descriptors/errors.d.ts +6 -5
- package/dist/descriptors/errors.d.ts.map +1 -1
- package/dist/descriptors/errors.js +6 -5
- package/dist/descriptors/errors.js.map +1 -1
- package/dist/descriptors/index.d.ts +7 -3
- package/dist/descriptors/index.d.ts.map +1 -1
- package/dist/descriptors/index.js +7 -3
- package/dist/descriptors/index.js.map +1 -1
- package/dist/descriptors/logSource.d.ts +28 -6
- package/dist/descriptors/logSource.d.ts.map +1 -1
- package/dist/descriptors/logSource.js +33 -7
- package/dist/descriptors/logSource.js.map +1 -1
- package/dist/enrollment/enrollment.d.ts.map +1 -1
- package/dist/enrollment/enrollment.js +3 -7
- package/dist/enrollment/enrollment.js.map +1 -1
- package/dist/genesis/accountGenesis.d.ts +8 -10
- package/dist/genesis/accountGenesis.d.ts.map +1 -1
- package/dist/genesis/accountGenesis.js +39 -41
- package/dist/genesis/accountGenesis.js.map +1 -1
- package/dist/genesis/kmsAuthentication.d.ts +50 -0
- package/dist/genesis/kmsAuthentication.d.ts.map +1 -0
- package/dist/genesis/kmsAuthentication.js +49 -0
- package/dist/genesis/kmsAuthentication.js.map +1 -0
- package/dist/keyring/kdf.d.ts +16 -20
- package/dist/keyring/kdf.d.ts.map +1 -1
- package/dist/keyring/kdf.js +2 -2
- package/dist/keyring/kdf.js.map +1 -1
- package/dist/keyring/unlockSpace.d.ts +8 -30
- package/dist/keyring/unlockSpace.d.ts.map +1 -1
- package/dist/keyring/unlockSpace.js +8 -31
- package/dist/keyring/unlockSpace.js.map +1 -1
- package/dist/keys/clientKeyRecord.d.ts +2 -1
- package/dist/keys/clientKeyRecord.d.ts.map +1 -1
- package/dist/keys/clientKeyRecord.js +28 -11
- package/dist/keys/clientKeyRecord.js.map +1 -1
- package/dist/keys/index.d.ts +6 -2
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +5 -1
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/rosterLogStore.d.ts.map +1 -1
- package/dist/keys/rosterLogStore.js +14 -5
- package/dist/keys/rosterLogStore.js.map +1 -1
- package/dist/keys/spaceEpochs.d.ts +92 -3
- package/dist/keys/spaceEpochs.d.ts.map +1 -1
- package/dist/keys/spaceEpochs.js +110 -4
- package/dist/keys/spaceEpochs.js.map +1 -1
- package/dist/keys/userKeyRoster.d.ts +30 -3
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +90 -15
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/keys/userKeyRosterCascade.d.ts.map +1 -1
- package/dist/keys/userKeyRosterCascade.js +5 -1
- package/dist/keys/userKeyRosterCascade.js.map +1 -1
- package/dist/recovery/continuation.d.ts +255 -0
- package/dist/recovery/continuation.d.ts.map +1 -0
- package/dist/recovery/continuation.js +471 -0
- package/dist/recovery/continuation.js.map +1 -0
- package/dist/recovery/index.d.ts +12 -8
- package/dist/recovery/index.d.ts.map +1 -1
- package/dist/recovery/index.js +11 -7
- package/dist/recovery/index.js.map +1 -1
- package/dist/recovery/recoveryDelegation.d.ts +23 -126
- package/dist/recovery/recoveryDelegation.d.ts.map +1 -1
- package/dist/recovery/recoveryDelegation.js +1 -266
- package/dist/recovery/recoveryDelegation.js.map +1 -1
- package/dist/recovery/recoveryWebvh.d.ts +42 -83
- package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
- package/dist/recovery/recoveryWebvh.js +44 -380
- package/dist/recovery/recoveryWebvh.js.map +1 -1
- package/dist/request/classify.d.ts +3 -14
- package/dist/request/classify.d.ts.map +1 -1
- package/dist/request/classify.js +19 -40
- package/dist/request/classify.js.map +1 -1
- package/dist/request/index.d.ts +1 -0
- package/dist/request/index.d.ts.map +1 -1
- package/dist/request/index.js +1 -0
- package/dist/request/index.js.map +1 -1
- package/dist/request/onboarding.d.ts.map +1 -1
- package/dist/request/onboarding.js +19 -27
- package/dist/request/onboarding.js.map +1 -1
- package/dist/request/parse.d.ts +5 -3
- package/dist/request/parse.d.ts.map +1 -1
- package/dist/request/parse.js +7 -6
- package/dist/request/parse.js.map +1 -1
- package/dist/request/processRequest.d.ts.map +1 -1
- package/dist/request/processRequest.js +2 -1
- package/dist/request/processRequest.js.map +1 -1
- package/dist/request/queryPredicates.d.ts +98 -0
- package/dist/request/queryPredicates.d.ts.map +1 -0
- package/dist/request/queryPredicates.js +107 -0
- package/dist/request/queryPredicates.js.map +1 -0
- package/dist/resourceLog/document.d.ts +39 -0
- package/dist/resourceLog/document.d.ts.map +1 -1
- package/dist/resourceLog/document.js +41 -0
- package/dist/resourceLog/document.js.map +1 -1
- package/dist/resourceLog/ladderRungs.d.ts.map +1 -1
- package/dist/resourceLog/ladderRungs.js +3 -2
- package/dist/resourceLog/ladderRungs.js.map +1 -1
- package/dist/sync/contactsConflict.d.ts.map +1 -1
- package/dist/sync/contactsConflict.js +8 -2
- package/dist/sync/contactsConflict.js.map +1 -1
- package/dist/sync/engine.d.ts +38 -23
- package/dist/sync/engine.d.ts.map +1 -1
- package/dist/sync/engine.js +36 -5
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/index.d.ts +9 -12
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +8 -11
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +1 -2
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/remint.d.ts +0 -31
- package/dist/sync/remint.d.ts.map +1 -1
- package/dist/sync/remint.js +32 -1
- package/dist/sync/remint.js.map +1 -1
- package/dist/sync/types.d.ts +4 -41
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/sync/types.js +4 -47
- package/dist/sync/types.js.map +1 -1
- package/dist/unlock/index.d.ts +1 -1
- 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 +16 -56
- package/dist/unlock/retire.d.ts.map +1 -1
- package/dist/unlock/retire.js +7 -76
- package/dist/unlock/retire.js.map +1 -1
- package/dist/unlock/standingWebvh.d.ts +20 -40
- package/dist/unlock/standingWebvh.d.ts.map +1 -1
- package/dist/unlock/standingWebvh.js +35 -76
- package/dist/unlock/standingWebvh.js.map +1 -1
- package/dist/unlock/unlockRecord.d.ts.map +1 -1
- package/dist/unlock/unlockRecord.js +69 -44
- package/dist/unlock/unlockRecord.js.map +1 -1
- package/dist/webvh/accountEntry.d.ts +63 -7
- package/dist/webvh/accountEntry.d.ts.map +1 -1
- package/dist/webvh/accountEntry.js +110 -19
- package/dist/webvh/accountEntry.js.map +1 -1
- package/dist/webvh/delegatedLogStore.d.ts +18 -12
- package/dist/webvh/delegatedLogStore.d.ts.map +1 -1
- package/dist/webvh/delegatedLogStore.js +32 -11
- package/dist/webvh/delegatedLogStore.js.map +1 -1
- package/dist/webvh/didWebvh.d.ts +39 -23
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +63 -45
- package/dist/webvh/didWebvh.js.map +1 -1
- package/dist/webvh/enrollClient.d.ts.map +1 -1
- package/dist/webvh/enrollClient.js +19 -23
- package/dist/webvh/enrollClient.js.map +1 -1
- package/dist/webvh/index.d.ts +11 -7
- package/dist/webvh/index.d.ts.map +1 -1
- package/dist/webvh/index.js +9 -6
- package/dist/webvh/index.js.map +1 -1
- package/dist/webvh/listClients.d.ts.map +1 -1
- package/dist/webvh/listClients.js +102 -65
- package/dist/webvh/listClients.js.map +1 -1
- package/dist/webvh/mergeMethods.d.ts +84 -0
- package/dist/webvh/mergeMethods.d.ts.map +1 -0
- package/dist/webvh/mergeMethods.js +46 -0
- package/dist/webvh/mergeMethods.js.map +1 -0
- package/dist/webvh/revokeClient.d.ts +12 -2
- package/dist/webvh/revokeClient.d.ts.map +1 -1
- package/dist/webvh/revokeClient.js +126 -48
- package/dist/webvh/revokeClient.js.map +1 -1
- package/dist/webvh/verifyLog.d.ts +21 -0
- package/dist/webvh/verifyLog.d.ts.map +1 -1
- package/dist/webvh/verifyLog.js +36 -14
- package/dist/webvh/verifyLog.js.map +1 -1
- package/package.json +11 -11
|
@@ -1,7 +1,28 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The recovery code's authorization bridge: the pre-minted PUT-on-`did.jsonl`
|
|
6
|
+
* delegation. The delegation is a wire artifact both apps must mint
|
|
7
|
+
* byte-identically (issuance and every re-bind produce the record another
|
|
8
|
+
* replica later recovers with), so its builder lives here: PUT on the one
|
|
9
|
+
* `did.jsonl` resource, one-year TTL, delegated to the code-derived signing
|
|
10
|
+
* DID. Its narrow scope is what keeps recovery loud -- a stolen code must
|
|
11
|
+
* extend the world-readable log before it can read anything.
|
|
12
|
+
*
|
|
13
|
+
* No ceremony re-mints another credential's bridge. A record's bridge and
|
|
14
|
+
* `delegatedClients` sibling are signed by that record's own credential's
|
|
15
|
+
* ladder VM, and its frame proof by that credential's own unlock identity
|
|
16
|
+
* key (`decisions/0019`), so the only thing that can rot a bridge is
|
|
17
|
+
* retiring the credential it belongs to -- which deletes the record with it.
|
|
18
|
+
* A bridge that ages out, or one a pre-rule bind left signed by a foreign
|
|
19
|
+
* key, is refreshed by that credential's own login on the house staleness
|
|
20
|
+
* axes ({@link zcapExpiring}, `recordedZcapStale`), and the registry fields
|
|
21
|
+
* a refresh records are built here ({@link recordedDelegationFields}).
|
|
22
|
+
*/
|
|
1
23
|
import type { IZcap } from '@interop/data-integrity-core';
|
|
2
24
|
import type { ZcapClient } from '@interop/ezcap';
|
|
3
|
-
import type {
|
|
4
|
-
import type { AccountPointer, RecordSigner } from '../keyring/record.js';
|
|
25
|
+
import type { AccountPointer } from '../keyring/record.js';
|
|
5
26
|
import { delegationProofKeyId } from '../webvh/standingZcap.js';
|
|
6
27
|
/**
|
|
7
28
|
* The recovery delegation's lifetime: the house standing-zcap value
|
|
@@ -64,128 +85,4 @@ export declare function recordedDelegationFields({ delegation, delegatedClients
|
|
|
64
85
|
delegatedClientsKeyId?: string;
|
|
65
86
|
delegatedClientsExpires?: string;
|
|
66
87
|
};
|
|
67
|
-
/**
|
|
68
|
-
* The members of a recovery-code registry entry the re-mint reads: where the
|
|
69
|
-
* code's unlock Space and record are (`unlockSpaceId`, `manageCapability`),
|
|
70
|
-
* which key signed the recorded delegation and when it expires
|
|
71
|
-
* (`delegationKeyId` / `delegationExpires` -- either absent on an entry
|
|
72
|
-
* predating its field, which the staleness checks conservatively flag), and
|
|
73
|
-
* the re-mint fields: the code-derived signing DID the fresh delegation names
|
|
74
|
-
* and the unlock KAK public half the record is re-wrapped to. A standing
|
|
75
|
-
* credential's entry additionally tracks its annex Space sibling
|
|
76
|
-
* delegation as a second scalar pair (`delegatedClientsKeyId` /
|
|
77
|
-
* `delegatedClientsExpires` -- absent for recovery codes, mirroring the
|
|
78
|
-
* record member's optionality); the sibling rots on exactly the bridge's
|
|
79
|
-
* axis, so one pass reseals both. Structural on
|
|
80
|
-
* purpose -- an app's richer registry entry satisfies it, and the re-mint
|
|
81
|
-
* hands the SAME entry back (with the fresh key ids and expiries) through the
|
|
82
|
-
* record seam, extra members untouched.
|
|
83
|
-
*/
|
|
84
|
-
export interface RecoveryDelegationEntry {
|
|
85
|
-
label: string;
|
|
86
|
-
unlockSpaceId: string;
|
|
87
|
-
manageCapability?: IZcap;
|
|
88
|
-
delegationKeyId?: string;
|
|
89
|
-
delegationExpires?: string;
|
|
90
|
-
delegatedClientsKeyId?: string;
|
|
91
|
-
delegatedClientsExpires?: string;
|
|
92
|
-
recoveryClientDid?: string;
|
|
93
|
-
unlockKeyAgreementKeyId?: string;
|
|
94
|
-
unlockKeyAgreementKeyMultibase?: string;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* One registry entry's fate in a re-mint pass: `current` (both members stand
|
|
98
|
-
* and are outside the renewal window -- nothing written), `reminted` (the
|
|
99
|
-
* record re-sealed and the entry handed back fresh; `siblingCarriedVerbatim`
|
|
100
|
-
* flags a recorded sibling the pass could not rebuild because the document
|
|
101
|
-
* points at no generation, which stays flagged for the health check),
|
|
102
|
-
* `incomplete-entry` (an entry predating the re-mint fields, skipped until
|
|
103
|
-
* the credential is re-bound), `pending-entry` (the entry's recorded
|
|
104
|
-
* unlock-key members do not match the credential the record at its unlock
|
|
105
|
-
* Space is sealed to -- a passphrase change torn before its retirement; the
|
|
106
|
-
* next passphrase login's repair finishes it, and re-minting here would
|
|
107
|
-
* re-arm the retired credential into the new one's record), or `failed` (the record could not be read,
|
|
108
|
-
* re-sealed, or re-PUT -- `error` carries the cause). A skipped or failed
|
|
109
|
-
* entry is named here so no caller can lose it silently.
|
|
110
|
-
*/
|
|
111
|
-
export interface RecordRemintOutcome {
|
|
112
|
-
label: string;
|
|
113
|
-
unlockSpaceId: string;
|
|
114
|
-
outcome: 'current' | 'reminted' | 'incomplete-entry' | 'pending-entry' | 'failed';
|
|
115
|
-
siblingCarriedVerbatim?: boolean;
|
|
116
|
-
error?: unknown;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Re-mints the recovery delegations the current document no longer backs --
|
|
120
|
-
* the recovery-code delta riding the revocation cascade (see the module doc
|
|
121
|
-
* for the mechanism and the skip policy).
|
|
122
|
-
*
|
|
123
|
-
* The record's credential-authenticated core is preserved verbatim: the
|
|
124
|
-
* re-mint reads the standing record through the entry's management zcap and
|
|
125
|
-
* replaces only its delegation members
|
|
126
|
-
* ({@link remintUnlockRecordDelegations}) -- the bridge always, and the
|
|
127
|
-
* annex Space sibling where the entry records one (the two rot on one
|
|
128
|
-
* axis, so both reseal in the same atomic pass and one registry-entry
|
|
129
|
-
* rewrite records both fresh pairs). The
|
|
130
|
-
* shell, the ladder member (where one rides), and the binding tag all travel
|
|
131
|
-
* untouched, since the re-mint can decrypt none of them and does not need to.
|
|
132
|
-
* A re-mint therefore can never change the pointer or controller the
|
|
133
|
-
* credential was bound against -- and after a host migration the tag no
|
|
134
|
-
* longer matches the moved pointer, so credentials must be rebound (codes
|
|
135
|
-
* re-issued) when the account moves hosts.
|
|
136
|
-
*
|
|
137
|
-
* The re-mint holds the code's KAK public half but not its signing key, so
|
|
138
|
-
* every record it re-PUTs is signed with the acting client's own account key
|
|
139
|
-
* (`recordSigner`) -- the mixed-signer case a reader settles against the
|
|
140
|
-
* verified did:webvh document.
|
|
141
|
-
*
|
|
142
|
-
* Best-effort per entry: a skipped entry stays flagged by the login-time
|
|
143
|
-
* health check, whose regenerate nudge remains the backstop.
|
|
144
|
-
*
|
|
145
|
-
* @param options {object}
|
|
146
|
-
* @param options.doc {PublishedKeyDocument} the locally verified did:webvh
|
|
147
|
-
* document, AFTER the revocation edit
|
|
148
|
-
* @param options.entries {RecoveryDelegationEntry[]} the registry's
|
|
149
|
-
* recovery-code entries, as the app's registry read returned them
|
|
150
|
-
* @param options.pointer {AccountPointer}
|
|
151
|
-
* @param options.storageServerUrl {string} the unlock Spaces' storage server
|
|
152
|
-
* @param options.zcapClient {ZcapClient} the acting client's promoted
|
|
153
|
-
* signer, which mints the fresh delegations
|
|
154
|
-
* @param options.recordSigner {RecordSigner} the acting client's account
|
|
155
|
-
* key, which signs the re-wrapped records
|
|
156
|
-
* @param options.managementZcapClient {Function} `({ capability }) =>
|
|
157
|
-
* ZcapClient` -- the client an entry's management zcap is invoked with
|
|
158
|
-
* @param options.recordEntry {Function} `({ entry }) => Promise<void>` --
|
|
159
|
-
* persists one updated registry entry (matching on the app's entry key)
|
|
160
|
-
* @param [options.mintDelegatedClientsDelegation] {Function} `({ controller })
|
|
161
|
-
* => Promise<IZcap | undefined>` -- the annex-side mint of a fresh
|
|
162
|
-
* `delegatedClients` sibling delegation, injected by the caller (the
|
|
163
|
-
* annex subpath's `delegatedClientsDelegationMinter` builds one over the
|
|
164
|
-
* verified document); `undefined` when the document points at no
|
|
165
|
-
* generation, in which case the old sealed member travels verbatim
|
|
166
|
-
* @returns {Promise<{ reminted: number; skipped: number }>}
|
|
167
|
-
*/
|
|
168
|
-
export declare function remintRecoveryDelegations<Entry extends RecoveryDelegationEntry>({ doc, entries, pointer, storageServerUrl, zcapClient, recordSigner, managementZcapClient, recordEntry, mintDelegatedClientsDelegation, retiringKeyMultibases, now }: {
|
|
169
|
-
doc: PublishedKeyDocument;
|
|
170
|
-
entries: Entry[];
|
|
171
|
-
pointer: AccountPointer;
|
|
172
|
-
storageServerUrl: string;
|
|
173
|
-
zcapClient: ZcapClient;
|
|
174
|
-
recordSigner: RecordSigner;
|
|
175
|
-
managementZcapClient: (options: {
|
|
176
|
-
capability: IZcap;
|
|
177
|
-
}) => ZcapClient;
|
|
178
|
-
recordEntry: (options: {
|
|
179
|
-
entry: Entry;
|
|
180
|
-
}) => Promise<void>;
|
|
181
|
-
mintDelegatedClientsDelegation?: (options: {
|
|
182
|
-
controller: string;
|
|
183
|
-
}) => Promise<IZcap | undefined>;
|
|
184
|
-
retiringKeyMultibases?: string[];
|
|
185
|
-
now?: number;
|
|
186
|
-
}): Promise<{
|
|
187
|
-
reminted: number;
|
|
188
|
-
skipped: number;
|
|
189
|
-
outcomes: RecordRemintOutcome[];
|
|
190
|
-
}>;
|
|
191
88
|
//# sourceMappingURL=recoveryDelegation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recoveryDelegation.d.ts","sourceRoot":"","sources":["../../src/recovery/recoveryDelegation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"recoveryDelegation.d.ts","sourceRoot":"","sources":["../../src/recovery/recoveryDelegation.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EACL,oBAAoB,EAErB,MAAM,0BAA0B,CAAA;AAEjC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,0BAA0B,QAAuB,CAAA;AAI9D,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAqB/E;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,GAAgB,EACjB,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,cAAc,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,GAAG,OAAO,CAAC,KAAK,CAAC,CAOjB;AAID,OAAO,EAAE,oBAAoB,EAAE,CAAA;AAE/B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,UAAU,EACV,gBAAgB,EACjB,EAAE;IACD,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,gBAAgB,CAAC,EAAE,KAAK,CAAA;CACzB,GAAG;IACF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACjC,CAiBA"}
|
|
@@ -1,55 +1,6 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* The recovery code's authorization bridge: the pre-minted PUT-on-`did.jsonl`
|
|
6
|
-
* delegation and the revocation cascade's re-mint of it. The delegation is a
|
|
7
|
-
* wire artifact both apps must mint byte-identically (issuance and every
|
|
8
|
-
* re-mint produce the record another replica later recovers with), so its
|
|
9
|
-
* builder lives here: PUT on the one `did.jsonl` resource, one-year TTL,
|
|
10
|
-
* delegated to the code-derived signing DID. Its narrow scope is what keeps
|
|
11
|
-
* recovery loud -- a stolen code must extend the world-readable log before it
|
|
12
|
-
* can read anything.
|
|
13
|
-
*
|
|
14
|
-
* Beside the builder lives the re-mint core (`remintRecoveryDelegations`):
|
|
15
|
-
* revoking a client kills, by the current-key-set rule, every `did.jsonl`
|
|
16
|
-
* delegation that client signed, which would brick recovery exactly when it
|
|
17
|
-
* is needed -- and a delegation left standing eventually reaches its own
|
|
18
|
-
* expiry. For each registry entry whose recorded delegation no longer
|
|
19
|
-
* chains (its signing verification method left `capabilityDelegation` in the
|
|
20
|
-
* document) or is expired or inside the renewal window, the acting client
|
|
21
|
-
* signs a fresh delegation to the code's signing DID, re-wraps the
|
|
22
|
-
* record to the code's unlock KAK (the public half the registry records --
|
|
23
|
-
* the record carries no secrets, so re-encryption needs none), re-PUTs it
|
|
24
|
-
* through the entry's management zcap, and updates the registry's
|
|
25
|
-
* `delegationKeyId` and `delegationExpires`. A standing credential's
|
|
26
|
-
* client-annex Space sibling delegation rides the same pass (its scalar pair is
|
|
27
|
-
* `delegatedClientsKeyId` / `delegatedClientsExpires`): either member going
|
|
28
|
-
* stale reseals both, and the one registry rewrite records both fresh pairs
|
|
29
|
-
* -- a re-mint handling only the bridge is incomplete. The skip policy is
|
|
30
|
-
* cross-replica correctness and is
|
|
31
|
-
* decided here once: an entry that predates the re-mint fields, or whose
|
|
32
|
-
* standing record cannot be read or carries no binding, is skipped and stays
|
|
33
|
-
* flagged by the login-time health check. Every entry's fate is reported
|
|
34
|
-
* (`RecordRemintOutcome`), so a record the pass could not reach is named
|
|
35
|
-
* rather than silently left with a rotted bridge. What stays app-side is the
|
|
36
|
-
* seams: the management-zcap client factory, the storage server URL, and the
|
|
37
|
-
* registry read/record halves.
|
|
38
|
-
*
|
|
39
|
-
* The same pass serves the last-client forget ceremony, whose acting signer
|
|
40
|
-
* is the ladder VM rather than an enrolled client: there the rot check runs
|
|
41
|
-
* against the post-install document, in which the client about to be removed
|
|
42
|
-
* still stands, so the ceremony names it as retiring
|
|
43
|
-
* (`retiringKeyMultibases`) and every delegation it signed counts as rotted
|
|
44
|
-
* ahead of the removal entry.
|
|
45
|
-
*/
|
|
46
|
-
import { X25519KeyAgreementKey2020 } from '@interop/x25519-key-agreement-key';
|
|
47
1
|
import { resourcePath, toUrl } from '@interop/was-client/paths';
|
|
48
|
-
import { log } from '../log.js';
|
|
49
2
|
import { DID_LOG_RESOURCE, ID_COLLECTION } from '../space/collections.js';
|
|
50
|
-
import {
|
|
51
|
-
import { remintUnlockRecordDelegations, unlockRecordSealedTo } from '../unlock/unlockRecord.js';
|
|
52
|
-
import { delegationProofKeyId, recordedZcapStale, STANDING_ZCAP_TTL_MS } from '../webvh/standingZcap.js';
|
|
3
|
+
import { delegationProofKeyId, STANDING_ZCAP_TTL_MS } from '../webvh/standingZcap.js';
|
|
53
4
|
/**
|
|
54
5
|
* The recovery delegation's lifetime: the house standing-zcap value
|
|
55
6
|
* ({@link STANDING_ZCAP_TTL_MS} -- one year, per NIST SP 800-57's
|
|
@@ -153,220 +104,4 @@ export function recordedDelegationFields({ delegation, delegatedClients }) {
|
|
|
153
104
|
function zcapExpires(zcap) {
|
|
154
105
|
return zcap.expires;
|
|
155
106
|
}
|
|
156
|
-
/**
|
|
157
|
-
* Re-mints the recovery delegations the current document no longer backs --
|
|
158
|
-
* the recovery-code delta riding the revocation cascade (see the module doc
|
|
159
|
-
* for the mechanism and the skip policy).
|
|
160
|
-
*
|
|
161
|
-
* The record's credential-authenticated core is preserved verbatim: the
|
|
162
|
-
* re-mint reads the standing record through the entry's management zcap and
|
|
163
|
-
* replaces only its delegation members
|
|
164
|
-
* ({@link remintUnlockRecordDelegations}) -- the bridge always, and the
|
|
165
|
-
* annex Space sibling where the entry records one (the two rot on one
|
|
166
|
-
* axis, so both reseal in the same atomic pass and one registry-entry
|
|
167
|
-
* rewrite records both fresh pairs). The
|
|
168
|
-
* shell, the ladder member (where one rides), and the binding tag all travel
|
|
169
|
-
* untouched, since the re-mint can decrypt none of them and does not need to.
|
|
170
|
-
* A re-mint therefore can never change the pointer or controller the
|
|
171
|
-
* credential was bound against -- and after a host migration the tag no
|
|
172
|
-
* longer matches the moved pointer, so credentials must be rebound (codes
|
|
173
|
-
* re-issued) when the account moves hosts.
|
|
174
|
-
*
|
|
175
|
-
* The re-mint holds the code's KAK public half but not its signing key, so
|
|
176
|
-
* every record it re-PUTs is signed with the acting client's own account key
|
|
177
|
-
* (`recordSigner`) -- the mixed-signer case a reader settles against the
|
|
178
|
-
* verified did:webvh document.
|
|
179
|
-
*
|
|
180
|
-
* Best-effort per entry: a skipped entry stays flagged by the login-time
|
|
181
|
-
* health check, whose regenerate nudge remains the backstop.
|
|
182
|
-
*
|
|
183
|
-
* @param options {object}
|
|
184
|
-
* @param options.doc {PublishedKeyDocument} the locally verified did:webvh
|
|
185
|
-
* document, AFTER the revocation edit
|
|
186
|
-
* @param options.entries {RecoveryDelegationEntry[]} the registry's
|
|
187
|
-
* recovery-code entries, as the app's registry read returned them
|
|
188
|
-
* @param options.pointer {AccountPointer}
|
|
189
|
-
* @param options.storageServerUrl {string} the unlock Spaces' storage server
|
|
190
|
-
* @param options.zcapClient {ZcapClient} the acting client's promoted
|
|
191
|
-
* signer, which mints the fresh delegations
|
|
192
|
-
* @param options.recordSigner {RecordSigner} the acting client's account
|
|
193
|
-
* key, which signs the re-wrapped records
|
|
194
|
-
* @param options.managementZcapClient {Function} `({ capability }) =>
|
|
195
|
-
* ZcapClient` -- the client an entry's management zcap is invoked with
|
|
196
|
-
* @param options.recordEntry {Function} `({ entry }) => Promise<void>` --
|
|
197
|
-
* persists one updated registry entry (matching on the app's entry key)
|
|
198
|
-
* @param [options.mintDelegatedClientsDelegation] {Function} `({ controller })
|
|
199
|
-
* => Promise<IZcap | undefined>` -- the annex-side mint of a fresh
|
|
200
|
-
* `delegatedClients` sibling delegation, injected by the caller (the
|
|
201
|
-
* annex subpath's `delegatedClientsDelegationMinter` builds one over the
|
|
202
|
-
* verified document); `undefined` when the document points at no
|
|
203
|
-
* generation, in which case the old sealed member travels verbatim
|
|
204
|
-
* @returns {Promise<{ reminted: number; skipped: number }>}
|
|
205
|
-
*/
|
|
206
|
-
export async function remintRecoveryDelegations({ doc, entries, pointer, storageServerUrl, zcapClient, recordSigner, managementZcapClient, recordEntry, mintDelegatedClientsDelegation, retiringKeyMultibases = [], now = Date.now() }) {
|
|
207
|
-
let reminted = 0;
|
|
208
|
-
let skipped = 0;
|
|
209
|
-
const outcomes = [];
|
|
210
|
-
// The house staleness policy, decided once in `webvh` and asked here over
|
|
211
|
-
// the scalars a registry entry records: expiry, the current-key-set rule
|
|
212
|
-
// (a recorded signing key the document no longer lists under
|
|
213
|
-
// `capabilityDelegation` -- or no recorded key at all -- has rotted), and
|
|
214
|
-
// the caller's retiring set, which the document still lists only until the
|
|
215
|
-
// entry that removes those keys lands.
|
|
216
|
-
const recordedStale = (delegationKeyId, expires) => recordedZcapStale({
|
|
217
|
-
doc,
|
|
218
|
-
...(delegationKeyId ? { delegationKeyId } : {}),
|
|
219
|
-
...(expires ? { expires } : {}),
|
|
220
|
-
retiringKeyMultibases,
|
|
221
|
-
now
|
|
222
|
-
});
|
|
223
|
-
for (const entry of entries) {
|
|
224
|
-
const stale = recordedStale(entry.delegationKeyId, entry.delegationExpires);
|
|
225
|
-
// The annex Space sibling, where the entry records one, is checked on the
|
|
226
|
-
// same axes; either member going stale re-mints BOTH in one atomic pass
|
|
227
|
-
// (both resealed, one registry-entry rewrite).
|
|
228
|
-
const siblingRecorded = entry.delegatedClientsKeyId !== undefined ||
|
|
229
|
-
entry.delegatedClientsExpires !== undefined;
|
|
230
|
-
const siblingStale = siblingRecorded &&
|
|
231
|
-
recordedStale(entry.delegatedClientsKeyId, entry.delegatedClientsExpires);
|
|
232
|
-
if (!stale && !siblingStale) {
|
|
233
|
-
outcomes.push({
|
|
234
|
-
label: entry.label,
|
|
235
|
-
unlockSpaceId: entry.unlockSpaceId,
|
|
236
|
-
outcome: 'current'
|
|
237
|
-
});
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
if (!entry.recoveryClientDid ||
|
|
241
|
-
!entry.unlockKeyAgreementKeyId ||
|
|
242
|
-
!entry.unlockKeyAgreementKeyMultibase ||
|
|
243
|
-
!entry.manageCapability) {
|
|
244
|
-
// An entry issued before the re-mint fields existed: the health check
|
|
245
|
-
// keeps flagging it until the code is regenerated.
|
|
246
|
-
skipped += 1;
|
|
247
|
-
outcomes.push({
|
|
248
|
-
label: entry.label,
|
|
249
|
-
unlockSpaceId: entry.unlockSpaceId,
|
|
250
|
-
outcome: 'incomplete-entry'
|
|
251
|
-
});
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
try {
|
|
255
|
-
// The standing record, whose credential-authenticated core travels
|
|
256
|
-
// verbatim (a record with no binding predates the standing layout and
|
|
257
|
-
// cannot be re-minted -- `remintUnlockRecordDelegations` refuses, and the
|
|
258
|
-
// entry is skipped into the health check's regenerate nudge).
|
|
259
|
-
const standing = await getUnlockKeyringWithCapability({
|
|
260
|
-
storageServerUrl,
|
|
261
|
-
zcapClient: managementZcapClient({
|
|
262
|
-
capability: entry.manageCapability
|
|
263
|
-
}),
|
|
264
|
-
spaceId: entry.unlockSpaceId,
|
|
265
|
-
capability: entry.manageCapability
|
|
266
|
-
});
|
|
267
|
-
// The pending-shaped guard: the entry's `unlockSpaceId` and
|
|
268
|
-
// `manageCapability` name one credential while its identity members
|
|
269
|
-
// name another -- the state a passphrase change torn before its
|
|
270
|
-
// retirement leaves. Re-minting here would seal a fresh
|
|
271
|
-
// current-client-signed bridge for the OLD credential into the NEW
|
|
272
|
-
// credential's record, re-arming the half-retired credential and
|
|
273
|
-
// bricking the new one's entry paths. Nothing is written; the next
|
|
274
|
-
// passphrase login's repair is the mender.
|
|
275
|
-
if (!unlockRecordSealedTo({
|
|
276
|
-
record: standing,
|
|
277
|
-
keyAgreementKeyMultibase: entry.unlockKeyAgreementKeyMultibase
|
|
278
|
-
})) {
|
|
279
|
-
log.warn('The unlock record at the Space recorded for this entry is ' +
|
|
280
|
-
'sealed to another credential (a passphrase change torn before ' +
|
|
281
|
-
'its retirement landed); its delegations are not re-minted', { label: entry.label });
|
|
282
|
-
skipped += 1;
|
|
283
|
-
outcomes.push({
|
|
284
|
-
label: entry.label,
|
|
285
|
-
unlockSpaceId: entry.unlockSpaceId,
|
|
286
|
-
outcome: 'pending-entry'
|
|
287
|
-
});
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
const delegation = await delegateLogWrite({
|
|
291
|
-
zcapClient,
|
|
292
|
-
pointer,
|
|
293
|
-
recoveryClientDid: entry.recoveryClientDid
|
|
294
|
-
});
|
|
295
|
-
// The fresh annex Space sibling, for an entry that records one --
|
|
296
|
-
// minted through the injected annex-side closure, so this orchestrator
|
|
297
|
-
// never imports the annex module. A document not (yet) pointing at a
|
|
298
|
-
// generation (or a caller wiring no minter) leaves nothing to rebuild
|
|
299
|
-
// the target from, so the old sealed member travels verbatim and the
|
|
300
|
-
// pair stays stale-flagged for the login-time health check.
|
|
301
|
-
let delegatedClients;
|
|
302
|
-
let siblingCarriedVerbatim = false;
|
|
303
|
-
if (siblingRecorded) {
|
|
304
|
-
delegatedClients = await mintDelegatedClientsDelegation?.({
|
|
305
|
-
controller: entry.recoveryClientDid
|
|
306
|
-
});
|
|
307
|
-
if (!delegatedClients) {
|
|
308
|
-
siblingCarriedVerbatim = true;
|
|
309
|
-
log.warn('The account document names no client-annex generation; the ' +
|
|
310
|
-
'delegatedClients delegation for this entry is carried verbatim', { label: entry.label });
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
// The credential's unlock KAK, public half only -- exactly enough to
|
|
314
|
-
// seal the fresh bridge to the same recipient the credential derives
|
|
315
|
-
// (sealing goes through the encrypt-only cipher, so no secret is
|
|
316
|
-
// needed).
|
|
317
|
-
const unlockKak = (await X25519KeyAgreementKey2020.from({
|
|
318
|
-
id: entry.unlockKeyAgreementKeyId,
|
|
319
|
-
controller: entry.unlockKeyAgreementKeyId.split('#')[0],
|
|
320
|
-
type: 'X25519KeyAgreementKey2020',
|
|
321
|
-
publicKeyMultibase: entry.unlockKeyAgreementKeyMultibase
|
|
322
|
-
}));
|
|
323
|
-
const wrapped = await remintUnlockRecordDelegations({
|
|
324
|
-
record: standing,
|
|
325
|
-
delegation,
|
|
326
|
-
...(delegatedClients ? { delegatedClients } : {}),
|
|
327
|
-
keyAgreementKey: unlockKak,
|
|
328
|
-
signer: recordSigner
|
|
329
|
-
});
|
|
330
|
-
await putUnlockKeyringWithCapability({
|
|
331
|
-
storageServerUrl,
|
|
332
|
-
zcapClient: managementZcapClient({
|
|
333
|
-
capability: entry.manageCapability
|
|
334
|
-
}),
|
|
335
|
-
spaceId: entry.unlockSpaceId,
|
|
336
|
-
record: wrapped,
|
|
337
|
-
capability: entry.manageCapability
|
|
338
|
-
});
|
|
339
|
-
await recordEntry({
|
|
340
|
-
entry: {
|
|
341
|
-
...entry,
|
|
342
|
-
...recordedDelegationFields({
|
|
343
|
-
delegation,
|
|
344
|
-
...(delegatedClients ? { delegatedClients } : {})
|
|
345
|
-
})
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
reminted += 1;
|
|
349
|
-
outcomes.push({
|
|
350
|
-
label: entry.label,
|
|
351
|
-
unlockSpaceId: entry.unlockSpaceId,
|
|
352
|
-
outcome: 'reminted',
|
|
353
|
-
...(siblingCarriedVerbatim ? { siblingCarriedVerbatim } : {})
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
catch (err) {
|
|
357
|
-
log.warn('Could not re-mint the recovery delegation', {
|
|
358
|
-
label: entry.label,
|
|
359
|
-
err
|
|
360
|
-
});
|
|
361
|
-
skipped += 1;
|
|
362
|
-
outcomes.push({
|
|
363
|
-
label: entry.label,
|
|
364
|
-
unlockSpaceId: entry.unlockSpaceId,
|
|
365
|
-
outcome: 'failed',
|
|
366
|
-
error: err
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
return { reminted, skipped, outcomes };
|
|
371
|
-
}
|
|
372
107
|
//# sourceMappingURL=recoveryDelegation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recoveryDelegation.js","sourceRoot":"","sources":["../../src/recovery/recoveryDelegation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"recoveryDelegation.js","sourceRoot":"","sources":["../../src/recovery/recoveryDelegation.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAEzE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,0BAA0B,CAAA;AAEjC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,oBAAoB,CAAA;AAE9D,wEAAwE;AACxE,2DAA2D;AAC3D,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE/E;;;;;;;;;;;GAWG;AACH,SAAS,SAAS,CAAC,EAAE,OAAO,EAA+B;IACzD,OAAO,KAAK,CAAC;QACX,SAAS,EAAE,OAAO,CAAC,IAAI;QACvB,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,EAAE,gBAAgB,CAAC;KACxE,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EACrC,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,EAMjB;IACC,OAAO,UAAU,CAAC,QAAQ,CAAC;QACzB,gBAAgB,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;QACxC,UAAU,EAAE,iBAAiB;QAC7B,cAAc,EAAE,CAAC,KAAK,CAAC;QACvB,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,GAAG,0BAA0B,CAAC;KACpD,CAAC,CAAA;AACJ,CAAC;AAED,sEAAsE;AACtE,wCAAwC;AACxC,OAAO,EAAE,oBAAoB,EAAE,CAAA;AAE/B;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB,CAAC,EACvC,UAAU,EACV,gBAAgB,EAIjB;IAMC,MAAM,eAAe,GAAG,UAAU;QAChC,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC;QAClC,CAAC,CAAC,SAAS,CAAA;IACb,MAAM,iBAAiB,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1E,MAAM,qBAAqB,GAAG,gBAAgB;QAC5C,CAAC,CAAC,oBAAoB,CAAC,gBAAgB,CAAC;QACxC,CAAC,CAAC,SAAS,CAAA;IACb,MAAM,uBAAuB,GAAG,gBAAgB;QAC9C,CAAC,CAAC,WAAW,CAAC,gBAAgB,CAAC;QAC/B,CAAC,CAAC,SAAS,CAAA;IACb,OAAO;QACL,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChE,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,IAAW;IAC9B,OAAQ,IAA6B,CAAC,OAAO,CAAA;AAC/C,CAAC"}
|
|
@@ -1,91 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import type { UnlockInventoryPart } from '../unlock/standingWebvh.js';
|
|
5
|
-
import type { AccountLogSigner } from '../webvh/accountEntry.js';
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
6
4
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* The did:webvh half of recovery-code lifecycle: the split configuration a
|
|
6
|
+
* code holds as a standing unlock credential that retires on spend. At
|
|
7
|
+
* issuance the document gains the code's `keyAgreement` verification method
|
|
8
|
+
* (an ordinary Multikey entry -- deliberately unmarked; a recovery key is
|
|
9
|
+
* distinguishable structurally, since it appears under `keyAgreement` and
|
|
10
|
+
* `assertionMethod`/`capabilityDelegation` while every enrolled client also
|
|
11
|
+
* publishes an invocation relationship, so client listings key on
|
|
12
|
+
* `capabilityInvocation` and never see it), the code's ladder VM, and its
|
|
13
|
+
* rung-0 hash in `nextKeyHashes` -- decryption and delegation standing,
|
|
14
|
+
* update authority latent: rung 0 joins `updateKeys` nowhere, and every key
|
|
15
|
+
* of the set exists nowhere until the code is typed.
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* ladder's rung 0 on the transient continuation, the new client's update key
|
|
17
|
-
* on the remembered one), which only that entry writes. What it retired is
|
|
18
|
-
* then the credential-class `keyAgreement` ids its predecessor published and
|
|
19
|
-
* it does not, less the spent code's own id -- the same exclusion the live
|
|
20
|
-
* branch makes, since the caller retires that one by name.
|
|
17
|
+
* At recovery time the pre-committed rung 0 reveals itself to sign the
|
|
18
|
+
* self-enrolling continuation, two entries:
|
|
21
19
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
did: string;
|
|
35
|
-
successorKeyMultibase: string;
|
|
36
|
-
spentVmId: string;
|
|
37
|
-
}): string[];
|
|
38
|
-
/**
|
|
39
|
-
* The verification-method id a code's key-agreement key publishes under --
|
|
40
|
-
* the ordinary `<did>#<multibase>` form, indistinguishable by id from any
|
|
41
|
-
* other keyAgreement entry. Consumers that must exclude recovery entries do
|
|
42
|
-
* it structurally (an enrolled client is a `capabilityInvocation` entry; a
|
|
43
|
-
* recovery key never has one) or by the registry's recorded multibase.
|
|
20
|
+
* 1. **Reveal + commit**: rung 0 joins `updateKeys` (its hash stands
|
|
21
|
+
* committed since issuance, which is what makes the entry verify -- the
|
|
22
|
+
* ordinary ladder reveal) and `nextKeyHashes` extends with the NEW
|
|
23
|
+
* ordinary client's update- and staged-key hashes plus the replacement
|
|
24
|
+
* code's rung-0 hash.
|
|
25
|
+
* 2. **Add + retire**: signed by the new client's update key (revealed from
|
|
26
|
+
* the commit), this entry publishes the new client's verification methods
|
|
27
|
+
* and update key, removes the spent code's `keyAgreement` VM and its
|
|
28
|
+
* ladder VM (with every other standing credential's, by the relation
|
|
29
|
+
* asymmetry), publishes the replacement code's inventory, and drops the
|
|
30
|
+
* spent code's revealed rung and its hash -- so no recovery authority
|
|
31
|
+
* stands afterwards.
|
|
44
32
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
did: string;
|
|
52
|
-
keyAgreementKeyMultibase: string;
|
|
53
|
-
}): string;
|
|
54
|
-
/**
|
|
55
|
-
* The public halves of a recovery code as the document and log carry them:
|
|
56
|
-
* the X25519 key-agreement key published as the recovery VM, and the update
|
|
57
|
-
* key whose hash stands in `nextKeyHashes`.
|
|
58
|
-
*/
|
|
59
|
-
export interface RecoveryPublicKeys {
|
|
60
|
-
keyAgreementKeyMultibase: string;
|
|
61
|
-
updateKeyMultibase: string;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* The public halves a SPEND needs of the replacement code it publishes: the
|
|
65
|
-
* two above plus the code's ladder VM key, which the add-and-retire entry
|
|
66
|
-
* installs under `assertionMethod` and `capabilityDelegation`. A code is a
|
|
67
|
-
* standing unlock credential with a ladder (`decisions/0020`) and its bridge
|
|
68
|
-
* delegation is signed by that ladder's VM (`decisions/0019`), so a
|
|
69
|
-
* replacement published without the VM could neither sign its own bridge nor
|
|
70
|
-
* spend. `recoveryClientFromCode` produces all three.
|
|
33
|
+
* Both entries are written through the caller's store seam; the recovery
|
|
34
|
+
* continuation publishes ONLY `did.jsonl` (the delegation the record carries
|
|
35
|
+
* covers nothing else -- narrow scope preserves loudness), and hands back the
|
|
36
|
+
* final `webDoc` so the recovered session can republish `did.json` once it is
|
|
37
|
+
* the authorized controller. Every step is idempotent/resumable: re-running
|
|
38
|
+
* with the same key material converges without forking the log.
|
|
71
39
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
export declare class RecoveryKeyNotCommittedError extends Error {
|
|
81
|
-
constructor(message?: string);
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* The narrow store seam the recovery continuation writes through: a public
|
|
85
|
-
* read of the log and the delegated `did.jsonl` PUT. A subset of
|
|
86
|
-
* {@link WebvhIdStore}, so an app's remote-store class satisfies it too.
|
|
87
|
-
*/
|
|
88
|
-
export type RecoveryLogStore = Pick<WebvhIdStore, 'getIdResourceRaw' | 'putIdResource'>;
|
|
40
|
+
import type { DIDDoc, DIDLog } from '@interop/did-method-webvh';
|
|
41
|
+
import type { ClientWebvhUpdateKeys, WebvhEnrollmentKeys, WebvhIdStore } from '../webvh/didWebvh.js';
|
|
42
|
+
import type { ResourceLogPinStore } from '@interop/vh-resource-log';
|
|
43
|
+
import type { UnlockInventoryPart } from '../unlock/standingWebvh.js';
|
|
44
|
+
import type { AccountLogSigner } from '../webvh/accountEntry.js';
|
|
45
|
+
import type { RecoveryLogStore, RecoveryPublicKeys, ReplacementRecoveryPublicKeys } from './continuation.js';
|
|
46
|
+
export { RecoveryCredentialStandingError, RecoveryKeyNotCommittedError, recoveryVmId, retiredCredentialVmIdsFromLog } from './continuation.js';
|
|
47
|
+
export type { RecoveryLogStore, RecoveryPublicKeys, ReplacementRecoveryPublicKeys } from './continuation.js';
|
|
89
48
|
/**
|
|
90
49
|
* ISSUANCE: publishes a recovery code's split configuration into the
|
|
91
50
|
* document -- the code's `keyAgreement` verification method (an ordinary,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recoveryWebvh.d.ts","sourceRoot":"","sources":["../../src/recovery/recoveryWebvh.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"recoveryWebvh.d.ts","sourceRoot":"","sources":["../../src/recovery/recoveryWebvh.ts"],"names":[],"mappings":"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"}
|