@ibgib/core-gib 0.1.64 → 0.1.66
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/CHANGELOG.md +7 -0
- package/dist/keystone/keystone-helpers.d.mts +8 -0
- package/dist/keystone/keystone-helpers.d.mts.map +1 -1
- package/dist/keystone/keystone-helpers.mjs +74 -4
- package/dist/keystone/keystone-helpers.mjs.map +1 -1
- package/dist/keystone/keystone-service-v1.d.mts +85 -18
- package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
- package/dist/keystone/keystone-service-v1.mjs +178 -22
- package/dist/keystone/keystone-service-v1.mjs.map +1 -1
- package/dist/keystone/keystone-service-v1.respec.mjs +780 -340
- package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
- package/dist/keystone/keystone-types.d.mts +15 -2
- package/dist/keystone/keystone-types.d.mts.map +1 -1
- package/dist/keystone/keystone-types.mjs +2 -0
- package/dist/keystone/keystone-types.mjs.map +1 -1
- package/dist/keystone/policy/profiles/profile-domain.json +2 -46
- package/dist/keystone/policy/profiles/profile-sync.json +2 -16
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts +27 -4
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +230 -135
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs.map +1 -1
- package/package.json +1 -1
- package/src/keystone/keystone-helpers.mts +89 -4
- package/src/keystone/keystone-service-v1.mts +262 -34
- package/src/keystone/keystone-service-v1.respec.mts +792 -376
- package/src/keystone/keystone-types.mts +16 -1
- package/src/keystone/policy/profiles/profile-domain.json +2 -46
- package/src/keystone/policy/profiles/profile-sync.json +2 -16
- package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +294 -131
- package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mts +1 -1
|
@@ -258,17 +258,20 @@ export interface KeystoneChallengePool {
|
|
|
258
258
|
|
|
259
259
|
// #region KeystoneClaimType enum
|
|
260
260
|
export const KEYSTONE_CLAIM_TYPE_ADD_POOL = 'add-pool';
|
|
261
|
+
export const KEYSTONE_CLAIM_TYPE_REMOVE_POOL = 'remove-pool';
|
|
261
262
|
export const KEYSTONE_CLAIM_TYPE_REPLACE_POOL = 'replace-pool';
|
|
262
263
|
export const KEYSTONE_CLAIM_TYPE_CHANGE_PASSWORD = 'change-password';
|
|
263
264
|
|
|
264
265
|
export type KeystoneClaimType =
|
|
265
266
|
| typeof KEYSTONE_CLAIM_TYPE_ADD_POOL
|
|
267
|
+
| typeof KEYSTONE_CLAIM_TYPE_REMOVE_POOL
|
|
266
268
|
| typeof KEYSTONE_CLAIM_TYPE_REPLACE_POOL
|
|
267
269
|
| typeof KEYSTONE_CLAIM_TYPE_CHANGE_PASSWORD
|
|
268
270
|
;
|
|
269
271
|
|
|
270
272
|
export const KeystoneClaimType = {
|
|
271
273
|
add_pool: KEYSTONE_CLAIM_TYPE_ADD_POOL,
|
|
274
|
+
remove_pool: KEYSTONE_CLAIM_TYPE_REMOVE_POOL,
|
|
272
275
|
replace_pool: KEYSTONE_CLAIM_TYPE_REPLACE_POOL,
|
|
273
276
|
change_password: KEYSTONE_CLAIM_TYPE_CHANGE_PASSWORD,
|
|
274
277
|
} satisfies { readonly [key: string]: KeystoneClaimType };
|
|
@@ -289,6 +292,10 @@ export interface ClaimDetails_AddPool {
|
|
|
289
292
|
add: string[];
|
|
290
293
|
}
|
|
291
294
|
|
|
295
|
+
export interface ClaimDetails_RemovePool {
|
|
296
|
+
remove: string[];
|
|
297
|
+
}
|
|
298
|
+
|
|
292
299
|
export interface ClaimDetails_ReplacePool {
|
|
293
300
|
replace: string;
|
|
294
301
|
}
|
|
@@ -366,12 +373,20 @@ export interface DelegateKeystoneInfo {
|
|
|
366
373
|
*/
|
|
367
374
|
delegateTjpAddr: IbGibAddr;
|
|
368
375
|
/**
|
|
369
|
-
*
|
|
376
|
+
* Concrete addr of **DELEGATE** keystone **at the time when the
|
|
370
377
|
* delegate was added.**
|
|
371
378
|
*
|
|
372
379
|
* So if we have a delegate keystone at D3, then this value would be the
|
|
373
380
|
* addr of that D3 keystone. This will have both a `punctiliarHash` and a
|
|
374
381
|
* `tjpGib` in its `GibInfo`.
|
|
382
|
+
*
|
|
383
|
+
* ## intent / architecture (ATOW 07/2026)
|
|
384
|
+
*
|
|
385
|
+
* This address captures the registration context of when the delegate was bound.
|
|
386
|
+
* Delegates are designed to evolve **independently** by design as to *not* require
|
|
387
|
+
* us to update the parent identity keystone whenever a delegate evolves.
|
|
388
|
+
* To resolve the active tip of a delegate's timeline, query the space via
|
|
389
|
+
* `keystoneService.getLatestKeystone({ addr: delegateTjpAddr, metaspace, space })`.
|
|
375
390
|
*/
|
|
376
391
|
delegateAddr: IbGibAddr;
|
|
377
392
|
/**
|
|
@@ -5,25 +5,11 @@
|
|
|
5
5
|
"securityLevel": "high"
|
|
6
6
|
},
|
|
7
7
|
"pools": {
|
|
8
|
-
"sync": {
|
|
9
|
-
"id": "sync",
|
|
10
|
-
"allowedVerbs": [
|
|
11
|
-
"sync"
|
|
12
|
-
],
|
|
13
|
-
"algo": "SHA-512",
|
|
14
|
-
"rounds": 4,
|
|
15
|
-
"behavior": {
|
|
16
|
-
"size": 2000,
|
|
17
|
-
"replenish": "top-up",
|
|
18
|
-
"selectSequentially": 10,
|
|
19
|
-
"selectRandomly": 10,
|
|
20
|
-
"targetBindingCount": 16
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
8
|
"manage": {
|
|
24
9
|
"id": "manage",
|
|
25
10
|
"allowedVerbs": [
|
|
26
|
-
"manage"
|
|
11
|
+
"manage",
|
|
12
|
+
"revoke"
|
|
27
13
|
],
|
|
28
14
|
"algo": "SHA-512",
|
|
29
15
|
"rounds": 6,
|
|
@@ -34,36 +20,6 @@
|
|
|
34
20
|
"selectRandomly": 12,
|
|
35
21
|
"targetBindingCount": 16
|
|
36
22
|
}
|
|
37
|
-
},
|
|
38
|
-
"revoke": {
|
|
39
|
-
"id": "revoke",
|
|
40
|
-
"allowedVerbs": [
|
|
41
|
-
"revoke"
|
|
42
|
-
],
|
|
43
|
-
"algo": "SHA-512",
|
|
44
|
-
"rounds": 20,
|
|
45
|
-
"behavior": {
|
|
46
|
-
"size": 2000,
|
|
47
|
-
"replenish": "delete-all",
|
|
48
|
-
"selectSequentially": 50,
|
|
49
|
-
"selectRandomly": 50,
|
|
50
|
-
"targetBindingCount": 0
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"sign": {
|
|
54
|
-
"id": "default",
|
|
55
|
-
"allowedVerbs": [
|
|
56
|
-
"sign"
|
|
57
|
-
],
|
|
58
|
-
"algo": "SHA-512",
|
|
59
|
-
"rounds": 4,
|
|
60
|
-
"behavior": {
|
|
61
|
-
"size": 2000,
|
|
62
|
-
"replenish": "top-up",
|
|
63
|
-
"selectSequentially": 10,
|
|
64
|
-
"selectRandomly": 10,
|
|
65
|
-
"targetBindingCount": 16
|
|
66
|
-
}
|
|
67
23
|
}
|
|
68
24
|
}
|
|
69
25
|
}
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"manage": {
|
|
24
24
|
"id": "manage",
|
|
25
25
|
"allowedVerbs": [
|
|
26
|
-
"manage"
|
|
26
|
+
"manage",
|
|
27
|
+
"revoke"
|
|
27
28
|
],
|
|
28
29
|
"algo": "SHA-256",
|
|
29
30
|
"rounds": 2,
|
|
@@ -35,21 +36,6 @@
|
|
|
35
36
|
"targetBindingCount": 8
|
|
36
37
|
}
|
|
37
38
|
},
|
|
38
|
-
"revoke": {
|
|
39
|
-
"id": "revoke",
|
|
40
|
-
"allowedVerbs": [
|
|
41
|
-
"revoke"
|
|
42
|
-
],
|
|
43
|
-
"algo": "SHA-256",
|
|
44
|
-
"rounds": 5,
|
|
45
|
-
"behavior": {
|
|
46
|
-
"size": 100,
|
|
47
|
-
"replenish": "delete-all",
|
|
48
|
-
"selectSequentially": 3,
|
|
49
|
-
"selectRandomly": 3,
|
|
50
|
-
"targetBindingCount": 0
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
39
|
"connect": {
|
|
54
40
|
"id": "connect",
|
|
55
41
|
"allowedVerbs": [
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { HashAlgorithm, extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
9
9
|
import { getIbGibAddr, getIbAndGib } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
10
|
+
import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
|
|
10
11
|
import { validateIbGibAddr, validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
|
|
11
12
|
import { getGibInfo } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
|
|
12
13
|
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
@@ -14,14 +15,16 @@ import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
|
14
15
|
import { GLOBAL_LOG_A_LOT } from '../../../../core-constants.mjs';
|
|
15
16
|
import {
|
|
16
17
|
KeystoneReplenishStrategy, KeystoneChallengeType, KeystoneIbGib_V1,
|
|
17
|
-
KeystoneSolution, KeystoneChallenge
|
|
18
|
+
KeystoneSolution, KeystoneChallenge,
|
|
19
|
+
KEYSTONE_CLAIM_TYPE_CHANGE_PASSWORD, KEYSTONE_CLAIM_TYPE_ADD_POOL,
|
|
20
|
+
KEYSTONE_CLAIM_TYPE_REMOVE_POOL, KEYSTONE_CLAIM_TYPE_REPLACE_POOL
|
|
18
21
|
} from '../../../../keystone/keystone-types.mjs';
|
|
19
|
-
import { parseKeystoneIb } from '../../../../keystone/keystone-helpers.mjs';
|
|
22
|
+
import { parseKeystoneIb, validateKeystoneIb } from '../../../../keystone/keystone-helpers.mjs';
|
|
20
23
|
import { KeystoneStrategyFactory } from '../../../../keystone/strategy/keystone-strategy-factory.mjs';
|
|
21
24
|
import { KeystoneService_V1 } from '../../../../keystone/keystone-service-v1.mjs';
|
|
22
25
|
import { IbGibSpaceAny } from '../../../../witness/space/space-base-v1.mjs';
|
|
23
26
|
import { MetaspaceService } from '../../../../witness/space/metaspace/metaspace-types.mjs';
|
|
24
|
-
import { POOL_ID_CONNECT, KEYSTONE_VERB_CONNECT, KEYSTONE_VERB_SYNC } from '../../../../keystone/keystone-constants.mjs';
|
|
27
|
+
import { POOL_ID_CONNECT, KEYSTONE_VERB_CONNECT, KEYSTONE_VERB_SYNC, KEYSTONE_VERB_MANAGE } from '../../../../keystone/keystone-constants.mjs';
|
|
25
28
|
import { getTjpAddr } from '../../../../common/other/ibgib-helper.mjs';
|
|
26
29
|
|
|
27
30
|
const logalot = GLOBAL_LOG_A_LOT
|
|
@@ -270,35 +273,69 @@ export async function validateAndRegisterPostKeystones({
|
|
|
270
273
|
}
|
|
271
274
|
|
|
272
275
|
/**
|
|
273
|
-
* Isomorphic pure function to validate a keystone evolution transition and
|
|
274
|
-
* and persist them to metaspace. Shared across
|
|
276
|
+
* Isomorphic pure function to validate a keystone evolution transition and
|
|
277
|
+
* related S session keystones, and persist them to metaspace. Shared across
|
|
278
|
+
* REST API evolve handlers and future socket evolution channels.
|
|
275
279
|
*/
|
|
276
280
|
export async function validateAndRegisterEvolveKeystone({
|
|
277
281
|
domainAddr,
|
|
278
282
|
keystoneIbGib,
|
|
279
|
-
|
|
283
|
+
relatedKeystoneIbGibs = [],
|
|
280
284
|
metaspace,
|
|
281
285
|
space
|
|
282
286
|
}: {
|
|
287
|
+
/**
|
|
288
|
+
* Address of the root parent domain identity keystone.
|
|
289
|
+
*/
|
|
283
290
|
domainAddr: string;
|
|
291
|
+
/**
|
|
292
|
+
* The main evolved keystone frame being synchronized.
|
|
293
|
+
*/
|
|
284
294
|
keystoneIbGib: KeystoneIbGib_V1;
|
|
285
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Array of other keystone frames related to this evolution.
|
|
297
|
+
* Distinction in intent:
|
|
298
|
+
* 1. Ephemeral Session Keystones: Temporary keystones generated to verify
|
|
299
|
+
* WebSocket connection sessions (under 'sync' claims, targeted via
|
|
300
|
+
* claim.target = sAddr).
|
|
301
|
+
* 2. Persistent Delegate Keystones: Long-lived sub-keystones registered in
|
|
302
|
+
* the parent's `delegates` dictionary that are evolved concurrently
|
|
303
|
+
* (e.g., during 'manage' password changes).
|
|
304
|
+
*/
|
|
305
|
+
relatedKeystoneIbGibs?: IbGib_V1[];
|
|
306
|
+
/**
|
|
307
|
+
* The MetaspaceService instance.
|
|
308
|
+
*/
|
|
286
309
|
metaspace: MetaspaceService;
|
|
310
|
+
/**
|
|
311
|
+
* The active storage space.
|
|
312
|
+
*/
|
|
287
313
|
space: IbGibSpaceAny;
|
|
288
314
|
}): Promise<void> {
|
|
289
315
|
const lc = `[${validateAndRegisterEvolveKeystone.name}]`;
|
|
290
316
|
try {
|
|
291
317
|
if (logalot) { console.log(`${lc} starting... (I: 42b826a690881cd5a8fe520cbdfad826)`); }
|
|
292
318
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
// 1. Intrinsic hash validation
|
|
319
|
+
// 1. Intrinsic hash validation on primary keystone
|
|
296
320
|
const intrinsicErrors = await validateIbGibIntrinsically({ ibGib: keystoneIbGib });
|
|
297
321
|
if (intrinsicErrors && intrinsicErrors.length > 0) {
|
|
298
322
|
throw new Error(`Intrinsic keystone validation failed: ${intrinsicErrors.join(', ')} (E: 38ea984585edc6ee88d2a698c7895826)`);
|
|
299
323
|
}
|
|
300
324
|
|
|
301
|
-
// 2.
|
|
325
|
+
// 2. Proofs & Verb extraction
|
|
326
|
+
const proofs = keystoneIbGib.data?.proofs ?? [];
|
|
327
|
+
if (proofs.length === 0) {
|
|
328
|
+
throw new Error('No proofs found in evolved keystone data (E: 399f8f51c78d722252ddb2894fdbe25)');
|
|
329
|
+
}
|
|
330
|
+
if (proofs.length !== 1) {
|
|
331
|
+
throw new Error(`evolving keystone with proofs.length !== 1? (E: 14e058a34964dcd7181395382cc60826)`);
|
|
332
|
+
}
|
|
333
|
+
const claim = proofs[0].claim;
|
|
334
|
+
if (!claim) { throw new Error(`proof.claim is falsy (E: 54be88be2c975ef18e571a4286928826)`); }
|
|
335
|
+
const verb = claim.verb;
|
|
336
|
+
if (!verb) { throw new Error(`claim.verb is falsy (E: 92cf38af58db2cd90e7132b8940fe326)`); }
|
|
337
|
+
|
|
338
|
+
// 3. Load latest root Domain Identity tip in space
|
|
302
339
|
const keystoneService = new KeystoneService_V1();
|
|
303
340
|
let parentKeystone: KeystoneIbGib_V1;
|
|
304
341
|
try {
|
|
@@ -318,147 +355,273 @@ export async function validateAndRegisterEvolveKeystone({
|
|
|
318
355
|
}
|
|
319
356
|
|
|
320
357
|
const isDelegate = incomingTjpAddr !== parentTjpAddr;
|
|
321
|
-
let prevIbGib: KeystoneIbGib_V1 | undefined;
|
|
322
|
-
|
|
323
|
-
if (isDelegate) {
|
|
324
|
-
// Verify that the delegate is registered under the root Domain Identity
|
|
325
|
-
const delegateInfo = parentKeystone.data?.delegates?.[incomingTjpAddr];
|
|
326
|
-
if (!delegateInfo) {
|
|
327
|
-
throw new Error(`Incoming delegate keystone (${incomingTjpAddr}) is not registered under parent Domain Identity (${parentTjpAddr}) (E: c288fae39b7d82fe)`);
|
|
328
|
-
}
|
|
329
358
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
359
|
+
// 4. Primary Verb Branching
|
|
360
|
+
switch (verb) {
|
|
361
|
+
case KEYSTONE_VERB_MANAGE:
|
|
362
|
+
await validateManageEvolveKeystone({
|
|
363
|
+
keystoneIbGib,
|
|
364
|
+
relatedKeystoneIbGibs,
|
|
365
|
+
parentKeystone,
|
|
366
|
+
isDelegate,
|
|
367
|
+
domainAddr,
|
|
368
|
+
metaspace,
|
|
369
|
+
space
|
|
370
|
+
});
|
|
371
|
+
break;
|
|
372
|
+
|
|
373
|
+
case KEYSTONE_VERB_SYNC:
|
|
374
|
+
await validateSyncEvolveKeystone({
|
|
375
|
+
keystoneIbGib,
|
|
376
|
+
relatedKeystoneIbGibs,
|
|
377
|
+
parentKeystone,
|
|
378
|
+
isDelegate,
|
|
379
|
+
domainAddr,
|
|
380
|
+
metaspace,
|
|
381
|
+
space
|
|
382
|
+
});
|
|
383
|
+
break;
|
|
335
384
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
addr: incomingTjpAddr,
|
|
339
|
-
space
|
|
340
|
-
});
|
|
341
|
-
if (delegateLatestAddr) {
|
|
342
|
-
const resGet = await metaspace.get({ addr: delegateLatestAddr, space });
|
|
343
|
-
if (resGet.success && resGet.ibGibs && resGet.ibGibs.length > 0) {
|
|
344
|
-
prevIbGib = resGet.ibGibs[0] as KeystoneIbGib_V1;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
} else {
|
|
348
|
-
// For root Domain Identity evolution, it must transition from the parent keystone tip
|
|
349
|
-
prevIbGib = parentKeystone;
|
|
385
|
+
default:
|
|
386
|
+
throw new Error(`Unsupported keystone evolution verb: ${verb} (E: eca4681b05486d1f784c0cb815ef9926)`);
|
|
350
387
|
}
|
|
351
388
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
throw new Error(`Keystone evolution validation failed: ${validationErrors.join(', ')} (E: 5212f8492ac839953842631834bcd826)`);
|
|
360
|
-
}
|
|
361
|
-
} else {
|
|
362
|
-
// Validate delegate's genesis or entire graph if no previous tip exists
|
|
363
|
-
const validationErrors = await keystoneService.validateKeystoneGraph({
|
|
364
|
-
keystoneIbGib,
|
|
365
|
-
getLatest: false,
|
|
366
|
-
invalidIfMoreRecentKeystoneFoundInSpace: false,
|
|
367
|
-
space
|
|
368
|
-
});
|
|
369
|
-
if (validationErrors && validationErrors.length > 0) {
|
|
370
|
-
throw new Error(`Keystone graph validation failed: ${validationErrors.join(', ')} (E: 3a288fae39b7d82e)`);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
391
|
+
throw error;
|
|
392
|
+
} finally {
|
|
393
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
394
|
+
}
|
|
395
|
+
}
|
|
373
396
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
397
|
+
/**
|
|
398
|
+
* Validates and registers a keystone evolution authorized by a 'manage' verb claim.
|
|
399
|
+
*
|
|
400
|
+
* ## Assumptions (ATOW 07/2026)
|
|
401
|
+
* - The primary Domain Identity evolution step is authorized by a single proof.
|
|
402
|
+
* - Sub-verb details (`claim.details?.type`) specify the structural management operation
|
|
403
|
+
* (e.g. 'change-password', 'add-pool', 'remove-pool').
|
|
404
|
+
* - Under 'change-password', relatedKeystoneIbGibs contains outward delegate keystones being
|
|
405
|
+
* registered or evolved concurrently.
|
|
406
|
+
* - Delegates evolve independently by design, so `delegateInfo.delegateAddr` in the parent keystone
|
|
407
|
+
* captures historical registration context. Active delegate tip resolution queries the space via
|
|
408
|
+
* `keystoneService.getLatestKeystone({ addr: delegateTjpAddr, metaspace, space })`.
|
|
409
|
+
*/
|
|
410
|
+
async function validateManageEvolveKeystone({
|
|
411
|
+
keystoneIbGib,
|
|
412
|
+
relatedKeystoneIbGibs,
|
|
413
|
+
parentKeystone,
|
|
414
|
+
isDelegate,
|
|
415
|
+
domainAddr,
|
|
416
|
+
metaspace,
|
|
417
|
+
space,
|
|
418
|
+
}: {
|
|
419
|
+
keystoneIbGib: KeystoneIbGib_V1;
|
|
420
|
+
relatedKeystoneIbGibs: IbGib_V1[];
|
|
421
|
+
parentKeystone: KeystoneIbGib_V1;
|
|
422
|
+
isDelegate: boolean;
|
|
423
|
+
domainAddr: IbGibAddr;
|
|
424
|
+
metaspace: MetaspaceService;
|
|
425
|
+
space: IbGibSpaceAny;
|
|
426
|
+
}): Promise<void> {
|
|
427
|
+
const lc = `[validateManageEvolveKeystone]`;
|
|
428
|
+
const keystoneService = new KeystoneService_V1();
|
|
429
|
+
|
|
430
|
+
// 1. Validate parent Domain Identity keystone transition from current tip in space
|
|
431
|
+
const transitionErrors = await keystoneService.validate({
|
|
432
|
+
currentIbGib: keystoneIbGib,
|
|
433
|
+
prevIbGib: parentKeystone
|
|
434
|
+
});
|
|
435
|
+
if (transitionErrors && transitionErrors.length > 0) {
|
|
436
|
+
throw new Error(`Parent Domain Identity evolution validation failed: ${transitionErrors.join(', ')} (E: 5212f8492ac839953842631834bcd826)`);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const proof = keystoneIbGib.data?.proofs?.[0];
|
|
440
|
+
const claim = proof?.claim;
|
|
441
|
+
const claimType = claim?.details?.type;
|
|
442
|
+
|
|
443
|
+
const prevDelegates = parentKeystone.data?.delegates ?? {};
|
|
444
|
+
const currDelegates = keystoneIbGib.data?.delegates ?? {};
|
|
445
|
+
|
|
446
|
+
// 2. Sub-verb branching based on claim details type
|
|
447
|
+
switch (claimType) {
|
|
448
|
+
case KEYSTONE_CLAIM_TYPE_CHANGE_PASSWORD:
|
|
449
|
+
case KEYSTONE_CLAIM_TYPE_ADD_POOL:
|
|
450
|
+
case KEYSTONE_CLAIM_TYPE_REMOVE_POOL:
|
|
451
|
+
case KEYSTONE_CLAIM_TYPE_REPLACE_POOL:
|
|
452
|
+
default:
|
|
453
|
+
// Validate all related delegate keystones provided in cargo
|
|
454
|
+
for (const related of relatedKeystoneIbGibs) {
|
|
455
|
+
const ibIsValid = await validateKeystoneIb({ ib: related.ib });
|
|
456
|
+
if (!ibIsValid) {
|
|
457
|
+
throw new Error(`Invalid related keystone ibgib. related.ib (${related.ib}) is not a valid keystone ib. (E: 89dff2f48fa8c33b449081e2478c6826)`);
|
|
384
458
|
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
if (poolIds.size > 1) {
|
|
388
|
-
throw new Error(`Multiple pools evolved (${Array.from(poolIds).join(', ')}). Only one pool evolution allowed at a time. (E: 4a9b28ae33e8e3eb4ddbad981aa7b126)`);
|
|
389
|
-
}
|
|
390
459
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
460
|
+
const relatedTjp = getTjpAddr({ ibGib: related });
|
|
461
|
+
if (!relatedTjp) {
|
|
462
|
+
throw new Error(`Related keystone in relatedKeystoneIbGibs is missing a TJP address (E: 2fe5a68438e288ab4e86c90d81d142826)`);
|
|
463
|
+
}
|
|
464
|
+
const relatedAddr = getIbGibAddr({ ibGib: related });
|
|
465
|
+
|
|
466
|
+
// Assert it is registered under the current delegates map of the parent
|
|
467
|
+
const delegateInfo = currDelegates[relatedTjp];
|
|
468
|
+
if (!delegateInfo) {
|
|
469
|
+
throw new Error(`Related keystone (${relatedTjp}) is not a registered delegate under parent Domain Identity (E: 3fe5a68438e288ab4e86c90d81d142826)`);
|
|
470
|
+
}
|
|
397
471
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const delegateAddr = delegateInfo.delegateAddr;
|
|
404
|
-
const delegateIbGib = relatedIbGibs.find(ibGib => getIbGibAddr({ ibGib }) === delegateAddr);
|
|
405
|
-
if (!delegateIbGib) {
|
|
406
|
-
throw new Error(`Evolved delegate keystone ${delegateAddr} must be provided in relatedIbGibs (E: 1fe5a68438e288ab4e86c90d81d142826)`);
|
|
472
|
+
const delegateIsNewlyRegistered = !prevDelegates[relatedTjp];
|
|
473
|
+
if (delegateIsNewlyRegistered) {
|
|
474
|
+
const delegateKeystone = related as KeystoneIbGib_V1;
|
|
475
|
+
if (delegateKeystone.data?.n !== 0) {
|
|
476
|
+
throw new Error(`Newly registered delegate keystone (${relatedAddr}) has data.n !== 0 (${delegateKeystone.data?.n}). Registering non-genesis delegate keystones is not supported at this time. (E: 4cdd0dee42d7d437ef6af698150cfe26)`);
|
|
407
477
|
}
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
478
|
+
const genesisErrors = await keystoneService.validateGenesisKeystone({
|
|
479
|
+
keystoneIbGib: delegateKeystone
|
|
480
|
+
});
|
|
481
|
+
if (genesisErrors && genesisErrors.length > 0) {
|
|
482
|
+
throw new Error(`Genesis validation failed for new delegate keystone ${relatedAddr}: ${genesisErrors.join(', ')} (E: d8afdc1dbed48c000455b35585dc26826)`);
|
|
483
|
+
}
|
|
484
|
+
} else {
|
|
485
|
+
// Transition/Evolution validation against the delegate's active tip in space
|
|
486
|
+
let prevDelegateTip: KeystoneIbGib_V1 | undefined;
|
|
487
|
+
try {
|
|
488
|
+
prevDelegateTip = await keystoneService.getLatestKeystone({
|
|
489
|
+
addr: relatedTjp,
|
|
490
|
+
metaspace,
|
|
491
|
+
space
|
|
492
|
+
});
|
|
493
|
+
} catch (err) {
|
|
494
|
+
throw new Error(`Could not find previous delegate tip for ${relatedTjp} in space: ${extractErrorMsg(err)} (E: 5fe5a68438e288ab4e86c90d81d142826)`);
|
|
411
495
|
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
496
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
497
|
+
const evolutionErrors = await keystoneService.validate({
|
|
498
|
+
currentIbGib: related as KeystoneIbGib_V1,
|
|
499
|
+
prevIbGib: prevDelegateTip
|
|
500
|
+
});
|
|
501
|
+
if (evolutionErrors && evolutionErrors.length > 0) {
|
|
502
|
+
throw new Error(`Evolution transition validation failed for delegate keystone ${relatedAddr}: ${evolutionErrors.join(', ')} (E: 6fe5a68438e288ab4e86c90d81d142826)`);
|
|
503
|
+
}
|
|
420
504
|
}
|
|
421
505
|
}
|
|
422
|
-
|
|
423
|
-
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
424
508
|
|
|
425
|
-
|
|
426
|
-
|
|
509
|
+
// Persist parent and related keystones
|
|
510
|
+
await metaspace.put({ ibGibs: [keystoneIbGib, ...relatedKeystoneIbGibs], space });
|
|
511
|
+
await metaspace.registerNewIbGib({ ibGib: keystoneIbGib, space });
|
|
512
|
+
for (const related of relatedKeystoneIbGibs) {
|
|
513
|
+
if (related.ib?.startsWith('keystone')) {
|
|
514
|
+
await metaspace.registerNewIbGib({ ibGib: related, space });
|
|
427
515
|
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
428
518
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
519
|
+
/**
|
|
520
|
+
* Validates and registers a sync delegate keystone evolution and its associated session keystone.
|
|
521
|
+
*
|
|
522
|
+
* ## Assumptions (ATOW 07/2026)
|
|
523
|
+
* - The evolving keystone must be an authorized outward delegate (Root Domain Identity cannot sync directly).
|
|
524
|
+
* - The claim verb is 'sync'.
|
|
525
|
+
* - relatedKeystoneIbGibs contains the newly created session keystone (S^Stjp) target address specified in claim.target.
|
|
526
|
+
*/
|
|
527
|
+
async function validateSyncEvolveKeystone({
|
|
528
|
+
keystoneIbGib,
|
|
529
|
+
relatedKeystoneIbGibs,
|
|
530
|
+
parentKeystone,
|
|
531
|
+
isDelegate,
|
|
532
|
+
domainAddr,
|
|
533
|
+
metaspace,
|
|
534
|
+
space,
|
|
535
|
+
}: {
|
|
536
|
+
keystoneIbGib: KeystoneIbGib_V1;
|
|
537
|
+
relatedKeystoneIbGibs: IbGib_V1[];
|
|
538
|
+
parentKeystone: KeystoneIbGib_V1;
|
|
539
|
+
isDelegate: boolean;
|
|
540
|
+
domainAddr: IbGibAddr;
|
|
541
|
+
metaspace: MetaspaceService;
|
|
542
|
+
space: IbGibSpaceAny;
|
|
543
|
+
}): Promise<void> {
|
|
544
|
+
const lc = `[validateSyncEvolveKeystone]`;
|
|
545
|
+
const keystoneService = new KeystoneService_V1();
|
|
432
546
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
547
|
+
if (!isDelegate) {
|
|
548
|
+
throw new Error(`Root Domain Identity (${domainAddr}) is not allowed to sync directly. A delegate must be used. (E: 2c88fae39b7d82fd)`);
|
|
549
|
+
}
|
|
437
550
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
551
|
+
const incomingTjpAddr = getTjpAddr({ ibGib: keystoneIbGib });
|
|
552
|
+
if (!incomingTjpAddr) {
|
|
553
|
+
throw new Error(`Incoming delegate keystone missing TJP address (E: d288fae39b7d825e)`);
|
|
554
|
+
}
|
|
443
555
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
}
|
|
556
|
+
// Verify delegate is registered under root Domain Identity
|
|
557
|
+
const delegateInfo = parentKeystone.data?.delegates?.[incomingTjpAddr];
|
|
558
|
+
if (!delegateInfo) {
|
|
559
|
+
throw new Error(`Incoming delegate keystone (${incomingTjpAddr}) is not registered under parent Domain Identity (E: c288fae39b7d82fe)`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Verify delegate is authorized for sync
|
|
563
|
+
const allowedVerbs = delegateInfo.allowedVerbs ?? [];
|
|
564
|
+
if (!allowedVerbs.includes(KEYSTONE_VERB_SYNC)) {
|
|
565
|
+
throw new Error(`Incoming delegate keystone is not authorized for sync. Allowed verbs: ${allowedVerbs.join(', ')} (E: a288fae39b7d82ff)`);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Load delegate's previous tip from space using keystoneService.getLatestKeystone if it exists
|
|
569
|
+
let prevDelegateTip: KeystoneIbGib_V1 | undefined;
|
|
570
|
+
try {
|
|
571
|
+
prevDelegateTip = await keystoneService.getLatestKeystone({
|
|
572
|
+
addr: incomingTjpAddr,
|
|
573
|
+
metaspace,
|
|
574
|
+
space
|
|
575
|
+
});
|
|
576
|
+
} catch (err) {
|
|
577
|
+
// No previous tip found in space yet; will validate graph below
|
|
578
|
+
}
|
|
448
579
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
580
|
+
if (prevDelegateTip) {
|
|
581
|
+
const validationErrors = await keystoneService.validate({
|
|
582
|
+
currentIbGib: keystoneIbGib,
|
|
583
|
+
prevIbGib: prevDelegateTip
|
|
584
|
+
});
|
|
585
|
+
if (validationErrors && validationErrors.length > 0) {
|
|
586
|
+
throw new Error(`Delegate keystone evolution validation failed: ${validationErrors.join(', ')} (E: 5212f8492ac839953842631834bcd827)`);
|
|
587
|
+
}
|
|
588
|
+
} else {
|
|
589
|
+
const validationErrors = await keystoneService.validateKeystoneGraph({
|
|
590
|
+
keystoneIbGib,
|
|
591
|
+
getLatest: false,
|
|
592
|
+
invalidIfMoreRecentKeystoneFoundInSpace: false,
|
|
593
|
+
space
|
|
594
|
+
});
|
|
595
|
+
if (validationErrors && validationErrors.length > 0) {
|
|
596
|
+
throw new Error(`Delegate keystone graph validation failed: ${validationErrors.join(', ')} (E: 3a288fae39b7d82f)`);
|
|
452
597
|
}
|
|
598
|
+
}
|
|
453
599
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
460
|
-
throw error;
|
|
461
|
-
} finally {
|
|
462
|
-
if (logalot) { console.log(`${lc} complete.`); }
|
|
600
|
+
const proof = keystoneIbGib.data?.proofs?.[0];
|
|
601
|
+
const claim = proof?.claim;
|
|
602
|
+
const sAddr = claim?.target;
|
|
603
|
+
if (!sAddr) {
|
|
604
|
+
throw new Error('No target address found in sync claim');
|
|
463
605
|
}
|
|
606
|
+
|
|
607
|
+
// Validate S^Stjp (session keystone ibgib) from relatedKeystoneIbGibs
|
|
608
|
+
const sIbGib = relatedKeystoneIbGibs.find(ibGib => getIbGibAddr({ ibGib }) === sAddr) as KeystoneIbGib_V1 | undefined;
|
|
609
|
+
if (!sIbGib) {
|
|
610
|
+
throw new Error(`Session keystone ${sAddr} must be provided in relatedKeystoneIbGibs (E: fe5a68438e288ab4e86c90d81d142826)`);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const sIntrinsicErrors = await validateIbGibIntrinsically({ ibGib: sIbGib });
|
|
614
|
+
if (sIntrinsicErrors && sIntrinsicErrors.length > 0) {
|
|
615
|
+
throw new Error(`Intrinsic validation failed for S^Stjp: ${sIntrinsicErrors.join(', ')} (E: 802d8350c3cccbd7184dd43866c05526)`);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const sGenesisErrors = await keystoneService.validateGenesisKeystone({ keystoneIbGib: sIbGib });
|
|
619
|
+
if (sGenesisErrors && sGenesisErrors.length > 0) {
|
|
620
|
+
throw new Error(`Genesis validation failed for S^Stjp: ${sGenesisErrors.join(', ')} (E: 8afdc1dbed48c000455b35585dc26826)`);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Persist and Register both I and S
|
|
624
|
+
await metaspace.put({ ibGibs: [keystoneIbGib, sIbGib], space });
|
|
625
|
+
await metaspace.registerNewIbGib({ ibGib: keystoneIbGib, space });
|
|
626
|
+
await metaspace.registerNewIbGib({ ibGib: sIbGib, space });
|
|
464
627
|
}
|