@ibgib/core-gib 0.1.62 → 0.1.64

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.
Files changed (102) hide show
  1. package/dist/keystone/keystone-constants.d.mts +1 -0
  2. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  3. package/dist/keystone/keystone-constants.mjs +1 -0
  4. package/dist/keystone/keystone-constants.mjs.map +1 -1
  5. package/dist/keystone/keystone-helpers.d.mts +19 -1
  6. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  7. package/dist/keystone/keystone-helpers.mjs +191 -16
  8. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  9. package/dist/keystone/keystone-service-v1.d.mts +84 -2
  10. package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
  11. package/dist/keystone/keystone-service-v1.mjs +324 -28
  12. package/dist/keystone/keystone-service-v1.mjs.map +1 -1
  13. package/dist/keystone/keystone-service-v1.respec.mjs +447 -2
  14. package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
  15. package/dist/keystone/keystone-types.d.mts +31 -2
  16. package/dist/keystone/keystone-types.d.mts.map +1 -1
  17. package/dist/keystone/keystone-types.mjs +13 -0
  18. package/dist/keystone/keystone-types.mjs.map +1 -1
  19. package/dist/keystone/policy/keystone-profile-builder.d.mts +1 -1
  20. package/dist/keystone/policy/keystone-profile-builder.d.mts.map +1 -1
  21. package/dist/keystone/policy/keystone-profile-builder.mjs +8 -0
  22. package/dist/keystone/policy/keystone-profile-builder.mjs.map +1 -1
  23. package/dist/keystone/policy/profiles/profile-domain.json +69 -0
  24. package/dist/keystone/policy/profiles/profile-sync.json +84 -0
  25. package/dist/keystone/policy/schemas/keystone.high.schema.json +1 -1
  26. package/dist/keystone/policy/schemas/keystone.medium.schema.json +1 -1
  27. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts +8 -0
  28. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts.map +1 -1
  29. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs +15 -1
  30. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs.map +1 -1
  31. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs +16 -4
  32. package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs.map +1 -1
  33. package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs +4 -1
  34. package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs.map +1 -1
  35. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs +4 -1
  36. package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs.map +1 -1
  37. package/dist/sync/sync-conflict-text-merge.withid.respec.mjs +10 -4
  38. package/dist/sync/sync-conflict-text-merge.withid.respec.mjs.map +1 -1
  39. package/dist/sync/sync-innerspace-constants.withid.respec.mjs +12 -3
  40. package/dist/sync/sync-innerspace-constants.withid.respec.mjs.map +1 -1
  41. package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs +4 -1
  42. package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs.map +1 -1
  43. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs +4 -1
  44. package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs.map +1 -1
  45. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs +4 -1
  46. package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs.map +1 -1
  47. package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs +4 -1
  48. package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs.map +1 -1
  49. package/dist/sync/sync-innerspace.withid.respec.mjs +4 -1
  50. package/dist/sync/sync-innerspace.withid.respec.mjs.map +1 -1
  51. package/dist/sync/sync-peer/sync-peer-types.d.mts +4 -0
  52. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  53. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  54. package/dist/sync/sync-peer/sync-peer-v1.mjs +4 -1
  55. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  56. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -1
  57. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +90 -22
  58. package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -1
  59. package/dist/sync/sync-saga-coordinator.d.mts +7 -10
  60. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  61. package/dist/sync/sync-saga-coordinator.mjs +14 -5
  62. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  63. package/dist/sync/sync-types.d.mts +5 -0
  64. package/dist/sync/sync-types.d.mts.map +1 -1
  65. package/dist/sync/sync-types.mjs.map +1 -1
  66. package/dist/sync/sync-withid.connect.respec.mjs +4 -1
  67. package/dist/sync/sync-withid.connect.respec.mjs.map +1 -1
  68. package/dist/sync/sync-withid.establish.respec.mjs +4 -1
  69. package/dist/sync/sync-withid.establish.respec.mjs.map +1 -1
  70. package/dist/sync/sync-withid.pingpong.respec.mjs +4 -1
  71. package/dist/sync/sync-withid.pingpong.respec.mjs.map +1 -1
  72. package/package.json +2 -2
  73. package/src/keystone/keystone-constants.mts +1 -0
  74. package/src/keystone/keystone-helpers.mts +223 -15
  75. package/src/keystone/keystone-service-v1.mts +391 -28
  76. package/src/keystone/keystone-service-v1.respec.mts +1990 -1479
  77. package/src/keystone/keystone-types.mts +48 -2
  78. package/src/keystone/policy/keystone-profile-builder.mts +9 -1
  79. package/src/keystone/policy/profiles/profile-domain.json +69 -0
  80. package/src/keystone/policy/profiles/profile-sync.json +84 -0
  81. package/src/keystone/policy/schemas/keystone.high.schema.json +1 -1
  82. package/src/keystone/policy/schemas/keystone.medium.schema.json +1 -1
  83. package/src/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mts +20 -1
  84. package/src/sync/sync-conflict-adv-multitimelines.withid.respec.mts +16 -4
  85. package/src/sync/sync-conflict-basic-divergence.withid.respec.mts +4 -1
  86. package/src/sync/sync-conflict-basic-multitimelines.withid.respec.mts +4 -1
  87. package/src/sync/sync-conflict-text-merge.withid.respec.mts +10 -4
  88. package/src/sync/sync-innerspace-constants.withid.respec.mts +12 -3
  89. package/src/sync/sync-innerspace-deep-updates.withid.respec.mts +4 -1
  90. package/src/sync/sync-innerspace-dest-ahead.withid.respec.mts +4 -1
  91. package/src/sync/sync-innerspace-multiple-timelines.withid.respec.mts +4 -1
  92. package/src/sync/sync-innerspace-partial-update.withid.respec.mts +4 -1
  93. package/src/sync/sync-innerspace.withid.respec.mts +4 -1
  94. package/src/sync/sync-peer/sync-peer-types.mts +4 -0
  95. package/src/sync/sync-peer/sync-peer-v1.mts +5 -1
  96. package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +96 -22
  97. package/src/sync/sync-saga-coordinator.mts +17 -12
  98. package/src/sync/sync-types.mts +6 -0
  99. package/src/sync/sync-withid.connect.respec.mts +5 -2
  100. package/src/sync/sync-withid.establish.respec.mts +4 -1
  101. package/src/sync/sync-withid.pingpong.respec.mts +4 -1
  102. package/src/sync/unused-identity-backup.mts.md +0 -311
@@ -1,4 +1,4 @@
1
- import { extractErrorMsg, mergeMapsOrArrays_Naive } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
1
+ import { extractErrorMsg, mergeMapsOrArrays_Naive, getUUID } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
2
  import { getIbGibAddr, getIbAndGib } from '@ibgib/ts-gib/dist/helper.mjs';
3
3
  import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
4
4
  import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
@@ -7,18 +7,24 @@ import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
7
7
  import {
8
8
  KeystoneData_V1, KeystoneIbGib_V1, KeystonePoolConfig, KeystoneClaim,
9
9
  KeystoneChallengePool, KeystoneReplenishStrategy, KeystoneRevocationInfo,
10
- DelegateKeystoneStatus,
10
+ DelegateKeystoneStatus, KeystoneClaimType,
11
+ ClaimDetails_AddPool, ClaimDetails_ReplacePool, ClaimDetails_ChangePassword
11
12
  } from './keystone-types.mjs';
12
13
  import { KeystoneStrategyFactory } from './strategy/keystone-strategy-factory.mjs';
14
+ import { createStandardPoolConfig } from './keystone-config-builder.mjs';
13
15
  import {
14
16
  POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE,
15
- KEYSTONE_CHECKPOINT_FREQUENCY, POOL_ID_MANAGE
17
+ KEYSTONE_CHECKPOINT_FREQUENCY, POOL_ID_MANAGE, KEYSTONE_VERB_SYNC,
18
+ POOL_ID_CUSTODIAN_MANAGE,
19
+ KEYSTONE_CONFIG_DEFAULT_SIZE, KEYSTONE_CONFIG_DEFAULT_SEQUENTIAL,
20
+ KEYSTONE_CONFIG_DEFAULT_RANDOM, KEYSTONE_CONFIG_DEFAULT_BINDING
16
21
  } from './keystone-constants.mjs';
17
22
  import {
18
23
  createKeystoneIbGibImpl, evolvePersistAndRegisterKeystone,
19
24
  generateOpaqueChallengeId, resolveTargetPool, selectChallengeIds,
20
25
  solveAndReplenish, validateKeystoneTransition,
21
- validateGenesisKeystone, validateKeystoneGraph
26
+ validateGenesisKeystone, validateKeystoneGraph,
27
+ generatePoolChallenges, rotatePoolChallenges
22
28
  } from './keystone-helpers.mjs';
23
29
  import { getLatestAddrs } from '../witness/space/space-helper.mjs';
24
30
  import { IbGibSpaceAny } from '../witness/space/space-base-v1.mjs';
@@ -45,12 +51,14 @@ export class KeystoneService_V1 {
45
51
  configs,
46
52
  metaspace,
47
53
  space,
54
+ isPrimary,
48
55
  }: {
49
56
  masterSecret: string;
50
57
  frameDetails?: any;
51
58
  configs: KeystonePoolConfig[];
52
59
  metaspace: MetaspaceService;
53
60
  space: IbGibSpaceAny;
61
+ isPrimary?: boolean;
54
62
  }): Promise<KeystoneIbGib_V1> {
55
63
  const lc = `${this.lc}[${this.genesis.name}]`;
56
64
  try {
@@ -59,24 +67,10 @@ export class KeystoneService_V1 {
59
67
  const challengePools: KeystoneChallengePool[] = [];
60
68
 
61
69
  for (const config of configs) {
62
- const strategy = KeystoneStrategyFactory.create({ config });
63
- const poolSecret = await strategy.derivePoolSecret({ masterSecret });
64
- const challenges: { [id: string]: any } = {};
65
-
66
- const targetSize = config.behavior.size;
67
- const timestamp = Date.now().toString();
68
-
69
- for (let i = 0; i < targetSize; i++) {
70
- const challengeId = await generateOpaqueChallengeId({
71
- salt: config.salt, timestamp, index: i
72
- });
73
-
74
- const solution = await strategy.generateSolution({
75
- poolSecret, poolId: config.id, challengeId,
76
- });
77
- const challenge = await strategy.generateChallenge({ solution });
78
- challenges[challengeId] = challenge;
79
- }
70
+ const challenges = await generatePoolChallenges({
71
+ config,
72
+ masterSecret
73
+ });
80
74
 
81
75
  challengePools.push({
82
76
  id: config.id,
@@ -88,7 +82,12 @@ export class KeystoneService_V1 {
88
82
  if (challengePools.length === 0) { throw new Error(`No challenge pools created. (E: 38e538530996940e1f16a8b199995825)`); }
89
83
 
90
84
  const data: KeystoneData_V1 = { challengePools, proofs: [] };
91
- if (frameDetails) { data.frameDetails = frameDetails; }
85
+ if (frameDetails || isPrimary !== undefined) {
86
+ data.frameDetails = { ...(frameDetails || {}) };
87
+ if (isPrimary !== undefined) {
88
+ data.frameDetails.isPrimary = isPrimary;
89
+ }
90
+ }
92
91
  const keystoneIbGib = await createKeystoneIbGibImpl({ data, metaspace, space });
93
92
  return keystoneIbGib;
94
93
  } catch (error) {
@@ -260,6 +259,7 @@ export class KeystoneService_V1 {
260
259
  frameDetails,
261
260
  metaspace,
262
261
  space,
262
+ allowedVerbs,
263
263
  }: {
264
264
  parentKeystone: KeystoneIbGib_V1;
265
265
  delegateKeystone: KeystoneIbGib_V1;
@@ -267,6 +267,7 @@ export class KeystoneService_V1 {
267
267
  frameDetails?: any;
268
268
  metaspace: MetaspaceService;
269
269
  space: IbGibSpaceAny;
270
+ allowedVerbs: string[];
270
271
  }): Promise<KeystoneIbGib_V1> {
271
272
  const lc = `${this.lc}[${this.registerDelegate.name}]`;
272
273
  try {
@@ -305,6 +306,8 @@ export class KeystoneService_V1 {
305
306
  delegateTjpAddr,
306
307
  delegateAddr: getIbGibAddr({ ibGib: delegateKeystone }),
307
308
  thisAddr: getIbGibAddr({ ibGib: parentKeystone }),
309
+ // allowedVerbs: allowedVerbs ?? [KEYSTONE_VERB_SYNC], // NO! We cannot default to sync just to get things to work right now
310
+ allowedVerbs,
308
311
  };
309
312
 
310
313
  // 5. Sign & evolve parent keystone using the 'manage' pool
@@ -581,10 +584,10 @@ export class KeystoneService_V1 {
581
584
 
582
585
  const prevData = latestKeystone.data!;
583
586
 
584
- // 1. Identify Authority (Resolve Revoke Pool)
587
+ // 1. Identify Authority (Resolve Revoke Pool by verb)
585
588
  const pool = resolveTargetPool({
586
589
  pools: prevData.challengePools,
587
- poolId: POOL_ID_REVOKE // Explicitly require the special revoke pool
590
+ verb: KEYSTONE_VERB_REVOKE
588
591
  });
589
592
 
590
593
  // 2. Construct Claim
@@ -716,13 +719,15 @@ export class KeystoneService_V1 {
716
719
 
717
720
  if (logalot) { console.log(`${lc} Authorized via pool: ${adminPool.id}`); }
718
721
 
719
- // 2. Construct the Management Claim
722
+ // 2. Construct the Management Claim with typed details
720
723
  const target = getIbGibAddr({ ibGib: latestKeystone });
721
724
  const claim: Partial<KeystoneClaim> = {
722
725
  verb: KEYSTONE_VERB_MANAGE,
723
726
  target, // I am managing myself
724
- // Scope creates a cryptographic commitment to WHICH pools are being added
725
- scope: JSON.stringify({ add: newPools.map(p => p.id) })
727
+ details: {
728
+ type: KeystoneClaimType.add_pool,
729
+ info: { add: newPools.map(p => p.id) } as ClaimDetails_AddPool
730
+ }
726
731
  };
727
732
 
728
733
  // 3. Calculate Costs
@@ -850,4 +855,362 @@ export class KeystoneService_V1 {
850
855
  throw error;
851
856
  }
852
857
  }
858
+
859
+ /**
860
+ * Retrieves common aggregated info for a keystone timeline.
861
+ */
862
+ async getKeystoneCommonInfo({
863
+ addr,
864
+ ibGib,
865
+ metaspace,
866
+ space,
867
+ }: {
868
+ addr?: string;
869
+ ibGib?: KeystoneIbGib_V1;
870
+ metaspace: MetaspaceService;
871
+ space: IbGibSpaceAny;
872
+ }): Promise<{
873
+ name: string;
874
+ description: string;
875
+ isPrimary: boolean;
876
+ aggregateDetails: any;
877
+ latestFrameDetails: any;
878
+ n: number;
879
+ timestamp?: string;
880
+ timestampMs?: number;
881
+ } | null> {
882
+ const lc = `${this.lc}[getKeystoneCommonInfo]`;
883
+ try {
884
+ let targetAddr = addr;
885
+ let targetIbGib: any = ibGib;
886
+ if (!targetAddr) {
887
+ if (!targetIbGib) { return null; }
888
+ targetAddr = getIbGibAddr({ ibGib: targetIbGib });
889
+ }
890
+ if (!targetIbGib) {
891
+ const { ib, gib } = getIbAndGib({ ibGibAddr: targetAddr });
892
+ targetIbGib = { ib, gib };
893
+ }
894
+
895
+ const resGetLatest = await getLatestAddrs({
896
+ ibGibs: [targetIbGib],
897
+ space,
898
+ });
899
+
900
+ if (!resGetLatest.data?.latestAddrsMap) { return null; }
901
+ const latestAddr = resGetLatest.data.latestAddrsMap[targetAddr] || Object.values(resGetLatest.data.latestAddrsMap)[0];
902
+ if (!latestAddr) { return null; }
903
+
904
+ const resGet = await metaspace.get({ addr: latestAddr, space });
905
+ const latestKeystone = resGet.ibGibs?.at(0) as KeystoneIbGib_V1;
906
+ if (!latestKeystone || !latestKeystone.data) { return null; }
907
+
908
+ const aggregateDetails = await this.getAggregateDetails({
909
+ latestKeystone,
910
+ metaspace,
911
+ space
912
+ });
913
+
914
+ const name = aggregateDetails?.username || aggregateDetails?.profile?.name || aggregateDetails?.name || '';
915
+ const description = aggregateDetails?.description || aggregateDetails?.profile?.description || '';
916
+ const isPrimary = !!aggregateDetails?.isPrimary || !!aggregateDetails?.profile?.isPrimary;
917
+ const latestFrameDetails = latestKeystone.data.frameDetails || {};
918
+ const n = latestKeystone.data.n ?? 0;
919
+ const timestamp = latestFrameDetails?.timestamp || aggregateDetails?.timestamp || '';
920
+ const timestampMs = latestFrameDetails?.timestampMs || aggregateDetails?.timestampMs || undefined;
921
+
922
+ return {
923
+ name,
924
+ description,
925
+ isPrimary,
926
+ aggregateDetails,
927
+ latestFrameDetails,
928
+ n,
929
+ timestamp,
930
+ timestampMs
931
+ };
932
+ } catch (error) {
933
+ console.error(`${lc} ${extractErrorMsg(error)}`);
934
+ return null;
935
+ }
936
+ }
937
+
938
+ /**
939
+ * Replaces a challenge pool (such as manage or custodian-manage) with a new pool,
940
+ * authorizing the transition via the specified signing pool.
941
+ *
942
+ * @param latestKeystone The current tip frame of the keystone timeline.
943
+ * - Visibility: Public (Public Merkle frame, safe for logs/ledger).
944
+ * - Generator: Client/Server (Constructed locally and synced).
945
+ *
946
+ * @param newPool The fully constructed new pool to place in the next frame.
947
+ * - Visibility: Public (Public configuration and public challenges, safe for ledger).
948
+ * - Generator: Client/Server (Generated dynamically by the party proposing the update).
949
+ *
950
+ * @param signingSecret The master secret or derived KDF secret of the pool authorizing the change.
951
+ * - Visibility: Private (Confidential secret credential. Must never go over the wire).
952
+ * - Generator: Client/Server (Known only to the signing party).
953
+ *
954
+ * @param signingPoolId The ID of the pool used to authorize the transition (defaults to 'manage').
955
+ * - Visibility: Public (Non-sensitive configuration string).
956
+ * - Generator: Client/Server (From pool configuration).
957
+ */
958
+ async replacePool({
959
+ latestKeystone,
960
+ newPool,
961
+ signingSecret,
962
+ signingPoolId = POOL_ID_MANAGE,
963
+ frameDetails,
964
+ metaspace,
965
+ space,
966
+ }: {
967
+ latestKeystone: KeystoneIbGib_V1;
968
+ newPool: KeystoneChallengePool;
969
+ signingSecret: string;
970
+ signingPoolId?: string;
971
+ frameDetails?: any;
972
+ metaspace: MetaspaceService;
973
+ space: IbGibSpaceAny;
974
+ }): Promise<KeystoneIbGib_V1> {
975
+ const lc = `${this.lc}[${this.replacePool.name}]`;
976
+ try {
977
+ if (logalot) { console.log(`${lc} starting... replacing pool: ${newPool.id}`); }
978
+
979
+ if (!latestKeystone.data) { throw new Error(`(UNEXPECTED) latestKeystone.data falsy? (E: 1334c8faed128166a999d428c7805b25)`); }
980
+ const prevData = latestKeystone.data;
981
+
982
+ if (prevData.revocationInfo) { throw new Error(`Keystone has been revoked. Cannot replace pool. (E: 2599f8f51c78d722252ddb2894fdbe25)`); }
983
+
984
+ // 1. Identify Authority (Resolve Signing Pool)
985
+ const prevPools = prevData.challengePools;
986
+ const signingPool = prevPools.find(p => p.id === signingPoolId);
987
+ if (!signingPool) {
988
+ throw new Error(`Signing pool not found: ${signingPoolId} (E: 3599f8f51c78d722252ddb2894fdbe25)`);
989
+ }
990
+
991
+ // 2. Construct the Management Claim with typed details
992
+ const target = getIbGibAddr({ ibGib: latestKeystone });
993
+ const claim: Partial<KeystoneClaim> = {
994
+ verb: KEYSTONE_VERB_MANAGE,
995
+ target,
996
+ details: {
997
+ type: KeystoneClaimType.replace_pool,
998
+ info: { replace: newPool.id } as ClaimDetails_ReplacePool
999
+ }
1000
+ };
1001
+
1002
+ // 3. Calculate Costs
1003
+ const idsToSolve = await selectChallengeIds({
1004
+ pool: signingPool,
1005
+ targetAddr: target
1006
+ });
1007
+
1008
+ // 4. Pay the Cost (Solve & Replenish)
1009
+ const { proof, nextPools } = await solveAndReplenish({
1010
+ targetPoolId: signingPoolId,
1011
+ prevPools,
1012
+ masterSecret: signingSecret,
1013
+ challengeIds: idsToSolve,
1014
+ claim,
1015
+ });
1016
+
1017
+ // 5. Replace target pool in nextPools
1018
+ const targetIdx = nextPools.findIndex(p => p.id === newPool.id);
1019
+ if (targetIdx === -1) {
1020
+ throw new Error(`Target pool to replace '${newPool.id}' not found in keystone challenge pools.`);
1021
+ }
1022
+ nextPools[targetIdx] = newPool;
1023
+
1024
+ // 6. Construct New Data
1025
+ const n = (prevData.n ?? 0) + 1;
1026
+ let checkpointDetails: any | undefined;
1027
+ if (n % KEYSTONE_CHECKPOINT_FREQUENCY === 0) {
1028
+ const currentFrameView: KeystoneIbGib_V1 = {
1029
+ ...latestKeystone,
1030
+ data: { ...prevData, frameDetails }
1031
+ };
1032
+ checkpointDetails = await this.getAggregateDetails({
1033
+ latestKeystone: currentFrameView,
1034
+ metaspace,
1035
+ space
1036
+ });
1037
+ }
1038
+
1039
+ const newData: KeystoneData_V1 = {
1040
+ challengePools: nextPools,
1041
+ proofs: [proof],
1042
+ frameDetails,
1043
+ checkpointDetails,
1044
+ ...(prevData.delegates ? { delegates: prevData.delegates } : {}),
1045
+ };
1046
+
1047
+ // 7. Commit
1048
+ const newKeystone = await evolvePersistAndRegisterKeystone({
1049
+ prevIbGib: latestKeystone,
1050
+ newData,
1051
+ metaspace,
1052
+ space
1053
+ });
1054
+
1055
+ return newKeystone;
1056
+ } catch (error) {
1057
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1058
+ throw error;
1059
+ } finally {
1060
+ if (logalot) { console.log(`${lc} complete.`); }
1061
+ }
1062
+ }
1063
+
1064
+ /**
1065
+ * Evolve the keystone by rotating the primary user manage pool (`manage`) to a new master secret (passphrase).
1066
+ * This creates a new frame signed by the specified `signingPoolId` using `signingSecret`.
1067
+ *
1068
+ * Supports recovery (signing via `custodian-manage` using the custodian secret) and normal rotation
1069
+ * (signing via `manage` using the old password).
1070
+ *
1071
+ * @param latestKeystone The current tip frame of the keystone.
1072
+ * - Visibility: Public (Public Merkle frame, safe for ledger).
1073
+ * - Generator: Client/Server (Constructed locally and synced).
1074
+ *
1075
+ * @param newMasterSecret The new passphrase/master secret to set for the user's primary pools.
1076
+ * - Visibility: Private (Confidential secret credential. Must never go over the wire).
1077
+ * - Generator: Client (From user input in settings).
1078
+ *
1079
+ * @param signingSecret The secret of the pool authorizing this change (either old passphrase or derived custodian secret).
1080
+ * - Visibility: Private (Confidential secret. Must never go over the wire).
1081
+ * - Generator: Client/Server (Known only to the signing party).
1082
+ *
1083
+ * @param signingPoolId The ID of the pool used to authorize the rotation (defaults to 'manage').
1084
+ * - Visibility: Public (Non-sensitive ID string).
1085
+ * - Generator: Client/Server (From pool configuration).
1086
+ */
1087
+ async changePassword({
1088
+ latestKeystone,
1089
+ newMasterSecret,
1090
+ signingSecret,
1091
+ signingPoolId = POOL_ID_MANAGE,
1092
+ poolIds,
1093
+ frameDetails,
1094
+ metaspace,
1095
+ space,
1096
+ }: {
1097
+ latestKeystone: KeystoneIbGib_V1;
1098
+ newMasterSecret: string;
1099
+ signingSecret: string;
1100
+ signingPoolId?: string;
1101
+ poolIds?: string[];
1102
+ frameDetails?: any;
1103
+ metaspace: MetaspaceService;
1104
+ space: IbGibSpaceAny;
1105
+ }): Promise<KeystoneIbGib_V1> {
1106
+ const lc = `${this.lc}[${this.changePassword.name}]`;
1107
+ try {
1108
+ if (logalot) { console.log(`${lc} starting...`); }
1109
+
1110
+ if (!latestKeystone.data) { throw new Error(`latestKeystone.data falsy`); }
1111
+ if (latestKeystone.data.revocationInfo) { throw new Error(`Keystone has been revoked. Cannot change password. (E: 8599f8f51c78d722252ddb2894fdbe25)`); }
1112
+
1113
+ const prevPools = latestKeystone.data.challengePools;
1114
+ const signingPool = prevPools.find(p => p.id === signingPoolId);
1115
+ if (!signingPool) {
1116
+ throw new Error(`Signing pool not found: ${signingPoolId} (E: 3599f8f51c78d722252ddb2894fdbe25)`);
1117
+ }
1118
+
1119
+ // 1. Resolve target pools to rotate
1120
+ let targets: KeystoneChallengePool[] = [];
1121
+ if (poolIds && poolIds.length > 0) {
1122
+ for (const id of poolIds) {
1123
+ const found = prevPools.find(p => p.id === id);
1124
+ if (!found) {
1125
+ throw new Error(`Target pool to rotate not found: ${id} (E: 4599f8f51c78d722252ddb2894fdbe25)`);
1126
+ }
1127
+ targets.push(found);
1128
+ }
1129
+ } else {
1130
+ targets = prevPools.filter(p => !p.isForeign);
1131
+ if (targets.length === 0) {
1132
+ throw new Error(`No non-foreign pools found to rotate. (E: 5599f8f51c78d722252ddb2894fdbe25)`);
1133
+ }
1134
+ }
1135
+
1136
+ // 2. Rotate the target pools
1137
+ const rotatedPools: KeystoneChallengePool[] = [];
1138
+ for (const targetPool of targets) {
1139
+ const rotated = await rotatePoolChallenges({
1140
+ prevPool: targetPool,
1141
+ newMasterSecret
1142
+ });
1143
+ rotatedPools.push(rotated);
1144
+ }
1145
+
1146
+ // 3. Construct Management Claim with typed details
1147
+ const target = getIbGibAddr({ ibGib: latestKeystone });
1148
+ const claim: Partial<KeystoneClaim> = {
1149
+ verb: KEYSTONE_VERB_MANAGE,
1150
+ target,
1151
+ details: {
1152
+ type: KeystoneClaimType.change_password,
1153
+ info: { change: rotatedPools.map(p => p.id) } as ClaimDetails_ChangePassword
1154
+ }
1155
+ };
1156
+
1157
+ // 4. Calculate Costs
1158
+ const idsToSolve = await selectChallengeIds({
1159
+ pool: signingPool,
1160
+ targetAddr: target
1161
+ });
1162
+
1163
+ // 5. Pay the Cost (Solve & Replenish)
1164
+ const { proof, nextPools } = await solveAndReplenish({
1165
+ targetPoolId: signingPoolId,
1166
+ prevPools,
1167
+ masterSecret: signingSecret,
1168
+ challengeIds: idsToSolve,
1169
+ claim
1170
+ });
1171
+
1172
+ // 6. Swap the rotated pools in nextPools
1173
+ for (const rotated of rotatedPools) {
1174
+ const idx = nextPools.findIndex(p => p.id === rotated.id);
1175
+ if (idx === -1) {
1176
+ throw new Error(`Rotated pool ${rotated.id} not found in next pools list. (E: 6599f8f51c78d722252ddb2894fdbe25)`);
1177
+ }
1178
+ nextPools[idx] = rotated;
1179
+ }
1180
+
1181
+ // 7. Construct New Data
1182
+ const n = (latestKeystone.data.n ?? 0) + 1;
1183
+ let checkpointDetails: any | undefined;
1184
+ if (n % KEYSTONE_CHECKPOINT_FREQUENCY === 0) {
1185
+ const currentFrameView: KeystoneIbGib_V1 = {
1186
+ ...latestKeystone,
1187
+ data: { ...latestKeystone.data, challengePools: nextPools }
1188
+ };
1189
+ checkpointDetails = await this.getAggregateDetails({
1190
+ latestKeystone: currentFrameView,
1191
+ metaspace,
1192
+ space
1193
+ });
1194
+ }
1195
+
1196
+ const newData: KeystoneData_V1 = {
1197
+ challengePools: nextPools,
1198
+ proofs: [proof],
1199
+ frameDetails,
1200
+ checkpointDetails,
1201
+ ...(latestKeystone.data.delegates ? { delegates: latestKeystone.data.delegates } : {}),
1202
+ };
1203
+
1204
+ // 8. Commit
1205
+ return await evolvePersistAndRegisterKeystone({
1206
+ prevIbGib: latestKeystone,
1207
+ newData,
1208
+ metaspace,
1209
+ space
1210
+ });
1211
+ } catch (error) {
1212
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1213
+ throw error;
1214
+ }
1215
+ }
853
1216
  }