@ibgib/node-gib 0.0.14 → 0.0.17
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/data/identity_index/email/hashes/32/13/49/e64f32730f01a61ada211f29eaf0a210fc2386b668ad04d7e8a9b16766.json +4 -0
- package/dist/email/email-helpers.d.mts.map +1 -1
- package/dist/email/email-helpers.mjs.map +1 -1
- package/dist/email/index.d.mts +3 -0
- package/dist/email/index.d.mts.map +1 -1
- package/dist/email/index.mjs +3 -0
- package/dist/email/index.mjs.map +1 -1
- package/dist/email/verify/email-verify-constants.d.mts +3 -0
- package/dist/email/verify/email-verify-constants.d.mts.map +1 -0
- package/dist/email/verify/email-verify-constants.mjs +3 -0
- package/dist/email/verify/email-verify-constants.mjs.map +1 -0
- package/dist/email/verify/email-verify-helpers.d.mts +107 -0
- package/dist/email/verify/email-verify-helpers.d.mts.map +1 -0
- package/dist/email/verify/email-verify-helpers.mjs +357 -0
- package/dist/email/verify/email-verify-helpers.mjs.map +1 -0
- package/dist/email/verify/email-verify-types.d.mts +41 -0
- package/dist/email/verify/email-verify-types.d.mts.map +1 -0
- package/dist/email/verify/email-verify-types.mjs +2 -0
- package/dist/email/verify/email-verify-types.mjs.map +1 -0
- package/dist/identity/sso/custodian-auth-helpers.d.mts +45 -0
- package/dist/identity/sso/custodian-auth-helpers.d.mts.map +1 -0
- package/dist/identity/sso/custodian-auth-helpers.mjs +108 -0
- package/dist/identity/sso/custodian-auth-helpers.mjs.map +1 -0
- package/dist/identity/sso/sso-config-helper.d.mts +7 -0
- package/dist/identity/sso/sso-config-helper.d.mts.map +1 -0
- package/dist/identity/sso/sso-config-helper.mjs +42 -0
- package/dist/identity/sso/sso-config-helper.mjs.map +1 -0
- package/dist/identity/sso/sso-custodian-service.d.mts +139 -0
- package/dist/identity/sso/sso-custodian-service.d.mts.map +1 -0
- package/dist/identity/sso/sso-custodian-service.mjs +471 -0
- package/dist/identity/sso/sso-custodian-service.mjs.map +1 -0
- package/dist/identity/sso/sso-types.d.mts +71 -0
- package/dist/identity/sso/sso-types.d.mts.map +1 -0
- package/dist/identity/sso/sso-types.mjs +7 -0
- package/dist/identity/sso/sso-types.mjs.map +1 -0
- package/dist/index.d.mts +5 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -1
- package/dist/index.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/email/email-outbound.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/email/email-outbound.handler.mjs +9 -2
- package/dist/serve-gib/handlers/api/email/email-outbound.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/email/email-verification-code.handler.d.mts +29 -0
- package/dist/serve-gib/handlers/api/email/email-verification-code.handler.d.mts.map +1 -0
- package/dist/serve-gib/handlers/api/email/email-verification-code.handler.mjs +149 -0
- package/dist/serve-gib/handlers/api/email/email-verification-code.handler.mjs.map +1 -0
- package/dist/serve-gib/handlers/api/email/email-verify-code-onetime.handler.d.mts +24 -0
- package/dist/serve-gib/handlers/api/email/email-verify-code-onetime.handler.d.mts.map +1 -0
- package/dist/serve-gib/handlers/api/email/email-verify-code-onetime.handler.mjs +212 -0
- package/dist/serve-gib/handlers/api/email/email-verify-code-onetime.handler.mjs.map +1 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-genesis.handler.d.mts +37 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-genesis.handler.d.mts.map +1 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-genesis.handler.mjs +192 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-genesis.handler.mjs.map +1 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.d.mts +33 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.d.mts.map +1 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.mjs +173 -0
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.mjs.map +1 -0
- package/dist/serve-gib/handlers/api/keystone/keystone-check-email.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-check-email.handler.mjs +2 -3
- package/dist/serve-gib/handlers/api/keystone/keystone-check-email.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-evolve.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-evolve.handler.mjs +38 -3
- package/dist/serve-gib/handlers/api/keystone/keystone-evolve.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-genesis.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-genesis.handler.mjs +54 -24
- package/dist/serve-gib/handlers/api/keystone/keystone-genesis.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-lookup.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-lookup.handler.mjs +13 -13
- package/dist/serve-gib/handlers/api/keystone/keystone-lookup.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-post.handler.mjs +1 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-post.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-config.handler.mjs +3 -3
- package/dist/serve-gib/handlers/api/keystone/sso-config.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-link.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-link.handler.mjs +28 -15
- package/dist/serve-gib/handlers/api/keystone/sso-link.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-login.handler.d.mts +29 -15
- package/dist/serve-gib/handlers/api/keystone/sso-login.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-login.handler.mjs +105 -108
- package/dist/serve-gib/handlers/api/keystone/sso-login.handler.mjs.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-constants.d.mts +3 -2
- package/dist/serve-gib/identity-index/identity-index-constants.d.mts.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-constants.mjs +4 -2
- package/dist/serve-gib/identity-index/identity-index-constants.mjs.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-helpers.d.mts.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-helpers.mjs +28 -11
- package/dist/serve-gib/identity-index/identity-index-helpers.mjs.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-service.d.mts +20 -3
- package/dist/serve-gib/identity-index/identity-index-service.d.mts.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-service.mjs +134 -18
- package/dist/serve-gib/identity-index/identity-index-service.mjs.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-types.d.mts +4 -2
- package/dist/serve-gib/identity-index/identity-index-types.d.mts.map +1 -1
- package/dist/serve-gib/index.d.mts +4 -0
- package/dist/serve-gib/index.d.mts.map +1 -1
- package/dist/serve-gib/index.mjs +12 -0
- package/dist/serve-gib/index.mjs.map +1 -1
- package/dist/serve-gib/path-constants.d.mts +17 -0
- package/dist/serve-gib/path-constants.d.mts.map +1 -1
- package/dist/serve-gib/path-constants.mjs +17 -0
- package/dist/serve-gib/path-constants.mjs.map +1 -1
- package/e2e/identity-custodian-lifecycle.e2e.md +93 -0
- package/e2e/identity-sso-lifecycle.e2e.md +132 -0
- package/package.json +5 -5
- package/src/email/email-helpers.mts +0 -1
- package/src/email/index.mts +3 -0
- package/src/email/verify/email-verify-constants.mts +3 -0
- package/src/email/verify/email-verify-helpers.mts +466 -0
- package/src/email/verify/email-verify-types.mts +47 -0
- package/src/identity/sso/custodian-auth-helpers.mts +146 -0
- package/src/identity/sso/custodian-auth-helpers.respec.mts +97 -0
- package/src/identity/sso/sso-config-helper.mts +52 -0
- package/src/identity/sso/sso-custodian-service.mts +566 -0
- package/src/identity/sso/sso-custodian-service.respec.mts +297 -0
- package/src/identity/sso/sso-types.mts +80 -0
- package/src/index.mts +14 -0
- package/src/serve-gib/handlers/api/email/email-outbound.handler.mts +8 -2
- package/src/serve-gib/handlers/api/email/email-verification-code.handler.mts +163 -0
- package/src/serve-gib/handlers/api/email/email-verify-code-onetime.handler.mts +231 -0
- package/src/serve-gib/handlers/api/email/email-verify.respec.mts +183 -0
- package/src/serve-gib/handlers/api/identity/keystone-custodian-genesis.handler.mts +233 -0
- package/src/serve-gib/handlers/api/identity/keystone-custodian-genesis.respec.mts +93 -0
- package/src/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.mts +210 -0
- package/src/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.respec.mts +112 -0
- package/src/serve-gib/handlers/api/keystone/keystone-check-email.handler.mts +2 -4
- package/src/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +42 -3
- package/src/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +46 -23
- package/src/serve-gib/handlers/api/keystone/keystone-lookup.handler.mts +11 -15
- package/src/serve-gib/handlers/api/keystone/keystone-post.handler.mts +1 -1
- package/src/serve-gib/handlers/api/keystone/sso-config.handler.mts +3 -3
- package/src/serve-gib/handlers/api/keystone/sso-link.handler.mts +29 -17
- package/src/serve-gib/handlers/api/keystone/sso-login.handler.mts +132 -125
- package/src/serve-gib/identity-index/identity-index-constants.mts +5 -2
- package/src/serve-gib/identity-index/identity-index-helpers.mts +26 -12
- package/src/serve-gib/identity-index/identity-index-service.mts +133 -16
- package/src/serve-gib/identity-index/identity-index-service.respec.mts +1 -1
- package/src/serve-gib/identity-index/identity-index-types.mts +4 -2
- package/src/serve-gib/index.mts +12 -0
- package/src/serve-gib/path-constants.mts +20 -0
- package/tsconfig.json +2 -2
- package/tsconfig.test.json +1 -1
- package/dist/assumptions.respec.d.mts +0 -2
- package/dist/assumptions.respec.d.mts.map +0 -1
- package/dist/assumptions.respec.mjs +0 -41
- package/dist/assumptions.respec.mjs.map +0 -1
- package/dist/email/email-service.respec.d.mts +0 -2
- package/dist/email/email-service.respec.d.mts.map +0 -1
- package/dist/email/email-service.respec.mjs +0 -115
- package/dist/email/email-service.respec.mjs.map +0 -1
- package/dist/serve-gib/bootstrap-helper.respec.d.mts +0 -2
- package/dist/serve-gib/bootstrap-helper.respec.d.mts.map +0 -1
- package/dist/serve-gib/bootstrap-helper.respec.mjs +0 -85
- package/dist/serve-gib/bootstrap-helper.respec.mjs.map +0 -1
- package/dist/serve-gib/handlers/api/health.respec.d.mts +0 -2
- package/dist/serve-gib/handlers/api/health.respec.d.mts.map +0 -1
- package/dist/serve-gib/handlers/api/health.respec.mjs +0 -47
- package/dist/serve-gib/handlers/api/health.respec.mjs.map +0 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-get.respec.d.mts +0 -2
- package/dist/serve-gib/handlers/api/keystone/keystone-get.respec.d.mts.map +0 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-get.respec.mjs +0 -98
- package/dist/serve-gib/handlers/api/keystone/keystone-get.respec.mjs.map +0 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-post.respec.d.mts +0 -2
- package/dist/serve-gib/handlers/api/keystone/keystone-post.respec.d.mts.map +0 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-post.respec.mjs +0 -131
- package/dist/serve-gib/handlers/api/keystone/keystone-post.respec.mjs.map +0 -1
- package/dist/serve-gib/identity-index/identity-index-service.respec.d.mts +0 -2
- package/dist/serve-gib/identity-index/identity-index-service.respec.d.mts.map +0 -1
- package/dist/serve-gib/identity-index/identity-index-service.respec.mjs +0 -109
- package/dist/serve-gib/identity-index/identity-index-service.respec.mjs.map +0 -1
- package/dist/serve-gib/keystone-schema-helpers.respec.d.mts +0 -2
- package/dist/serve-gib/keystone-schema-helpers.respec.d.mts.map +0 -1
- package/dist/serve-gib/keystone-schema-helpers.respec.mjs +0 -68
- package/dist/serve-gib/keystone-schema-helpers.respec.mjs.map +0 -1
- package/dist/serve-gib/path-helper.respec.d.mts +0 -2
- package/dist/serve-gib/path-helper.respec.d.mts.map +0 -1
- package/dist/serve-gib/path-helper.respec.mjs +0 -83
- package/dist/serve-gib/path-helper.respec.mjs.map +0 -1
- package/dist/serve-gib/serve-gib.respec.d.mts +0 -2
- package/dist/serve-gib/serve-gib.respec.d.mts.map +0 -1
- package/dist/serve-gib/serve-gib.respec.mjs +0 -85
- package/dist/serve-gib/serve-gib.respec.mjs.map +0 -1
- package/dist/spec-helper.node.respec.d.mts +0 -13
- package/dist/spec-helper.node.respec.d.mts.map +0 -1
- package/dist/spec-helper.node.respec.mjs +0 -50
- package/dist/spec-helper.node.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_createAndInit.node-indexed-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_createAndInit.node-indexed-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_createAndInit.node-indexed-filesystem-space-v1.respec.mjs +0 -52
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_createAndInit.node-indexed-filesystem-space-v1.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_persistTransformResult.node-indexed-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_persistTransformResult.node-indexed-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_persistTransformResult.node-indexed-filesystem-space-v1.respec.mjs +0 -53
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_persistTransformResult.node-indexed-filesystem-space-v1.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_putGetDelete.node-indexed-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_putGetDelete.node-indexed-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_putGetDelete.node-indexed-filesystem-space-v1.respec.mjs +0 -59
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_putGetDelete.node-indexed-filesystem-space-v1.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-indexed-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-indexed-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-indexed-filesystem-space-v1.respec.mjs +0 -55
- package/dist/witness/space/node-filesystem-space/node-indexed-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-indexed-filesystem-space-v1.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_createAndInit.node-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/respec/testSpace_createAndInit.node-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_createAndInit.node-filesystem-space-v1.respec.mjs +0 -67
- package/dist/witness/space/node-filesystem-space/respec/testSpace_createAndInit.node-filesystem-space-v1.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_persistTransformResult.node-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/respec/testSpace_persistTransformResult.node-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_persistTransformResult.node-filesystem-space-v1.respec.mjs +0 -67
- package/dist/witness/space/node-filesystem-space/respec/testSpace_persistTransformResult.node-filesystem-space-v1.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_putGetDelete.node-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/respec/testSpace_putGetDelete.node-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_putGetDelete.node-filesystem-space-v1.respec.mjs +0 -68
- package/dist/witness/space/node-filesystem-space/respec/testSpace_putGetDelete.node-filesystem-space-v1.respec.mjs.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-filesystem-space-v1.respec.d.mts +0 -2
- package/dist/witness/space/node-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-filesystem-space-v1.respec.d.mts.map +0 -1
- package/dist/witness/space/node-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-filesystem-space-v1.respec.mjs +0 -69
- package/dist/witness/space/node-filesystem-space/respec/testSpace_registerNewIbGib_GetLatest.node-filesystem-space-v1.respec.mjs.map +0 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { existsSync, rmSync } from 'node:fs';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
respecfully,
|
|
5
|
+
iReckon,
|
|
6
|
+
ifWe
|
|
7
|
+
} from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
8
|
+
|
|
9
|
+
import { KeystoneCustodianGenesisHandler } from './keystone-custodian-genesis.handler.mjs';
|
|
10
|
+
import { verifyCustodianRequirements } from '../../../../identity/sso/custodian-auth-helpers.mjs';
|
|
11
|
+
import { loadSsoServerConfig } from '../../../../identity/sso/sso-config-helper.mjs';
|
|
12
|
+
|
|
13
|
+
const sir = `[${import.meta.url}]`;
|
|
14
|
+
|
|
15
|
+
await respecfully(sir, 'KeystoneCustodianGenesisHandler', async () => {
|
|
16
|
+
const testDataDir = './test-data-custodian-genesis';
|
|
17
|
+
|
|
18
|
+
if (existsSync(testDataDir)) {
|
|
19
|
+
rmSync(testDataDir, { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const origDataDir = process.env.DATA_DIR;
|
|
23
|
+
process.env.DATA_DIR = testDataDir;
|
|
24
|
+
|
|
25
|
+
const handler = new KeystoneCustodianGenesisHandler();
|
|
26
|
+
|
|
27
|
+
await ifWe(sir, 'reject request with 400 if email is missing or invalid', async () => {
|
|
28
|
+
const reqCtx: any = {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
body: JSON.stringify({ email: 'invalid-email' }),
|
|
31
|
+
dataDir: testDataDir
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const res = await handler.handleRoute(reqCtx);
|
|
35
|
+
iReckon(sir, res?.status).isGonnaBe(400);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await ifWe(sir, 'create new custodian primary identity and return custodianReqs for new email', async () => {
|
|
39
|
+
const reqCtx: any = {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
body: JSON.stringify({ email: 'alice.custodian@example.com', username: 'alice' }),
|
|
42
|
+
dataDir: testDataDir
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const res = await handler.handleRoute(reqCtx);
|
|
46
|
+
iReckon(sir, res?.status).isGonnaBe(201);
|
|
47
|
+
|
|
48
|
+
const body = JSON.parse(res?.body || '{}');
|
|
49
|
+
iReckon(sir, body.success).isGonnaBeTrue();
|
|
50
|
+
iReckon(sir, body.isNewIdentity).isGonnaBeTrue();
|
|
51
|
+
iReckon(sir, body.primaryTjpAddr).includes('keystone^');
|
|
52
|
+
iReckon(sir, body.primaryKeystone).not.isGonnaBeUndefined();
|
|
53
|
+
iReckon(sir, body.custodianReqs).not.isGonnaBeUndefined();
|
|
54
|
+
|
|
55
|
+
// Verify returned custodianReqs authCode signature
|
|
56
|
+
const serverSecret = loadSsoServerConfig().ssoServerKdfSecret;
|
|
57
|
+
const verifyRes = await verifyCustodianRequirements({
|
|
58
|
+
custodianReqs: body.custodianReqs,
|
|
59
|
+
serverSecret
|
|
60
|
+
});
|
|
61
|
+
iReckon(sir, verifyRes.valid).isGonnaBeTrue();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await ifWe(sir, 'retrieve existing primary identity and return fresh custodianReqs for existing email', async () => {
|
|
65
|
+
const reqCtx: any = {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
body: JSON.stringify({ email: 'alice.custodian@example.com' }),
|
|
68
|
+
dataDir: testDataDir
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const res = await handler.handleRoute(reqCtx);
|
|
72
|
+
iReckon(sir, res?.status).isGonnaBe(200);
|
|
73
|
+
|
|
74
|
+
const body = JSON.parse(res?.body || '{}');
|
|
75
|
+
iReckon(sir, body.success).isGonnaBeTrue();
|
|
76
|
+
iReckon(sir, body.isNewIdentity).isGonnaBeFalse();
|
|
77
|
+
iReckon(sir, body.primaryTjpAddr).includes('keystone^');
|
|
78
|
+
iReckon(sir, body.custodianReqs).not.isGonnaBeUndefined();
|
|
79
|
+
|
|
80
|
+
const serverSecret = loadSsoServerConfig().ssoServerKdfSecret;
|
|
81
|
+
const verifyRes = await verifyCustodianRequirements({
|
|
82
|
+
custodianReqs: body.custodianReqs,
|
|
83
|
+
serverSecret
|
|
84
|
+
});
|
|
85
|
+
iReckon(sir, verifyRes.valid).isGonnaBeTrue();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Cleanup
|
|
89
|
+
process.env.DATA_DIR = origDataDir;
|
|
90
|
+
if (existsSync(testDataDir)) {
|
|
91
|
+
rmSync(testDataDir, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler
|
|
3
|
+
*
|
|
4
|
+
* POST /api/identity/custodian/register-delegate
|
|
5
|
+
*
|
|
6
|
+
* Validates a client delegate keystone containing single-turn `custodianReqs`,
|
|
7
|
+
* enforces single-use nonce reservation, verifies cryptographic `authCode`,
|
|
8
|
+
* evolves the server-held primary identity keystone to link the delegate,
|
|
9
|
+
* and returns the updated `evolvedPrimaryKeystone`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from 'fs/promises';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
import { extractErrorMsg, hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
16
|
+
import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
|
|
17
|
+
import { getDependencyGraph } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
|
|
18
|
+
import { FlatIbGibGraph } from '@ibgib/core-gib/dist/common/other/graph-types.mjs';
|
|
19
|
+
import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
|
|
20
|
+
import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
|
|
21
|
+
import { KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
|
|
22
|
+
|
|
23
|
+
import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
|
|
24
|
+
import { ServeGibHandlerBase } from '../../handler-base.mjs';
|
|
25
|
+
import { RequestContext, ResponseResult, ServeGibHttpMethod } from '../../../types.mjs';
|
|
26
|
+
import { API_PATH_REGEXES } from '../../../path-constants.mjs';
|
|
27
|
+
import { bootstrapDomainMetaspace } from '../../../bootstrap-helper.mjs';
|
|
28
|
+
import { loadSsoServerConfig } from '../../../../identity/sso/sso-config-helper.mjs';
|
|
29
|
+
import { getAuthCustodianIndex, verifyCustodianRequirements } from '../../../../identity/sso/custodian-auth-helpers.mjs';
|
|
30
|
+
import { CustodianRequirements } from '../../../../identity/sso/sso-types.mjs';
|
|
31
|
+
|
|
32
|
+
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
33
|
+
|
|
34
|
+
export interface CustodianRegisterDelegateRequestBody {
|
|
35
|
+
delegateKeystone: any;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface CustodianRegisterDelegateResponseBody {
|
|
39
|
+
success: boolean;
|
|
40
|
+
primaryTjpAddr: string;
|
|
41
|
+
evolvedPrimaryKeystone: any;
|
|
42
|
+
primaryGraph?: FlatIbGibGraph;
|
|
43
|
+
message?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* POST /api/identity/custodian/register-delegate
|
|
48
|
+
*/
|
|
49
|
+
export class KeystoneCustodianRegisterDelegateHandler extends ServeGibHandlerBase<undefined, undefined> {
|
|
50
|
+
protected override lc: string = `[${KeystoneCustodianRegisterDelegateHandler.name}]`;
|
|
51
|
+
protected override method: ServeGibHttpMethod = 'POST';
|
|
52
|
+
protected override regex = API_PATH_REGEXES.KEYSTONE_CUSTODIAN_REGISTER_DELEGATE;
|
|
53
|
+
|
|
54
|
+
protected async handleRouteImpl(
|
|
55
|
+
reqCtx: RequestContext<undefined, undefined>
|
|
56
|
+
): Promise<ResponseResult | undefined> {
|
|
57
|
+
const lc = `${this.lc}[${this.handleRouteImpl.name}]`;
|
|
58
|
+
let authFilePathToClean: string | undefined;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
if (logalot) { console.log(`${lc} starting... (I: a23456789abcdef0123456789c0001)`); }
|
|
62
|
+
|
|
63
|
+
if (reqCtx.method !== 'POST') {
|
|
64
|
+
return this.error(405, 'Method Not Allowed');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!reqCtx.body) {
|
|
68
|
+
return this.error(400, 'Request body is empty (E: b23456789abcdef0123456789c0002)');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let body: CustodianRegisterDelegateRequestBody;
|
|
72
|
+
try {
|
|
73
|
+
body = JSON.parse(reqCtx.body);
|
|
74
|
+
} catch {
|
|
75
|
+
return this.error(400, 'Request body must be valid JSON (E: c23456789abcdef0123456789c0003)');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const { delegateKeystone } = body;
|
|
79
|
+
if (!delegateKeystone) {
|
|
80
|
+
return this.error(400, 'Request body must contain delegateKeystone (E: d23456789abcdef0123456789c0004)');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 1. Intrinsic hash validation on delegate keystone
|
|
84
|
+
const intrinsicErrors = await validateIbGibIntrinsically({ ibGib: delegateKeystone });
|
|
85
|
+
if (intrinsicErrors && intrinsicErrors.length > 0) {
|
|
86
|
+
return this.error(422, 'Intrinsic validation failed for delegateKeystone', { errors: intrinsicErrors });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 2. Structural keystone validation
|
|
90
|
+
const keystoneService = new KeystoneService_V1();
|
|
91
|
+
const genesisErrors = await keystoneService.validateGenesisKeystone({ keystoneIbGib: delegateKeystone });
|
|
92
|
+
if (genesisErrors && genesisErrors.length > 0) {
|
|
93
|
+
return this.error(422, 'Delegate keystone structure validation failed', { errors: genesisErrors });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 3. Extract and check custodianReqs from frameDetails
|
|
97
|
+
const frameDetails = delegateKeystone.data?.frameDetails || delegateKeystone.data;
|
|
98
|
+
const custodianReqs: CustodianRequirements | undefined = frameDetails?.custodianReqs;
|
|
99
|
+
if (!custodianReqs) {
|
|
100
|
+
return this.error(400, 'Missing custodianReqs payload in delegate keystone frameDetails (E: e23456789abcdef0123456789c0005)');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const delegatePrimaryTjpAddr: string | undefined = frameDetails?.primaryTjpAddr;
|
|
104
|
+
if (delegatePrimaryTjpAddr && delegatePrimaryTjpAddr !== custodianReqs.primaryTjpAddr) {
|
|
105
|
+
return this.error(400, 'Primary TJP address mismatch between delegate frameDetails and custodianReqs (E: f23456789abcdef0123456789c0006)');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 4. Verify cryptographic signature & expiration of custodianReqs
|
|
109
|
+
const ssoConfig = loadSsoServerConfig();
|
|
110
|
+
const serverSecret = ssoConfig.ssoServerKdfSecret;
|
|
111
|
+
const verifyRes = await verifyCustodianRequirements({ custodianReqs, serverSecret });
|
|
112
|
+
if (!verifyRes.valid) {
|
|
113
|
+
return this.error(401, verifyRes.error || 'Invalid custodian requirements payload');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 5. Atomic Single-Turn Nonce Reservation Check (`{ flag: 'wx' }`)
|
|
117
|
+
const authCustodianIndex = await getAuthCustodianIndex({ custodianReqs });
|
|
118
|
+
const dataDir = reqCtx.dataDir || process.env.DATA_DIR || 'data';
|
|
119
|
+
const authDir = path.join(dataDir, 'identity_index', 'auth_custodian');
|
|
120
|
+
await fs.mkdir(authDir, { recursive: true });
|
|
121
|
+
|
|
122
|
+
authFilePathToClean = path.join(authDir, `${authCustodianIndex}.json`);
|
|
123
|
+
try {
|
|
124
|
+
await fs.writeFile(authFilePathToClean, JSON.stringify({
|
|
125
|
+
usedAt: Date.now(),
|
|
126
|
+
primaryTjpAddr: custodianReqs.primaryTjpAddr,
|
|
127
|
+
nonce: custodianReqs.nonce
|
|
128
|
+
}), { flag: 'wx' });
|
|
129
|
+
} catch (fileErr: any) {
|
|
130
|
+
if (fileErr.code === 'EEXIST') {
|
|
131
|
+
return this.error(409, 'Custodian requirements payload has already been used. Nonce single-turn reservation violation.');
|
|
132
|
+
}
|
|
133
|
+
throw fileErr;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 6. Evolve Server-Held Primary Identity Keystone
|
|
137
|
+
const metaspace = await bootstrapDomainMetaspace(custodianReqs.primaryTjpAddr, reqCtx.dataDir);
|
|
138
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
139
|
+
if (!space) {
|
|
140
|
+
return this.error(500, `Could not load domain space for primary identity ${custodianReqs.primaryTjpAddr}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const latestPrimaryAddr = await metaspace.getLatestAddr({ addr: custodianReqs.primaryTjpAddr, space }) ?? custodianReqs.primaryTjpAddr;
|
|
144
|
+
const getRes = await metaspace.get({ addrs: [latestPrimaryAddr], space });
|
|
145
|
+
const parentKeystone = getRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
|
|
146
|
+
|
|
147
|
+
if (!parentKeystone) {
|
|
148
|
+
return this.error(404, `Primary identity keystone not found for address ${custodianReqs.primaryTjpAddr}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Derive server's primary custodian secret
|
|
152
|
+
const primaryEmail: string = parentKeystone.data?.emails?.[0]
|
|
153
|
+
|| parentKeystone.data?.frameDetails?.emails?.[0]
|
|
154
|
+
|| frameDetails?.email
|
|
155
|
+
|| '';
|
|
156
|
+
|
|
157
|
+
if (!primaryEmail) {
|
|
158
|
+
return this.error(500, `Could not determine primary email for identity ${custodianReqs.primaryTjpAddr}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const primarySecret = await hash({ s: `${serverSecret}_custodian_${primaryEmail}` });
|
|
162
|
+
|
|
163
|
+
// Execute primary keystone evolution linking the new delegate
|
|
164
|
+
const evolvedPrimaryKeystone = await keystoneService.registerDelegate({
|
|
165
|
+
parentKeystone,
|
|
166
|
+
delegateKeystone,
|
|
167
|
+
masterSecret: primarySecret,
|
|
168
|
+
metaspace,
|
|
169
|
+
space,
|
|
170
|
+
allowedVerbs: custodianReqs.allowedVerbs || [KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT],
|
|
171
|
+
deviceName: frameDetails?.deviceTag || 'client-delegate'
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Persist delegate keystone in domain space
|
|
175
|
+
await metaspace.put({ ibGibs: [delegateKeystone], space });
|
|
176
|
+
await metaspace.registerNewIbGib({ ibGib: delegateKeystone, space });
|
|
177
|
+
|
|
178
|
+
// Extract complete primary keystone dependency graph
|
|
179
|
+
const primaryGraph = await getDependencyGraph({
|
|
180
|
+
ibGib: evolvedPrimaryKeystone,
|
|
181
|
+
space,
|
|
182
|
+
live: false
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const responseBody: CustodianRegisterDelegateResponseBody = {
|
|
186
|
+
success: true,
|
|
187
|
+
primaryTjpAddr: custodianReqs.primaryTjpAddr,
|
|
188
|
+
evolvedPrimaryKeystone,
|
|
189
|
+
primaryGraph,
|
|
190
|
+
message: 'Custodian delegate keystone registered and primary identity evolved successfully.'
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return this.ok(responseBody, 200);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
const emsg = extractErrorMsg(error);
|
|
196
|
+
console.error(`${lc} ${emsg}`);
|
|
197
|
+
return this.error(500, emsg);
|
|
198
|
+
} finally {
|
|
199
|
+
// Clean up single-turn reservation file after processing
|
|
200
|
+
if (authFilePathToClean) {
|
|
201
|
+
try {
|
|
202
|
+
await fs.unlink(authFilePathToClean);
|
|
203
|
+
} catch {
|
|
204
|
+
// Ignore unlinking errors if already cleaned up
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { existsSync, rmSync } from 'node:fs';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
respecfully,
|
|
5
|
+
iReckon,
|
|
6
|
+
ifWe
|
|
7
|
+
} from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
8
|
+
|
|
9
|
+
import { KeystoneCustodianGenesisHandler } from './keystone-custodian-genesis.handler.mjs';
|
|
10
|
+
import { KeystoneCustodianRegisterDelegateHandler } from './keystone-custodian-register-delegate.handler.mjs';
|
|
11
|
+
import { KeystoneProfileBuilder } from '@ibgib/core-gib/dist/keystone/policy/keystone-profile-builder.mjs';
|
|
12
|
+
import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
|
|
13
|
+
import { deriveLocalCustodianDelegateSecret } from '@ibgib/web-gib/dist/identity/custodian-delegate-helper.mjs';
|
|
14
|
+
import { bootstrapDomainMetaspace } from '../../../bootstrap-helper.mjs';
|
|
15
|
+
|
|
16
|
+
const sir = `[${import.meta.url}]`;
|
|
17
|
+
|
|
18
|
+
await respecfully(sir, 'KeystoneCustodianRegisterDelegateHandler', async () => {
|
|
19
|
+
const testDataDir = './test-data-custodian-register';
|
|
20
|
+
|
|
21
|
+
if (existsSync(testDataDir)) {
|
|
22
|
+
rmSync(testDataDir, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const origDataDir = process.env.DATA_DIR;
|
|
26
|
+
process.env.DATA_DIR = testDataDir;
|
|
27
|
+
|
|
28
|
+
const genesisHandler = new KeystoneCustodianGenesisHandler();
|
|
29
|
+
const registerHandler = new KeystoneCustodianRegisterDelegateHandler();
|
|
30
|
+
|
|
31
|
+
await ifWe(sir, 'reject request with 400 if delegateKeystone or custodianReqs is missing', async () => {
|
|
32
|
+
const reqCtx: any = {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
body: JSON.stringify({}),
|
|
35
|
+
dataDir: testDataDir
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const res = await registerHandler.handleRoute(reqCtx);
|
|
39
|
+
iReckon(sir, res?.status).isGonnaBe(400);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await ifWe(sir, 'successfully register delegate keystone and evolve primary identity keystone', async () => {
|
|
43
|
+
// Step 1: Genesis via custodian genesis handler
|
|
44
|
+
const genesisReqCtx: any = {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
body: JSON.stringify({ email: 'bob.custodian@example.com', username: 'bob' }),
|
|
47
|
+
dataDir: testDataDir
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const genesisRes = await genesisHandler.handleRoute(genesisReqCtx);
|
|
51
|
+
iReckon(sir, genesisRes?.status).isGonnaBe(201);
|
|
52
|
+
|
|
53
|
+
const genesisBody = JSON.parse(genesisRes?.body || '{}');
|
|
54
|
+
const primaryTjpAddr = genesisBody.primaryTjpAddr;
|
|
55
|
+
const custodianReqs = genesisBody.custodianReqs;
|
|
56
|
+
|
|
57
|
+
iReckon(sir, primaryTjpAddr).not.isGonnaBeUndefined();
|
|
58
|
+
iReckon(sir, custodianReqs).not.isGonnaBeUndefined();
|
|
59
|
+
|
|
60
|
+
// Step 2: Build client delegate keystone containing custodianReqs
|
|
61
|
+
const delegateSecret = await deriveLocalCustodianDelegateSecret({ primaryTjpAddr });
|
|
62
|
+
const delegateBuilder = KeystoneProfileBuilder.buildKeystone('sync')
|
|
63
|
+
.withUsername('bob-sync-phone')
|
|
64
|
+
.withDescription('Sync Delegate for bob on phone')
|
|
65
|
+
.withDetails({
|
|
66
|
+
client: 'space-gib-web',
|
|
67
|
+
role: 'sync-delegate',
|
|
68
|
+
deviceTag: 'phone',
|
|
69
|
+
primaryTjpAddr,
|
|
70
|
+
custodianReqs,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const configs = await delegateBuilder.compileConfigs();
|
|
74
|
+
const metaspace = await bootstrapDomainMetaspace(primaryTjpAddr, testDataDir);
|
|
75
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
76
|
+
|
|
77
|
+
const keystoneService = new KeystoneService_V1();
|
|
78
|
+
const delegateKeystone = await keystoneService.genesis({
|
|
79
|
+
masterSecret: delegateSecret,
|
|
80
|
+
configs,
|
|
81
|
+
metaspace,
|
|
82
|
+
space: space!,
|
|
83
|
+
frameDetails: delegateBuilder.getFrameDetails(),
|
|
84
|
+
isPrimary: false
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Step 3: Register delegate keystone with server
|
|
88
|
+
const registerReqCtx: any = {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
body: JSON.stringify({ delegateKeystone }),
|
|
91
|
+
dataDir: testDataDir
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const registerRes = await registerHandler.handleRoute(registerReqCtx);
|
|
95
|
+
iReckon(sir, registerRes?.status).isGonnaBe(200);
|
|
96
|
+
|
|
97
|
+
const registerBody = JSON.parse(registerRes?.body || '{}');
|
|
98
|
+
iReckon(sir, registerBody.success).isGonnaBeTrue();
|
|
99
|
+
iReckon(sir, registerBody.primaryTjpAddr).isGonnaBe(primaryTjpAddr);
|
|
100
|
+
iReckon(sir, registerBody.evolvedPrimaryKeystone).not.isGonnaBeUndefined();
|
|
101
|
+
|
|
102
|
+
// Verify primary keystone frame n=1 has been evolved
|
|
103
|
+
const evolvedPrimary = registerBody.evolvedPrimaryKeystone;
|
|
104
|
+
iReckon(sir, evolvedPrimary.data?.n).isGonnaBe(1);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Cleanup
|
|
108
|
+
process.env.DATA_DIR = origDataDir;
|
|
109
|
+
if (existsSync(testDataDir)) {
|
|
110
|
+
rmSync(testDataDir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
@@ -6,10 +6,8 @@
|
|
|
6
6
|
* Checks whether an email address is already registered in the server identity index.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import * as path from 'node:path';
|
|
10
9
|
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
11
|
-
import {
|
|
12
|
-
import { getIdentityEmailHash } from '../../../identity-index/identity-index-helpers.mjs';
|
|
10
|
+
import { getIdentityIndexService } from '../../../identity-index/identity-index-service.mjs';
|
|
13
11
|
import { ServeGibHandlerBase } from '../../handler-base.mjs';
|
|
14
12
|
import { RequestContext, ResponseResult, ServeGibHttpMethod } from '../../../types.mjs';
|
|
15
13
|
import { API_PATH_REGEXES } from '../../../path-constants.mjs';
|
|
@@ -36,7 +34,7 @@ export class KeystoneCheckEmailHandler extends ServeGibHandlerBase<undefined, {
|
|
|
36
34
|
return this.error(400, 'Query param email is required');
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
const indexService =
|
|
37
|
+
const indexService = getIdentityIndexService();
|
|
40
38
|
const record = await indexService.getEmailIndex({ email });
|
|
41
39
|
|
|
42
40
|
if (record) {
|
|
@@ -15,15 +15,17 @@ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
|
15
15
|
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
16
16
|
import { validateAndRegisterEvolveKeystone } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs';
|
|
17
17
|
import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
|
|
18
|
-
import { loadSsoServerConfig } from '
|
|
19
|
-
import { SsoCustodianService } from '
|
|
18
|
+
import { loadSsoServerConfig } from '../../../../identity/sso/sso-config-helper.mjs';
|
|
19
|
+
import { SsoCustodianService } from '../../../../identity/sso/sso-custodian-service.mjs';
|
|
20
20
|
|
|
21
21
|
import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
|
|
22
|
+
import { getIdentityIndexService } from '../../../identity-index/identity-index-service.mjs';
|
|
23
|
+
import { savePendingStagingKeystone, dispatchVerificationCode } from '../../../../email/verify/email-verify-helpers.mjs';
|
|
22
24
|
import { ServeGibHandlerWithMetaspaceBase } from '../../handler-base.mjs';
|
|
23
25
|
import { API_PATH_REGEXES } from '../../../path-constants.mjs';
|
|
24
26
|
import { ParamsWithDomain, RequestContext, ResponseResult } from '../../../types.mjs';
|
|
25
27
|
|
|
26
|
-
const logalot = GLOBAL_LOG_A_LOT
|
|
28
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
27
29
|
|
|
28
30
|
interface EvolveParams extends ParamsWithDomain {
|
|
29
31
|
domainAddr: string;
|
|
@@ -97,6 +99,43 @@ export class KeystoneEvolveHandler extends ServeGibHandlerWithMetaspaceBase<Evol
|
|
|
97
99
|
return this.error(500, 'No local user space found (E: a1144e5d6cd9641fb82d6b359f131126)');
|
|
98
100
|
}
|
|
99
101
|
|
|
102
|
+
// Check for any new unverified email addresses attached to the evolved keystone
|
|
103
|
+
const incomingEmails: string[] = keystoneIbGib.data?.emails ?? keystoneIbGib.data?.frameDetails?.emails ?? [];
|
|
104
|
+
if (incomingEmails.length > 0) {
|
|
105
|
+
const unverifiedEmails: string[] = [];
|
|
106
|
+
for (const email of incomingEmails) {
|
|
107
|
+
const record = await getIdentityIndexService().lookupIdentityByEmail({ email });
|
|
108
|
+
if (!record || record.primaryTjpAddr !== domainAddr) {
|
|
109
|
+
unverifiedEmails.push(email);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (unverifiedEmails.length > 0) {
|
|
114
|
+
console.log(`${lc} Evolved keystone contains unverified email(s): ${unverifiedEmails.join(', ')}. Staging evolution in quarantine area.`);
|
|
115
|
+
const saveRes = await savePendingStagingKeystone({
|
|
116
|
+
keystone: keystoneIbGib,
|
|
117
|
+
emails: unverifiedEmails,
|
|
118
|
+
primaryTjpAddr: domainAddr,
|
|
119
|
+
dataDir: reqCtx.dataDir
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Immediately dispatch 6-digit verification code email for first unverified email
|
|
123
|
+
const primaryEmail = unverifiedEmails[0];
|
|
124
|
+
await dispatchVerificationCode({
|
|
125
|
+
email: primaryEmail,
|
|
126
|
+
primaryTjpAddr: domainAddr,
|
|
127
|
+
pendingDir: saveRes.pendingDir,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return this.ok({
|
|
131
|
+
success: true,
|
|
132
|
+
pending: true,
|
|
133
|
+
addr: domainAddr,
|
|
134
|
+
message: 'Evolved keystone quarantined in pending staging area. 6-digit verification code sent to your email.'
|
|
135
|
+
}, 202);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
100
139
|
// Delegate all intrinsic checks, transition rules, pool restrictions, and registration/persistence to core-gib helper
|
|
101
140
|
await validateAndRegisterEvolveKeystone({
|
|
102
141
|
domainAddr,
|
|
@@ -33,12 +33,11 @@
|
|
|
33
33
|
import { existsSync } from 'node:fs';
|
|
34
34
|
import * as path from 'node:path';
|
|
35
35
|
|
|
36
|
-
import { extractErrorMsg, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
36
|
+
import { extractErrorMsg, getUUID, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
37
37
|
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
38
38
|
import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
|
|
39
39
|
import { getGibInfo } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
|
|
40
40
|
import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
|
|
41
|
-
import { IdentityIndexService } from '../../../identity-index/identity-index-service.mjs';
|
|
42
41
|
|
|
43
42
|
import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
|
|
44
43
|
import { ServeGibHandlerBase } from '../../handler-base.mjs';
|
|
@@ -46,12 +45,11 @@ import { RequestContext, ResponseResult, ServeGibHttpMethod } from '../../../typ
|
|
|
46
45
|
import { API_PATH_REGEXES } from '../../../path-constants.mjs';
|
|
47
46
|
import { getDomainRootPath } from '../../../bootstrap-helper.mjs';
|
|
48
47
|
import { bootstrapDomainMetaspace } from '../../../bootstrap-helper.mjs';
|
|
48
|
+
import { savePendingStagingKeystone, dispatchVerificationCode } from '../../../../email/verify/email-verify-helpers.mjs';
|
|
49
49
|
|
|
50
50
|
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
53
|
/**
|
|
56
54
|
* POST /api/keystone/genesis
|
|
57
55
|
*
|
|
@@ -66,8 +64,11 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
|
|
|
66
64
|
reqCtx: RequestContext<undefined, undefined>
|
|
67
65
|
): Promise<ResponseResult | undefined> {
|
|
68
66
|
const lc = `${this.lc}[${this.handleRouteImpl.name}]`;
|
|
67
|
+
const timestampUUID = `${lc}${[(await getUUID()).substring(0, 8)]}`;
|
|
69
68
|
try {
|
|
70
|
-
if (logalot) { console.log(`${lc} starting... (I:
|
|
69
|
+
if (logalot) { console.log(`${lc} starting... (I: 866db89dfcb947c7353a1a8849bb2826)`); }
|
|
70
|
+
|
|
71
|
+
if (logalot) { console.time(timestampUUID); }
|
|
71
72
|
|
|
72
73
|
// ----------------------------------------------------------------
|
|
73
74
|
// 1. Parse body — expect { keystoneIbGib }
|
|
@@ -79,6 +80,8 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
|
|
|
79
80
|
return this.error(400, 'Request body must be valid JSON (E: dd8618857568f8fc5e9c62b8ed135826)');
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
if (logalot) { console.timeLog(timestampUUID, 'parse complete') }
|
|
84
|
+
|
|
82
85
|
const { keystoneIbGib } = parsed;
|
|
83
86
|
if (!keystoneIbGib) {
|
|
84
87
|
return this.error(400, 'Body must contain keystoneIbGib (E: 9c8c5d979d7842cd716ba64f69349c26)');
|
|
@@ -92,6 +95,8 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
|
|
|
92
95
|
return this.error(422, 'Intrinsic keystone validation failed (E: 76d388e198f23a87dd6596f59c36e826)', { errors: intrinsicErrors });
|
|
93
96
|
}
|
|
94
97
|
|
|
98
|
+
if (logalot) { console.timeLog(timestampUUID, 'intrinsic validation complete') }
|
|
99
|
+
|
|
95
100
|
// ----------------------------------------------------------------
|
|
96
101
|
// 3. Structural keystone + genesis-frame checks
|
|
97
102
|
// ----------------------------------------------------------------
|
|
@@ -102,11 +107,14 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
|
|
|
102
107
|
if (keystoneErrors && keystoneErrors.length > 0) {
|
|
103
108
|
return this.error(422, `Keystone genesis validation failed. Errors: ${keystoneErrors} (E: 8384285be7a8ab0d41cfd1df2e2aa826)`, { errors: keystoneErrors });
|
|
104
109
|
}
|
|
110
|
+
if (logalot) { console.timeLog(timestampUUID, 'keystone validation complete') }
|
|
105
111
|
|
|
106
112
|
// ----------------------------------------------------------------
|
|
107
113
|
// 4. Domain uniqueness & Email Index Registration
|
|
108
114
|
// ----------------------------------------------------------------
|
|
109
115
|
const addr = getIbGibAddr({ ibGib: keystoneIbGib });
|
|
116
|
+
const primaryTjpAddr = addr;
|
|
117
|
+
if (logalot) { console.log(`${lc} primaryTjpAddr: ${primaryTjpAddr} (I: c09d68025348261ac8ccec8ebe59d626)`); }
|
|
110
118
|
const { tjpGib, punctiliarHash } = getGibInfo({ ibGibAddr: addr });
|
|
111
119
|
const domainGib = tjpGib || punctiliarHash;
|
|
112
120
|
if (!domainGib) {
|
|
@@ -120,31 +128,42 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
|
|
|
120
128
|
|
|
121
129
|
// Extract email addresses attached to primary identity keystone (if present)
|
|
122
130
|
const emails: string[] = keystoneIbGib.data?.emails ?? keystoneIbGib.data?.frameDetails?.emails ?? [];
|
|
123
|
-
const indexService = new IdentityIndexService({ baseDir: path.join(reqCtx.dataDir, 'index') });
|
|
124
|
-
const registeredHashes: string[] = [];
|
|
125
131
|
|
|
126
132
|
if (emails.length > 0) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
// Staging Quarantine: Save keystone & email records to email/pending/
|
|
134
|
+
console.log(`${lc} Staging genesis keystone with unverified email(s): ${emails.join(', ')} (I: c123456789abcdef0123456789abcdef)`);
|
|
135
|
+
const saveRes = await savePendingStagingKeystone({
|
|
136
|
+
keystone: keystoneIbGib,
|
|
137
|
+
emails,
|
|
138
|
+
primaryTjpAddr: addr,
|
|
139
|
+
dataDir: reqCtx.dataDir
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Immediately dispatch 6-digit verification code email for primary email
|
|
143
|
+
const primaryEmail = emails[0];
|
|
144
|
+
await dispatchVerificationCode({
|
|
145
|
+
email: primaryEmail,
|
|
146
|
+
primaryTjpAddr: addr,
|
|
147
|
+
pendingDir: saveRes.pendingDir,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (logalot) { console.timeLog(timestampUUID, `quarantine staging complete & code dispatched to ${primaryEmail}`); }
|
|
151
|
+
|
|
152
|
+
// EARLY RETURN 202 Accepted — do NOT bootstrap domain space or write to email/hashes/ until email is verified!
|
|
153
|
+
return this.ok({
|
|
154
|
+
success: true,
|
|
155
|
+
pending: true,
|
|
156
|
+
addr,
|
|
157
|
+
message: 'Genesis keystone quarantined in pending staging area. 6-digit verification code sent to your email.'
|
|
158
|
+
}, 202);
|
|
142
159
|
}
|
|
160
|
+
if (logalot) { console.timeLog(timestampUUID, 'emails complete') }
|
|
143
161
|
|
|
144
162
|
// ----------------------------------------------------------------
|
|
145
163
|
// 5. Bootstrap the new domain metaspace (creates folders)
|
|
146
164
|
// ----------------------------------------------------------------
|
|
147
165
|
const metaspace = await bootstrapDomainMetaspace(addr, reqCtx.dataDir);
|
|
166
|
+
if (logalot) { console.timeLog(timestampUUID, 'metaspace bootstrap complete') }
|
|
148
167
|
|
|
149
168
|
// ----------------------------------------------------------------
|
|
150
169
|
// 6. Persist the genesis keystone into the new domain space
|
|
@@ -158,6 +177,7 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
|
|
|
158
177
|
await metaspace.registerNewIbGib({ ibGib: keystoneIbGib, space });
|
|
159
178
|
|
|
160
179
|
console.log(`${lc} domain created and keystone persisted: ${addr}`);
|
|
180
|
+
if (logalot) { console.timeLog(timestampUUID, 'domain created complete') }
|
|
161
181
|
// if (logalot) { console.log(`${lc} keystoneIbGib: ${pretty(keystoneIbGib)} (I: d598c6ff7a48997d585b84c19c464826)`); }
|
|
162
182
|
return this.ok({ success: true, addr }, 201);
|
|
163
183
|
} catch (error) {
|
|
@@ -165,7 +185,10 @@ export class KeystoneGenesisHandler extends ServeGibHandlerBase<undefined, undef
|
|
|
165
185
|
console.error(`${lc} ${emsg}`);
|
|
166
186
|
return this.error(500, emsg);
|
|
167
187
|
} finally {
|
|
168
|
-
if (logalot) {
|
|
188
|
+
if (logalot) {
|
|
189
|
+
console.log(`${lc} complete.`);
|
|
190
|
+
console.timeEnd(timestampUUID);
|
|
191
|
+
}
|
|
169
192
|
}
|
|
170
193
|
}
|
|
171
194
|
}
|