@gugananuvem/aws-local-simulator 1.0.10 → 1.0.12

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.
Files changed (44) hide show
  1. package/README.md +257 -193
  2. package/bin/aws-local-simulator.js +62 -62
  3. package/package.json +2 -2
  4. package/src/config/config-loader.js +114 -112
  5. package/src/config/default-config.js +67 -65
  6. package/src/config/env-loader.js +68 -68
  7. package/src/index.js +130 -130
  8. package/src/index.mjs +123 -123
  9. package/src/server.js +223 -222
  10. package/src/services/apigateway/index.js +68 -66
  11. package/src/services/apigateway/server.js +487 -434
  12. package/src/services/apigateway/simulator.js +1251 -1251
  13. package/src/services/cognito/index.js +65 -65
  14. package/src/services/cognito/server.js +279 -228
  15. package/src/services/cognito/simulator.js +1114 -847
  16. package/src/services/dynamodb/index.js +70 -70
  17. package/src/services/dynamodb/server.js +121 -121
  18. package/src/services/dynamodb/simulator.js +620 -614
  19. package/src/services/ecs/index.js +65 -65
  20. package/src/services/ecs/server.js +233 -233
  21. package/src/services/ecs/simulator.js +844 -844
  22. package/src/services/eventbridge/index.js +84 -84
  23. package/src/services/index.js +18 -18
  24. package/src/services/lambda/handler-loader.js +183 -172
  25. package/src/services/lambda/index.js +73 -72
  26. package/src/services/lambda/route-registry.js +274 -274
  27. package/src/services/lambda/server.js +145 -152
  28. package/src/services/lambda/simulator.js +172 -285
  29. package/src/services/s3/index.js +69 -69
  30. package/src/services/s3/server.js +238 -238
  31. package/src/services/s3/simulator.js +740 -740
  32. package/src/services/sns/index.js +75 -75
  33. package/src/services/sqs/index.js +95 -95
  34. package/src/services/sqs/server.js +345 -273
  35. package/src/services/sqs/simulator.js +441 -660
  36. package/src/services/sts/index.js +37 -0
  37. package/src/services/sts/server.js +142 -0
  38. package/src/services/sts/simulator.js +69 -0
  39. package/src/template/aws-config-template.js +87 -87
  40. package/src/template/aws-config-template.mjs +90 -90
  41. package/src/template/config-template.json +203 -203
  42. package/src/utils/aws-config.js +91 -91
  43. package/src/utils/local-store.js +67 -67
  44. package/src/utils/logger.js +59 -59
@@ -1,848 +1,1115 @@
1
- /**
2
- * Cognito Simulator Core
3
- * Simula User Pools, Identity Pools, Autenticação, Tokens JWT
4
- */
5
-
6
- const crypto = require('crypto');
7
- const jwt = require('jsonwebtoken');
8
- const { v4: uuidv4 } = require('uuid');
9
- const logger = require('../../utils/logger');
10
- const LocalStore = require('../../utils/local-store');
11
- const path = require('path');
12
-
13
- class CognitoSimulator {
14
- constructor(config) {
15
- this.config = config;
16
- this.dataDir = path.join(process.env.AWS_LOCAL_SIMULATOR_DATA_DIR, 'cognito');
17
- this.store = new LocalStore(this.dataDir);
18
- this.userPools = new Map();
19
- this.identityPools = new Map();
20
- this.users = new Map();
21
- this.sessions = new Map();
22
- this.refreshTokens = new Map();
23
- this.accessTokens = new Map();
24
- this.jwtSecret = crypto.randomBytes(64).toString('hex');
25
- }
26
-
27
- async initialize() {
28
- logger.debug('Inicializando Cognito Simulator...');
29
- this.loadUserPools();
30
- this.loadIdentityPools();
31
- this.loadUsers();
32
- this.loadSessions();
33
-
34
- logger.debug(`✅ Cognito Simulator inicializado com ${this.userPools.size} user pools, ${this.identityPools.size} identity pools, ${this.users.size} usuários`);
35
- }
36
-
37
- // ============ User Pool Operations ============
38
-
39
- createUserPool(params) {
40
- const { PoolName, Policies, LambdaConfig, AutoVerifiedAttributes, AliasAttributes, UsernameAttributes, MfaConfiguration } = params;
41
-
42
- const poolId = `local_${PoolName}_${Date.now()}`;
43
- const userPool = {
44
- Id: poolId,
45
- Name: PoolName,
46
- Arn: `arn:aws:cognito:local:000000000000:userpool/${poolId}`,
47
- Status: 'ACTIVE',
48
- CreationDate: new Date().toISOString(),
49
- LastModifiedDate: new Date().toISOString(),
50
- Policies: Policies || {
51
- PasswordPolicy: {
52
- MinimumLength: 8,
53
- RequireUppercase: true,
54
- RequireLowercase: true,
55
- RequireNumbers: true,
56
- RequireSymbols: false
57
- }
58
- },
59
- LambdaConfig: LambdaConfig || {},
60
- AutoVerifiedAttributes: AutoVerifiedAttributes || ['email'],
61
- AliasAttributes: AliasAttributes || [],
62
- UsernameAttributes: UsernameAttributes || ['email'],
63
- MfaConfiguration: MfaConfiguration || 'OFF',
64
- EstimatedNumberOfUsers: 0,
65
- Users: [],
66
- Clients: new Map(),
67
- Groups: new Map(),
68
- IdentityProviders: new Map(),
69
- ResourceServers: new Map()
70
- };
71
-
72
- this.userPools.set(poolId, userPool);
73
- this.persistUserPools();
74
-
75
- logger.debug(`✅ User Pool criado: ${PoolName} (${poolId})`);
76
-
77
- return {
78
- UserPool: {
79
- Id: userPool.Id,
80
- Name: userPool.Name,
81
- Arn: userPool.Arn,
82
- Status: userPool.Status,
83
- CreationDate: userPool.CreationDate,
84
- LastModifiedDate: userPool.LastModifiedDate,
85
- MfaConfiguration: userPool.MfaConfiguration,
86
- EstimatedNumberOfUsers: 0
87
- }
88
- };
89
- }
90
-
91
- listUserPools(params = {}) {
92
- const { MaxResults = 60, NextToken } = params;
93
- let userPools = Array.from(this.userPools.values());
94
-
95
- if (NextToken) {
96
- const startIndex = parseInt(NextToken);
97
- userPools = userPools.slice(startIndex);
98
- }
99
-
100
- const results = userPools.slice(0, MaxResults);
101
- const nextToken = results.length === MaxResults ? String(MaxResults) : null;
102
-
103
- return {
104
- UserPools: results.map(pool => ({
105
- Id: pool.Id,
106
- Name: pool.Name,
107
- Arn: pool.Arn,
108
- Status: pool.Status,
109
- CreationDate: pool.CreationDate,
110
- LastModifiedDate: pool.LastModifiedDate
111
- })),
112
- NextToken: nextToken
113
- };
114
- }
115
-
116
- describeUserPool(params) {
117
- const { UserPoolId } = params;
118
- const userPool = this.userPools.get(UserPoolId);
119
-
120
- if (!userPool) {
121
- throw new Error(`User pool ${UserPoolId} not found`);
122
- }
123
-
124
- return {
125
- UserPool: {
126
- Id: userPool.Id,
127
- Name: userPool.Name,
128
- Arn: userPool.Arn,
129
- Status: userPool.Status,
130
- CreationDate: userPool.CreationDate,
131
- LastModifiedDate: userPool.LastModifiedDate,
132
- Policies: userPool.Policies,
133
- LambdaConfig: userPool.LambdaConfig,
134
- AutoVerifiedAttributes: userPool.AutoVerifiedAttributes,
135
- AliasAttributes: userPool.AliasAttributes,
136
- UsernameAttributes: userPool.UsernameAttributes,
137
- MfaConfiguration: userPool.MfaConfiguration,
138
- EstimatedNumberOfUsers: userPool.Users.length
139
- }
140
- };
141
- }
142
-
143
- deleteUserPool(params) {
144
- const { UserPoolId } = params;
145
-
146
- if (!this.userPools.has(UserPoolId)) {
147
- throw new Error(`User pool ${UserPoolId} not found`);
148
- }
149
-
150
- this.userPools.delete(UserPoolId);
151
- this.persistUserPools();
152
-
153
- return {};
154
- }
155
-
156
- // ============ User Pool Client Operations ============
157
-
158
- createUserPoolClient(params) {
159
- const { UserPoolId, ClientName, GenerateSecret, RefreshTokenValidity, AccessTokenValidity, IdTokenValidity, AllowedOAuthFlows, AllowedOAuthScopes, CallbackURLs, LogoutURLs } = params;
160
-
161
- const userPool = this.userPools.get(UserPoolId);
162
- if (!userPool) {
163
- throw new Error(`User pool ${UserPoolId} not found`);
164
- }
165
-
166
- const clientId = crypto.randomBytes(20).toString('hex');
167
- const clientSecret = GenerateSecret ? crypto.randomBytes(32).toString('hex') : null;
168
-
169
- const client = {
170
- ClientId: clientId,
171
- ClientName: ClientName,
172
- ClientSecret: clientSecret,
173
- UserPoolId: UserPoolId,
174
- RefreshTokenValidity: RefreshTokenValidity || 30,
175
- AccessTokenValidity: AccessTokenValidity || 1,
176
- IdTokenValidity: IdTokenValidity || 1,
177
- AllowedOAuthFlows: AllowedOAuthFlows || ['code'],
178
- AllowedOAuthScopes: AllowedOAuthScopes || ['openid', 'email', 'profile'],
179
- CallbackURLs: CallbackURLs || [],
180
- LogoutURLs: LogoutURLs || [],
181
- CreatedDate: new Date().toISOString(),
182
- LastModifiedDate: new Date().toISOString()
183
- };
184
-
185
- userPool.Clients.set(clientId, client);
186
- this.persistUserPools();
187
-
188
- logger.debug(`✅ User Pool Client criado: ${ClientName} (${clientId})`);
189
-
190
- return {
191
- UserPoolClient: {
192
- ClientId: client.ClientId,
193
- ClientName: client.ClientName,
194
- ClientSecret: client.ClientSecret,
195
- UserPoolId: client.UserPoolId,
196
- RefreshTokenValidity: client.RefreshTokenValidity,
197
- AccessTokenValidity: client.AccessTokenValidity,
198
- IdTokenValidity: client.IdTokenValidity,
199
- AllowedOAuthFlows: client.AllowedOAuthFlows,
200
- AllowedOAuthScopes: client.AllowedOAuthScopes,
201
- CallbackURLs: client.CallbackURLs,
202
- LogoutURLs: client.LogoutURLs,
203
- CreationDate: client.CreatedDate
204
- }
205
- };
206
- }
207
-
208
- // ============ User Operations ============
209
-
210
- signUp(params) {
211
- const { ClientId, Username, Password, UserAttributes, ValidationData } = params;
212
-
213
- // Encontra o user pool pelo client id
214
- const userPool = this.findUserPoolByClientId(ClientId);
215
- if (!userPool) {
216
- throw new Error(`Client ${ClientId} not found`);
217
- }
218
-
219
- // Verifica se usuário existe
220
- const existingUser = Array.from(this.users.values()).find(
221
- u => u.Username === Username && u.UserPoolId === userPool.Id
222
- );
223
-
224
- if (existingUser) {
225
- throw new Error(`User already exists: ${Username}`);
226
- }
227
-
228
- const userId = uuidv4();
229
- const user = {
230
- Username: Username,
231
- UserPoolId: userPool.Id,
232
- UserId: userId,
233
- Attributes: this.normalizeUserAttributes(UserAttributes || []),
234
- Enabled: true,
235
- UserStatus: 'CONFIRMED', // Por padrão, confirma imediatamente (para teste)
236
- CreatedDate: new Date().toISOString(),
237
- LastModifiedDate: new Date().toISOString(),
238
- Password: this.hashPassword(Password),
239
- MfaOptions: [],
240
- PreferredMfaSetting: null,
241
- UserMFASettingList: []
242
- };
243
-
244
- this.users.set(userId, user);
245
- userPool.Users.push(userId);
246
- userPool.EstimatedNumberOfUsers++;
247
- this.persistUsers();
248
- this.persistUserPools();
249
-
250
- logger.debug(`✅ Usuário criado: ${Username} (${userId})`);
251
-
252
- return {
253
- UserConfirmed: true,
254
- UserSub: userId,
255
- CodeDeliveryDetails: null
256
- };
257
- }
258
-
259
- confirmSignUp(params) {
260
- const { ClientId, Username, ConfirmationCode } = params;
261
-
262
- const user = this.findUserByUsername(Username, ClientId);
263
- if (!user) {
264
- throw new Error(`User not found: ${Username}`);
265
- }
266
-
267
- user.UserStatus = 'CONFIRMED';
268
- user.LastModifiedDate = new Date().toISOString();
269
- this.persistUsers();
270
-
271
- return {};
272
- }
273
-
274
- initiateAuth(params) {
275
- const { AuthFlow, ClientId, AuthParameters } = params;
276
- const userPool = this.findUserPoolByClientId(ClientId);
277
-
278
- if (!userPool) {
279
- throw new Error(`Client ${ClientId} not found`);
280
- }
281
-
282
- const username = AuthParameters.USERNAME;
283
- const password = AuthParameters.PASSWORD;
284
-
285
- const user = this.findUserByUsername(username, ClientId);
286
- if (!user) {
287
- throw new Error(`User not found: ${username}`);
288
- }
289
-
290
- if (user.UserStatus !== 'CONFIRMED') {
291
- throw new Error(`User not confirmed: ${username}`);
292
- }
293
-
294
- if (!this.verifyPassword(password, user.Password)) {
295
- throw new Error('Incorrect username or password');
296
- }
297
-
298
- // Gera tokens JWT
299
- const accessToken = this.generateAccessToken(user, userPool, ClientId);
300
- const idToken = this.generateIdToken(user, userPool, ClientId);
301
- const refreshToken = this.generateRefreshToken(user, userPool, ClientId);
302
-
303
- const sessionId = uuidv4();
304
- const session = {
305
- Id: sessionId,
306
- UserId: user.UserId,
307
- UserPoolId: userPool.Id,
308
- ClientId: ClientId,
309
- AccessToken: accessToken,
310
- IdToken: idToken,
311
- RefreshToken: refreshToken,
312
- CreatedAt: new Date().toISOString(),
313
- ExpiresAt: new Date(Date.now() + 3600000).toISOString() // 1 hora
314
- };
315
-
316
- this.sessions.set(sessionId, session);
317
- this.accessTokens.set(accessToken, session);
318
- this.refreshTokens.set(refreshToken, session);
319
- this.persistSessions();
320
-
321
- logger.debug(`🔐 Usuário autenticado: ${username}`);
322
-
323
- return {
324
- AuthenticationResult: {
325
- AccessToken: accessToken,
326
- IdToken: idToken,
327
- RefreshToken: refreshToken,
328
- TokenType: 'Bearer',
329
- ExpiresIn: 3600
330
- },
331
- ChallengeName: null,
332
- Session: null
333
- };
334
- }
335
-
336
- getToken(params) {
337
- const { AuthFlow, ClientId, AuthParameters } = params;
338
-
339
- if (AuthFlow === 'REFRESH_TOKEN_AUTH') {
340
- const refreshToken = AuthParameters.REFRESH_TOKEN;
341
- const session = this.refreshTokens.get(refreshToken);
342
-
343
- if (!session) {
344
- throw new Error('Invalid refresh token');
345
- }
346
-
347
- const user = this.users.get(session.UserId);
348
- const userPool = this.userPools.get(session.UserPoolId);
349
-
350
- if (!user || !userPool) {
351
- throw new Error('Invalid session');
352
- }
353
-
354
- // Gera novos tokens
355
- const newAccessToken = this.generateAccessToken(user, userPool, session.ClientId);
356
- const newIdToken = this.generateIdToken(user, userPool, session.ClientId);
357
-
358
- session.AccessToken = newAccessToken;
359
- session.IdToken = newIdToken;
360
- session.ExpiresAt = new Date(Date.now() + 3600000).toISOString();
361
-
362
- this.accessTokens.set(newAccessToken, session);
363
- this.persistSessions();
364
-
365
- return {
366
- AuthenticationResult: {
367
- AccessToken: newAccessToken,
368
- IdToken: newIdToken,
369
- TokenType: 'Bearer',
370
- ExpiresIn: 3600
371
- }
372
- };
373
- }
374
-
375
- throw new Error(`Unsupported AuthFlow: ${AuthFlow}`);
376
- }
377
-
378
- // ============ Token Management ============
379
-
380
- generateAccessToken(user, userPool, clientId) {
381
- const payload = {
382
- sub: user.UserId,
383
- token_use: 'access',
384
- client_id: clientId,
385
- username: user.Username,
386
- scope: 'aws.cognito.signin.user.admin',
387
- iss: `https://cognito-idp.local/${userPool.Id}`,
388
- exp: Math.floor(Date.now() / 1000) + 3600,
389
- iat: Math.floor(Date.now() / 1000)
390
- };
391
-
392
- return jwt.sign(payload, this.jwtSecret, { algorithm: 'HS256' });
393
- }
394
-
395
- generateIdToken(user, userPool, clientId) {
396
- const payload = {
397
- sub: user.UserId,
398
- token_use: 'id',
399
- client_id: clientId,
400
- email: user.Attributes.email,
401
- email_verified: user.Attributes.email_verified || true,
402
- username: user.Username,
403
- iss: `https://cognito-idp.local/${userPool.Id}`,
404
- exp: Math.floor(Date.now() / 1000) + 3600,
405
- iat: Math.floor(Date.now() / 1000)
406
- };
407
-
408
- // Adiciona outros atributos do usuário
409
- for (const [key, value] of Object.entries(user.Attributes)) {
410
- if (key !== 'email' && key !== 'email_verified') {
411
- payload[key] = value;
412
- }
413
- }
414
-
415
- return jwt.sign(payload, this.jwtSecret, { algorithm: 'HS256' });
416
- }
417
-
418
- generateRefreshToken(user, userPool, clientId) {
419
- const payload = {
420
- sub: user.UserId,
421
- token_use: 'refresh',
422
- client_id: clientId,
423
- username: user.Username,
424
- iss: `https://cognito-idp.local/${userPool.Id}`,
425
- exp: Math.floor(Date.now() / 1000) + 2592000, // 30 dias
426
- iat: Math.floor(Date.now() / 1000)
427
- };
428
-
429
- return jwt.sign(payload, this.jwtSecret, { algorithm: 'HS256' });
430
- }
431
-
432
- verifyAccessToken(token) {
433
- try {
434
- const decoded = jwt.verify(token, this.jwtSecret);
435
- const session = this.accessTokens.get(token);
436
-
437
- if (!session || session.ExpiresAt < new Date().toISOString()) {
438
- return null;
439
- }
440
-
441
- return decoded;
442
- } catch (error) {
443
- return null;
444
- }
445
- }
446
-
447
- // ============ Admin Operations ============
448
-
449
- adminGetUser(params) {
450
- const { UserPoolId, Username } = params;
451
- const userPool = this.userPools.get(UserPoolId);
452
-
453
- if (!userPool) {
454
- throw new Error(`User pool ${UserPoolId} not found`);
455
- }
456
-
457
- const user = this.findUserByUsername(Username, null, UserPoolId);
458
- if (!user) {
459
- throw new Error(`User not found: ${Username}`);
460
- }
461
-
462
- return {
463
- Username: user.Username,
464
- UserAttributes: this.formatUserAttributes(user.Attributes),
465
- UserCreateDate: user.CreatedDate,
466
- UserLastModifiedDate: user.LastModifiedDate,
467
- Enabled: user.Enabled,
468
- UserStatus: user.UserStatus,
469
- MFAOptions: user.MfaOptions,
470
- PreferredMfaSetting: user.PreferredMfaSetting,
471
- UserMFASettingList: user.UserMFASettingList
472
- };
473
- }
474
-
475
- adminCreateUser(params) {
476
- const { UserPoolId, Username, UserAttributes, TemporaryPassword, DesiredDeliveryMediums } = params;
477
- const userPool = this.userPools.get(UserPoolId);
478
-
479
- if (!userPool) {
480
- throw new Error(`User pool ${UserPoolId} not found`);
481
- }
482
-
483
- const userId = uuidv4();
484
- const user = {
485
- Username: Username,
486
- UserPoolId: UserPoolId,
487
- UserId: userId,
488
- Attributes: this.normalizeUserAttributes(UserAttributes || []),
489
- Enabled: true,
490
- UserStatus: 'FORCE_CHANGE_PASSWORD',
491
- CreatedDate: new Date().toISOString(),
492
- LastModifiedDate: new Date().toISOString(),
493
- Password: this.hashPassword(TemporaryPassword || 'Temp123!'),
494
- MfaOptions: [],
495
- PreferredMfaSetting: null,
496
- UserMFASettingList: []
497
- };
498
-
499
- this.users.set(userId, user);
500
- userPool.Users.push(userId);
501
- userPool.EstimatedNumberOfUsers++;
502
- this.persistUsers();
503
- this.persistUserPools();
504
-
505
- logger.debug(`👤 Usuário administrador criado: ${Username}`);
506
-
507
- return {
508
- User: {
509
- Username: user.Username,
510
- UserAttributes: this.formatUserAttributes(user.Attributes),
511
- UserCreateDate: user.CreatedDate,
512
- UserLastModifiedDate: user.LastModifiedDate,
513
- Enabled: user.Enabled,
514
- UserStatus: user.UserStatus
515
- }
516
- };
517
- }
518
-
519
- adminSetUserPassword(params) {
520
- const { UserPoolId, Username, Password, Permanent } = params;
521
- const user = this.findUserByUsername(Username, null, UserPoolId);
522
-
523
- if (!user) {
524
- throw new Error(`User not found: ${Username}`);
525
- }
526
-
527
- user.Password = this.hashPassword(Password);
528
- if (Permanent) {
529
- user.UserStatus = 'CONFIRMED';
530
- }
531
- user.LastModifiedDate = new Date().toISOString();
532
- this.persistUsers();
533
-
534
- return {};
535
- }
536
-
537
- adminDeleteUser(params) {
538
- const { UserPoolId, Username } = params;
539
- const user = this.findUserByUsername(Username, null, UserPoolId);
540
-
541
- if (!user) {
542
- throw new Error(`User not found: ${Username}`);
543
- }
544
-
545
- const userPool = this.userPools.get(UserPoolId);
546
- if (userPool) {
547
- const index = userPool.Users.indexOf(user.UserId);
548
- if (index !== -1) {
549
- userPool.Users.splice(index, 1);
550
- userPool.EstimatedNumberOfUsers--;
551
- }
552
- }
553
-
554
- this.users.delete(user.UserId);
555
- this.persistUsers();
556
- this.persistUserPools();
557
-
558
- return {};
559
- }
560
-
561
- // ============ Helper Methods ============
562
-
563
- findUserPoolByClientId(clientId) {
564
- for (const userPool of this.userPools.values()) {
565
- if (userPool.Clients.has(clientId)) {
566
- return userPool;
567
- }
568
- }
569
- return null;
570
- }
571
-
572
- findUserByUsername(username, clientId = null, userPoolId = null) {
573
- let targetUserPoolId = userPoolId;
574
-
575
- if (clientId && !targetUserPoolId) {
576
- const userPool = this.findUserPoolByClientId(clientId);
577
- if (userPool) {
578
- targetUserPoolId = userPool.Id;
579
- }
580
- }
581
-
582
- for (const user of this.users.values()) {
583
- if (user.Username === username && user.UserPoolId === targetUserPoolId) {
584
- return user;
585
- }
586
- }
587
-
588
- return null;
589
- }
590
-
591
- normalizeUserAttributes(attributes) {
592
- const normalized = {};
593
- for (const attr of attributes) {
594
- normalized[attr.Name] = attr.Value;
595
- }
596
- return normalized;
597
- }
598
-
599
- formatUserAttributes(attributes) {
600
- return Object.entries(attributes).map(([Name, Value]) => ({ Name, Value }));
601
- }
602
-
603
- hashPassword(password) {
604
- // Simulação de hash (não usar em produção real)
605
- return crypto.createHash('sha256').update(password).digest('hex');
606
- }
607
-
608
- verifyPassword(password, hash) {
609
- return this.hashPassword(password) === hash;
610
- }
611
-
612
- // ============ Identity Pool Operations ============
613
-
614
- createIdentityPool(params) {
615
- const { IdentityPoolName, AllowUnauthenticatedIdentities, SupportedLoginProviders, CognitoIdentityProviders } = params;
616
-
617
- const identityPoolId = `local:${IdentityPoolName}_${Date.now()}`;
618
- const identityPool = {
619
- IdentityPoolId: identityPoolId,
620
- IdentityPoolName: IdentityPoolName,
621
- AllowUnauthenticatedIdentities: AllowUnauthenticatedIdentities || false,
622
- SupportedLoginProviders: SupportedLoginProviders || {},
623
- CognitoIdentityProviders: CognitoIdentityProviders || [],
624
- Identities: new Map()
625
- };
626
-
627
- this.identityPools.set(identityPoolId, identityPool);
628
- this.persistIdentityPools();
629
-
630
- logger.debug(`✅ Identity Pool criado: ${IdentityPoolName} (${identityPoolId})`);
631
-
632
- return {
633
- IdentityPoolId: identityPoolId,
634
- IdentityPoolName: identityPoolName,
635
- AllowUnauthenticatedIdentities: identityPool.AllowUnauthenticatedIdentities
636
- };
637
- }
638
-
639
- getId(params) {
640
- const { IdentityPoolId, Logins } = params;
641
- const identityPool = this.identityPools.get(IdentityPoolId);
642
-
643
- if (!identityPool) {
644
- throw new Error(`Identity pool ${IdentityPoolId} not found`);
645
- }
646
-
647
- let identityId = null;
648
-
649
- if (Logins) {
650
- // Procura identidade existente com os logins fornecidos
651
- for (const [id, identity] of identityPool.Identities) {
652
- if (identity.Logins && this.matchesLogins(identity.Logins, Logins)) {
653
- identityId = id;
654
- break;
655
- }
656
- }
657
- }
658
-
659
- if (!identityId) {
660
- identityId = uuidv4();
661
- identityPool.Identities.set(identityId, {
662
- IdentityId: identityId,
663
- Logins: Logins || {},
664
- CreationDate: new Date().toISOString(),
665
- LastModifiedDate: new Date().toISOString()
666
- });
667
- this.persistIdentityPools();
668
- }
669
-
670
- return {
671
- IdentityId: identityId
672
- };
673
- }
674
-
675
- getCredentialsForIdentity(params) {
676
- const { IdentityId, Logins } = params;
677
- const identityPool = this.findIdentityPoolByIdentityId(IdentityId);
678
-
679
- if (!identityPool) {
680
- throw new Error(`Identity ${IdentityId} not found`);
681
- }
682
-
683
- const identity = identityPool.Identities.get(IdentityId);
684
- if (!identity) {
685
- throw new Error(`Identity ${IdentityId} not found in pool`);
686
- }
687
-
688
- // Gera credenciais temporárias (simuladas)
689
- const credentials = {
690
- AccessKeyId: `AKIA${crypto.randomBytes(16).toString('hex').toUpperCase()}`,
691
- SecretKey: crypto.randomBytes(32).toString('hex'),
692
- SessionToken: crypto.randomBytes(64).toString('base64'),
693
- Expiration: new Date(Date.now() + 3600000).toISOString()
694
- };
695
-
696
- return {
697
- Credentials: credentials,
698
- IdentityId: IdentityId
699
- };
700
- }
701
-
702
- findIdentityPoolByIdentityId(identityId) {
703
- for (const pool of this.identityPools.values()) {
704
- if (pool.Identities.has(identityId)) {
705
- return pool;
706
- }
707
- }
708
- return null;
709
- }
710
-
711
- matchesLogins(existingLogins, newLogins) {
712
- const existingKeys = Object.keys(existingLogins);
713
- const newKeys = Object.keys(newLogins);
714
-
715
- if (existingKeys.length !== newKeys.length) return false;
716
-
717
- for (const key of existingKeys) {
718
- if (existingLogins[key] !== newLogins[key]) {
719
- return false;
720
- }
721
- }
722
-
723
- return true;
724
- }
725
-
726
- // ============ Persistence ============
727
-
728
- loadUserPools() {
729
- const saved = this.store.read('__userpools__');
730
- if (saved) {
731
- for (const [id, data] of Object.entries(saved)) {
732
- // Reconstitui Maps
733
- data.Clients = new Map(Object.entries(data.Clients || {}));
734
- data.Groups = new Map(Object.entries(data.Groups || {}));
735
- data.IdentityProviders = new Map(Object.entries(data.IdentityProviders || {}));
736
- data.ResourceServers = new Map(Object.entries(data.ResourceServers || {}));
737
- this.userPools.set(id, data);
738
- }
739
- }
740
- }
741
-
742
- loadIdentityPools() {
743
- const saved = this.store.read('__identitypools__');
744
- if (saved) {
745
- for (const [id, data] of Object.entries(saved)) {
746
- data.Identities = new Map(Object.entries(data.Identities || {}));
747
- this.identityPools.set(id, data);
748
- }
749
- }
750
- }
751
-
752
- loadUsers() {
753
- const saved = this.store.read('__users__');
754
- if (saved) {
755
- for (const [id, user] of Object.entries(saved)) {
756
- this.users.set(id, user);
757
- }
758
- }
759
- }
760
-
761
- loadSessions() {
762
- const saved = this.store.read('__sessions__');
763
- if (saved) {
764
- for (const [id, session] of Object.entries(saved)) {
765
- this.sessions.set(id, session);
766
- this.accessTokens.set(session.AccessToken, session);
767
- this.refreshTokens.set(session.RefreshToken, session);
768
- }
769
- }
770
- }
771
-
772
- persistUserPools() {
773
- const poolsObj = {};
774
- for (const [id, pool] of this.userPools.entries()) {
775
- poolsObj[id] = {
776
- ...pool,
777
- Clients: Object.fromEntries(pool.Clients),
778
- Groups: Object.fromEntries(pool.Groups),
779
- IdentityProviders: Object.fromEntries(pool.IdentityProviders),
780
- ResourceServers: Object.fromEntries(pool.ResourceServers)
781
- };
782
- }
783
- this.store.write('__userpools__', poolsObj);
784
- }
785
-
786
- persistIdentityPools() {
787
- const poolsObj = {};
788
- for (const [id, pool] of this.identityPools.entries()) {
789
- poolsObj[id] = {
790
- ...pool,
791
- Identities: Object.fromEntries(pool.Identities)
792
- };
793
- }
794
- this.store.write('__identitypools__', poolsObj);
795
- }
796
-
797
- persistUsers() {
798
- const usersObj = {};
799
- for (const [id, user] of this.users.entries()) {
800
- usersObj[id] = user;
801
- }
802
- this.store.write('__users__', usersObj);
803
- }
804
-
805
- persistSessions() {
806
- const sessionsObj = {};
807
- for (const [id, session] of this.sessions.entries()) {
808
- sessionsObj[id] = session;
809
- }
810
- this.store.write('__sessions__', sessionsObj);
811
- }
812
-
813
- async reset() {
814
- this.userPools.clear();
815
- this.identityPools.clear();
816
- this.users.clear();
817
- this.sessions.clear();
818
- this.accessTokens.clear();
819
- this.refreshTokens.clear();
820
-
821
- this.persistUserPools();
822
- this.persistIdentityPools();
823
- this.persistUsers();
824
- this.persistSessions();
825
-
826
- logger.debug('Cognito: Todos os dados resetados');
827
- }
828
-
829
- // ============ Stats ============
830
-
831
- getUserPoolsCount() {
832
- return this.userPools.size;
833
- }
834
-
835
- getTotalUsersCount() {
836
- return this.users.size;
837
- }
838
-
839
- getIdentityPoolsCount() {
840
- return this.identityPools.size;
841
- }
842
-
843
- getActiveSessionsCount() {
844
- return this.sessions.size;
845
- }
846
- }
847
-
1
+ /**
2
+ * Cognito Simulator Core
3
+ * Simula User Pools, Identity Pools, Autenticação, Tokens JWT
4
+ */
5
+
6
+ const crypto = require('crypto');
7
+ const jwt = require('jsonwebtoken');
8
+ const { v4: uuidv4 } = require('uuid');
9
+ const logger = require('../../utils/logger');
10
+ const LocalStore = require('../../utils/local-store');
11
+ const path = require('path');
12
+
13
+ class CognitoSimulator {
14
+ constructor(config) {
15
+ this.config = config;
16
+ this.dataDir = path.join(process.env.AWS_LOCAL_SIMULATOR_DATA_DIR, 'cognito');
17
+ this.store = new LocalStore(this.dataDir);
18
+ this.userPools = new Map();
19
+ this.identityPools = new Map();
20
+ this.users = new Map();
21
+ this.sessions = new Map();
22
+ this.refreshTokens = new Map();
23
+ this.accessTokens = new Map();
24
+ this.jwtSecret = crypto.randomBytes(64).toString('hex');
25
+ }
26
+
27
+ async initialize() {
28
+ logger.debug('Inicializando Cognito Simulator...');
29
+ this.loadUserPools();
30
+ this.loadIdentityPools();
31
+ this.loadUsers();
32
+ this.loadSessions();
33
+
34
+ logger.debug(`✅ Cognito Simulator inicializado com ${this.userPools.size} user pools, ${this.identityPools.size} identity pools, ${this.users.size} usuários`);
35
+ }
36
+
37
+ // ============ User Pool Operations ============
38
+
39
+ createUserPool(params) {
40
+ const { PoolName, Policies, LambdaConfig, AutoVerifiedAttributes, AliasAttributes, UsernameAttributes, MfaConfiguration } = params;
41
+
42
+ const poolId = `local_${PoolName}_${Date.now()}`;
43
+ const userPool = {
44
+ Id: poolId,
45
+ Name: PoolName,
46
+ Arn: `arn:aws:cognito:local:000000000000:userpool/${poolId}`,
47
+ Status: 'ACTIVE',
48
+ CreationDate: new Date().toISOString(),
49
+ LastModifiedDate: new Date().toISOString(),
50
+ Policies: Policies || {
51
+ PasswordPolicy: {
52
+ MinimumLength: 8,
53
+ RequireUppercase: true,
54
+ RequireLowercase: true,
55
+ RequireNumbers: true,
56
+ RequireSymbols: false
57
+ }
58
+ },
59
+ LambdaConfig: LambdaConfig || {},
60
+ AutoVerifiedAttributes: AutoVerifiedAttributes || ['email'],
61
+ AliasAttributes: AliasAttributes || [],
62
+ UsernameAttributes: UsernameAttributes || ['email'],
63
+ MfaConfiguration: MfaConfiguration || 'OFF',
64
+ EstimatedNumberOfUsers: 0,
65
+ Users: [],
66
+ Clients: new Map(),
67
+ Groups: new Map(),
68
+ IdentityProviders: new Map(),
69
+ ResourceServers: new Map()
70
+ };
71
+
72
+ this.userPools.set(poolId, userPool);
73
+ this.persistUserPools();
74
+
75
+ logger.debug(`✅ User Pool criado: ${PoolName} (${poolId})`);
76
+
77
+ return {
78
+ UserPool: {
79
+ Id: userPool.Id,
80
+ Name: userPool.Name,
81
+ Arn: userPool.Arn,
82
+ Status: userPool.Status,
83
+ CreationDate: userPool.CreationDate,
84
+ LastModifiedDate: userPool.LastModifiedDate,
85
+ MfaConfiguration: userPool.MfaConfiguration,
86
+ EstimatedNumberOfUsers: 0
87
+ }
88
+ };
89
+ }
90
+
91
+ listUserPools(params = {}) {
92
+ const { MaxResults = 60, NextToken } = params;
93
+ let userPools = Array.from(this.userPools.values());
94
+
95
+ if (NextToken) {
96
+ const startIndex = parseInt(NextToken);
97
+ userPools = userPools.slice(startIndex);
98
+ }
99
+
100
+ const results = userPools.slice(0, MaxResults);
101
+ const nextToken = results.length === MaxResults ? String(MaxResults) : null;
102
+
103
+ return {
104
+ UserPools: results.map(pool => ({
105
+ Id: pool.Id,
106
+ Name: pool.Name,
107
+ Arn: pool.Arn,
108
+ Status: pool.Status,
109
+ CreationDate: pool.CreationDate,
110
+ LastModifiedDate: pool.LastModifiedDate
111
+ })),
112
+ NextToken: nextToken
113
+ };
114
+ }
115
+
116
+ describeUserPool(params) {
117
+ const { UserPoolId } = params;
118
+ const userPool = this.userPools.get(UserPoolId);
119
+
120
+ if (!userPool) {
121
+ throw new Error(`User pool ${UserPoolId} not found`);
122
+ }
123
+
124
+ return {
125
+ UserPool: {
126
+ Id: userPool.Id,
127
+ Name: userPool.Name,
128
+ Arn: userPool.Arn,
129
+ Status: userPool.Status,
130
+ CreationDate: userPool.CreationDate,
131
+ LastModifiedDate: userPool.LastModifiedDate,
132
+ Policies: userPool.Policies,
133
+ LambdaConfig: userPool.LambdaConfig,
134
+ AutoVerifiedAttributes: userPool.AutoVerifiedAttributes,
135
+ AliasAttributes: userPool.AliasAttributes,
136
+ UsernameAttributes: userPool.UsernameAttributes,
137
+ MfaConfiguration: userPool.MfaConfiguration,
138
+ EstimatedNumberOfUsers: userPool.Users.length
139
+ }
140
+ };
141
+ }
142
+
143
+ listUsers(params = {}) {
144
+ const { UserPoolId, Filter, Limit = 60, PaginationToken } = params;
145
+ const userPool = this.userPools.get(UserPoolId);
146
+
147
+ if (!userPool) {
148
+ throw new Error(`User pool ${UserPoolId} not found`);
149
+ }
150
+
151
+ let users = Array.from(this.users.values()).filter(u => u.UserPoolId === UserPoolId);
152
+
153
+ if (PaginationToken) {
154
+ const startIndex = parseInt(PaginationToken);
155
+ users = users.slice(startIndex);
156
+ }
157
+
158
+ const results = users.slice(0, Limit);
159
+ const nextToken = results.length === Limit && users.length > Limit ? String(Limit) : null;
160
+
161
+ return {
162
+ Users: results.map(u => ({
163
+ Username: u.Username,
164
+ UserStatus: u.UserStatus,
165
+ Enabled: u.Enabled,
166
+ UserCreateDate: u.CreatedDate,
167
+ UserLastModifiedDate: u.LastModifiedDate,
168
+ Attributes: this.formatUserAttributes(u.Attributes)
169
+ })),
170
+ PaginationToken: nextToken
171
+ };
172
+ }
173
+
174
+ listUserPoolClients(params = {}) {
175
+ const { UserPoolId, MaxResults = 60, NextToken } = params;
176
+ const userPool = this.userPools.get(UserPoolId);
177
+ if (!userPool) throw new Error(`User pool ${UserPoolId} not found`);
178
+
179
+ let clients = Array.from(userPool.Clients.values());
180
+ if (NextToken) clients = clients.slice(parseInt(NextToken));
181
+ const results = clients.slice(0, MaxResults);
182
+
183
+ return {
184
+ UserPoolClients: results.map(c => ({
185
+ ClientId: c.ClientId,
186
+ ClientName: c.ClientName,
187
+ UserPoolId: c.UserPoolId
188
+ })),
189
+ NextToken: results.length === MaxResults && clients.length > MaxResults ? String(MaxResults) : null
190
+ };
191
+ }
192
+
193
+ describeUserPoolClient(params = {}) {
194
+ const { UserPoolId, ClientId } = params;
195
+ const userPool = this.userPools.get(UserPoolId);
196
+ if (!userPool) throw new Error(`User pool ${UserPoolId} not found`);
197
+ const client = userPool.Clients.get(ClientId);
198
+ if (!client) throw new Error(`Client ${ClientId} not found`);
199
+ return { UserPoolClient: client };
200
+ }
201
+
202
+ deleteUserPoolClient(params = {}) {
203
+ const { UserPoolId, ClientId } = params;
204
+ const userPool = this.userPools.get(UserPoolId);
205
+ if (!userPool) throw new Error(`User pool ${UserPoolId} not found`);
206
+ userPool.Clients.delete(ClientId);
207
+ this.persistUserPools();
208
+ return {};
209
+ }
210
+
211
+ forgotPassword(params = {}) {
212
+ const { ClientId, Username } = params;
213
+ const userPool = this.findUserPoolByClientId(ClientId);
214
+ if (!userPool) throw new Error(`Client ${ClientId} not found`);
215
+ return { CodeDeliveryDetails: { Destination: 'test@example.com', DeliveryMedium: 'EMAIL', AttributeName: 'email' } };
216
+ }
217
+
218
+ confirmForgotPassword(params = {}) {
219
+ const { ClientId, Username, ConfirmationCode, Password } = params;
220
+ const user = this.findUserByUsername(Username, ClientId);
221
+ if (!user) throw new Error(`User not found: ${Username}`);
222
+ user.Password = this.hashPassword(Password);
223
+ user.UserStatus = 'CONFIRMED';
224
+ this.persistUsers();
225
+ return {};
226
+ }
227
+
228
+ changePassword(params = {}) {
229
+ const { AccessToken, PreviousPassword, ProposedPassword } = params;
230
+ const session = this.accessTokens.get(AccessToken);
231
+ if (!session) throw new Error('Invalid access token');
232
+ const user = this.users.get(session.UserId);
233
+ if (!user) throw new Error('User not found');
234
+ if (!this.verifyPassword(PreviousPassword, user.Password)) throw new Error('Incorrect previous password');
235
+ user.Password = this.hashPassword(ProposedPassword);
236
+ this.persistUsers();
237
+ return {};
238
+ }
239
+
240
+ respondToAuthChallenge(params = {}) {
241
+ return { AuthenticationResult: null, ChallengeName: null };
242
+ }
243
+
244
+ revokeToken(params = {}) {
245
+ const { Token, ClientId } = params;
246
+ // Remove refresh token session if it exists
247
+ const session = this.refreshTokens.get(Token);
248
+ if (session) {
249
+ this.sessions.delete(session.Id);
250
+ this.accessTokens.delete(session.AccessToken);
251
+ this.refreshTokens.delete(Token);
252
+ this.persistSessions();
253
+ }
254
+ return {};
255
+ }
256
+
257
+ globalSignOut(params = {}) {
258
+ const { AccessToken } = params;
259
+ const session = this.accessTokens.get(AccessToken);
260
+ if (session) {
261
+ this.sessions.delete(session.Id);
262
+ this.accessTokens.delete(AccessToken);
263
+ this.refreshTokens.delete(session.RefreshToken);
264
+ this.persistSessions();
265
+ }
266
+ return {};
267
+ }
268
+
269
+ getUser(params = {}) {
270
+ const { AccessToken } = params;
271
+ const session = this.accessTokens.get(AccessToken);
272
+ if (!session) throw new Error('Invalid access token');
273
+ // Check session is still active
274
+ if (!this.sessions.has(session.Id)) throw new Error('Token has been revoked');
275
+ const user = this.users.get(session.UserId);
276
+ if (!user) throw new Error('User not found');
277
+ return {
278
+ Username: user.Username,
279
+ UserAttributes: this.formatUserAttributes(user.Attributes),
280
+ UserStatus: user.UserStatus
281
+ };
282
+ }
283
+
284
+ updateUserAttributes(params = {}) {
285
+ const { AccessToken, UserAttributes } = params;
286
+ const session = this.accessTokens.get(AccessToken);
287
+ if (!session) throw new Error('Invalid access token');
288
+ const user = this.users.get(session.UserId);
289
+ if (!user) throw new Error('User not found');
290
+ const updates = this.normalizeUserAttributes(UserAttributes || []);
291
+ Object.assign(user.Attributes, updates);
292
+ this.persistUsers();
293
+ return { CodeDeliveryDetailsList: [] };
294
+ }
295
+
296
+ deleteUser(params = {}) {
297
+ const { AccessToken } = params;
298
+ const session = this.accessTokens.get(AccessToken);
299
+ if (!session) throw new Error('Invalid access token');
300
+ this.users.delete(session.UserId);
301
+ this.persistUsers();
302
+ return {};
303
+ }
304
+
305
+ adminDisableUser(params = {}) {
306
+ const { UserPoolId, Username } = params;
307
+ const user = this.findUserByUsername(Username, null, UserPoolId);
308
+ if (!user) throw new Error(`User not found: ${Username}`);
309
+ user.Enabled = false;
310
+ this.persistUsers();
311
+ return {};
312
+ }
313
+
314
+ adminEnableUser(params = {}) {
315
+ const { UserPoolId, Username } = params;
316
+ const user = this.findUserByUsername(Username, null, UserPoolId);
317
+ if (!user) throw new Error(`User not found: ${Username}`);
318
+ user.Enabled = true;
319
+ this.persistUsers();
320
+ return {};
321
+ }
322
+
323
+ adminResetUserPassword(params = {}) {
324
+ const { UserPoolId, Username } = params;
325
+ const user = this.findUserByUsername(Username, null, UserPoolId);
326
+ if (!user) throw new Error(`User not found: ${Username}`);
327
+ user.UserStatus = 'RESET_REQUIRED';
328
+ this.persistUsers();
329
+ return {};
330
+ }
331
+
332
+ adminUserGlobalSignOut(params = {}) {
333
+ const { UserPoolId, Username } = params;
334
+ const user = this.findUserByUsername(Username, null, UserPoolId);
335
+ if (!user) throw new Error(`User not found: ${Username}`);
336
+ // Invalidate all sessions for this user
337
+ for (const [id, session] of this.sessions.entries()) {
338
+ if (session.UserId === user.UserId) {
339
+ this.accessTokens.delete(session.AccessToken);
340
+ this.refreshTokens.delete(session.RefreshToken);
341
+ this.sessions.delete(id);
342
+ }
343
+ }
344
+ this.persistSessions();
345
+ return {};
346
+ }
347
+
348
+ adminListGroupsForUser(params = {}) {
349
+ return { Groups: [], NextToken: null };
350
+ }
351
+
352
+ deleteUserPool(params) {
353
+ const { UserPoolId } = params;
354
+
355
+ if (!this.userPools.has(UserPoolId)) {
356
+ throw new Error(`User pool ${UserPoolId} not found`);
357
+ }
358
+
359
+ this.userPools.delete(UserPoolId);
360
+ this.persistUserPools();
361
+
362
+ return {};
363
+ }
364
+
365
+ // ============ User Pool Client Operations ============
366
+
367
+ createUserPoolClient(params) {
368
+ const { UserPoolId, ClientName, GenerateSecret, RefreshTokenValidity, AccessTokenValidity, IdTokenValidity, AllowedOAuthFlows, AllowedOAuthScopes, CallbackURLs, LogoutURLs } = params;
369
+
370
+ const userPool = this.userPools.get(UserPoolId);
371
+ if (!userPool) {
372
+ throw new Error(`User pool ${UserPoolId} not found`);
373
+ }
374
+
375
+ const clientId = crypto.randomBytes(20).toString('hex');
376
+ const clientSecret = GenerateSecret ? crypto.randomBytes(32).toString('hex') : null;
377
+
378
+ const client = {
379
+ ClientId: clientId,
380
+ ClientName: ClientName,
381
+ ClientSecret: clientSecret,
382
+ UserPoolId: UserPoolId,
383
+ RefreshTokenValidity: RefreshTokenValidity || 30,
384
+ AccessTokenValidity: AccessTokenValidity || 1,
385
+ IdTokenValidity: IdTokenValidity || 1,
386
+ AllowedOAuthFlows: AllowedOAuthFlows || ['code'],
387
+ AllowedOAuthScopes: AllowedOAuthScopes || ['openid', 'email', 'profile'],
388
+ CallbackURLs: CallbackURLs || [],
389
+ LogoutURLs: LogoutURLs || [],
390
+ CreatedDate: new Date().toISOString(),
391
+ LastModifiedDate: new Date().toISOString()
392
+ };
393
+
394
+ userPool.Clients.set(clientId, client);
395
+ this.persistUserPools();
396
+
397
+ logger.debug(`✅ User Pool Client criado: ${ClientName} (${clientId})`);
398
+
399
+ return {
400
+ UserPoolClient: {
401
+ ClientId: client.ClientId,
402
+ ClientName: client.ClientName,
403
+ ClientSecret: client.ClientSecret,
404
+ UserPoolId: client.UserPoolId,
405
+ RefreshTokenValidity: client.RefreshTokenValidity,
406
+ AccessTokenValidity: client.AccessTokenValidity,
407
+ IdTokenValidity: client.IdTokenValidity,
408
+ AllowedOAuthFlows: client.AllowedOAuthFlows,
409
+ AllowedOAuthScopes: client.AllowedOAuthScopes,
410
+ CallbackURLs: client.CallbackURLs,
411
+ LogoutURLs: client.LogoutURLs,
412
+ CreationDate: client.CreatedDate
413
+ }
414
+ };
415
+ }
416
+
417
+ // ============ User Operations ============
418
+
419
+ signUp(params = {}) {
420
+ const { ClientId, Username, Password, UserAttributes, ValidationData } = params;
421
+
422
+ // Encontra o user pool pelo client id
423
+ const userPool = this.findUserPoolByClientId(ClientId);
424
+ if (!userPool) {
425
+ throw new Error(`Client ${ClientId} not found`);
426
+ }
427
+
428
+ // Verifica se usuário já existe
429
+ const existingUser = Array.from(this.users.values()).find(
430
+ u => u.Username === Username && u.UserPoolId === userPool.Id
431
+ );
432
+
433
+ if (existingUser) {
434
+ throw new Error(`User already exists: ${Username}`);
435
+ }
436
+
437
+ const userId = uuidv4();
438
+ const user = {
439
+ Username: Username,
440
+ UserPoolId: userPool.Id,
441
+ UserId: userId,
442
+ Attributes: this.normalizeUserAttributes(UserAttributes || []),
443
+ Enabled: true,
444
+ UserStatus: 'CONFIRMED', // Por padrão, confirma imediatamente (para teste)
445
+ CreatedDate: new Date().toISOString(),
446
+ LastModifiedDate: new Date().toISOString(),
447
+ Password: this.hashPassword(Password),
448
+ MfaOptions: [],
449
+ PreferredMfaSetting: null,
450
+ UserMFASettingList: []
451
+ };
452
+
453
+ this.users.set(userId, user);
454
+ userPool.Users.push(userId);
455
+ userPool.EstimatedNumberOfUsers++;
456
+ this.persistUsers();
457
+ this.persistUserPools();
458
+
459
+ logger.debug(`✅ Usuário criado: ${Username} (${userId})`);
460
+
461
+ return {
462
+ UserConfirmed: true,
463
+ UserSub: userId,
464
+ CodeDeliveryDetails: null
465
+ };
466
+ }
467
+
468
+ confirmSignUp(params) {
469
+ const { ClientId, Username, ConfirmationCode } = params;
470
+
471
+ const user = this.findUserByUsername(Username, ClientId);
472
+ if (!user) {
473
+ throw new Error(`User not found: ${Username}`);
474
+ }
475
+
476
+ user.UserStatus = 'CONFIRMED';
477
+ user.LastModifiedDate = new Date().toISOString();
478
+ this.persistUsers();
479
+
480
+ return {};
481
+ }
482
+
483
+ initiateAuth(params) {
484
+ const { AuthFlow, ClientId, AuthParameters } = params;
485
+ const userPool = this.findUserPoolByClientId(ClientId);
486
+
487
+ if (!userPool) {
488
+ throw new Error(`Client ${ClientId} not found`);
489
+ }
490
+
491
+ const username = AuthParameters.USERNAME;
492
+ const password = AuthParameters.PASSWORD;
493
+
494
+ const user = this.findUserByUsername(username, ClientId);
495
+ if (!user) {
496
+ throw new Error(`User not found: ${username}`);
497
+ }
498
+
499
+ if (user.UserStatus !== 'CONFIRMED') {
500
+ throw new Error(`User not confirmed: ${username}`);
501
+ }
502
+
503
+ if (!this.verifyPassword(password, user.Password)) {
504
+ throw new Error('Incorrect username or password');
505
+ }
506
+
507
+ // Gera tokens JWT
508
+ const accessToken = this.generateAccessToken(user, userPool, ClientId);
509
+ const idToken = this.generateIdToken(user, userPool, ClientId);
510
+ const refreshToken = this.generateRefreshToken(user, userPool, ClientId);
511
+
512
+ const sessionId = uuidv4();
513
+ const session = {
514
+ Id: sessionId,
515
+ UserId: user.UserId,
516
+ UserPoolId: userPool.Id,
517
+ ClientId: ClientId,
518
+ AccessToken: accessToken,
519
+ IdToken: idToken,
520
+ RefreshToken: refreshToken,
521
+ CreatedAt: new Date().toISOString(),
522
+ ExpiresAt: new Date(Date.now() + 3600000).toISOString() // 1 hora
523
+ };
524
+
525
+ this.sessions.set(sessionId, session);
526
+ this.accessTokens.set(accessToken, session);
527
+ this.refreshTokens.set(refreshToken, session);
528
+ this.persistSessions();
529
+
530
+ logger.debug(`🔐 Usuário autenticado: ${username}`);
531
+
532
+ return {
533
+ AuthenticationResult: {
534
+ AccessToken: accessToken,
535
+ IdToken: idToken,
536
+ RefreshToken: refreshToken,
537
+ TokenType: 'Bearer',
538
+ ExpiresIn: 3600
539
+ },
540
+ ChallengeName: null,
541
+ Session: null
542
+ };
543
+ }
544
+
545
+ getToken(params) {
546
+ const { AuthFlow, ClientId, AuthParameters } = params;
547
+
548
+ if (AuthFlow === 'REFRESH_TOKEN_AUTH') {
549
+ const refreshToken = AuthParameters.REFRESH_TOKEN;
550
+ const session = this.refreshTokens.get(refreshToken);
551
+
552
+ if (!session) {
553
+ throw new Error('Invalid refresh token');
554
+ }
555
+
556
+ const user = this.users.get(session.UserId);
557
+ const userPool = this.userPools.get(session.UserPoolId);
558
+
559
+ if (!user || !userPool) {
560
+ throw new Error('Invalid session');
561
+ }
562
+
563
+ // Gera novos tokens
564
+ const newAccessToken = this.generateAccessToken(user, userPool, session.ClientId);
565
+ const newIdToken = this.generateIdToken(user, userPool, session.ClientId);
566
+
567
+ session.AccessToken = newAccessToken;
568
+ session.IdToken = newIdToken;
569
+ session.ExpiresAt = new Date(Date.now() + 3600000).toISOString();
570
+
571
+ this.accessTokens.set(newAccessToken, session);
572
+ this.persistSessions();
573
+
574
+ return {
575
+ AuthenticationResult: {
576
+ AccessToken: newAccessToken,
577
+ IdToken: newIdToken,
578
+ TokenType: 'Bearer',
579
+ ExpiresIn: 3600
580
+ }
581
+ };
582
+ }
583
+
584
+ throw new Error(`Unsupported AuthFlow: ${AuthFlow}`);
585
+ }
586
+
587
+ // ============ Token Management ============
588
+
589
+ generateAccessToken(user, userPool, clientId) {
590
+ const payload = {
591
+ sub: user.UserId,
592
+ token_use: 'access',
593
+ client_id: clientId,
594
+ username: user.Username,
595
+ scope: 'aws.cognito.signin.user.admin',
596
+ iss: `https://cognito-idp.local/${userPool.Id}`,
597
+ exp: Math.floor(Date.now() / 1000) + 3600,
598
+ iat: Math.floor(Date.now() / 1000)
599
+ };
600
+
601
+ return jwt.sign(payload, this.jwtSecret, { algorithm: 'HS256' });
602
+ }
603
+
604
+ generateIdToken(user, userPool, clientId) {
605
+ const payload = {
606
+ sub: user.UserId,
607
+ token_use: 'id',
608
+ client_id: clientId,
609
+ email: user.Attributes.email,
610
+ email_verified: user.Attributes.email_verified || true,
611
+ username: user.Username,
612
+ iss: `https://cognito-idp.local/${userPool.Id}`,
613
+ exp: Math.floor(Date.now() / 1000) + 3600,
614
+ iat: Math.floor(Date.now() / 1000)
615
+ };
616
+
617
+ // Adiciona outros atributos do usuário
618
+ for (const [key, value] of Object.entries(user.Attributes)) {
619
+ if (key !== 'email' && key !== 'email_verified') {
620
+ payload[key] = value;
621
+ }
622
+ }
623
+
624
+ return jwt.sign(payload, this.jwtSecret, { algorithm: 'HS256' });
625
+ }
626
+
627
+ generateRefreshToken(user, userPool, clientId) {
628
+ const payload = {
629
+ sub: user.UserId,
630
+ token_use: 'refresh',
631
+ client_id: clientId,
632
+ username: user.Username,
633
+ iss: `https://cognito-idp.local/${userPool.Id}`,
634
+ exp: Math.floor(Date.now() / 1000) + 2592000, // 30 dias
635
+ iat: Math.floor(Date.now() / 1000)
636
+ };
637
+
638
+ return jwt.sign(payload, this.jwtSecret, { algorithm: 'HS256' });
639
+ }
640
+
641
+ verifyAccessToken(token) {
642
+ try {
643
+ const decoded = jwt.verify(token, this.jwtSecret);
644
+ const session = this.accessTokens.get(token);
645
+
646
+ if (!session || session.ExpiresAt < new Date().toISOString()) {
647
+ return null;
648
+ }
649
+
650
+ return decoded;
651
+ } catch (error) {
652
+ return null;
653
+ }
654
+ }
655
+
656
+ // ============ Admin Operations ============
657
+
658
+ adminGetUser(params) {
659
+ const { UserPoolId, Username } = params;
660
+ const userPool = this.userPools.get(UserPoolId);
661
+
662
+ if (!userPool) {
663
+ throw new Error(`User pool ${UserPoolId} not found`);
664
+ }
665
+
666
+ const user = this.findUserByUsername(Username, null, UserPoolId);
667
+ if (!user) {
668
+ throw new Error(`User not found: ${Username}`);
669
+ }
670
+
671
+ return {
672
+ Username: user.Username,
673
+ UserAttributes: this.formatUserAttributes(user.Attributes),
674
+ UserCreateDate: user.CreatedDate,
675
+ UserLastModifiedDate: user.LastModifiedDate,
676
+ Enabled: user.Enabled,
677
+ UserStatus: user.UserStatus,
678
+ MFAOptions: user.MfaOptions,
679
+ PreferredMfaSetting: user.PreferredMfaSetting,
680
+ UserMFASettingList: user.UserMFASettingList
681
+ };
682
+ }
683
+
684
+ adminCreateUser(params) {
685
+ const { UserPoolId, Username, UserAttributes, TemporaryPassword, DesiredDeliveryMediums } = params;
686
+ const userPool = this.userPools.get(UserPoolId);
687
+
688
+ if (!userPool) {
689
+ throw new Error(`User pool ${UserPoolId} not found`);
690
+ }
691
+
692
+ const userId = uuidv4();
693
+ const user = {
694
+ Username: Username,
695
+ UserPoolId: UserPoolId,
696
+ UserId: userId,
697
+ Attributes: this.normalizeUserAttributes(UserAttributes || []),
698
+ Enabled: true,
699
+ UserStatus: 'FORCE_CHANGE_PASSWORD',
700
+ CreatedDate: new Date().toISOString(),
701
+ LastModifiedDate: new Date().toISOString(),
702
+ Password: this.hashPassword(TemporaryPassword || 'Temp123!'),
703
+ MfaOptions: [],
704
+ PreferredMfaSetting: null,
705
+ UserMFASettingList: []
706
+ };
707
+
708
+ this.users.set(userId, user);
709
+ userPool.Users.push(userId);
710
+ userPool.EstimatedNumberOfUsers++;
711
+ this.persistUsers();
712
+ this.persistUserPools();
713
+
714
+ logger.debug(`👤 Usuário administrador criado: ${Username}`);
715
+
716
+ return {
717
+ User: {
718
+ Username: user.Username,
719
+ UserAttributes: this.formatUserAttributes(user.Attributes),
720
+ UserCreateDate: user.CreatedDate,
721
+ UserLastModifiedDate: user.LastModifiedDate,
722
+ Enabled: user.Enabled,
723
+ UserStatus: user.UserStatus
724
+ }
725
+ };
726
+ }
727
+
728
+ adminSetUserPassword(params) {
729
+ const { UserPoolId, Username, Password, Permanent } = params;
730
+ const user = this.findUserByUsername(Username, null, UserPoolId);
731
+
732
+ if (!user) {
733
+ throw new Error(`User not found: ${Username}`);
734
+ }
735
+
736
+ user.Password = this.hashPassword(Password);
737
+ if (Permanent) {
738
+ user.UserStatus = 'CONFIRMED';
739
+ }
740
+ user.LastModifiedDate = new Date().toISOString();
741
+ this.persistUsers();
742
+
743
+ return {};
744
+ }
745
+
746
+ adminDeleteUser(params) {
747
+ const { UserPoolId, Username } = params;
748
+ const user = this.findUserByUsername(Username, null, UserPoolId);
749
+
750
+ if (!user) {
751
+ throw new Error(`User not found: ${Username}`);
752
+ }
753
+
754
+ const userPool = this.userPools.get(UserPoolId);
755
+ if (userPool) {
756
+ const index = userPool.Users.indexOf(user.UserId);
757
+ if (index !== -1) {
758
+ userPool.Users.splice(index, 1);
759
+ userPool.EstimatedNumberOfUsers--;
760
+ }
761
+ }
762
+
763
+ this.users.delete(user.UserId);
764
+ this.persistUsers();
765
+ this.persistUserPools();
766
+
767
+ return {};
768
+ }
769
+
770
+ // ============ Helper Methods ============
771
+
772
+ findUserPoolByClientId(clientId) {
773
+ for (const userPool of this.userPools.values()) {
774
+ if (userPool.Clients.has(clientId)) {
775
+ return userPool;
776
+ }
777
+ }
778
+ return null;
779
+ }
780
+
781
+ findUserByUsername(username, clientId = null, userPoolId = null) {
782
+ let targetUserPoolId = userPoolId;
783
+
784
+ if (clientId && !targetUserPoolId) {
785
+ const userPool = this.findUserPoolByClientId(clientId);
786
+ if (userPool) {
787
+ targetUserPoolId = userPool.Id;
788
+ }
789
+ }
790
+
791
+ for (const user of this.users.values()) {
792
+ if (user.Username === username && user.UserPoolId === targetUserPoolId) {
793
+ return user;
794
+ }
795
+ }
796
+
797
+ return null;
798
+ }
799
+
800
+ normalizeUserAttributes(attributes) {
801
+ const normalized = {};
802
+ for (const attr of attributes) {
803
+ normalized[attr.Name] = attr.Value;
804
+ }
805
+ return normalized;
806
+ }
807
+
808
+ formatUserAttributes(attributes) {
809
+ return Object.entries(attributes).map(([Name, Value]) => ({ Name, Value }));
810
+ }
811
+
812
+ hashPassword(password) {
813
+ // Simulação de hash (não usar em produção real)
814
+ return crypto.createHash('sha256').update(password).digest('hex');
815
+ }
816
+
817
+ verifyPassword(password, hash) {
818
+ return this.hashPassword(password) === hash;
819
+ }
820
+
821
+ // ============ Identity Pool Operations ============
822
+
823
+ createIdentityPool(params) {
824
+ const { IdentityPoolName, AllowUnauthenticatedIdentities, SupportedLoginProviders, CognitoIdentityProviders } = params;
825
+
826
+ const identityPoolId = `local:${IdentityPoolName}_${Date.now()}`;
827
+ const identityPool = {
828
+ IdentityPoolId: identityPoolId,
829
+ IdentityPoolName: IdentityPoolName,
830
+ AllowUnauthenticatedIdentities: AllowUnauthenticatedIdentities || false,
831
+ SupportedLoginProviders: SupportedLoginProviders || {},
832
+ CognitoIdentityProviders: CognitoIdentityProviders || [],
833
+ Identities: new Map()
834
+ };
835
+
836
+ this.identityPools.set(identityPoolId, identityPool);
837
+ this.persistIdentityPools();
838
+
839
+ logger.debug(`✅ Identity Pool criado: ${IdentityPoolName} (${identityPoolId})`);
840
+
841
+ return {
842
+ IdentityPoolId: identityPoolId,
843
+ IdentityPoolName: identityPoolName,
844
+ AllowUnauthenticatedIdentities: identityPool.AllowUnauthenticatedIdentities
845
+ };
846
+ }
847
+
848
+ getId(params) {
849
+ const { IdentityPoolId, Logins } = params;
850
+ const identityPool = this.identityPools.get(IdentityPoolId);
851
+
852
+ if (!identityPool) {
853
+ throw new Error(`Identity pool ${IdentityPoolId} not found`);
854
+ }
855
+
856
+ let identityId = null;
857
+
858
+ if (Logins) {
859
+ // Procura identidade existente com os logins fornecidos
860
+ for (const [id, identity] of identityPool.Identities) {
861
+ if (identity.Logins && this.matchesLogins(identity.Logins, Logins)) {
862
+ identityId = id;
863
+ break;
864
+ }
865
+ }
866
+ }
867
+
868
+ if (!identityId) {
869
+ identityId = uuidv4();
870
+ identityPool.Identities.set(identityId, {
871
+ IdentityId: identityId,
872
+ Logins: Logins || {},
873
+ CreationDate: new Date().toISOString(),
874
+ LastModifiedDate: new Date().toISOString()
875
+ });
876
+ this.persistIdentityPools();
877
+ }
878
+
879
+ return {
880
+ IdentityId: identityId
881
+ };
882
+ }
883
+
884
+ getCredentialsForIdentity(params) {
885
+ const { IdentityId, Logins } = params;
886
+ const identityPool = this.findIdentityPoolByIdentityId(IdentityId);
887
+
888
+ if (!identityPool) {
889
+ throw new Error(`Identity ${IdentityId} not found`);
890
+ }
891
+
892
+ const identity = identityPool.Identities.get(IdentityId);
893
+ if (!identity) {
894
+ throw new Error(`Identity ${IdentityId} not found in pool`);
895
+ }
896
+
897
+ // Gera credenciais temporárias (simuladas)
898
+ const credentials = {
899
+ AccessKeyId: `AKIA${crypto.randomBytes(16).toString('hex').toUpperCase()}`,
900
+ SecretKey: crypto.randomBytes(32).toString('hex'),
901
+ SessionToken: crypto.randomBytes(64).toString('base64'),
902
+ Expiration: new Date(Date.now() + 3600000).toISOString()
903
+ };
904
+
905
+ return {
906
+ Credentials: credentials,
907
+ IdentityId: IdentityId
908
+ };
909
+ }
910
+
911
+ findIdentityPoolByIdentityId(identityId) {
912
+ for (const pool of this.identityPools.values()) {
913
+ if (pool.Identities.has(identityId)) {
914
+ return pool;
915
+ }
916
+ }
917
+ return null;
918
+ }
919
+
920
+ matchesLogins(existingLogins, newLogins) {
921
+ const existingKeys = Object.keys(existingLogins);
922
+ const newKeys = Object.keys(newLogins);
923
+
924
+ if (existingKeys.length !== newKeys.length) return false;
925
+
926
+ for (const key of existingKeys) {
927
+ if (existingLogins[key] !== newLogins[key]) {
928
+ return false;
929
+ }
930
+ }
931
+
932
+ return true;
933
+ }
934
+
935
+ // ============ Persistence ============
936
+
937
+ loadUserPools() {
938
+ // Load persisted pools first
939
+ const saved = this.store.read('__userpools__');
940
+ if (saved) {
941
+ for (const [id, data] of Object.entries(saved)) {
942
+ data.Clients = new Map(Object.entries(data.Clients || {}));
943
+ data.Groups = new Map(Object.entries(data.Groups || {}));
944
+ data.IdentityProviders = new Map(Object.entries(data.IdentityProviders || {}));
945
+ data.ResourceServers = new Map(Object.entries(data.ResourceServers || {}));
946
+ this.userPools.set(id, data);
947
+ }
948
+ }
949
+
950
+ // Create user pools from config if not already persisted
951
+ if (this.config.cognito?.userPools) {
952
+ let configChanged = false;
953
+ const configPath = this.config._configPath;
954
+
955
+ for (let i = 0; i < this.config.cognito.userPools.length; i++) {
956
+ const poolConfig = this.config.cognito.userPools[i];
957
+ const existing = Array.from(this.userPools.values()).find(p => p.Name === poolConfig.PoolName);
958
+
959
+ if (!existing) {
960
+ const result = this.createUserPool(poolConfig);
961
+ const poolId = result.UserPool.Id;
962
+ logger.debug(`✅ User Pool criado a partir da config: ${poolConfig.PoolName} (${poolId})`);
963
+
964
+ // Auto-create a default client if not specified
965
+ if (!poolConfig.ClientId) {
966
+ const clientResult = this.createUserPoolClient({
967
+ UserPoolId: poolId,
968
+ ClientName: `${poolConfig.PoolName}-client`,
969
+ GenerateSecret: false
970
+ });
971
+ const clientId = clientResult.UserPoolClient.ClientId;
972
+ this.config.cognito.userPools[i].ClientId = clientId;
973
+ this.config.cognito.userPools[i].UserPoolId = poolId;
974
+ configChanged = true;
975
+ logger.debug(`✅ Client criado automaticamente: ${clientId}`);
976
+ }
977
+ } else if (!poolConfig.ClientId) {
978
+ // Pool exists but no clientId in config — write it back
979
+ const firstClient = existing.Clients.size > 0 ? existing.Clients.values().next().value : null;
980
+ if (firstClient) {
981
+ this.config.cognito.userPools[i].ClientId = firstClient.ClientId;
982
+ this.config.cognito.userPools[i].UserPoolId = existing.Id;
983
+ configChanged = true;
984
+ }
985
+ }
986
+ }
987
+
988
+ // Write clientId back to aws-local-simulator.json
989
+ if (configChanged && configPath) {
990
+ try {
991
+ const fs = require('fs');
992
+ const fileContent = JSON.parse(fs.readFileSync(configPath, 'utf8'));
993
+ fileContent.cognito = fileContent.cognito || {};
994
+ fileContent.cognito.userPools = this.config.cognito.userPools.map(p => ({
995
+ PoolName: p.PoolName,
996
+ AutoVerifiedAttributes: p.AutoVerifiedAttributes,
997
+ UserPoolId: p.UserPoolId,
998
+ ClientId: p.ClientId
999
+ }));
1000
+ fs.writeFileSync(configPath, JSON.stringify(fileContent, null, 2));
1001
+ logger.info(`✅ ClientId gravado em: ${configPath}`);
1002
+ } catch (err) {
1003
+ logger.warn(`⚠️ Não foi possível gravar clientId no config: ${err.message}`);
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+
1009
+ loadIdentityPools() {
1010
+ const saved = this.store.read('__identitypools__');
1011
+ if (saved) {
1012
+ for (const [id, data] of Object.entries(saved)) {
1013
+ data.Identities = new Map(Object.entries(data.Identities || {}));
1014
+ this.identityPools.set(id, data);
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ loadUsers() {
1020
+ const saved = this.store.read('__users__');
1021
+ if (saved) {
1022
+ for (const [id, user] of Object.entries(saved)) {
1023
+ this.users.set(id, user);
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ loadSessions() {
1029
+ const saved = this.store.read('__sessions__');
1030
+ if (saved) {
1031
+ for (const [id, session] of Object.entries(saved)) {
1032
+ this.sessions.set(id, session);
1033
+ this.accessTokens.set(session.AccessToken, session);
1034
+ this.refreshTokens.set(session.RefreshToken, session);
1035
+ }
1036
+ }
1037
+ }
1038
+
1039
+ persistUserPools() {
1040
+ const poolsObj = {};
1041
+ for (const [id, pool] of this.userPools.entries()) {
1042
+ poolsObj[id] = {
1043
+ ...pool,
1044
+ Clients: Object.fromEntries(pool.Clients),
1045
+ Groups: Object.fromEntries(pool.Groups),
1046
+ IdentityProviders: Object.fromEntries(pool.IdentityProviders),
1047
+ ResourceServers: Object.fromEntries(pool.ResourceServers)
1048
+ };
1049
+ }
1050
+ this.store.write('__userpools__', poolsObj);
1051
+ }
1052
+
1053
+ persistIdentityPools() {
1054
+ const poolsObj = {};
1055
+ for (const [id, pool] of this.identityPools.entries()) {
1056
+ poolsObj[id] = {
1057
+ ...pool,
1058
+ Identities: Object.fromEntries(pool.Identities)
1059
+ };
1060
+ }
1061
+ this.store.write('__identitypools__', poolsObj);
1062
+ }
1063
+
1064
+ persistUsers() {
1065
+ const usersObj = {};
1066
+ for (const [id, user] of this.users.entries()) {
1067
+ usersObj[id] = user;
1068
+ }
1069
+ this.store.write('__users__', usersObj);
1070
+ }
1071
+
1072
+ persistSessions() {
1073
+ const sessionsObj = {};
1074
+ for (const [id, session] of this.sessions.entries()) {
1075
+ sessionsObj[id] = session;
1076
+ }
1077
+ this.store.write('__sessions__', sessionsObj);
1078
+ }
1079
+
1080
+ async reset() {
1081
+ this.userPools.clear();
1082
+ this.identityPools.clear();
1083
+ this.users.clear();
1084
+ this.sessions.clear();
1085
+ this.accessTokens.clear();
1086
+ this.refreshTokens.clear();
1087
+
1088
+ this.persistUserPools();
1089
+ this.persistIdentityPools();
1090
+ this.persistUsers();
1091
+ this.persistSessions();
1092
+
1093
+ logger.debug('Cognito: Todos os dados resetados');
1094
+ }
1095
+
1096
+ // ============ Stats ============
1097
+
1098
+ getUserPoolsCount() {
1099
+ return this.userPools.size;
1100
+ }
1101
+
1102
+ getTotalUsersCount() {
1103
+ return this.users.size;
1104
+ }
1105
+
1106
+ getIdentityPoolsCount() {
1107
+ return this.identityPools.size;
1108
+ }
1109
+
1110
+ getActiveSessionsCount() {
1111
+ return this.sessions.size;
1112
+ }
1113
+ }
1114
+
848
1115
  module.exports = CognitoSimulator;