@interop/wallet-core 0.62.0 → 0.65.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 +55 -34
- package/dist/clientAnnex/establish.d.ts.map +1 -1
- package/dist/clientAnnex/establish.js +102 -56
- package/dist/clientAnnex/establish.js.map +1 -1
- package/dist/clientAnnex/forget.d.ts +16 -2
- package/dist/clientAnnex/forget.d.ts.map +1 -1
- package/dist/clientAnnex/forget.js +11 -9
- package/dist/clientAnnex/forget.js.map +1 -1
- package/dist/clientAnnex/forgetLast.d.ts +62 -18
- package/dist/clientAnnex/forgetLast.d.ts.map +1 -1
- package/dist/clientAnnex/forgetLast.js +92 -26
- 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 +7 -7
- package/dist/clientAnnex/gc.js.map +1 -1
- package/dist/clientAnnex/heal.d.ts +38 -5
- package/dist/clientAnnex/heal.d.ts.map +1 -1
- package/dist/clientAnnex/heal.js +346 -236
- package/dist/clientAnnex/heal.js.map +1 -1
- package/dist/clientAnnex/index.d.ts +21 -5
- package/dist/clientAnnex/index.d.ts.map +1 -1
- package/dist/clientAnnex/index.js +24 -5
- 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 +222 -33
- 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 +162 -43
- package/dist/clientAnnex/log.d.ts.map +1 -1
- package/dist/clientAnnex/log.js +423 -192
- 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 +26 -12
- 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 +10 -6
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +9 -5
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/rosterLogStore.d.ts +12 -11
- package/dist/keys/rosterLogStore.d.ts.map +1 -1
- package/dist/keys/rosterLogStore.js +15 -13
- 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/userKeyRoster.d.ts +57 -7
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +222 -17
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/keys/userKeyRosterCascade.d.ts +7 -6
- package/dist/keys/userKeyRosterCascade.d.ts.map +1 -1
- package/dist/keys/userKeyRosterCascade.js +7 -6
- 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 +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/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.map +1 -1
- package/dist/recovery/recoveryDelegation.js +21 -34
- 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/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
|
@@ -28,15 +28,17 @@
|
|
|
28
28
|
* one-entry forget -- live in `clientAnnex/ladderAnchored.ts`. What stays
|
|
29
29
|
* here is the verify-side half every wallet needs regardless of account configuration.
|
|
30
30
|
*/
|
|
31
|
-
import { deriveNextKeyHash
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
31
|
+
import { deriveNextKeyHash } from '@interop/did-method-webvh';
|
|
32
|
+
import { MULTIKEY_COMMITMENT_VM_TYPE, MULTIKEY_VM_TYPE, ladderVerificationMethod, readPublishedLogOrThrow, withLogConflictRetry } from '../webvh/didWebvh.js';
|
|
33
|
+
import { signAccountEntry } from '../webvh/accountEntry.js';
|
|
34
|
+
import { preEntryProjectionPublisher } from '../webvh/didWebProjection.js';
|
|
35
|
+
import { ladderVmIds, relationIds } from '../resourceLog/document.js';
|
|
34
36
|
// The one deliberate base-side dependency on the annex subpath, pinned as an
|
|
35
37
|
// exception in the lint rule: this module resolves a credential's CURRENT
|
|
36
38
|
// ladder inventory from the log itself (the shared attribution helpers in
|
|
37
39
|
// `clientAnnex/ladder.ts`), never touching the annex log machinery, and
|
|
38
40
|
// derives the credential's ladder VM from its seed at the install.
|
|
39
|
-
import { attributeLadderInventory, LadderAttributionError, ladderVmKeyMultibase } from '../clientAnnex/ladder.js';
|
|
41
|
+
import { attributeLadderInventory, LadderAttributionError, ladderVmIdsIntroducedWithCredential, ladderVmKeyMultibase } from '../clientAnnex/ladder.js';
|
|
40
42
|
/**
|
|
41
43
|
* The ladder inventory the removal edit resolved from the log diverges from
|
|
42
44
|
* what the caller was told one read earlier. A ceremony that names its
|
|
@@ -62,6 +64,54 @@ export class LadderInventoryDriftError extends Error {
|
|
|
62
64
|
this.attributed = attributed;
|
|
63
65
|
}
|
|
64
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* A retirement whose ladder attribution could not claim the retired
|
|
69
|
+
* credential's ladder VM, refused with nothing written. The shape is the
|
|
70
|
+
* seedless strike claiming nothing: the credential still stands in the
|
|
71
|
+
* document, the walk struck no ladder VM, and ladder VMs stand there that it
|
|
72
|
+
* could not claim. A leftover VM would keep the retired credential's
|
|
73
|
+
* delegation authority alive -- under `capabilityDelegation` it can still
|
|
74
|
+
* sign a DELETE-only capability on the account Space -- and nothing
|
|
75
|
+
* downstream can tell such a leftover from a sibling credential's standing
|
|
76
|
+
* VM, so the retirement is the one place the state can be closed
|
|
77
|
+
* (`decisions/0015`).
|
|
78
|
+
*
|
|
79
|
+
* `unclaimedLadderVmIds` names every ladder VM the walk left unclaimed, and
|
|
80
|
+
* `anchorKeyMultibase` the update key the walk was anchored on (a recovery
|
|
81
|
+
* code's revocation anchors on the rung-0 multibase the registry recorded at
|
|
82
|
+
* issuance). On a
|
|
83
|
+
* multi-credential account that list carries the siblings' VMs beside the
|
|
84
|
+
* retired credential's, since telling them apart is exactly what the walk
|
|
85
|
+
* could not do. `retryableWithLadderSeed` says whether a retry supplying the
|
|
86
|
+
* credential's ladder seed can let attribution succeed. The gate raises this
|
|
87
|
+
* error only from a seedless claim (a seeded one either strikes the derived
|
|
88
|
+
* VM or proves there is none), so the hint is `true` from this library; the
|
|
89
|
+
* member is the wallets' read for the retry they offer.
|
|
90
|
+
* Matched on `name` (the error crosses app-injected seams that may resolve
|
|
91
|
+
* to another copy of this package).
|
|
92
|
+
*/
|
|
93
|
+
export class UnclaimedLadderVmRetirementError extends Error {
|
|
94
|
+
unclaimedLadderVmIds;
|
|
95
|
+
retryableWithLadderSeed;
|
|
96
|
+
anchorKeyMultibase;
|
|
97
|
+
constructor({ unclaimedLadderVmIds, retryableWithLadderSeed, anchorKeyMultibase }) {
|
|
98
|
+
super("did:webvh: the retirement cannot claim the retired credential's ladder " +
|
|
99
|
+
`VM (standing unclaimed: ${unclaimedLadderVmIds.join(', ')}` +
|
|
100
|
+
(anchorKeyMultibase === undefined
|
|
101
|
+
? ''
|
|
102
|
+
: `; anchored on ${anchorKeyMultibase}`) +
|
|
103
|
+
'); nothing was published and the credential still stands. ' +
|
|
104
|
+
(retryableWithLadderSeed
|
|
105
|
+
? "Retry with the credential's ladder seed in hand."
|
|
106
|
+
: 'No retry with the ladder seed can claim it.'));
|
|
107
|
+
this.name = 'UnclaimedLadderVmRetirementError';
|
|
108
|
+
this.unclaimedLadderVmIds = unclaimedLadderVmIds;
|
|
109
|
+
this.retryableWithLadderSeed = retryableWithLadderSeed;
|
|
110
|
+
if (anchorKeyMultibase !== undefined) {
|
|
111
|
+
this.anchorKeyMultibase = anchorKeyMultibase;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
65
115
|
/**
|
|
66
116
|
* The verification-method id a credential's key-agreement entry publishes
|
|
67
117
|
* under: `<did>#<multibase>` for a verbatim key (indistinguishable by id from
|
|
@@ -111,6 +161,191 @@ export async function attributeUnlockLadderInventory({ log, did, unlockKeys, lad
|
|
|
111
161
|
...(ladderSeed ? { ladderSeed } : {})
|
|
112
162
|
});
|
|
113
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* What of the document's ladder VMs a credential's attribution claims: the
|
|
166
|
+
* VM its seed derives (when the ceremony holds one), plus every VM the log
|
|
167
|
+
* attributes to its ladder. Resolved once here and shared by the removal
|
|
168
|
+
* edit, the retirement ceremony's pre-edit stage, and the read-only
|
|
169
|
+
* pre-flight, so the three agree on what is struck and what is left.
|
|
170
|
+
*
|
|
171
|
+
* `struck` is what the removal edit strikes: the derived id when it stands,
|
|
172
|
+
* and the attributed ids. `unclaimed` is every ladder VM standing in the
|
|
173
|
+
* document that neither the seed nor the attribution claims -- on a
|
|
174
|
+
* multi-credential account, the siblings' VMs at least. A supplied seed also
|
|
175
|
+
* cross-checks the attribution: a log attributing a VM the seed does not
|
|
176
|
+
* derive refuses with {@link LadderAttributionError}.
|
|
177
|
+
*
|
|
178
|
+
* @param options {object}
|
|
179
|
+
* @param options.doc {DIDDoc} the document the attribution ran over
|
|
180
|
+
* @param options.did {string} the account DID
|
|
181
|
+
* @param options.inventory {LadderStandingInventory} the credential's
|
|
182
|
+
* attributed ladder inventory ({@link attributeUnlockLadderInventory})
|
|
183
|
+
* @param [options.ladderSeed] {Uint8Array} the credential's ladder seed
|
|
184
|
+
* @returns {Promise<{ ladderVmId?: string, struck: string[], unclaimed:
|
|
185
|
+
* string[] }>} the seed-derived VM id when a seed was held
|
|
186
|
+
*/
|
|
187
|
+
export async function ladderVmClaimOf({ doc, did, inventory, ladderSeed }) {
|
|
188
|
+
const ladderVmId = ladderSeed
|
|
189
|
+
? `${did}#${await ladderVmKeyMultibase({ ladderSeed })}`
|
|
190
|
+
: undefined;
|
|
191
|
+
if (ladderVmId !== undefined) {
|
|
192
|
+
const foreign = inventory.ladderVmIds.filter(id => id !== ladderVmId);
|
|
193
|
+
if (foreign.length > 0) {
|
|
194
|
+
throw new LadderAttributionError("The published log attributes a ladder VM this credential's seed " +
|
|
195
|
+
'does not derive; refusing to strike on an ambiguous ' +
|
|
196
|
+
'attribution.');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const standing = ladderVmIds({ doc });
|
|
200
|
+
const struck = new Set();
|
|
201
|
+
if (ladderVmId !== undefined && standing.includes(ladderVmId)) {
|
|
202
|
+
struck.add(ladderVmId);
|
|
203
|
+
}
|
|
204
|
+
for (const id of inventory.ladderVmIds) {
|
|
205
|
+
struck.add(id);
|
|
206
|
+
}
|
|
207
|
+
const claimed = new Set([
|
|
208
|
+
...struck,
|
|
209
|
+
...(ladderVmId !== undefined ? [ladderVmId] : [])
|
|
210
|
+
]);
|
|
211
|
+
return {
|
|
212
|
+
...(ladderVmId !== undefined ? { ladderVmId } : {}),
|
|
213
|
+
struck: [...struck],
|
|
214
|
+
unclaimed: standing.filter(id => !claimed.has(id))
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The retirement gate (`decisions/0015`): refuses, with
|
|
219
|
+
* {@link UnclaimedLadderVmRetirementError}, a retirement of a
|
|
220
|
+
* ladder-carrying credential whose SEEDLESS claim struck nothing while a
|
|
221
|
+
* ladder VM that COULD BE THIS CREDENTIAL'S stands unclaimed and the
|
|
222
|
+
* credential itself still stands in the document. Deliberately narrower than
|
|
223
|
+
* "`unclaimed` is non-empty", which every retirement on a healthy
|
|
224
|
+
* multi-credential account produces, and narrower again than the standing
|
|
225
|
+
* unclaimed set: a sibling credential's VM is nothing this retirement could
|
|
226
|
+
* leave behind.
|
|
227
|
+
*
|
|
228
|
+
* Which unclaimed VMs are candidates is
|
|
229
|
+
* {@link ladderVmIdsIntroducedWithCredential}'s question, read off the log's
|
|
230
|
+
* entry shapes rather than off an attribution that has already refused: a VM
|
|
231
|
+
* introduced by the entry that introduced this credential's `keyAgreement`
|
|
232
|
+
* member, or by the entry that committed or authorized its anchor (the split
|
|
233
|
+
* bind, whose key and authority entries sit two versions apart). None, and
|
|
234
|
+
* the credential never had a VM to leave standing, so the retirement
|
|
235
|
+
* completes and strikes what it can. That is the torn issuance's orphan -- a
|
|
236
|
+
* credential with a `keyAgreement` member, no ladder VM, and no committed
|
|
237
|
+
* rung -- which previously could never be removed at all, since a sibling's
|
|
238
|
+
* standing VM refused it forever.
|
|
239
|
+
*
|
|
240
|
+
* Two shapes pass ahead of that. A credential whose `keyAgreement` member is
|
|
241
|
+
* already gone is a completed retirement re-running. And a claim resolved
|
|
242
|
+
* WITH the seed never refuses: the derived VM is either standing (and
|
|
243
|
+
* struck) or absent, and an absent derived VM is proof the credential has
|
|
244
|
+
* nothing to claim -- the last-client transition torn between its strike and
|
|
245
|
+
* reinstall entries leaves exactly that, and a seeded retirement there must
|
|
246
|
+
* complete rather than wait on the transition's re-run. So the error's retry
|
|
247
|
+
* hint is `true` whenever this gate raises it.
|
|
248
|
+
*
|
|
249
|
+
* The caller decides whether the credential carries a ladder.
|
|
250
|
+
*
|
|
251
|
+
* @param options {object}
|
|
252
|
+
* @param options.log {DIDLog} the verified log the claim was resolved over
|
|
253
|
+
* @param options.doc {DIDDoc} the document the claim was resolved over
|
|
254
|
+
* @param options.credentialVmId {string} the credential's `keyAgreement`
|
|
255
|
+
* verification-method id ({@link unlockKeyVmId})
|
|
256
|
+
* @param options.claim {{ ladderVmId?: string, struck: string[], unclaimed:
|
|
257
|
+
* string[] }} from {@link ladderVmClaimOf}
|
|
258
|
+
* @param [options.anchorKeyMultibase] {string} the update key the walk was
|
|
259
|
+
* anchored on: the candidate reading's second anchor form, and named in
|
|
260
|
+
* the refusal
|
|
261
|
+
* @returns {Promise<void>}
|
|
262
|
+
*/
|
|
263
|
+
export async function assertLadderVmClaimed({ log, doc, credentialVmId, claim, anchorKeyMultibase }) {
|
|
264
|
+
const credentialStands = (doc.verificationMethod ?? []).some(method => method.id === credentialVmId);
|
|
265
|
+
if (!credentialStands ||
|
|
266
|
+
claim.ladderVmId !== undefined ||
|
|
267
|
+
claim.struck.length > 0 ||
|
|
268
|
+
claim.unclaimed.length === 0) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const candidates = await ladderVmIdsIntroducedWithCredential({
|
|
272
|
+
log,
|
|
273
|
+
credentialVmId,
|
|
274
|
+
...(anchorKeyMultibase !== undefined ? { anchorKeyMultibase } : {})
|
|
275
|
+
});
|
|
276
|
+
const unclaimed = claim.unclaimed.filter(id => candidates.includes(id));
|
|
277
|
+
if (unclaimed.length === 0) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
throw new UnclaimedLadderVmRetirementError({
|
|
281
|
+
unclaimedLadderVmIds: unclaimed,
|
|
282
|
+
retryableWithLadderSeed: true,
|
|
283
|
+
...(anchorKeyMultibase !== undefined ? { anchorKeyMultibase } : {})
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The retirement gate run read-only, before anything is written: one pinned
|
|
288
|
+
* read of the account log, the credential's ladder attribution, and
|
|
289
|
+
* {@link assertLadderVmClaimed} over the result. A caller that establishes a
|
|
290
|
+
* replacement credential before it retires the old one (a passphrase change,
|
|
291
|
+
* a tap-confirmed passkey removal) runs this first, so a gate refusal lands
|
|
292
|
+
* the way an invalid-input check does -- nothing established, no
|
|
293
|
+
* pending-shaped registry entry written -- rather than after establishment,
|
|
294
|
+
* where the refusal would leave a torn state no seedless repair can clear.
|
|
295
|
+
* The in-ceremony gate stays as defense in depth, and it is what answers a
|
|
296
|
+
* log entry landing between the pre-flight and the retirement: the
|
|
297
|
+
* pre-flight's verdict holds for the head it read, and nothing binds the two
|
|
298
|
+
* reads.
|
|
299
|
+
*
|
|
300
|
+
* @param options {object}
|
|
301
|
+
* @param options.idStore {UnlockLogStore} the account's `id` collection
|
|
302
|
+
* read side
|
|
303
|
+
* @param options.unlockKeys {StandingUnlockKeys} the credential's recorded
|
|
304
|
+
* public inventory
|
|
305
|
+
* @param [options.ladderSeed] {Uint8Array} the credential's ladder seed,
|
|
306
|
+
* when the caller holds it
|
|
307
|
+
* @param [options.expectedDid] {string} the account DID the log must
|
|
308
|
+
* resolve to
|
|
309
|
+
* @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
|
|
310
|
+
* pins
|
|
311
|
+
* @param [options.logId] {string} the account log's pin slot; required
|
|
312
|
+
* whenever a `pinStore` is supplied
|
|
313
|
+
* @returns {Promise<LadderVmRemovalReport>} what the retirement would
|
|
314
|
+
* strike and what it would leave unclaimed
|
|
315
|
+
*/
|
|
316
|
+
export async function preflightUnlockCredentialRetirement({ idStore, unlockKeys, ladderSeed, expectedDid, pinStore, logId }) {
|
|
317
|
+
const published = await readPublishedLogOrThrow({
|
|
318
|
+
idStore,
|
|
319
|
+
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
320
|
+
...(pinStore ? { pinStore } : {}),
|
|
321
|
+
...(logId !== undefined ? { logId } : {}),
|
|
322
|
+
missingMessage: 'did:webvh: did.jsonl is missing; nothing to retire from.'
|
|
323
|
+
});
|
|
324
|
+
const { did, doc } = published;
|
|
325
|
+
const inventory = await attributeUnlockLadderInventory({
|
|
326
|
+
log: published.log,
|
|
327
|
+
did,
|
|
328
|
+
unlockKeys,
|
|
329
|
+
...(ladderSeed ? { ladderSeed } : {})
|
|
330
|
+
});
|
|
331
|
+
const claim = await ladderVmClaimOf({
|
|
332
|
+
doc,
|
|
333
|
+
did,
|
|
334
|
+
inventory,
|
|
335
|
+
...(ladderSeed ? { ladderSeed } : {})
|
|
336
|
+
});
|
|
337
|
+
await assertLadderVmClaimed({
|
|
338
|
+
log: published.log,
|
|
339
|
+
doc,
|
|
340
|
+
credentialVmId: unlockKeyVmId({
|
|
341
|
+
did,
|
|
342
|
+
keyAgreement: unlockKeys.keyAgreement
|
|
343
|
+
}),
|
|
344
|
+
claim,
|
|
345
|
+
anchorKeyMultibase: unlockKeys.updateKeyMultibase
|
|
346
|
+
});
|
|
347
|
+
return { struck: claim.struck, unclaimed: claim.unclaimed };
|
|
348
|
+
}
|
|
114
349
|
/**
|
|
115
350
|
* The credential's `keyAgreement` verification method: an ordinary unmarked
|
|
116
351
|
* entry carrying either the key verbatim (a `Multikey` with
|
|
@@ -144,34 +379,6 @@ export function unlockKeyVerificationMethod({ did, keyAgreement }) {
|
|
|
144
379
|
publicKeyCommitment: keyAgreement.commitment
|
|
145
380
|
};
|
|
146
381
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Reads and resolves the published log through the narrow store seam.
|
|
149
|
-
*
|
|
150
|
-
* @param options {object}
|
|
151
|
-
* @param options.store {UnlockLogStore}
|
|
152
|
-
* @param [options.expectedDid] {string} the account DID the log must resolve
|
|
153
|
-
* to, where the caller holds one
|
|
154
|
-
* @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
|
|
155
|
-
* pins; a served log that is a rollback, a fork, or an identity switch
|
|
156
|
-
* against the pinned head is refused (`ResourceLogContinuityError`)
|
|
157
|
-
* @param [options.logId] {string} the account log's pin slot
|
|
158
|
-
* (`accountLogPinId({ spaceId })`); required whenever a `pinStore` is
|
|
159
|
-
* supplied
|
|
160
|
-
* @returns {Promise<PublishedWebvhLog>}
|
|
161
|
-
*/
|
|
162
|
-
export async function readLogOrThrow({ store, expectedDid, pinStore, logId }) {
|
|
163
|
-
// readPublishedLog only calls getIdResourceRaw, so the narrow seam is safe.
|
|
164
|
-
const published = await readPublishedLog({
|
|
165
|
-
idStore: store,
|
|
166
|
-
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
167
|
-
...(pinStore ? { pinStore } : {}),
|
|
168
|
-
...(logId !== undefined ? { logId } : {})
|
|
169
|
-
});
|
|
170
|
-
if (!published) {
|
|
171
|
-
throw new Error('did:webvh: did.jsonl is missing; nothing to enroll into.');
|
|
172
|
-
}
|
|
173
|
-
return published;
|
|
174
|
-
}
|
|
175
382
|
/**
|
|
176
383
|
* BIND (run by an enrolled client, root authority): publishes a standing
|
|
177
384
|
* credential's split configuration into the document -- one entry adding the
|
|
@@ -187,8 +394,13 @@ export async function readLogOrThrow({ store, expectedDid, pinStore, logId }) {
|
|
|
187
394
|
* idempotence against the SAME seed, finds the completed stage and publishes
|
|
188
395
|
* nothing -- where a mint-when-absent would publish a second VM that no
|
|
189
396
|
* anchored attribution could later strike. A credential with no ladder at all
|
|
190
|
-
*
|
|
191
|
-
*
|
|
397
|
+
* passes `null` and gets no VM.
|
|
398
|
+
*
|
|
399
|
+
* `part` splits the bind across two entries where a ceremony needs the
|
|
400
|
+
* credential's decryption material to precede its authority: `'key'`
|
|
401
|
+
* publishes the `keyAgreement` member alone, `'authority'` installs the
|
|
402
|
+
* ladder VM and commits the rung-0 hash, and `'all'` (the default) is the one
|
|
403
|
+
* merged entry every other caller writes.
|
|
192
404
|
*
|
|
193
405
|
* Idempotent: an inventory already published is a no-op, so re-running a torn
|
|
194
406
|
* bind converges. The entry publishes conditionally on the log this call
|
|
@@ -197,13 +409,16 @@ export async function readLogOrThrow({ store, expectedDid, pinStore, logId }) {
|
|
|
197
409
|
*
|
|
198
410
|
* @param options {object}
|
|
199
411
|
* @param options.idStore {WebvhIdStore}
|
|
200
|
-
* @param options.
|
|
201
|
-
* did:webvh update-key seeds
|
|
412
|
+
* @param options.signer {AccountLogSigner} who signs the entry: the BINDING
|
|
413
|
+
* client's own did:webvh update-key seeds, or the acting credential's
|
|
414
|
+
* ladder seed
|
|
202
415
|
* @param options.unlockKeys {StandingUnlockKeys} the credential's public
|
|
203
416
|
* inventory
|
|
204
417
|
* @param options.ladderSeed {Uint8Array | null} the credential's ladder
|
|
205
418
|
* seed, whose VM this entry installs; `null` for a credential that carries
|
|
206
419
|
* no ladder
|
|
420
|
+
* @param [options.part] {string} `'all'` (the default), `'key'`, or
|
|
421
|
+
* `'authority'` -- see above
|
|
207
422
|
* @param [options.expectedDid] {string} the account DID the log must resolve
|
|
208
423
|
* to, from the caller's stored account pointer
|
|
209
424
|
* @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
|
|
@@ -276,6 +491,15 @@ export async function publishUnlockKey(options) {
|
|
|
276
491
|
* @param options {object} see {@link publishUnlockKey}, plus:
|
|
277
492
|
* @param [options.ladderSeed] {Uint8Array} the retired credential's ladder
|
|
278
493
|
* seed, when in hand
|
|
494
|
+
* @param [options.projectionStore] {object} an `id`-collection store the
|
|
495
|
+
* caller may write through (a transient session's, bound to its generation
|
|
496
|
+
* delegation; an enrolled client's own root-invoking store). Supplied, the
|
|
497
|
+
* post-strike `did:web` projection is PUT through it immediately BEFORE
|
|
498
|
+
* this entry publishes, which is what keeps a ladder-signed removal from
|
|
499
|
+
* leaving `did.json` naming the retired credential. Best-effort: a failed
|
|
500
|
+
* PUT is warned and the removal proceeds. Omitted, the ladder arm leaves
|
|
501
|
+
* the projection to the next visit's `ensureDidWebProjection` and the
|
|
502
|
+
* client arm publishes it after the entry, as before
|
|
279
503
|
* @param [options.expectedLadderVmIds] {string[]} the ladder VM ids the
|
|
280
504
|
* caller already resolved for this credential, from its own read of the
|
|
281
505
|
* log. Supplied, this edit's own attribution must match them as a set --
|
|
@@ -283,6 +507,14 @@ export async function publishUnlockKey(options) {
|
|
|
283
507
|
* {@link LadderInventoryDriftError} before writing anything. That is what
|
|
284
508
|
* ties the retirement's stage-0 read (whose list the dependent-record
|
|
285
509
|
* re-mint pass acted on) to this one, which is otherwise independent
|
|
510
|
+
* @param [options.requireLadderVmClaim] {boolean} the credential carries a
|
|
511
|
+
* ladder, so its VM must be claimed: the edit refuses with
|
|
512
|
+
* {@link UnclaimedLadderVmRetirementError} before writing when the claim
|
|
513
|
+
* struck nothing while ladder VMs stand unclaimed and the credential still
|
|
514
|
+
* stands ({@link assertLadderVmClaimed}). The retirement ceremony sets it,
|
|
515
|
+
* and so does a recovery code's removal, whose inventory carries the code's
|
|
516
|
+
* own ladder VM. The refusal names the recorded update key the walk was
|
|
517
|
+
* anchored on
|
|
286
518
|
* @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog, ladderVm:
|
|
287
519
|
* LadderVmRemovalReport }>} see {@link publishUnlockKey}, plus the ladder
|
|
288
520
|
* VM report: what this entry struck, and what stands unclaimed after it
|
|
@@ -299,189 +531,216 @@ export async function removeUnlockKey(options) {
|
|
|
299
531
|
* @param options {object} see {@link publishUnlockKey}, plus `polarity`
|
|
300
532
|
* @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog }>}
|
|
301
533
|
*/
|
|
302
|
-
async function setUnlockKeyInventoryOnce({ idStore,
|
|
303
|
-
|
|
304
|
-
|
|
534
|
+
async function setUnlockKeyInventoryOnce({ idStore, signer, projectionStore, unlockKeys, ladderSeed, part = 'all', expectedLadderVmIds, requireLadderVmClaim, expectedDid, pinStore, logId, verb, polarity }) {
|
|
535
|
+
let ladderVmReport = { struck: [], unclaimed: [] };
|
|
536
|
+
const outcome = await signAccountEntry({
|
|
537
|
+
idStore,
|
|
538
|
+
signer,
|
|
305
539
|
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
306
540
|
...(pinStore ? { pinStore } : {}),
|
|
307
|
-
...(logId !== undefined ? { logId } : {})
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
? await attributeUnlockLadderInventory({
|
|
321
|
-
log: published.log,
|
|
322
|
-
did,
|
|
323
|
-
unlockKeys,
|
|
324
|
-
...(ladderSeed ? { ladderSeed } : {})
|
|
325
|
-
})
|
|
326
|
-
: { revealedKeys: [], committedHashes: [], ladderVmIds: [] };
|
|
327
|
-
const removedHashes = new Set(inventory.committedHashes);
|
|
328
|
-
const removedKeys = new Set(inventory.revealedKeys);
|
|
329
|
-
// The credential's ladder VM: installed by the publish polarity in this
|
|
330
|
-
// same entry, struck by the remove polarity in this same entry. The
|
|
331
|
-
// derived id is what the install publishes; the removal takes it from the
|
|
332
|
-
// seed when the ceremony holds one and from the log's attribution
|
|
333
|
-
// otherwise, so a seedless retirement still ends the credential's
|
|
334
|
-
// delegation authority.
|
|
335
|
-
const ladderVmKey = ladderSeed
|
|
336
|
-
? await ladderVmKeyMultibase({ ladderSeed })
|
|
337
|
-
: undefined;
|
|
338
|
-
const ladderVmId = ladderVmKey === undefined ? undefined : `${did}#${ladderVmKey}`;
|
|
339
|
-
const standingLadderVmIds = ladderVmIds({ doc });
|
|
340
|
-
const struckLadderVmIds = new Set();
|
|
341
|
-
if (polarity === 'remove') {
|
|
342
|
-
if (ladderVmId !== undefined) {
|
|
343
|
-
const foreign = inventory.ladderVmIds.filter(id => id !== ladderVmId);
|
|
344
|
-
if (foreign.length > 0) {
|
|
345
|
-
throw new LadderAttributionError("The published log attributes a ladder VM this credential's seed " +
|
|
346
|
-
'does not derive; refusing to strike on an ambiguous ' +
|
|
347
|
-
'attribution.');
|
|
541
|
+
...(logId !== undefined ? { logId } : {}),
|
|
542
|
+
missingMessage: 'did:webvh: did.jsonl is missing; nothing to enroll into.',
|
|
543
|
+
verb: verb ?? 'changing an unlock credential',
|
|
544
|
+
// The post-strike projection, published while the caller's store can
|
|
545
|
+
// still write it and before the entry the ladder arm cannot publish it
|
|
546
|
+
// with. Only the removal polarity is ever handed one: a publish adds
|
|
547
|
+
// inventory, which the served projection under-lists until some later
|
|
548
|
+
// writer refreshes it -- the safe direction.
|
|
549
|
+
...(projectionStore
|
|
550
|
+
? {
|
|
551
|
+
beforePublish: preEntryProjectionPublisher({
|
|
552
|
+
store: projectionStore
|
|
553
|
+
})
|
|
348
554
|
}
|
|
349
|
-
|
|
350
|
-
|
|
555
|
+
: {}),
|
|
556
|
+
build: async ({ published }) => {
|
|
557
|
+
const { did, doc } = published;
|
|
558
|
+
const keyHash = await deriveNextKeyHash(unlockKeys.updateKeyMultibase);
|
|
559
|
+
const vmId = unlockKeyVmId({ did, keyAgreement: unlockKeys.keyAgreement });
|
|
560
|
+
const vmPresent = (doc.verificationMethod ?? []).some(method => method.id === vmId);
|
|
561
|
+
// The remove polarity strikes the ladder's CURRENT inventory, resolved
|
|
562
|
+
// from the log with the recorded key as anchor -- never just the
|
|
563
|
+
// recorded key's hash, which a self-enrollment since the bind leaves
|
|
564
|
+
// stale (see {@link removeUnlockKey}). The credential's own
|
|
565
|
+
// verification-method id goes along: it is what tells the walk a climb
|
|
566
|
+
// from a spend, so the removal never annexes the commitment a spend
|
|
567
|
+
// handed to its replacement.
|
|
568
|
+
const inventory = polarity === 'remove'
|
|
569
|
+
? await attributeUnlockLadderInventory({
|
|
570
|
+
log: published.log,
|
|
571
|
+
did,
|
|
572
|
+
unlockKeys,
|
|
573
|
+
...(ladderSeed ? { ladderSeed } : {})
|
|
574
|
+
})
|
|
575
|
+
: { revealedKeys: [], committedHashes: [], ladderVmIds: [] };
|
|
576
|
+
const removedHashes = new Set(inventory.committedHashes);
|
|
577
|
+
const removedKeys = new Set(inventory.revealedKeys);
|
|
578
|
+
// The credential's ladder VM: installed by the publish polarity in this
|
|
579
|
+
// same entry, struck by the remove polarity in this same entry. The
|
|
580
|
+
// derived id is what the install publishes; the removal takes it from
|
|
581
|
+
// the seed when the ceremony holds one and from the log's attribution
|
|
582
|
+
// otherwise, so a seedless retirement still ends the credential's
|
|
583
|
+
// delegation authority.
|
|
584
|
+
const ladderVmKey = ladderSeed
|
|
585
|
+
? await ladderVmKeyMultibase({ ladderSeed })
|
|
586
|
+
: undefined;
|
|
587
|
+
const ladderVmId = ladderVmKey === undefined ? undefined : `${did}#${ladderVmKey}`;
|
|
588
|
+
const standingLadderVmIds = ladderVmIds({ doc });
|
|
589
|
+
const claim = polarity === 'remove'
|
|
590
|
+
? await ladderVmClaimOf({
|
|
591
|
+
doc,
|
|
592
|
+
did,
|
|
593
|
+
inventory,
|
|
594
|
+
...(ladderSeed ? { ladderSeed } : {})
|
|
595
|
+
})
|
|
596
|
+
: { struck: [], unclaimed: [] };
|
|
597
|
+
if (polarity === 'remove') {
|
|
598
|
+
// The drift check, before any write: this edit's own attribution
|
|
599
|
+
// against the list the caller resolved a read earlier. A concurrent
|
|
600
|
+
// ceremony, or a host serving two different log versions to the two
|
|
601
|
+
// reads, would otherwise let the strike diverge from what the
|
|
602
|
+
// caller's dependent-record pass already acted on.
|
|
603
|
+
if (expectedLadderVmIds !== undefined) {
|
|
604
|
+
const attributed = new Set(inventory.ladderVmIds);
|
|
605
|
+
const expected = new Set(expectedLadderVmIds);
|
|
606
|
+
const sameSet = attributed.size === expected.size &&
|
|
607
|
+
[...expected].every(id => attributed.has(id));
|
|
608
|
+
if (!sameSet) {
|
|
609
|
+
throw new LadderInventoryDriftError({
|
|
610
|
+
expected: [...expected],
|
|
611
|
+
attributed: [...attributed]
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
// The retirement gate, before any write and after the drift check: a
|
|
616
|
+
// ladder-carrying credential whose claim struck nothing while ladder
|
|
617
|
+
// VMs stand unclaimed is refused rather than retired with its VM left
|
|
618
|
+
// standing.
|
|
619
|
+
if (requireLadderVmClaim) {
|
|
620
|
+
await assertLadderVmClaimed({
|
|
621
|
+
log: published.log,
|
|
622
|
+
doc,
|
|
623
|
+
credentialVmId: vmId,
|
|
624
|
+
claim,
|
|
625
|
+
anchorKeyMultibase: unlockKeys.updateKeyMultibase
|
|
626
|
+
});
|
|
627
|
+
}
|
|
351
628
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
629
|
+
const struckLadderVmIds = new Set(claim.struck);
|
|
630
|
+
const ladderVmPresent = polarity === 'publish'
|
|
631
|
+
? ladderVmId !== undefined && standingLadderVmIds.includes(ladderVmId)
|
|
632
|
+
: struckLadderVmIds.size > 0;
|
|
633
|
+
const struckIds = new Set([vmId, ...struckLadderVmIds]);
|
|
634
|
+
const hashCommitted = published.nextKeyHashes.includes(keyHash);
|
|
635
|
+
// What this entry is responsible for, by `part`: the key half publishes
|
|
636
|
+
// the `keyAgreement` member alone, the authority half the ladder VM and
|
|
637
|
+
// the rung's commitment, and the default entry both.
|
|
638
|
+
const publishesKey = part === 'all' || part === 'key';
|
|
639
|
+
const publishesAuthority = part === 'all' || part === 'authority';
|
|
640
|
+
const settled = polarity === 'publish'
|
|
641
|
+
? (!publishesKey || vmPresent) &&
|
|
642
|
+
(!publishesAuthority ||
|
|
643
|
+
(hashCommitted && (ladderVmId === undefined || ladderVmPresent)))
|
|
644
|
+
: !vmPresent &&
|
|
645
|
+
!ladderVmPresent &&
|
|
646
|
+
removedHashes.size === 0 &&
|
|
647
|
+
removedKeys.size === 0;
|
|
648
|
+
ladderVmReport = {
|
|
649
|
+
struck: claim.struck,
|
|
650
|
+
unclaimed: claim.unclaimed
|
|
651
|
+
};
|
|
652
|
+
if (settled) {
|
|
653
|
+
return undefined;
|
|
371
654
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
]);
|
|
393
|
-
return {
|
|
394
|
-
struck: [...struck],
|
|
395
|
-
unclaimed: ladderVmIds({ doc: resultDoc }).filter(id => !claimed.has(id))
|
|
396
|
-
};
|
|
397
|
-
};
|
|
398
|
-
if (settled) {
|
|
399
|
-
return {
|
|
400
|
-
did,
|
|
401
|
-
doc,
|
|
402
|
-
log: published.log,
|
|
403
|
-
ladderVm: ladderVmReport(doc, struckLadderVmIds)
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
const activeKey = await updateKeyMultibase({ seed: updateKeys.updateSeed });
|
|
407
|
-
if (!published.updateKeys.includes(activeKey)) {
|
|
408
|
-
throw new Error("did:webvh: the published log does not authorize this client's active " +
|
|
409
|
-
'update key; finalize the pending rotation before ' +
|
|
410
|
-
`${verb ?? 'changing an unlock credential'}.`);
|
|
411
|
-
}
|
|
412
|
-
await assertCarryOverCommitments({ published });
|
|
413
|
-
const existingMethods = (doc.verificationMethod ?? []);
|
|
414
|
-
const signer = await updateKeySigner({ seed: updateKeys.updateSeed });
|
|
415
|
-
const nextKeyHashes = polarity === 'publish'
|
|
416
|
-
? [...new Set([...published.nextKeyHashes, keyHash])]
|
|
417
|
-
: published.nextKeyHashes.filter(hash => !removedHashes.has(hash));
|
|
418
|
-
// A torn self-enrollment leaves a revealed rung in `updateKeys`; the remove
|
|
419
|
-
// polarity strikes it in the same entry as its hash, keeping the carry-over
|
|
420
|
-
// invariant self-consistent. On the publish polarity and the ordinary
|
|
421
|
-
// committed-only removal this is the published set unchanged.
|
|
422
|
-
const statedUpdateKeys = polarity === 'publish'
|
|
423
|
-
? published.updateKeys
|
|
424
|
-
: published.updateKeys.filter(key => !removedKeys.has(key));
|
|
425
|
-
const verificationMethods = polarity === 'publish'
|
|
426
|
-
? [
|
|
427
|
-
...existingMethods.filter(method => method.id !== vmId && method.id !== ladderVmId),
|
|
428
|
-
unlockKeyVerificationMethod({
|
|
429
|
-
did,
|
|
430
|
-
keyAgreement: unlockKeys.keyAgreement
|
|
431
|
-
}),
|
|
432
|
-
...(ladderVmKey !== undefined
|
|
655
|
+
const existingMethods = (doc.verificationMethod ??
|
|
656
|
+
[]);
|
|
657
|
+
// The publish polarity commits the credential's update-key hash through
|
|
658
|
+
// the seam's `commitHashes`, so on a ladder-signed entry it lands after
|
|
659
|
+
// the acting rung's own carry-over hash (`decisions/0007` order).
|
|
660
|
+
const commitHashes = polarity === 'publish' && publishesAuthority && !hashCommitted
|
|
661
|
+
? [keyHash]
|
|
662
|
+
: [];
|
|
663
|
+
const nextKeyHashes = polarity === 'publish'
|
|
664
|
+
? undefined
|
|
665
|
+
: published.nextKeyHashes.filter(hash => !removedHashes.has(hash));
|
|
666
|
+
// A torn self-enrollment leaves a revealed rung in `updateKeys`; the
|
|
667
|
+
// remove polarity strikes it in the same entry as its hash, keeping the
|
|
668
|
+
// carry-over invariant self-consistent. On the publish polarity and the
|
|
669
|
+
// ordinary committed-only removal this is the published set unchanged.
|
|
670
|
+
const statedUpdateKeys = polarity === 'publish'
|
|
671
|
+
? undefined
|
|
672
|
+
: published.updateKeys.filter(key => !removedKeys.has(key));
|
|
673
|
+
const installedLadderVmKey = publishesAuthority ? ladderVmKey : undefined;
|
|
674
|
+
const verificationMethods = polarity === 'publish'
|
|
433
675
|
? [
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
676
|
+
...existingMethods.filter(method => method.id !== (publishesKey ? vmId : undefined) &&
|
|
677
|
+
method.id !== (publishesAuthority ? ladderVmId : undefined)),
|
|
678
|
+
...(publishesKey
|
|
679
|
+
? [
|
|
680
|
+
unlockKeyVerificationMethod({
|
|
681
|
+
did,
|
|
682
|
+
keyAgreement: unlockKeys.keyAgreement
|
|
683
|
+
})
|
|
684
|
+
]
|
|
685
|
+
: []),
|
|
686
|
+
...(installedLadderVmKey !== undefined
|
|
687
|
+
? [
|
|
688
|
+
ladderVerificationMethod({
|
|
689
|
+
controller: did,
|
|
690
|
+
publicKeyMultibase: installedLadderVmKey
|
|
691
|
+
})
|
|
692
|
+
]
|
|
693
|
+
: [])
|
|
438
694
|
]
|
|
439
|
-
:
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
695
|
+
: existingMethods.filter(method => method.id === undefined || !struckIds.has(method.id));
|
|
696
|
+
// On the remove polarity every relation drops the struck ids: the
|
|
697
|
+
// credential's entry sits under `keyAgreement` alone and the ladder VM
|
|
698
|
+
// under `assertionMethod` and `capabilityDelegation` alone, so one
|
|
699
|
+
// filter serves all five without restating either placement here.
|
|
700
|
+
const relation = (ids) => polarity === 'publish'
|
|
701
|
+
? relationIds(ids)
|
|
702
|
+
: relationIds(ids).filter(id => !struckIds.has(id));
|
|
703
|
+
const keyAgreement = polarity === 'publish'
|
|
704
|
+
? publishesKey
|
|
705
|
+
? [...new Set([...relationIds(doc.keyAgreement), vmId])]
|
|
706
|
+
: relationIds(doc.keyAgreement)
|
|
707
|
+
: relation(doc.keyAgreement);
|
|
708
|
+
// The ladder VM's two relations, and only those: the asymmetry is what
|
|
709
|
+
// recognizes it (`ladderVmIds`) and what keeps it out of every client
|
|
710
|
+
// listing.
|
|
711
|
+
const withLadderVm = (ids) => installedLadderVmKey === undefined || ladderVmId === undefined
|
|
712
|
+
? relationIds(ids)
|
|
713
|
+
: [...new Set([...relationIds(ids), ladderVmId])];
|
|
714
|
+
const assertionMethod = polarity === 'publish'
|
|
715
|
+
? withLadderVm(doc.assertionMethod)
|
|
716
|
+
: relation(doc.assertionMethod);
|
|
717
|
+
const capabilityDelegation = polarity === 'publish'
|
|
718
|
+
? withLadderVm(doc.capabilityDelegation)
|
|
719
|
+
: relation(doc.capabilityDelegation);
|
|
720
|
+
return {
|
|
721
|
+
// The byoe context that defines a commitment entry's terms is
|
|
722
|
+
// installed at genesis and carried forward by every update, so no
|
|
723
|
+
// edit re-appends it.
|
|
724
|
+
...(statedUpdateKeys !== undefined
|
|
725
|
+
? { updateKeys: statedUpdateKeys }
|
|
726
|
+
: {}),
|
|
727
|
+
...(nextKeyHashes !== undefined ? { nextKeyHashes } : {}),
|
|
728
|
+
...(commitHashes.length > 0 ? { commitHashes } : {}),
|
|
729
|
+
verificationMethods,
|
|
730
|
+
authentication: relation(doc.authentication),
|
|
731
|
+
assertionMethod,
|
|
732
|
+
keyAgreement,
|
|
733
|
+
capabilityInvocation: relation(doc.capabilityInvocation),
|
|
734
|
+
capabilityDelegation
|
|
735
|
+
};
|
|
736
|
+
}
|
|
478
737
|
});
|
|
479
|
-
|
|
738
|
+
const settledHead = outcome.updated ?? outcome.published;
|
|
480
739
|
return {
|
|
481
|
-
did:
|
|
482
|
-
doc:
|
|
483
|
-
log:
|
|
484
|
-
ladderVm: ladderVmReport
|
|
740
|
+
did: settledHead.did,
|
|
741
|
+
doc: settledHead.doc,
|
|
742
|
+
log: settledHead.log,
|
|
743
|
+
ladderVm: ladderVmReport
|
|
485
744
|
};
|
|
486
745
|
}
|
|
487
746
|
//# sourceMappingURL=standingWebvh.js.map
|