@nauth-toolkit/core 0.1.6 → 0.1.9

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 (133) hide show
  1. package/dist/adapters/express.adapter.js +1 -1
  2. package/dist/adapters/express.adapter.js.map +1 -1
  3. package/dist/adapters.d.ts +2 -0
  4. package/dist/adapters.d.ts.map +1 -0
  5. package/dist/adapters.js +18 -0
  6. package/dist/adapters.js.map +1 -0
  7. package/dist/dto/admin-set-password.dto.d.ts +12 -0
  8. package/dist/dto/admin-set-password.dto.d.ts.map +1 -0
  9. package/dist/dto/admin-set-password.dto.js +62 -0
  10. package/dist/dto/admin-set-password.dto.js.map +1 -0
  11. package/dist/dto/confirm-forgot-password.dto.d.ts +10 -0
  12. package/dist/dto/confirm-forgot-password.dto.d.ts.map +1 -0
  13. package/dist/dto/confirm-forgot-password.dto.js +58 -0
  14. package/dist/dto/confirm-forgot-password.dto.js.map +1 -0
  15. package/dist/dto/forgot-password.dto.d.ts +10 -0
  16. package/dist/dto/forgot-password.dto.d.ts.map +1 -0
  17. package/dist/dto/forgot-password.dto.js +43 -0
  18. package/dist/dto/forgot-password.dto.js.map +1 -0
  19. package/dist/dto/index.d.ts +3 -0
  20. package/dist/dto/index.d.ts.map +1 -1
  21. package/dist/dto/index.js +3 -0
  22. package/dist/dto/index.js.map +1 -1
  23. package/dist/dto.d.ts +2 -0
  24. package/dist/dto.d.ts.map +1 -0
  25. package/dist/dto.js +18 -0
  26. package/dist/dto.js.map +1 -0
  27. package/dist/entities/challenge-session.entity.d.ts +3 -3
  28. package/dist/entities/challenge-session.entity.d.ts.map +1 -1
  29. package/dist/entities/user.entity.d.ts +19 -19
  30. package/dist/entities/user.entity.d.ts.map +1 -1
  31. package/dist/entities.d.ts +2 -0
  32. package/dist/entities.d.ts.map +1 -0
  33. package/dist/entities.js +18 -0
  34. package/dist/entities.js.map +1 -0
  35. package/dist/enums/error-codes.enum.d.ts +4 -0
  36. package/dist/enums/error-codes.enum.d.ts.map +1 -1
  37. package/dist/enums/error-codes.enum.js +4 -0
  38. package/dist/enums/error-codes.enum.js.map +1 -1
  39. package/dist/enums/risk-factor.enum.d.ts +1 -0
  40. package/dist/enums/risk-factor.enum.d.ts.map +1 -1
  41. package/dist/enums/risk-factor.enum.js +1 -0
  42. package/dist/enums/risk-factor.enum.js.map +1 -1
  43. package/dist/handlers/token-delivery.handler.d.ts +2 -1
  44. package/dist/handlers/token-delivery.handler.d.ts.map +1 -1
  45. package/dist/handlers/token-delivery.handler.js +7 -1
  46. package/dist/handlers/token-delivery.handler.js.map +1 -1
  47. package/dist/interfaces/config.interface.d.ts +10 -1
  48. package/dist/interfaces/config.interface.d.ts.map +1 -1
  49. package/dist/interfaces.d.ts +2 -0
  50. package/dist/interfaces.d.ts.map +1 -0
  51. package/dist/interfaces.js +18 -0
  52. package/dist/interfaces.js.map +1 -0
  53. package/dist/internal.d.ts +1 -0
  54. package/dist/internal.d.ts.map +1 -1
  55. package/dist/internal.js +3 -1
  56. package/dist/internal.js.map +1 -1
  57. package/dist/schemas/auth-config.schema.d.ts +147 -53
  58. package/dist/schemas/auth-config.schema.d.ts.map +1 -1
  59. package/dist/schemas/auth-config.schema.js +17 -1
  60. package/dist/schemas/auth-config.schema.js.map +1 -1
  61. package/dist/services/auth-audit.service.js.map +1 -1
  62. package/dist/services/auth-challenge-helper.service.js +1 -1
  63. package/dist/services/auth-challenge-helper.service.js.map +1 -1
  64. package/dist/services/auth-flow-context-builder.service.d.ts.map +1 -1
  65. package/dist/services/auth-flow-context-builder.service.js.map +1 -1
  66. package/dist/services/auth-flow-state-machine.service.js +1 -1
  67. package/dist/services/auth-flow-state-machine.service.js.map +1 -1
  68. package/dist/services/auth.service.d.ts +10 -1
  69. package/dist/services/auth.service.d.ts.map +1 -1
  70. package/dist/services/auth.service.js +240 -62
  71. package/dist/services/auth.service.js.map +1 -1
  72. package/dist/services/csrf.service.d.ts +2 -1
  73. package/dist/services/csrf.service.d.ts.map +1 -1
  74. package/dist/services/csrf.service.js.map +1 -1
  75. package/dist/services/geo-location.service.d.ts.map +1 -1
  76. package/dist/services/geo-location.service.js +9 -8
  77. package/dist/services/geo-location.service.js.map +1 -1
  78. package/dist/services/jwt.service.d.ts +3 -0
  79. package/dist/services/jwt.service.d.ts.map +1 -1
  80. package/dist/services/jwt.service.js +22 -3
  81. package/dist/services/jwt.service.js.map +1 -1
  82. package/dist/services/password-reset.service.d.ts +32 -0
  83. package/dist/services/password-reset.service.d.ts.map +1 -0
  84. package/dist/services/password-reset.service.js +198 -0
  85. package/dist/services/password-reset.service.js.map +1 -0
  86. package/dist/services/password.service.d.ts.map +1 -1
  87. package/dist/services/password.service.js +7 -0
  88. package/dist/services/password.service.js.map +1 -1
  89. package/dist/services/risk-detection.service.d.ts.map +1 -1
  90. package/dist/services/risk-detection.service.js +8 -0
  91. package/dist/services/risk-detection.service.js.map +1 -1
  92. package/dist/services/risk-scoring.service.d.ts.map +1 -1
  93. package/dist/services/risk-scoring.service.js +1 -0
  94. package/dist/services/risk-scoring.service.js.map +1 -1
  95. package/dist/services/session.service.js.map +1 -1
  96. package/dist/services/social-auth-base.service.d.ts +5 -5
  97. package/dist/services/social-auth-base.service.d.ts.map +1 -1
  98. package/dist/services/social-auth-base.service.js +5 -4
  99. package/dist/services/social-auth-base.service.js.map +1 -1
  100. package/dist/services/social-auth.service.d.ts +1 -1
  101. package/dist/services/social-auth.service.d.ts.map +1 -1
  102. package/dist/services/social-auth.service.js.map +1 -1
  103. package/dist/storage.d.ts +2 -0
  104. package/dist/storage.d.ts.map +1 -0
  105. package/dist/storage.js +18 -0
  106. package/dist/storage.js.map +1 -0
  107. package/dist/templates.d.ts +2 -0
  108. package/dist/templates.d.ts.map +1 -0
  109. package/dist/templates.js +18 -0
  110. package/dist/templates.js.map +1 -0
  111. package/dist/utils/ip-extractor.d.ts +12 -1
  112. package/dist/utils/ip-extractor.d.ts.map +1 -1
  113. package/dist/utils/ip-extractor.js +3 -2
  114. package/dist/utils/ip-extractor.js.map +1 -1
  115. package/dist/utils/setup/init-services.d.ts.map +1 -1
  116. package/dist/utils/setup/init-services.js +24 -13
  117. package/dist/utils/setup/init-services.js.map +1 -1
  118. package/dist/utils/setup/init-social.d.ts +4 -3
  119. package/dist/utils/setup/init-social.d.ts.map +1 -1
  120. package/dist/utils/setup/init-social.js +38 -15
  121. package/dist/utils/setup/init-social.js.map +1 -1
  122. package/dist/utils/setup/init-storage.d.ts +2 -2
  123. package/dist/utils/setup/init-storage.d.ts.map +1 -1
  124. package/dist/utils/setup/init-storage.js +26 -9
  125. package/dist/utils/setup/init-storage.js.map +1 -1
  126. package/dist/utils/setup/register-mfa.d.ts.map +1 -1
  127. package/dist/utils/setup/register-mfa.js +50 -22
  128. package/dist/utils/setup/register-mfa.js.map +1 -1
  129. package/dist/utils.d.ts +2 -0
  130. package/dist/utils.d.ts.map +1 -0
  131. package/dist/utils.js +18 -0
  132. package/dist/utils.js.map +1 -0
  133. package/package.json +1 -1
@@ -45,6 +45,7 @@ const verify_phone_by_sub_dto_1 = require("../dto/verify-phone-by-sub.dto");
45
45
  const nauth_exception_1 = require("../exceptions/nauth.exception");
46
46
  const error_codes_enum_1 = require("../enums/error-codes.enum");
47
47
  const mfa_method_enum_1 = require("../enums/mfa-method.enum");
48
+ const class_validator_1 = require("class-validator");
48
49
  const crypto = __importStar(require("crypto"));
49
50
  const DUMMY_ARGON2_HASH = '$argon2id$v=19$m=65536,t=3,p=4$RFVNTVlfU0FMVF9GT1JfVElNSU5H$dummyhashfordummyhashfordummyhash1234567890';
50
51
  class AuthService {
@@ -65,7 +66,8 @@ class AuthService {
65
66
  mfaService;
66
67
  mfaDeviceRepository;
67
68
  trustedDeviceService;
68
- constructor(userRepository, loginAttemptRepository, passwordService, jwtService, sessionService, challengeService, challengeHelper, emailVerificationService, clientInfoService, accountLockoutStorage, config, logger, auditService, phoneVerificationService, mfaService, mfaDeviceRepository, trustedDeviceService) {
69
+ passwordResetService;
70
+ constructor(userRepository, loginAttemptRepository, passwordService, jwtService, sessionService, challengeService, challengeHelper, emailVerificationService, clientInfoService, accountLockoutStorage, config, logger, auditService, phoneVerificationService, mfaService, mfaDeviceRepository, trustedDeviceService, passwordResetService) {
69
71
  this.userRepository = userRepository;
70
72
  this.loginAttemptRepository = loginAttemptRepository;
71
73
  this.passwordService = passwordService;
@@ -83,6 +85,7 @@ class AuthService {
83
85
  this.mfaService = mfaService;
84
86
  this.mfaDeviceRepository = mfaDeviceRepository;
85
87
  this.trustedDeviceService = trustedDeviceService;
88
+ this.passwordResetService = passwordResetService;
86
89
  this.logger?.log?.('AuthService initialized');
87
90
  }
88
91
  async signup(dto) {
@@ -427,7 +430,7 @@ class AuthService {
427
430
  }
428
431
  }
429
432
  }
430
- catch (error) {
433
+ catch {
431
434
  this.logger?.debug?.('Failed to extract sessionId/deviceId from token for audit');
432
435
  }
433
436
  const isTrustedDevice = response.trusted || false;
@@ -1150,31 +1153,19 @@ class AuthService {
1150
1153
  throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.CHALLENGE_INVALID, 'User not found in challenge session');
1151
1154
  }
1152
1155
  this.logger?.log?.(`Changing password for user: ${user.sub}`);
1153
- const validation = await this.passwordService.validatePassword(newPassword, {
1154
- email: user.email,
1155
- username: user.username || undefined,
1156
+ await this.updateUserPassword({
1157
+ user,
1158
+ newPassword,
1159
+ mustChangePassword: false,
1160
+ revokeSessions: true,
1161
+ revokeReason: 'Password changed (force change password)',
1162
+ audit: {
1163
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.PASSWORD_CHANGED,
1164
+ eventStatus: 'SUCCESS',
1165
+ reason: 'force_change_password',
1166
+ description: 'Password changed due to FORCE_CHANGE_PASSWORD challenge',
1167
+ },
1156
1168
  });
1157
- if (!validation.valid) {
1158
- throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.WEAK_PASSWORD, validation.errors.join(', '), {
1159
- errors: validation.errors,
1160
- });
1161
- }
1162
- if (this.config.password?.historyCount) {
1163
- const historyToCheck = user.passwordHistory || [];
1164
- const allPreviousPasswords = user.passwordHash ? [user.passwordHash, ...historyToCheck] : historyToCheck;
1165
- const isReused = await this.passwordService.isPasswordInHistory(newPassword, allPreviousPasswords);
1166
- if (isReused) {
1167
- throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_REUSED, 'You have used this password recently. Please choose a different password.');
1168
- }
1169
- }
1170
- const newHash = await this.passwordService.hashPassword(newPassword);
1171
- const newHistory = this.passwordService.addToHistory(user.passwordHistory || [], user.passwordHash);
1172
- user.passwordHash = newHash;
1173
- user.passwordChangedAt = new Date();
1174
- user.passwordHistory = newHistory;
1175
- user.mustChangePassword = false;
1176
- await this.userRepository.save(user);
1177
- this.logger?.log?.(`Password changed successfully for user: ${user.sub}`);
1178
1169
  await this.challengeService.validateAndConsumeSession(challengeSession.sessionToken, auth_challenge_dto_1.AuthChallenge.FORCE_CHANGE_PASSWORD);
1179
1170
  const updatedUser = await this.userRepository.findOne({ where: { sub: user.sub } });
1180
1171
  if (!updatedUser) {
@@ -1864,47 +1855,20 @@ class AuthService {
1864
1855
  if (!isValid) {
1865
1856
  throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_INCORRECT, 'Current password is incorrect');
1866
1857
  }
1867
- const validation = await this.passwordService.validatePassword(dto.newPassword, {
1868
- email: user.email,
1869
- username: user.username || undefined,
1870
- });
1871
- if (!validation.valid) {
1872
- throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.WEAK_PASSWORD, validation.errors.join(', '), {
1873
- errors: validation.errors,
1874
- });
1875
- }
1876
- if (this.config.password?.historyCount) {
1877
- const historyToCheck = user.passwordHistory || [];
1878
- const allPreviousPasswords = user.passwordHash ? [user.passwordHash, ...historyToCheck] : historyToCheck;
1879
- const isReused = await this.passwordService.isPasswordInHistory(dto.newPassword, allPreviousPasswords);
1880
- if (isReused) {
1881
- throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_REUSED, 'You have used this password recently. Please choose a different password.');
1882
- }
1883
- }
1884
- const newHash = await this.passwordService.hashPassword(dto.newPassword);
1885
- const newHistory = this.passwordService.addToHistory(user.passwordHistory || [], user.passwordHash);
1886
- user.passwordHash = newHash;
1887
- user.passwordChangedAt = new Date();
1888
- user.passwordHistory = newHistory;
1889
- await this.userRepository.save(user);
1890
1858
  if (this.config.hooks?.afterPasswordChange) {
1891
1859
  await this.config.hooks.afterPasswordChange(dto.sub);
1892
1860
  }
1893
- await this.sessionService.revokeAllUserSessions(user.id, 'Password changed');
1894
- try {
1895
- await this.auditService?.recordEvent({
1896
- userId: user.id,
1861
+ await this.updateUserPassword({
1862
+ user,
1863
+ newPassword: dto.newPassword,
1864
+ mustChangePassword: false,
1865
+ revokeSessions: true,
1866
+ revokeReason: 'Password changed',
1867
+ audit: {
1897
1868
  eventType: auth_audit_event_type_enum_1.AuthAuditEventType.PASSWORD_CHANGED,
1898
1869
  eventStatus: 'SUCCESS',
1899
- });
1900
- }
1901
- catch (auditError) {
1902
- const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
1903
- this.logger?.error?.(`Failed to record PASSWORD_CHANGED audit event: ${errorMessage}`, {
1904
- error: auditError,
1905
- userId: user.id,
1906
- });
1907
- }
1870
+ },
1871
+ });
1908
1872
  return { success: true };
1909
1873
  }
1910
1874
  async updateUserAttributes(dto) {
@@ -2351,6 +2315,220 @@ class AuthService {
2351
2315
  this.logger?.log?.(`Must-change-password flag set for user: ${dto.userId}`);
2352
2316
  return { success: true };
2353
2317
  }
2318
+ async adminSetPassword(dto) {
2319
+ this.logger?.log?.(`Admin password reset requested for identifier: ${dto.identifier}`);
2320
+ this.logger?.debug?.(`Reset details: { identifier: ${dto.identifier}, mustChangePassword: ${dto.mustChangePassword ?? true}, revokeSessions: ${dto.revokeSessions ?? true} }`);
2321
+ let user = null;
2322
+ if ((0, class_validator_1.isUUID)(dto.identifier)) {
2323
+ this.logger?.debug?.(`Identifier appears to be UUID, searching by sub: ${dto.identifier}`);
2324
+ user = (await this.userRepository.findOne({ where: { sub: dto.identifier } }));
2325
+ }
2326
+ if (!user) {
2327
+ this.logger?.debug?.(`Searching by identifier (email/username/phone): ${dto.identifier}`);
2328
+ user = await this.findUserByIdentifier(dto.identifier);
2329
+ }
2330
+ if (!user) {
2331
+ this.logger?.warn?.(`Password reset failed - user not found: ${dto.identifier}`);
2332
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
2333
+ }
2334
+ if (!user.passwordHash) {
2335
+ this.logger?.warn?.(`Password reset failed - user doesn't have a password (pure social signup): ${user.sub}`);
2336
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_CHANGE_NOT_ALLOWED, 'Password reset not available. This account uses social authentication only and has no password.');
2337
+ }
2338
+ const mustChangePassword = dto.mustChangePassword ?? true;
2339
+ const revokeSessions = dto.revokeSessions !== false;
2340
+ const { sessionsRevoked } = await this.updateUserPassword({
2341
+ user,
2342
+ newPassword: dto.newPassword,
2343
+ mustChangePassword,
2344
+ revokeSessions,
2345
+ revokeReason: 'Password reset by administrator',
2346
+ audit: {
2347
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.PASSWORD_RESET_COMPLETED,
2348
+ eventStatus: 'SUCCESS',
2349
+ reason: 'admin_reset',
2350
+ description: 'Password reset by administrator',
2351
+ metadata: {
2352
+ identifier: dto.identifier,
2353
+ mustChangePassword,
2354
+ },
2355
+ },
2356
+ });
2357
+ return {
2358
+ success: true,
2359
+ mustChangePassword,
2360
+ sessionsRevoked,
2361
+ };
2362
+ }
2363
+ async forgotPassword(dto) {
2364
+ const response = { success: true };
2365
+ if (!this.passwordResetService) {
2366
+ this.logger?.warn?.('PasswordResetService not configured; forgotPassword will not send any delivery');
2367
+ return response;
2368
+ }
2369
+ if (this.config.login?.identifierType &&
2370
+ !this.validateIdentifierType(dto.identifier, this.config.login.identifierType)) {
2371
+ return response;
2372
+ }
2373
+ const user = await this.findUserByIdentifier(dto.identifier, this.config.login?.identifierType);
2374
+ if (!user) {
2375
+ return response;
2376
+ }
2377
+ if (!user.passwordHash) {
2378
+ this.logger?.warn?.(`Password reset requested for social-only account; ignoring for user: ${user.sub}`);
2379
+ try {
2380
+ await this.auditService?.recordEvent({
2381
+ userId: user.id,
2382
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.PASSWORD_RESET_REQUESTED,
2383
+ eventStatus: 'SUSPICIOUS',
2384
+ authMethod: 'social',
2385
+ reason: 'forgot_password_social_only',
2386
+ description: 'Password reset requested for social-only account (ignored)',
2387
+ });
2388
+ }
2389
+ catch (auditError) {
2390
+ const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
2391
+ this.logger?.error?.(`Failed to record PASSWORD_RESET_REQUESTED audit event: ${errorMessage}`, {
2392
+ error: auditError,
2393
+ userId: user.id,
2394
+ });
2395
+ }
2396
+ return response;
2397
+ }
2398
+ const verificationMethod = this.config.signup?.verificationMethod ?? 'email';
2399
+ let delivery;
2400
+ if (verificationMethod === 'none') {
2401
+ if (user.email)
2402
+ delivery = 'email';
2403
+ else if (user.phone)
2404
+ delivery = 'sms';
2405
+ }
2406
+ else if (verificationMethod === 'email') {
2407
+ if (user.isEmailVerified && user.email)
2408
+ delivery = 'email';
2409
+ }
2410
+ else if (verificationMethod === 'phone') {
2411
+ if (user.isPhoneVerified && user.phone)
2412
+ delivery = 'sms';
2413
+ }
2414
+ else if (verificationMethod === 'both') {
2415
+ if (user.isEmailVerified && user.email)
2416
+ delivery = 'email';
2417
+ else if (user.isPhoneVerified && user.phone)
2418
+ delivery = 'sms';
2419
+ }
2420
+ if (!delivery) {
2421
+ return response;
2422
+ }
2423
+ try {
2424
+ const result = await this.passwordResetService.requestReset(user, delivery);
2425
+ response.destination = result.destination;
2426
+ response.deliveryMedium = result.deliveryMedium;
2427
+ response.expiresIn = result.expiresIn;
2428
+ }
2429
+ catch (error) {
2430
+ if (error instanceof nauth_exception_1.NAuthException && error.code === error_codes_enum_1.AuthErrorCode.RATE_LIMIT_PASSWORD_RESET) {
2431
+ throw error;
2432
+ }
2433
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
2434
+ this.logger?.error?.(`Failed to send password reset code: ${errorMessage}`, { error });
2435
+ }
2436
+ return response;
2437
+ }
2438
+ async confirmForgotPassword(dto) {
2439
+ if (!this.passwordResetService) {
2440
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.SERVICE_UNAVAILABLE, 'Password reset is not available');
2441
+ }
2442
+ const user = await this.findUserByIdentifier(dto.identifier, this.config.login?.identifierType);
2443
+ if (!user || !user.passwordHash) {
2444
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_RESET_CODE_INVALID, 'Invalid password reset code');
2445
+ }
2446
+ const { sessionsRevoked: _sessionsRevoked } = await this.updateUserPassword({
2447
+ user,
2448
+ newPassword: dto.newPassword,
2449
+ mustChangePassword: false,
2450
+ revokeSessions: true,
2451
+ revokeReason: 'Password reset',
2452
+ beforePersist: async () => {
2453
+ await this.passwordResetService.consumeValidCode(user, dto.code);
2454
+ },
2455
+ audit: {
2456
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.PASSWORD_RESET_COMPLETED,
2457
+ eventStatus: 'SUCCESS',
2458
+ authMethod: 'password',
2459
+ description: 'Password reset completed by user',
2460
+ reason: 'forgot_password',
2461
+ },
2462
+ });
2463
+ return { success: true, mustChangePassword: false };
2464
+ }
2465
+ async updateUserPassword(params) {
2466
+ const { user, newPassword, mustChangePassword, revokeSessions, revokeReason, beforePersist, audit } = params;
2467
+ const userEntity = (await this.userRepository.findOne({ where: { id: user.id } }));
2468
+ if (!userEntity) {
2469
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
2470
+ }
2471
+ const validation = await this.passwordService.validatePassword(newPassword, {
2472
+ email: userEntity.email,
2473
+ username: userEntity.username || undefined,
2474
+ });
2475
+ if (!validation.valid) {
2476
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.WEAK_PASSWORD, validation.errors.join(', '), {
2477
+ errors: validation.errors,
2478
+ });
2479
+ }
2480
+ if (this.config.password?.historyCount) {
2481
+ const historyToCheck = userEntity.passwordHistory || [];
2482
+ const allPreviousPasswords = userEntity.passwordHash
2483
+ ? [userEntity.passwordHash, ...historyToCheck]
2484
+ : historyToCheck;
2485
+ const isReused = await this.passwordService.isPasswordInHistory(newPassword, allPreviousPasswords);
2486
+ if (isReused) {
2487
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_REUSED, 'Cannot reuse a recent password');
2488
+ }
2489
+ }
2490
+ if (beforePersist) {
2491
+ await beforePersist();
2492
+ }
2493
+ const newHash = await this.passwordService.hashPassword(newPassword);
2494
+ const newHistory = userEntity.passwordHash
2495
+ ? this.passwordService.addToHistory(userEntity.passwordHistory || [], userEntity.passwordHash)
2496
+ : userEntity.passwordHistory || [];
2497
+ userEntity.passwordHash = newHash;
2498
+ userEntity.passwordChangedAt = new Date();
2499
+ userEntity.passwordHistory = newHistory;
2500
+ userEntity.mustChangePassword = mustChangePassword;
2501
+ await this.userRepository.save(userEntity);
2502
+ let sessionsRevoked = 0;
2503
+ if (revokeSessions) {
2504
+ sessionsRevoked = await this.sessionService.revokeAllUserSessions(userEntity.id, revokeReason);
2505
+ }
2506
+ if (audit) {
2507
+ try {
2508
+ await this.auditService?.recordEvent({
2509
+ userId: userEntity.id,
2510
+ eventType: audit.eventType,
2511
+ eventStatus: audit.eventStatus,
2512
+ reason: audit.reason,
2513
+ description: audit.description,
2514
+ authMethod: audit.authMethod,
2515
+ metadata: {
2516
+ ...audit.metadata,
2517
+ mustChangePassword,
2518
+ sessionsRevoked,
2519
+ },
2520
+ });
2521
+ }
2522
+ catch (auditError) {
2523
+ const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
2524
+ this.logger?.error?.(`Failed to record ${audit.eventType} audit event: ${errorMessage}`, {
2525
+ error: auditError,
2526
+ userId: userEntity.id,
2527
+ });
2528
+ }
2529
+ }
2530
+ return { sessionsRevoked };
2531
+ }
2354
2532
  }
2355
2533
  exports.AuthService = AuthService;
2356
2534
  //# sourceMappingURL=auth.service.js.map