keri-ts 2.2.4 → 2.2.6
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/esm/keri/npm/src/_dnt.polyfills.js +14 -14
- package/esm/keri/npm/src/acdc/dhking.js +29 -2
- package/esm/keri/npm/src/acdc/observing.js +10 -3
- package/esm/keri/npm/src/acdc/query-resend.js +74 -0
- package/esm/keri/npm/src/acdc/regengine.js +39 -9
- package/esm/keri/npm/src/acdc/regeventing.js +5 -3
- package/esm/keri/npm/src/acdc/registering.js +19 -0
- package/esm/keri/npm/src/acdc/salting.js +4 -0
- package/esm/keri/npm/src/acdc/unblinding.js +38 -3
- package/esm/keri/npm/src/app/bootstrap/authenticating.js +32 -10
- package/esm/keri/npm/src/app/bootstrap/oobiery.js +363 -30
- package/esm/keri/npm/src/app/credentials/credential-importing.js +33 -4
- package/esm/keri/npm/src/app/credentials/root-replicator.js +27 -15
- package/esm/keri/npm/src/app/credentials/schema-resolving.js +5 -1
- package/esm/keri/npm/src/app/credentials/tel-publishing.js +16 -7
- package/esm/keri/npm/src/app/delivery/forwarding.js +205 -44
- package/esm/keri/npm/src/app/delivery/relaying.js +232 -0
- package/esm/keri/npm/src/app/delivery/respondant.js +8 -5
- package/esm/keri/npm/src/app/exchanges/exchange-messaging.js +1 -1
- package/esm/keri/npm/src/app/exchanges/exchanging.js +65 -9
- package/esm/keri/npm/src/app/identity/delegating.js +66 -9
- package/esm/keri/npm/src/app/identity/habbing.js +190 -71
- package/esm/keri/npm/src/app/identity/keeping.js +111 -39
- package/esm/keri/npm/src/app/identity/retire-identifier.js +98 -0
- package/esm/keri/npm/src/app/ipex/disclosure-replaying.js +116 -0
- package/esm/keri/npm/src/app/ipex/group-ipex.js +122 -25
- package/esm/keri/npm/src/app/ipex/group-issuance.js +137 -37
- package/esm/keri/npm/src/app/ipex/ipex-discloser.js +94 -31
- package/esm/keri/npm/src/app/ipex/ipex-grouping.js +53 -3
- package/esm/keri/npm/src/app/ipex/ipex-v2.js +7 -2
- package/esm/keri/npm/src/app/ipex/issuance.js +147 -44
- package/esm/keri/npm/src/app/ipex/pending-presentations.js +4 -2
- package/esm/keri/npm/src/app/ipex/presenting.js +3 -18
- package/esm/keri/npm/src/app/ipex/receive-issuance.js +2 -1
- package/esm/keri/npm/src/app/ipex/unblinding-workflow.js +39 -11
- package/esm/keri/npm/src/app/mailbox/agent-inbox.js +292 -0
- package/esm/keri/npm/src/app/mailbox/forward-handler.js +298 -52
- package/esm/keri/npm/src/app/mailbox/kel-publisher.js +26 -31
- package/esm/keri/npm/src/app/mailbox/mailbox-poller.js +70 -62
- package/esm/keri/npm/src/app/mailbox/mailboxing.js +20 -4
- package/esm/keri/npm/src/app/multisig/counseling.js +71 -27
- package/esm/keri/npm/src/app/multisig/group-members.js +41 -5
- package/esm/keri/npm/src/app/multisig/grouping.js +50 -2
- package/esm/keri/npm/src/app/multisig/multisig-workflows.js +3 -18
- package/esm/keri/npm/src/app/multisig/proposing.js +1 -16
- package/esm/keri/npm/src/app/multisig/rejoin-group.js +99 -0
- package/esm/keri/npm/src/app/multisig/replace-member.js +29 -8
- package/esm/keri/npm/src/app/protocol/parsering.js +45 -17
- package/esm/keri/npm/src/app/protocol/protocol-processing.js +47 -21
- package/esm/keri/npm/src/app/queries/query-replies.js +0 -22
- package/esm/keri/npm/src/app/queries/relay-refresh.js +81 -0
- package/esm/keri/npm/src/app/queries/witness-inquisitor.js +180 -34
- package/esm/keri/npm/src/app/runtime/agent-runtime.js +42 -73
- package/esm/keri/npm/src/app/runtime/cue-runtime.js +45 -5
- package/esm/keri/npm/src/app/runtime/ipex-auxiliaries.js +8 -1
- package/esm/keri/npm/src/app/runtime/operation-owners.js +26 -56
- package/esm/keri/npm/src/app/runtime/workflow-contract.js +7 -4
- package/esm/keri/npm/src/app/transport/http-client.js +20 -2
- package/esm/keri/npm/src/app/transport/message-source.js +2 -1
- package/esm/keri/npm/src/app/transport/messengering.js +39 -8
- package/esm/keri/npm/src/app/witness/ingress.js +7 -0
- package/esm/keri/npm/src/app/witness/receipt-client.js +43 -16
- package/esm/keri/npm/src/app/witness/receipting.js +62 -20
- package/esm/keri/npm/src/cli/messaging/multisig.js +4 -3
- package/esm/keri/npm/src/core/errors.js +73 -0
- package/esm/keri/npm/src/core/kel/delegation-ancestry.js +11 -2
- package/esm/keri/npm/src/core/kel/eventing.js +25 -28
- package/esm/keri/npm/src/core/kel/kever.js +15 -9
- package/esm/keri/npm/src/core/mailbox/kram-policy.js +16 -0
- package/esm/keri/npm/src/core/mailbox/kram-pruning.js +25 -6
- package/esm/keri/npm/src/core/mailbox/kram-time.js +34 -6
- package/esm/keri/npm/src/core/mailbox/kraming.js +58 -2
- package/esm/keri/npm/src/core/missing-anchor-query.js +20 -0
- package/esm/keri/npm/src/core/routing.js +18 -25
- package/esm/keri/npm/src/core/scheming.js +12 -5
- package/esm/keri/npm/src/core/wire-fields.js +126 -0
- package/esm/keri/npm/src/db/basing.js +4 -13
- package/esm/keri/npm/src/db/core/indexeddb-persistence.js +3 -2
- package/esm/keri/npm/src/db/core/webdber.js +85 -27
- package/esm/keri/npm/src/db/mailbox/mailboxing.js +13 -0
- package/esm/keri/npm/src/db/subing.js +4 -0
- package/esm/keri/npm/src/runtime/index.js +11 -5
- package/esm/keri/npm/src/time/mod.js +5 -0
- package/esm/keri/npm/src/vdr/credential-tsn-record.js +2 -7
- package/esm/keri/npm/src/vdr/eventing.js +71 -28
- package/esm/keri/npm/src/vdr/registry-tsn-record.js +3 -13
- package/esm/keri/npm/src/version.js +2 -2
- package/package.json +1 -1
- package/types/_dnt.polyfills.d.ts +9 -9
- package/types/_dnt.polyfills.d.ts.map +1 -1
- package/types/acdc/dhking.d.ts +8 -0
- package/types/acdc/dhking.d.ts.map +1 -1
- package/types/acdc/observing.d.ts +5 -1
- package/types/acdc/observing.d.ts.map +1 -1
- package/types/acdc/query-resend.d.ts +24 -0
- package/types/acdc/query-resend.d.ts.map +1 -0
- package/types/acdc/regengine.d.ts +19 -1
- package/types/acdc/regengine.d.ts.map +1 -1
- package/types/acdc/regeventing.d.ts.map +1 -1
- package/types/acdc/registering.d.ts +6 -0
- package/types/acdc/registering.d.ts.map +1 -1
- package/types/acdc/salting.d.ts.map +1 -1
- package/types/acdc/unblinding.d.ts +13 -1
- package/types/acdc/unblinding.d.ts.map +1 -1
- package/types/app/bootstrap/authenticating.d.ts +12 -2
- package/types/app/bootstrap/authenticating.d.ts.map +1 -1
- package/types/app/bootstrap/oobiery.d.ts +144 -7
- package/types/app/bootstrap/oobiery.d.ts.map +1 -1
- package/types/app/credentials/credential-importing.d.ts +8 -0
- package/types/app/credentials/credential-importing.d.ts.map +1 -1
- package/types/app/credentials/root-replicator.d.ts +19 -8
- package/types/app/credentials/root-replicator.d.ts.map +1 -1
- package/types/app/credentials/schema-resolving.d.ts.map +1 -1
- package/types/app/credentials/tel-publishing.d.ts +4 -2
- package/types/app/credentials/tel-publishing.d.ts.map +1 -1
- package/types/app/delivery/forwarding.d.ts +90 -5
- package/types/app/delivery/forwarding.d.ts.map +1 -1
- package/types/app/delivery/relaying.d.ts +144 -0
- package/types/app/delivery/relaying.d.ts.map +1 -0
- package/types/app/delivery/respondant.d.ts +9 -2
- package/types/app/delivery/respondant.d.ts.map +1 -1
- package/types/app/exchanges/exchanging.d.ts +36 -0
- package/types/app/exchanges/exchanging.d.ts.map +1 -1
- package/types/app/identity/delegating.d.ts +6 -0
- package/types/app/identity/delegating.d.ts.map +1 -1
- package/types/app/identity/habbing.d.ts +106 -19
- package/types/app/identity/habbing.d.ts.map +1 -1
- package/types/app/identity/keeping.d.ts +54 -19
- package/types/app/identity/keeping.d.ts.map +1 -1
- package/types/app/identity/retire-identifier.d.ts +24 -0
- package/types/app/identity/retire-identifier.d.ts.map +1 -0
- package/types/app/ipex/disclosure-replaying.d.ts +61 -0
- package/types/app/ipex/disclosure-replaying.d.ts.map +1 -0
- package/types/app/ipex/group-ipex.d.ts +60 -14
- package/types/app/ipex/group-ipex.d.ts.map +1 -1
- package/types/app/ipex/group-issuance.d.ts +54 -8
- package/types/app/ipex/group-issuance.d.ts.map +1 -1
- package/types/app/ipex/ipex-discloser.d.ts +39 -2
- package/types/app/ipex/ipex-discloser.d.ts.map +1 -1
- package/types/app/ipex/ipex-grouping.d.ts +23 -2
- package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
- package/types/app/ipex/ipex-v2.d.ts +5 -2
- package/types/app/ipex/ipex-v2.d.ts.map +1 -1
- package/types/app/ipex/issuance.d.ts +46 -16
- package/types/app/ipex/issuance.d.ts.map +1 -1
- package/types/app/ipex/pending-presentations.d.ts +4 -2
- package/types/app/ipex/pending-presentations.d.ts.map +1 -1
- package/types/app/ipex/presenting.d.ts.map +1 -1
- package/types/app/ipex/receive-issuance.d.ts +2 -1
- package/types/app/ipex/receive-issuance.d.ts.map +1 -1
- package/types/app/ipex/unblinding-workflow.d.ts +13 -2
- package/types/app/ipex/unblinding-workflow.d.ts.map +1 -1
- package/types/app/mailbox/agent-inbox.d.ts +126 -0
- package/types/app/mailbox/agent-inbox.d.ts.map +1 -0
- package/types/app/mailbox/forward-handler.d.ts +114 -14
- package/types/app/mailbox/forward-handler.d.ts.map +1 -1
- package/types/app/mailbox/kel-publisher.d.ts +12 -22
- package/types/app/mailbox/kel-publisher.d.ts.map +1 -1
- package/types/app/mailbox/mailbox-poller.d.ts +40 -24
- package/types/app/mailbox/mailbox-poller.d.ts.map +1 -1
- package/types/app/mailbox/mailboxing.d.ts +19 -5
- package/types/app/mailbox/mailboxing.d.ts.map +1 -1
- package/types/app/multisig/counseling.d.ts +32 -11
- package/types/app/multisig/counseling.d.ts.map +1 -1
- package/types/app/multisig/group-members.d.ts +17 -1
- package/types/app/multisig/group-members.d.ts.map +1 -1
- package/types/app/multisig/grouping.d.ts +17 -1
- package/types/app/multisig/grouping.d.ts.map +1 -1
- package/types/app/multisig/multisig-workflows.d.ts +0 -8
- package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
- package/types/app/multisig/proposing.d.ts +4 -19
- package/types/app/multisig/proposing.d.ts.map +1 -1
- package/types/app/multisig/rejoin-group.d.ts +119 -0
- package/types/app/multisig/rejoin-group.d.ts.map +1 -0
- package/types/app/multisig/replace-member.d.ts +15 -1
- package/types/app/multisig/replace-member.d.ts.map +1 -1
- package/types/app/protocol/parsering.d.ts +21 -2
- package/types/app/protocol/parsering.d.ts.map +1 -1
- package/types/app/protocol/protocol-processing.d.ts +25 -5
- package/types/app/protocol/protocol-processing.d.ts.map +1 -1
- package/types/app/queries/query-replies.d.ts +4 -8
- package/types/app/queries/query-replies.d.ts.map +1 -1
- package/types/app/queries/relay-refresh.d.ts +26 -0
- package/types/app/queries/relay-refresh.d.ts.map +1 -0
- package/types/app/queries/witness-inquisitor.d.ts +56 -5
- package/types/app/queries/witness-inquisitor.d.ts.map +1 -1
- package/types/app/runtime/agent-runtime.d.ts +34 -3
- package/types/app/runtime/agent-runtime.d.ts.map +1 -1
- package/types/app/runtime/cue-runtime.d.ts +15 -3
- package/types/app/runtime/cue-runtime.d.ts.map +1 -1
- package/types/app/runtime/ipex-auxiliaries.d.ts.map +1 -1
- package/types/app/runtime/operation-owners.d.ts +16 -26
- package/types/app/runtime/operation-owners.d.ts.map +1 -1
- package/types/app/runtime/workflow-contract.d.ts +21 -6
- package/types/app/runtime/workflow-contract.d.ts.map +1 -1
- package/types/app/transport/http-client.d.ts +9 -0
- package/types/app/transport/http-client.d.ts.map +1 -1
- package/types/app/transport/message-source.d.ts +6 -3
- package/types/app/transport/message-source.d.ts.map +1 -1
- package/types/app/transport/messengering.d.ts +10 -1
- package/types/app/transport/messengering.d.ts.map +1 -1
- package/types/app/witness/ingress.d.ts +1 -0
- package/types/app/witness/ingress.d.ts.map +1 -1
- package/types/app/witness/receipt-client.d.ts +19 -1
- package/types/app/witness/receipt-client.d.ts.map +1 -1
- package/types/app/witness/receipting.d.ts +24 -1
- package/types/app/witness/receipting.d.ts.map +1 -1
- package/types/cli/messaging/multisig.d.ts.map +1 -1
- package/types/core/cues.d.ts +53 -1
- package/types/core/cues.d.ts.map +1 -1
- package/types/core/errors.d.ts +32 -0
- package/types/core/errors.d.ts.map +1 -1
- package/types/core/kel/delegation-ancestry.d.ts.map +1 -1
- package/types/core/kel/eventing.d.ts.map +1 -1
- package/types/core/kel/kever-decisions.d.ts +3 -1
- package/types/core/kel/kever-decisions.d.ts.map +1 -1
- package/types/core/kel/kever.d.ts +7 -1
- package/types/core/kel/kever.d.ts.map +1 -1
- package/types/core/mailbox/kram-policy.d.ts +12 -0
- package/types/core/mailbox/kram-policy.d.ts.map +1 -1
- package/types/core/mailbox/kram-pruning.d.ts +5 -1
- package/types/core/mailbox/kram-pruning.d.ts.map +1 -1
- package/types/core/mailbox/kram-time.d.ts +26 -2
- package/types/core/mailbox/kram-time.d.ts.map +1 -1
- package/types/core/mailbox/kraming.d.ts +14 -1
- package/types/core/mailbox/kraming.d.ts.map +1 -1
- package/types/core/missing-anchor-query.d.ts +34 -0
- package/types/core/missing-anchor-query.d.ts.map +1 -0
- package/types/core/routing.d.ts +3 -7
- package/types/core/routing.d.ts.map +1 -1
- package/types/core/scheming.d.ts.map +1 -1
- package/types/core/wire-fields.d.ts +56 -0
- package/types/core/wire-fields.d.ts.map +1 -0
- package/types/db/basing.d.ts.map +1 -1
- package/types/db/core/indexeddb-persistence.d.ts +3 -2
- package/types/db/core/indexeddb-persistence.d.ts.map +1 -1
- package/types/db/core/webdber.d.ts +32 -6
- package/types/db/core/webdber.d.ts.map +1 -1
- package/types/db/exchange/exchange-records.d.ts +4 -0
- package/types/db/exchange/exchange-records.d.ts.map +1 -1
- package/types/db/mailbox/mailboxing.d.ts +10 -1
- package/types/db/mailbox/mailboxing.d.ts.map +1 -1
- package/types/db/subing.d.ts +2 -0
- package/types/db/subing.d.ts.map +1 -1
- package/types/runtime/index.d.ts +20 -14
- package/types/runtime/index.d.ts.map +1 -1
- package/types/time/mod.d.ts +2 -0
- package/types/time/mod.d.ts.map +1 -1
- package/types/vdr/credential-tsn-record.d.ts.map +1 -1
- package/types/vdr/eventing.d.ts +32 -1
- package/types/vdr/eventing.d.ts.map +1 -1
- package/types/vdr/registry-tsn-record.d.ts.map +1 -1
- package/types/version.d.ts +2 -2
- package/esm/keri/npm/src/app/runtime/signer-conditions.js +0 -51
- package/types/app/runtime/signer-conditions.d.ts +0 -32
- package/types/app/runtime/signer-conditions.d.ts.map +0 -1
|
@@ -277,21 +277,22 @@ export class Hab {
|
|
|
277
277
|
return !!this.pre && this.db.getKever(this.pre) !== null;
|
|
278
278
|
}
|
|
279
279
|
/**
|
|
280
|
-
* Whether
|
|
281
|
-
* False for a keyless habitat (`makeSignedHab`) until the
|
|
280
|
+
* Whether this habitat can sign now: every key `sign` would use has a held or stored signer
|
|
281
|
+
* (`Manager.hasSigner`). A pure read that signs nothing. False for a keyless habitat (`makeSignedHab`) until the
|
|
282
|
+
* host holds its signer, and for a habitat with no signing keys (no accepted state, or a group whose local member
|
|
283
|
+
* has no contribution). A group answers through its local member's contribution.
|
|
284
|
+
*
|
|
285
|
+
* Background loops read it before they sign and skip a habitat that cannot sign yet; a later `Manager.hold` lets
|
|
286
|
+
* the habitat act on the next tock.
|
|
282
287
|
*/
|
|
283
288
|
canSign() {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
catch {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
289
|
+
const keys = this.signingKeys();
|
|
290
|
+
return keys.kind === "keys" && keys.pubs.every((pub) => this.mgr.hasSigner(pub));
|
|
291
|
+
}
|
|
292
|
+
/** The current public keys `sign` would use whose signers are neither held nor stored; empty when it can sign. */
|
|
293
|
+
missingSigners() {
|
|
294
|
+
const keys = this.signingKeys();
|
|
295
|
+
return keys.kind === "keys" ? keys.pubs.filter((pub) => !this.mgr.hasSigner(pub)) : [];
|
|
295
296
|
}
|
|
296
297
|
/** Return the live accepted-state `Kever` for this habitat when available. */
|
|
297
298
|
get kever() {
|
|
@@ -408,8 +409,32 @@ export class Hab {
|
|
|
408
409
|
* - mirrors the pattern where local inception is signed in the habitat layer
|
|
409
410
|
* and then fed through `Kevery.processEvent()` rather than hand-writing
|
|
410
411
|
* `states.`/`kels.` directly
|
|
412
|
+
*
|
|
413
|
+
* Failure leaves nothing behind: the Keeper rows `Manager.incept` and `move`
|
|
414
|
+
* wrote roll back with the enclosing Keeper transaction, and the `habs.`
|
|
415
|
+
* record and `names.` mapping are undone, as `makeSigned` does. KERIpy keeps
|
|
416
|
+
* them.
|
|
411
417
|
*/
|
|
412
418
|
make(args = {}) {
|
|
419
|
+
const ns = this.ns ?? "";
|
|
420
|
+
const priorName = this.db.getName(ns, this.name);
|
|
421
|
+
try {
|
|
422
|
+
this.ks.transaction(() => this.inceptLocally(args));
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
if (this.pre && !args.hidden) {
|
|
426
|
+
this.db.habs.rem(this.pre);
|
|
427
|
+
if (priorName)
|
|
428
|
+
this.db.pinName(ns, this.name, priorName);
|
|
429
|
+
else
|
|
430
|
+
this.db.names.rem([ns, this.name]);
|
|
431
|
+
}
|
|
432
|
+
this.pre = "";
|
|
433
|
+
throw error;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/** Derive keys, sign and admit the inception; `make` owns the Keeper transaction and the rollback. */
|
|
437
|
+
inceptLocally(args) {
|
|
413
438
|
const { code = "E", transferable = true, isith = undefined, icount = 1, icode = undefined, nsith = undefined, ncount = undefined, ncode = undefined, toad = 0, wits = [], delpre = undefined, estOnly = false, DnD = false, hidden = false, data = [], algo = undefined, salt = undefined, tier = undefined, version = Vrsn_2_0, } = args;
|
|
414
439
|
let nextCount = ncount ?? icount;
|
|
415
440
|
let nextSith = nsith ?? isith;
|
|
@@ -660,43 +685,43 @@ export class Hab {
|
|
|
660
685
|
return this.mgr.decrypt(ser, { verfers: verfers ?? kever.verfers });
|
|
661
686
|
}
|
|
662
687
|
sign(ser, indexed = false) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const
|
|
667
|
-
if (
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
const member = this.db.getHab(this.pre)?.mid;
|
|
672
|
-
if (member) {
|
|
673
|
-
const state = this.db.getKever(member);
|
|
674
|
-
if (!state)
|
|
675
|
-
throw new ValidationError(`Missing accepted member key state for ${member}.`);
|
|
676
|
-
// KERIpy GroupHab.sign/fetchLatestContribTo: a member may have rotated
|
|
677
|
-
// ahead of its contribution to the group's currently accepted key list.
|
|
678
|
-
const contribution = latestGroupContribution(this.db, member, kever.verfers);
|
|
679
|
-
if (contribution) {
|
|
680
|
-
const { index, verfer } = contribution;
|
|
681
|
-
if (indexed) {
|
|
682
|
-
// Endorsement proves current authority only. Rotation signatures have
|
|
683
|
-
// a separate prior-next commitment path in rotateGroupHab().
|
|
684
|
-
return this.mgr.sign(ser, {
|
|
685
|
-
pubs: [verfer.qb64],
|
|
686
|
-
indexed: true,
|
|
687
|
-
indices: [index],
|
|
688
|
-
ondices: [null],
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
return this.mgr.sign(ser, [verfer.qb64], false);
|
|
692
|
-
}
|
|
693
|
-
throw new ValidationError(`Member ${member} has no contribution to group ${this.pre}.`);
|
|
688
|
+
const keys = this.signingKeys();
|
|
689
|
+
if (keys.kind === "none")
|
|
690
|
+
throw new ValidationError(keys.reason);
|
|
691
|
+
const { pubs, index } = keys;
|
|
692
|
+
if (index !== null && indexed) {
|
|
693
|
+
// Endorsement proves current authority only. Rotation signatures have
|
|
694
|
+
// a separate prior-next commitment path in rotateGroupHab().
|
|
695
|
+
return this.mgr.sign(ser, { pubs, indexed: true, indices: [index], ondices: [null] });
|
|
694
696
|
}
|
|
695
697
|
if (indexed) {
|
|
696
698
|
return this.mgr.sign(ser, pubs, true);
|
|
697
699
|
}
|
|
698
700
|
return this.mgr.sign(ser, pubs, false);
|
|
699
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* Select the keys `sign` uses. A group habitat uses only its designated member's latest single-key contribution,
|
|
704
|
+
* located in its accepted KEL; any other habitat uses its accepted current keys.
|
|
705
|
+
*/
|
|
706
|
+
signingKeys() {
|
|
707
|
+
if (!this.pre)
|
|
708
|
+
return { kind: "none", reason: "Signing requires a local habitat prefix." };
|
|
709
|
+
const kever = this.kever;
|
|
710
|
+
if (!kever)
|
|
711
|
+
return { kind: "none", reason: `Missing accepted key state for ${this.pre}.` };
|
|
712
|
+
const member = this.db.getHab(this.pre)?.mid;
|
|
713
|
+
if (!member)
|
|
714
|
+
return { kind: "keys", pubs: kever.verfers.map((verfer) => verfer.qb64), index: null };
|
|
715
|
+
if (!this.db.getKever(member)) {
|
|
716
|
+
return { kind: "none", reason: `Missing accepted member key state for ${member}.` };
|
|
717
|
+
}
|
|
718
|
+
// KERIpy GroupHab.sign/fetchLatestContribTo: a member may have rotated
|
|
719
|
+
// ahead of its contribution to the group's currently accepted key list.
|
|
720
|
+
const contribution = latestGroupContribution(this.db, member, kever.verfers);
|
|
721
|
+
if (!contribution)
|
|
722
|
+
return { kind: "none", reason: `Member ${member} has no contribution to group ${this.pre}.` };
|
|
723
|
+
return { kind: "keys", pubs: [contribution.verfer.qb64], index: contribution.index };
|
|
724
|
+
}
|
|
700
725
|
/**
|
|
701
726
|
* Endorse one already-built KERI message body with this habitat's current
|
|
702
727
|
* establishment keys.
|
|
@@ -1357,42 +1382,44 @@ export class Habery {
|
|
|
1357
1382
|
}
|
|
1358
1383
|
hab.reconfigure();
|
|
1359
1384
|
}
|
|
1360
|
-
// Restart recovery:
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
this.recoverAcceptedGroupMembers(pre);
|
|
1385
|
+
// Restart recovery: a group whose establishment event was accepted while no runtime aligned its members.
|
|
1386
|
+
for (const pre of this.habs.keys()) {
|
|
1387
|
+
this.alignGroupMembers(pre);
|
|
1364
1388
|
}
|
|
1365
1389
|
}
|
|
1366
1390
|
/**
|
|
1367
|
-
*
|
|
1368
|
-
*
|
|
1391
|
+
* Bring a local group's stored members (`smids`/`rmids` on its habitat record and in the keeper) in line with
|
|
1392
|
+
* the group's latest accepted establishment event. This is the one writer of a local group's member lists after
|
|
1393
|
+
* its record is created; acceptance, reopen recovery, member replacement and a proposer's immediate acceptance
|
|
1394
|
+
* all reach it, and the runtime's Counselor calls it on its pass after each accepted establishment event, so a
|
|
1395
|
+
* rotation that completes late (a co-member's signature arriving after the proposer stopped waiting) is followed
|
|
1396
|
+
* without any caller asking.
|
|
1397
|
+
*
|
|
1398
|
+
* Members come from accepted key state only (`acceptedGroupMembers`, KERIpy `GroupHab.acceptedMembers`), never
|
|
1399
|
+
* from a proposal's or caller's lists: the stored members are tried first, then every AID with local key state.
|
|
1400
|
+
* When a key cannot be attributed yet nothing is written and the result is `unattributed`; a partial list is
|
|
1401
|
+
* never stored. Only the latest accepted event is followed, so members never roll back, and repeating it
|
|
1402
|
+
* changes nothing.
|
|
1369
1403
|
*
|
|
1370
|
-
*
|
|
1371
|
-
*
|
|
1372
|
-
*
|
|
1373
|
-
*
|
|
1374
|
-
* are committed only when they differ from the stored record and the local
|
|
1375
|
-
* member contributes to that event; a record that does not yet include the
|
|
1376
|
-
* local member is a pending join, not a stale commit. Only the latest
|
|
1377
|
-
* accepted event is committed, so this never rolls members back, and
|
|
1378
|
-
* repeating it changes nothing. Returns whether stale members were committed.
|
|
1404
|
+
* The recorded local member (`mid`) is never changed here; replacing it stays `joinGroupHab`'s explicit
|
|
1405
|
+
* replacement. Diverging from KERIpy `GroupHab.recoverAcceptedMembers`, the lists follow accepted state even
|
|
1406
|
+
* when it does not include the local member (a member rotated out, or one whose join is not accepted yet).
|
|
1407
|
+
* Weight plays no part: a member whose signing weight is 0 is a member like any other.
|
|
1379
1408
|
*/
|
|
1380
|
-
|
|
1409
|
+
alignGroupMembers(pre) {
|
|
1381
1410
|
const record = this.db.getHab(pre);
|
|
1382
|
-
if (!record?.mid || record.sid || !this.habs.has(record.mid))
|
|
1383
|
-
return
|
|
1411
|
+
if (this.readonly || !record?.mid || record.sid || !this.habs.has(record.mid))
|
|
1412
|
+
return "unchanged";
|
|
1384
1413
|
const smids = [...(record.smids ?? [])], rmids = [...(record.rmids ?? [])];
|
|
1385
1414
|
const accepted = acceptedGroupMembers(this.db, pre, new Set([...smids, ...rmids]))
|
|
1386
1415
|
?? acceptedGroupMembers(this.db, pre, [...this.db.states.getTopItemIter()].map(([keys]) => keys.join(".")));
|
|
1387
1416
|
if (!accepted)
|
|
1388
|
-
return
|
|
1417
|
+
return "unattributed";
|
|
1389
1418
|
const same = (left, right) => left.length === right.length && left.every((aid, index) => aid === right[index]);
|
|
1390
1419
|
if (same(accepted.smids, smids) && same(accepted.rmids, rmids))
|
|
1391
|
-
return
|
|
1392
|
-
if (!accepted.smids.includes(record.mid) && !accepted.rmids.includes(record.mid))
|
|
1393
|
-
return false;
|
|
1420
|
+
return "unchanged";
|
|
1394
1421
|
this.commitGroupHabMembers(pre, accepted.smids, accepted.rmids);
|
|
1395
|
-
return
|
|
1422
|
+
return "aligned";
|
|
1396
1423
|
}
|
|
1397
1424
|
/** Local AID prefixes currently managed by this habery. */
|
|
1398
1425
|
get prefixes() {
|
|
@@ -1596,8 +1623,8 @@ export class Habery {
|
|
|
1596
1623
|
}
|
|
1597
1624
|
this.habs.set(pre, hab);
|
|
1598
1625
|
if (replacing && !this.readonly) {
|
|
1599
|
-
// The stored lists must follow accepted state,
|
|
1600
|
-
this.
|
|
1626
|
+
// The stored lists must follow accepted state, whatever lists the caller passed.
|
|
1627
|
+
this.alignGroupMembers(pre);
|
|
1601
1628
|
this.retireGroupMemberState(pre, existingRecord.mid);
|
|
1602
1629
|
}
|
|
1603
1630
|
return hab;
|
|
@@ -1621,7 +1648,7 @@ export class Habery {
|
|
|
1621
1648
|
this.db.rrsn.rem(keys);
|
|
1622
1649
|
}
|
|
1623
1650
|
}
|
|
1624
|
-
/**
|
|
1651
|
+
/** Write member lists already derived from accepted state; only `alignGroupMembers` calls this. */
|
|
1625
1652
|
commitGroupHabMembers(pre, smids, rmids = smids) {
|
|
1626
1653
|
const record = this.db.getHab(pre);
|
|
1627
1654
|
if (!record?.mid) {
|
|
@@ -1696,8 +1723,9 @@ export class Habery {
|
|
|
1696
1723
|
if (decision.kind === "reject") {
|
|
1697
1724
|
throw new ValidationError(decision.message);
|
|
1698
1725
|
}
|
|
1726
|
+
// Accepted on local signatures alone: the members follow it now. Otherwise they follow when it is accepted.
|
|
1699
1727
|
if (serder.sn !== null && serder.said && this.db.kels.getLast(hab.pre, serder.sn) === serder.said) {
|
|
1700
|
-
this.
|
|
1728
|
+
this.alignGroupMembers(hab.pre);
|
|
1701
1729
|
}
|
|
1702
1730
|
return {
|
|
1703
1731
|
hab,
|
|
@@ -1872,6 +1900,97 @@ export class Habery {
|
|
|
1872
1900
|
this.habs.set(pre, hab);
|
|
1873
1901
|
return hab;
|
|
1874
1902
|
}
|
|
1903
|
+
/**
|
|
1904
|
+
* Retire one local, non-group habitat: it stops being local, and its stored private keys are deleted.
|
|
1905
|
+
*
|
|
1906
|
+
* Removed, durable rows in one `db.transaction` (the Keeper deletes run in a nested Keeper transaction, see
|
|
1907
|
+
* `Manager.forget`): the `habs.` record, its `names.` mapping when that still maps to `pre`, and the
|
|
1908
|
+
* Keeper's stored key rows. After commit, `pre` leaves `db.prefixes`, `habs` and `deferredReconfigure`.
|
|
1909
|
+
*
|
|
1910
|
+
* Kept, deliberately: the KEL with its attachments, `states.`, receipts, key-state notices, every accepted
|
|
1911
|
+
* reply the identifier authored or that names it (end-role and location records and their BADA date-times
|
|
1912
|
+
* and signatures), and the `Kever` cache entry. KERI never deletes a KEL, and BADA/RUN acceptance compares
|
|
1913
|
+
* new replies against the stored ones, so deleting them would let an older signed reply be accepted again.
|
|
1914
|
+
* The identifier is afterwards an ordinary remote one; `Baser.reloadKevers` rebuilds `prefixes` from
|
|
1915
|
+
* `habs.` only, so a reopen agrees. Retirement is one-way: `makeSignedHab` refuses a prefix with a `Kever`,
|
|
1916
|
+
* and the kept Keeper `pres.` rows make `makeHab` refuse an inception that derives the retired keys again.
|
|
1917
|
+
* Retirement deletes the stored keys and the ability to act as a local habitat, not the secret's
|
|
1918
|
+
* derivability: a rooted salty habitat's seeds stay derivable from the Keeper's root salt plus its name.
|
|
1919
|
+
* No event is made and nothing is signed. The held signers of the identifier's current keys are dropped
|
|
1920
|
+
* (`Manager.forget`) once the rows are deleted. Runtime state (pollers, cursors, operations) is the caller's to
|
|
1921
|
+
* clean up.
|
|
1922
|
+
*
|
|
1923
|
+
* Refused with a `ValidationError`, before any write, when `pre` is not a local habitat, is a group
|
|
1924
|
+
* habitat, is the recorded local member (`mid`) of a local group, is an accepted signing or rotation
|
|
1925
|
+
* member of a local group, or is the delegator of a local habitat.
|
|
1926
|
+
*
|
|
1927
|
+
* Differences from KERIpy `Habery.deleteHab(name, ns)`: keyed by prefix rather than by name, throws where
|
|
1928
|
+
* KERIpy returns `False`, refuses the cases above where KERIpy has no guards, and deletes the Keeper's stored
|
|
1929
|
+
* key rows other than `pres.` where KERIpy keeps them all.
|
|
1930
|
+
*/
|
|
1931
|
+
retireHab(pre) {
|
|
1932
|
+
const refusal = this.retireRefusal(pre);
|
|
1933
|
+
if (refusal)
|
|
1934
|
+
throw new ValidationError(refusal);
|
|
1935
|
+
const record = this.db.getHab(pre);
|
|
1936
|
+
const name = record.name;
|
|
1937
|
+
const ns = record.domain ?? "";
|
|
1938
|
+
const current = this.db.getKever(pre)?.verfers.map((verfer) => verfer.qb64) ?? [];
|
|
1939
|
+
const { deleted, released } = this.db.transaction(() => {
|
|
1940
|
+
this.db.habs.rem(pre);
|
|
1941
|
+
if (this.db.getName(ns, name) === pre)
|
|
1942
|
+
this.db.names.rem([ns, name]);
|
|
1943
|
+
return this.mgr.forget(pre, current);
|
|
1944
|
+
});
|
|
1945
|
+
this.db.prefixes.delete(pre);
|
|
1946
|
+
this.habs.delete(pre);
|
|
1947
|
+
const deferred = this.deferredReconfigure.indexOf(pre);
|
|
1948
|
+
if (deferred >= 0)
|
|
1949
|
+
this.deferredReconfigure.splice(deferred, 1);
|
|
1950
|
+
return { pre, name, domain: record.domain, keys: deleted, released };
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* The accepted local habitats that cannot sign now, each with the current public keys whose signers are neither
|
|
1954
|
+
* held nor stored. Derived on every call from `Hab.missingSigners`; nothing records it. A store opened without a
|
|
1955
|
+
* habitat's signer lists that habitat until the host calls `Manager.hold`. A habitat with no signing keys at all
|
|
1956
|
+
* (a group whose local member has no contribution) is not listed: that is not a missing signer.
|
|
1957
|
+
*/
|
|
1958
|
+
unsignable() {
|
|
1959
|
+
const unsignable = [];
|
|
1960
|
+
for (const hab of this.habs.values()) {
|
|
1961
|
+
if (!hab.accepted)
|
|
1962
|
+
continue;
|
|
1963
|
+
const missing = hab.missingSigners();
|
|
1964
|
+
if (missing.length)
|
|
1965
|
+
unsignable.push({ pre: hab.pre, missing });
|
|
1966
|
+
}
|
|
1967
|
+
return unsignable;
|
|
1968
|
+
}
|
|
1969
|
+
/**
|
|
1970
|
+
* Why {@link retireHab} would refuse `pre`, or null when it would retire it. A pure read: the refusals listed
|
|
1971
|
+
* on `retireHab`, in the same order, so a caller can decide between retiring and keeping without a throw.
|
|
1972
|
+
*/
|
|
1973
|
+
retireRefusal(pre) {
|
|
1974
|
+
const record = this.db.getHab(pre);
|
|
1975
|
+
if (!record?.name)
|
|
1976
|
+
return `${pre} is not a local habitat.`;
|
|
1977
|
+
if (record.mid || this.db.groups.has(pre)) {
|
|
1978
|
+
return `${pre} is a group habitat; retiring group habitats is not supported.`;
|
|
1979
|
+
}
|
|
1980
|
+
for (const [key, local] of this.db.getHabItemIter()) {
|
|
1981
|
+
const hid = local.hid || key;
|
|
1982
|
+
if (hid === pre)
|
|
1983
|
+
continue;
|
|
1984
|
+
if (local.mid === pre)
|
|
1985
|
+
return `${pre} is the recorded local member of group ${hid}.`;
|
|
1986
|
+
if (local.mid && isAcceptedGroupMember(this.db, hid, pre)) {
|
|
1987
|
+
return `${pre} is an accepted member of local group ${hid}.`;
|
|
1988
|
+
}
|
|
1989
|
+
if (this.db.getKever(hid)?.delpre === pre)
|
|
1990
|
+
return `${pre} is the delegator of local habitat ${hid}.`;
|
|
1991
|
+
}
|
|
1992
|
+
return null;
|
|
1993
|
+
}
|
|
1875
1994
|
/** Creates this Habery's sidecar stores. */
|
|
1876
1995
|
get opener() {
|
|
1877
1996
|
if (!this.storeOpener)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { decodeB64, Decrypter, Diger, Encrypter, hydrateMatter, intToB64, MtrDex, NumberPrimitive, NumDex, parseMatter, Prefixer, Saider, Salter, Signer, Tiers, Verfer, } from "cesr-ts";
|
|
2
|
-
import { b } from "cesr-ts";
|
|
2
|
+
import { b, ParserError } from "cesr-ts";
|
|
3
3
|
import { ValidationError } from "../../core/errors.js";
|
|
4
4
|
import { PubLot } from "../../db/keeping.js";
|
|
5
5
|
/**
|
|
@@ -194,9 +194,9 @@ function emptyLot(dt = "") {
|
|
|
194
194
|
return new PubLot({ pubs: [], ridx: 0, kidx: 0, dt });
|
|
195
195
|
}
|
|
196
196
|
/**
|
|
197
|
-
* No private key for `pub`: neither held (`Manager.hold`) nor stored in the Keeper. A
|
|
198
|
-
*
|
|
199
|
-
*
|
|
197
|
+
* No private key for `pub`: neither held (`Manager.hold`) nor stored in the Keeper. A background loop reads
|
|
198
|
+
* `Hab.canSign()` before it signs and skips a habitat that cannot, so this error escaping a loop is a real fault.
|
|
199
|
+
* The message is the one the Keeper has always used.
|
|
200
200
|
*/
|
|
201
201
|
export class SignerNotHeldError extends Error {
|
|
202
202
|
constructor(pub) {
|
|
@@ -270,13 +270,6 @@ export class Manager {
|
|
|
270
270
|
writable: true,
|
|
271
271
|
value: new Map()
|
|
272
272
|
});
|
|
273
|
-
/** Told after `hold()` borrows signers; a loop that waited for a missing signer resumes on it. */
|
|
274
|
-
Object.defineProperty(this, "holdListeners", {
|
|
275
|
-
enumerable: true,
|
|
276
|
-
configurable: true,
|
|
277
|
-
writable: true,
|
|
278
|
-
value: new Set()
|
|
279
|
-
});
|
|
280
273
|
const { ks, seed = "", aeid = "", pidx = 0, algo = Algos.salty, salt = randomSaltQb64(), tier = Tiers.low, } = args;
|
|
281
274
|
this._ks = ks;
|
|
282
275
|
this._seed = seed;
|
|
@@ -433,9 +426,9 @@ export class Manager {
|
|
|
433
426
|
this.decrypter = decrypter;
|
|
434
427
|
this._seed = seed;
|
|
435
428
|
}
|
|
436
|
-
/** Require full canonical keys; local ownership is the calling operation's responsibility. */
|
|
429
|
+
/** Require full canonical keys for a write; local ownership is the calling operation's responsibility. */
|
|
437
430
|
registryRootKeys(aid, regid) {
|
|
438
|
-
if (
|
|
431
|
+
if (!canonicalRegistryRootKeys(aid, regid)) {
|
|
439
432
|
throw new Error("Registry root keys must be canonical AID and registry SAID strings");
|
|
440
433
|
}
|
|
441
434
|
return [aid, regid];
|
|
@@ -454,7 +447,10 @@ export class Manager {
|
|
|
454
447
|
}
|
|
455
448
|
/** Return the retained Salt128 root; absent reads require no encryption. */
|
|
456
449
|
getRegistryRoot(aid, regid) {
|
|
457
|
-
|
|
450
|
+
// No root is stored under a key that is not canonical (see `canonicalRegistryRootKeys`).
|
|
451
|
+
if (!canonicalRegistryRootKeys(aid, regid))
|
|
452
|
+
return null;
|
|
453
|
+
const cipher = this.ks.rroots.get([aid, regid]);
|
|
458
454
|
if (!cipher)
|
|
459
455
|
return null;
|
|
460
456
|
const { decrypter } = this.registryRootCrypto();
|
|
@@ -476,9 +472,12 @@ export class Manager {
|
|
|
476
472
|
const { aeid, encrypter, decrypter } = this.registryRootCrypto();
|
|
477
473
|
return this.ks.retainRegistryRoot(keys, root, aeid, encrypter, decrypter, overwrite);
|
|
478
474
|
}
|
|
479
|
-
/**
|
|
475
|
+
/**
|
|
476
|
+
* Whether a root is retained for `aid` and `regid`; reads no ciphertext and needs no unlocked Keeper. False for
|
|
477
|
+
* a key that is not canonical, since no root is stored under one (see `canonicalRegistryRootKeys`).
|
|
478
|
+
*/
|
|
480
479
|
hasRegistryRoot(aid, regid) {
|
|
481
|
-
return !!this.ks.rroots.get(
|
|
480
|
+
return canonicalRegistryRootKeys(aid, regid) && !!this.ks.rroots.get([aid, regid]);
|
|
482
481
|
}
|
|
483
482
|
signerDecrypter() {
|
|
484
483
|
if (this.aeid && !this.decrypter) {
|
|
@@ -504,7 +503,8 @@ export class Manager {
|
|
|
504
503
|
* and hold that encoding. A request for the other encoding does not match.
|
|
505
504
|
* - The host owns each `Signer` and its seed bytes, including zeroing them.
|
|
506
505
|
* This keeps the reference only; it never copies seed bytes and never
|
|
507
|
-
* erases them.
|
|
506
|
+
* erases them. Retiring the habitat (`forget()`) drops the reference but
|
|
507
|
+
* does not zero memory.
|
|
508
508
|
* - Holding a pub that is already held replaces the earlier signer. A held
|
|
509
509
|
* signer shadows a stored key with the same public key.
|
|
510
510
|
* - The `pre/path` branch of `sign()` re-derives salty keys from the stored
|
|
@@ -522,32 +522,18 @@ export class Manager {
|
|
|
522
522
|
}
|
|
523
523
|
for (const [pub, signer] of batch)
|
|
524
524
|
this.held.set(pub, signer);
|
|
525
|
-
for (const listener of [...this.holdListeners])
|
|
526
|
-
listener();
|
|
527
525
|
}
|
|
528
526
|
/**
|
|
529
|
-
*
|
|
527
|
+
* Whether this Manager can sign with `pub` now: a signer is held for it, or the Keeper stores its private key.
|
|
528
|
+
* A pure read; it neither decrypts nor signs.
|
|
530
529
|
*
|
|
531
|
-
*
|
|
530
|
+
* A store may be opened without a habitat's signer (a keyless habitat before its host calls `hold()`), so this
|
|
531
|
+
* is ordinary state: background loops read it before they sign and skip what cannot be signed yet.
|
|
532
532
|
*/
|
|
533
|
-
|
|
534
|
-
this.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Drop held signer references: all of them, or only those for `pubs`.
|
|
539
|
-
*
|
|
540
|
-
* Unheld pubs are ignored. Afterwards a request for a released key resolves
|
|
541
|
-
* from stored keys only and fails as any missing key does. This drops
|
|
542
|
-
* references; zeroing a signer's seed stays the host's job.
|
|
543
|
-
*/
|
|
544
|
-
release(pubs) {
|
|
545
|
-
if (pubs === undefined) {
|
|
546
|
-
this.held.clear();
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
for (const pub of pubs)
|
|
550
|
-
this.held.delete(pub);
|
|
533
|
+
hasSigner(pub) {
|
|
534
|
+
if (this.held.has(pub))
|
|
535
|
+
return true;
|
|
536
|
+
return this.ks.pris.has(pub);
|
|
551
537
|
}
|
|
552
538
|
/** Resolve one signer by qualified public key: held first, then the Keeper's `pris.`. */
|
|
553
539
|
getSignerByPub(pub) {
|
|
@@ -835,6 +821,15 @@ export class Manager {
|
|
|
835
821
|
if (!opre) {
|
|
836
822
|
throw new Error("Invalid incept configuration produced no current verfers.");
|
|
837
823
|
}
|
|
824
|
+
// The same seed under the other transferability encodes the same public key differently (`D...`/`B...`),
|
|
825
|
+
// so a forgotten prefix's kept `pres.` row is looked up under both encodings.
|
|
826
|
+
const first = isigners[0];
|
|
827
|
+
const twin = new Signer({ code: first.code, raw: first.raw, transferable: !first.transferable }).verfer.qb64;
|
|
828
|
+
const retired = [opre, twin].map((pub) => this.ks.getPres(pub)).find((owner) => owner !== null && this.ks.getSits(owner) === null);
|
|
829
|
+
if (retired) {
|
|
830
|
+
throw new Error(`Already incepted pre=${opre}: these keys derive the forgotten keys of retired identifier ${retired}; `
|
|
831
|
+
+ "use another name, namespace or salt.");
|
|
832
|
+
}
|
|
838
833
|
if (!this.ks.putPres(opre, opre)) {
|
|
839
834
|
throw new Error(`Already incepted pre=${opre}.`);
|
|
840
835
|
}
|
|
@@ -981,6 +976,68 @@ export class Manager {
|
|
|
981
976
|
}
|
|
982
977
|
return [verfers, digers];
|
|
983
978
|
}
|
|
979
|
+
/**
|
|
980
|
+
* Delete the stored key rows of one managed prefix, in one Keeper transaction.
|
|
981
|
+
*
|
|
982
|
+
* Removed rows:
|
|
983
|
+
* - `prms.` and `sits.` for `pre`
|
|
984
|
+
* - every `pubs.` lot stored under `pre` or under an inception alias that
|
|
985
|
+
* `move()` bound to it (the first current public key of a self-addressing prefix)
|
|
986
|
+
* - `pris.` for every public key named by those lots or by the situation
|
|
987
|
+
*
|
|
988
|
+
* Kept: every `pres.` row that resolves to `pre`. They are the one-way marker:
|
|
989
|
+
* `incept()` refuses any later inception whose first key is one of them, so
|
|
990
|
+
* the same name, namespace and salt cannot derive these keys again under a
|
|
991
|
+
* new or the same prefix.
|
|
992
|
+
*
|
|
993
|
+
* Limit: this deletes stored rows, not the secret's derivability. For a
|
|
994
|
+
* rooted salty prefix the seeds stay derivable from the Keeper-global salt
|
|
995
|
+
* and the habitat's derivation stem (its namespace and name).
|
|
996
|
+
*
|
|
997
|
+
* A prefix with no key rows, such as a keyless habitat whose signers are held
|
|
998
|
+
* externally (`hold()`) or one already forgotten, has no stored keys to delete.
|
|
999
|
+
* Held signers for `current` (the prefix's current public keys, which a keyless
|
|
1000
|
+
* habitat has no Keeper row for) are dropped as well; zeroing their seeds stays
|
|
1001
|
+
* the host's job. There is no other way to drop a held signer: a store's signers
|
|
1002
|
+
* only ever grow until it closes.
|
|
1003
|
+
*
|
|
1004
|
+
* No KERIpy counterpart: `Habery.deleteHab` keeps all of the Keeper's state.
|
|
1005
|
+
*
|
|
1006
|
+
* @param pre Prefix to forget.
|
|
1007
|
+
* @param current The prefix's current public keys, whose held signers are dropped.
|
|
1008
|
+
* @returns What was deleted and dropped.
|
|
1009
|
+
*/
|
|
1010
|
+
forget(pre, current) {
|
|
1011
|
+
const deleted = this.ks.transaction(() => {
|
|
1012
|
+
const aliases = new Set([pre]);
|
|
1013
|
+
for (const [keys, prefixer] of this.ks.pres.getTopItemIter()) {
|
|
1014
|
+
if (prefixer.qb64 === pre)
|
|
1015
|
+
aliases.add(keys.join("."));
|
|
1016
|
+
}
|
|
1017
|
+
const pubs = new Set();
|
|
1018
|
+
const sit = this.ks.getSits(pre);
|
|
1019
|
+
for (const lot of sit ? [sit.old, sit.new, sit.nxt] : []) {
|
|
1020
|
+
for (const pub of lot.pubs)
|
|
1021
|
+
pubs.add(pub);
|
|
1022
|
+
}
|
|
1023
|
+
for (const alias of aliases) {
|
|
1024
|
+
for (const [, lot] of this.ks.pubs.getTopItemIter(alias, { topive: true })) {
|
|
1025
|
+
for (const pub of lot.pubs)
|
|
1026
|
+
pubs.add(pub);
|
|
1027
|
+
}
|
|
1028
|
+
this.ks.pubs.trim(alias, { topive: true });
|
|
1029
|
+
}
|
|
1030
|
+
this.ks.prms.rem(pre);
|
|
1031
|
+
this.ks.sits.rem(pre);
|
|
1032
|
+
let deleted = 0;
|
|
1033
|
+
for (const pub of pubs) {
|
|
1034
|
+
if (this.ks.pris.rem(pub))
|
|
1035
|
+
deleted += 1;
|
|
1036
|
+
}
|
|
1037
|
+
return deleted;
|
|
1038
|
+
});
|
|
1039
|
+
return { deleted, released: current.filter((pub) => this.held.delete(pub)) };
|
|
1040
|
+
}
|
|
984
1041
|
sign(ser, pubsOrArgs = [], indexed = true) {
|
|
985
1042
|
const args = Array.isArray(pubsOrArgs)
|
|
986
1043
|
? { pubs: pubsOrArgs, indexed }
|
|
@@ -1312,3 +1369,18 @@ export function b64DecodeUrl(text) {
|
|
|
1312
1369
|
export function ensureKeeperCryptoReady() {
|
|
1313
1370
|
// no-op
|
|
1314
1371
|
}
|
|
1372
|
+
/**
|
|
1373
|
+
* Whether `aid` and `regid` are one complete canonical AID and one complete canonical SAID. A registry identifier is
|
|
1374
|
+
* often a peer's text (a Grant's `rd`), so text that does not decode as CESR is a key that names no stored root, not
|
|
1375
|
+
* a fault: a lookup answers "not held" and only a write refuses it.
|
|
1376
|
+
*/
|
|
1377
|
+
function canonicalRegistryRootKeys(aid, regid) {
|
|
1378
|
+
try {
|
|
1379
|
+
return new Prefixer({ qb64: aid }).qb64 === aid && new Diger({ qb64: regid }).qb64 === regid;
|
|
1380
|
+
}
|
|
1381
|
+
catch (error) {
|
|
1382
|
+
if (error instanceof ParserError)
|
|
1383
|
+
return false;
|
|
1384
|
+
throw error;
|
|
1385
|
+
}
|
|
1386
|
+
}
|