@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
package/dist/webvh/didWebvh.js
CHANGED
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* key-agreement key (under `keyAgreement`, the source of record for
|
|
22
22
|
* user-key-wrap recipient keys). The genesis comes in two flavors: a wallet
|
|
23
23
|
* that keeps a KMS supplies its `didWebKeys` map and the document gains one
|
|
24
|
-
* server-held key, the KMS `authentication` key (a
|
|
25
|
-
* a wallet with no KMS supplies no map and the document
|
|
26
|
-
* only
|
|
27
|
-
*
|
|
24
|
+
* server-held key, the KMS `authentication` key (a DIDAuth signing key the
|
|
25
|
+
* document publishes); a wallet with no KMS supplies no map and the document
|
|
26
|
+
* holds client keys only, permanently -- no later entry adds the KMS key to a
|
|
27
|
+
* document that published without it. In either flavor every other relation
|
|
28
28
|
* lists client keys only. In particular no server-held key may appear under
|
|
29
29
|
* `keyAgreement` (no server key is a wrap target) or under `assertionMethod`
|
|
30
30
|
* (membership there is what entitles a key to issue assertions as the account
|
|
@@ -35,8 +35,7 @@
|
|
|
35
35
|
* glue: a `Signer` bridge over a client-held update-key seed, the idempotent,
|
|
36
36
|
* crash-resumable provisioning flow (`ensureDidWebvh`), the per-client
|
|
37
37
|
* update-key rotation ceremony (`rotateWebvhUpdateKey`), the two-entry client
|
|
38
|
-
* enrollment ceremony (`enrollWebvhClient`)
|
|
39
|
-
* path for the did:web relationship bindings (`repairKeyBindings`). Update-key
|
|
38
|
+
* enrollment ceremony (`enrollWebvhClient`). Update-key
|
|
40
39
|
* seeds are minted here but persisted by the caller -- with client-held keys a
|
|
41
40
|
* lost seed is lost update authority, so every publish is preceded by a
|
|
42
41
|
* caller-persisted write.
|
|
@@ -71,10 +70,11 @@ import { equalBytes } from '@noble/ciphers/utils.js';
|
|
|
71
70
|
import { sha256 } from '@noble/hashes/sha2.js';
|
|
72
71
|
import { base58, base64urlnopad } from '@scure/base';
|
|
73
72
|
import { VOCAB_CONTEXT_URL } from 'byoe-context';
|
|
74
|
-
import {
|
|
73
|
+
import { DID_LOG_RESOURCE, ID_COLLECTION } from '../space/collections.js';
|
|
75
74
|
import { ResourceLogContinuityError } from '@interop/vh-resource-log';
|
|
75
|
+
import { putDidWebProjection } from './didWebProjection.js';
|
|
76
76
|
import { multibaseOf } from './didWeb.js';
|
|
77
|
-
import { accountLogPinId, checkAccountLogContinuity } from './verifyLog.js';
|
|
77
|
+
import { accountLogPinId, checkAccountLogContinuity, checkAndAdvanceAccountLogPin } from './verifyLog.js';
|
|
78
78
|
/**
|
|
79
79
|
* The Multikey verification-method type the did:webvh data model uses for both
|
|
80
80
|
* the Ed25519 (authentication/assertionMethod/capability*) and X25519
|
|
@@ -339,9 +339,9 @@ export function assertCanonicalClientKeys({ signingKeyMultibase, keyAgreementKey
|
|
|
339
339
|
* The method is listed under `assertionMethod` and `capabilityDelegation`
|
|
340
340
|
* ONLY -- no `authentication`, no `capabilityInvocation`, no `keyAgreement`
|
|
341
341
|
* twin, and no marker property. Recognition is by that relation asymmetry
|
|
342
|
-
* (`ladderVmIds
|
|
343
|
-
* absent from `capabilityInvocation` is the
|
|
344
|
-
* structurally out of every client listing.
|
|
342
|
+
* (`ladderVmIds`, in the shared account-document readers): a
|
|
343
|
+
* `capabilityDelegation` member absent from `capabilityInvocation` is the
|
|
344
|
+
* ladder VM, which also keeps it structurally out of every client listing.
|
|
345
345
|
*
|
|
346
346
|
* Because the key is derived, a reinstall republishes the SAME key under the
|
|
347
347
|
* SAME id, and a still-unexpired delegation it signed resumes verifying the
|
|
@@ -600,7 +600,7 @@ function assembleWebvhVerificationMethods({ controllerTemplate, didWebKeys, clie
|
|
|
600
600
|
* @param options.updateKeyPublicKeyMultibase {string}
|
|
601
601
|
* @param options.nextKeyHashes {string[]}
|
|
602
602
|
* @param options.signer {Signer}
|
|
603
|
-
* @returns {Promise<
|
|
603
|
+
* @returns {Promise<CreatedWebvhLog>}
|
|
604
604
|
*/
|
|
605
605
|
async function createWebvhLog({ wasServerUrl, spaceId, didWebKeys, clientKeys, ladderVm, updateKeyPublicKeyMultibase, nextKeyHashes, signer }) {
|
|
606
606
|
const { host } = new URL(wasServerUrl);
|
|
@@ -633,7 +633,19 @@ async function createWebvhLog({ wasServerUrl, spaceId, didWebKeys, clientKeys, l
|
|
|
633
633
|
if (!result.webDoc) {
|
|
634
634
|
throw new Error('createDID did not return a webDoc despite alsoKnownAsWeb.');
|
|
635
635
|
}
|
|
636
|
-
return {
|
|
636
|
+
return {
|
|
637
|
+
log: result.log,
|
|
638
|
+
webDoc: result.webDoc,
|
|
639
|
+
did: result.did,
|
|
640
|
+
// Detached: `createDID` hands back the very object the genesis entry
|
|
641
|
+
// carries as its `state`, and a read-side head's document is a copy of
|
|
642
|
+
// the entry's state. Cloning here makes both producers of a
|
|
643
|
+
// {@link PublishedWebvhLog} alias the same way, so a caller that mutates
|
|
644
|
+
// a document it was handed can never edit a log entry through it.
|
|
645
|
+
doc: structuredClone(result.doc),
|
|
646
|
+
updateKeys: result.meta.updateKeys ?? [],
|
|
647
|
+
nextKeyHashes: result.meta.nextKeyHashes ?? []
|
|
648
|
+
};
|
|
637
649
|
}
|
|
638
650
|
/**
|
|
639
651
|
* Builds a genesis entry's `nextKeyHashes`: the active update key's own
|
|
@@ -690,7 +702,7 @@ export async function genesisNextKeyHashes({ activeKeyMultibase, stagedKeyMultib
|
|
|
690
702
|
* @param options.updateKeyPublicKeyMultibase {string} ladder rung 0's key
|
|
691
703
|
* @param options.nextKeyHashes {string[]} [hash(rung 0), hash(rung 1)]
|
|
692
704
|
* @param options.signer {Signer} ladder rung 0's signer
|
|
693
|
-
* @returns {Promise<
|
|
705
|
+
* @returns {Promise<CreatedWebvhLog>}
|
|
694
706
|
*/
|
|
695
707
|
export async function createLadderAnchoredWebvhLog({ wasServerUrl, spaceId, didWebKeys, ladderVmKeyMultibase, credentialKeyAgreementMethod, updateKeyPublicKeyMultibase, nextKeyHashes, signer }) {
|
|
696
708
|
return createWebvhLog({
|
|
@@ -760,17 +772,20 @@ export async function withLogConflictRetry(run) {
|
|
|
760
772
|
* @param options.log {DIDLog}
|
|
761
773
|
* @param [options.ifMatch] {string} publish only if the log is unchanged
|
|
762
774
|
* @param [options.ifNoneMatch] {boolean} publish only if the log is absent
|
|
763
|
-
* @returns {Promise<
|
|
775
|
+
* @returns {Promise<{ etag?: string }>} the new validator of the log just
|
|
776
|
+
* written, for a stage building its entry on this head; absent against a
|
|
777
|
+
* backend that serves no ETags
|
|
764
778
|
*/
|
|
765
779
|
export async function putLogResource({ store, log, ifMatch, ifNoneMatch }) {
|
|
766
780
|
try {
|
|
767
|
-
await store.putIdResource({
|
|
781
|
+
const written = await store.putIdResource({
|
|
768
782
|
resourceId: DID_LOG_RESOURCE,
|
|
769
783
|
content: logToJsonlString(log),
|
|
770
784
|
contentType: 'text/jsonl',
|
|
771
785
|
ifMatch,
|
|
772
786
|
ifNoneMatch
|
|
773
787
|
});
|
|
788
|
+
return written?.etag !== undefined ? { etag: written.etag } : {};
|
|
774
789
|
}
|
|
775
790
|
catch (err) {
|
|
776
791
|
if (err?.name === 'PreconditionFailedError') {
|
|
@@ -779,6 +794,45 @@ export async function putLogResource({ store, log, ifMatch, ifNoneMatch }) {
|
|
|
779
794
|
throw err;
|
|
780
795
|
}
|
|
781
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* THE POSTAMBLE: publishes `did.jsonl` -- the log only, never `did.json` (a
|
|
799
|
+
* caller writing through a bridge delegation is authorized for nothing else)
|
|
800
|
+
* -- and advances the caller's chain-head pin to what it just published, so a
|
|
801
|
+
* host rolling the log back straight afterwards is refused on the next read.
|
|
802
|
+
*
|
|
803
|
+
* So an entry published here leaves the `did:web` projection standing at
|
|
804
|
+
* whatever it said before: a ceremony whose entry REMOVES inventory (a
|
|
805
|
+
* removal, a retirement) must republish the projection itself before the
|
|
806
|
+
* entry lands, and a projection left behind by one that did not is mended by
|
|
807
|
+
* `ensureDidWebProjection` at the next visit holding a writer for the `id`
|
|
808
|
+
* collection (a controller-invoking client, or a transient visit under its
|
|
809
|
+
* generation delegation).
|
|
810
|
+
* The publish is conditional on the read the entry was built on; a lost race
|
|
811
|
+
* surfaces as a {@link WebvhLogConflictError} (the mapping lives in
|
|
812
|
+
* {@link putLogResource}).
|
|
813
|
+
*
|
|
814
|
+
* The two halves are one function on purpose. Separating them is what leaves
|
|
815
|
+
* a pin standing behind an entry this client itself published, the gap that
|
|
816
|
+
* already forced `BuiltOnHeadNotReachedError` into existence as a
|
|
817
|
+
* compensating class.
|
|
818
|
+
*
|
|
819
|
+
* @param options {object}
|
|
820
|
+
* @param options.store {object} anything with the seam's `putIdResource`
|
|
821
|
+
* @param options.log {DIDLog} the log this entry produced
|
|
822
|
+
* @param [options.ifMatch] {string} publish only if `did.jsonl` is unchanged
|
|
823
|
+
* @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
|
|
824
|
+
* pins; the pin advances only when a `logId` names its slot
|
|
825
|
+
* @param [options.logId] {string} the log's pin slot
|
|
826
|
+
* @returns {Promise<{ etag?: string }>} the new validator of the log this
|
|
827
|
+
* entry just published, for a stage building on the post-entry head
|
|
828
|
+
*/
|
|
829
|
+
export async function publishEntryPinned({ store, log, ifMatch, pinStore, logId }) {
|
|
830
|
+
const written = await putLogResource({ store, log, ifMatch });
|
|
831
|
+
if (pinStore && logId !== undefined) {
|
|
832
|
+
await pinStore.write({ logId, pin: pinOfLog(log) });
|
|
833
|
+
}
|
|
834
|
+
return written;
|
|
835
|
+
}
|
|
782
836
|
/**
|
|
783
837
|
* Publishes an already-created log: PUT `did.jsonl` (`text/jsonl`) then PUT
|
|
784
838
|
* `did.json` from `webDoc` (`application/did+json`, adopting the webvh
|
|
@@ -795,8 +849,11 @@ export async function putLogResource({ store, log, ifMatch, ifNoneMatch }) {
|
|
|
795
849
|
* after the log's compare-and-swap was WON, so it is already serialized behind
|
|
796
850
|
* that win; the log is the source of truth and the projection a derived cache;
|
|
797
851
|
* and {@link concludeWithPublishedLog} re-derives and republishes the
|
|
798
|
-
* projection from the resolved log on
|
|
799
|
-
*
|
|
852
|
+
* projection from the resolved log on the no-op path of every ceremony that
|
|
853
|
+
* reaches this function, so a torn publish on one of those paths is healed by
|
|
854
|
+
* the next run of the same ceremony. That reach is the controller-invoking
|
|
855
|
+
* paths alone; `ensureDidWebProjection` is what mends a projection a
|
|
856
|
+
* ladder-signed entry ({@link publishEntryPinned}) left behind.
|
|
800
857
|
*
|
|
801
858
|
* @param options {object}
|
|
802
859
|
* @param options.idStore {WebvhIdStore}
|
|
@@ -804,15 +861,19 @@ export async function putLogResource({ store, log, ifMatch, ifNoneMatch }) {
|
|
|
804
861
|
* @param options.webDoc {object}
|
|
805
862
|
* @param [options.ifMatch] {string} publish only if `did.jsonl` is unchanged
|
|
806
863
|
* @param [options.ifNoneMatch] {boolean} publish only if `did.jsonl` is absent
|
|
807
|
-
* @returns {Promise<
|
|
864
|
+
* @returns {Promise<{ etag?: string }>} the LOG's new validator, never the
|
|
865
|
+
* projection's: the projection is a derived cache, and only the log's ETag
|
|
866
|
+
* is a precondition anything is built on
|
|
808
867
|
*/
|
|
809
868
|
export async function publishWebvhLog({ idStore, log, webDoc, ifMatch, ifNoneMatch }) {
|
|
810
|
-
await putLogResource({
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
869
|
+
const written = await putLogResource({
|
|
870
|
+
store: idStore,
|
|
871
|
+
log,
|
|
872
|
+
ifMatch,
|
|
873
|
+
ifNoneMatch
|
|
815
874
|
});
|
|
875
|
+
await putDidWebProjection({ store: idStore, webDoc });
|
|
876
|
+
return written;
|
|
816
877
|
}
|
|
817
878
|
/**
|
|
818
879
|
* The shared guard-and-publish tail of every ceremony that extends the log
|
|
@@ -827,13 +888,13 @@ export async function publishWebvhLog({ idStore, log, webDoc, ifMatch, ifNoneMat
|
|
|
827
888
|
* @param [options.updated.webDoc] {object}
|
|
828
889
|
* @param [options.ifMatch] {string} the ETag of the read this entry was built
|
|
829
890
|
* on
|
|
830
|
-
* @returns {Promise<
|
|
891
|
+
* @returns {Promise<{ etag?: string }>} the log's new validator
|
|
831
892
|
*/
|
|
832
893
|
export async function publishUpdatedLog({ idStore, updated, ifMatch }) {
|
|
833
894
|
if (!updated.webDoc) {
|
|
834
895
|
throw new Error('did:webvh: updateDID returned no webDoc despite the did:web alsoKnownAs.');
|
|
835
896
|
}
|
|
836
|
-
|
|
897
|
+
return publishWebvhLog({
|
|
837
898
|
idStore,
|
|
838
899
|
log: updated.log,
|
|
839
900
|
webDoc: updated.webDoc,
|
|
@@ -841,20 +902,116 @@ export async function publishUpdatedLog({ idStore, updated, ifMatch }) {
|
|
|
841
902
|
});
|
|
842
903
|
}
|
|
843
904
|
/**
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
847
|
-
*
|
|
905
|
+
* The served `keys.json`, read for the two members this module acts on. A body
|
|
906
|
+
* of any other shape reads as an empty map rather than throwing: the resource
|
|
907
|
+
* is host-held bookkeeping, and the caller's next step is a rewrite either
|
|
908
|
+
* way.
|
|
909
|
+
*
|
|
910
|
+
* @param content {unknown}
|
|
911
|
+
* @returns {object} the members present, as a partial key map
|
|
912
|
+
*/
|
|
913
|
+
function servedKeyMap(content) {
|
|
914
|
+
const map = content;
|
|
915
|
+
const { vmId, kmsKeyId } = map?.authentication ?? {};
|
|
916
|
+
const did = map?.webvh?.did;
|
|
917
|
+
return {
|
|
918
|
+
...(typeof vmId === 'string' && typeof kmsKeyId === 'string'
|
|
919
|
+
? { authentication: { vmId, kmsKeyId } }
|
|
920
|
+
: {}),
|
|
921
|
+
...(typeof did === 'string' ? { webvh: { did } } : {})
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Writes `keys.json` v2: the KMS binding plus the `webvh` block. Exported for
|
|
926
|
+
* the ladder-anchored ensure, whose create path records the account DID the
|
|
927
|
+
* same way the enrolled-client one does.
|
|
928
|
+
*
|
|
929
|
+
* The body is CONSTRUCTED from the two members the map carries rather than
|
|
930
|
+
* spread from the caller's, so a legacy `keyAgreement` binding a stored map
|
|
931
|
+
* still holds is dropped by this rewrite.
|
|
932
|
+
*
|
|
933
|
+
* This is the genesis' rewrite of the map the KMS stage created one stage
|
|
934
|
+
* earlier, so it carries that write's ETag as its `ifMatch`. A caller holding
|
|
935
|
+
* no ETag (a backend that versions nothing) writes unconditionally.
|
|
936
|
+
*
|
|
937
|
+
* A lost precondition CONVERGES rather than propagating, since the genesis
|
|
938
|
+
* entry has already published by the time this runs and a bookkeeping resource
|
|
939
|
+
* must not fail a ceremony standing behind it: the served map is re-read, a
|
|
940
|
+
* map already naming this DID under this binding is left alone, and anything
|
|
941
|
+
* else is rewritten once under the served ETag. A second lost precondition
|
|
942
|
+
* propagates. Without the store's optional read there is nothing to converge
|
|
943
|
+
* on, and the first failure propagates.
|
|
848
944
|
*
|
|
849
945
|
* @param options {object}
|
|
850
946
|
* @param options.idStore {WebvhIdStore}
|
|
851
|
-
* @param options.didWebKeys {DidWebKeyMap}
|
|
947
|
+
* @param options.didWebKeys {DidWebKeyMap} the binding to record, which on
|
|
948
|
+
* the create path is the one this run published in the genesis entry
|
|
852
949
|
* @param options.webvh {DidWebvhBlock}
|
|
950
|
+
* @param [options.ifMatch] {string} the ETag the KMS stage's own write
|
|
951
|
+
* returned
|
|
952
|
+
* @returns {Promise<void>}
|
|
953
|
+
*/
|
|
954
|
+
export async function writeKeysJson({ idStore, didWebKeys, webvh, ifMatch }) {
|
|
955
|
+
const content = {
|
|
956
|
+
authentication: didWebKeys.authentication,
|
|
957
|
+
webvh
|
|
958
|
+
};
|
|
959
|
+
try {
|
|
960
|
+
await idStore.putKeyMap({
|
|
961
|
+
content,
|
|
962
|
+
...(ifMatch !== undefined && { ifMatch })
|
|
963
|
+
});
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
catch (err) {
|
|
967
|
+
const lostRace = err?.name === 'PreconditionFailedError';
|
|
968
|
+
if (!lostRace || !idStore.getKeyMapRaw) {
|
|
969
|
+
throw err;
|
|
970
|
+
}
|
|
971
|
+
const served = await idStore.getKeyMapRaw();
|
|
972
|
+
const servedMap = servedKeyMap(served?.content);
|
|
973
|
+
if (servedMap.webvh?.did === webvh.did &&
|
|
974
|
+
servedMap.authentication?.vmId === content.authentication.vmId) {
|
|
975
|
+
// The winner recorded this DID under this binding already: done.
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
await idStore.putKeyMap({
|
|
979
|
+
content,
|
|
980
|
+
...(served?.etag !== undefined && { ifMatch: served.etag })
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Records the account DID into a `keys.json` carrying a KMS binding and no (or
|
|
986
|
+
* a stale) `webvh` block -- the state a run torn between its genesis entry and
|
|
987
|
+
* its rewrite leaves behind. It is the adoption path's half of that rewrite,
|
|
988
|
+
* and the binding comes from the SERVED map: the run that published the log
|
|
989
|
+
* recorded it, while this run's own map may name a key that log never
|
|
990
|
+
* published.
|
|
991
|
+
*
|
|
992
|
+
* A no-op when the store offers no read, when the served map carries no
|
|
993
|
+
* binding, and when it already names this DID.
|
|
994
|
+
*
|
|
995
|
+
* @param options {object}
|
|
996
|
+
* @param options.idStore {WebvhIdStore}
|
|
997
|
+
* @param options.did {string} the DID the adopted log resolves to
|
|
853
998
|
* @returns {Promise<void>}
|
|
854
999
|
*/
|
|
855
|
-
export async function
|
|
856
|
-
|
|
857
|
-
|
|
1000
|
+
export async function backfillKeyMapWebvhBlock({ idStore, did }) {
|
|
1001
|
+
if (!idStore.getKeyMapRaw) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const served = await idStore.getKeyMapRaw();
|
|
1005
|
+
const servedMap = servedKeyMap(served?.content);
|
|
1006
|
+
if (!servedMap.authentication || servedMap.webvh?.did === did) {
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
await writeKeysJson({
|
|
1010
|
+
idStore,
|
|
1011
|
+
didWebKeys: { authentication: servedMap.authentication },
|
|
1012
|
+
webvh: { did },
|
|
1013
|
+
...(served?.etag !== undefined && { ifMatch: served.etag })
|
|
1014
|
+
});
|
|
858
1015
|
}
|
|
859
1016
|
/**
|
|
860
1017
|
* Reads and resolves the published `did.jsonl`, or returns `undefined` when
|
|
@@ -883,7 +1040,9 @@ export async function writeKeysJson({ idStore, didWebKeys, webvh }) {
|
|
|
883
1040
|
* refused as a `rollback` instead of read as `undefined`.
|
|
884
1041
|
*
|
|
885
1042
|
* @param options {object}
|
|
886
|
-
* @param options.idStore {WebvhIdStore}
|
|
1043
|
+
* @param options.idStore {Pick<WebvhIdStore, 'getIdResourceRaw'>} the read
|
|
1044
|
+
* half of the seam alone, so a caller holding a narrower store (a bridge
|
|
1045
|
+
* delegation's read + PUT pair) passes it directly
|
|
887
1046
|
* @param [options.expectedDid] {string} the DID the log must resolve to
|
|
888
1047
|
* @param [options.pinStore] {ResourceLogPinStore} this client's chain-head
|
|
889
1048
|
* pins for the account log
|
|
@@ -917,20 +1076,7 @@ export async function readPublishedLog({ idStore, expectedDid, pinStore, logId }
|
|
|
917
1076
|
if (resolved.meta.error || !resolved.did || !resolved.doc) {
|
|
918
1077
|
throw new Error(`did:webvh: existing did.jsonl failed to resolve (${resolved.meta.error}).`);
|
|
919
1078
|
}
|
|
920
|
-
|
|
921
|
-
throw new Error('did:webvh: the published did.jsonl resolves to a different DID ' +
|
|
922
|
-
`(${resolved.did}) than expected (${expectedDid}).`);
|
|
923
|
-
}
|
|
924
|
-
if (pinned) {
|
|
925
|
-
const pin = await pinned.store.read({ logId: pinned.logId });
|
|
926
|
-
const served = checkAccountLogContinuity({ log, pin });
|
|
927
|
-
// Advanced only when the served head is genuinely ahead of the pin: the
|
|
928
|
-
// check above has already refused everything that is not.
|
|
929
|
-
if (!pin || pin.head !== served.head) {
|
|
930
|
-
await pinned.store.write({ logId: pinned.logId, pin: served });
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
return {
|
|
1079
|
+
const published = {
|
|
934
1080
|
log,
|
|
935
1081
|
did: resolved.did,
|
|
936
1082
|
doc: resolved.doc,
|
|
@@ -938,6 +1084,77 @@ export async function readPublishedLog({ idStore, expectedDid, pinStore, logId }
|
|
|
938
1084
|
nextKeyHashes: resolved.meta.nextKeyHashes ?? [],
|
|
939
1085
|
etag: read.etag
|
|
940
1086
|
};
|
|
1087
|
+
assertPublishedLogDid({ published, expectedDid });
|
|
1088
|
+
if (pinned) {
|
|
1089
|
+
await checkAndAdvanceAccountLogPin({
|
|
1090
|
+
pinStore: pinned.store,
|
|
1091
|
+
logId: pinned.logId,
|
|
1092
|
+
log
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
return published;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* The substituted-account refusal on its own: a resolved head that is not the
|
|
1099
|
+
* DID the caller expected is refused rather than built on. Stated once so a
|
|
1100
|
+
* fresh read and a caller-threaded head refuse identically.
|
|
1101
|
+
*
|
|
1102
|
+
* A ceremony that takes an already-read head from its caller (the transient
|
|
1103
|
+
* visit's one-read composition, where the readiness stage hands its verified
|
|
1104
|
+
* head to the enrollment) runs this explicitly: the read that would otherwise
|
|
1105
|
+
* have run it never happened, and a head resolving to another DID must not
|
|
1106
|
+
* become the entry's basis just because it arrived by parameter.
|
|
1107
|
+
*
|
|
1108
|
+
* @param options {object}
|
|
1109
|
+
* @param options.published {PublishedWebvhLog} the resolved head
|
|
1110
|
+
* @param [options.expectedDid] {string} the DID it must resolve to; absent,
|
|
1111
|
+
* the head is accepted (the caller discovering the DID from the log itself)
|
|
1112
|
+
* @returns {PublishedWebvhLog} the head verbatim
|
|
1113
|
+
*/
|
|
1114
|
+
export function assertPublishedLogDid({ published, expectedDid }) {
|
|
1115
|
+
if (expectedDid !== undefined && published.did !== expectedDid) {
|
|
1116
|
+
throw new Error('did:webvh: the published did.jsonl resolves to a different DID ' +
|
|
1117
|
+
`(${published.did}) than expected (${expectedDid}).`);
|
|
1118
|
+
}
|
|
1119
|
+
return published;
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* {@link readPublishedLog} for the ceremonies whose premise is a log that
|
|
1123
|
+
* already exists: an absent `did.jsonl` is a refusal rather than a state to
|
|
1124
|
+
* branch on, so the caller gets a `PublishedWebvhLog` or an error. The
|
|
1125
|
+
* `missingMessage` is the caller's own phrasing of what there is nothing to do
|
|
1126
|
+
* against ("nothing to enroll into", "nothing to recover"), since the read
|
|
1127
|
+
* itself cannot know which ceremony is standing on it.
|
|
1128
|
+
*
|
|
1129
|
+
* Every other option, and every check behind them -- the `expectedDid`
|
|
1130
|
+
* refusal and the chain-head pin's rollback / fork / identity-switch
|
|
1131
|
+
* refusals -- is {@link readPublishedLog}'s verbatim. Each attempt of a
|
|
1132
|
+
* conflict-retried ceremony reads for itself, so the continuity check runs on
|
|
1133
|
+
* the read the compare-and-swap publish is conditioned on rather than only on
|
|
1134
|
+
* an orchestrator's pre-read.
|
|
1135
|
+
*
|
|
1136
|
+
* @param options {object}
|
|
1137
|
+
* @param options.idStore {Pick<WebvhIdStore, 'getIdResourceRaw'>}
|
|
1138
|
+
* @param [options.expectedDid] {string} the DID the log must resolve to
|
|
1139
|
+
* @param [options.pinStore] {ResourceLogPinStore} this client's chain-head
|
|
1140
|
+
* pins for the log being read
|
|
1141
|
+
* @param [options.logId] {string} the log's pin-slot key; required whenever
|
|
1142
|
+
* a `pinStore` is supplied
|
|
1143
|
+
* @param [options.missingMessage] {string} the thrown `Error`'s message when
|
|
1144
|
+
* the log is absent
|
|
1145
|
+
* @returns {Promise<PublishedWebvhLog>}
|
|
1146
|
+
*/
|
|
1147
|
+
export async function readPublishedLogOrThrow({ idStore, expectedDid, pinStore, logId, missingMessage = 'did:webvh: did.jsonl is missing.' }) {
|
|
1148
|
+
const published = await readPublishedLog({
|
|
1149
|
+
idStore,
|
|
1150
|
+
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
1151
|
+
...(pinStore ? { pinStore } : {}),
|
|
1152
|
+
...(logId !== undefined ? { logId } : {})
|
|
1153
|
+
});
|
|
1154
|
+
if (!published) {
|
|
1155
|
+
throw new Error(missingMessage);
|
|
1156
|
+
}
|
|
1157
|
+
return published;
|
|
941
1158
|
}
|
|
942
1159
|
/**
|
|
943
1160
|
* The chain-head pin a log establishes: the genesis entry's method and SCID
|
|
@@ -969,16 +1186,22 @@ export function servedHead(log) {
|
|
|
969
1186
|
* already-revoked no-op. All of them used to infer completion from `did.jsonl`
|
|
970
1187
|
* alone, which is a half of the state: {@link publishWebvhLog} writes the log
|
|
971
1188
|
* and its `did:web` projection in two non-atomic PUTs, so a crash between them
|
|
972
|
-
* leaves a `did.jsonl` that is complete beside a `did.json` that lags it
|
|
973
|
-
* forever (nothing else republishes the projection).
|
|
1189
|
+
* leaves a `did.jsonl` that is complete beside a `did.json` that lags it.
|
|
974
1190
|
*
|
|
975
1191
|
* So the projection is re-derived from the resolved log and re-PUT
|
|
976
1192
|
* unconditionally rather than compared first: the write is idempotent and one
|
|
977
1193
|
* request either way, and the resolved log is the source of truth for what the
|
|
978
1194
|
* projection must say. A ceremony that no-ops on the log therefore still heals
|
|
979
|
-
* a torn earlier publish. The projection PUT is deliberately
|
|
980
|
-
* here too: healing it is the whole point, and the log it was
|
|
981
|
-
* the state this call just read and resolved.
|
|
1195
|
+
* a torn earlier publish OF THAT CEREMONY. The projection PUT is deliberately
|
|
1196
|
+
* unconditional here too: healing it is the whole point, and the log it was
|
|
1197
|
+
* derived from is the state this call just read and resolved.
|
|
1198
|
+
*
|
|
1199
|
+
* The reach is what to hold on to: every caller here invokes as the account's
|
|
1200
|
+
* controller, so this heals nothing for the ladder-signed entries that publish
|
|
1201
|
+
* through {@link publishEntryPinned} and write the log alone. Those are mended
|
|
1202
|
+
* by their own ceremony's pre-entry projection PUT and, failing that, by
|
|
1203
|
+
* `ensureDidWebProjection` at the next visit that holds an `id`-collection
|
|
1204
|
+
* writer.
|
|
982
1205
|
*
|
|
983
1206
|
* @param options {object}
|
|
984
1207
|
* @param options.idStore {WebvhIdStore}
|
|
@@ -987,10 +1210,9 @@ export function servedHead(log) {
|
|
|
987
1210
|
* resolved document
|
|
988
1211
|
*/
|
|
989
1212
|
export async function concludeWithPublishedLog({ idStore, published }) {
|
|
990
|
-
await
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
contentType: 'application/did+json'
|
|
1213
|
+
await putDidWebProjection({
|
|
1214
|
+
store: idStore,
|
|
1215
|
+
webDoc: generateParallelDidWeb(published.did, published.doc)
|
|
994
1216
|
});
|
|
995
1217
|
return { did: published.did, doc: published.doc };
|
|
996
1218
|
}
|
|
@@ -1019,6 +1241,22 @@ export function effectiveParameters(log) {
|
|
|
1019
1241
|
}
|
|
1020
1242
|
return out;
|
|
1021
1243
|
}
|
|
1244
|
+
/**
|
|
1245
|
+
* The log's current `updateKeys` / `nextKeyHashes` view: the last entry's
|
|
1246
|
+
* effective parameters, or the empty pair for a log with no entries.
|
|
1247
|
+
*
|
|
1248
|
+
* The empty default is a policy choice, not a convenience: it is what makes
|
|
1249
|
+
* an unresolvable log attribute as "no rung standing" rather than throw, so
|
|
1250
|
+
* it is stated here once rather than at each attribution site.
|
|
1251
|
+
*
|
|
1252
|
+
* @param published {object}
|
|
1253
|
+
* @param published.log {DIDLog}
|
|
1254
|
+
* @returns {object}
|
|
1255
|
+
*/
|
|
1256
|
+
export function currentLogParameters(published) {
|
|
1257
|
+
const params = effectiveParameters(published.log);
|
|
1258
|
+
return params[params.length - 1] ?? { updateKeys: [], nextKeyHashes: [] };
|
|
1259
|
+
}
|
|
1022
1260
|
/**
|
|
1023
1261
|
* The `publicKeyMultibase` of every update-key seed this client holds, in
|
|
1024
1262
|
* role order (active, staged, pending).
|
|
@@ -1105,8 +1343,10 @@ function advancedSeeds({ published, multibases, updateKeys }) {
|
|
|
1105
1343
|
* @param options.wasServerUrl {string}
|
|
1106
1344
|
* @param options.spaceId {string}
|
|
1107
1345
|
* @param [options.didWebKeys] {DidWebKeyMapV2} the parsed keys.json (with any
|
|
1108
|
-
* webvh block) returned by the
|
|
1346
|
+
* webvh block) returned by the KMS-authentication stage; absent on a
|
|
1109
1347
|
* client-keys-only genesis (no KMS anywhere in the path)
|
|
1348
|
+
* @param [options.keysJsonEtag] {string} the ETag that stage's own write
|
|
1349
|
+
* returned, carried as the `ifMatch` of the rewrite that records the DID
|
|
1110
1350
|
* @param options.clientKeys {WebvhClientKeys} this client's published keys
|
|
1111
1351
|
* @param options.updateKeys {ClientWebvhUpdateKeys} already persisted
|
|
1112
1352
|
* client-local
|
|
@@ -1126,7 +1366,7 @@ export async function ensureDidWebvh(options) {
|
|
|
1126
1366
|
* @param options {object} see {@link ensureDidWebvh}
|
|
1127
1367
|
* @returns {Promise<{ did: string }>}
|
|
1128
1368
|
*/
|
|
1129
|
-
async function ensureDidWebvhOnce({ idStore, wasServerUrl, spaceId, didWebKeys, clientKeys, updateKeys, expectedDid, pinStore }) {
|
|
1369
|
+
async function ensureDidWebvhOnce({ idStore, wasServerUrl, spaceId, didWebKeys, keysJsonEtag, clientKeys, updateKeys, expectedDid, pinStore }) {
|
|
1130
1370
|
// The DID this run expects the published log to resolve to: the caller's,
|
|
1131
1371
|
// else the one keys.json already records. Undefined only on the documented
|
|
1132
1372
|
// first-contact adoption, which discovers the DID from the log itself.
|
|
@@ -1158,10 +1398,13 @@ async function ensureDidWebvhOnce({ idStore, wasServerUrl, spaceId, didWebKeys,
|
|
|
1158
1398
|
await writeKeysJson({
|
|
1159
1399
|
idStore,
|
|
1160
1400
|
didWebKeys,
|
|
1161
|
-
webvh: { did: published.did }
|
|
1401
|
+
webvh: { did: published.did },
|
|
1402
|
+
...(keysJsonEtag !== undefined && { ifMatch: keysJsonEtag })
|
|
1162
1403
|
});
|
|
1163
1404
|
}
|
|
1164
|
-
// Heals a did.json left lagging by a torn earlier publish
|
|
1405
|
+
// Heals a did.json left lagging by a torn earlier publish of this
|
|
1406
|
+
// controller-invoking path (a ladder-signed entry's lag is not reached
|
|
1407
|
+
// here; `ensureDidWebProjection` is that mender).
|
|
1165
1408
|
const { did } = await concludeWithPublishedLog({ idStore, published });
|
|
1166
1409
|
return { did };
|
|
1167
1410
|
}
|
|
@@ -1196,7 +1439,8 @@ async function ensureDidWebvhOnce({ idStore, wasServerUrl, spaceId, didWebKeys,
|
|
|
1196
1439
|
await writeKeysJson({
|
|
1197
1440
|
idStore,
|
|
1198
1441
|
didWebKeys,
|
|
1199
|
-
webvh: { did: created.did }
|
|
1442
|
+
webvh: { did: created.did },
|
|
1443
|
+
...(keysJsonEtag !== undefined && { ifMatch: keysJsonEtag })
|
|
1200
1444
|
});
|
|
1201
1445
|
}
|
|
1202
1446
|
return { did: created.did };
|
|
@@ -1380,281 +1624,4 @@ export async function assertCarryOverCommitments({ published }) {
|
|
|
1380
1624
|
}
|
|
1381
1625
|
}
|
|
1382
1626
|
}
|
|
1383
|
-
/**
|
|
1384
|
-
* The relationship references of a resolved document as verification-method
|
|
1385
|
-
* ids, tolerating embedded objects beside string references.
|
|
1386
|
-
*
|
|
1387
|
-
* @param relation {Array} the relationship array, when present
|
|
1388
|
-
* @returns {string[]}
|
|
1389
|
-
*/
|
|
1390
|
-
export function relationIds(relation) {
|
|
1391
|
-
const ids = [];
|
|
1392
|
-
for (const entry of relation ?? []) {
|
|
1393
|
-
const id = typeof entry === 'string' ? entry : entry?.id;
|
|
1394
|
-
if (id) {
|
|
1395
|
-
ids.push(id);
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
return ids;
|
|
1399
|
-
}
|
|
1400
|
-
/**
|
|
1401
|
-
* Enrolls a second wallet client into the published did:webvh document -- the
|
|
1402
|
-
* log half of the enrollment ceremony (the user key roster wrap happens first,
|
|
1403
|
-
* outside this module). Two entries, forced by prerotation (a new update key
|
|
1404
|
-
* must hash into the PREVIOUS entry's `nextKeyHashes`):
|
|
1405
|
-
*
|
|
1406
|
-
* 1. **Commit**: a sparse entry extending `nextKeyHashes` with the new
|
|
1407
|
-
* client's update-key and staged-key hashes (document and `updateKeys`
|
|
1408
|
-
* untouched).
|
|
1409
|
-
* 2. **Add**: an entry adding the new client's verification methods (its
|
|
1410
|
-
* Ed25519 key under the four signing relationships, its X25519 twin under
|
|
1411
|
-
* `keyAgreement`) and its update key to `updateKeys`.
|
|
1412
|
-
*
|
|
1413
|
-
* Both entries are signed by THIS client's active update key (quorum-of-one:
|
|
1414
|
-
* any single enrolled client can enroll). The ceremony is resumable from
|
|
1415
|
-
* durable state alone: a tear after the commit is detected by its hashes
|
|
1416
|
-
* already standing in `nextKeyHashes` (skip to the add entry), and a
|
|
1417
|
-
* completed enrollment is detected by the update key already being authorized
|
|
1418
|
-
* (no-op). Re-running with the same key set converges without forking the
|
|
1419
|
-
* log.
|
|
1420
|
-
*
|
|
1421
|
-
* Each entry publishes conditionally on the read it was built on (the add
|
|
1422
|
-
* entry on the mid-ceremony re-read), so a concurrent ceremony -- a revocation,
|
|
1423
|
-
* another enrollment -- can never be erased by this one; a lost race re-runs
|
|
1424
|
-
* from the top (see {@link withLogConflictRetry}) and rebases on the new head.
|
|
1425
|
-
*
|
|
1426
|
-
* @param options {object}
|
|
1427
|
-
* @param options.idStore {WebvhIdStore}
|
|
1428
|
-
* @param options.updateKeys {ClientWebvhUpdateKeys} THIS client's seeds
|
|
1429
|
-
* @param options.newClient {WebvhEnrollmentKeys} the enrollee's public halves
|
|
1430
|
-
* @returns {Promise<{ did: string }>}
|
|
1431
|
-
*/
|
|
1432
|
-
export async function enrollWebvhClient(options) {
|
|
1433
|
-
return withLogConflictRetry(() => enrollWebvhClientOnce(options));
|
|
1434
|
-
}
|
|
1435
|
-
/**
|
|
1436
|
-
* One attempt of {@link enrollWebvhClient}, re-invoked by the conflict retry.
|
|
1437
|
-
*
|
|
1438
|
-
* @param options {object} see {@link enrollWebvhClient}
|
|
1439
|
-
* @returns {Promise<{ did: string }>}
|
|
1440
|
-
*/
|
|
1441
|
-
async function enrollWebvhClientOnce({ idStore, updateKeys, newClient }) {
|
|
1442
|
-
let published = await readPublishedLog({ idStore });
|
|
1443
|
-
if (!published) {
|
|
1444
|
-
throw new Error('did:webvh: did.jsonl is missing; nothing to enroll into.');
|
|
1445
|
-
}
|
|
1446
|
-
const multibases = await updateKeyMultibases({ updateKeys });
|
|
1447
|
-
// Already enrolled (a completed earlier run): the new client's update key is
|
|
1448
|
-
// authorized, which only the add entry writes. Idempotent no-op on the log,
|
|
1449
|
-
// but it still heals a did.json the earlier run left lagging.
|
|
1450
|
-
if (published.updateKeys.includes(newClient.updateKeyMultibase)) {
|
|
1451
|
-
const { did } = await concludeWithPublishedLog({ idStore, published });
|
|
1452
|
-
return { did };
|
|
1453
|
-
}
|
|
1454
|
-
// Both entries are signed by this client's active update key; a log that
|
|
1455
|
-
// does not authorize it (a rotation torn elsewhere) must heal first.
|
|
1456
|
-
if (!published.updateKeys.includes(multibases.update)) {
|
|
1457
|
-
throw new Error("did:webvh: the published log does not authorize this client's active " +
|
|
1458
|
-
'update key; finalize the pending rotation before enrolling.');
|
|
1459
|
-
}
|
|
1460
|
-
const newUpdateKeyHash = await deriveNextKeyHash(newClient.updateKeyMultibase);
|
|
1461
|
-
const newStagedKeyHash = await deriveNextKeyHash(newClient.stagedUpdateKeyMultibase);
|
|
1462
|
-
// The commit entry (skipped when a torn earlier run already published it).
|
|
1463
|
-
const committed = published.nextKeyHashes.includes(newUpdateKeyHash) &&
|
|
1464
|
-
published.nextKeyHashes.includes(newStagedKeyHash);
|
|
1465
|
-
if (!committed) {
|
|
1466
|
-
// A sparse entry re-states the authorized updateKeys, and the resolver
|
|
1467
|
-
// checks each against the PREVIOUS entry's commitments -- so every
|
|
1468
|
-
// currently authorized key's hash must already stand in nextKeyHashes
|
|
1469
|
-
// (the carry-over convention). A log minted before the convention cannot
|
|
1470
|
-
// take a non-rotating entry.
|
|
1471
|
-
for (const key of published.updateKeys) {
|
|
1472
|
-
if (!published.nextKeyHashes.includes(await deriveNextKeyHash(key))) {
|
|
1473
|
-
throw new Error('did:webvh: the published log does not carry the active update ' +
|
|
1474
|
-
"keys' own hashes in nextKeyHashes (it predates the carry-over " +
|
|
1475
|
-
'commitment convention); re-provision the account before ' +
|
|
1476
|
-
'enrolling.');
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
const signer = await updateKeySigner({ seed: updateKeys.updateSeed });
|
|
1480
|
-
const updated = await updateDID({
|
|
1481
|
-
log: published.log,
|
|
1482
|
-
signer,
|
|
1483
|
-
alsoKnownAsWeb: true,
|
|
1484
|
-
// Re-stated unchanged (the library requires them explicitly while
|
|
1485
|
-
// prerotation is active); the carry-over commitments are what make the
|
|
1486
|
-
// re-statement resolvable.
|
|
1487
|
-
updateKeys: published.updateKeys,
|
|
1488
|
-
nextKeyHashes: [
|
|
1489
|
-
...new Set([
|
|
1490
|
-
...published.nextKeyHashes,
|
|
1491
|
-
newUpdateKeyHash,
|
|
1492
|
-
newStagedKeyHash
|
|
1493
|
-
])
|
|
1494
|
-
]
|
|
1495
|
-
});
|
|
1496
|
-
await publishUpdatedLog({ idStore, updated, ifMatch: published.etag });
|
|
1497
|
-
// Re-read through the same verifying path the resume case uses, so the
|
|
1498
|
-
// add entry below always builds on the published, resolved state. It must
|
|
1499
|
-
// still be the same account: the DID the first read resolved to is what
|
|
1500
|
-
// the entry just published extends.
|
|
1501
|
-
published = await readPublishedLog({ idStore, expectedDid: published.did });
|
|
1502
|
-
if (!published) {
|
|
1503
|
-
throw new Error('did:webvh: did.jsonl vanished mid-enrollment.');
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
// The add entry: the new client's two verification methods and its update
|
|
1507
|
-
// key, on top of the full existing document (updateDID replaces the
|
|
1508
|
-
// verification-method set and relationship arrays wholesale).
|
|
1509
|
-
const { did, doc, log, updateKeys: authorizedKeys, nextKeyHashes, etag } = published;
|
|
1510
|
-
const vmId = (publicKeyMultibase) => `${did}#${publicKeyMultibase}`;
|
|
1511
|
-
// The signing method is controlled by the account; the key-agreement method
|
|
1512
|
-
// alone carries the controller marker, and the pair builder refuses a
|
|
1513
|
-
// key-agreement key that is not the signing key's canonical twin.
|
|
1514
|
-
const addedMethods = markedVerificationMethodPair({
|
|
1515
|
-
controller: did,
|
|
1516
|
-
signingKeyMultibase: newClient.signingKeyMultibase,
|
|
1517
|
-
keyAgreementKeyMultibase: newClient.keyAgreementKeyMultibase
|
|
1518
|
-
});
|
|
1519
|
-
const existingMethods = (doc.verificationMethod ?? []);
|
|
1520
|
-
const verificationMethods = [
|
|
1521
|
-
...existingMethods.filter(method => !addedMethods.some(added => added.id === method.id)),
|
|
1522
|
-
...addedMethods
|
|
1523
|
-
];
|
|
1524
|
-
const withReference = (relation, id) => [...new Set([...relationIds(relation), id])];
|
|
1525
|
-
const signingVmId = vmId(newClient.signingKeyMultibase);
|
|
1526
|
-
const signer = await updateKeySigner({ seed: updateKeys.updateSeed });
|
|
1527
|
-
const updated = await updateDID({
|
|
1528
|
-
log,
|
|
1529
|
-
signer,
|
|
1530
|
-
alsoKnownAsWeb: true,
|
|
1531
|
-
updateKeys: [...new Set([...authorizedKeys, newClient.updateKeyMultibase])],
|
|
1532
|
-
nextKeyHashes,
|
|
1533
|
-
verificationMethods,
|
|
1534
|
-
authentication: withReference(doc.authentication, signingVmId),
|
|
1535
|
-
assertionMethod: withReference(doc.assertionMethod, signingVmId),
|
|
1536
|
-
keyAgreement: withReference(doc.keyAgreement, vmId(newClient.keyAgreementKeyMultibase)),
|
|
1537
|
-
capabilityInvocation: withReference(doc.capabilityInvocation, signingVmId),
|
|
1538
|
-
capabilityDelegation: withReference(doc.capabilityDelegation, signingVmId)
|
|
1539
|
-
});
|
|
1540
|
-
// The etag of the read this entry was built on: the mid-ceremony re-read
|
|
1541
|
-
// when the commit entry ran here, the original read when it was skipped.
|
|
1542
|
-
await publishUpdatedLog({ idStore, updated, ifMatch: etag });
|
|
1543
|
-
return { did: updated.did };
|
|
1544
|
-
}
|
|
1545
|
-
/**
|
|
1546
|
-
* Rebuilds `keys.json` from the published artifacts plus a WebKMS key listing
|
|
1547
|
-
* -- the recovery path for a lost or rolled-back `keys.json`. List Keys is
|
|
1548
|
-
* authorized as `read` against the keystore controller, which only the
|
|
1549
|
-
* root-controlled keystore agent can invoke.
|
|
1550
|
-
*
|
|
1551
|
-
* KMS key local ids are server-generated random and appear in no published
|
|
1552
|
-
* artifact, so the bindings are rediscovered by public key material instead.
|
|
1553
|
-
* List the keystore once -- each listed description carries `keyUrl`, the
|
|
1554
|
-
* key's canonical invocation URL (the signable handle its alias-overridden
|
|
1555
|
-
* `id` erases) -- then match `did.json`'s relationship verification methods
|
|
1556
|
-
* by `publicKeyMultibase` and rewrite `keys.json` from what matched. The
|
|
1557
|
-
* `authentication` and `keyAgreement` bindings are required; `assertionMethod`
|
|
1558
|
-
* lists client keys only, so no KMS binding exists there and none is rebuilt.
|
|
1559
|
-
* When `did.jsonl` is published, its resolved DID is recorded in the `webvh`
|
|
1560
|
-
* block; there is nothing else to repair there, since the log's update keys are
|
|
1561
|
-
* client-held seeds that no keystore listing could recover.
|
|
1562
|
-
*
|
|
1563
|
-
* An unmatchable binding is unrepairable and throws: a published artifact
|
|
1564
|
-
* depends on a key the keystore no longer lists.
|
|
1565
|
-
*
|
|
1566
|
-
* The log read takes the same checks every other ceremony read does, and for
|
|
1567
|
-
* the same reason: what it reads is written straight back into the rebuilt
|
|
1568
|
-
* `keys.json`, so a substituted log would rewrite the `webvh` block to a wrong
|
|
1569
|
-
* DID and a truncated one would be adopted as this account's history. A caller
|
|
1570
|
-
* that still holds the account pointer passes `expectedDid` and its
|
|
1571
|
-
* `pinStore`; the pure-recovery caller that has lost everything but the
|
|
1572
|
-
* keystore has no DID to expect and passes neither, which is the one read here
|
|
1573
|
-
* that legitimately discovers the DID from the log itself.
|
|
1574
|
-
*
|
|
1575
|
-
* @param options {object}
|
|
1576
|
-
* @param options.keystoreAgent {KeystoreAgent}
|
|
1577
|
-
* @param options.idStore {WebvhIdStore}
|
|
1578
|
-
* @param [options.expectedDid] {string} the DID the published log must
|
|
1579
|
-
* resolve to
|
|
1580
|
-
* @param [options.pinStore] {ResourceLogPinStore} this client's chain-head
|
|
1581
|
-
* pins for the account log
|
|
1582
|
-
* @param [options.logId] {string} the account log's pin-slot key, built by
|
|
1583
|
-
* the caller with `accountLogPinId({ spaceId })`; required whenever a
|
|
1584
|
-
* `pinStore` is supplied
|
|
1585
|
-
* @returns {Promise<DidWebKeyMapV2>} the rebuilt, persisted keys.json
|
|
1586
|
-
*/
|
|
1587
|
-
export async function repairKeyBindings({ keystoreAgent, idStore, expectedDid, pinStore, logId }) {
|
|
1588
|
-
if (pinStore && logId === undefined) {
|
|
1589
|
-
throw new TypeError('logId is required when pinStore is supplied');
|
|
1590
|
-
}
|
|
1591
|
-
const didDoc = (await idStore.getIdResource({
|
|
1592
|
-
resourceId: DID_DOCUMENT_RESOURCE
|
|
1593
|
-
}));
|
|
1594
|
-
if (!didDoc) {
|
|
1595
|
-
throw new Error('keys.json repair: did.json is not published; there is nothing to ' +
|
|
1596
|
-
'match key bindings against.');
|
|
1597
|
-
}
|
|
1598
|
-
// One listing, matched by public key material below. `keyUrl` is the
|
|
1599
|
-
// list-only projection field (webkms-client >= 14.7.1 types it; an older
|
|
1600
|
-
// server omits it, so entries without one are skipped and simply fail to
|
|
1601
|
-
// match).
|
|
1602
|
-
const listed = (await keystoreAgent.listKeys());
|
|
1603
|
-
const keyUrlByMultibase = new Map();
|
|
1604
|
-
for (const description of listed) {
|
|
1605
|
-
if (description.publicKeyMultibase && description.keyUrl) {
|
|
1606
|
-
keyUrlByMultibase.set(description.publicKeyMultibase, description.keyUrl);
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1609
|
-
// A relationship's first keystore-backed verification method. A
|
|
1610
|
-
// relationship can name several verification methods now that enrolled
|
|
1611
|
-
// clients publish their own keys beside the KMS ones, so every reference is
|
|
1612
|
-
// tried and the first keystore-backed one wins; a client-held key simply
|
|
1613
|
-
// fails to match and is skipped.
|
|
1614
|
-
const findKmsBacked = (relationship) => {
|
|
1615
|
-
const tried = [];
|
|
1616
|
-
for (const reference of didDoc[relationship] ?? []) {
|
|
1617
|
-
const vmId = typeof reference === 'string' ? reference : reference?.id;
|
|
1618
|
-
if (!vmId) {
|
|
1619
|
-
continue;
|
|
1620
|
-
}
|
|
1621
|
-
const method = didDoc.verificationMethod?.find(entry => entry.id === vmId);
|
|
1622
|
-
const publicKeyMultibase = method?.publicKeyMultibase ?? multibaseOf(vmId);
|
|
1623
|
-
tried.push(publicKeyMultibase);
|
|
1624
|
-
const kmsKeyId = keyUrlByMultibase.get(publicKeyMultibase);
|
|
1625
|
-
if (kmsKeyId) {
|
|
1626
|
-
return { bound: { vmId, kmsKeyId }, tried };
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
return { tried };
|
|
1630
|
-
};
|
|
1631
|
-
const bind = (relationship) => {
|
|
1632
|
-
if ((didDoc[relationship] ?? []).length === 0) {
|
|
1633
|
-
throw new Error(`keys.json repair: did.json declares no ${relationship} verification method.`);
|
|
1634
|
-
}
|
|
1635
|
-
const { bound, tried } = findKmsBacked(relationship);
|
|
1636
|
-
if (!bound) {
|
|
1637
|
-
throw new Error(`keys.json repair: no keystore key matches the ${relationship} ` +
|
|
1638
|
-
`verification method (${tried.join(', ')}).`);
|
|
1639
|
-
}
|
|
1640
|
-
return bound;
|
|
1641
|
-
};
|
|
1642
|
-
const repaired = {
|
|
1643
|
-
authentication: bind('authentication'),
|
|
1644
|
-
keyAgreement: bind('keyAgreement')
|
|
1645
|
-
};
|
|
1646
|
-
// The webvh block, recovered from the published log: the DID and nothing
|
|
1647
|
-
// else, since the update keys never left the client that minted them.
|
|
1648
|
-
const published = await readPublishedLog({
|
|
1649
|
-
idStore,
|
|
1650
|
-
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
1651
|
-
...(pinStore && logId !== undefined ? { pinStore, logId } : {})
|
|
1652
|
-
});
|
|
1653
|
-
if (published) {
|
|
1654
|
-
repaired.webvh = { did: published.did };
|
|
1655
|
-
}
|
|
1656
|
-
// Persist the rebuilt anchor in one write.
|
|
1657
|
-
await idStore.putKeyMap({ content: repaired });
|
|
1658
|
-
return repaired;
|
|
1659
|
-
}
|
|
1660
1627
|
//# sourceMappingURL=didWebvh.js.map
|