@ibgib/node-gib 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/email/verify/email-verify-helpers.d.mts +6 -1
- package/dist/email/verify/email-verify-helpers.d.mts.map +1 -1
- package/dist/email/verify/email-verify-helpers.mjs +6 -2
- package/dist/email/verify/email-verify-helpers.mjs.map +1 -1
- package/dist/identity/sso/sso-custodian-service.d.mts +8 -0
- package/dist/identity/sso/sso-custodian-service.d.mts.map +1 -1
- package/dist/identity/sso/sso-custodian-service.mjs +126 -77
- package/dist/identity/sso/sso-custodian-service.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/email/email-verification-code.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/email/email-verification-code.handler.mjs +50 -4
- package/dist/serve-gib/handlers/api/email/email-verification-code.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-add-master-password.handler.d.mts +8 -5
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-add-master-password.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-add-master-password.handler.mjs +15 -11
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-add-master-password.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.mjs +5 -1
- package/dist/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.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 +6 -1
- package/dist/serve-gib/handlers/api/keystone/keystone-evolve.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-config.handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-config.handler.mjs +2 -11
- 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 +66 -26
- 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.map +1 -1
- package/dist/serve-gib/handlers/api/keystone/sso-login.handler.mjs +2 -10
- package/dist/serve-gib/handlers/api/keystone/sso-login.handler.mjs.map +1 -1
- package/dist/serve-gib/handlers/static-handler.d.mts.map +1 -1
- package/dist/serve-gib/handlers/static-handler.mjs +4 -0
- package/dist/serve-gib/handlers/static-handler.mjs.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-service.d.mts.map +1 -1
- package/dist/serve-gib/identity-index/identity-index-service.mjs +34 -19
- package/dist/serve-gib/identity-index/identity-index-service.mjs.map +1 -1
- package/package.json +2 -2
- package/src/email/verify/email-verify-helpers.mts +13 -2
- package/src/identity/sso/sso-custodian-service.mts +129 -84
- package/src/serve-gib/handlers/api/email/email-verification-code.handler.mts +52 -5
- package/src/serve-gib/handlers/api/identity/keystone-custodian-add-master-password.handler.mts +24 -17
- package/src/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.mts +6 -1
- package/src/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +6 -1
- package/src/serve-gib/handlers/api/keystone/sso-config.handler.mts +2 -12
- package/src/serve-gib/handlers/api/keystone/sso-link.handler.mts +61 -26
- package/src/serve-gib/handlers/api/keystone/sso-login.handler.mts +2 -11
- package/src/serve-gib/handlers/static-handler.mts +5 -0
- package/src/serve-gib/identity-index/identity-index-service.mts +28 -18
|
@@ -64,30 +64,45 @@ export class IdentityIndexService {
|
|
|
64
64
|
* Throws `duplicate_identity_409` error if email is already registered.
|
|
65
65
|
*/
|
|
66
66
|
async registerEmailIndex({ email, tjpAddr, primaryTjpAddr, }) {
|
|
67
|
-
const
|
|
68
|
-
if (!targetAddr) {
|
|
69
|
-
throw new Error('Either tjpAddr or primaryTjpAddr must be provided. (E: 62f15851b9a8c8d718279ab84e426826)');
|
|
70
|
-
}
|
|
71
|
-
const emailHash = await getIdentityEmailHash({ email, salt: this.salt });
|
|
72
|
-
const { folderPath, filePath } = getShardedIndexPath({
|
|
73
|
-
baseDir: this.baseDir,
|
|
74
|
-
emailHash
|
|
75
|
-
});
|
|
76
|
-
await fs.mkdir(folderPath, { recursive: true });
|
|
77
|
-
const record = {
|
|
78
|
-
tjpAddr: targetAddr,
|
|
79
|
-
createdAt: Date.now(),
|
|
80
|
-
};
|
|
67
|
+
const lc = `${this.lc}[${this.registerEmailIndex.name}]`;
|
|
81
68
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
if (logalot) {
|
|
70
|
+
console.log(`${lc} starting... (I: 5d1728a955657616a8cf6ce8b5afa226)`);
|
|
71
|
+
}
|
|
72
|
+
const targetAddr = tjpAddr || primaryTjpAddr;
|
|
73
|
+
if (!targetAddr) {
|
|
74
|
+
throw new Error('Either tjpAddr or primaryTjpAddr must be provided. (E: 62f15851b9a8c8d718279ab84e426826)');
|
|
75
|
+
}
|
|
76
|
+
const emailHash = await getIdentityEmailHash({ email, salt: this.salt });
|
|
77
|
+
const { folderPath, filePath } = getShardedIndexPath({
|
|
78
|
+
baseDir: this.baseDir,
|
|
79
|
+
emailHash
|
|
80
|
+
});
|
|
81
|
+
await fs.mkdir(folderPath, { recursive: true });
|
|
82
|
+
const record = {
|
|
83
|
+
tjpAddr: targetAddr,
|
|
84
|
+
createdAt: Date.now(),
|
|
85
|
+
};
|
|
86
|
+
try {
|
|
87
|
+
await fs.writeFile(filePath, JSON.stringify(record, null, 2), { flag: 'wx' });
|
|
88
|
+
return { emailHash, filePath, record };
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error.code === 'EEXIST') {
|
|
92
|
+
throw new Error(`Email is already registered (E: duplicate_identity_409)`);
|
|
93
|
+
}
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
84
96
|
}
|
|
85
97
|
catch (error) {
|
|
86
|
-
|
|
87
|
-
throw new Error(`Email is already registered (E: duplicate_identity_409)`);
|
|
88
|
-
}
|
|
98
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
89
99
|
throw error;
|
|
90
100
|
}
|
|
101
|
+
finally {
|
|
102
|
+
if (logalot) {
|
|
103
|
+
console.log(`${lc} complete.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
91
106
|
}
|
|
92
107
|
/**
|
|
93
108
|
* Retrieves the registered identity info for an email address.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-index-service.mjs","sourceRoot":"","sources":["../../../src/serve-gib/identity-index/identity-index-service.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,iDAAiD,CAAC;AAG1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AAC9G,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGzF,MAAM,OAAO,GAAG,gBAAgB,IAAI,IAAI,CAAC;AAEzC;;GAEG;AACH,MAAM,OAAO,oBAAoB;IACrB,EAAE,GAAG,IAAI,oBAAoB,CAAC,IAAI,GAAG,CAAC;IACtC,OAAO,CAAS;IAChB,IAAI,CAAS;IAErB,YAAY,OAAqC;QAC7C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;QACjD,MAAM,YAAY,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,CAAC;QAC/D,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,+BAA+B,CAAC,CAAC;QAC1H,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,2BAA2B,CAAC;IACvF,CAAC;IAED,MAAM;IACN,+CAA+C;IAC/C,kFAAkF;IAClF,MAAM;IACN,0CAA0C;IAC1C,qBAAqB;IACrB,iCAAiC;IACjC,wBAAwB;IACxB,wBAAwB;IACxB,qBAAqB;IACrB,0CAA0C;IAC1C,4DAA4D;IAC5D,6BAA6B;IAC7B,8CAA8C;IAC9C,UAAU;IACV,IAAI;IAEJ,MAAM;IACN,kEAAkE;IAClE,qFAAqF;IACrF,MAAM;IACN,6CAA6C;IAC7C,qBAAqB;IACrB,wBAAwB;IACxB,wBAAwB;IACxB,qBAAqB;IACrB,kGAAkG;IAClG,qFAAqF;IACrF,IAAI;IAEJ,MAAM;IACN,iDAAiD;IACjD,oFAAoF;IACpF,MAAM;IACN,4CAA4C;IAC5C,qBAAqB;IACrB,wBAAwB;IACxB,wBAAwB;IACxB,qBAAqB;IACrB,yBAAyB;IACzB,oFAAoF;IACpF,IAAI;IAEJ;;;;OAIG;IACH,KAAK,CAAC,kBAAkB,CAAC,EACrB,KAAK,EACL,OAAO,EACP,cAAc,GAKjB;QACG,MAAM,UAAU,GAAG,OAAO,IAAI,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"identity-index-service.mjs","sourceRoot":"","sources":["../../../src/serve-gib/identity-index/identity-index-service.mts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibgib/node-gib",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"description": "Node and server-specific ibGib code, i.e., things that don't run in the browser.",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@ibgib/helper-gib": "^0.0.37",
|
|
28
28
|
"@ibgib/ts-gib": "^0.5.34",
|
|
29
|
-
"@ibgib/core-gib": "^0.1.
|
|
29
|
+
"@ibgib/core-gib": "^0.1.77",
|
|
30
30
|
"@ibgib/encrypt-gib": "^0.3.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
@@ -236,13 +236,18 @@ export interface SavePendingCodeRecordOptions {
|
|
|
236
236
|
code: string;
|
|
237
237
|
maxAttempts?: number;
|
|
238
238
|
ttlMs?: number;
|
|
239
|
+
resendCount?: number;
|
|
240
|
+
attempts?: number;
|
|
239
241
|
}
|
|
240
242
|
|
|
241
243
|
export interface PendingCodeRecord {
|
|
242
244
|
codeHash: string;
|
|
245
|
+
rawCode?: string;
|
|
243
246
|
attempts: number;
|
|
244
247
|
maxAttempts: number;
|
|
245
248
|
expiresAt: number;
|
|
249
|
+
dispatchedAt: number;
|
|
250
|
+
resendCount: number;
|
|
246
251
|
}
|
|
247
252
|
|
|
248
253
|
/**
|
|
@@ -253,16 +258,22 @@ export async function savePendingCodeRecord({
|
|
|
253
258
|
code,
|
|
254
259
|
maxAttempts = 5,
|
|
255
260
|
ttlMs = DEFAULT_MAGIC_LINK_TTL_MS,
|
|
256
|
-
|
|
261
|
+
resendCount = 0,
|
|
262
|
+
attempts = 0,
|
|
263
|
+
}: SavePendingCodeRecordOptions): Promise<PendingCodeRecord> {
|
|
257
264
|
const codeHash = await hash({ s: `verificationcode${code}` });
|
|
258
265
|
const record: PendingCodeRecord = {
|
|
259
266
|
codeHash,
|
|
260
|
-
|
|
267
|
+
rawCode: code,
|
|
268
|
+
attempts,
|
|
261
269
|
maxAttempts,
|
|
262
270
|
expiresAt: Date.now() + ttlMs,
|
|
271
|
+
dispatchedAt: Date.now(),
|
|
272
|
+
resendCount,
|
|
263
273
|
};
|
|
264
274
|
const codeFilePath = path.join(pendingDir, 'code.json');
|
|
265
275
|
await fs.writeFile(codeFilePath, JSON.stringify(record, null, 2), 'utf-8');
|
|
276
|
+
return record;
|
|
266
277
|
}
|
|
267
278
|
|
|
268
279
|
/**
|
|
@@ -10,11 +10,15 @@ import { KeystoneStrategyFactory } from '@ibgib/core-gib/dist/keystone/strategy/
|
|
|
10
10
|
import { MetaspaceService } from '@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs';
|
|
11
11
|
import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
|
|
12
12
|
|
|
13
|
+
import { GLOBAL_LOG_A_LOT } from '../../constants.mjs';
|
|
14
|
+
import { loadSsoServerConfig } from './sso-config-helper.mjs';
|
|
13
15
|
import {
|
|
14
16
|
SsoServerConfig, SsoProviderId, OAuthUserInfo, SsoProviderServerConfig,
|
|
15
17
|
SsoProviderClientConfig
|
|
16
18
|
} from './sso-types.mjs';
|
|
17
19
|
|
|
20
|
+
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
21
|
+
|
|
18
22
|
interface JwkKey {
|
|
19
23
|
kty: string;
|
|
20
24
|
alg?: string;
|
|
@@ -62,33 +66,42 @@ export class SsoCustodianService {
|
|
|
62
66
|
* - Generator: Client/Server (Derived from environmental configuration and sent by client).
|
|
63
67
|
*/
|
|
64
68
|
async getOAuthUserInfo(providerId: SsoProviderId, code: string, redirectUri: string): Promise<OAuthUserInfo> {
|
|
65
|
-
const lc =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
throw new Error(`Provider '${providerId}' is not configured on this server. (E: c28900abfefd23e89cf23f12)`);
|
|
69
|
-
}
|
|
69
|
+
const lc = `[${this.getOAuthUserInfo.name}]`;
|
|
70
|
+
try {
|
|
71
|
+
if (logalot) { console.log(`${lc} starting... (I: 3ad578b5065ec6d5517469571a4da826)`); }
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
const providerConfig = this.config.providers[providerId];
|
|
74
|
+
if (!providerConfig) {
|
|
75
|
+
throw new Error(`Provider '${providerId}' is not configured on this server. (E: c28900abfefd23e89cf23f12)`);
|
|
76
|
+
}
|
|
72
77
|
|
|
73
|
-
|
|
74
|
-
const tokens = await this.exchangeCodeForTokens(providerConfig, code, redirectUri);
|
|
78
|
+
console.log(`${lc} Exchanging code for provider: ${providerId}`);
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
// 1. Exchange authorization code for tokens
|
|
81
|
+
const tokens = await this.exchangeCodeForTokens(providerConfig, code, redirectUri);
|
|
82
|
+
|
|
83
|
+
// 2. Retrieve and normalize user info
|
|
84
|
+
if (providerId === 'google') {
|
|
85
|
+
// Google returns an id_token (JWT) directly containing user info
|
|
86
|
+
if (!tokens.id_token) {
|
|
87
|
+
throw new Error(`Google token exchange did not return id_token. (E: e28900abfefd23e89cf45f23)`);
|
|
88
|
+
}
|
|
89
|
+
return this.verifyAndNormalizeGoogleToken(tokens.id_token);
|
|
90
|
+
} else if (providerId === 'github') {
|
|
91
|
+
// GitHub requires calling the /user API using the access_token
|
|
92
|
+
if (!tokens.access_token) {
|
|
93
|
+
throw new Error(`GitHub token exchange did not return access_token. (E: a28900abfefd23e89cf56f34)`);
|
|
94
|
+
}
|
|
95
|
+
return this.fetchAndNormalizeGithubUser(providerConfig, tokens.access_token);
|
|
87
96
|
}
|
|
88
|
-
return this.fetchAndNormalizeGithubUser(providerConfig, tokens.access_token);
|
|
89
|
-
}
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
throw new Error(`Unsupported provider: ${providerId}. (E: d28900abfefd23e89cf67f45)`);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
101
|
+
throw error;
|
|
102
|
+
} finally {
|
|
103
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
104
|
+
}
|
|
92
105
|
}
|
|
93
106
|
|
|
94
107
|
/**
|
|
@@ -413,76 +426,87 @@ export class SsoCustodianService {
|
|
|
413
426
|
metaspace: MetaspaceService;
|
|
414
427
|
space: IbGibSpaceAny;
|
|
415
428
|
}): Promise<KeystoneChallengePool> {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
429
|
+
const lc = `[${this.createCustodianChallengePool.name}]`;
|
|
430
|
+
try {
|
|
431
|
+
if (logalot) { console.log(`${lc} starting... (I: 4238580990ff19dd2815d5186ffa0826)`); }
|
|
432
|
+
|
|
433
|
+
// 1. Fetch target keystone
|
|
434
|
+
const keystoneService = new KeystoneService_V1();
|
|
435
|
+
const targetKeystone = await keystoneService.getLatestKeystone({
|
|
436
|
+
addr: keystoneAddr,
|
|
437
|
+
metaspace,
|
|
438
|
+
space
|
|
439
|
+
});
|
|
423
440
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
441
|
+
if (!targetKeystone) {
|
|
442
|
+
throw new Error(`Keystone not found for address: ${keystoneAddr} (E: 8a9c2b1d3e5f6a7b8c9d0e1f2a3b4c5d)`);
|
|
443
|
+
}
|
|
427
444
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
445
|
+
// 2. Locate native manage pool
|
|
446
|
+
const userManagePool = targetKeystone.data?.challengePools.find(p => p.id === POOL_ID_MANAGE);
|
|
447
|
+
if (!userManagePool) {
|
|
448
|
+
throw new Error(`Keystone manage pool not found. Custodian manage pool must match the user manage pool's security config. (E: 7c4e5f6a7b8c9d0e1f2a3b4c5e6f7a8b)`);
|
|
449
|
+
}
|
|
433
450
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
451
|
+
// 3. Dynamic poolId based on providerId with regex validation
|
|
452
|
+
if (!providerId || !KEYSTONE_POOL_ID_REGEXP.test(providerId)) {
|
|
453
|
+
throw new Error(`Invalid providerId: "${providerId}". Must match ${KEYSTONE_POOL_ID_REGEXP} (E: 3a2c4e5f6a7b8c9d0e1f2a3b4c5e6f)`);
|
|
454
|
+
}
|
|
455
|
+
const poolId = `custodian-manage-${providerId}`;
|
|
439
456
|
|
|
440
|
-
|
|
441
|
-
|
|
457
|
+
// 4. Derive delegate secrets
|
|
458
|
+
const custodianSecret = await this.deriveServerDelegateSecret(providerKey, userNonce);
|
|
442
459
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
460
|
+
const poolSalt = await hash({
|
|
461
|
+
s: `${providerKey}:${userNonce}:salt`,
|
|
462
|
+
algorithm: HashAlgorithm.sha_256
|
|
463
|
+
});
|
|
464
|
+
const poolSaltShort = poolSalt.substring(0, 16);
|
|
465
|
+
|
|
466
|
+
// 5. Clone user's manage pool config, updating only ID, salt, and allowedVerbs
|
|
467
|
+
const config: KeystonePoolConfig = {
|
|
468
|
+
...userManagePool.config,
|
|
469
|
+
id: poolId,
|
|
470
|
+
salt: poolSaltShort,
|
|
471
|
+
allowedVerbs: [KEYSTONE_VERB_MANAGE, KEYSTONE_VERB_REVOKE]
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const strategy = KeystoneStrategyFactory.create({ config });
|
|
475
|
+
const poolSecret = await strategy.derivePoolSecret({ masterSecret: custodianSecret });
|
|
476
|
+
const challenges: { [id: string]: any } = {};
|
|
477
|
+
const timestamp = Date.now().toString();
|
|
478
|
+
|
|
479
|
+
for (let i = 0; i < config.behavior.size; i++) {
|
|
480
|
+
const challengeId = await generateOpaqueChallengeId({
|
|
481
|
+
salt: config.salt,
|
|
482
|
+
timestamp,
|
|
483
|
+
index: i
|
|
484
|
+
});
|
|
485
|
+
const solution = await strategy.generateSolution({
|
|
486
|
+
poolSecret,
|
|
487
|
+
poolId: config.id,
|
|
488
|
+
challengeId
|
|
489
|
+
});
|
|
490
|
+
challenges[challengeId] = await strategy.generateChallenge({ solution });
|
|
491
|
+
}
|
|
456
492
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
493
|
+
return {
|
|
494
|
+
id: poolId,
|
|
495
|
+
config,
|
|
496
|
+
challenges,
|
|
497
|
+
isForeign: true,
|
|
498
|
+
metadata: {
|
|
499
|
+
owner: 'custodian',
|
|
500
|
+
providerKey
|
|
501
|
+
}
|
|
502
|
+
};
|
|
461
503
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
});
|
|
468
|
-
const solution = await strategy.generateSolution({
|
|
469
|
-
poolSecret,
|
|
470
|
-
poolId: config.id,
|
|
471
|
-
challengeId
|
|
472
|
-
});
|
|
473
|
-
challenges[challengeId] = await strategy.generateChallenge({ solution });
|
|
504
|
+
} catch (error) {
|
|
505
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
506
|
+
throw error;
|
|
507
|
+
} finally {
|
|
508
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
474
509
|
}
|
|
475
|
-
|
|
476
|
-
return {
|
|
477
|
-
id: poolId,
|
|
478
|
-
config,
|
|
479
|
-
challenges,
|
|
480
|
-
isForeign: true,
|
|
481
|
-
metadata: {
|
|
482
|
-
owner: 'custodian',
|
|
483
|
-
providerKey
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
510
|
}
|
|
487
511
|
|
|
488
512
|
/**
|
|
@@ -564,3 +588,24 @@ export class SsoCustodianService {
|
|
|
564
588
|
}
|
|
565
589
|
}
|
|
566
590
|
}
|
|
591
|
+
|
|
592
|
+
let ssoCustodianService: SsoCustodianService | undefined;
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Gets or initializes the singleton SsoCustodianService instance.
|
|
596
|
+
*/
|
|
597
|
+
export function getSsoCustodianService(): SsoCustodianService {
|
|
598
|
+
if (!ssoCustodianService) {
|
|
599
|
+
const config = loadSsoServerConfig();
|
|
600
|
+
ssoCustodianService = new SsoCustodianService(config);
|
|
601
|
+
}
|
|
602
|
+
return ssoCustodianService;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Resets the singleton SsoCustodianService instance (useful for test resets).
|
|
607
|
+
*/
|
|
608
|
+
export function resetSsoCustodianService(): void {
|
|
609
|
+
ssoCustodianService = undefined;
|
|
610
|
+
}
|
|
611
|
+
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
* Handler for POST /api/email/verification-code
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import * as fs from 'node:fs/promises';
|
|
9
|
+
import { existsSync } from 'node:fs';
|
|
10
|
+
import { extractErrorMsg, getUUID, delay } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
8
11
|
import { EmailSenderAws } from '../../../../email/aws/email-sender-aws.mjs';
|
|
9
12
|
// import { generateVerificationCode, getPendingTjpHash, savePendingCodeRecord, getPendingStagingDir, validateEmail } from '../../../../email/index.mjs';
|
|
10
13
|
import { EmailSender, OutboundEmail } from '../../../../email/email-types.mjs';
|
|
@@ -13,7 +16,7 @@ import { API_PATH_REGEXES } from '../../../path-constants.mjs';
|
|
|
13
16
|
import { RequestContext, ResponseResult, ServeGibHttpMethod } from '../../../types.mjs';
|
|
14
17
|
import { ServeGibHandlerBase } from '../../handler-base.mjs';
|
|
15
18
|
import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
|
|
16
|
-
import { createDefaultEmailSender, generateVerificationCode, getPendingStagingDir, getPendingTjpHash, savePendingCodeRecord, savePendingStagingKeystone } from '../../../../email/verify/email-verify-helpers.mjs';
|
|
19
|
+
import { createDefaultEmailSender, generateVerificationCode, getPendingStagingDir, getPendingTjpHash, savePendingCodeRecord, savePendingStagingKeystone, PendingCodeRecord } from '../../../../email/verify/email-verify-helpers.mjs';
|
|
17
20
|
import { validateEmail } from '../../../../email/email-helpers.mjs';
|
|
18
21
|
import { normalizeEmail } from '../../../identity-index/identity-index-helpers.mjs';
|
|
19
22
|
|
|
@@ -75,11 +78,14 @@ export class EmailVerificationCodeHandler extends ServeGibHandlerBase {
|
|
|
75
78
|
return this.error(400, 'Invalid email address format (E: e3f4a5b67890123456789abcdef012)');
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
// Artificial delay to mitigate brute force & timing attacks (min 1s)
|
|
82
|
+
await delay(1000 + Math.random() * 500);
|
|
83
|
+
|
|
78
84
|
const normEmail = normalizeEmail(email);
|
|
79
85
|
const effectivePrimaryTjpAddr = primaryTjpAddr || `pending:${normEmail}`;
|
|
80
86
|
const tjpHash = await getPendingTjpHash(effectivePrimaryTjpAddr);
|
|
81
87
|
|
|
82
|
-
|
|
88
|
+
let code: string = generateVerificationCode();
|
|
83
89
|
if (reqCtx.dataDir && tjpHash) {
|
|
84
90
|
let info = await getPendingStagingDir({ dataDir: reqCtx.dataDir, tjpHash });
|
|
85
91
|
if (!info) {
|
|
@@ -93,8 +99,49 @@ export class EmailVerificationCodeHandler extends ServeGibHandlerBase {
|
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
if (info) {
|
|
96
|
-
|
|
97
|
-
|
|
102
|
+
const codeFilePath = path.join(info.pendingDir, 'code.json');
|
|
103
|
+
let existingRecord: PendingCodeRecord | undefined;
|
|
104
|
+
if (existsSync(codeFilePath)) {
|
|
105
|
+
try {
|
|
106
|
+
existingRecord = JSON.parse(await fs.readFile(codeFilePath, 'utf-8'));
|
|
107
|
+
} catch { /* ignore corrupted record */ }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
if (existingRecord) {
|
|
112
|
+
// Check 30-second cooldown
|
|
113
|
+
const elapsedMs = now - (existingRecord.dispatchedAt || 0);
|
|
114
|
+
if (elapsedMs < 30_000) {
|
|
115
|
+
const remainingSecs = Math.ceil((30_000 - elapsedMs) / 1000);
|
|
116
|
+
return this.error(429, `Please wait ${remainingSecs}s before requesting another verification code.`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check Max Resend limit (5 resends per 15-minute window)
|
|
120
|
+
if (existingRecord.resendCount >= 5 && now < existingRecord.expiresAt) {
|
|
121
|
+
return this.error(429, 'Too many verification code requests. Please wait 15 minutes before trying again.');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Reuse existing valid code if not expired and attempts < maxAttempts
|
|
125
|
+
if (existingRecord.rawCode && now < existingRecord.expiresAt && existingRecord.attempts < existingRecord.maxAttempts) {
|
|
126
|
+
code = existingRecord.rawCode;
|
|
127
|
+
existingRecord.dispatchedAt = now;
|
|
128
|
+
existingRecord.resendCount = (existingRecord.resendCount || 0) + 1;
|
|
129
|
+
await fs.writeFile(codeFilePath, JSON.stringify(existingRecord, null, 2), 'utf-8');
|
|
130
|
+
} else {
|
|
131
|
+
// Generate fresh code and increment resendCount
|
|
132
|
+
code = generateVerificationCode();
|
|
133
|
+
await savePendingCodeRecord({
|
|
134
|
+
pendingDir: info.pendingDir,
|
|
135
|
+
code,
|
|
136
|
+
resendCount: (existingRecord.resendCount || 0) + 1,
|
|
137
|
+
attempts: 0,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
code = generateVerificationCode();
|
|
142
|
+
await savePendingCodeRecord({ pendingDir: info.pendingDir, code, resendCount: 0, attempts: 0 });
|
|
143
|
+
}
|
|
144
|
+
if (logalot) { console.timeLog(timestampUUID, 'code record processed in pending staging'); }
|
|
98
145
|
} else {
|
|
99
146
|
console.warn(`${lc} Failed to create or access pending staging directory for tjpHash ${tjpHash}`);
|
|
100
147
|
}
|
package/src/serve-gib/handlers/api/identity/keystone-custodian-add-master-password.handler.mts
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { extractErrorMsg, hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
14
14
|
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
15
15
|
import { getTjpAddr } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
|
|
16
|
+
import { getDependencyGraph } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
|
|
17
|
+
import { FlatIbGibGraph } from '@ibgib/core-gib/dist/common/other/graph-types.mjs';
|
|
16
18
|
import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
|
|
17
19
|
import { KeystoneChallengePool } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
|
|
18
20
|
import { KEYSTONE_VERB_MANAGE, POOL_ID_MANAGE } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
|
|
@@ -28,35 +30,28 @@ import { bootstrapDomainMetaspace } from '../../../bootstrap-helper.mjs';
|
|
|
28
30
|
import { getIdentityIndexService } from '../../../identity-index/identity-index-service.mjs';
|
|
29
31
|
import { normalizeEmail } from '../../../identity-index/identity-index-helpers.mjs';
|
|
30
32
|
import { loadSsoServerConfig } from '../../../../identity/sso/sso-config-helper.mjs';
|
|
31
|
-
import {
|
|
33
|
+
import { getSsoCustodianService } from '../../../../identity/sso/sso-custodian-service.mjs';
|
|
32
34
|
import { SsoProviderId } from '../../../../identity/sso/sso-types.mjs';
|
|
33
35
|
import { getPendingStagingDir, getPendingTjpHash, verifyPendingCode } from '../../../../email/verify/email-verify-helpers.mjs';
|
|
34
36
|
|
|
35
37
|
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
36
38
|
|
|
37
|
-
let custodian: SsoCustodianService | undefined;
|
|
38
|
-
function getCustodian(): SsoCustodianService {
|
|
39
|
-
if (!custodian) {
|
|
40
|
-
const config = loadSsoServerConfig();
|
|
41
|
-
custodian = new SsoCustodianService(config);
|
|
42
|
-
}
|
|
43
|
-
return custodian;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
39
|
export interface CustodianAddMasterPasswordRequestBody {
|
|
47
|
-
|
|
48
|
-
newManagePool: KeystoneChallengePool;
|
|
40
|
+
code: string;
|
|
49
41
|
providerId?: SsoProviderId;
|
|
50
|
-
code?: string;
|
|
51
42
|
redirectUri?: string;
|
|
52
43
|
email?: string;
|
|
44
|
+
primaryTjpAddr: string;
|
|
45
|
+
newManagePool: KeystoneChallengePool;
|
|
53
46
|
}
|
|
54
47
|
|
|
55
48
|
export interface CustodianAddMasterPasswordResponseBody {
|
|
56
49
|
success: boolean;
|
|
57
|
-
primaryTjpAddr
|
|
58
|
-
primaryKeystone
|
|
50
|
+
primaryTjpAddr?: string;
|
|
51
|
+
primaryKeystone?: any;
|
|
52
|
+
primaryGraph?: FlatIbGibGraph;
|
|
59
53
|
message?: string;
|
|
54
|
+
error?: string;
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
/**
|
|
@@ -108,7 +103,7 @@ export class KeystoneCustodianAddMasterPasswordHandler extends ServeGibHandlerBa
|
|
|
108
103
|
let effectiveProvider: string = providerId || 'email';
|
|
109
104
|
|
|
110
105
|
if (providerId && code && redirectUri) {
|
|
111
|
-
const service =
|
|
106
|
+
const service = getSsoCustodianService();
|
|
112
107
|
const userInfo = await service.getOAuthUserInfo(providerId, code, redirectUri);
|
|
113
108
|
if (!userInfo || !userInfo.email) {
|
|
114
109
|
return this.error(401, `Failed to authenticate with SSO provider ${providerId} (E: 8a1b2c3d4e5f67890a1b2c3d4e5f6796)`);
|
|
@@ -121,7 +116,11 @@ export class KeystoneCustodianAddMasterPasswordHandler extends ServeGibHandlerBa
|
|
|
121
116
|
verifiedEmail = normalizeEmail(email);
|
|
122
117
|
|
|
123
118
|
const tjpHash = await getPendingTjpHash(primaryTjpAddr);
|
|
124
|
-
|
|
119
|
+
let pendingInfo = reqCtx.dataDir && tjpHash ? await getPendingStagingDir({ dataDir: reqCtx.dataDir, tjpHash }) : undefined;
|
|
120
|
+
if (!pendingInfo) {
|
|
121
|
+
const emailTjpHash = await getPendingTjpHash(`pending:${verifiedEmail}`);
|
|
122
|
+
pendingInfo = reqCtx.dataDir && emailTjpHash ? await getPendingStagingDir({ dataDir: reqCtx.dataDir, tjpHash: emailTjpHash }) : undefined;
|
|
123
|
+
}
|
|
125
124
|
|
|
126
125
|
if (!pendingInfo || pendingInfo.isExpired) {
|
|
127
126
|
return this.error(400, 'Verification record missing or expired. Please request a new verification code. (E: 8a1b2c3d4e5f67890a1b2c3d4e5f6798)');
|
|
@@ -228,10 +227,18 @@ export class KeystoneCustodianAddMasterPasswordHandler extends ServeGibHandlerBa
|
|
|
228
227
|
await metaspace.put({ ibGibs: [evolvedKeystone], space });
|
|
229
228
|
await metaspace.registerNewIbGib({ ibGib: evolvedKeystone, space });
|
|
230
229
|
|
|
230
|
+
// Extract complete primary keystone dependency graph across all frames
|
|
231
|
+
const primaryGraph = await getDependencyGraph({
|
|
232
|
+
ibGib: evolvedKeystone,
|
|
233
|
+
space,
|
|
234
|
+
live: false
|
|
235
|
+
});
|
|
236
|
+
|
|
231
237
|
const response: CustodianAddMasterPasswordResponseBody = {
|
|
232
238
|
success: true,
|
|
233
239
|
primaryTjpAddr,
|
|
234
240
|
primaryKeystone: evolvedKeystone,
|
|
241
|
+
primaryGraph,
|
|
235
242
|
message: 'Successfully elevated identity to sovereign master password'
|
|
236
243
|
};
|
|
237
244
|
|
package/src/serve-gib/handlers/api/identity/keystone-custodian-register-delegate.handler.mts
CHANGED
|
@@ -162,15 +162,20 @@ export class KeystoneCustodianRegisterDelegateHandler extends ServeGibHandlerBas
|
|
|
162
162
|
|
|
163
163
|
const primarySecret = await hash({ s: `${serverSecret}_custodian_${primaryEmail}` });
|
|
164
164
|
|
|
165
|
+
const delegateDeviceName = delegateKeystone.data?.frameDetails?.deviceTag
|
|
166
|
+
|| frameDetails?.deviceTag
|
|
167
|
+
|| 'client-delegate';
|
|
168
|
+
|
|
165
169
|
// Execute primary keystone evolution linking the new delegate
|
|
166
170
|
const evolvedPrimaryKeystone = await keystoneService.registerDelegate({
|
|
167
171
|
parentKeystone,
|
|
168
172
|
delegateKeystone,
|
|
169
173
|
masterSecret: primarySecret,
|
|
174
|
+
signingPoolId: 'manage',
|
|
170
175
|
metaspace,
|
|
171
176
|
space,
|
|
172
177
|
allowedVerbs: custodianReqs.allowedVerbs || [KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT],
|
|
173
|
-
deviceName:
|
|
178
|
+
deviceName: delegateDeviceName
|
|
174
179
|
});
|
|
175
180
|
|
|
176
181
|
// Persist delegate keystone in domain space
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
14
14
|
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
15
|
+
import { getGibInfo } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
|
|
15
16
|
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
16
17
|
import { validateAndRegisterEvolveKeystone } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs';
|
|
17
18
|
import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
|
|
@@ -56,7 +57,11 @@ export class KeystoneEvolveHandler extends ServeGibHandlerWithMetaspaceBase<Evol
|
|
|
56
57
|
if (match && match.length >= 3) {
|
|
57
58
|
const domainIb = decodeURIComponent(match[1]);
|
|
58
59
|
const domainGib = decodeURIComponent(match[2]);
|
|
59
|
-
|
|
60
|
+
let domainAddr = getIbGibAddr({ ib: domainIb, gib: domainGib });
|
|
61
|
+
const { tjpGib } = getGibInfo({ ibGibAddr: domainAddr });
|
|
62
|
+
if (tjpGib && domainIb) {
|
|
63
|
+
domainAddr = `${domainIb}^${tjpGib}`;
|
|
64
|
+
}
|
|
60
65
|
return {
|
|
61
66
|
domainAddr,
|
|
62
67
|
domainInfo: this.getDomainInfo({ domainAddr })
|