@ibgib/core-gib 0.1.61 → 0.1.63
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 +13 -0
- package/dist/keystone/keystone-constants.d.mts +0 -1
- package/dist/keystone/keystone-constants.d.mts.map +1 -1
- package/dist/keystone/keystone-constants.mjs +0 -1
- package/dist/keystone/keystone-constants.mjs.map +1 -1
- package/dist/keystone/keystone-helpers.d.mts +23 -1
- package/dist/keystone/keystone-helpers.d.mts.map +1 -1
- package/dist/keystone/keystone-helpers.mjs +98 -5
- package/dist/keystone/keystone-helpers.mjs.map +1 -1
- package/dist/keystone/keystone-service-v1.d.mts +39 -2
- package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
- package/dist/keystone/keystone-service-v1.mjs +175 -3
- package/dist/keystone/keystone-service-v1.mjs.map +1 -1
- package/dist/keystone/keystone-service-v1.respec.mjs +397 -42
- package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
- package/dist/keystone/keystone-types.d.mts +54 -0
- package/dist/keystone/keystone-types.d.mts.map +1 -1
- package/dist/keystone/policy/keystone-profile-builder.d.mts +1 -1
- package/dist/keystone/policy/keystone-profile-builder.d.mts.map +1 -1
- package/dist/keystone/policy/keystone-profile-builder.mjs +8 -0
- package/dist/keystone/policy/keystone-profile-builder.mjs.map +1 -1
- package/dist/keystone/policy/profiles/profile-domain.json +84 -0
- package/dist/keystone/policy/profiles/profile-sync.json +84 -0
- package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts +8 -0
- package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts.map +1 -1
- package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs +15 -1
- package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs.map +1 -1
- package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs +16 -4
- package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs +4 -1
- package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs +4 -1
- package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-text-merge.withid.respec.mjs +10 -4
- package/dist/sync/sync-conflict-text-merge.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-constants.withid.respec.mjs +12 -3
- package/dist/sync/sync-innerspace-constants.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs +4 -1
- package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs +4 -1
- package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs +4 -1
- package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs +4 -1
- package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace.withid.respec.mjs +4 -1
- package/dist/sync/sync-innerspace.withid.respec.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-types.d.mts +4 -0
- package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +4 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
- 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 +90 -22
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +7 -10
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +14 -5
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-types.d.mts +5 -0
- package/dist/sync/sync-types.d.mts.map +1 -1
- package/dist/sync/sync-types.mjs.map +1 -1
- package/dist/sync/sync-withid.connect.respec.mjs +4 -1
- package/dist/sync/sync-withid.connect.respec.mjs.map +1 -1
- package/dist/sync/sync-withid.establish.respec.mjs +4 -1
- package/dist/sync/sync-withid.establish.respec.mjs.map +1 -1
- package/dist/sync/sync-withid.pingpong.respec.mjs +4 -1
- package/dist/sync/sync-withid.pingpong.respec.mjs.map +1 -1
- package/package.json +1 -1
- package/src/keystone/README.md +15 -2
- package/src/keystone/docs/architecture.md +21 -2
- package/src/keystone/docs/delegation.md +57 -0
- package/src/keystone/keystone-constants.mts +0 -1
- package/src/keystone/keystone-helpers.mts +131 -5
- package/src/keystone/keystone-service-v1.mts +223 -2
- package/src/keystone/keystone-service-v1.respec.mts +436 -40
- package/src/keystone/keystone-types.mts +55 -0
- package/src/keystone/policy/keystone-profile-builder.mts +9 -1
- package/src/keystone/policy/profiles/profile-domain.json +84 -0
- package/src/keystone/policy/profiles/profile-sync.json +84 -0
- package/src/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mts +20 -1
- package/src/sync/sync-conflict-adv-multitimelines.withid.respec.mts +16 -4
- package/src/sync/sync-conflict-basic-divergence.withid.respec.mts +4 -1
- package/src/sync/sync-conflict-basic-multitimelines.withid.respec.mts +4 -1
- package/src/sync/sync-conflict-text-merge.withid.respec.mts +10 -4
- package/src/sync/sync-innerspace-constants.withid.respec.mts +12 -3
- package/src/sync/sync-innerspace-deep-updates.withid.respec.mts +4 -1
- package/src/sync/sync-innerspace-dest-ahead.withid.respec.mts +4 -1
- package/src/sync/sync-innerspace-multiple-timelines.withid.respec.mts +4 -1
- package/src/sync/sync-innerspace-partial-update.withid.respec.mts +4 -1
- package/src/sync/sync-innerspace.withid.respec.mts +4 -1
- package/src/sync/sync-peer/sync-peer-types.mts +4 -0
- package/src/sync/sync-peer/sync-peer-v1.mts +5 -1
- package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +96 -22
- package/src/sync/sync-saga-coordinator.mts +17 -12
- package/src/sync/sync-types.mts +6 -0
- package/src/sync/sync-withid.connect.respec.mts +5 -2
- package/src/sync/sync-withid.establish.respec.mts +4 -1
- package/src/sync/sync-withid.pingpong.respec.mts +4 -1
- package/src/sync/unused-identity-backup.mts.md +0 -311
|
@@ -10,10 +10,12 @@ import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
|
|
|
10
10
|
import { KeystoneStrategyFactory } from './strategy/keystone-strategy-factory.mjs';
|
|
11
11
|
import { KeystoneChallengePool, KeystoneClaim, KeystoneIbGib_V1, KeystonePoolConfig_HashV1 } from './keystone-types.mjs';
|
|
12
12
|
import { createRevocationPoolConfig, createStandardPoolConfig } from './keystone-config-builder.mjs';
|
|
13
|
-
import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE } from './keystone-constants.mjs';
|
|
14
|
-
import { KeystoneService_V1 } from './keystone-service-v1.mjs';
|
|
15
|
-
import { selectChallengeIds, validateChallengePool } from './keystone-helpers.mjs';
|
|
13
|
+
import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE, POOL_ID_MANAGE, KEYSTONE_VERB_SYNC } from './keystone-constants.mjs';
|
|
14
|
+
import { KeystoneService_V1, } from './keystone-service-v1.mjs';
|
|
15
|
+
import { selectChallengeIds, validateChallengePool, validateKeystoneIb, validateKeystoneTransition, validateGenesisKeystone } from './keystone-helpers.mjs';
|
|
16
16
|
import { KeystoneProfileBuilder } from './policy/keystone-profile-builder.mjs';
|
|
17
|
+
import { getTjpAddr } from '../common/other/ibgib-helper.mjs';
|
|
18
|
+
import { deriveDelegateSecret } from './strategy/hash-reveal-v1/hash-reveal-v1.mjs';
|
|
17
19
|
|
|
18
20
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
19
21
|
|
|
@@ -37,16 +39,55 @@ class MockIbGibSpace {
|
|
|
37
39
|
return data ? JSON.parse(JSON.stringify(data)) : null;
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
async argy({ argData, ibGibs }: { argData: any; ibGibs?: IbGib_V1[] }): Promise<any> {
|
|
43
|
+
return {
|
|
44
|
+
ib: 'arg^gib',
|
|
45
|
+
gib: 'arg_gib',
|
|
46
|
+
data: argData,
|
|
47
|
+
ibGibs,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
async witness(arg: any): Promise<any> {
|
|
41
52
|
const cmd = arg.data?.cmd;
|
|
53
|
+
const cmdModifiers = arg.data?.cmdModifiers || [];
|
|
42
54
|
if (cmd === 'get') {
|
|
43
55
|
const addrs = arg.data.ibGibAddrs || [];
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
56
|
+
if (cmdModifiers.includes('latest') && cmdModifiers.includes('addrs')) {
|
|
57
|
+
const latestAddrsMap: { [addr: string]: string } = {};
|
|
58
|
+
for (const queryAddr of addrs) {
|
|
59
|
+
const queryTjpGib = queryAddr.includes('.') ? queryAddr.split('.')[1] : queryAddr.split('^')[1];
|
|
60
|
+
let latestAddr = queryAddr;
|
|
61
|
+
let maxN = -1;
|
|
62
|
+
for (const [addr, ibGib] of this.store.entries()) {
|
|
63
|
+
const tjpGib = addr.includes('.') ? addr.split('.')[1] : addr.split('^')[1];
|
|
64
|
+
if (tjpGib === queryTjpGib) {
|
|
65
|
+
const n = ibGib.data?.n ?? 0;
|
|
66
|
+
if (n > maxN) {
|
|
67
|
+
maxN = n;
|
|
68
|
+
latestAddr = addr;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
latestAddrsMap[queryAddr] = latestAddr;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
data: {
|
|
76
|
+
success: true,
|
|
77
|
+
latestAddrsMap,
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
} else {
|
|
81
|
+
const ibGibs: IbGib_V1[] = [];
|
|
82
|
+
for (const addr of addrs) {
|
|
83
|
+
const x = await this.get({ addr });
|
|
84
|
+
if (x) { ibGibs.push(x); }
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
data: { success: true },
|
|
88
|
+
ibGibs,
|
|
89
|
+
};
|
|
48
90
|
}
|
|
49
|
-
return { ibGibs };
|
|
50
91
|
}
|
|
51
92
|
return undefined;
|
|
52
93
|
}
|
|
@@ -81,6 +122,15 @@ class MockMetaspaceService {
|
|
|
81
122
|
return target.put(args);
|
|
82
123
|
}
|
|
83
124
|
|
|
125
|
+
async get(args: { addr: string, space?: any }): Promise<{ success: boolean, ibGibs?: IbGib_V1[] }> {
|
|
126
|
+
const target = args.space || this.space;
|
|
127
|
+
const x = await target.get({ addr: args.addr });
|
|
128
|
+
return {
|
|
129
|
+
success: !!x,
|
|
130
|
+
ibGibs: x ? [x] : [],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
84
134
|
/**
|
|
85
135
|
* Tracks the latest version of an ibGib timeline.
|
|
86
136
|
*/
|
|
@@ -132,7 +182,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
132
182
|
|
|
133
183
|
await respecfully(sir, 'Derivation Logic', async () => {
|
|
134
184
|
|
|
135
|
-
await
|
|
185
|
+
await ifWe(sir, 'derivePoolSecret with same inputs returns same output', async () => {
|
|
136
186
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
137
187
|
|
|
138
188
|
const secretA = await strategy.derivePoolSecret({ masterSecret });
|
|
@@ -142,7 +192,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
142
192
|
iReckon(sir, secretA).asTo('secret length').isGonnaBeTruthy();
|
|
143
193
|
});
|
|
144
194
|
|
|
145
|
-
await
|
|
195
|
+
await ifWe(sir, 'derivePoolSecret with different master secret returns different output', async () => {
|
|
146
196
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
147
197
|
|
|
148
198
|
const secretA = await strategy.derivePoolSecret({ masterSecret });
|
|
@@ -151,7 +201,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
151
201
|
iReckon(sir, secretA).asTo('secrets differ').not.willEqual(secretB);
|
|
152
202
|
});
|
|
153
203
|
|
|
154
|
-
await
|
|
204
|
+
await ifWe(sir, 'derivePoolSecret with different salt returns different output', async () => {
|
|
155
205
|
// Modify salt in a copy of config
|
|
156
206
|
const configB = { ...config, salt: "OtherPool" };
|
|
157
207
|
const strategyA = KeystoneStrategyFactory.create({ config });
|
|
@@ -162,11 +212,22 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
162
212
|
|
|
163
213
|
iReckon(sir, secretA).asTo('salt affects secret').not.willEqual(secretB);
|
|
164
214
|
});
|
|
215
|
+
|
|
216
|
+
await ifWe(sir, 'deriveDelegateSecret derives a consistent secret using KDF', async () => {
|
|
217
|
+
const secretA = await deriveDelegateSecret({ masterSecret });
|
|
218
|
+
const secretB = await deriveDelegateSecret({ masterSecret });
|
|
219
|
+
|
|
220
|
+
iReckon(sir, secretA).asTo('consistency').willEqual(secretB);
|
|
221
|
+
iReckon(sir, secretA).asTo('truthy').isGonnaBeTruthy();
|
|
222
|
+
|
|
223
|
+
const secretC = await deriveDelegateSecret({ masterSecret: masterSecret + '_other' });
|
|
224
|
+
iReckon(sir, secretA).asTo('differ').not.willEqual(secretC);
|
|
225
|
+
});
|
|
165
226
|
});
|
|
166
227
|
|
|
167
228
|
await respecfully(sir, 'Challenge/Solution Logic', async () => {
|
|
168
229
|
|
|
169
|
-
await
|
|
230
|
+
await ifWe(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
|
|
170
231
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
171
232
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
172
233
|
const challengeId = "a3ff7843552870fc28bef2b"; // arbitrary random challengeId
|
|
@@ -185,7 +246,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
185
246
|
iReckon(sir, isValid).asTo('valid pair should pass').isGonnaBeTrue();
|
|
186
247
|
});
|
|
187
248
|
|
|
188
|
-
await
|
|
249
|
+
await ifWe(sir, 'validateSolution fails for mismatched values', async () => {
|
|
189
250
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
190
251
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
191
252
|
const challengeId = "8c994f3ed598f150e25513"; // arbitrary random challengeId
|
|
@@ -201,7 +262,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
201
262
|
iReckon(sir, isValid).asTo('tampered solution should fail').isGonnaBeFalse();
|
|
202
263
|
});
|
|
203
264
|
|
|
204
|
-
await
|
|
265
|
+
await ifWe(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
|
|
205
266
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
206
267
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
207
268
|
|
|
@@ -242,7 +303,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
242
303
|
});
|
|
243
304
|
|
|
244
305
|
await respecfully(sir, 'Genesis', async () => {
|
|
245
|
-
await
|
|
306
|
+
await ifWe(sir, 'creates a valid genesis frame and persists it', async () => {
|
|
246
307
|
const salt = (await getUUID()).substring(0, 16);
|
|
247
308
|
const config = createStandardPoolConfig({
|
|
248
309
|
id: POOL_ID_DEFAULT,
|
|
@@ -274,7 +335,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
274
335
|
});
|
|
275
336
|
|
|
276
337
|
await respecfully(sir, 'Signing (Evolution)', async () => {
|
|
277
|
-
await
|
|
338
|
+
await ifWe(sir, 'evolves the keystone with a valid proof', async () => {
|
|
278
339
|
const claim: Partial<KeystoneClaim> = {
|
|
279
340
|
target: "comment 123^gib",
|
|
280
341
|
verb: "post"
|
|
@@ -304,7 +365,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
304
365
|
});
|
|
305
366
|
|
|
306
367
|
await respecfully(sir, 'Validation', async () => {
|
|
307
|
-
await
|
|
368
|
+
await ifWe(sir, 'validates the genesis->signed transition', async () => {
|
|
308
369
|
const errors = await service.validate({
|
|
309
370
|
prevIbGib: genesisKeystone,
|
|
310
371
|
currentIbGib: signedKeystone,
|
|
@@ -353,7 +414,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
|
|
|
353
414
|
});
|
|
354
415
|
|
|
355
416
|
await respecfully(sir, 'Wrong Secret (Forgery)', async () => {
|
|
356
|
-
await
|
|
417
|
+
await ifWe(sir, 'prevents creation of forged frames', async () => {
|
|
357
418
|
const claim: Partial<KeystoneClaim> = { target: "comment 123^gib", verb: "post" };
|
|
358
419
|
|
|
359
420
|
let errorCaught = false;
|
|
@@ -382,7 +443,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
|
|
|
382
443
|
});
|
|
383
444
|
|
|
384
445
|
await respecfully(sir, 'Policy Violation (Restricted Verbs)', async () => {
|
|
385
|
-
await
|
|
446
|
+
await ifWe(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
|
|
386
447
|
// Create a specific restricted pool config manually
|
|
387
448
|
const restrictedPoolId = "read_only_pool";
|
|
388
449
|
const restrictedConfig = createStandardPoolConfig({
|
|
@@ -462,7 +523,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
462
523
|
await respecfully(sir, 'Revoke Lifecycle', async () => {
|
|
463
524
|
let revokedKeystone: KeystoneIbGib_V1;
|
|
464
525
|
|
|
465
|
-
await
|
|
526
|
+
await ifWe(sir, 'successfully creates a revocation frame', async () => {
|
|
466
527
|
revokedKeystone = await service.revoke({
|
|
467
528
|
latestKeystone: genesisKeystone,
|
|
468
529
|
masterSecret,
|
|
@@ -480,7 +541,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
480
541
|
iReckon(sir, data.revocationInfo!.proof.claim.verb).willEqual(KEYSTONE_VERB_REVOKE);
|
|
481
542
|
});
|
|
482
543
|
|
|
483
|
-
await
|
|
544
|
+
await ifWe(sir, 'validates the revocation frame', async () => {
|
|
484
545
|
const errors = await service.validate({
|
|
485
546
|
prevIbGib: genesisKeystone,
|
|
486
547
|
currentIbGib: revokedKeystone!,
|
|
@@ -491,7 +552,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
491
552
|
iReckon(sir, errors.length).asTo('no validation errors').willEqual(0);
|
|
492
553
|
});
|
|
493
554
|
|
|
494
|
-
await
|
|
555
|
+
await ifWe(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
|
|
495
556
|
const data = revokedKeystone!.data!;
|
|
496
557
|
const revokePool = data.challengePools.find(p => p.id === POOL_ID_REVOKE);
|
|
497
558
|
|
|
@@ -567,7 +628,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
567
628
|
});
|
|
568
629
|
|
|
569
630
|
await respecfully(sir, 'Happy Path', async () => {
|
|
570
|
-
await
|
|
631
|
+
await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
|
|
571
632
|
const bobPool = await createForeignPool("pool_bob", ["post"]);
|
|
572
633
|
|
|
573
634
|
const updatedKeystone = await service.addPools({
|
|
@@ -606,7 +667,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
606
667
|
});
|
|
607
668
|
|
|
608
669
|
await respecfully(sir, 'Permissions & Logic', async () => {
|
|
609
|
-
await
|
|
670
|
+
await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
|
|
610
671
|
// 1. Create a restricted keystone
|
|
611
672
|
let id = "read_only";
|
|
612
673
|
const restrictedConfig = createStandardPoolConfig({ id, salt: id });
|
|
@@ -639,7 +700,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
639
700
|
iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
|
|
640
701
|
});
|
|
641
702
|
|
|
642
|
-
await
|
|
703
|
+
await ifWe(sir, 'fails on ID collision', async () => {
|
|
643
704
|
// Try to add "pool_bob" again (it was added in Happy Path)
|
|
644
705
|
const duplicatePool = await createForeignPool("pool_bob");
|
|
645
706
|
|
|
@@ -727,7 +788,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
727
788
|
});
|
|
728
789
|
|
|
729
790
|
await respecfully(sir, 'Happy Path', async () => {
|
|
730
|
-
await
|
|
791
|
+
await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
|
|
731
792
|
const bobPool = await createForeignPool("pool_bob", ["post"]);
|
|
732
793
|
|
|
733
794
|
const updatedKeystone = await service.addPools({
|
|
@@ -766,7 +827,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
766
827
|
});
|
|
767
828
|
|
|
768
829
|
await respecfully(sir, 'Permissions & Logic', async () => {
|
|
769
|
-
await
|
|
830
|
+
await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
|
|
770
831
|
// 1. Create a restricted keystone (read-only)
|
|
771
832
|
let id = "read_only";
|
|
772
833
|
const restrictedConfig = createStandardPoolConfig({ id, salt: id });
|
|
@@ -799,7 +860,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
799
860
|
iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
|
|
800
861
|
});
|
|
801
862
|
|
|
802
|
-
await
|
|
863
|
+
await ifWe(sir, 'fails on ID collision', async () => {
|
|
803
864
|
// Try to add "pool_bob" again (it was added in Happy Path)
|
|
804
865
|
const duplicatePool = await createForeignPool("pool_bob");
|
|
805
866
|
|
|
@@ -861,7 +922,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
861
922
|
|
|
862
923
|
await respecfully(sir, 'Proof Granularity & Math', async () => {
|
|
863
924
|
|
|
864
|
-
await
|
|
925
|
+
await ifWe(sir, 'generates exactly the expected number of solutions', async () => {
|
|
865
926
|
signedKeystone = await service.sign({
|
|
866
927
|
latestKeystone: genesisKeystone,
|
|
867
928
|
masterSecret: aliceSecret,
|
|
@@ -878,7 +939,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
878
939
|
iReckon(sir, solutions.length).asTo('solution count').willEqual(4);
|
|
879
940
|
});
|
|
880
941
|
|
|
881
|
-
await
|
|
942
|
+
await ifWe(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
|
|
882
943
|
const proof = signedKeystone.data!.proofs[0];
|
|
883
944
|
const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === poolId)!;
|
|
884
945
|
|
|
@@ -907,7 +968,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
907
968
|
}
|
|
908
969
|
});
|
|
909
970
|
|
|
910
|
-
await
|
|
971
|
+
await ifWe(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
|
|
911
972
|
const proof = signedKeystone.data!.proofs[0];
|
|
912
973
|
const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === poolId)!;
|
|
913
974
|
|
|
@@ -926,7 +987,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
926
987
|
iReckon(sir, hasSecond).asTo(`Solution includes 2nd FIFO ID (${expectedFifoIds[1]})`).isGonnaBeTrue();
|
|
927
988
|
});
|
|
928
989
|
|
|
929
|
-
await
|
|
990
|
+
await ifWe(sir, 'verifies Next-Gen Hash-Based Target Binding Selection', async () => {
|
|
930
991
|
const bindingConfig = createStandardPoolConfig({
|
|
931
992
|
id: "binding_pool",
|
|
932
993
|
salt: "binding_salt",
|
|
@@ -974,7 +1035,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
974
1035
|
}
|
|
975
1036
|
});
|
|
976
1037
|
|
|
977
|
-
await
|
|
1038
|
+
await ifWe(sir, 'fails validation if total requested challenges >= size', async () => {
|
|
978
1039
|
const invalidConfig = createStandardPoolConfig({
|
|
979
1040
|
id: "invalid_pool",
|
|
980
1041
|
salt: "invalid_salt",
|
|
@@ -993,7 +1054,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
993
1054
|
|
|
994
1055
|
await respecfully(sir, 'DTO & Serialization', async () => {
|
|
995
1056
|
|
|
996
|
-
await
|
|
1057
|
+
await ifWe(sir, 'survives a clone/JSON-cycle without corruption', async () => {
|
|
997
1058
|
// 1. Create a DTO (simulate network transmission/storage)
|
|
998
1059
|
// 'clone' does a JSON stringify/parse under the hood (usually) or structured clone.
|
|
999
1060
|
const dto = clone(signedKeystone);
|
|
@@ -1013,7 +1074,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
1013
1074
|
iReckon(sir, errors.length).asTo('DTO validation errors').willEqual(0);
|
|
1014
1075
|
});
|
|
1015
1076
|
|
|
1016
|
-
await
|
|
1077
|
+
await ifWe(sir, 'ensures data contains no functions or circular refs', async () => {
|
|
1017
1078
|
// A crude but effective test: ensure JSON.stringify doesn't throw
|
|
1018
1079
|
// and the result is equal to the object (if we parsed it back).
|
|
1019
1080
|
|
|
@@ -1040,7 +1101,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
1040
1101
|
|
|
1041
1102
|
await respecfully(sir, 'KeystoneProfileBuilder and Modular Schemas', async () => {
|
|
1042
1103
|
|
|
1043
|
-
await
|
|
1104
|
+
await ifWe(sir, 'compiles configs successfully with medium profile', async () => {
|
|
1044
1105
|
const builder = KeystoneProfileBuilder.buildKeystone('medium')
|
|
1045
1106
|
.withUsername('alice')
|
|
1046
1107
|
.withEmail('alice@example.com')
|
|
@@ -1063,7 +1124,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
1063
1124
|
iReckon(sir, details.extraInfo).asTo('extraInfo').willEqual('abc');
|
|
1064
1125
|
});
|
|
1065
1126
|
|
|
1066
|
-
await
|
|
1127
|
+
await ifWe(sir, 'supports customized overrides', async () => {
|
|
1067
1128
|
const builder = KeystoneProfileBuilder.buildKeystone('test')
|
|
1068
1129
|
.customizePool('sync', {
|
|
1069
1130
|
behavior: {
|
|
@@ -1082,7 +1143,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
1082
1143
|
|
|
1083
1144
|
await respecfully(sir, 'Keystone Metadata Validation', async () => {
|
|
1084
1145
|
|
|
1085
|
-
await
|
|
1146
|
+
await ifWe(sir, 'validates correct username and description', async () => {
|
|
1086
1147
|
const service = new KeystoneService_V1();
|
|
1087
1148
|
const space = new MockIbGibSpace();
|
|
1088
1149
|
const metaspace = new MockMetaspaceService(space);
|
|
@@ -1108,7 +1169,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
1108
1169
|
iReckon(sir, errors.length).asTo('errors count').willEqual(0);
|
|
1109
1170
|
});
|
|
1110
1171
|
|
|
1111
|
-
await
|
|
1172
|
+
await ifWe(sir, 'fails validation for invalid username length or character', async () => {
|
|
1112
1173
|
const service = new KeystoneService_V1();
|
|
1113
1174
|
const space = new MockIbGibSpace();
|
|
1114
1175
|
const metaspace = new MockMetaspaceService(space);
|
|
@@ -1133,7 +1194,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
1133
1194
|
iReckon(sir, errors[0]).includes('invalid username');
|
|
1134
1195
|
});
|
|
1135
1196
|
|
|
1136
|
-
await
|
|
1197
|
+
await ifWe(sir, 'fails validation for invalid description characters', async () => {
|
|
1137
1198
|
const service = new KeystoneService_V1();
|
|
1138
1199
|
const space = new MockIbGibSpace();
|
|
1139
1200
|
const metaspace = new MockMetaspaceService(space);
|
|
@@ -1160,4 +1221,339 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
1160
1221
|
});
|
|
1161
1222
|
|
|
1162
1223
|
});
|
|
1224
|
+
});
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
// ===========================================================================
|
|
1228
|
+
// SUITE E: DELEGATION (Register/Unregister)
|
|
1229
|
+
// ===========================================================================
|
|
1230
|
+
|
|
1231
|
+
await respecfully(sir, 'Suite E: Delegation (Register/Unregister)', async () => {
|
|
1232
|
+
|
|
1233
|
+
const service = new KeystoneService_V1();
|
|
1234
|
+
const parentSecret = "ParentMasterSecret_123";
|
|
1235
|
+
const delegateSecret = "DelegateMasterSecret_456";
|
|
1236
|
+
|
|
1237
|
+
let mockSpace: MockIbGibSpace;
|
|
1238
|
+
let mockMetaspace: any;
|
|
1239
|
+
|
|
1240
|
+
let parentKeystone: KeystoneIbGib_V1;
|
|
1241
|
+
let delegateKeystone: KeystoneIbGib_V1;
|
|
1242
|
+
|
|
1243
|
+
firstOfEach(sir, async () => {
|
|
1244
|
+
mockSpace = new MockIbGibSpace();
|
|
1245
|
+
mockMetaspace = new MockMetaspaceService(mockSpace);
|
|
1246
|
+
|
|
1247
|
+
const salt = (await getUUID()).substring(0, 16);
|
|
1248
|
+
const defaultConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt });
|
|
1249
|
+
const manageConfig = createStandardPoolConfig({ id: POOL_ID_MANAGE, salt: salt + "_manage" });
|
|
1250
|
+
manageConfig.allowedVerbs = [KEYSTONE_VERB_MANAGE];
|
|
1251
|
+
|
|
1252
|
+
// 1. Create Parent Keystone (with manage pool)
|
|
1253
|
+
parentKeystone = await service.genesis({
|
|
1254
|
+
masterSecret: parentSecret,
|
|
1255
|
+
configs: [defaultConfig, manageConfig],
|
|
1256
|
+
metaspace: mockMetaspace,
|
|
1257
|
+
space: mockSpace as any,
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
// 2. Create Delegate Keystone
|
|
1261
|
+
const delegateConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt + "_delegate" });
|
|
1262
|
+
delegateKeystone = await service.genesis({
|
|
1263
|
+
masterSecret: delegateSecret,
|
|
1264
|
+
configs: [delegateConfig],
|
|
1265
|
+
metaspace: mockMetaspace,
|
|
1266
|
+
space: mockSpace as any,
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1270
|
+
await ifWe(sir, 'registers a delegate keystone and evolves parent using manage pool', async () => {
|
|
1271
|
+
// Register the delegate
|
|
1272
|
+
const evolvedParent = await service.registerDelegate({
|
|
1273
|
+
parentKeystone,
|
|
1274
|
+
delegateKeystone,
|
|
1275
|
+
masterSecret: parentSecret,
|
|
1276
|
+
metaspace: mockMetaspace,
|
|
1277
|
+
space: mockSpace as any,
|
|
1278
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
iReckon(sir, evolvedParent).asTo('evolved parent exists').isGonnaBeTruthy();
|
|
1282
|
+
iReckon(sir, evolvedParent.data?.delegates).asTo('delegates map exists').isGonnaBeTruthy();
|
|
1283
|
+
|
|
1284
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1285
|
+
if (!delegateTjpAddr) { throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 312e986ce4b2ed6c084c03e8f45fa826)`); }
|
|
1286
|
+
const delegateInfo = evolvedParent.data?.delegates?.[delegateTjpAddr];
|
|
1287
|
+
iReckon(sir, delegateInfo).asTo('delegate info registered').isGonnaBeTruthy();
|
|
1288
|
+
iReckon(sir, delegateInfo?.delegateTjpAddr).asTo('delegate tjp matches').willEqual(delegateTjpAddr);
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
await ifWe(sir, 'gets correct delegate status via parent TJP address', async () => {
|
|
1292
|
+
const parentTjpAddr = getTjpAddr({ ibGib: parentKeystone });
|
|
1293
|
+
if (!parentTjpAddr) { throw new Error(`(UNEXPECTED) parentTjpAddr falsy? (E: b7ce2835ccd951d8c99257328be3b826)`); }
|
|
1294
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1295
|
+
if (!delegateTjpAddr) { throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 3e4878ea19dd8034e827466a8bf09526)`); }
|
|
1296
|
+
|
|
1297
|
+
// Before registration
|
|
1298
|
+
const statusBefore = await service.getDelegateStatus({
|
|
1299
|
+
parentTjpAddr: parentTjpAddr,
|
|
1300
|
+
delegateTjpAddr: delegateTjpAddr,
|
|
1301
|
+
metaspace: mockMetaspace,
|
|
1302
|
+
space: mockSpace as any,
|
|
1303
|
+
});
|
|
1304
|
+
iReckon(sir, statusBefore.registered).asTo('initially unregistered').isGonnaBeFalse();
|
|
1305
|
+
|
|
1306
|
+
// Register
|
|
1307
|
+
const evolvedParent = await service.registerDelegate({
|
|
1308
|
+
parentKeystone,
|
|
1309
|
+
delegateKeystone,
|
|
1310
|
+
masterSecret: parentSecret,
|
|
1311
|
+
metaspace: mockMetaspace,
|
|
1312
|
+
space: mockSpace as any,
|
|
1313
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
// After registration
|
|
1317
|
+
const statusAfter = await service.getDelegateStatus({
|
|
1318
|
+
parentTjpAddr: parentTjpAddr,
|
|
1319
|
+
delegateTjpAddr: delegateTjpAddr,
|
|
1320
|
+
metaspace: mockMetaspace,
|
|
1321
|
+
space: mockSpace as any,
|
|
1322
|
+
});
|
|
1323
|
+
iReckon(sir, statusAfter.registered).asTo('registered status').isGonnaBeTrue();
|
|
1324
|
+
iReckon(sir, statusAfter.delegateInfo?.delegateTjpAddr).asTo('status tjp matches').willEqual(delegateTjpAddr);
|
|
1325
|
+
});
|
|
1326
|
+
|
|
1327
|
+
await ifWe(sir, 'unregisters a registered delegate keystone', async () => {
|
|
1328
|
+
// Register first
|
|
1329
|
+
const evolvedParent = await service.registerDelegate({
|
|
1330
|
+
parentKeystone,
|
|
1331
|
+
delegateKeystone,
|
|
1332
|
+
masterSecret: parentSecret,
|
|
1333
|
+
metaspace: mockMetaspace,
|
|
1334
|
+
space: mockSpace as any,
|
|
1335
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1339
|
+
if (!delegateTjpAddr) { throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 486b486a8c984a52b8d2b22418c20d26)`); }
|
|
1340
|
+
|
|
1341
|
+
// Unregister
|
|
1342
|
+
const finalParent = await service.unregisterDelegate({
|
|
1343
|
+
parentKeystone: evolvedParent,
|
|
1344
|
+
delegateTjpAddr,
|
|
1345
|
+
masterSecret: parentSecret,
|
|
1346
|
+
metaspace: mockMetaspace,
|
|
1347
|
+
space: mockSpace as any,
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
iReckon(sir, finalParent).asTo('final evolved parent exists').isGonnaBeTruthy();
|
|
1351
|
+
const info = finalParent.data?.delegates?.[delegateTjpAddr];
|
|
1352
|
+
iReckon(sir, info).asTo('delegate info removed').isGonnaBeUndefined();
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1355
|
+
await ifWe(sir, 'throws if parent does not have a manage pool', async () => {
|
|
1356
|
+
// Create a parent WITHOUT a manage pool
|
|
1357
|
+
const salt = (await getUUID()).substring(0, 16);
|
|
1358
|
+
const defaultConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt });
|
|
1359
|
+
const restrictedParent = await service.genesis({
|
|
1360
|
+
masterSecret: parentSecret,
|
|
1361
|
+
configs: [defaultConfig],
|
|
1362
|
+
metaspace: mockMetaspace,
|
|
1363
|
+
space: mockSpace as any,
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
let errorCaught = false;
|
|
1367
|
+
try {
|
|
1368
|
+
await service.registerDelegate({
|
|
1369
|
+
parentKeystone: restrictedParent,
|
|
1370
|
+
delegateKeystone,
|
|
1371
|
+
masterSecret: parentSecret,
|
|
1372
|
+
metaspace: mockMetaspace,
|
|
1373
|
+
space: mockSpace as any,
|
|
1374
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1375
|
+
});
|
|
1376
|
+
} catch (e: any) {
|
|
1377
|
+
errorCaught = true;
|
|
1378
|
+
iReckon(sir, e.message).includes('Manage pool is required');
|
|
1379
|
+
}
|
|
1380
|
+
iReckon(sir, errorCaught).asTo('delegation rejected').isGonnaBeTrue();
|
|
1381
|
+
});
|
|
1382
|
+
});
|
|
1383
|
+
|
|
1384
|
+
await respecfully(sir, 'Suite G: Delegate & IB Validation', async () => {
|
|
1385
|
+
const service = new KeystoneService_V1();
|
|
1386
|
+
const parentSecret = "ParentMasterSecret_SuiteG";
|
|
1387
|
+
const delegateSecret = "DelegateMasterSecret_SuiteG";
|
|
1388
|
+
|
|
1389
|
+
let mockSpace: MockIbGibSpace;
|
|
1390
|
+
let mockMetaspace: any;
|
|
1391
|
+
|
|
1392
|
+
let parentKeystone: KeystoneIbGib_V1;
|
|
1393
|
+
let delegateKeystone: KeystoneIbGib_V1;
|
|
1394
|
+
|
|
1395
|
+
firstOfEach(sir, async () => {
|
|
1396
|
+
mockSpace = new MockIbGibSpace();
|
|
1397
|
+
mockMetaspace = new MockMetaspaceService(mockSpace);
|
|
1398
|
+
|
|
1399
|
+
const salt1 = (await getUUID()).substring(0, 16);
|
|
1400
|
+
const salt2 = (await getUUID()).substring(0, 16);
|
|
1401
|
+
|
|
1402
|
+
const manageConfig = createStandardPoolConfig({ id: POOL_ID_MANAGE, salt: salt2 });
|
|
1403
|
+
manageConfig.allowedVerbs = [KEYSTONE_VERB_MANAGE];
|
|
1404
|
+
|
|
1405
|
+
const configs = [
|
|
1406
|
+
createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt1 }),
|
|
1407
|
+
manageConfig
|
|
1408
|
+
];
|
|
1409
|
+
|
|
1410
|
+
parentKeystone = await service.genesis({
|
|
1411
|
+
masterSecret: parentSecret,
|
|
1412
|
+
configs,
|
|
1413
|
+
metaspace: mockMetaspace,
|
|
1414
|
+
space: mockSpace as any,
|
|
1415
|
+
});
|
|
1416
|
+
|
|
1417
|
+
delegateKeystone = await service.genesis({
|
|
1418
|
+
masterSecret: delegateSecret,
|
|
1419
|
+
configs: [createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt1 })],
|
|
1420
|
+
metaspace: mockMetaspace,
|
|
1421
|
+
space: mockSpace as any,
|
|
1422
|
+
});
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
await ifWe(sir, 'validateKeystoneIb returns true for valid keystone ib and false for others', async () => {
|
|
1426
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'keystone' })).isGonnaBeTrue();
|
|
1427
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'keystone user info' })).isGonnaBeTrue();
|
|
1428
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'invalidAtom' })).isGonnaBeFalse();
|
|
1429
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'not_keystone sub_atom' })).isGonnaBeFalse();
|
|
1430
|
+
});
|
|
1431
|
+
|
|
1432
|
+
await ifWe(sir, 'validateGenesisKeystone fails validation if ib is invalid', async () => {
|
|
1433
|
+
const invalidGenesis = {
|
|
1434
|
+
...parentKeystone,
|
|
1435
|
+
ib: 'not_a_keystone^' + parentKeystone.gib,
|
|
1436
|
+
};
|
|
1437
|
+
const errors = await validateGenesisKeystone({ keystoneIbGib: invalidGenesis });
|
|
1438
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1439
|
+
iReckon(sir, errors[0]).includes('invalid keystone ib');
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
await ifWe(sir, 'validateKeystoneTransition passes for valid delegate registration', async () => {
|
|
1443
|
+
const evolvedParent = await service.registerDelegate({
|
|
1444
|
+
parentKeystone,
|
|
1445
|
+
delegateKeystone,
|
|
1446
|
+
masterSecret: parentSecret,
|
|
1447
|
+
metaspace: mockMetaspace,
|
|
1448
|
+
space: mockSpace as any,
|
|
1449
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1450
|
+
});
|
|
1451
|
+
|
|
1452
|
+
const errors = await validateKeystoneTransition({
|
|
1453
|
+
currentIbGib: evolvedParent,
|
|
1454
|
+
prevIbGib: parentKeystone,
|
|
1455
|
+
});
|
|
1456
|
+
iReckon(sir, errors.length).willEqual(0);
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
await ifWe(sir, 'validateKeystoneTransition fails if delegates map is mutated without manage proof', async () => {
|
|
1460
|
+
const evolvedParent = await service.registerDelegate({
|
|
1461
|
+
parentKeystone,
|
|
1462
|
+
delegateKeystone,
|
|
1463
|
+
masterSecret: parentSecret,
|
|
1464
|
+
metaspace: mockMetaspace,
|
|
1465
|
+
space: mockSpace as any,
|
|
1466
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1467
|
+
});
|
|
1468
|
+
|
|
1469
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent)) as KeystoneIbGib_V1;
|
|
1470
|
+
|
|
1471
|
+
// Remove the manage verb proof by converting it to sign
|
|
1472
|
+
for (const proof of tamperedParent.data.proofs) {
|
|
1473
|
+
if (proof.claim) {
|
|
1474
|
+
proof.claim.verb = 'sign';
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
const errors = await validateKeystoneTransition({
|
|
1479
|
+
currentIbGib: tamperedParent,
|
|
1480
|
+
prevIbGib: parentKeystone,
|
|
1481
|
+
});
|
|
1482
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1483
|
+
iReckon(sir, errors.some(e => e.includes('Policy Violation: Delegates map was mutated'))).isGonnaBeTrue();
|
|
1484
|
+
});
|
|
1485
|
+
|
|
1486
|
+
await ifWe(sir, 'validateKeystoneTransition fails if delegate key does not match delegateTjpAddr', async () => {
|
|
1487
|
+
const evolvedParent = await service.registerDelegate({
|
|
1488
|
+
parentKeystone,
|
|
1489
|
+
delegateKeystone,
|
|
1490
|
+
masterSecret: parentSecret,
|
|
1491
|
+
metaspace: mockMetaspace,
|
|
1492
|
+
space: mockSpace as any,
|
|
1493
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1494
|
+
});
|
|
1495
|
+
|
|
1496
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent)) as KeystoneIbGib_V1;
|
|
1497
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1498
|
+
if (!delegateTjpAddr) { throw new Error(`delegateTjpAddr falsy?`); }
|
|
1499
|
+
|
|
1500
|
+
const info = tamperedParent.data.delegates![delegateTjpAddr];
|
|
1501
|
+
delete tamperedParent.data.delegates![delegateTjpAddr];
|
|
1502
|
+
tamperedParent.data.delegates!['mismatched_key'] = info;
|
|
1503
|
+
|
|
1504
|
+
const errors = await validateKeystoneTransition({
|
|
1505
|
+
currentIbGib: tamperedParent,
|
|
1506
|
+
prevIbGib: parentKeystone,
|
|
1507
|
+
});
|
|
1508
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1509
|
+
iReckon(sir, errors.some(e => e.includes('does not match delegateTjpAddr'))).isGonnaBeTrue();
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
await ifWe(sir, 'validateKeystoneTransition fails if delegate addresses have invalid keystone ib', async () => {
|
|
1513
|
+
const evolvedParent = await service.registerDelegate({
|
|
1514
|
+
parentKeystone,
|
|
1515
|
+
delegateKeystone,
|
|
1516
|
+
masterSecret: parentSecret,
|
|
1517
|
+
metaspace: mockMetaspace,
|
|
1518
|
+
space: mockSpace as any,
|
|
1519
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent)) as KeystoneIbGib_V1;
|
|
1523
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1524
|
+
if (!delegateTjpAddr) { throw new Error(`delegateTjpAddr falsy?`); }
|
|
1525
|
+
|
|
1526
|
+
tamperedParent.data.delegates![delegateTjpAddr].delegateAddr = 'invalid_ib^12345';
|
|
1527
|
+
|
|
1528
|
+
const errors = await validateKeystoneTransition({
|
|
1529
|
+
currentIbGib: tamperedParent,
|
|
1530
|
+
prevIbGib: parentKeystone,
|
|
1531
|
+
});
|
|
1532
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1533
|
+
iReckon(sir, errors.some(e => e.includes('not a valid keystone address'))).isGonnaBeTrue();
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
await ifWe(sir, 'validateKeystoneTransition fails if thisAddr is not in the parent timeline history', async () => {
|
|
1537
|
+
const evolvedParent = await service.registerDelegate({
|
|
1538
|
+
parentKeystone,
|
|
1539
|
+
delegateKeystone,
|
|
1540
|
+
masterSecret: parentSecret,
|
|
1541
|
+
metaspace: mockMetaspace,
|
|
1542
|
+
space: mockSpace as any,
|
|
1543
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1544
|
+
});
|
|
1545
|
+
|
|
1546
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent)) as KeystoneIbGib_V1;
|
|
1547
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1548
|
+
if (!delegateTjpAddr) { throw new Error(`delegateTjpAddr falsy?`); }
|
|
1549
|
+
|
|
1550
|
+
tamperedParent.data.delegates![delegateTjpAddr].thisAddr = 'keystone^randomgib';
|
|
1551
|
+
|
|
1552
|
+
const errors = await validateKeystoneTransition({
|
|
1553
|
+
currentIbGib: tamperedParent,
|
|
1554
|
+
prevIbGib: parentKeystone,
|
|
1555
|
+
});
|
|
1556
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1557
|
+
iReckon(sir, errors.some(e => e.includes('not a valid historical address in the parent keystone timeline'))).isGonnaBeTrue();
|
|
1558
|
+
});
|
|
1163
1559
|
});
|