@ibgib/core-gib 0.1.59 → 0.1.61
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 +12 -1
- package/dist/common/other/graph-helper.d.mts.map +1 -1
- package/dist/common/other/graph-helper.mjs +7 -6
- package/dist/common/other/graph-helper.mjs.map +1 -1
- package/dist/keystone/keystone-config-builder.d.mts +1 -2
- package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
- package/dist/keystone/keystone-config-builder.mjs +4 -19
- package/dist/keystone/keystone-config-builder.mjs.map +1 -1
- package/dist/keystone/keystone-constants.d.mts +2 -0
- package/dist/keystone/keystone-constants.d.mts.map +1 -1
- package/dist/keystone/keystone-constants.mjs +2 -0
- package/dist/keystone/keystone-constants.mjs.map +1 -1
- package/dist/keystone/keystone-helpers.d.mts +5 -15
- package/dist/keystone/keystone-helpers.d.mts.map +1 -1
- package/dist/keystone/keystone-helpers.mjs +59 -73
- package/dist/keystone/keystone-helpers.mjs.map +1 -1
- package/dist/keystone/keystone-policy-types.d.mts +6 -4
- package/dist/keystone/keystone-policy-types.d.mts.map +1 -1
- package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
- package/dist/keystone/keystone-service-v1.mjs +4 -8
- package/dist/keystone/keystone-service-v1.mjs.map +1 -1
- package/dist/keystone/keystone-service-v1.respec.mjs +182 -33
- package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
- package/dist/keystone/keystone-types.d.mts +4 -11
- package/dist/keystone/keystone-types.d.mts.map +1 -1
- package/dist/keystone/policy/keystone-profile-builder.d.mts +25 -0
- package/dist/keystone/policy/keystone-profile-builder.d.mts.map +1 -0
- package/dist/keystone/policy/keystone-profile-builder.mjs +117 -0
- package/dist/keystone/policy/keystone-profile-builder.mjs.map +1 -0
- package/dist/keystone/policy/profiles/profile-high.json +84 -0
- package/dist/keystone/policy/profiles/profile-low.json +84 -0
- package/dist/keystone/policy/profiles/profile-medium.json +84 -0
- package/dist/keystone/policy/profiles/profile-session.json +84 -0
- package/dist/keystone/policy/profiles/profile-test.json +84 -0
- package/dist/keystone/policy/schemas/connect-pool.high.schema.json +23 -0
- package/dist/keystone/policy/schemas/connect-pool.low.schema.json +23 -0
- package/dist/keystone/policy/schemas/connect-pool.medium.schema.json +23 -0
- package/dist/keystone/policy/schemas/keystone.high.schema.json +26 -0
- package/dist/keystone/policy/schemas/keystone.low.schema.json +26 -0
- package/dist/keystone/policy/schemas/keystone.medium.schema.json +26 -0
- package/dist/keystone/policy/schemas/manage-pool.high.schema.json +23 -0
- package/dist/keystone/policy/schemas/manage-pool.low.schema.json +23 -0
- package/dist/keystone/policy/schemas/manage-pool.medium.schema.json +23 -0
- package/dist/keystone/policy/schemas/revoke-pool.high.schema.json +23 -0
- package/dist/keystone/policy/schemas/revoke-pool.low.schema.json +23 -0
- package/dist/keystone/policy/schemas/revoke-pool.medium.schema.json +23 -0
- package/dist/keystone/policy/schemas/sign-pool.high.schema.json +23 -0
- package/dist/keystone/policy/schemas/sign-pool.low.schema.json +23 -0
- package/dist/keystone/policy/schemas/sign-pool.medium.schema.json +23 -0
- package/dist/keystone/policy/schemas/sync-pool.high.schema.json +23 -0
- package/dist/keystone/policy/schemas/sync-pool.low.schema.json +23 -0
- package/dist/keystone/policy/schemas/sync-pool.medium.schema.json +23 -0
- package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.d.mts +8 -0
- package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs +582 -0
- package/dist/sync/sync-conflict-adv-multitimelines.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-conflict-basic-divergence.withid.respec.d.mts +7 -0
- package/dist/sync/sync-conflict-basic-divergence.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs +274 -0
- package/dist/sync/sync-conflict-basic-divergence.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.d.mts +8 -0
- package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs +322 -0
- package/dist/sync/sync-conflict-basic-multitimelines.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-conflict-text-merge.withid.respec.d.mts +7 -0
- package/dist/sync/sync-conflict-text-merge.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-conflict-text-merge.withid.respec.mjs +307 -0
- package/dist/sync/sync-conflict-text-merge.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-innerspace-constants.withid.respec.d.mts +8 -0
- package/dist/sync/sync-innerspace-constants.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-innerspace-constants.withid.respec.mjs +233 -0
- package/dist/sync/sync-innerspace-constants.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-innerspace-deep-updates.withid.respec.d.mts +7 -0
- package/dist/sync/sync-innerspace-deep-updates.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs +233 -0
- package/dist/sync/sync-innerspace-deep-updates.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-innerspace-dest-ahead.withid.respec.d.mts +7 -0
- package/dist/sync/sync-innerspace-dest-ahead.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs +225 -0
- package/dist/sync/sync-innerspace-dest-ahead.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.d.mts +7 -0
- package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs +235 -0
- package/dist/sync/sync-innerspace-multiple-timelines.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-innerspace-partial-update.withid.respec.d.mts +7 -0
- package/dist/sync/sync-innerspace-partial-update.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs +211 -0
- package/dist/sync/sync-innerspace-partial-update.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-innerspace.withid.respec.d.mts +8 -0
- package/dist/sync/sync-innerspace.withid.respec.d.mts.map +1 -0
- package/dist/sync/sync-innerspace.withid.respec.mjs +260 -0
- package/dist/sync/sync-innerspace.withid.respec.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-types.d.mts +12 -1
- package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts +7 -0
- package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +43 -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-peer-websocket-receiver-v1.d.mts +2 -0
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs +28 -9
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts +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 +5 -3
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts +16 -0
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs +223 -79
- package/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs.map +1 -1
- 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 +41 -2
- 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 +4 -0
- package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +6 -0
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +213 -137
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-withid.pingpong.respec.mjs +70 -2
- package/dist/sync/sync-withid.pingpong.respec.mjs.map +1 -1
- package/dist/timeline/timeline-api.d.mts.map +1 -1
- package/dist/timeline/timeline-api.mjs +1 -14
- package/dist/timeline/timeline-api.mjs.map +1 -1
- package/dist/witness/space/reconciliation-space/reconciliation-space-base.d.mts.map +1 -1
- package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs +0 -40
- package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs.map +1 -1
- package/dist/witness/space/reconciliation-space/reconciliation-space-helper.d.mts.map +1 -1
- package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs +6 -6
- package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs.map +1 -1
- package/ibgib-foundations.md +2 -1
- package/package.json +1 -1
- package/src/common/other/graph-helper.mts +7 -6
- package/src/keystone/README.md +19 -15
- package/src/keystone/docs/CRYPTANALYSIS.md +185 -0
- package/src/keystone/docs/architecture.md +24 -1
- package/src/keystone/docs/profiles.md +124 -0
- package/src/keystone/keystone-config-builder.mts +3 -21
- package/src/keystone/keystone-constants.mts +2 -0
- package/src/keystone/keystone-helpers.mts +74 -77
- package/src/keystone/keystone-policy-types.mts +6 -4
- package/src/keystone/keystone-service-v1.mts +4 -9
- package/src/keystone/keystone-service-v1.respec.mts +214 -32
- package/src/keystone/keystone-types.mts +5 -9
- package/src/keystone/policy/IMPLEMENTATION.md +60 -0
- package/src/keystone/policy/README.md +94 -0
- package/src/keystone/policy/keystone-profile-builder.mts +131 -0
- package/src/keystone/policy/profiles/profile-high.json +84 -0
- package/src/keystone/policy/profiles/profile-low.json +84 -0
- package/src/keystone/policy/profiles/profile-medium.json +84 -0
- package/src/keystone/policy/profiles/profile-session.json +84 -0
- package/src/keystone/policy/profiles/profile-test.json +84 -0
- package/src/keystone/policy/schemas/connect-pool.high.schema.json +23 -0
- package/src/keystone/policy/schemas/connect-pool.low.schema.json +23 -0
- package/src/keystone/policy/schemas/connect-pool.medium.schema.json +23 -0
- package/src/keystone/policy/schemas/keystone.high.schema.json +26 -0
- package/src/keystone/policy/schemas/keystone.low.schema.json +26 -0
- package/src/keystone/policy/schemas/keystone.medium.schema.json +26 -0
- package/src/keystone/policy/schemas/manage-pool.high.schema.json +23 -0
- package/src/keystone/policy/schemas/manage-pool.low.schema.json +23 -0
- package/src/keystone/policy/schemas/manage-pool.medium.schema.json +23 -0
- package/src/keystone/policy/schemas/revoke-pool.high.schema.json +23 -0
- package/src/keystone/policy/schemas/revoke-pool.low.schema.json +23 -0
- package/src/keystone/policy/schemas/revoke-pool.medium.schema.json +23 -0
- package/src/keystone/policy/schemas/sign-pool.high.schema.json +23 -0
- package/src/keystone/policy/schemas/sign-pool.low.schema.json +23 -0
- package/src/keystone/policy/schemas/sign-pool.medium.schema.json +23 -0
- package/src/keystone/policy/schemas/sync-pool.high.schema.json +23 -0
- package/src/keystone/policy/schemas/sync-pool.low.schema.json +23 -0
- package/src/keystone/policy/schemas/sync-pool.medium.schema.json +23 -0
- package/src/sync/docs/security-3b.md +92 -0
- package/src/sync/docs/security.md +139 -38
- package/src/sync/sync-conflict-adv-multitimelines.withid.respec.mts +706 -0
- package/src/sync/sync-conflict-basic-divergence.withid.respec.mts +321 -0
- package/src/sync/sync-conflict-basic-multitimelines.withid.respec.mts +374 -0
- package/src/sync/sync-conflict-text-merge.withid.respec.mts +347 -0
- package/src/sync/sync-innerspace-constants.withid.respec.mts +264 -0
- package/src/sync/sync-innerspace-deep-updates.withid.respec.mts +272 -0
- package/src/sync/sync-innerspace-dest-ahead.withid.respec.mts +266 -0
- package/src/sync/sync-innerspace-multiple-timelines.respec.mts +0 -1
- package/src/sync/sync-innerspace-multiple-timelines.withid.respec.mts +273 -0
- package/src/sync/sync-innerspace-partial-update.withid.respec.mts +249 -0
- package/src/sync/sync-innerspace.withid.respec.mts +265 -0
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +1 -1
- package/src/sync/sync-peer/sync-peer-types.mts +11 -1
- package/src/sync/sync-peer/sync-peer-v1.mts +47 -1
- package/src/sync/sync-peer/sync-peer-websocket/README.md +42 -0
- package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mts +26 -9
- package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +5 -3
- package/src/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mts +242 -78
- package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +46 -4
- package/src/sync/sync-saga-context/sync-saga-context-types.mts +5 -0
- package/src/sync/sync-saga-coordinator.mts +221 -137
- package/src/sync/sync-withid.pingpong.respec.mts +76 -3
- package/src/timeline/timeline-api.mts +1 -15
- package/src/timeline/timeline-api.respec.mts +3 -3
- package/src/witness/space/reconciliation-space/reconciliation-space-base.mts +0 -46
- package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts +6 -5
- package/tsconfig.json +6 -1
- package/src/keystone/keystone-policy.schema.json +0 -51
- package/src/sync/docs/ping_pong_plan.md +0 -147
- package/src/witness/space/reconciliation-space/reconciliation-space-base.mts.OLD.md +0 -884
- package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts.OLD.md +0 -125
|
@@ -12,7 +12,8 @@ import { KeystoneChallengePool, KeystoneClaim, KeystoneIbGib_V1, KeystonePoolCon
|
|
|
12
12
|
import { createRevocationPoolConfig, createStandardPoolConfig } from './keystone-config-builder.mjs';
|
|
13
13
|
import { POOL_ID_DEFAULT, POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE } from './keystone-constants.mjs';
|
|
14
14
|
import { KeystoneService_V1 } from './keystone-service-v1.mjs';
|
|
15
|
-
import {
|
|
15
|
+
import { selectChallengeIds, validateChallengePool } from './keystone-helpers.mjs';
|
|
16
|
+
import { KeystoneProfileBuilder } from './policy/keystone-profile-builder.mjs';
|
|
16
17
|
|
|
17
18
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
18
19
|
|
|
@@ -131,7 +132,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
131
132
|
|
|
132
133
|
await respecfully(sir, 'Derivation Logic', async () => {
|
|
133
134
|
|
|
134
|
-
await
|
|
135
|
+
await ifWeMight(sir, 'derivePoolSecret with same inputs returns same output', async () => {
|
|
135
136
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
136
137
|
|
|
137
138
|
const secretA = await strategy.derivePoolSecret({ masterSecret });
|
|
@@ -141,7 +142,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
141
142
|
iReckon(sir, secretA).asTo('secret length').isGonnaBeTruthy();
|
|
142
143
|
});
|
|
143
144
|
|
|
144
|
-
await
|
|
145
|
+
await ifWeMight(sir, 'derivePoolSecret with different master secret returns different output', async () => {
|
|
145
146
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
146
147
|
|
|
147
148
|
const secretA = await strategy.derivePoolSecret({ masterSecret });
|
|
@@ -150,7 +151,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
150
151
|
iReckon(sir, secretA).asTo('secrets differ').not.willEqual(secretB);
|
|
151
152
|
});
|
|
152
153
|
|
|
153
|
-
await
|
|
154
|
+
await ifWeMight(sir, 'derivePoolSecret with different salt returns different output', async () => {
|
|
154
155
|
// Modify salt in a copy of config
|
|
155
156
|
const configB = { ...config, salt: "OtherPool" };
|
|
156
157
|
const strategyA = KeystoneStrategyFactory.create({ config });
|
|
@@ -165,7 +166,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
165
166
|
|
|
166
167
|
await respecfully(sir, 'Challenge/Solution Logic', async () => {
|
|
167
168
|
|
|
168
|
-
await
|
|
169
|
+
await ifWeMight(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
|
|
169
170
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
170
171
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
171
172
|
const challengeId = "a3ff7843552870fc28bef2b"; // arbitrary random challengeId
|
|
@@ -184,7 +185,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
184
185
|
iReckon(sir, isValid).asTo('valid pair should pass').isGonnaBeTrue();
|
|
185
186
|
});
|
|
186
187
|
|
|
187
|
-
await
|
|
188
|
+
await ifWeMight(sir, 'validateSolution fails for mismatched values', async () => {
|
|
188
189
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
189
190
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
190
191
|
const challengeId = "8c994f3ed598f150e25513"; // arbitrary random challengeId
|
|
@@ -200,7 +201,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
|
|
|
200
201
|
iReckon(sir, isValid).asTo('tampered solution should fail').isGonnaBeFalse();
|
|
201
202
|
});
|
|
202
203
|
|
|
203
|
-
await
|
|
204
|
+
await ifWeMight(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
|
|
204
205
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
205
206
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret });
|
|
206
207
|
|
|
@@ -241,7 +242,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
241
242
|
});
|
|
242
243
|
|
|
243
244
|
await respecfully(sir, 'Genesis', async () => {
|
|
244
|
-
await
|
|
245
|
+
await ifWeMight(sir, 'creates a valid genesis frame and persists it', async () => {
|
|
245
246
|
const salt = (await getUUID()).substring(0, 16);
|
|
246
247
|
const config = createStandardPoolConfig({
|
|
247
248
|
id: POOL_ID_DEFAULT,
|
|
@@ -273,7 +274,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
273
274
|
});
|
|
274
275
|
|
|
275
276
|
await respecfully(sir, 'Signing (Evolution)', async () => {
|
|
276
|
-
await
|
|
277
|
+
await ifWeMight(sir, 'evolves the keystone with a valid proof', async () => {
|
|
277
278
|
const claim: Partial<KeystoneClaim> = {
|
|
278
279
|
target: "comment 123^gib",
|
|
279
280
|
verb: "post"
|
|
@@ -303,7 +304,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
|
|
|
303
304
|
});
|
|
304
305
|
|
|
305
306
|
await respecfully(sir, 'Validation', async () => {
|
|
306
|
-
await
|
|
307
|
+
await ifWeMight(sir, 'validates the genesis->signed transition', async () => {
|
|
307
308
|
const errors = await service.validate({
|
|
308
309
|
prevIbGib: genesisKeystone,
|
|
309
310
|
currentIbGib: signedKeystone,
|
|
@@ -352,7 +353,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
|
|
|
352
353
|
});
|
|
353
354
|
|
|
354
355
|
await respecfully(sir, 'Wrong Secret (Forgery)', async () => {
|
|
355
|
-
await
|
|
356
|
+
await ifWeMight(sir, 'prevents creation of forged frames', async () => {
|
|
356
357
|
const claim: Partial<KeystoneClaim> = { target: "comment 123^gib", verb: "post" };
|
|
357
358
|
|
|
358
359
|
let errorCaught = false;
|
|
@@ -381,7 +382,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
|
|
|
381
382
|
});
|
|
382
383
|
|
|
383
384
|
await respecfully(sir, 'Policy Violation (Restricted Verbs)', async () => {
|
|
384
|
-
await
|
|
385
|
+
await ifWeMight(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
|
|
385
386
|
// Create a specific restricted pool config manually
|
|
386
387
|
const restrictedPoolId = "read_only_pool";
|
|
387
388
|
const restrictedConfig = createStandardPoolConfig({
|
|
@@ -461,7 +462,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
461
462
|
await respecfully(sir, 'Revoke Lifecycle', async () => {
|
|
462
463
|
let revokedKeystone: KeystoneIbGib_V1;
|
|
463
464
|
|
|
464
|
-
await
|
|
465
|
+
await ifWeMight(sir, 'successfully creates a revocation frame', async () => {
|
|
465
466
|
revokedKeystone = await service.revoke({
|
|
466
467
|
latestKeystone: genesisKeystone,
|
|
467
468
|
masterSecret,
|
|
@@ -479,7 +480,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
479
480
|
iReckon(sir, data.revocationInfo!.proof.claim.verb).willEqual(KEYSTONE_VERB_REVOKE);
|
|
480
481
|
});
|
|
481
482
|
|
|
482
|
-
await
|
|
483
|
+
await ifWeMight(sir, 'validates the revocation frame', async () => {
|
|
483
484
|
const errors = await service.validate({
|
|
484
485
|
prevIbGib: genesisKeystone,
|
|
485
486
|
currentIbGib: revokedKeystone!,
|
|
@@ -490,7 +491,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
|
|
|
490
491
|
iReckon(sir, errors.length).asTo('no validation errors').willEqual(0);
|
|
491
492
|
});
|
|
492
493
|
|
|
493
|
-
await
|
|
494
|
+
await ifWeMight(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
|
|
494
495
|
const data = revokedKeystone!.data!;
|
|
495
496
|
const revokePool = data.challengePools.find(p => p.id === POOL_ID_REVOKE);
|
|
496
497
|
|
|
@@ -528,7 +529,6 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
528
529
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
529
530
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret: bobSecret });
|
|
530
531
|
const challenges: { [id: string]: any } = {};
|
|
531
|
-
const bindingMap: { [char: string]: string[] } = {};
|
|
532
532
|
|
|
533
533
|
for (let i = 0; i < 10; i++) {
|
|
534
534
|
// Manually replicate ID gen for test
|
|
@@ -540,14 +540,12 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
540
540
|
});
|
|
541
541
|
const challenge = await strategy.generateChallenge({ solution });
|
|
542
542
|
challenges[challengeId] = challenge;
|
|
543
|
-
addToBindingMap(bindingMap, challengeId);
|
|
544
543
|
}
|
|
545
544
|
|
|
546
545
|
return {
|
|
547
546
|
id,
|
|
548
547
|
config,
|
|
549
548
|
challenges,
|
|
550
|
-
bindingMap,
|
|
551
549
|
isForeign: true,
|
|
552
550
|
metadata: { owner: 'Bob' }
|
|
553
551
|
};
|
|
@@ -569,7 +567,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
569
567
|
});
|
|
570
568
|
|
|
571
569
|
await respecfully(sir, 'Happy Path', async () => {
|
|
572
|
-
await
|
|
570
|
+
await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
|
|
573
571
|
const bobPool = await createForeignPool("pool_bob", ["post"]);
|
|
574
572
|
|
|
575
573
|
const updatedKeystone = await service.addPools({
|
|
@@ -608,7 +606,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
608
606
|
});
|
|
609
607
|
|
|
610
608
|
await respecfully(sir, 'Permissions & Logic', async () => {
|
|
611
|
-
await
|
|
609
|
+
await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
|
|
612
610
|
// 1. Create a restricted keystone
|
|
613
611
|
let id = "read_only";
|
|
614
612
|
const restrictedConfig = createStandardPoolConfig({ id, salt: id });
|
|
@@ -641,7 +639,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
641
639
|
iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
|
|
642
640
|
});
|
|
643
641
|
|
|
644
|
-
await
|
|
642
|
+
await ifWeMight(sir, 'fails on ID collision', async () => {
|
|
645
643
|
// Try to add "pool_bob" again (it was added in Happy Path)
|
|
646
644
|
const duplicatePool = await createForeignPool("pool_bob");
|
|
647
645
|
|
|
@@ -688,7 +686,6 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
688
686
|
const strategy = KeystoneStrategyFactory.create({ config });
|
|
689
687
|
const poolSecret = await strategy.derivePoolSecret({ masterSecret: bobSecret });
|
|
690
688
|
const challenges: { [id: string]: any } = {};
|
|
691
|
-
const bindingMap: { [char: string]: string[] } = {};
|
|
692
689
|
|
|
693
690
|
// Generate a small set of challenges
|
|
694
691
|
for (let i = 0; i < 10; i++) {
|
|
@@ -700,14 +697,12 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
700
697
|
});
|
|
701
698
|
const challenge = await strategy.generateChallenge({ solution });
|
|
702
699
|
challenges[challengeId] = challenge;
|
|
703
|
-
addToBindingMap(bindingMap, challengeId);
|
|
704
700
|
}
|
|
705
701
|
|
|
706
702
|
return {
|
|
707
703
|
id,
|
|
708
704
|
config,
|
|
709
705
|
challenges,
|
|
710
|
-
bindingMap,
|
|
711
706
|
isForeign: true,
|
|
712
707
|
metadata: { owner: 'Bob', role: 'Delegate' }
|
|
713
708
|
};
|
|
@@ -732,7 +727,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
732
727
|
});
|
|
733
728
|
|
|
734
729
|
await respecfully(sir, 'Happy Path', async () => {
|
|
735
|
-
await
|
|
730
|
+
await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
|
|
736
731
|
const bobPool = await createForeignPool("pool_bob", ["post"]);
|
|
737
732
|
|
|
738
733
|
const updatedKeystone = await service.addPools({
|
|
@@ -771,7 +766,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
771
766
|
});
|
|
772
767
|
|
|
773
768
|
await respecfully(sir, 'Permissions & Logic', async () => {
|
|
774
|
-
await
|
|
769
|
+
await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
|
|
775
770
|
// 1. Create a restricted keystone (read-only)
|
|
776
771
|
let id = "read_only";
|
|
777
772
|
const restrictedConfig = createStandardPoolConfig({ id, salt: id });
|
|
@@ -804,7 +799,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
|
|
|
804
799
|
iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
|
|
805
800
|
});
|
|
806
801
|
|
|
807
|
-
await
|
|
802
|
+
await ifWeMight(sir, 'fails on ID collision', async () => {
|
|
808
803
|
// Try to add "pool_bob" again (it was added in Happy Path)
|
|
809
804
|
const duplicatePool = await createForeignPool("pool_bob");
|
|
810
805
|
|
|
@@ -866,7 +861,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
866
861
|
|
|
867
862
|
await respecfully(sir, 'Proof Granularity & Math', async () => {
|
|
868
863
|
|
|
869
|
-
await
|
|
864
|
+
await ifWeMight(sir, 'generates exactly the expected number of solutions', async () => {
|
|
870
865
|
signedKeystone = await service.sign({
|
|
871
866
|
latestKeystone: genesisKeystone,
|
|
872
867
|
masterSecret: aliceSecret,
|
|
@@ -883,7 +878,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
883
878
|
iReckon(sir, solutions.length).asTo('solution count').willEqual(4);
|
|
884
879
|
});
|
|
885
880
|
|
|
886
|
-
await
|
|
881
|
+
await ifWeMight(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
|
|
887
882
|
const proof = signedKeystone.data!.proofs[0];
|
|
888
883
|
const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === poolId)!;
|
|
889
884
|
|
|
@@ -912,7 +907,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
912
907
|
}
|
|
913
908
|
});
|
|
914
909
|
|
|
915
|
-
await
|
|
910
|
+
await ifWeMight(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
|
|
916
911
|
const proof = signedKeystone.data!.proofs[0];
|
|
917
912
|
const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === poolId)!;
|
|
918
913
|
|
|
@@ -930,11 +925,75 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
930
925
|
iReckon(sir, hasFirst).asTo(`Solution includes 1st FIFO ID (${expectedFifoIds[0]})`).isGonnaBeTrue();
|
|
931
926
|
iReckon(sir, hasSecond).asTo(`Solution includes 2nd FIFO ID (${expectedFifoIds[1]})`).isGonnaBeTrue();
|
|
932
927
|
});
|
|
928
|
+
|
|
929
|
+
await ifWeMight(sir, 'verifies Next-Gen Hash-Based Target Binding Selection', async () => {
|
|
930
|
+
const bindingConfig = createStandardPoolConfig({
|
|
931
|
+
id: "binding_pool",
|
|
932
|
+
salt: "binding_salt",
|
|
933
|
+
sequential: 0,
|
|
934
|
+
random: 0,
|
|
935
|
+
targetBinding: 3,
|
|
936
|
+
size: 20
|
|
937
|
+
}) as KeystonePoolConfig_HashV1;
|
|
938
|
+
|
|
939
|
+
const tempGenesis = await service.genesis({
|
|
940
|
+
masterSecret: aliceSecret,
|
|
941
|
+
configs: [bindingConfig],
|
|
942
|
+
metaspace: mockMetaspace,
|
|
943
|
+
space: mockSpace as any,
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
// Evolve using the binding pool
|
|
947
|
+
const evolved = await service.sign({
|
|
948
|
+
latestKeystone: tempGenesis,
|
|
949
|
+
masterSecret: aliceSecret,
|
|
950
|
+
poolId: "binding_pool",
|
|
951
|
+
claim: {
|
|
952
|
+
verb: "sign",
|
|
953
|
+
target: "some_target_address^gib"
|
|
954
|
+
},
|
|
955
|
+
metaspace: mockMetaspace,
|
|
956
|
+
space: mockSpace as any,
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
const proof = evolved.data!.proofs[0];
|
|
960
|
+
iReckon(sir, proof.solutions.length).asTo('proof solutions count').willEqual(3);
|
|
961
|
+
|
|
962
|
+
// Now, let's verify that the selection is perfectly deterministic.
|
|
963
|
+
// If we run selectChallengeIds manually with the same pool and target, it must return the same IDs.
|
|
964
|
+
const poolSnapshot = tempGenesis.data!.challengePools.find(p => p.id === "binding_pool")!;
|
|
965
|
+
const selectedIds = await selectChallengeIds({
|
|
966
|
+
pool: poolSnapshot,
|
|
967
|
+
targetAddr: "some_target_address^gib"
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
const proofIds = proof.solutions.map(s => s.challengeId);
|
|
971
|
+
iReckon(sir, selectedIds.length).asTo('selected IDs count').willEqual(3);
|
|
972
|
+
for (const id of selectedIds) {
|
|
973
|
+
iReckon(sir, proofIds.includes(id)).asTo(`proof includes selected ID ${id}`).isGonnaBeTrue();
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
await ifWeMight(sir, 'fails validation if total requested challenges >= size', async () => {
|
|
978
|
+
const invalidConfig = createStandardPoolConfig({
|
|
979
|
+
id: "invalid_pool",
|
|
980
|
+
salt: "invalid_salt",
|
|
981
|
+
sequential: 5,
|
|
982
|
+
random: 5,
|
|
983
|
+
targetBinding: 6,
|
|
984
|
+
size: 15 // total requested is 5+5+6 = 16 >= 15
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
const errors = await validateChallengePool({ pool: { id: "invalid_pool", config: invalidConfig, challenges: {} } });
|
|
988
|
+
iReckon(sir, errors.length > 0).asTo('errors length is positive').isGonnaBeTrue();
|
|
989
|
+
const hasCorrectError = errors.some(e => e.includes("Total requested challenges"));
|
|
990
|
+
iReckon(sir, hasCorrectError).asTo('validation error content').isGonnaBeTrue();
|
|
991
|
+
});
|
|
933
992
|
});
|
|
934
993
|
|
|
935
994
|
await respecfully(sir, 'DTO & Serialization', async () => {
|
|
936
995
|
|
|
937
|
-
await
|
|
996
|
+
await ifWeMight(sir, 'survives a clone/JSON-cycle without corruption', async () => {
|
|
938
997
|
// 1. Create a DTO (simulate network transmission/storage)
|
|
939
998
|
// 'clone' does a JSON stringify/parse under the hood (usually) or structured clone.
|
|
940
999
|
const dto = clone(signedKeystone);
|
|
@@ -954,7 +1013,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
954
1013
|
iReckon(sir, errors.length).asTo('DTO validation errors').willEqual(0);
|
|
955
1014
|
});
|
|
956
1015
|
|
|
957
|
-
await
|
|
1016
|
+
await ifWeMight(sir, 'ensures data contains no functions or circular refs', async () => {
|
|
958
1017
|
// A crude but effective test: ensure JSON.stringify doesn't throw
|
|
959
1018
|
// and the result is equal to the object (if we parsed it back).
|
|
960
1019
|
|
|
@@ -978,4 +1037,127 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
|
|
|
978
1037
|
});
|
|
979
1038
|
|
|
980
1039
|
});
|
|
1040
|
+
|
|
1041
|
+
await respecfully(sir, 'KeystoneProfileBuilder and Modular Schemas', async () => {
|
|
1042
|
+
|
|
1043
|
+
await ifWeMight(sir, 'compiles configs successfully with medium profile', async () => {
|
|
1044
|
+
const builder = KeystoneProfileBuilder.buildKeystone('medium')
|
|
1045
|
+
.withUsername('alice')
|
|
1046
|
+
.withEmail('alice@example.com')
|
|
1047
|
+
.withDescription('Alice test keystone')
|
|
1048
|
+
.withDetails({ extraInfo: 'abc' });
|
|
1049
|
+
|
|
1050
|
+
const configs = await builder.compileConfigs();
|
|
1051
|
+
iReckon(sir, configs.length).asTo('number of pools').willEqual(5);
|
|
1052
|
+
|
|
1053
|
+
// Verify unique salt derivation per pool
|
|
1054
|
+
const salts = configs.map(c => c.salt);
|
|
1055
|
+
const uniqueSalts = new Set(salts);
|
|
1056
|
+
iReckon(sir, uniqueSalts.size).asTo('unique salts count').willEqual(5);
|
|
1057
|
+
|
|
1058
|
+
// Verify frameDetails unification
|
|
1059
|
+
const details = builder.getFrameDetails();
|
|
1060
|
+
iReckon(sir, details.username).asTo('username').willEqual('alice');
|
|
1061
|
+
iReckon(sir, details.email).asTo('email').willEqual('alice@example.com');
|
|
1062
|
+
iReckon(sir, details.description).asTo('description').willEqual('Alice test keystone');
|
|
1063
|
+
iReckon(sir, details.extraInfo).asTo('extraInfo').willEqual('abc');
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
await ifWeMight(sir, 'supports customized overrides', async () => {
|
|
1067
|
+
const builder = KeystoneProfileBuilder.buildKeystone('test')
|
|
1068
|
+
.customizePool('sync', {
|
|
1069
|
+
behavior: {
|
|
1070
|
+
size: 15,
|
|
1071
|
+
targetBindingCount: 4
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
const configs = await builder.compileConfigs();
|
|
1076
|
+
const syncPool = configs.find(c => c.id === 'sync')!;
|
|
1077
|
+
iReckon(sir, syncPool.behavior.size).asTo('customized size').willEqual(15);
|
|
1078
|
+
iReckon(sir, syncPool.behavior.targetBindingCount).asTo('customized target binding').willEqual(4);
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
await respecfully(sir, 'Keystone Metadata Validation', async () => {
|
|
1084
|
+
|
|
1085
|
+
await ifWeMight(sir, 'validates correct username and description', async () => {
|
|
1086
|
+
const service = new KeystoneService_V1();
|
|
1087
|
+
const space = new MockIbGibSpace();
|
|
1088
|
+
const metaspace = new MockMetaspaceService(space);
|
|
1089
|
+
|
|
1090
|
+
const builder = KeystoneProfileBuilder.buildKeystone('test')
|
|
1091
|
+
.withUsername('alice_123.test')
|
|
1092
|
+
.withDescription('Valid description: yes, it is!')
|
|
1093
|
+
.withDetails({ client: 'respec' });
|
|
1094
|
+
|
|
1095
|
+
const configs = await builder.compileConfigs();
|
|
1096
|
+
const frameDetails = builder.getFrameDetails();
|
|
1097
|
+
|
|
1098
|
+
// Should succeed without error
|
|
1099
|
+
const keystoneIbGib = await service.genesis({
|
|
1100
|
+
masterSecret: 'mysecret',
|
|
1101
|
+
configs,
|
|
1102
|
+
metaspace: metaspace as any,
|
|
1103
|
+
space: space as any,
|
|
1104
|
+
frameDetails
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
const errors = await service.validateGenesisKeystone({ keystoneIbGib });
|
|
1108
|
+
iReckon(sir, errors.length).asTo('errors count').willEqual(0);
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
await ifWeMight(sir, 'fails validation for invalid username length or character', async () => {
|
|
1112
|
+
const service = new KeystoneService_V1();
|
|
1113
|
+
const space = new MockIbGibSpace();
|
|
1114
|
+
const metaspace = new MockMetaspaceService(space);
|
|
1115
|
+
|
|
1116
|
+
const builder = KeystoneProfileBuilder.buildKeystone('test')
|
|
1117
|
+
.withUsername('invalid_user_name_that_is_way_too_long_for_the_sixty_three_char_limit_and_will_fail_regex_check')
|
|
1118
|
+
.withDetails({ client: 'respec' });
|
|
1119
|
+
|
|
1120
|
+
const configs = await builder.compileConfigs();
|
|
1121
|
+
const frameDetails = builder.getFrameDetails();
|
|
1122
|
+
|
|
1123
|
+
const keystoneIbGib = await service.genesis({
|
|
1124
|
+
masterSecret: 'mysecret',
|
|
1125
|
+
configs,
|
|
1126
|
+
metaspace: metaspace as any,
|
|
1127
|
+
space: space as any,
|
|
1128
|
+
frameDetails
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
const errors = await service.validateGenesisKeystone({ keystoneIbGib });
|
|
1132
|
+
iReckon(sir, errors.length).asTo('errors count').willEqual(1);
|
|
1133
|
+
iReckon(sir, errors[0]).includes('invalid username');
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
await ifWeMight(sir, 'fails validation for invalid description characters', async () => {
|
|
1137
|
+
const service = new KeystoneService_V1();
|
|
1138
|
+
const space = new MockIbGibSpace();
|
|
1139
|
+
const metaspace = new MockMetaspaceService(space);
|
|
1140
|
+
|
|
1141
|
+
const builder = KeystoneProfileBuilder.buildKeystone('test')
|
|
1142
|
+
.withUsername('alice')
|
|
1143
|
+
.withDescription('Invalid desc with weird emoji 🚀')
|
|
1144
|
+
.withDetails({ client: 'respec' });
|
|
1145
|
+
|
|
1146
|
+
const configs = await builder.compileConfigs();
|
|
1147
|
+
const frameDetails = builder.getFrameDetails();
|
|
1148
|
+
|
|
1149
|
+
const keystoneIbGib = await service.genesis({
|
|
1150
|
+
masterSecret: 'mysecret',
|
|
1151
|
+
configs,
|
|
1152
|
+
metaspace: metaspace as any,
|
|
1153
|
+
space: space as any,
|
|
1154
|
+
frameDetails
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
const errors = await service.validateGenesisKeystone({ keystoneIbGib });
|
|
1158
|
+
iReckon(sir, errors.length).asTo('errors count').willEqual(1);
|
|
1159
|
+
iReckon(sir, errors[0]).includes('invalid description');
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
});
|
|
981
1163
|
});
|
|
@@ -111,10 +111,12 @@ export interface KeystonePoolBehavior {
|
|
|
111
111
|
selectRandomly: number;
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
|
-
* Number of
|
|
114
|
+
* Number of challenges to draw deterministically from the pool using
|
|
115
|
+
* next-gen hash-based index selection (drawing without replacement)
|
|
116
|
+
* bound to the full target address (`ib` + `gib`).
|
|
115
117
|
* @default 0
|
|
116
118
|
*/
|
|
117
|
-
|
|
119
|
+
targetBindingCount: number;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
export interface KeystonePoolConfigBase {
|
|
@@ -227,13 +229,7 @@ export interface KeystoneChallengePool {
|
|
|
227
229
|
*/
|
|
228
230
|
challenges: { [challengeId: string]: KeystoneChallenge };
|
|
229
231
|
|
|
230
|
-
|
|
231
|
-
* Explicit Buckets for Target Binding.
|
|
232
|
-
* Key: Hex Character ('0'-'f').
|
|
233
|
-
* Value: Array of Challenge IDs that satisfy this bucket.
|
|
234
|
-
* Note: A single ID may appear in multiple buckets (Coverage Strategy).
|
|
235
|
-
*/
|
|
236
|
-
bindingMap: { [hexChar: string]: string[] };
|
|
232
|
+
|
|
237
233
|
|
|
238
234
|
/**
|
|
239
235
|
* If true, this pool's secrets are NOT derived from the Keystone's
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Implementation Plan: Modular Policy Schemas & Keystone Profile Builder
|
|
2
|
+
|
|
3
|
+
This document outlines the step-by-step development tasks to transition the Keystone policy engine to a modular JSON-schema composed architecture with a fluent builder.
|
|
4
|
+
|
|
5
|
+
Parent Architecture Doc: [ARCHITECTURE.md](../../../../../docs/identity/ARCHITECTURE.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📋 Task Checklist
|
|
10
|
+
|
|
11
|
+
- [x] **1. Modular JSON Schema & Profiles Definitions**
|
|
12
|
+
- [x] Create schemas: `sync-pool.schema.json`, `manage-pool.schema.json`, `revoke-pool.schema.json`, `connect-pool.schema.json`, `sign-pool.schema.json` under `libs/core-gib/src/keystone/policy/schemas/`.
|
|
13
|
+
- [x] Define composite schemas `keystone.high.schema.json`, `keystone.medium.schema.json`, `keystone.low.schema.json`.
|
|
14
|
+
- [x] Migrate JSON profile files to use new schema locations.
|
|
15
|
+
|
|
16
|
+
- [x] **2. Type System Refactoring**
|
|
17
|
+
- [x] Update [keystone-policy-types.mts](../keystone-policy-types.mts) to support composite profiles and new metadata schemas.
|
|
18
|
+
|
|
19
|
+
- [x] **3. Implement `KeystoneProfileBuilder`**
|
|
20
|
+
- [x] Create `keystone-profile-builder.mts` inside `libs/core-gib/src/keystone/policy/`.
|
|
21
|
+
- [x] Implement `buildKeystone`, `withUsername`, `withEmail`, `withDescription`, `withDetails`.
|
|
22
|
+
- [x] Implement `customizePool` and `compileConfigs` with unique salt derivation and `frameDetails` unification.
|
|
23
|
+
|
|
24
|
+
- [x] **4. Build Pipeline Integration**
|
|
25
|
+
- [x] Update `build-core-gib.mts` to copy new schema/profile directories to `dist`.
|
|
26
|
+
|
|
27
|
+
- [x] **5. Downstream Consumption Refactoring**
|
|
28
|
+
- [x] Refactor space-gib's `keystone-creator.mts` to use the new builder.
|
|
29
|
+
|
|
30
|
+
- [x] **6. Automated Verification**
|
|
31
|
+
- [x] Add integration tests in `keystone-service-v1.respec.mts` ensuring the builder and modular schemas are correctly parsed, validated, and applied.
|
|
32
|
+
|
|
33
|
+
- [x] **7. Documentation & Architecture Sync**
|
|
34
|
+
- [x] Update [ARCHITECTURE.md](../../../../../docs/identity/ARCHITECTURE.md) with corrected code snippets (including fluent builder code samples) and clickable links to the actual code files (like schemas and builder implementation) for reference.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🛠️ Build & Verification Guide
|
|
39
|
+
|
|
40
|
+
Use the following commands from the monorepo root to build and verify your changes:
|
|
41
|
+
|
|
42
|
+
### 1. Build core-gib
|
|
43
|
+
Check if core-gib compiles clean:
|
|
44
|
+
```powershell
|
|
45
|
+
npm run build:core-gib
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Monorepo Chain Build
|
|
49
|
+
Build all libraries and compile the downstream `space-gib` application to test integration:
|
|
50
|
+
```powershell
|
|
51
|
+
npm run chain:build:core-gib
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 3. Run Space-Gib Client
|
|
55
|
+
To manually test the Keystone creation process via the space-gib UI, run:
|
|
56
|
+
```powershell
|
|
57
|
+
npm run dev:space-gib
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Keystone Identity Policies & Fluent Builder
|
|
2
|
+
|
|
3
|
+
This module manages Keystone Identity Policies, including security preset profiles (`high`, `medium`, `low`), modular schema composition, and the fluent configuration builder.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📖 Documentation Index
|
|
8
|
+
|
|
9
|
+
* **[Policy Architecture](../../../../../docs/identity/ARCHITECTURE.md)**: Conceptual design of separate pool behaviors, verbs, and composed schemas.
|
|
10
|
+
* **[Implementation Roadmap](./IMPLEMENTATION.md)**: Current development checklist and tasks.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 🛠️ Usage: Fluent Builder API
|
|
15
|
+
|
|
16
|
+
The `KeystoneProfileBuilder` provides a fluid interface to construct, enrich, and customize Keystone configurations before genesis.
|
|
17
|
+
|
|
18
|
+
### Basic Identity Creation
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { KeystoneProfileBuilder } from "@ibgib/core-gib/dist/keystone/policy/keystone-profile-builder.mjs";
|
|
22
|
+
|
|
23
|
+
// Build a medium-security identity config salted for a specific user
|
|
24
|
+
const configs = KeystoneProfileBuilder
|
|
25
|
+
.buildKeystone('medium')
|
|
26
|
+
.withUsername('alice')
|
|
27
|
+
.withEmail('alice@example.com')
|
|
28
|
+
.withDescription('Main user identity for Space-Gib')
|
|
29
|
+
.compileConfigs();
|
|
30
|
+
|
|
31
|
+
// Pass these configurations directly to genesis
|
|
32
|
+
const identity = await keystoneService.genesis({
|
|
33
|
+
masterSecret,
|
|
34
|
+
configs,
|
|
35
|
+
metaspace,
|
|
36
|
+
space
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Unifying Identity Details
|
|
41
|
+
|
|
42
|
+
The metadata provided to `withUsername`, `withEmail`, `withDescription`, and `withDetails` are automatically consolidated into the unified `frameDetails` field of the genesis frame:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const configs = KeystoneProfileBuilder
|
|
46
|
+
.buildKeystone('low')
|
|
47
|
+
.withUsername('bob')
|
|
48
|
+
.withDetails({
|
|
49
|
+
device: 'Pixel 8 Pro',
|
|
50
|
+
os: 'Android 14'
|
|
51
|
+
})
|
|
52
|
+
.compileConfigs();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Runtime Customizations
|
|
56
|
+
|
|
57
|
+
If an application needs to customize a specific pool's parameters dynamically (for example, raising KDF hash rounds on the sync pool for higher-security environments), use `customizePool`:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const configs = KeystoneProfileBuilder
|
|
61
|
+
.buildKeystone('medium')
|
|
62
|
+
.withUsername('charlie')
|
|
63
|
+
.customizePool('sync', {
|
|
64
|
+
rounds: 5, // Override base medium profile rounds
|
|
65
|
+
})
|
|
66
|
+
.compileConfigs();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## ⚠️ TypeScript & JSON Config Integration
|
|
72
|
+
|
|
73
|
+
If downstream projects import or load their own JSON configurations (e.g., custom `.json` files representing schemas or behavior configurations) rather than relying solely on the built-in profiles, TypeScript requires explicit path tracking in projects using `"composite": true`.
|
|
74
|
+
|
|
75
|
+
To prevent compiler errors like `TS6307: File '...' is not listed within the file list...`, ensure your project's `tsconfig.json` contains:
|
|
76
|
+
|
|
77
|
+
1. `"resolveJsonModule": true` under `compilerOptions` to allow static importing of JSON files as ES modules.
|
|
78
|
+
2. The folder/wildcard path of the JSON files added to the `"include"` array. For example:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"compilerOptions": {
|
|
83
|
+
"composite": true,
|
|
84
|
+
"resolveJsonModule": true,
|
|
85
|
+
"module": "ESNext"
|
|
86
|
+
},
|
|
87
|
+
"include": [
|
|
88
|
+
"src/**/*.ts",
|
|
89
|
+
"src/**/*.mts",
|
|
90
|
+
"src/custom-policies/*.json"
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|