@interop/wallet-core 0.62.0 → 0.66.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 +41 -16
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts +46 -26
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts.map +1 -1
- package/dist/clientAnnex/credentialAnchoredGenesis.js +91 -39
- package/dist/clientAnnex/credentialAnchoredGenesis.js.map +1 -1
- package/dist/clientAnnex/establish.d.ts +119 -35
- package/dist/clientAnnex/establish.d.ts.map +1 -1
- package/dist/clientAnnex/establish.js +227 -160
- package/dist/clientAnnex/establish.js.map +1 -1
- package/dist/clientAnnex/forget.d.ts +18 -8
- package/dist/clientAnnex/forget.d.ts.map +1 -1
- package/dist/clientAnnex/forget.js +37 -64
- package/dist/clientAnnex/forget.js.map +1 -1
- package/dist/clientAnnex/forgetLast.d.ts +85 -38
- package/dist/clientAnnex/forgetLast.d.ts.map +1 -1
- package/dist/clientAnnex/forgetLast.js +155 -98
- package/dist/clientAnnex/forgetLast.js.map +1 -1
- package/dist/clientAnnex/gc.d.ts +3 -2
- package/dist/clientAnnex/gc.d.ts.map +1 -1
- package/dist/clientAnnex/gc.js +16 -7
- package/dist/clientAnnex/gc.js.map +1 -1
- package/dist/clientAnnex/heal.d.ts +65 -14
- package/dist/clientAnnex/heal.d.ts.map +1 -1
- package/dist/clientAnnex/heal.js +397 -298
- package/dist/clientAnnex/heal.js.map +1 -1
- package/dist/clientAnnex/index.d.ts +23 -7
- package/dist/clientAnnex/index.d.ts.map +1 -1
- package/dist/clientAnnex/index.js +26 -7
- package/dist/clientAnnex/index.js.map +1 -1
- package/dist/clientAnnex/ladder.d.ts +58 -0
- package/dist/clientAnnex/ladder.d.ts.map +1 -1
- package/dist/clientAnnex/ladder.js +249 -41
- package/dist/clientAnnex/ladder.js.map +1 -1
- package/dist/clientAnnex/ladderAnchored.d.ts +148 -22
- package/dist/clientAnnex/ladderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/ladderAnchored.js +391 -346
- package/dist/clientAnnex/ladderAnchored.js.map +1 -1
- package/dist/clientAnnex/log.d.ts +237 -53
- package/dist/clientAnnex/log.d.ts.map +1 -1
- package/dist/clientAnnex/log.js +533 -198
- package/dist/clientAnnex/log.js.map +1 -1
- package/dist/clientAnnex/mend.d.ts +12 -6
- package/dist/clientAnnex/mend.d.ts.map +1 -1
- package/dist/clientAnnex/mend.js +44 -72
- package/dist/clientAnnex/mend.js.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts +6 -4
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.js +56 -35
- package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -1
- package/dist/clientAnnex/spaceCapability.d.ts +123 -0
- package/dist/clientAnnex/spaceCapability.d.ts.map +1 -0
- package/dist/clientAnnex/spaceCapability.js +152 -0
- package/dist/clientAnnex/spaceCapability.js.map +1 -0
- package/dist/clientAnnex/stages.d.ts +63 -0
- package/dist/clientAnnex/stages.d.ts.map +1 -0
- package/dist/clientAnnex/stages.js +64 -0
- package/dist/clientAnnex/stages.js.map +1 -0
- package/dist/clientAnnex/zcap.d.ts +1 -1
- package/dist/clientAnnex/zcap.d.ts.map +1 -1
- package/dist/clientAnnex/zcap.js +42 -35
- package/dist/clientAnnex/zcap.js.map +1 -1
- package/dist/clients/policy.d.ts +15 -1
- package/dist/clients/policy.d.ts.map +1 -1
- package/dist/clients/policy.js +12 -6
- package/dist/clients/policy.js.map +1 -1
- package/dist/clients/revocation.d.ts +18 -10
- package/dist/clients/revocation.d.ts.map +1 -1
- package/dist/clients/revocation.js +13 -5
- package/dist/clients/revocation.js.map +1 -1
- package/dist/clients/rosterPolicy.d.ts +10 -2
- package/dist/clients/rosterPolicy.d.ts.map +1 -1
- package/dist/clients/rosterPolicy.js +41 -24
- package/dist/clients/rosterPolicy.js.map +1 -1
- package/dist/descriptors/acquire.d.ts.map +1 -1
- package/dist/descriptors/acquire.js +6 -23
- package/dist/descriptors/acquire.js.map +1 -1
- package/dist/descriptors/cipher.d.ts.map +1 -1
- package/dist/descriptors/cipher.js +5 -0
- package/dist/descriptors/cipher.js.map +1 -1
- package/dist/descriptors/errors.d.ts +43 -0
- package/dist/descriptors/errors.d.ts.map +1 -0
- package/dist/descriptors/errors.js +45 -0
- package/dist/descriptors/errors.js.map +1 -0
- package/dist/descriptors/index.d.ts +5 -0
- package/dist/descriptors/index.d.ts.map +1 -1
- package/dist/descriptors/index.js +5 -0
- package/dist/descriptors/index.js.map +1 -1
- package/dist/enrollment/enrollment.d.ts +37 -10
- package/dist/enrollment/enrollment.d.ts.map +1 -1
- package/dist/enrollment/enrollment.js +52 -15
- package/dist/enrollment/enrollment.js.map +1 -1
- package/dist/genesis/accountGenesis.d.ts +42 -11
- package/dist/genesis/accountGenesis.d.ts.map +1 -1
- package/dist/genesis/accountGenesis.js +80 -22
- package/dist/genesis/accountGenesis.js.map +1 -1
- package/dist/genesis/index.d.ts +3 -1
- package/dist/genesis/index.d.ts.map +1 -1
- package/dist/genesis/index.js +3 -1
- package/dist/genesis/index.js.map +1 -1
- package/dist/identity/agents.d.ts +17 -1
- package/dist/identity/agents.d.ts.map +1 -1
- package/dist/identity/agents.js +23 -7
- package/dist/identity/agents.js.map +1 -1
- package/dist/identity/index.d.ts +3 -1
- package/dist/identity/index.d.ts.map +1 -1
- package/dist/identity/index.js +3 -1
- package/dist/identity/index.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/keyring/index.d.ts +2 -1
- package/dist/keyring/index.d.ts.map +1 -1
- package/dist/keyring/index.js +2 -1
- package/dist/keyring/index.js.map +1 -1
- package/dist/keyring/record.d.ts.map +1 -1
- package/dist/keyring/record.js +3 -6
- package/dist/keyring/record.js.map +1 -1
- package/dist/keyring/unlockSpace.d.ts +14 -5
- package/dist/keyring/unlockSpace.d.ts.map +1 -1
- package/dist/keyring/unlockSpace.js +31 -36
- package/dist/keyring/unlockSpace.js.map +1 -1
- package/dist/keys/index.d.ts +22 -8
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +20 -6
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/rosterLogStore.d.ts +15 -12
- package/dist/keys/rosterLogStore.d.ts.map +1 -1
- package/dist/keys/rosterLogStore.js +21 -16
- package/dist/keys/rosterLogStore.js.map +1 -1
- package/dist/keys/rosterStore.d.ts +3 -6
- package/dist/keys/rosterStore.d.ts.map +1 -1
- package/dist/keys/rosterStore.js +10 -9
- package/dist/keys/rosterStore.js.map +1 -1
- package/dist/keys/spaceEpochs.d.ts.map +1 -1
- package/dist/keys/spaceEpochs.js +2 -3
- package/dist/keys/spaceEpochs.js.map +1 -1
- package/dist/keys/userKeyCascade.d.ts +8 -5
- package/dist/keys/userKeyCascade.d.ts.map +1 -1
- package/dist/keys/userKeyCascade.js +7 -6
- package/dist/keys/userKeyCascade.js.map +1 -1
- package/dist/keys/userKeyRoster.d.ts +95 -8
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +278 -35
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/keys/userKeyRosterCascade.d.ts +117 -16
- package/dist/keys/userKeyRosterCascade.d.ts.map +1 -1
- package/dist/keys/userKeyRosterCascade.js +184 -43
- package/dist/keys/userKeyRosterCascade.js.map +1 -1
- package/dist/keys/wasLabelsStore.d.ts +9 -2
- package/dist/keys/wasLabelsStore.d.ts.map +1 -1
- package/dist/keys/wasLabelsStore.js +14 -6
- package/dist/keys/wasLabelsStore.js.map +1 -1
- package/dist/log.d.ts +7 -2
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +6 -1
- package/dist/log.js.map +1 -1
- package/dist/recovery/index.d.ts +13 -9
- package/dist/recovery/index.d.ts.map +1 -1
- package/dist/recovery/index.js +12 -8
- package/dist/recovery/index.js.map +1 -1
- package/dist/recovery/recoveryCode.d.ts +27 -7
- package/dist/recovery/recoveryCode.d.ts.map +1 -1
- package/dist/recovery/recoveryCode.js +18 -6
- package/dist/recovery/recoveryCode.js.map +1 -1
- package/dist/recovery/recoveryDelegation.d.ts +23 -0
- package/dist/recovery/recoveryDelegation.d.ts.map +1 -1
- package/dist/recovery/recoveryDelegation.js +66 -46
- package/dist/recovery/recoveryDelegation.js.map +1 -1
- package/dist/recovery/recoveryWebvh.d.ts +75 -63
- package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
- package/dist/recovery/recoveryWebvh.js +127 -116
- package/dist/recovery/recoveryWebvh.js.map +1 -1
- package/dist/request/appKey.d.ts +35 -1
- package/dist/request/appKey.d.ts.map +1 -1
- package/dist/request/appKey.js +29 -10
- package/dist/request/appKey.js.map +1 -1
- package/dist/request/classify.d.ts +32 -8
- package/dist/request/classify.d.ts.map +1 -1
- package/dist/request/classify.js +39 -14
- package/dist/request/classify.js.map +1 -1
- package/dist/request/ephemeralExchange.d.ts +1 -6
- package/dist/request/ephemeralExchange.d.ts.map +1 -1
- package/dist/request/ephemeralExchange.js.map +1 -1
- package/dist/request/onboarding.d.ts.map +1 -1
- package/dist/request/onboarding.js +2 -2
- package/dist/request/onboarding.js.map +1 -1
- package/dist/request/parse.d.ts.map +1 -1
- package/dist/request/parse.js +2 -3
- package/dist/request/parse.js.map +1 -1
- package/dist/resourceLog/controller.d.ts +34 -12
- package/dist/resourceLog/controller.d.ts.map +1 -1
- package/dist/resourceLog/controller.js +79 -86
- package/dist/resourceLog/controller.js.map +1 -1
- package/dist/resourceLog/document.d.ts +182 -0
- package/dist/resourceLog/document.d.ts.map +1 -0
- package/dist/resourceLog/document.js +159 -0
- package/dist/resourceLog/document.js.map +1 -0
- package/dist/resourceLog/errors.d.ts +47 -8
- package/dist/resourceLog/errors.d.ts.map +1 -1
- package/dist/resourceLog/errors.js +54 -8
- package/dist/resourceLog/errors.js.map +1 -1
- package/dist/resourceLog/index.d.ts +7 -3
- package/dist/resourceLog/index.d.ts.map +1 -1
- package/dist/resourceLog/index.js +7 -3
- package/dist/resourceLog/index.js.map +1 -1
- package/dist/resourceLog/ladderRungs.d.ts +35 -0
- package/dist/resourceLog/ladderRungs.d.ts.map +1 -0
- package/dist/resourceLog/ladderRungs.js +352 -0
- package/dist/resourceLog/ladderRungs.js.map +1 -0
- package/dist/resourceLog/license.d.ts +42 -17
- package/dist/resourceLog/license.d.ts.map +1 -1
- package/dist/resourceLog/license.js +38 -24
- package/dist/resourceLog/license.js.map +1 -1
- package/dist/space/activity.d.ts +15 -15
- package/dist/space/activity.d.ts.map +1 -1
- package/dist/space/activity.js +15 -15
- package/dist/space/activity.js.map +1 -1
- package/dist/space/collections.d.ts +11 -0
- package/dist/space/collections.d.ts.map +1 -1
- package/dist/space/collections.js +13 -0
- package/dist/space/collections.js.map +1 -1
- package/dist/space/deleteSpace.d.ts +28 -0
- package/dist/space/deleteSpace.d.ts.map +1 -0
- package/dist/space/deleteSpace.js +44 -0
- package/dist/space/deleteSpace.js.map +1 -0
- package/dist/space/errors.d.ts.map +1 -1
- package/dist/space/errors.js +0 -1
- package/dist/space/errors.js.map +1 -1
- package/dist/space/index.d.ts +6 -0
- package/dist/space/index.d.ts.map +1 -1
- package/dist/space/index.js +6 -0
- package/dist/space/index.js.map +1 -1
- package/dist/space/plaintextCollection.d.ts +43 -0
- package/dist/space/plaintextCollection.d.ts.map +1 -0
- package/dist/space/plaintextCollection.js +17 -0
- package/dist/space/plaintextCollection.js.map +1 -0
- package/dist/stages.d.ts +23 -0
- package/dist/stages.d.ts.map +1 -0
- package/dist/stages.js +23 -0
- package/dist/stages.js.map +1 -0
- package/dist/sync/index.d.ts +7 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +7 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/push.js +4 -4
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/remint.js +2 -2
- package/dist/sync/remint.js.map +1 -1
- package/dist/sync/types.d.ts +41 -1
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/sync/types.js +47 -1
- package/dist/sync/types.js.map +1 -1
- package/dist/unlock/index.d.ts +5 -1
- package/dist/unlock/index.d.ts.map +1 -1
- package/dist/unlock/index.js +5 -1
- package/dist/unlock/index.js.map +1 -1
- package/dist/unlock/retire.d.ts +35 -7
- package/dist/unlock/retire.d.ts.map +1 -1
- package/dist/unlock/retire.js +52 -14
- package/dist/unlock/retire.js.map +1 -1
- package/dist/unlock/standingClient.d.ts.map +1 -1
- package/dist/unlock/standingClient.js +5 -1
- package/dist/unlock/standingClient.js.map +1 -1
- package/dist/unlock/standingWebvh.d.ts +217 -35
- package/dist/unlock/standingWebvh.d.ts.map +1 -1
- package/dist/unlock/standingWebvh.js +469 -210
- package/dist/unlock/standingWebvh.js.map +1 -1
- package/dist/webvh/accountEntry.d.ts +146 -0
- package/dist/webvh/accountEntry.d.ts.map +1 -0
- package/dist/webvh/accountEntry.js +239 -0
- package/dist/webvh/accountEntry.js.map +1 -0
- package/dist/webvh/didWeb.d.ts +12 -7
- package/dist/webvh/didWeb.d.ts.map +1 -1
- package/dist/webvh/didWeb.js +2 -2
- package/dist/webvh/didWeb.js.map +1 -1
- package/dist/webvh/didWebProjection.d.ts +164 -0
- package/dist/webvh/didWebProjection.d.ts.map +1 -0
- package/dist/webvh/didWebProjection.js +230 -0
- package/dist/webvh/didWebProjection.js.map +1 -0
- package/dist/webvh/didWebvh.d.ts +275 -136
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +307 -340
- package/dist/webvh/didWebvh.js.map +1 -1
- package/dist/webvh/enrollClient.d.ts +65 -0
- package/dist/webvh/enrollClient.d.ts.map +1 -0
- package/dist/webvh/enrollClient.js +172 -0
- package/dist/webvh/enrollClient.js.map +1 -0
- package/dist/webvh/index.d.ts +37 -12
- package/dist/webvh/index.d.ts.map +1 -1
- package/dist/webvh/index.js +33 -10
- package/dist/webvh/index.js.map +1 -1
- package/dist/webvh/listClients.d.ts +1 -35
- package/dist/webvh/listClients.d.ts.map +1 -1
- package/dist/webvh/listClients.js +2 -30
- package/dist/webvh/listClients.js.map +1 -1
- package/dist/webvh/revokeClient.d.ts +41 -11
- package/dist/webvh/revokeClient.d.ts.map +1 -1
- package/dist/webvh/revokeClient.js +99 -48
- package/dist/webvh/revokeClient.js.map +1 -1
- package/dist/webvh/standingZcap.d.ts +61 -14
- package/dist/webvh/standingZcap.d.ts.map +1 -1
- package/dist/webvh/standingZcap.js +91 -0
- package/dist/webvh/standingZcap.js.map +1 -1
- package/dist/webvh/verifyLog.d.ts +59 -5
- package/dist/webvh/verifyLog.d.ts.map +1 -1
- package/dist/webvh/verifyLog.js +76 -11
- package/dist/webvh/verifyLog.js.map +1 -1
- package/dist/webvh/wasIdStore.d.ts +8 -8
- package/dist/webvh/wasIdStore.d.ts.map +1 -1
- package/dist/webvh/wasIdStore.js +39 -14
- package/dist/webvh/wasIdStore.js.map +1 -1
- package/dist/webvh/zcap.d.ts +14 -1
- package/dist/webvh/zcap.d.ts.map +1 -1
- package/dist/webvh/zcap.js +3 -27
- package/dist/webvh/zcap.js.map +1 -1
- package/package.json +2 -2
- package/dist/webvh/keyAgreement.d.ts +0 -97
- package/dist/webvh/keyAgreement.d.ts.map +0 -1
- package/dist/webvh/keyAgreement.js +0 -71
- package/dist/webvh/keyAgreement.js.map +0 -1
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
* whole document inventory out; the last enrolled client refuses
|
|
39
39
|
* ({@link LastEnrolledClientForgetError}).
|
|
40
40
|
* - {@link strikeLadderVmWebvh} / {@link installLadderVmWebvh} /
|
|
41
|
-
*
|
|
41
|
+
* `forgetLastWebvhClient` -- the entries of the LAST enrolled
|
|
42
42
|
* client's forget (decision 0004's 2026-08-19 amendment): the credential's
|
|
43
43
|
* own ladder VM struck and then reinstalled while the client stands (the
|
|
44
44
|
* pair supplying the transition's inventory-changing document version),
|
|
@@ -53,12 +53,14 @@
|
|
|
53
53
|
* from durable state alone, on the recovery continuation's pattern.
|
|
54
54
|
*/
|
|
55
55
|
import { deriveNextKeyHash, updateDID } from '@interop/did-method-webvh';
|
|
56
|
-
import { assertCanonicalClientKeys,
|
|
56
|
+
import { assertCanonicalClientKeys, backfillKeyMapWebvhBlock, concludeWithPublishedLog, createLadderAnchoredWebvhLog, didWebvhControllerTemplate, genesisNextKeyHashes, ladderVerificationMethod, markedVerificationMethodPair, pinOfLog, publishEntryPinned, publishWebvhLog, readPublishedLog, readPublishedLogOrThrow, servedHead, updateKeySigner, withLogConflictRetry, writeKeysJson } from '../webvh/didWebvh.js';
|
|
57
|
+
import { putDidWebProjection } from '../webvh/didWebProjection.js';
|
|
57
58
|
import { accountLogPinId } from '../webvh/verifyLog.js';
|
|
58
|
-
import { ladderVmIds } from '../
|
|
59
|
+
import { ladderVmIds, relationIds } from '../resourceLog/document.js';
|
|
59
60
|
import { clientRemovalFields, clientRemovalTarget } from '../webvh/revokeClient.js';
|
|
60
|
-
import {
|
|
61
|
+
import { unlockKeyVerificationMethod } from '../unlock/standingWebvh.js';
|
|
61
62
|
import { attributeLadderRung, ladderRung, ladderVmKeyMultibase } from './ladder.js';
|
|
63
|
+
import { signAccountEntry } from '../webvh/accountEntry.js';
|
|
62
64
|
/**
|
|
63
65
|
* LADDER-ANCHORED GENESIS: assembles the one-entry did:webvh log of an account
|
|
64
66
|
* with zero enrolled clients, anchored on the minting credential's
|
|
@@ -94,7 +96,7 @@ import { attributeLadderRung, ladderRung, ladderVmKeyMultibase } from './ladder.
|
|
|
94
96
|
* @param options.ladderSeed {Uint8Array} the credential's ladder seed
|
|
95
97
|
* @param options.keyAgreement {UnlockKeyAgreementPublication} the
|
|
96
98
|
* credential's key-agreement publication (commitment or verbatim)
|
|
97
|
-
* @returns {Promise<
|
|
99
|
+
* @returns {Promise<CreatedWebvhLog>}
|
|
98
100
|
*/
|
|
99
101
|
export async function createLadderAnchoredAccountLog({ wasServerUrl, spaceId, didWebKeys, ladderSeed, keyAgreement }) {
|
|
100
102
|
const rung0 = await ladderRung({ ladderSeed, index: 0 });
|
|
@@ -145,6 +147,9 @@ export async function createLadderAnchoredAccountLog({ wasServerUrl, spaceId, di
|
|
|
145
147
|
* the wallet keeps a KMS; folded into the CREATE path only (see the
|
|
146
148
|
* adoption note in the body), which also records the minted DID into
|
|
147
149
|
* keys.json's webvh block as the enrolled-client ensure does
|
|
150
|
+
* @param [options.keysJsonEtag] {string} the ETag the KMS-authentication
|
|
151
|
+
* stage's own `keys.json` write returned, carried as the `ifMatch` of that
|
|
152
|
+
* rewrite
|
|
148
153
|
* @param options.ladderSeed {Uint8Array} the credential's ladder seed
|
|
149
154
|
* @param options.keyAgreement {UnlockKeyAgreementPublication} the
|
|
150
155
|
* credential's key-agreement publication (commitment or verbatim)
|
|
@@ -154,7 +159,18 @@ export async function createLadderAnchoredAccountLog({ wasServerUrl, spaceId, di
|
|
|
154
159
|
* @param [options.pinStore] {ResourceLogPinStore} this client's chain-head
|
|
155
160
|
* pins; the account log's slot is keyed by `accountLogPinId` over the
|
|
156
161
|
* `spaceId` above
|
|
157
|
-
* @returns {Promise<{ did: string
|
|
162
|
+
* @returns {Promise<{ did: string, published: PublishedWebvhLog,
|
|
163
|
+
* logMinted: boolean }>} `published` is the head this stage stands on --
|
|
164
|
+
* the served one on the adopt branch, the minted one paired with its
|
|
165
|
+
* create PUT's ETag on the create branch -- so the stage after it can build
|
|
166
|
+
* on this head instead of re-reading the log this one just read or wrote.
|
|
167
|
+
* Its `etag` is absent against a backend that serves none, which is one
|
|
168
|
+
* case a later stage must still read for itself. `logMinted` says WHICH
|
|
169
|
+
* branch produced it, which a later stage needs before reusing it: a
|
|
170
|
+
* minted head is one no other writer could have held a moment ago, while
|
|
171
|
+
* an adopted head is a snapshot of an account other clients are free to
|
|
172
|
+
* write to, and the parts of it no ETag protects (the document's
|
|
173
|
+
* completion tests) can be stale by the time a later stage reads them
|
|
158
174
|
*/
|
|
159
175
|
export async function ensureLadderAnchoredDidWebvh(options) {
|
|
160
176
|
return withLogConflictRetry(() => ensureLadderAnchoredDidWebvhOnce(options));
|
|
@@ -164,9 +180,10 @@ export async function ensureLadderAnchoredDidWebvh(options) {
|
|
|
164
180
|
* conflict retry.
|
|
165
181
|
*
|
|
166
182
|
* @param options {object} see {@link ensureLadderAnchoredDidWebvh}
|
|
167
|
-
* @returns {Promise<{ did: string
|
|
183
|
+
* @returns {Promise<{ did: string, published: PublishedWebvhLog,
|
|
184
|
+
* logMinted: boolean }>}
|
|
168
185
|
*/
|
|
169
|
-
async function ensureLadderAnchoredDidWebvhOnce({ idStore, wasServerUrl, spaceId, didWebKeys, ladderSeed, keyAgreement, expectedDid, pinStore }) {
|
|
186
|
+
async function ensureLadderAnchoredDidWebvhOnce({ idStore, wasServerUrl, spaceId, didWebKeys, keysJsonEtag, ladderSeed, keyAgreement, expectedDid, pinStore }) {
|
|
170
187
|
const logId = accountLogPinId({ spaceId });
|
|
171
188
|
const published = await readPublishedLog({
|
|
172
189
|
idStore,
|
|
@@ -184,9 +201,21 @@ async function ensureLadderAnchoredDidWebvhOnce({ idStore, wasServerUrl, spaceId
|
|
|
184
201
|
// edits it, and a log published without the KMS convenience key is
|
|
185
202
|
// healed by a later login, not here.
|
|
186
203
|
await attributeLadderRung({ ladderSeed, published });
|
|
187
|
-
// Heals a
|
|
204
|
+
// Heals a keys.json left without its `webvh` block by a run torn between
|
|
205
|
+
// the genesis entry and the rewrite: the served map's own binding gains
|
|
206
|
+
// the DID this log resolves to. Gated on this run keeping a KMS, so a
|
|
207
|
+
// KMS-less wallet spends no read on a resource it never writes.
|
|
208
|
+
if (didWebKeys) {
|
|
209
|
+
await backfillKeyMapWebvhBlock({ idStore, did: published.did });
|
|
210
|
+
}
|
|
211
|
+
// Heals a did.json left lagging by a torn earlier publish of this
|
|
212
|
+
// controller-invoking genesis; a lag left by a later ladder-signed entry
|
|
213
|
+
// is `ensureDidWebProjection`'s to mend.
|
|
188
214
|
const { did } = await concludeWithPublishedLog({ idStore, published });
|
|
189
|
-
|
|
215
|
+
// The served head verbatim: the projection PUT above touches no log, so
|
|
216
|
+
// the read's own ETag is still the log's validator. `logMinted: false`
|
|
217
|
+
// marks it as a snapshot of an account other clients may be writing to.
|
|
218
|
+
return { did, published, logMinted: false };
|
|
190
219
|
}
|
|
191
220
|
const created = await createLadderAnchoredAccountLog({
|
|
192
221
|
wasServerUrl,
|
|
@@ -195,7 +224,7 @@ async function ensureLadderAnchoredDidWebvhOnce({ idStore, wasServerUrl, spaceId
|
|
|
195
224
|
ladderSeed,
|
|
196
225
|
keyAgreement
|
|
197
226
|
});
|
|
198
|
-
await publishWebvhLog({
|
|
227
|
+
const written = await publishWebvhLog({
|
|
199
228
|
idStore,
|
|
200
229
|
log: created.log,
|
|
201
230
|
webDoc: created.webDoc,
|
|
@@ -216,26 +245,86 @@ async function ensureLadderAnchoredDidWebvhOnce({ idStore, wasServerUrl, spaceId
|
|
|
216
245
|
await writeKeysJson({
|
|
217
246
|
idStore,
|
|
218
247
|
didWebKeys,
|
|
219
|
-
webvh: { did: created.did }
|
|
248
|
+
webvh: { did: created.did },
|
|
249
|
+
...(keysJsonEtag !== undefined && { ifMatch: keysJsonEtag })
|
|
220
250
|
});
|
|
221
251
|
}
|
|
222
|
-
|
|
252
|
+
// The head this run just wrote, assembled from what `createDID` already
|
|
253
|
+
// resolved plus the create PUT's own validator -- no second read, and no
|
|
254
|
+
// second resolve.
|
|
255
|
+
return {
|
|
256
|
+
did: created.did,
|
|
257
|
+
logMinted: true,
|
|
258
|
+
published: {
|
|
259
|
+
log: created.log,
|
|
260
|
+
did: created.did,
|
|
261
|
+
doc: created.doc,
|
|
262
|
+
updateKeys: created.updateKeys,
|
|
263
|
+
nextKeyHashes: created.nextKeyHashes,
|
|
264
|
+
...(written.etag !== undefined ? { etag: written.etag } : {})
|
|
265
|
+
}
|
|
266
|
+
};
|
|
223
267
|
}
|
|
224
268
|
/**
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
269
|
+
* ONE LADDER-SIGNED ACCOUNT-LOG ENTRY: the account-entry seam
|
|
270
|
+
* ({@link signAccountEntry}) on its ladder arm, narrowed to the outcome the
|
|
271
|
+
* annex's ceremonies read. The seam owns the nine steps -- the pinned read,
|
|
272
|
+
* the rung attribution, the rung's carry-over hash, the carry-over
|
|
273
|
+
* precondition, the update-key signer, the self-reveal union into
|
|
274
|
+
* `updateKeys`, the carry-over union into `nextKeyHashes`, the conditional
|
|
275
|
+
* publish (`did.jsonl` alone, the bridge's whole reach), and the pin advance.
|
|
276
|
+
*
|
|
277
|
+
* No conflict retry of its own: a lost compare-and-swap surfaces as a
|
|
278
|
+
* `WebvhLogConflictError` for the caller's {@link withLogConflictRetry} to
|
|
279
|
+
* re-run, which is what re-attributes the rung and climbs to the winner's
|
|
280
|
+
* committed one (the retry-up-the-ladder resolution).
|
|
230
281
|
*
|
|
231
282
|
* @param options {object}
|
|
232
|
-
* @param options.store {UnlockLogStore}
|
|
233
|
-
* @param options.
|
|
234
|
-
* @param [options.
|
|
235
|
-
*
|
|
283
|
+
* @param options.store {UnlockLogStore} public log read + delegated PUT
|
|
284
|
+
* @param options.ladderSeed {Uint8Array} the credential's ladder seed
|
|
285
|
+
* @param [options.expectedDid] {string} the account DID the log must resolve
|
|
286
|
+
* to, from the caller's stored account pointer
|
|
287
|
+
* @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
|
|
288
|
+
* pins: the read is checked against the pinned head, and the pin advances
|
|
289
|
+
* to the head this entry publishes
|
|
290
|
+
* @param [options.logId] {string} the account log's pin slot
|
|
291
|
+
* (`accountLogPinId({ spaceId })`); required whenever a `pinStore` is
|
|
292
|
+
* supplied
|
|
293
|
+
* @param [options.skip] {function} `(published) => boolean` -- run on the
|
|
294
|
+
* read, before any attribution; `true` returns `skipped` with nothing
|
|
295
|
+
* published
|
|
296
|
+
* @param options.build {function}
|
|
297
|
+
* `({ published, rung, state }) => LadderSignedEntry | undefined` -- the
|
|
298
|
+
* entry's own members, or `undefined` to decline
|
|
299
|
+
* @param [options.beforePublish] {function} `({ updated }) => Promise<void>`
|
|
300
|
+
* -- the pre-publish seam, for the ceremonies that PUT their post-entry
|
|
301
|
+
* `did:web` projection while the authority they are about to end can still
|
|
302
|
+
* write it. See {@link signAccountEntry}
|
|
303
|
+
* @returns {Promise<LadderSignedEntryOutcome>}
|
|
236
304
|
*/
|
|
237
|
-
async function
|
|
238
|
-
await
|
|
305
|
+
export async function ladderSignedAccountEntry({ store, ladderSeed, expectedDid, pinStore, logId, skip, build, beforePublish }) {
|
|
306
|
+
const outcome = await signAccountEntry({
|
|
307
|
+
idStore: store,
|
|
308
|
+
signer: { kind: 'ladder', ladderSeed },
|
|
309
|
+
build: ({ published, rung, state }) => build({ published, rung: rung, state: state }),
|
|
310
|
+
...(skip ? { skip } : {}),
|
|
311
|
+
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
312
|
+
...(pinStore ? { pinStore } : {}),
|
|
313
|
+
...(logId !== undefined ? { logId } : {}),
|
|
314
|
+
missingMessage: 'did:webvh: did.jsonl is missing; nothing to enroll into.',
|
|
315
|
+
...(beforePublish ? { beforePublish } : {})
|
|
316
|
+
});
|
|
317
|
+
if (outcome.skipped) {
|
|
318
|
+
return { skipped: true, published: outcome.published };
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
skipped: false,
|
|
322
|
+
published: outcome.published,
|
|
323
|
+
rung: outcome.rung,
|
|
324
|
+
rungHash: outcome.rungHash,
|
|
325
|
+
state: outcome.state,
|
|
326
|
+
...(outcome.updated ? { updated: outcome.updated } : {})
|
|
327
|
+
};
|
|
239
328
|
}
|
|
240
329
|
/**
|
|
241
330
|
* SELF-ENROLLMENT (run by the credential-derived client through the delegated
|
|
@@ -406,83 +495,63 @@ export class BuiltOnHeadNotReachedError extends Error {
|
|
|
406
495
|
* @returns {Promise<{ did: string, webDoc?: object, committed: boolean }>}
|
|
407
496
|
*/
|
|
408
497
|
async function selfEnrollWebvhClientOnce({ store, ladderSeed, newClientKeys, newClientUpdateSeeds, onCommitted, builtOnHead, expectedDid, pinStore, logId }) {
|
|
409
|
-
//
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
const
|
|
413
|
-
...(pinStore ? { pinStore } : {}),
|
|
414
|
-
...(logId !== undefined ? { logId } : {})
|
|
415
|
-
};
|
|
416
|
-
let published = await readLogOrThrow({
|
|
498
|
+
// The reveal-and-commit entry, through the shared preamble and postamble.
|
|
499
|
+
// It is skipped when a torn earlier run already published it (the rung
|
|
500
|
+
// revealed AND every needed hash committed).
|
|
501
|
+
const reveal = await ladderSignedAccountEntry({
|
|
417
502
|
store,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
const updated = await updateDID({
|
|
455
|
-
log: published.log,
|
|
456
|
-
signer,
|
|
457
|
-
alsoKnownAsWeb: true,
|
|
458
|
-
updateKeys: [...new Set([...published.updateKeys, rung.keyMultibase])],
|
|
459
|
-
// The spent rung's own hash is kept through this entry (so a resumed
|
|
460
|
-
// commit can re-state the revealed key); the add entry drops it, while
|
|
461
|
-
// the next rung's hash stays as the credential's standing commitment.
|
|
462
|
-
nextKeyHashes: [
|
|
463
|
-
...new Set([
|
|
464
|
-
...published.nextKeyHashes,
|
|
465
|
-
rungHash,
|
|
466
|
-
newUpdateHash,
|
|
467
|
-
newStagedHash,
|
|
468
|
-
nextRungHash
|
|
469
|
-
])
|
|
470
|
-
]
|
|
471
|
-
});
|
|
472
|
-
await publishLogOnly({ store, log: updated.log, ifMatch: published.etag });
|
|
473
|
-
// Advance the pin to what the reveal entry just published, so the re-read
|
|
474
|
-
// below (and any read after a tear here) refuses a host that rolls the
|
|
475
|
-
// log back behind it.
|
|
476
|
-
if (pinStore && logId !== undefined) {
|
|
477
|
-
await pinStore.write({ logId, pin: pinOfLog(updated.log) });
|
|
503
|
+
ladderSeed,
|
|
504
|
+
expectedDid,
|
|
505
|
+
pinStore,
|
|
506
|
+
logId,
|
|
507
|
+
skip: read => {
|
|
508
|
+
// The resume marker, checked before anything else -- the completion
|
|
509
|
+
// check included, so a truncated served log is refused rather than read
|
|
510
|
+
// as "not complete yet" and rebuilt over.
|
|
511
|
+
if (builtOnHead) {
|
|
512
|
+
const genesisScid = read.log[0]?.parameters.scid ?? '';
|
|
513
|
+
const reached = read.log.some(entry => entry.versionId === builtOnHead.versionId);
|
|
514
|
+
if (genesisScid !== builtOnHead.scid || !reached) {
|
|
515
|
+
throw new BuiltOnHeadNotReachedError({ builtOnHead });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// Already complete (a torn earlier run finished the add entry): the new
|
|
519
|
+
// client's update key is authorized, which only the add entry writes.
|
|
520
|
+
// The seam is deliberately NOT entered on this path -- nothing is about
|
|
521
|
+
// to be published, so there is no pivot to persist ahead of.
|
|
522
|
+
return read.updateKeys.includes(newClientKeys.updateKeyMultibase);
|
|
523
|
+
},
|
|
524
|
+
build: async ({ published: read, rung, state }) => {
|
|
525
|
+
const nextRung = await ladderRung({ ladderSeed, index: rung.index + 1 });
|
|
526
|
+
const newUpdateHash = await deriveNextKeyHash(newClientKeys.updateKeyMultibase);
|
|
527
|
+
const newStagedHash = await deriveNextKeyHash(newClientKeys.stagedUpdateKeyMultibase);
|
|
528
|
+
const nextRungHash = await deriveNextKeyHash(nextRung.keyMultibase);
|
|
529
|
+
const committed = [newUpdateHash, newStagedHash, nextRungHash].every(hash => read.nextKeyHashes.includes(hash));
|
|
530
|
+
if (state === 'revealed' && committed) {
|
|
531
|
+
return undefined;
|
|
532
|
+
}
|
|
533
|
+
// The spent rung's own hash is kept through this entry by the shared
|
|
534
|
+
// carry-over union (so a resumed commit can re-state the revealed key);
|
|
535
|
+
// the add entry drops it, while the next rung's hash stays as the
|
|
536
|
+
// credential's standing commitment. The three land after it, in the
|
|
537
|
+
// append order `decisions/0007` ratifies.
|
|
538
|
+
return { commitHashes: [newUpdateHash, newStagedHash, nextRungHash] };
|
|
478
539
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
expectedDid: published.did,
|
|
483
|
-
...pinned
|
|
484
|
-
});
|
|
540
|
+
});
|
|
541
|
+
if (reveal.skipped) {
|
|
542
|
+
return { did: reveal.published.did, committed: false };
|
|
485
543
|
}
|
|
544
|
+
const { rung, rungHash } = reveal;
|
|
545
|
+
// The same account the reveal entry just extended, under the same pin.
|
|
546
|
+
const published = reveal.updated
|
|
547
|
+
? await readPublishedLogOrThrow({
|
|
548
|
+
idStore: store,
|
|
549
|
+
expectedDid: reveal.published.did,
|
|
550
|
+
pinStore,
|
|
551
|
+
logId,
|
|
552
|
+
missingMessage: 'did:webvh: did.jsonl is missing; nothing to enroll into.'
|
|
553
|
+
})
|
|
554
|
+
: reveal.published;
|
|
486
555
|
// The persist-before-publish seam: the pending client-key record is
|
|
487
556
|
// persisted client-local HERE, on the head the add entry is about to be
|
|
488
557
|
// built on, before that entry -- the ceremony's pivot -- publishes a client
|
|
@@ -536,12 +605,13 @@ async function selfEnrollWebvhClientOnce({ store, ladderSeed, newClientKeys, new
|
|
|
536
605
|
});
|
|
537
606
|
// Conditional on the read this entry was built on: the re-read above when
|
|
538
607
|
// the commit entry ran here, the first read when it was skipped.
|
|
539
|
-
await
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
608
|
+
await publishEntryPinned({
|
|
609
|
+
store,
|
|
610
|
+
log: updated.log,
|
|
611
|
+
ifMatch: published.etag,
|
|
612
|
+
pinStore,
|
|
613
|
+
logId
|
|
614
|
+
});
|
|
545
615
|
return { did: updated.did, webDoc: updated.webDoc, committed: true };
|
|
546
616
|
}
|
|
547
617
|
/**
|
|
@@ -605,6 +675,13 @@ export class LastEnrolledClientForgetError extends Error {
|
|
|
605
675
|
* @param options {object}
|
|
606
676
|
* @param options.store {UnlockLogStore} the credential's delegated
|
|
607
677
|
* `did.jsonl` bridge store
|
|
678
|
+
* @param [options.projectionStore] {object} an `id`-collection store the
|
|
679
|
+
* FORGETTING client can still write through (its own root-invoking store):
|
|
680
|
+
* the post-removal `did:web` projection is PUT through it immediately
|
|
681
|
+
* before the removal entry publishes, and only when this run publishes that
|
|
682
|
+
* entry. See {@link clientForgetEntryOnce} for the ordering rationale.
|
|
683
|
+
* Omitted, `did.json` keeps naming the forgotten client until some later
|
|
684
|
+
* writer runs `ensureDidWebProjection`
|
|
608
685
|
* @param options.ladderSeed {Uint8Array} the credential's ladder seed
|
|
609
686
|
* @param options.forgottenClient {RevokedClientKeys} this client's public
|
|
610
687
|
* halves; an `updateKeyMultibase` the log does not authorize (stale, or the
|
|
@@ -626,120 +703,130 @@ export class LastEnrolledClientForgetError extends Error {
|
|
|
626
703
|
* on the idempotent no-op path)
|
|
627
704
|
*/
|
|
628
705
|
export async function forgetWebvhClient(options) {
|
|
629
|
-
return withLogConflictRetry(() => clientForgetEntryOnce({ ...options,
|
|
706
|
+
return withLogConflictRetry(() => clientForgetEntryOnce({ ...options, assertRemovable: assertNotLastClient }));
|
|
630
707
|
}
|
|
631
708
|
/**
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
* the
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
* ladder anchor. Run only from the composed ceremony
|
|
640
|
-
* (`forgetLastEnrolledClient`), which sequences the install entry and the
|
|
641
|
-
* delegation revocations before it.
|
|
709
|
+
* The plain forget's removability invariant: `capabilityInvocation` lists
|
|
710
|
+
* exactly the enrolled clients' signing keys (a recovery code's key is
|
|
711
|
+
* `keyAgreement`-only and the KMS convenience key `authentication`-only), so
|
|
712
|
+
* the forgotten client standing alone there means removing it strands the
|
|
713
|
+
* account. The transition ceremony supplies its own invariant instead
|
|
714
|
+
* (`forgetLast.ts`), which is why this one is injected rather than selected
|
|
715
|
+
* by a flag inside the shared entry builder.
|
|
642
716
|
*
|
|
643
|
-
* @param options {object}
|
|
644
|
-
* @
|
|
717
|
+
* @param options {object}
|
|
718
|
+
* @param options.published {PublishedWebvhLog}
|
|
719
|
+
* @param options.target {ClientRemovalTarget}
|
|
720
|
+
* @returns {void}
|
|
645
721
|
*/
|
|
646
|
-
|
|
647
|
-
|
|
722
|
+
function assertNotLastClient({ published, target }) {
|
|
723
|
+
const invocationIds = relationIds(published.doc.capabilityInvocation);
|
|
724
|
+
if (invocationIds.includes(target.signingVmId) &&
|
|
725
|
+
invocationIds.every(id => id === target.signingVmId)) {
|
|
726
|
+
throw new LastEnrolledClientForgetError();
|
|
727
|
+
}
|
|
648
728
|
}
|
|
649
729
|
/**
|
|
650
|
-
* One attempt of {@link forgetWebvhClient} or
|
|
651
|
-
* re-invoked by
|
|
652
|
-
*
|
|
653
|
-
*
|
|
730
|
+
* One attempt of {@link forgetWebvhClient} or `forgetLastWebvhClient`
|
|
731
|
+
* (`forgetLast.ts`), re-invoked by their conflict retries. The two share the
|
|
732
|
+
* whole removal entry and differ only in what makes the removal admissible,
|
|
733
|
+
* which each supplies as `assertRemovable` -- the plain forget refuses the
|
|
734
|
+
* last enrolled client, the transition removal requires the ladder VM already
|
|
735
|
+
* installed. The invariant travels with the ceremony that owns it rather than
|
|
736
|
+
* living here as a flag.
|
|
737
|
+
*
|
|
738
|
+
* THE PROJECTION IS PUBLISHED BEFORE THE ENTRY, and the order is forced: the
|
|
739
|
+
* removal entry is ladder-signed and publishes `did.jsonl` alone (the bridge
|
|
740
|
+
* delegation covers nothing else), while the forgotten client's authority
|
|
741
|
+
* dies at that entry under the current-key-set rule. So the post-removal
|
|
742
|
+
* `did:web` projection has to be written while that client can still write
|
|
743
|
+
* it. A run torn between the projection PUT and the entry leaves `did.json`
|
|
744
|
+
* omitting a client the log still lists, which is fail-closed for a `did:web`
|
|
745
|
+
* verifier and is re-PUT by the re-run; the reverse order would leave the
|
|
746
|
+
* revoked client standing in `did.json` with nothing left able to remove it.
|
|
747
|
+
* The idempotent already-forgotten path writes no projection at all: the
|
|
748
|
+
* removal entry landed on an earlier run, so this client's authority is
|
|
749
|
+
* already gone and its store can only be refused. A projection that path
|
|
750
|
+
* leaves stale is mended by the next transient visit's
|
|
751
|
+
* `ensureDidWebProjection`, which invokes under its generation delegation.
|
|
654
752
|
*
|
|
655
753
|
* @param options {object} see {@link forgetWebvhClient}, plus:
|
|
656
|
-
* @param options.
|
|
657
|
-
*
|
|
658
|
-
*
|
|
754
|
+
* @param options.assertRemovable {function}
|
|
755
|
+
* `({ published, target }) => void` -- run on the read, after the
|
|
756
|
+
* idempotent already-forgotten check and before anything is attributed or
|
|
757
|
+
* built; it throws to refuse the removal
|
|
659
758
|
* @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog }>}
|
|
660
759
|
*/
|
|
661
|
-
async function clientForgetEntryOnce({ store, ladderSeed, forgottenClient, knownLatentHashes = [], expectedDid, pinStore, logId,
|
|
662
|
-
//
|
|
663
|
-
//
|
|
664
|
-
|
|
760
|
+
export async function clientForgetEntryOnce({ store, projectionStore, ladderSeed, forgottenClient, knownLatentHashes = [], expectedDid, pinStore, logId, assertRemovable }) {
|
|
761
|
+
// Resolved by the skip hook on the read the entry is built on, and used by
|
|
762
|
+
// the build below -- the same snapshot, never a second read.
|
|
763
|
+
let target;
|
|
764
|
+
const entry = await ladderSignedAccountEntry({
|
|
665
765
|
store,
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
signer,
|
|
728
|
-
alsoKnownAsWeb: true,
|
|
729
|
-
...fields,
|
|
730
|
-
// The acting rung reveals itself in the entry it signs (its hash stands
|
|
731
|
-
// committed, or the rung is already revealed), and its own hash is kept
|
|
732
|
-
// committed so the carry-over convention holds for the next entry.
|
|
733
|
-
updateKeys: [...new Set([...fields.updateKeys, rung.keyMultibase])],
|
|
734
|
-
nextKeyHashes: [...new Set([...fields.nextKeyHashes, rungHash])]
|
|
766
|
+
ladderSeed,
|
|
767
|
+
expectedDid,
|
|
768
|
+
pinStore,
|
|
769
|
+
logId,
|
|
770
|
+
skip: async (published) => {
|
|
771
|
+
target = await clientRemovalTarget({
|
|
772
|
+
published,
|
|
773
|
+
client: forgottenClient
|
|
774
|
+
});
|
|
775
|
+
if (!target.present) {
|
|
776
|
+
// Already forgotten (a torn earlier run finished the entry). No
|
|
777
|
+
// projection is written on this path: this client's verification
|
|
778
|
+
// methods left the document with that entry, so its store is
|
|
779
|
+
// authorized for nothing. The next transient visit's
|
|
780
|
+
// `ensureDidWebProjection` is the mender.
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
await assertRemovable({ published, target });
|
|
784
|
+
return false;
|
|
785
|
+
},
|
|
786
|
+
build: async ({ published, rung }) => {
|
|
787
|
+
// The ladder vouches for its own commitments: a self-enrolled client's
|
|
788
|
+
// staged hash was committed in the same reveal entry as the next rung's
|
|
789
|
+
// hash, so without these the staged-hash attribution cannot tell the
|
|
790
|
+
// two apart. Every hash a reveal entry can have committed is for a rung
|
|
791
|
+
// at or one past the current index.
|
|
792
|
+
const ladderHashes = [];
|
|
793
|
+
for (let index = 0; index <= rung.index + 1; index++) {
|
|
794
|
+
const laddered = await ladderRung({ ladderSeed, index });
|
|
795
|
+
ladderHashes.push(await deriveNextKeyHash(laddered.keyMultibase));
|
|
796
|
+
}
|
|
797
|
+
// The removal's own filtered sets; the acting rung's key and hash are
|
|
798
|
+
// unioned back in by the shared carry-over conventions.
|
|
799
|
+
return clientRemovalFields({
|
|
800
|
+
published,
|
|
801
|
+
target: target,
|
|
802
|
+
knownLatentHashes: [...knownLatentHashes, ...ladderHashes]
|
|
803
|
+
});
|
|
804
|
+
},
|
|
805
|
+
// The post-removal projection, published while the client being removed
|
|
806
|
+
// can still write it (see the header). `webDoc` is the `alsoKnownAsWeb`
|
|
807
|
+
// projection `ladderSignedAccountEntry` always asks `updateDID` for.
|
|
808
|
+
...(projectionStore
|
|
809
|
+
? {
|
|
810
|
+
beforePublish: async ({ updated }) => {
|
|
811
|
+
if (!updated.webDoc) {
|
|
812
|
+
// `publishUpdatedLog` states the same invariant: every entry is
|
|
813
|
+
// built with `alsoKnownAsWeb`, so a missing projection is a
|
|
814
|
+
// defect. Refusing here is what keeps the removal entry from
|
|
815
|
+
// publishing with `did.json` left naming the removed client,
|
|
816
|
+
// which on a client-less account nothing could mend.
|
|
817
|
+
throw new Error('did:webvh: updateDID returned no webDoc despite the ' +
|
|
818
|
+
'did:web alsoKnownAs.');
|
|
819
|
+
}
|
|
820
|
+
await putDidWebProjection({
|
|
821
|
+
store: projectionStore,
|
|
822
|
+
webDoc: updated.webDoc
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
: {})
|
|
735
827
|
});
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
// log back straight afterwards is refused on the next read.
|
|
739
|
-
if (pinStore && logId !== undefined) {
|
|
740
|
-
await pinStore.write({ logId, pin: pinOfLog(updated.log) });
|
|
741
|
-
}
|
|
742
|
-
return { did: updated.did, doc: updated.doc, log: updated.log };
|
|
828
|
+
const settled = entry.updated ?? entry.published;
|
|
829
|
+
return { did: settled.did, doc: settled.doc, log: settled.log };
|
|
743
830
|
}
|
|
744
831
|
/**
|
|
745
832
|
* THE LADDER-VM INSTALL ENTRY (the two-entry transition ceremony's first
|
|
@@ -794,72 +881,83 @@ export async function installLadderVmWebvh(options) {
|
|
|
794
881
|
* @param options {object} see {@link installLadderVmWebvh}
|
|
795
882
|
* @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog, installed: boolean }>}
|
|
796
883
|
*/
|
|
797
|
-
async function installLadderVmWebvhOnce(
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
store,
|
|
802
|
-
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
803
|
-
...(pinStore ? { pinStore } : {}),
|
|
804
|
-
...(logId !== undefined ? { logId } : {})
|
|
884
|
+
async function installLadderVmWebvhOnce(options) {
|
|
885
|
+
const { changed, ...settled } = await setLadderVmPresenceOnce({
|
|
886
|
+
...options,
|
|
887
|
+
present: true
|
|
805
888
|
});
|
|
806
|
-
|
|
889
|
+
return { ...settled, installed: changed };
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* ONE LADDER-VM PRESENCE ENTRY, in either direction: `present: true`
|
|
893
|
+
* publishes this credential's ladder VM, `present: false` strikes it, and the
|
|
894
|
+
* entries are otherwise the same edit read backwards -- the VM in or out of
|
|
895
|
+
* `verificationMethod`, `assertionMethod`, and `capabilityDelegation`, with
|
|
896
|
+
* `authentication`, `keyAgreement`, and `capabilityInvocation` re-stated
|
|
897
|
+
* untouched. That relation asymmetry (`assertionMethod` and
|
|
898
|
+
* `capabilityDelegation` only, never `authentication` or
|
|
899
|
+
* `capabilityInvocation`) is what the recognition reads and what keeps a
|
|
900
|
+
* ladder VM out of every client listing, so the two directions must agree on
|
|
901
|
+
* it exactly; stating it once is the point of the merge.
|
|
902
|
+
*
|
|
903
|
+
* The id derives from the ladder seed, so the entry reaches ONE credential's
|
|
904
|
+
* VM: another standing credential's ladder VM, and every enrolled client's
|
|
905
|
+
* inventory, stand untouched. Idempotent in both directions -- a document
|
|
906
|
+
* already in the asked-for state is a no-op returning `changed: false`,
|
|
907
|
+
* detected BEFORE the rung attribution so a re-run over a retired credential
|
|
908
|
+
* returns unchanged rather than failing closed.
|
|
909
|
+
*
|
|
910
|
+
* @param options {object} see {@link installLadderVmWebvh}, plus:
|
|
911
|
+
* @param options.present {boolean} the state the entry leaves the ladder VM
|
|
912
|
+
* in
|
|
913
|
+
* @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog, changed: boolean }>}
|
|
914
|
+
*/
|
|
915
|
+
async function setLadderVmPresenceOnce({ store, ladderSeed, expectedDid, pinStore, logId, present }) {
|
|
807
916
|
const ladderVmKey = await ladderVmKeyMultibase({ ladderSeed });
|
|
808
|
-
const
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
verificationMethods,
|
|
846
|
-
authentication: relationIds(doc.authentication),
|
|
847
|
-
assertionMethod: withVm(doc.assertionMethod),
|
|
848
|
-
keyAgreement: relationIds(doc.keyAgreement),
|
|
849
|
-
capabilityInvocation: relationIds(doc.capabilityInvocation),
|
|
850
|
-
capabilityDelegation: withVm(doc.capabilityDelegation)
|
|
917
|
+
const entry = await ladderSignedAccountEntry({
|
|
918
|
+
store,
|
|
919
|
+
ladderSeed,
|
|
920
|
+
expectedDid,
|
|
921
|
+
pinStore,
|
|
922
|
+
logId,
|
|
923
|
+
// Already in the asked-for state: a torn earlier run published the entry,
|
|
924
|
+
// the account is mid-transition, or the credential never bound a VM here.
|
|
925
|
+
skip: published => ladderVmIds({ doc: published.doc }).includes(`${published.did}#${ladderVmKey}`) === present,
|
|
926
|
+
build: ({ published }) => {
|
|
927
|
+
const { did, doc } = published;
|
|
928
|
+
const ladderVmId = `${did}#${ladderVmKey}`;
|
|
929
|
+
const withoutVm = (relation) => relationIds(relation).filter(id => id !== ladderVmId);
|
|
930
|
+
const withVm = (relation) => [...new Set([...relationIds(relation), ladderVmId])];
|
|
931
|
+
const inRelation = present ? withVm : withoutVm;
|
|
932
|
+
const otherMethods = (doc.verificationMethod ?? []).filter(method => method.id !== ladderVmId);
|
|
933
|
+
return {
|
|
934
|
+
verificationMethods: present
|
|
935
|
+
? [
|
|
936
|
+
...otherMethods,
|
|
937
|
+
ladderVerificationMethod({
|
|
938
|
+
controller: did,
|
|
939
|
+
publicKeyMultibase: ladderVmKey
|
|
940
|
+
})
|
|
941
|
+
]
|
|
942
|
+
: otherMethods,
|
|
943
|
+
// The ladder VM's relation asymmetry: `assertionMethod` and
|
|
944
|
+
// `capabilityDelegation` only -- no `authentication`, no
|
|
945
|
+
// `capabilityInvocation` -- which is also what keeps it out of every
|
|
946
|
+
// client listing.
|
|
947
|
+
authentication: relationIds(doc.authentication),
|
|
948
|
+
assertionMethod: inRelation(doc.assertionMethod),
|
|
949
|
+
keyAgreement: relationIds(doc.keyAgreement),
|
|
950
|
+
capabilityInvocation: relationIds(doc.capabilityInvocation),
|
|
951
|
+
capabilityDelegation: inRelation(doc.capabilityDelegation)
|
|
952
|
+
};
|
|
953
|
+
}
|
|
851
954
|
});
|
|
852
|
-
|
|
853
|
-
// Advance the pin to what this entry just published, so a host rolling the
|
|
854
|
-
// log back straight afterwards is refused on the next read.
|
|
855
|
-
if (pinStore && logId !== undefined) {
|
|
856
|
-
await pinStore.write({ logId, pin: pinOfLog(updated.log) });
|
|
857
|
-
}
|
|
955
|
+
const settled = entry.updated ?? entry.published;
|
|
858
956
|
return {
|
|
859
|
-
did:
|
|
860
|
-
doc:
|
|
861
|
-
log:
|
|
862
|
-
|
|
957
|
+
did: settled.did,
|
|
958
|
+
doc: settled.doc,
|
|
959
|
+
log: settled.log,
|
|
960
|
+
changed: entry.updated !== undefined
|
|
863
961
|
};
|
|
864
962
|
}
|
|
865
963
|
/**
|
|
@@ -916,54 +1014,12 @@ export async function strikeLadderVmWebvh(options) {
|
|
|
916
1014
|
* @param options {object} see {@link strikeLadderVmWebvh}
|
|
917
1015
|
* @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog, struck: boolean }>}
|
|
918
1016
|
*/
|
|
919
|
-
async function strikeLadderVmWebvhOnce(
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
store,
|
|
924
|
-
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
925
|
-
...(pinStore ? { pinStore } : {}),
|
|
926
|
-
...(logId !== undefined ? { logId } : {})
|
|
927
|
-
});
|
|
928
|
-
const { did, doc } = published;
|
|
929
|
-
const ladderVmId = `${did}#${await ladderVmKeyMultibase({ ladderSeed })}`;
|
|
930
|
-
if (!ladderVmIds({ doc }).includes(ladderVmId)) {
|
|
931
|
-
// Nothing of this credential's to strike (a torn earlier run published
|
|
932
|
-
// the entry, or the credential never bound a VM here).
|
|
933
|
-
return { did, doc, log: published.log, struck: false };
|
|
934
|
-
}
|
|
935
|
-
// Which rung is current, recovered from the log itself. Fails closed with
|
|
936
|
-
// `LadderAttributionError` for a revoked (or never-bound) credential and
|
|
937
|
-
// for any ambiguous history.
|
|
938
|
-
const { rung } = await attributeLadderRung({ ladderSeed, published });
|
|
939
|
-
const rungHash = await deriveNextKeyHash(rung.keyMultibase);
|
|
940
|
-
await assertCarryOverCommitments({ published });
|
|
941
|
-
const existingMethods = (doc.verificationMethod ?? []);
|
|
942
|
-
const withoutVm = (relation) => relationIds(relation).filter(id => id !== ladderVmId);
|
|
943
|
-
const signer = await updateKeySigner({ seed: rung.seed });
|
|
944
|
-
const updated = await updateDID({
|
|
945
|
-
log: published.log,
|
|
946
|
-
signer,
|
|
947
|
-
alsoKnownAsWeb: true,
|
|
948
|
-
// The acting rung reveals itself in the entry it signs (its hash stands
|
|
949
|
-
// committed, or the rung is already revealed), and its own hash is kept
|
|
950
|
-
// committed so the carry-over convention holds for the next entry.
|
|
951
|
-
updateKeys: [...new Set([...published.updateKeys, rung.keyMultibase])],
|
|
952
|
-
nextKeyHashes: [...new Set([...published.nextKeyHashes, rungHash])],
|
|
953
|
-
verificationMethods: existingMethods.filter(method => method.id !== ladderVmId),
|
|
954
|
-
authentication: relationIds(doc.authentication),
|
|
955
|
-
assertionMethod: withoutVm(doc.assertionMethod),
|
|
956
|
-
keyAgreement: relationIds(doc.keyAgreement),
|
|
957
|
-
capabilityInvocation: relationIds(doc.capabilityInvocation),
|
|
958
|
-
capabilityDelegation: withoutVm(doc.capabilityDelegation)
|
|
1017
|
+
async function strikeLadderVmWebvhOnce(options) {
|
|
1018
|
+
const { changed, ...settled } = await setLadderVmPresenceOnce({
|
|
1019
|
+
...options,
|
|
1020
|
+
present: false
|
|
959
1021
|
});
|
|
960
|
-
|
|
961
|
-
// Advance the pin to what this entry just published, so a host rolling the
|
|
962
|
-
// log back straight afterwards is refused on the next read.
|
|
963
|
-
if (pinStore && logId !== undefined) {
|
|
964
|
-
await pinStore.write({ logId, pin: pinOfLog(updated.log) });
|
|
965
|
-
}
|
|
966
|
-
return { did: updated.did, doc: updated.doc, log: updated.log, struck: true };
|
|
1022
|
+
return { ...settled, struck: changed };
|
|
967
1023
|
}
|
|
968
1024
|
/**
|
|
969
1025
|
* THE STANDALONE REVEAL-AND-COMMIT ENTRY: reveals this credential's currently
|
|
@@ -1005,38 +1061,27 @@ async function strikeLadderVmWebvhOnce({ store, ladderSeed, expectedDid, pinStor
|
|
|
1005
1061
|
* entry
|
|
1006
1062
|
*/
|
|
1007
1063
|
export async function revealLadderRungWebvh({ store, ladderSeed, expectedDid, pinStore, logId }) {
|
|
1008
|
-
const
|
|
1064
|
+
const entry = await ladderSignedAccountEntry({
|
|
1009
1065
|
store,
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
...published.nextKeyHashes,
|
|
1029
|
-
await deriveNextKeyHash(rung.keyMultibase),
|
|
1030
|
-
await deriveNextKeyHash(nextRung.keyMultibase)
|
|
1031
|
-
])
|
|
1032
|
-
]
|
|
1066
|
+
ladderSeed,
|
|
1067
|
+
expectedDid,
|
|
1068
|
+
pinStore,
|
|
1069
|
+
logId,
|
|
1070
|
+
build: async ({ rung, state }) => {
|
|
1071
|
+
// A rung already revealed (a torn earlier run, or a racing ceremony
|
|
1072
|
+
// that got there first) leaves nothing to publish. The decline sits
|
|
1073
|
+
// after the attribution because the attribution is what answers it.
|
|
1074
|
+
if (state === 'revealed') {
|
|
1075
|
+
return undefined;
|
|
1076
|
+
}
|
|
1077
|
+
// The entry commits the next rung only; the acting rung's own key and
|
|
1078
|
+
// carry-over hash come from the shared reveal and carry-over unions.
|
|
1079
|
+
const nextRung = await ladderRung({ ladderSeed, index: rung.index + 1 });
|
|
1080
|
+
return {
|
|
1081
|
+
commitHashes: [await deriveNextKeyHash(nextRung.keyMultibase)]
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1033
1084
|
});
|
|
1034
|
-
|
|
1035
|
-
// Advance the pin to what this entry just published, so a host rolling the
|
|
1036
|
-
// log back straight afterwards is refused on the next read.
|
|
1037
|
-
if (pinStore && logId !== undefined) {
|
|
1038
|
-
await pinStore.write({ logId, pin: pinOfLog(updated.log) });
|
|
1039
|
-
}
|
|
1040
|
-
return { revealed: true };
|
|
1085
|
+
return { revealed: entry.updated !== undefined };
|
|
1041
1086
|
}
|
|
1042
1087
|
//# sourceMappingURL=ladderAnchored.js.map
|