@ibgib/core-gib 0.1.47 → 0.1.48
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/dist/common/other/ibgib-helper.d.mts +12 -0
- package/dist/common/other/ibgib-helper.d.mts.map +1 -1
- package/dist/common/other/ibgib-helper.mjs +39 -0
- package/dist/common/other/ibgib-helper.mjs.map +1 -1
- package/dist/keystone/kdf/kdf-helpers.mjs +2 -2
- package/dist/keystone/kdf/kdf-helpers.mjs.map +1 -1
- package/dist/keystone/keystone-config-builder.d.mts +2 -1
- package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
- package/dist/keystone/keystone-config-builder.mjs +8 -2
- package/dist/keystone/keystone-config-builder.mjs.map +1 -1
- package/dist/keystone/keystone-constants.d.mts +24 -3
- package/dist/keystone/keystone-constants.d.mts.map +1 -1
- package/dist/keystone/keystone-constants.mjs +22 -1
- package/dist/keystone/keystone-constants.mjs.map +1 -1
- package/dist/keystone/keystone-helpers.d.mts.map +1 -1
- package/dist/keystone/keystone-helpers.mjs +7 -9
- package/dist/keystone/keystone-helpers.mjs.map +1 -1
- package/dist/keystone/keystone-service-v1.d.mts +4 -1
- package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
- package/dist/keystone/keystone-service-v1.mjs +6 -1
- package/dist/keystone/keystone-service-v1.mjs.map +1 -1
- package/dist/keystone/keystone-service-v1.respec.mjs +26 -26
- package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
- package/dist/keystone/keystone-types.d.mts +24 -5
- package/dist/keystone/keystone-types.d.mts.map +1 -1
- package/dist/keystone/keystone-types.mjs.map +1 -1
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +1 -1
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-divergence.respec.mjs +1 -1
- package/dist/sync/sync-conflict-basic-divergence.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs +1 -1
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-text-merge.respec.mjs +1 -1
- package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
- package/dist/sync/sync-constants.d.mts +47 -1
- package/dist/sync/sync-constants.d.mts.map +1 -1
- package/dist/sync/sync-constants.mjs +49 -1
- package/dist/sync/sync-constants.mjs.map +1 -1
- package/dist/sync/sync-innerspace-constants.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +33 -19
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-partial-update.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace.respec.mjs +1 -1
- package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +5 -0
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts +6 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +56 -23
- package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +7 -3
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +32 -3
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +16 -0
- package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +18 -3
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +240 -55
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-types.d.mts +1 -1
- package/dist/sync/sync-types.d.mts.map +1 -1
- package/package.json +1 -1
- package/src/common/other/ibgib-helper.mts +39 -0
- package/src/keystone/kdf/kdf-helpers.mts +2 -2
- package/src/keystone/keystone-config-builder.mts +13 -2
- package/src/keystone/keystone-constants.mts +24 -2
- package/src/keystone/keystone-helpers.mts +5 -10
- package/src/keystone/keystone-service-v1.mts +5 -0
- package/src/keystone/keystone-service-v1.respec.mts +25 -25
- package/src/keystone/keystone-types.mts +27 -7
- package/src/sync/sync-conflict-adv-multitimelines.respec.mts +1 -1
- package/src/sync/sync-conflict-basic-divergence.respec.mts +1 -1
- package/src/sync/sync-conflict-basic-multitimelines.respec.mts +1 -1
- package/src/sync/sync-conflict-text-merge.respec.mts +1 -1
- package/src/sync/sync-constants.mts +51 -1
- package/src/sync/sync-innerspace-constants.respec.mts +1 -1
- package/src/sync/sync-innerspace-deep-updates.respec.mts +1 -1
- package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +36 -19
- package/src/sync/sync-innerspace-dest-ahead.respec.mts +1 -1
- package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
- package/src/sync/sync-innerspace-partial-update.respec.mts +1 -1
- package/src/sync/sync-innerspace.respec.mts +1 -1
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +5 -0
- package/src/sync/sync-peer/sync-peer-v1.mts +63 -25
- package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +52 -4
- package/src/sync/sync-saga-context/sync-saga-context-types.mts +17 -0
- package/src/sync/sync-saga-coordinator.mts +295 -62
- package/src/sync/sync-types.mts +1 -1
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
clone,
|
|
8
8
|
unique,
|
|
9
9
|
delay,
|
|
10
|
+
hash,
|
|
10
11
|
} from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
11
12
|
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
12
13
|
import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
|
|
@@ -16,7 +17,7 @@ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
|
|
|
16
17
|
import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
|
|
17
18
|
import { IbGibSpaceAny } from "../witness/space/space-base-v1.mjs";
|
|
18
19
|
import { putInSpace, getLatestAddrs, getFromSpace, registerNewIbGib } from "../witness/space/space-helper.mjs";
|
|
19
|
-
import { KeystoneIbGib_V1, KeystonePoolConfig_HashV1 } from "../keystone/keystone-types.mjs";
|
|
20
|
+
import { KeystoneChallengePool, KeystoneChallengeType, KeystoneIbGib_V1, KeystonePoolConfig_HashV1, KeystoneReplenishStrategy } from "../keystone/keystone-types.mjs";
|
|
20
21
|
import { KeystoneService_V1 } from "../keystone/keystone-service-v1.mjs";
|
|
21
22
|
import { deriveKey } from "../keystone/kdf/kdf-helpers.mjs";
|
|
22
23
|
import { KdfStrategy } from "../keystone/kdf/kdf-constants.mjs";
|
|
@@ -25,7 +26,26 @@ import {
|
|
|
25
26
|
SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN,
|
|
26
27
|
SyncConflictStrategy,
|
|
27
28
|
SYNC_CONFLICT_STRATEGY_VALID_VALUES,
|
|
28
|
-
|
|
29
|
+
SESSION_IDENTITY_KEYSTONE_SECRET_TRANSITIONPOOL,
|
|
30
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO,
|
|
31
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS,
|
|
32
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM,
|
|
33
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY,
|
|
34
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL,
|
|
35
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING,
|
|
36
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE,
|
|
37
|
+
SESSION_IDENTITY_KEYSTONE_TRANSITION_POOL_ID,
|
|
38
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE_TRANSITIONPOOL,
|
|
39
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY_TRANSITIONPOOL,
|
|
40
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM_TRANSITIONPOOL,
|
|
41
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL_TRANSITIONPOOL,
|
|
42
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING_TRANSITIONPOOL,
|
|
43
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO_TRANSITIONPOOL,
|
|
44
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS_TRANSITIONPOOL,
|
|
45
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_TRANSITIONPOOL,
|
|
46
|
+
SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_DELEGATE,
|
|
47
|
+
SESSION_IDENTITY_KEYSTONE_DELEGATE_POOL_ID,
|
|
48
|
+
SESSION_IDENTITY_KEYSTONE_PRIMARY_POOL_ID,
|
|
29
49
|
} from "./sync-constants.mjs";
|
|
30
50
|
import {
|
|
31
51
|
appendToTimeline, createTimeline, getHistory, getHistoryAddrs, Rel8nInfo, Rel8nRemovalInfo
|
|
@@ -63,9 +83,11 @@ import { graftTimelines, } from "./graft-info/graft-info-helpers.mjs";
|
|
|
63
83
|
import { GRAFT_INFO_REL8N_NAME } from "./graft-info/graft-info-constants.mjs";
|
|
64
84
|
import { GraftInfoIbGib_V1 } from "./graft-info/graft-info-types.mjs";
|
|
65
85
|
import { validateIbGibIntrinsically } from "@ibgib/ts-gib/dist/V1/validate-helper.mjs";
|
|
66
|
-
import { KEYSTONE_VERB_MANAGE } from "../keystone/keystone-constants.mjs";
|
|
67
|
-
import { validateKeystoneGraph } from "../keystone/keystone-helpers.mjs";
|
|
86
|
+
import { KEYSTONE_VERB_MANAGE, KEYSTONE_VERB_SIGN } from "../keystone/keystone-constants.mjs";
|
|
87
|
+
import { addToBindingMap, generateOpaqueChallengeId, validateGenesisKeystone, validateKeystoneGraph } from "../keystone/keystone-helpers.mjs";
|
|
68
88
|
import { SYNC_SAGA_CONTEXT_ATOM } from "./sync-saga-context/sync-saga-context-constants.mjs";
|
|
89
|
+
import { createStandardPoolConfig } from "../keystone/keystone-config-builder.mjs";
|
|
90
|
+
import { KeystoneStrategyFactory } from "../keystone/strategy/keystone-strategy-factory.mjs";
|
|
69
91
|
|
|
70
92
|
|
|
71
93
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
@@ -214,7 +236,18 @@ export class SyncSagaCoordinator {
|
|
|
214
236
|
// creates the initial session identity (keystone). the flow
|
|
215
237
|
// (i think) will go: evolve saga frame, then sign keystone,
|
|
216
238
|
// then create/send context.
|
|
217
|
-
|
|
239
|
+
const resCreateSessionIdentity = await this.createSessionIdentity({
|
|
240
|
+
sagaId,
|
|
241
|
+
primaryIdentity: identity,
|
|
242
|
+
nonSessionSecret: identitySecret,
|
|
243
|
+
metaspace,
|
|
244
|
+
localSpace
|
|
245
|
+
});
|
|
246
|
+
sessionIdentity = resCreateSessionIdentity.sessionIdentity;
|
|
247
|
+
if (identity) {
|
|
248
|
+
if (!resCreateSessionIdentity.newPrimaryIdentity) { throw new Error(`(UNEXPECTED) identity truthy but resCreateSessionIdentity.newPrimaryIdentity falsy? (E: 4f82e88a3cc5bd7e58a40f8d77bda826)`); }
|
|
249
|
+
identity = resCreateSessionIdentity.newPrimaryIdentity;
|
|
250
|
+
}
|
|
218
251
|
}
|
|
219
252
|
|
|
220
253
|
// if (logalot) { console.log(`${lc} sessionIdentity: ${sessionIdentity ? pretty(sessionIdentity) : 'undefined'} (I: abc01872800b3a66b819a05898bba826)`); }
|
|
@@ -350,20 +383,31 @@ export class SyncSagaCoordinator {
|
|
|
350
383
|
}
|
|
351
384
|
}
|
|
352
385
|
|
|
353
|
-
|
|
386
|
+
/**
|
|
387
|
+
* helper that KDFs the given identitySecret, using {@link sagaId} to do so.
|
|
388
|
+
*
|
|
389
|
+
* @returns deterministically derived session secret
|
|
390
|
+
*/
|
|
391
|
+
private async deriveSessionSecret({
|
|
354
392
|
sagaId,
|
|
355
|
-
|
|
393
|
+
nonSessionSecret,
|
|
356
394
|
}: {
|
|
357
395
|
sagaId: string,
|
|
358
|
-
|
|
396
|
+
/**
|
|
397
|
+
* driving secret behind the sync operation. usually, this will be the
|
|
398
|
+
* secret corresponding to a primary identity keystone. But this can
|
|
399
|
+
* also just be a one-time secret just to have more security in the
|
|
400
|
+
* transmission intrinsically.
|
|
401
|
+
*/
|
|
402
|
+
nonSessionSecret: string,
|
|
359
403
|
}): Promise<string> {
|
|
360
|
-
const lc = `${this.lc}[${this.
|
|
404
|
+
const lc = `${this.lc}[${this.deriveSessionSecret.name}]`;
|
|
361
405
|
try {
|
|
362
406
|
if (logalot) { console.log(`${lc} starting... (I: 0de03f8dcd3e32f1fca244e8f2a8a826)`); }
|
|
363
407
|
|
|
364
408
|
// Derive session-specific secret using KDF
|
|
365
409
|
const sessionSecret = await deriveKey({
|
|
366
|
-
masterSecret:
|
|
410
|
+
masterSecret: nonSessionSecret,
|
|
367
411
|
kdfOpts: {
|
|
368
412
|
strategy: KdfStrategy.recursive_salt_wrap,
|
|
369
413
|
salt: sagaId,
|
|
@@ -381,18 +425,18 @@ export class SyncSagaCoordinator {
|
|
|
381
425
|
}
|
|
382
426
|
}
|
|
383
427
|
|
|
384
|
-
private async
|
|
428
|
+
private async getInitialWeakTransitionSessionSecret({
|
|
385
429
|
sagaId,
|
|
386
430
|
}: {
|
|
387
431
|
sagaId: string,
|
|
388
432
|
}): Promise<string> {
|
|
389
|
-
const lc = `${this.lc}[${this.
|
|
433
|
+
const lc = `${this.lc}[${this.getInitialWeakTransitionSessionSecret.name}]`;
|
|
390
434
|
try {
|
|
391
435
|
if (logalot) { console.log(`${lc} starting... (I: 872ab81a78827b9f2822b78459203226)`); }
|
|
392
436
|
|
|
393
437
|
// Create delegate pool bootstrap secret (publicly derivable)
|
|
394
|
-
const
|
|
395
|
-
masterSecret:
|
|
438
|
+
const initialTransitionSecret = await deriveKey({
|
|
439
|
+
masterSecret: SESSION_IDENTITY_KEYSTONE_SECRET_TRANSITIONPOOL, // Weak, publicly derivable secret
|
|
396
440
|
kdfOpts: {
|
|
397
441
|
strategy: KdfStrategy.recursive_salt_wrap,
|
|
398
442
|
salt: sagaId,
|
|
@@ -401,7 +445,7 @@ export class SyncSagaCoordinator {
|
|
|
401
445
|
}
|
|
402
446
|
});
|
|
403
447
|
|
|
404
|
-
return
|
|
448
|
+
return initialTransitionSecret;
|
|
405
449
|
} catch (error) {
|
|
406
450
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
407
451
|
throw error;
|
|
@@ -410,75 +454,263 @@ export class SyncSagaCoordinator {
|
|
|
410
454
|
}
|
|
411
455
|
}
|
|
412
456
|
|
|
413
|
-
private async
|
|
457
|
+
private async getTransitionKeystonePool({
|
|
414
458
|
sagaId,
|
|
415
|
-
|
|
459
|
+
}: {
|
|
460
|
+
sagaId: string,
|
|
461
|
+
}): Promise<KeystoneChallengePool> {
|
|
462
|
+
const lc = `${this.lc}[${this.getTransitionKeystonePool.name}]`;
|
|
463
|
+
try {
|
|
464
|
+
if (logalot) { console.log(`${lc} starting... (I: 1ec1c8db7438938b08b96559fcee0826)`); }
|
|
465
|
+
|
|
466
|
+
const config = createStandardPoolConfig({
|
|
467
|
+
salt: sagaId,
|
|
468
|
+
id: SESSION_IDENTITY_KEYSTONE_TRANSITION_POOL_ID,
|
|
469
|
+
type: KeystoneChallengeType.hash_reveal_v1,
|
|
470
|
+
size: SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE_TRANSITIONPOOL,
|
|
471
|
+
replenishStrategy: SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY_TRANSITIONPOOL,
|
|
472
|
+
random: SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM_TRANSITIONPOOL,
|
|
473
|
+
sequential: SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL_TRANSITIONPOOL,
|
|
474
|
+
targetBinding: SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING_TRANSITIONPOOL,
|
|
475
|
+
hashAlgorithm: SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO_TRANSITIONPOOL,
|
|
476
|
+
hashRounds: SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS_TRANSITIONPOOL,
|
|
477
|
+
verbs: SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_TRANSITIONPOOL,
|
|
478
|
+
});
|
|
479
|
+
const strategy = KeystoneStrategyFactory.create({ config });
|
|
480
|
+
const poolSecret = await strategy.derivePoolSecret({
|
|
481
|
+
masterSecret: await this.getInitialWeakTransitionSessionSecret({ sagaId }),
|
|
482
|
+
});
|
|
483
|
+
const challenges: { [id: string]: any } = {};
|
|
484
|
+
const bindingMap: { [char: string]: string[] } = {};
|
|
485
|
+
|
|
486
|
+
const targetSize = config.behavior.size;
|
|
487
|
+
const timestamp = Date.now().toString();
|
|
488
|
+
for (let i = 0; i < targetSize; i++) {
|
|
489
|
+
const challengeId = await generateOpaqueChallengeId({
|
|
490
|
+
salt: config.salt, timestamp, index: i
|
|
491
|
+
});
|
|
492
|
+
const solution = await strategy.generateSolution({
|
|
493
|
+
poolSecret, poolId: config.salt, challengeId,
|
|
494
|
+
});
|
|
495
|
+
const challenge = await strategy.generateChallenge({ solution });
|
|
496
|
+
challenges[challengeId] = challenge;
|
|
497
|
+
// Populate Binding Map
|
|
498
|
+
addToBindingMap(bindingMap, challengeId);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const transitionPool: KeystoneChallengePool = {
|
|
502
|
+
id: SESSION_IDENTITY_KEYSTONE_TRANSITION_POOL_ID,
|
|
503
|
+
config,
|
|
504
|
+
challenges,
|
|
505
|
+
bindingMap,
|
|
506
|
+
isForeign: true,
|
|
507
|
+
// metadata: { origin: 'receiver', role: 'delegate' } // don't need metadata since we have the pool id being 'delegate' (i think)
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
return transitionPool;
|
|
511
|
+
} catch (error) {
|
|
512
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
513
|
+
throw error;
|
|
514
|
+
} finally {
|
|
515
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private async getDelegateKeystonePool({
|
|
520
|
+
sagaId,
|
|
521
|
+
}: {
|
|
522
|
+
sagaId: string,
|
|
523
|
+
}): Promise<KeystoneChallengePool> {
|
|
524
|
+
const lc = `${this.lc}[${this.getDelegateKeystonePool.name}]`;
|
|
525
|
+
try {
|
|
526
|
+
if (logalot) { console.log(`${lc} starting... (I: 6b1d338f8e988e68f8d77e72ed00d526)`); }
|
|
527
|
+
|
|
528
|
+
// todo: change this to a helper function that does the delegated
|
|
529
|
+
// functionality better. also the f***ing binding map needs better
|
|
530
|
+
// implementation. f***ng glazed over by AI.
|
|
531
|
+
|
|
532
|
+
const config = createStandardPoolConfig({
|
|
533
|
+
salt: sagaId,
|
|
534
|
+
id: SESSION_IDENTITY_KEYSTONE_DELEGATE_POOL_ID,
|
|
535
|
+
type: KeystoneChallengeType.hash_reveal_v1,
|
|
536
|
+
size: SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE,
|
|
537
|
+
replenishStrategy: SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY,
|
|
538
|
+
random: SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM,
|
|
539
|
+
sequential: SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL,
|
|
540
|
+
targetBinding: SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING,
|
|
541
|
+
hashAlgorithm: SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO,
|
|
542
|
+
hashRounds: SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS,
|
|
543
|
+
verbs: SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_DELEGATE,
|
|
544
|
+
});
|
|
545
|
+
const strategy = KeystoneStrategyFactory.create({ config });
|
|
546
|
+
const poolSecret = await strategy.derivePoolSecret({
|
|
547
|
+
masterSecret: SESSION_IDENTITY_KEYSTONE_SECRET_TRANSITIONPOOL
|
|
548
|
+
});
|
|
549
|
+
const challenges: { [id: string]: any } = {};
|
|
550
|
+
const bindingMap: { [char: string]: string[] } = {};
|
|
551
|
+
|
|
552
|
+
const targetSize = config.behavior.size;
|
|
553
|
+
const timestamp = Date.now().toString();
|
|
554
|
+
for (let i = 0; i < targetSize; i++) {
|
|
555
|
+
const challengeId = await generateOpaqueChallengeId({
|
|
556
|
+
salt: config.salt, timestamp, index: i
|
|
557
|
+
});
|
|
558
|
+
const solution = await strategy.generateSolution({
|
|
559
|
+
poolSecret, poolId: config.salt, challengeId,
|
|
560
|
+
});
|
|
561
|
+
const challenge = await strategy.generateChallenge({ solution });
|
|
562
|
+
challenges[challengeId] = challenge;
|
|
563
|
+
// Populate Binding Map
|
|
564
|
+
addToBindingMap(bindingMap, challengeId);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const delegatePool: KeystoneChallengePool = {
|
|
568
|
+
id: SESSION_IDENTITY_KEYSTONE_DELEGATE_POOL_ID,
|
|
569
|
+
config,
|
|
570
|
+
challenges,
|
|
571
|
+
bindingMap,
|
|
572
|
+
isForeign: true,
|
|
573
|
+
// metadata: { origin: 'receiver', role: 'delegate' } // don't need metadata since we have the pool id being 'delegate' (i think)
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
return delegatePool;
|
|
577
|
+
} catch (error) {
|
|
578
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
579
|
+
throw error;
|
|
580
|
+
} finally {
|
|
581
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* creates a session identity keystone based off of the given args.
|
|
587
|
+
*
|
|
588
|
+
* Then, if the {@link primaryIdentity} keystone is provided, this also
|
|
589
|
+
* **signs** this keystone pointing to the address of the sess
|
|
590
|
+
* @param param0
|
|
591
|
+
* @returns
|
|
592
|
+
*/
|
|
593
|
+
private async createSessionIdentity({
|
|
594
|
+
sagaId,
|
|
595
|
+
primaryIdentity,
|
|
596
|
+
nonSessionSecret,
|
|
416
597
|
metaspace,
|
|
417
598
|
localSpace,
|
|
418
599
|
}: {
|
|
600
|
+
/**
|
|
601
|
+
* unique to any one particular saga.
|
|
602
|
+
*/
|
|
419
603
|
sagaId: string,
|
|
420
|
-
|
|
604
|
+
/**
|
|
605
|
+
* optional main identity, e.g., Alice's keystone
|
|
606
|
+
*/
|
|
607
|
+
primaryIdentity: KeystoneIbGib_V1 | undefined,
|
|
608
|
+
/**
|
|
609
|
+
* driving secret behind the sync operation. usually, this will be the
|
|
610
|
+
* secret corresponding to a primary identity keystone. But this can
|
|
611
|
+
* also just be a one-time secret just to have more security in the
|
|
612
|
+
* transmission intrinsically.
|
|
613
|
+
*/
|
|
614
|
+
nonSessionSecret: string,
|
|
421
615
|
metaspace: MetaspaceService,
|
|
422
616
|
localSpace: IbGibSpaceAny,
|
|
423
|
-
}): Promise<
|
|
424
|
-
|
|
617
|
+
}): Promise<{
|
|
618
|
+
sessionIdentity: KeystoneIbGib_V1,
|
|
619
|
+
/**
|
|
620
|
+
* if truthy, this evolved from the incoming {@link primaryIdentity} and
|
|
621
|
+
* has already persisted/registered in the incoming {@link localSpace}.
|
|
622
|
+
*/
|
|
623
|
+
newPrimaryIdentity: KeystoneIbGib_V1 | undefined
|
|
624
|
+
}> {
|
|
625
|
+
const lc = `${this.lc}[${this.createSessionIdentity.name}]`;
|
|
425
626
|
try {
|
|
426
627
|
if (logalot) { console.log(`${lc} starting... (I: 428392a4ee636b7bd8f7d5d89a87e826)`); }
|
|
427
628
|
|
|
428
|
-
if (!
|
|
429
|
-
|
|
430
|
-
const sessionSecret = await this.getSessionSecret({ sagaId, identitySecret });
|
|
629
|
+
if (!nonSessionSecret) { throw new Error(`(UNEXPECTED) nonSessionSecret falsy? This is expected to be truthy by this point. (E: 8ce053fe59825a6678713128953b9d26)`); }
|
|
431
630
|
|
|
432
|
-
const
|
|
631
|
+
const primarySessionSecret = await this.deriveSessionSecret({
|
|
632
|
+
sagaId, nonSessionSecret
|
|
633
|
+
});
|
|
433
634
|
|
|
635
|
+
// Generate keystone with two initial pools in two steps.
|
|
636
|
+
// 1. Create primary pool with genesis method to correspond to the
|
|
637
|
+
// sender/sender's secret/identity.
|
|
638
|
+
// 2. Create a separate pool and add separately because a
|
|
639
|
+
// different pw + config is used for the transition pool.
|
|
434
640
|
|
|
435
|
-
// Create TWO pool configs: Primary (strong) + Delegate (weak bootstrap)
|
|
436
641
|
const primaryPoolConfig: KeystonePoolConfig_HashV1 = {
|
|
437
642
|
allowedVerbs: [KEYSTONE_VERB_MANAGE],
|
|
438
|
-
id:
|
|
439
|
-
type: 'hash-reveal-v1',
|
|
643
|
+
id: SESSION_IDENTITY_KEYSTONE_PRIMARY_POOL_ID,
|
|
440
644
|
salt: sagaId,
|
|
441
645
|
behavior: {
|
|
442
|
-
size:
|
|
443
|
-
replenish:
|
|
444
|
-
selectSequentially:
|
|
445
|
-
selectRandomly:
|
|
446
|
-
targetBindingChars:
|
|
646
|
+
size: SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE, // Large pool for many signatures
|
|
647
|
+
replenish: SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY,
|
|
648
|
+
selectSequentially: SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL,
|
|
649
|
+
selectRandomly: SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM,
|
|
650
|
+
targetBindingChars: SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING,
|
|
447
651
|
},
|
|
448
|
-
|
|
449
|
-
|
|
652
|
+
type: KeystoneChallengeType.hash_reveal_v1,
|
|
653
|
+
algo: SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO,
|
|
654
|
+
rounds: SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS,
|
|
450
655
|
};
|
|
656
|
+
const sessionIdentity_genesis = await this.keystoneSvc.genesis({
|
|
657
|
+
masterSecret: primarySessionSecret,
|
|
658
|
+
configs: [primaryPoolConfig],
|
|
659
|
+
metaspace,
|
|
660
|
+
space: localSpace,
|
|
661
|
+
});
|
|
451
662
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
algo: 'SHA-256',
|
|
464
|
-
rounds: 1
|
|
465
|
-
};
|
|
663
|
+
// #region sanity validation of genesis keystone
|
|
664
|
+
/**
|
|
665
|
+
* not necessary but since it's a new design, I'm putting in this
|
|
666
|
+
* immediate validation just to put it through its paces. (worth the
|
|
667
|
+
* slight perf hit).
|
|
668
|
+
*/
|
|
669
|
+
const validationErrors = await validateGenesisKeystone({
|
|
670
|
+
keystoneIbGib: sessionIdentity_genesis
|
|
671
|
+
});
|
|
672
|
+
if (validationErrors) { throw new Error(`(UNEXPECTED) the sessionIdentity_genesis that we just created already has validation errors just after creation? (E: e9ca08cf0f8858bb1ace8b9fa89f8726)`); }
|
|
673
|
+
// #endregion sanity validation of genesis keystone
|
|
466
674
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
675
|
+
const transitionPool = await this.getTransitionKeystonePool({ sagaId });
|
|
676
|
+
/**
|
|
677
|
+
* Note this actually **signs** the initial {@link sessionIdentity_genesis}
|
|
678
|
+
* and requires the use of a pool with management priveleges.
|
|
679
|
+
*/
|
|
680
|
+
const sessionIdentity_withTransitionPool = await this.keystoneSvc.addPools({
|
|
681
|
+
latestKeystone: sessionIdentity_genesis,
|
|
682
|
+
/**
|
|
683
|
+
* this secret does not do the delegate pool challenges,
|
|
684
|
+
* rather, this is the sessionSecret itself to evolve the
|
|
685
|
+
* keystone **to add** the delegate pool in the first place.
|
|
686
|
+
*/
|
|
687
|
+
masterSecret: primarySessionSecret,
|
|
473
688
|
metaspace,
|
|
474
|
-
space: localSpace
|
|
689
|
+
space: localSpace,
|
|
690
|
+
newPools: [transitionPool],
|
|
475
691
|
});
|
|
476
692
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
693
|
+
let newPrimaryIdentity: KeystoneIbGib_V1 | undefined = undefined;
|
|
694
|
+
if (primaryIdentity) {
|
|
695
|
+
newPrimaryIdentity = await this.keystoneSvc.sign({
|
|
696
|
+
latestKeystone: primaryIdentity,
|
|
697
|
+
poolId: primaryPoolConfig.id,
|
|
698
|
+
claim: {
|
|
699
|
+
verb: KEYSTONE_VERB_SIGN,
|
|
700
|
+
target: getIbGibAddr({ ibGib: sessionIdentity_withTransitionPool }),
|
|
701
|
+
},
|
|
702
|
+
masterSecret: nonSessionSecret,
|
|
703
|
+
metaspace,
|
|
704
|
+
space: localSpace,
|
|
705
|
+
// frameDetails: undefined, // anything to put here?
|
|
706
|
+
// requiredChallengeIds: undefined, // not relevant I think
|
|
707
|
+
});
|
|
708
|
+
}
|
|
480
709
|
|
|
481
|
-
return
|
|
710
|
+
return {
|
|
711
|
+
sessionIdentity: sessionIdentity_withTransitionPool,
|
|
712
|
+
newPrimaryIdentity,
|
|
713
|
+
}
|
|
482
714
|
} catch (error) {
|
|
483
715
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
484
716
|
throw error;
|
|
@@ -846,6 +1078,7 @@ export class SyncSagaCoordinator {
|
|
|
846
1078
|
masterSecret: sessionSecret,
|
|
847
1079
|
metaspace,
|
|
848
1080
|
});
|
|
1081
|
+
contextIbGib.fnIdentitySecret = () => Promise.resolve(sessionSecret);
|
|
849
1082
|
}
|
|
850
1083
|
|
|
851
1084
|
return contextIbGib;
|
|
@@ -1665,8 +1898,8 @@ export class SyncSagaCoordinator {
|
|
|
1665
1898
|
if (ackData.stage !== SyncStage.ack) {
|
|
1666
1899
|
throw new Error(`${lc} Invalid ack frame: ackData.stage !== SyncStage.ack (E: 2e8b0a94b5954a66a6a1a7a0b3f5b7a1)`);
|
|
1667
1900
|
}
|
|
1668
|
-
if (logalot) { console.log(`${lc} ackData: ${pretty(ackData)} (I:
|
|
1669
|
-
if (!sagaIbGib.data) { throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E:
|
|
1901
|
+
if (logalot) { console.log(`${lc} ackData: ${pretty(ackData)} (I: b817c5571c5e916fe8f90b892b3e8e26)`); }
|
|
1902
|
+
if (!sagaIbGib.data) { throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: e3f2e8f162484859787651b85c011826)`); }
|
|
1670
1903
|
// #region sanity/validation
|
|
1671
1904
|
|
|
1672
1905
|
// 1. Check for Conflicts
|
|
@@ -2889,7 +3122,7 @@ export class SyncSagaCoordinator {
|
|
|
2889
3122
|
|
|
2890
3123
|
// Attach session keystone to saga frame via hard rel8n
|
|
2891
3124
|
if (sessionIdentity) {
|
|
2892
|
-
rel8ns.
|
|
3125
|
+
rel8ns.sessionKeystone = [getIbGibAddr({ ibGib: sessionIdentity })];
|
|
2893
3126
|
}
|
|
2894
3127
|
|
|
2895
3128
|
const resNew = await createTimeline({
|
package/src/sync/sync-types.mts
CHANGED
|
@@ -205,7 +205,7 @@ export interface SyncRel8ns_V1 extends IbGibRel8ns_V1 {
|
|
|
205
205
|
* Each sync endpoint retrieves the session keystone from this rel8n
|
|
206
206
|
* rather than searching spaces. Keystones are stored in durable spaces.
|
|
207
207
|
*/
|
|
208
|
-
|
|
208
|
+
sessionKeystone?: IbGibAddr[];
|
|
209
209
|
|
|
210
210
|
/**
|
|
211
211
|
* The message stone that contains the information about the particular
|