@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
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { respecfully, iReckon, firstOfAll,
|
|
1
|
+
import { respecfully, iReckon, ifWe, firstOfAll, firstOfEach } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
2
2
|
const maam = `[${import.meta.url}]`, sir = maam;
|
|
3
3
|
import { clone, hash, getUUID } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
4
4
|
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
5
5
|
import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
|
|
6
6
|
import { KeystoneStrategyFactory } from './strategy/keystone-strategy-factory.mjs';
|
|
7
7
|
import { createRevocationPoolConfig, createStandardPoolConfig } from './keystone-config-builder.mjs';
|
|
8
|
-
import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE } from './keystone-constants.mjs';
|
|
9
|
-
import { KeystoneService_V1 } from './keystone-service-v1.mjs';
|
|
10
|
-
import { selectChallengeIds, validateChallengePool } from './keystone-helpers.mjs';
|
|
8
|
+
import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE, POOL_ID_MANAGE, KEYSTONE_VERB_SYNC } from './keystone-constants.mjs';
|
|
9
|
+
import { KeystoneService_V1, } from './keystone-service-v1.mjs';
|
|
10
|
+
import { selectChallengeIds, validateChallengePool, validateKeystoneIb, validateKeystoneTransition, validateGenesisKeystone } from './keystone-helpers.mjs';
|
|
11
11
|
import { KeystoneProfileBuilder } from './policy/keystone-profile-builder.mjs';
|
|
12
|
+
import { getTjpAddr } from '../common/other/ibgib-helper.mjs';
|
|
13
|
+
import { deriveDelegateSecret } from './strategy/hash-reveal-v1/hash-reveal-v1.mjs';
|
|
12
14
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
13
15
|
/**
|
|
14
16
|
* A simple in-memory map acting as a Space.
|
|
@@ -28,18 +30,57 @@ class MockIbGibSpace {
|
|
|
28
30
|
const data = this.store.get(addr);
|
|
29
31
|
return data ? JSON.parse(JSON.stringify(data)) : null;
|
|
30
32
|
}
|
|
33
|
+
async argy({ argData, ibGibs }) {
|
|
34
|
+
return {
|
|
35
|
+
ib: 'arg^gib',
|
|
36
|
+
gib: 'arg_gib',
|
|
37
|
+
data: argData,
|
|
38
|
+
ibGibs,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
31
41
|
async witness(arg) {
|
|
32
42
|
const cmd = arg.data?.cmd;
|
|
43
|
+
const cmdModifiers = arg.data?.cmdModifiers || [];
|
|
33
44
|
if (cmd === 'get') {
|
|
34
45
|
const addrs = arg.data.ibGibAddrs || [];
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
if (cmdModifiers.includes('latest') && cmdModifiers.includes('addrs')) {
|
|
47
|
+
const latestAddrsMap = {};
|
|
48
|
+
for (const queryAddr of addrs) {
|
|
49
|
+
const queryTjpGib = queryAddr.includes('.') ? queryAddr.split('.')[1] : queryAddr.split('^')[1];
|
|
50
|
+
let latestAddr = queryAddr;
|
|
51
|
+
let maxN = -1;
|
|
52
|
+
for (const [addr, ibGib] of this.store.entries()) {
|
|
53
|
+
const tjpGib = addr.includes('.') ? addr.split('.')[1] : addr.split('^')[1];
|
|
54
|
+
if (tjpGib === queryTjpGib) {
|
|
55
|
+
const n = ibGib.data?.n ?? 0;
|
|
56
|
+
if (n > maxN) {
|
|
57
|
+
maxN = n;
|
|
58
|
+
latestAddr = addr;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
latestAddrsMap[queryAddr] = latestAddr;
|
|
40
63
|
}
|
|
64
|
+
return {
|
|
65
|
+
data: {
|
|
66
|
+
success: true,
|
|
67
|
+
latestAddrsMap,
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const ibGibs = [];
|
|
73
|
+
for (const addr of addrs) {
|
|
74
|
+
const x = await this.get({ addr });
|
|
75
|
+
if (x) {
|
|
76
|
+
ibGibs.push(x);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
data: { success: true },
|
|
81
|
+
ibGibs,
|
|
82
|
+
};
|
|
41
83
|
}
|
|
42
|
-
return { ibGibs };
|
|
43
84
|
}
|
|
44
85
|
return undefined;
|
|
45
86
|
}
|
|
@@ -70,6 +111,14 @@ class MockMetaspaceService {
|
|
|
70
111
|
const target = args.space || this.space;
|
|
71
112
|
return target.put(args);
|
|
72
113
|
}
|
|
114
|
+
async get(args) {
|
|
115
|
+
const target = args.space || this.space;
|
|
116
|
+
const x = await target.get({ addr: args.addr });
|
|
117
|
+
return {
|
|
118
|
+
success: !!x,
|
|
119
|
+
ibGibs: x ? [x] : [],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
73
122
|
/**
|
|
74
123
|
* Tracks the latest version of an ibGib timeline.
|
|
75
124
|
*/
|
|
@@ -111,20 +160,20 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
111
160
|
});
|
|
112
161
|
});
|
|
113
162
|
await respecfully(sir, 'Derivation Logic', async () => {
|
|
114
|
-
await
|
|
163
|
+
await ifWe(sir, 'derivePoolSecret with same inputs returns same output', async () => {
|
|
115
164
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
116
165
|
const secretA = await strategy.derivePoolSecret({ masterSecret });
|
|
117
166
|
const secretB = await strategy.derivePoolSecret({ masterSecret });
|
|
118
167
|
iReckon(sir, secretA).asTo('secret consistency').willEqual(secretB);
|
|
119
168
|
iReckon(sir, secretA).asTo('secret length').isGonnaBeTruthy();
|
|
120
169
|
});
|
|
121
|
-
await
|
|
170
|
+
await ifWe(sir, 'derivePoolSecret with different master secret returns different output', async () => {
|
|
122
171
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
123
172
|
const secretA = await strategy.derivePoolSecret({ masterSecret });
|
|
124
173
|
const secretB = await strategy.derivePoolSecret({ masterSecret: masterSecret + "_diff" });
|
|
125
174
|
iReckon(sir, secretA).asTo('secrets differ').not.willEqual(secretB);
|
|
126
175
|
});
|
|
127
|
-
await
|
|
176
|
+
await ifWe(sir, 'derivePoolSecret with different salt returns different output', async () => {
|
|
128
177
|
// Modify salt in a copy of config
|
|
129
178
|
const configB = { ...config, salt: "OtherPool" };
|
|
130
179
|
const strategyA = KeystoneStrategyFactory.create({ config });
|
|
@@ -133,9 +182,17 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
133
182
|
const secretB = await strategyB.derivePoolSecret({ masterSecret });
|
|
134
183
|
iReckon(sir, secretA).asTo('salt affects secret').not.willEqual(secretB);
|
|
135
184
|
});
|
|
185
|
+
await ifWe(sir, 'deriveDelegateSecret derives a consistent secret using KDF', async () => {
|
|
186
|
+
const secretA = await deriveDelegateSecret({ masterSecret });
|
|
187
|
+
const secretB = await deriveDelegateSecret({ masterSecret });
|
|
188
|
+
iReckon(sir, secretA).asTo('consistency').willEqual(secretB);
|
|
189
|
+
iReckon(sir, secretA).asTo('truthy').isGonnaBeTruthy();
|
|
190
|
+
const secretC = await deriveDelegateSecret({ masterSecret: masterSecret + '_other' });
|
|
191
|
+
iReckon(sir, secretA).asTo('differ').not.willEqual(secretC);
|
|
192
|
+
});
|
|
136
193
|
});
|
|
137
194
|
await respecfully(sir, 'Challenge/Solution Logic', async () => {
|
|
138
|
-
await
|
|
195
|
+
await ifWe(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
|
|
139
196
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
140
197
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
141
198
|
const challengeId = "a3ff7843552870fc28bef2b"; // arbitrary random challengeId
|
|
@@ -150,7 +207,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
150
207
|
const isValid = await strategy.validateSolution({ solution, challenge });
|
|
151
208
|
iReckon(sir, isValid).asTo('valid pair should pass').isGonnaBeTrue();
|
|
152
209
|
});
|
|
153
|
-
await
|
|
210
|
+
await ifWe(sir, 'validateSolution fails for mismatched values', async () => {
|
|
154
211
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
155
212
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
156
213
|
const challengeId = "8c994f3ed598f150e25513"; // arbitrary random challengeId
|
|
@@ -162,7 +219,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
162
219
|
const isValid = await strategy.validateSolution({ solution: badSolution, challenge });
|
|
163
220
|
iReckon(sir, isValid).asTo('tampered solution should fail').isGonnaBeFalse();
|
|
164
221
|
});
|
|
165
|
-
await
|
|
222
|
+
await ifWe(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
|
|
166
223
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
167
224
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
168
225
|
// Generate pair A
|
|
@@ -193,7 +250,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
193
250
|
mockMetaspace = new MockMetaspaceService(mockSpace);
|
|
194
251
|
});
|
|
195
252
|
await respecfully(sir, 'Genesis', async () => {
|
|
196
|
-
await
|
|
253
|
+
await ifWe(sir, 'creates a valid genesis frame and persists it', async () => {
|
|
197
254
|
const salt = (await getUUID()).substring(0, 16);
|
|
198
255
|
const config = createStandardPoolConfig({
|
|
199
256
|
id: POOL_ID_DEFAULT,
|
|
@@ -219,7 +276,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
219
276
|
});
|
|
220
277
|
});
|
|
221
278
|
await respecfully(sir, 'Signing (Evolution)', async () => {
|
|
222
|
-
await
|
|
279
|
+
await ifWe(sir, 'evolves the keystone with a valid proof', async () => {
|
|
223
280
|
const claim = {
|
|
224
281
|
target: "comment 123^gib",
|
|
225
282
|
verb: "post"
|
|
@@ -244,7 +301,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
244
301
|
});
|
|
245
302
|
});
|
|
246
303
|
await respecfully(sir, 'Validation', async () => {
|
|
247
|
-
await
|
|
304
|
+
await ifWe(sir, 'validates the genesis->signed transition', async () => {
|
|
248
305
|
const errors = await service.validate({
|
|
249
306
|
prevIbGib: genesisKeystone,
|
|
250
307
|
currentIbGib: signedKeystone,
|
|
@@ -285,7 +342,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
|
|
|
285
342
|
});
|
|
286
343
|
});
|
|
287
344
|
await respecfully(sir, 'Wrong Secret (Forgery)', async () => {
|
|
288
|
-
await
|
|
345
|
+
await ifWe(sir, 'prevents creation of forged frames', async () => {
|
|
289
346
|
const claim = { target: "comment 123^gib", verb: "post" };
|
|
290
347
|
let errorCaught = false;
|
|
291
348
|
let errorMsg = "";
|
|
@@ -311,7 +368,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
|
|
|
311
368
|
});
|
|
312
369
|
});
|
|
313
370
|
await respecfully(sir, 'Policy Violation (Restricted Verbs)', async () => {
|
|
314
|
-
await
|
|
371
|
+
await ifWe(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
|
|
315
372
|
// Create a specific restricted pool config manually
|
|
316
373
|
const restrictedPoolId = "read_only_pool";
|
|
317
374
|
const restrictedConfig = createStandardPoolConfig({
|
|
@@ -379,7 +436,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
379
436
|
});
|
|
380
437
|
await respecfully(sir, 'Revoke Lifecycle', async () => {
|
|
381
438
|
let revokedKeystone;
|
|
382
|
-
await
|
|
439
|
+
await ifWe(sir, 'successfully creates a revocation frame', async () => {
|
|
383
440
|
revokedKeystone = await service.revoke({
|
|
384
441
|
latestKeystone: genesisKeystone,
|
|
385
442
|
masterSecret,
|
|
@@ -394,7 +451,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
394
451
|
iReckon(sir, data.revocationInfo.reason).willEqual("Key compromised");
|
|
395
452
|
iReckon(sir, data.revocationInfo.proof.claim.verb).willEqual(KEYSTONE_VERB_REVOKE);
|
|
396
453
|
});
|
|
397
|
-
await
|
|
454
|
+
await ifWe(sir, 'validates the revocation frame', async () => {
|
|
398
455
|
const errors = await service.validate({
|
|
399
456
|
prevIbGib: genesisKeystone,
|
|
400
457
|
currentIbGib: revokedKeystone,
|
|
@@ -403,7 +460,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
403
460
|
});
|
|
404
461
|
iReckon(sir, errors.length).asTo('no validation errors').willEqual(0);
|
|
405
462
|
});
|
|
406
|
-
await
|
|
463
|
+
await ifWe(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
|
|
407
464
|
const data = revokedKeystone.data;
|
|
408
465
|
const revokePool = data.challengePools.find(p => p.id === POOL_ID_REVOKE);
|
|
409
466
|
// The pool should exist...
|
|
@@ -465,7 +522,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
465
522
|
});
|
|
466
523
|
});
|
|
467
524
|
await respecfully(sir, 'Happy Path', async () => {
|
|
468
|
-
await
|
|
525
|
+
await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
|
|
469
526
|
const bobPool = await createForeignPool("pool_bob", ["post"]);
|
|
470
527
|
const updatedKeystone = await service.addPools({
|
|
471
528
|
latestKeystone: aliceKeystone,
|
|
@@ -497,7 +554,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
497
554
|
});
|
|
498
555
|
});
|
|
499
556
|
await respecfully(sir, 'Permissions & Logic', async () => {
|
|
500
|
-
await
|
|
557
|
+
await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
|
|
501
558
|
// 1. Create a restricted keystone
|
|
502
559
|
let id = "read_only";
|
|
503
560
|
const restrictedConfig = createStandardPoolConfig({ id, salt: id });
|
|
@@ -526,7 +583,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
526
583
|
}
|
|
527
584
|
iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
|
|
528
585
|
});
|
|
529
|
-
await
|
|
586
|
+
await ifWe(sir, 'fails on ID collision', async () => {
|
|
530
587
|
// Try to add "pool_bob" again (it was added in Happy Path)
|
|
531
588
|
const duplicatePool = await createForeignPool("pool_bob");
|
|
532
589
|
let errorCaught = false;
|
|
@@ -601,7 +658,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
601
658
|
});
|
|
602
659
|
});
|
|
603
660
|
await respecfully(sir, 'Happy Path', async () => {
|
|
604
|
-
await
|
|
661
|
+
await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
|
|
605
662
|
const bobPool = await createForeignPool("pool_bob", ["post"]);
|
|
606
663
|
const updatedKeystone = await service.addPools({
|
|
607
664
|
latestKeystone: aliceKeystone,
|
|
@@ -633,7 +690,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
633
690
|
});
|
|
634
691
|
});
|
|
635
692
|
await respecfully(sir, 'Permissions & Logic', async () => {
|
|
636
|
-
await
|
|
693
|
+
await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
|
|
637
694
|
// 1. Create a restricted keystone (read-only)
|
|
638
695
|
let id = "read_only";
|
|
639
696
|
const restrictedConfig = createStandardPoolConfig({ id, salt: id });
|
|
@@ -662,7 +719,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
662
719
|
}
|
|
663
720
|
iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
|
|
664
721
|
});
|
|
665
|
-
await
|
|
722
|
+
await ifWe(sir, 'fails on ID collision', async () => {
|
|
666
723
|
// Try to add "pool_bob" again (it was added in Happy Path)
|
|
667
724
|
const duplicatePool = await createForeignPool("pool_bob");
|
|
668
725
|
let errorCaught = false;
|
|
@@ -714,7 +771,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
714
771
|
});
|
|
715
772
|
});
|
|
716
773
|
await respecfully(sir, 'Proof Granularity & Math', async () => {
|
|
717
|
-
await
|
|
774
|
+
await ifWe(sir, 'generates exactly the expected number of solutions', async () => {
|
|
718
775
|
signedKeystone = await service.sign({
|
|
719
776
|
latestKeystone: genesisKeystone,
|
|
720
777
|
masterSecret: aliceSecret,
|
|
@@ -728,7 +785,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
728
785
|
// 2 Sequential + 2 Random = 4
|
|
729
786
|
iReckon(sir, solutions.length).asTo('solution count').willEqual(4);
|
|
730
787
|
});
|
|
731
|
-
await
|
|
788
|
+
await ifWe(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
|
|
732
789
|
const proof = signedKeystone.data.proofs[0];
|
|
733
790
|
const poolSnapshot = genesisKeystone.data.challengePools.find(p => p.id === poolId);
|
|
734
791
|
// We iterate every solution in the proof and MANUALLY verify the hash relationship
|
|
@@ -751,7 +808,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
751
808
|
iReckon(sir, calculatedHash).asTo(`Manual hash verification for ${solution.challengeId}`).willEqual(challenge.hash);
|
|
752
809
|
}
|
|
753
810
|
});
|
|
754
|
-
await
|
|
811
|
+
await ifWe(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
|
|
755
812
|
const proof = signedKeystone.data.proofs[0];
|
|
756
813
|
const poolSnapshot = genesisKeystone.data.challengePools.find(p => p.id === poolId);
|
|
757
814
|
// The first N keys in the pool should be the FIFO targets.
|
|
@@ -765,7 +822,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
765
822
|
iReckon(sir, hasFirst).asTo(`Solution includes 1st FIFO ID (${expectedFifoIds[0]})`).isGonnaBeTrue();
|
|
766
823
|
iReckon(sir, hasSecond).asTo(`Solution includes 2nd FIFO ID (${expectedFifoIds[1]})`).isGonnaBeTrue();
|
|
767
824
|
});
|
|
768
|
-
await
|
|
825
|
+
await ifWe(sir, 'verifies Next-Gen Hash-Based Target Binding Selection', async () => {
|
|
769
826
|
const bindingConfig = createStandardPoolConfig({
|
|
770
827
|
id: "binding_pool",
|
|
771
828
|
salt: "binding_salt",
|
|
@@ -807,7 +864,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
807
864
|
iReckon(sir, proofIds.includes(id)).asTo(`proof includes selected ID ${id}`).isGonnaBeTrue();
|
|
808
865
|
}
|
|
809
866
|
});
|
|
810
|
-
await
|
|
867
|
+
await ifWe(sir, 'fails validation if total requested challenges >= size', async () => {
|
|
811
868
|
const invalidConfig = createStandardPoolConfig({
|
|
812
869
|
id: "invalid_pool",
|
|
813
870
|
salt: "invalid_salt",
|
|
@@ -823,7 +880,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
823
880
|
});
|
|
824
881
|
});
|
|
825
882
|
await respecfully(sir, 'DTO & Serialization', async () => {
|
|
826
|
-
await
|
|
883
|
+
await ifWe(sir, 'survives a clone/JSON-cycle without corruption', async () => {
|
|
827
884
|
// 1. Create a DTO (simulate network transmission/storage)
|
|
828
885
|
// 'clone' does a JSON stringify/parse under the hood (usually) or structured clone.
|
|
829
886
|
const dto = clone(signedKeystone);
|
|
@@ -839,7 +896,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
839
896
|
});
|
|
840
897
|
iReckon(sir, errors.length).asTo('DTO validation errors').willEqual(0);
|
|
841
898
|
});
|
|
842
|
-
await
|
|
899
|
+
await ifWe(sir, 'ensures data contains no functions or circular refs', async () => {
|
|
843
900
|
// A crude but effective test: ensure JSON.stringify doesn't throw
|
|
844
901
|
// and the result is equal to the object (if we parsed it back).
|
|
845
902
|
const jsonStr = JSON.stringify(signedKeystone);
|
|
@@ -858,7 +915,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
858
915
|
});
|
|
859
916
|
});
|
|
860
917
|
await respecfully(sir, 'KeystoneProfileBuilder and Modular Schemas', async () => {
|
|
861
|
-
await
|
|
918
|
+
await ifWe(sir, 'compiles configs successfully with medium profile', async () => {
|
|
862
919
|
const builder = KeystoneProfileBuilder.buildKeystone('medium')
|
|
863
920
|
.withUsername('alice')
|
|
864
921
|
.withEmail('alice@example.com')
|
|
@@ -877,7 +934,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
877
934
|
iReckon(sir, details.description).asTo('description').willEqual('Alice test keystone');
|
|
878
935
|
iReckon(sir, details.extraInfo).asTo('extraInfo').willEqual('abc');
|
|
879
936
|
});
|
|
880
|
-
await
|
|
937
|
+
await ifWe(sir, 'supports customized overrides', async () => {
|
|
881
938
|
const builder = KeystoneProfileBuilder.buildKeystone('test')
|
|
882
939
|
.customizePool('sync', {
|
|
883
940
|
behavior: {
|
|
@@ -892,7 +949,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
892
949
|
});
|
|
893
950
|
});
|
|
894
951
|
await respecfully(sir, 'Keystone Metadata Validation', async () => {
|
|
895
|
-
await
|
|
952
|
+
await ifWe(sir, 'validates correct username and description', async () => {
|
|
896
953
|
const service = new KeystoneService_V1();
|
|
897
954
|
const space = new MockIbGibSpace();
|
|
898
955
|
const metaspace = new MockMetaspaceService(space);
|
|
@@ -913,7 +970,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
913
970
|
const errors = await service.validateGenesisKeystone({ keystoneIbGib });
|
|
914
971
|
iReckon(sir, errors.length).asTo('errors count').willEqual(0);
|
|
915
972
|
});
|
|
916
|
-
await
|
|
973
|
+
await ifWe(sir, 'fails validation for invalid username length or character', async () => {
|
|
917
974
|
const service = new KeystoneService_V1();
|
|
918
975
|
const space = new MockIbGibSpace();
|
|
919
976
|
const metaspace = new MockMetaspaceService(space);
|
|
@@ -933,7 +990,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
933
990
|
iReckon(sir, errors.length).asTo('errors count').willEqual(1);
|
|
934
991
|
iReckon(sir, errors[0]).includes('invalid username');
|
|
935
992
|
});
|
|
936
|
-
await
|
|
993
|
+
await ifWe(sir, 'fails validation for invalid description characters', async () => {
|
|
937
994
|
const service = new KeystoneService_V1();
|
|
938
995
|
const space = new MockIbGibSpace();
|
|
939
996
|
const metaspace = new MockMetaspaceService(space);
|
|
@@ -956,4 +1013,302 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
956
1013
|
});
|
|
957
1014
|
});
|
|
958
1015
|
});
|
|
1016
|
+
// ===========================================================================
|
|
1017
|
+
// SUITE E: DELEGATION (Register/Unregister)
|
|
1018
|
+
// ===========================================================================
|
|
1019
|
+
await respecfully(sir, 'Suite E: Delegation (Register/Unregister)', async () => {
|
|
1020
|
+
const service = new KeystoneService_V1();
|
|
1021
|
+
const parentSecret = "ParentMasterSecret_123";
|
|
1022
|
+
const delegateSecret = "DelegateMasterSecret_456";
|
|
1023
|
+
let mockSpace;
|
|
1024
|
+
let mockMetaspace;
|
|
1025
|
+
let parentKeystone;
|
|
1026
|
+
let delegateKeystone;
|
|
1027
|
+
firstOfEach(sir, async () => {
|
|
1028
|
+
mockSpace = new MockIbGibSpace();
|
|
1029
|
+
mockMetaspace = new MockMetaspaceService(mockSpace);
|
|
1030
|
+
const salt = (await getUUID()).substring(0, 16);
|
|
1031
|
+
const defaultConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt });
|
|
1032
|
+
const manageConfig = createStandardPoolConfig({ id: POOL_ID_MANAGE, salt: salt + "_manage" });
|
|
1033
|
+
manageConfig.allowedVerbs = [KEYSTONE_VERB_MANAGE];
|
|
1034
|
+
// 1. Create Parent Keystone (with manage pool)
|
|
1035
|
+
parentKeystone = await service.genesis({
|
|
1036
|
+
masterSecret: parentSecret,
|
|
1037
|
+
configs: [defaultConfig, manageConfig],
|
|
1038
|
+
metaspace: mockMetaspace,
|
|
1039
|
+
space: mockSpace,
|
|
1040
|
+
});
|
|
1041
|
+
// 2. Create Delegate Keystone
|
|
1042
|
+
const delegateConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt + "_delegate" });
|
|
1043
|
+
delegateKeystone = await service.genesis({
|
|
1044
|
+
masterSecret: delegateSecret,
|
|
1045
|
+
configs: [delegateConfig],
|
|
1046
|
+
metaspace: mockMetaspace,
|
|
1047
|
+
space: mockSpace,
|
|
1048
|
+
});
|
|
1049
|
+
});
|
|
1050
|
+
await ifWe(sir, 'registers a delegate keystone and evolves parent using manage pool', async () => {
|
|
1051
|
+
// Register the delegate
|
|
1052
|
+
const evolvedParent = await service.registerDelegate({
|
|
1053
|
+
parentKeystone,
|
|
1054
|
+
delegateKeystone,
|
|
1055
|
+
masterSecret: parentSecret,
|
|
1056
|
+
metaspace: mockMetaspace,
|
|
1057
|
+
space: mockSpace,
|
|
1058
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1059
|
+
});
|
|
1060
|
+
iReckon(sir, evolvedParent).asTo('evolved parent exists').isGonnaBeTruthy();
|
|
1061
|
+
iReckon(sir, evolvedParent.data?.delegates).asTo('delegates map exists').isGonnaBeTruthy();
|
|
1062
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1063
|
+
if (!delegateTjpAddr) {
|
|
1064
|
+
throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 312e986ce4b2ed6c084c03e8f45fa826)`);
|
|
1065
|
+
}
|
|
1066
|
+
const delegateInfo = evolvedParent.data?.delegates?.[delegateTjpAddr];
|
|
1067
|
+
iReckon(sir, delegateInfo).asTo('delegate info registered').isGonnaBeTruthy();
|
|
1068
|
+
iReckon(sir, delegateInfo?.delegateTjpAddr).asTo('delegate tjp matches').willEqual(delegateTjpAddr);
|
|
1069
|
+
});
|
|
1070
|
+
await ifWe(sir, 'gets correct delegate status via parent TJP address', async () => {
|
|
1071
|
+
const parentTjpAddr = getTjpAddr({ ibGib: parentKeystone });
|
|
1072
|
+
if (!parentTjpAddr) {
|
|
1073
|
+
throw new Error(`(UNEXPECTED) parentTjpAddr falsy? (E: b7ce2835ccd951d8c99257328be3b826)`);
|
|
1074
|
+
}
|
|
1075
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1076
|
+
if (!delegateTjpAddr) {
|
|
1077
|
+
throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 3e4878ea19dd8034e827466a8bf09526)`);
|
|
1078
|
+
}
|
|
1079
|
+
// Before registration
|
|
1080
|
+
const statusBefore = await service.getDelegateStatus({
|
|
1081
|
+
parentTjpAddr: parentTjpAddr,
|
|
1082
|
+
delegateTjpAddr: delegateTjpAddr,
|
|
1083
|
+
metaspace: mockMetaspace,
|
|
1084
|
+
space: mockSpace,
|
|
1085
|
+
});
|
|
1086
|
+
iReckon(sir, statusBefore.registered).asTo('initially unregistered').isGonnaBeFalse();
|
|
1087
|
+
// Register
|
|
1088
|
+
const evolvedParent = await service.registerDelegate({
|
|
1089
|
+
parentKeystone,
|
|
1090
|
+
delegateKeystone,
|
|
1091
|
+
masterSecret: parentSecret,
|
|
1092
|
+
metaspace: mockMetaspace,
|
|
1093
|
+
space: mockSpace,
|
|
1094
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1095
|
+
});
|
|
1096
|
+
// After registration
|
|
1097
|
+
const statusAfter = await service.getDelegateStatus({
|
|
1098
|
+
parentTjpAddr: parentTjpAddr,
|
|
1099
|
+
delegateTjpAddr: delegateTjpAddr,
|
|
1100
|
+
metaspace: mockMetaspace,
|
|
1101
|
+
space: mockSpace,
|
|
1102
|
+
});
|
|
1103
|
+
iReckon(sir, statusAfter.registered).asTo('registered status').isGonnaBeTrue();
|
|
1104
|
+
iReckon(sir, statusAfter.delegateInfo?.delegateTjpAddr).asTo('status tjp matches').willEqual(delegateTjpAddr);
|
|
1105
|
+
});
|
|
1106
|
+
await ifWe(sir, 'unregisters a registered delegate keystone', async () => {
|
|
1107
|
+
// Register first
|
|
1108
|
+
const evolvedParent = await service.registerDelegate({
|
|
1109
|
+
parentKeystone,
|
|
1110
|
+
delegateKeystone,
|
|
1111
|
+
masterSecret: parentSecret,
|
|
1112
|
+
metaspace: mockMetaspace,
|
|
1113
|
+
space: mockSpace,
|
|
1114
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1115
|
+
});
|
|
1116
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1117
|
+
if (!delegateTjpAddr) {
|
|
1118
|
+
throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: 486b486a8c984a52b8d2b22418c20d26)`);
|
|
1119
|
+
}
|
|
1120
|
+
// Unregister
|
|
1121
|
+
const finalParent = await service.unregisterDelegate({
|
|
1122
|
+
parentKeystone: evolvedParent,
|
|
1123
|
+
delegateTjpAddr,
|
|
1124
|
+
masterSecret: parentSecret,
|
|
1125
|
+
metaspace: mockMetaspace,
|
|
1126
|
+
space: mockSpace,
|
|
1127
|
+
});
|
|
1128
|
+
iReckon(sir, finalParent).asTo('final evolved parent exists').isGonnaBeTruthy();
|
|
1129
|
+
const info = finalParent.data?.delegates?.[delegateTjpAddr];
|
|
1130
|
+
iReckon(sir, info).asTo('delegate info removed').isGonnaBeUndefined();
|
|
1131
|
+
});
|
|
1132
|
+
await ifWe(sir, 'throws if parent does not have a manage pool', async () => {
|
|
1133
|
+
// Create a parent WITHOUT a manage pool
|
|
1134
|
+
const salt = (await getUUID()).substring(0, 16);
|
|
1135
|
+
const defaultConfig = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt });
|
|
1136
|
+
const restrictedParent = await service.genesis({
|
|
1137
|
+
masterSecret: parentSecret,
|
|
1138
|
+
configs: [defaultConfig],
|
|
1139
|
+
metaspace: mockMetaspace,
|
|
1140
|
+
space: mockSpace,
|
|
1141
|
+
});
|
|
1142
|
+
let errorCaught = false;
|
|
1143
|
+
try {
|
|
1144
|
+
await service.registerDelegate({
|
|
1145
|
+
parentKeystone: restrictedParent,
|
|
1146
|
+
delegateKeystone,
|
|
1147
|
+
masterSecret: parentSecret,
|
|
1148
|
+
metaspace: mockMetaspace,
|
|
1149
|
+
space: mockSpace,
|
|
1150
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
catch (e) {
|
|
1154
|
+
errorCaught = true;
|
|
1155
|
+
iReckon(sir, e.message).includes('Manage pool is required');
|
|
1156
|
+
}
|
|
1157
|
+
iReckon(sir, errorCaught).asTo('delegation rejected').isGonnaBeTrue();
|
|
1158
|
+
});
|
|
1159
|
+
});
|
|
1160
|
+
await respecfully(sir, 'Suite G: Delegate & IB Validation', async () => {
|
|
1161
|
+
const service = new KeystoneService_V1();
|
|
1162
|
+
const parentSecret = "ParentMasterSecret_SuiteG";
|
|
1163
|
+
const delegateSecret = "DelegateMasterSecret_SuiteG";
|
|
1164
|
+
let mockSpace;
|
|
1165
|
+
let mockMetaspace;
|
|
1166
|
+
let parentKeystone;
|
|
1167
|
+
let delegateKeystone;
|
|
1168
|
+
firstOfEach(sir, async () => {
|
|
1169
|
+
mockSpace = new MockIbGibSpace();
|
|
1170
|
+
mockMetaspace = new MockMetaspaceService(mockSpace);
|
|
1171
|
+
const salt1 = (await getUUID()).substring(0, 16);
|
|
1172
|
+
const salt2 = (await getUUID()).substring(0, 16);
|
|
1173
|
+
const manageConfig = createStandardPoolConfig({ id: POOL_ID_MANAGE, salt: salt2 });
|
|
1174
|
+
manageConfig.allowedVerbs = [KEYSTONE_VERB_MANAGE];
|
|
1175
|
+
const configs = [
|
|
1176
|
+
createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt1 }),
|
|
1177
|
+
manageConfig
|
|
1178
|
+
];
|
|
1179
|
+
parentKeystone = await service.genesis({
|
|
1180
|
+
masterSecret: parentSecret,
|
|
1181
|
+
configs,
|
|
1182
|
+
metaspace: mockMetaspace,
|
|
1183
|
+
space: mockSpace,
|
|
1184
|
+
});
|
|
1185
|
+
delegateKeystone = await service.genesis({
|
|
1186
|
+
masterSecret: delegateSecret,
|
|
1187
|
+
configs: [createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: salt1 })],
|
|
1188
|
+
metaspace: mockMetaspace,
|
|
1189
|
+
space: mockSpace,
|
|
1190
|
+
});
|
|
1191
|
+
});
|
|
1192
|
+
await ifWe(sir, 'validateKeystoneIb returns true for valid keystone ib and false for others', async () => {
|
|
1193
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'keystone' })).isGonnaBeTrue();
|
|
1194
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'keystone user info' })).isGonnaBeTrue();
|
|
1195
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'invalidAtom' })).isGonnaBeFalse();
|
|
1196
|
+
iReckon(sir, await validateKeystoneIb({ ib: 'not_keystone sub_atom' })).isGonnaBeFalse();
|
|
1197
|
+
});
|
|
1198
|
+
await ifWe(sir, 'validateGenesisKeystone fails validation if ib is invalid', async () => {
|
|
1199
|
+
const invalidGenesis = {
|
|
1200
|
+
...parentKeystone,
|
|
1201
|
+
ib: 'not_a_keystone^' + parentKeystone.gib,
|
|
1202
|
+
};
|
|
1203
|
+
const errors = await validateGenesisKeystone({ keystoneIbGib: invalidGenesis });
|
|
1204
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1205
|
+
iReckon(sir, errors[0]).includes('invalid keystone ib');
|
|
1206
|
+
});
|
|
1207
|
+
await ifWe(sir, 'validateKeystoneTransition passes for valid delegate registration', async () => {
|
|
1208
|
+
const evolvedParent = await service.registerDelegate({
|
|
1209
|
+
parentKeystone,
|
|
1210
|
+
delegateKeystone,
|
|
1211
|
+
masterSecret: parentSecret,
|
|
1212
|
+
metaspace: mockMetaspace,
|
|
1213
|
+
space: mockSpace,
|
|
1214
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1215
|
+
});
|
|
1216
|
+
const errors = await validateKeystoneTransition({
|
|
1217
|
+
currentIbGib: evolvedParent,
|
|
1218
|
+
prevIbGib: parentKeystone,
|
|
1219
|
+
});
|
|
1220
|
+
iReckon(sir, errors.length).willEqual(0);
|
|
1221
|
+
});
|
|
1222
|
+
await ifWe(sir, 'validateKeystoneTransition fails if delegates map is mutated without manage proof', async () => {
|
|
1223
|
+
const evolvedParent = await service.registerDelegate({
|
|
1224
|
+
parentKeystone,
|
|
1225
|
+
delegateKeystone,
|
|
1226
|
+
masterSecret: parentSecret,
|
|
1227
|
+
metaspace: mockMetaspace,
|
|
1228
|
+
space: mockSpace,
|
|
1229
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1230
|
+
});
|
|
1231
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
|
|
1232
|
+
// Remove the manage verb proof by converting it to sign
|
|
1233
|
+
for (const proof of tamperedParent.data.proofs) {
|
|
1234
|
+
if (proof.claim) {
|
|
1235
|
+
proof.claim.verb = 'sign';
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
const errors = await validateKeystoneTransition({
|
|
1239
|
+
currentIbGib: tamperedParent,
|
|
1240
|
+
prevIbGib: parentKeystone,
|
|
1241
|
+
});
|
|
1242
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1243
|
+
iReckon(sir, errors.some(e => e.includes('Policy Violation: Delegates map was mutated'))).isGonnaBeTrue();
|
|
1244
|
+
});
|
|
1245
|
+
await ifWe(sir, 'validateKeystoneTransition fails if delegate key does not match delegateTjpAddr', async () => {
|
|
1246
|
+
const evolvedParent = await service.registerDelegate({
|
|
1247
|
+
parentKeystone,
|
|
1248
|
+
delegateKeystone,
|
|
1249
|
+
masterSecret: parentSecret,
|
|
1250
|
+
metaspace: mockMetaspace,
|
|
1251
|
+
space: mockSpace,
|
|
1252
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1253
|
+
});
|
|
1254
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
|
|
1255
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1256
|
+
if (!delegateTjpAddr) {
|
|
1257
|
+
throw new Error(`delegateTjpAddr falsy?`);
|
|
1258
|
+
}
|
|
1259
|
+
const info = tamperedParent.data.delegates[delegateTjpAddr];
|
|
1260
|
+
delete tamperedParent.data.delegates[delegateTjpAddr];
|
|
1261
|
+
tamperedParent.data.delegates['mismatched_key'] = info;
|
|
1262
|
+
const errors = await validateKeystoneTransition({
|
|
1263
|
+
currentIbGib: tamperedParent,
|
|
1264
|
+
prevIbGib: parentKeystone,
|
|
1265
|
+
});
|
|
1266
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1267
|
+
iReckon(sir, errors.some(e => e.includes('does not match delegateTjpAddr'))).isGonnaBeTrue();
|
|
1268
|
+
});
|
|
1269
|
+
await ifWe(sir, 'validateKeystoneTransition fails if delegate addresses have invalid keystone ib', async () => {
|
|
1270
|
+
const evolvedParent = await service.registerDelegate({
|
|
1271
|
+
parentKeystone,
|
|
1272
|
+
delegateKeystone,
|
|
1273
|
+
masterSecret: parentSecret,
|
|
1274
|
+
metaspace: mockMetaspace,
|
|
1275
|
+
space: mockSpace,
|
|
1276
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1277
|
+
});
|
|
1278
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
|
|
1279
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1280
|
+
if (!delegateTjpAddr) {
|
|
1281
|
+
throw new Error(`delegateTjpAddr falsy?`);
|
|
1282
|
+
}
|
|
1283
|
+
tamperedParent.data.delegates[delegateTjpAddr].delegateAddr = 'invalid_ib^12345';
|
|
1284
|
+
const errors = await validateKeystoneTransition({
|
|
1285
|
+
currentIbGib: tamperedParent,
|
|
1286
|
+
prevIbGib: parentKeystone,
|
|
1287
|
+
});
|
|
1288
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1289
|
+
iReckon(sir, errors.some(e => e.includes('not a valid keystone address'))).isGonnaBeTrue();
|
|
1290
|
+
});
|
|
1291
|
+
await ifWe(sir, 'validateKeystoneTransition fails if thisAddr is not in the parent timeline history', async () => {
|
|
1292
|
+
const evolvedParent = await service.registerDelegate({
|
|
1293
|
+
parentKeystone,
|
|
1294
|
+
delegateKeystone,
|
|
1295
|
+
masterSecret: parentSecret,
|
|
1296
|
+
metaspace: mockMetaspace,
|
|
1297
|
+
space: mockSpace,
|
|
1298
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC],
|
|
1299
|
+
});
|
|
1300
|
+
const tamperedParent = JSON.parse(JSON.stringify(evolvedParent));
|
|
1301
|
+
const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
|
|
1302
|
+
if (!delegateTjpAddr) {
|
|
1303
|
+
throw new Error(`delegateTjpAddr falsy?`);
|
|
1304
|
+
}
|
|
1305
|
+
tamperedParent.data.delegates[delegateTjpAddr].thisAddr = 'keystone^randomgib';
|
|
1306
|
+
const errors = await validateKeystoneTransition({
|
|
1307
|
+
currentIbGib: tamperedParent,
|
|
1308
|
+
prevIbGib: parentKeystone,
|
|
1309
|
+
});
|
|
1310
|
+
iReckon(sir, errors.length > 0).isGonnaBeTrue();
|
|
1311
|
+
iReckon(sir, errors.some(e => e.includes('not a valid historical address in the parent keystone timeline'))).isGonnaBeTrue();
|
|
1312
|
+
});
|
|
1313
|
+
});
|
|
959
1314
|
//# sourceMappingURL=keystone-service-v1.respec.mjs.map
|