@nauth-toolkit/core 0.1.87 → 0.1.89

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 (174) hide show
  1. package/dist/dto/admin-get-mfa-status.dto.d.ts +20 -0
  2. package/dist/dto/admin-get-mfa-status.dto.d.ts.map +1 -0
  3. package/dist/dto/{change-password-request.dto.js → admin-get-mfa-status.dto.js} +22 -32
  4. package/dist/dto/admin-get-mfa-status.dto.js.map +1 -0
  5. package/dist/dto/admin-get-user-auth-history.dto.d.ts +62 -0
  6. package/dist/dto/admin-get-user-auth-history.dto.d.ts.map +1 -0
  7. package/dist/dto/admin-get-user-auth-history.dto.js +87 -0
  8. package/dist/dto/admin-get-user-auth-history.dto.js.map +1 -0
  9. package/dist/dto/admin-logout-all.dto.d.ts +48 -0
  10. package/dist/dto/admin-logout-all.dto.d.ts.map +1 -0
  11. package/dist/dto/admin-logout-all.dto.js +85 -0
  12. package/dist/dto/admin-logout-all.dto.js.map +1 -0
  13. package/dist/dto/admin-remove-devices.dto.d.ts +25 -0
  14. package/dist/dto/admin-remove-devices.dto.d.ts.map +1 -0
  15. package/dist/dto/admin-remove-devices.dto.js +50 -0
  16. package/dist/dto/admin-remove-devices.dto.js.map +1 -0
  17. package/dist/dto/admin-reset-password.dto.d.ts +15 -19
  18. package/dist/dto/admin-reset-password.dto.d.ts.map +1 -1
  19. package/dist/dto/admin-reset-password.dto.js +21 -41
  20. package/dist/dto/admin-reset-password.dto.js.map +1 -1
  21. package/dist/dto/admin-revoke-session.dto.d.ts +22 -0
  22. package/dist/dto/admin-revoke-session.dto.d.ts.map +1 -0
  23. package/dist/dto/admin-revoke-session.dto.js +48 -0
  24. package/dist/dto/admin-revoke-session.dto.js.map +1 -0
  25. package/dist/dto/admin-set-password.dto.d.ts +8 -10
  26. package/dist/dto/admin-set-password.dto.d.ts.map +1 -1
  27. package/dist/dto/admin-set-password.dto.js +11 -21
  28. package/dist/dto/admin-set-password.dto.js.map +1 -1
  29. package/dist/dto/admin-set-preferred-method.dto.d.ts +25 -0
  30. package/dist/dto/admin-set-preferred-method.dto.d.ts.map +1 -0
  31. package/dist/dto/admin-set-preferred-method.dto.js +50 -0
  32. package/dist/dto/admin-set-preferred-method.dto.js.map +1 -0
  33. package/dist/dto/admin-update-user-attributes.dto.d.ts +41 -0
  34. package/dist/dto/admin-update-user-attributes.dto.d.ts.map +1 -0
  35. package/dist/dto/{update-user-attributes-request.dto.js → admin-update-user-attributes.dto.js} +12 -17
  36. package/dist/dto/admin-update-user-attributes.dto.js.map +1 -0
  37. package/dist/dto/auth-challenge.dto.d.ts +2 -2
  38. package/dist/dto/auth-challenge.dto.d.ts.map +1 -1
  39. package/dist/dto/auth-challenge.dto.js +3 -3
  40. package/dist/dto/auth-challenge.dto.js.map +1 -1
  41. package/dist/dto/auth-response.dto.d.ts +1 -1
  42. package/dist/dto/auth-response.dto.d.ts.map +1 -1
  43. package/dist/dto/auth-response.dto.js +1 -1
  44. package/dist/dto/auth-response.dto.js.map +1 -1
  45. package/dist/dto/get-mfa-status.dto.d.ts +3 -32
  46. package/dist/dto/get-mfa-status.dto.d.ts.map +1 -1
  47. package/dist/dto/get-mfa-status.dto.js +4 -55
  48. package/dist/dto/get-mfa-status.dto.js.map +1 -1
  49. package/dist/dto/get-risk-assessment-history.dto.d.ts +3 -3
  50. package/dist/dto/get-risk-assessment-history.dto.d.ts.map +1 -1
  51. package/dist/dto/get-risk-assessment-history.dto.js +5 -5
  52. package/dist/dto/get-risk-assessment-history.dto.js.map +1 -1
  53. package/dist/dto/get-suspicious-activity.dto.d.ts +3 -3
  54. package/dist/dto/get-suspicious-activity.dto.d.ts.map +1 -1
  55. package/dist/dto/get-suspicious-activity.dto.js +5 -5
  56. package/dist/dto/get-suspicious-activity.dto.js.map +1 -1
  57. package/dist/dto/get-user-auth-history.dto.d.ts +4 -39
  58. package/dist/dto/get-user-auth-history.dto.d.ts.map +1 -1
  59. package/dist/dto/get-user-auth-history.dto.js +53 -51
  60. package/dist/dto/get-user-auth-history.dto.js.map +1 -1
  61. package/dist/dto/get-user-devices.dto.d.ts +5 -18
  62. package/dist/dto/get-user-devices.dto.d.ts.map +1 -1
  63. package/dist/dto/get-user-devices.dto.js +5 -39
  64. package/dist/dto/get-user-devices.dto.js.map +1 -1
  65. package/dist/dto/get-user-sessions-response.dto.d.ts +1 -1
  66. package/dist/dto/get-user-sessions-response.dto.js +1 -1
  67. package/dist/dto/get-user-sessions.dto.d.ts +1 -1
  68. package/dist/dto/get-user-sessions.dto.js +1 -1
  69. package/dist/dto/index.d.ts +9 -2
  70. package/dist/dto/index.d.ts.map +1 -1
  71. package/dist/dto/index.js +9 -2
  72. package/dist/dto/index.js.map +1 -1
  73. package/dist/dto/logout-all-response.dto.d.ts +1 -1
  74. package/dist/dto/logout-all-response.dto.js +1 -1
  75. package/dist/dto/logout-all.dto.d.ts +1 -18
  76. package/dist/dto/logout-all.dto.d.ts.map +1 -1
  77. package/dist/dto/logout-all.dto.js +1 -30
  78. package/dist/dto/logout-all.dto.js.map +1 -1
  79. package/dist/dto/logout-session.dto.d.ts +0 -5
  80. package/dist/dto/logout-session.dto.d.ts.map +1 -1
  81. package/dist/dto/logout-session.dto.js +0 -12
  82. package/dist/dto/logout-session.dto.js.map +1 -1
  83. package/dist/dto/logout.dto.d.ts +1 -18
  84. package/dist/dto/logout.dto.d.ts.map +1 -1
  85. package/dist/dto/logout.dto.js +1 -30
  86. package/dist/dto/logout.dto.js.map +1 -1
  87. package/dist/dto/remove-devices.dto.d.ts +4 -16
  88. package/dist/dto/remove-devices.dto.d.ts.map +1 -1
  89. package/dist/dto/remove-devices.dto.js +4 -26
  90. package/dist/dto/remove-devices.dto.js.map +1 -1
  91. package/dist/dto/set-mfa-exemption.dto.d.ts +8 -9
  92. package/dist/dto/set-mfa-exemption.dto.d.ts.map +1 -1
  93. package/dist/dto/set-mfa-exemption.dto.js +11 -13
  94. package/dist/dto/set-mfa-exemption.dto.js.map +1 -1
  95. package/dist/dto/set-must-change-password.dto.d.ts +3 -3
  96. package/dist/dto/set-must-change-password.dto.d.ts.map +1 -1
  97. package/dist/dto/set-must-change-password.dto.js +5 -5
  98. package/dist/dto/set-must-change-password.dto.js.map +1 -1
  99. package/dist/dto/set-preferred-method.dto.d.ts +4 -16
  100. package/dist/dto/set-preferred-method.dto.d.ts.map +1 -1
  101. package/dist/dto/set-preferred-method.dto.js +4 -26
  102. package/dist/dto/set-preferred-method.dto.js.map +1 -1
  103. package/dist/dto/setup-mfa.dto.d.ts +3 -18
  104. package/dist/dto/setup-mfa.dto.d.ts.map +1 -1
  105. package/dist/dto/setup-mfa.dto.js +3 -30
  106. package/dist/dto/setup-mfa.dto.js.map +1 -1
  107. package/dist/dto/social-auth.dto.d.ts +4 -34
  108. package/dist/dto/social-auth.dto.d.ts.map +1 -1
  109. package/dist/dto/social-auth.dto.js +10 -68
  110. package/dist/dto/social-auth.dto.js.map +1 -1
  111. package/dist/dto/update-user-attributes.dto.d.ts +26 -0
  112. package/dist/dto/update-user-attributes.dto.d.ts.map +1 -0
  113. package/dist/dto/update-user-attributes.dto.js +30 -0
  114. package/dist/dto/update-user-attributes.dto.js.map +1 -0
  115. package/dist/index.d.ts +5 -0
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +5 -0
  118. package/dist/index.js.map +1 -1
  119. package/dist/interfaces/hooks.interface.d.ts +2 -1
  120. package/dist/interfaces/hooks.interface.d.ts.map +1 -1
  121. package/dist/interfaces/mfa-provider.interface.d.ts +7 -8
  122. package/dist/interfaces/mfa-provider.interface.d.ts.map +1 -1
  123. package/dist/interfaces/provider.interface.d.ts +1 -1
  124. package/dist/interfaces/provider.interface.d.ts.map +1 -1
  125. package/dist/services/adaptive-mfa-decision.service.js +2 -2
  126. package/dist/services/adaptive-mfa-decision.service.js.map +1 -1
  127. package/dist/services/admin-auth.service.d.ts +307 -0
  128. package/dist/services/admin-auth.service.d.ts.map +1 -0
  129. package/dist/services/admin-auth.service.js +885 -0
  130. package/dist/services/admin-auth.service.js.map +1 -0
  131. package/dist/services/auth-audit.service.d.ts +16 -16
  132. package/dist/services/auth-audit.service.d.ts.map +1 -1
  133. package/dist/services/auth-audit.service.js +33 -33
  134. package/dist/services/auth-audit.service.js.map +1 -1
  135. package/dist/services/auth-challenge-helper.service.js +3 -3
  136. package/dist/services/auth-challenge-helper.service.js.map +1 -1
  137. package/dist/services/auth-service-internal-helpers.d.ts +13 -2
  138. package/dist/services/auth-service-internal-helpers.d.ts.map +1 -1
  139. package/dist/services/auth-service-internal-helpers.js +39 -1
  140. package/dist/services/auth-service-internal-helpers.js.map +1 -1
  141. package/dist/services/auth.service.d.ts +94 -438
  142. package/dist/services/auth.service.d.ts.map +1 -1
  143. package/dist/services/auth.service.js +388 -1255
  144. package/dist/services/auth.service.js.map +1 -1
  145. package/dist/services/mfa-base.service.d.ts +14 -4
  146. package/dist/services/mfa-base.service.d.ts.map +1 -1
  147. package/dist/services/mfa-base.service.js +22 -1
  148. package/dist/services/mfa-base.service.js.map +1 -1
  149. package/dist/services/mfa.service.d.ts +107 -33
  150. package/dist/services/mfa.service.d.ts.map +1 -1
  151. package/dist/services/mfa.service.js +456 -333
  152. package/dist/services/mfa.service.js.map +1 -1
  153. package/dist/services/social-auth.service.d.ts +7 -0
  154. package/dist/services/social-auth.service.d.ts.map +1 -1
  155. package/dist/services/social-auth.service.js +38 -26
  156. package/dist/services/social-auth.service.js.map +1 -1
  157. package/dist/services/user.service.d.ts +3 -3
  158. package/dist/services/user.service.d.ts.map +1 -1
  159. package/dist/services/user.service.js +7 -7
  160. package/dist/services/user.service.js.map +1 -1
  161. package/dist/utils/dto-validator.d.ts.map +1 -1
  162. package/dist/utils/dto-validator.js +50 -4
  163. package/dist/utils/dto-validator.js.map +1 -1
  164. package/dist/utils/setup/init-services.d.ts +2 -1
  165. package/dist/utils/setup/init-services.d.ts.map +1 -1
  166. package/dist/utils/setup/init-services.js +2 -0
  167. package/dist/utils/setup/init-services.js.map +1 -1
  168. package/package.json +1 -1
  169. package/dist/dto/change-password-request.dto.d.ts +0 -43
  170. package/dist/dto/change-password-request.dto.d.ts.map +0 -1
  171. package/dist/dto/change-password-request.dto.js.map +0 -1
  172. package/dist/dto/update-user-attributes-request.dto.d.ts +0 -44
  173. package/dist/dto/update-user-attributes-request.dto.d.ts.map +0 -1
  174. package/dist/dto/update-user-attributes-request.dto.js.map +0 -1
@@ -0,0 +1,885 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AdminAuthService = void 0;
4
+ const auth_audit_event_type_enum_1 = require("../enums/auth-audit-event-type.enum");
5
+ const admin_signup_dto_1 = require("../dto/admin-signup.dto");
6
+ const admin_signup_social_dto_1 = require("../dto/admin-signup-social.dto");
7
+ const user_response_dto_1 = require("../dto/user-response.dto");
8
+ const get_user_sessions_dto_1 = require("../dto/get-user-sessions.dto");
9
+ const admin_logout_all_dto_1 = require("../dto/admin-logout-all.dto");
10
+ const admin_revoke_session_dto_1 = require("../dto/admin-revoke-session.dto");
11
+ const admin_set_password_dto_1 = require("../dto/admin-set-password.dto");
12
+ const admin_reset_password_dto_1 = require("../dto/admin-reset-password.dto");
13
+ const nauth_exception_1 = require("../exceptions/nauth.exception");
14
+ const error_codes_enum_1 = require("../enums/error-codes.enum");
15
+ const password_generator_1 = require("../utils/password-generator");
16
+ const dto_validator_1 = require("../utils/dto-validator");
17
+ const auth_service_internal_helpers_1 = require("./auth-service-internal-helpers");
18
+ const user_service_1 = require("./user.service");
19
+ /**
20
+ * Administrative authentication service
21
+ *
22
+ * Provides admin-only operations for managing users, sessions, and password workflows.
23
+ * This service is intentionally separate from AuthService to keep user self-service
24
+ * APIs isolated from admin actions.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const result = await adminAuthService.disableUser({ sub: 'user-uuid' });
29
+ * ```
30
+ */
31
+ class AdminAuthService {
32
+ userRepository;
33
+ loginAttemptRepository;
34
+ passwordService;
35
+ sessionService;
36
+ challengeService;
37
+ challengeHelper;
38
+ emailVerificationService;
39
+ clientInfoService;
40
+ accountLockoutStorage;
41
+ config;
42
+ logger;
43
+ hookRegistry;
44
+ auditService;
45
+ phoneVerificationService;
46
+ mfaDeviceRepository;
47
+ trustedDeviceService;
48
+ passwordResetService;
49
+ socialAuthService;
50
+ sessionRepository;
51
+ verificationTokenRepository;
52
+ socialAccountRepository;
53
+ challengeSessionRepository;
54
+ authAuditRepository;
55
+ trustedDeviceRepository;
56
+ helpers;
57
+ userService;
58
+ constructor(userRepository, loginAttemptRepository, passwordService, sessionService, challengeService, challengeHelper, emailVerificationService, clientInfoService, accountLockoutStorage, config, logger, hookRegistry, auditService, phoneVerificationService, mfaDeviceRepository, trustedDeviceService, passwordResetService, socialAuthService, sessionRepository, verificationTokenRepository, socialAccountRepository, challengeSessionRepository, authAuditRepository, trustedDeviceRepository) {
59
+ this.userRepository = userRepository;
60
+ this.loginAttemptRepository = loginAttemptRepository;
61
+ this.passwordService = passwordService;
62
+ this.sessionService = sessionService;
63
+ this.challengeService = challengeService;
64
+ this.challengeHelper = challengeHelper;
65
+ this.emailVerificationService = emailVerificationService;
66
+ this.clientInfoService = clientInfoService;
67
+ this.accountLockoutStorage = accountLockoutStorage;
68
+ this.config = config;
69
+ this.logger = logger;
70
+ this.hookRegistry = hookRegistry;
71
+ this.auditService = auditService;
72
+ this.phoneVerificationService = phoneVerificationService;
73
+ this.mfaDeviceRepository = mfaDeviceRepository;
74
+ this.trustedDeviceService = trustedDeviceService;
75
+ this.passwordResetService = passwordResetService;
76
+ this.socialAuthService = socialAuthService;
77
+ this.sessionRepository = sessionRepository;
78
+ this.verificationTokenRepository = verificationTokenRepository;
79
+ this.socialAccountRepository = socialAccountRepository;
80
+ this.challengeSessionRepository = challengeSessionRepository;
81
+ this.authAuditRepository = authAuditRepository;
82
+ this.trustedDeviceRepository = trustedDeviceRepository;
83
+ this.helpers = new auth_service_internal_helpers_1.AuthServiceInternalHelpers(userRepository, loginAttemptRepository, emailVerificationService, phoneVerificationService, challengeService, challengeHelper, clientInfoService, sessionService, accountLockoutStorage, config, logger, hookRegistry);
84
+ this.userService = new user_service_1.UserService(userRepository, loginAttemptRepository, sessionService, config, logger, mfaDeviceRepository, auditService, hookRegistry, clientInfoService, sessionRepository, verificationTokenRepository, socialAccountRepository, challengeSessionRepository, authAuditRepository, trustedDeviceRepository, this.helpers);
85
+ this.logger?.log?.('AdminAuthService initialized');
86
+ }
87
+ /**
88
+ * Administrative user deletion with complete cascade cleanup
89
+ *
90
+ * @param dto - User sub to delete
91
+ * @returns Deletion confirmation with cascade counts
92
+ * @throws {NAuthException} USER_NOT_FOUND
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * const result = await adminAuthService.deleteUser({ sub: 'user-uuid-123' });
97
+ * ```
98
+ */
99
+ async deleteUser(dto) {
100
+ return await this.userService.deleteUser(dto);
101
+ }
102
+ /**
103
+ * Get paginated list of users with advanced filtering
104
+ *
105
+ * @param dto - Filters, pagination, sorting
106
+ * @returns Paginated user list with metadata
107
+ * @throws {NAuthException} When validation fails
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * const result = await adminAuthService.getUsers({ page: 1, limit: 20 });
112
+ * ```
113
+ */
114
+ async getUsers(dto) {
115
+ return await this.userService.getUsers(dto);
116
+ }
117
+ /**
118
+ * Administrative permanent account locking
119
+ *
120
+ * @param dto - User sub and optional reason
121
+ * @returns User object with updated lock status and revoked session count
122
+ * @throws {NAuthException} USER_NOT_FOUND
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * const result = await adminAuthService.disableUser({ sub: 'user-uuid-123' });
127
+ * ```
128
+ */
129
+ async disableUser(dto) {
130
+ return await this.userService.disableUser(dto);
131
+ }
132
+ /**
133
+ * Enable (unlock) user account
134
+ *
135
+ * @param dto - User sub to enable
136
+ * @returns User object with updated lock status
137
+ * @throws {NAuthException} USER_NOT_FOUND
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * const result = await adminAuthService.enableUser({ sub: 'user-uuid-123' });
142
+ * ```
143
+ */
144
+ async enableUser(dto) {
145
+ return await this.userService.enableUser(dto);
146
+ }
147
+ /**
148
+ * Get user by ID (sub)
149
+ *
150
+ * @param dto - GetUserByIdDTO containing sub
151
+ * @returns User response DTO or null if not found
152
+ * @throws {NAuthException} When validation fails
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * const user = await adminAuthService.getUserById({ sub: 'user-uuid' });
157
+ * ```
158
+ */
159
+ async getUserById(dto) {
160
+ return await this.userService.getUserById(dto);
161
+ }
162
+ /**
163
+ * Get user by email address.
164
+ *
165
+ * @param dto - GetUserByEmailDTO containing email and optional requireEmailVerified
166
+ * @returns User response DTO or null if not found
167
+ * @throws {NAuthException} When validation fails
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * const user = await adminAuthService.getUserByEmail({ email: 'user@example.com' });
172
+ * ```
173
+ */
174
+ async getUserByEmail(dto) {
175
+ return await this.userService.getUserByEmail(dto);
176
+ }
177
+ /**
178
+ * Require user to change password at next login.
179
+ *
180
+ * @param dto - SetMustChangePasswordDTO containing sub
181
+ * @returns Success response
182
+ * @throws {NAuthException} If user is not found or cannot change password
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * await adminAuthService.setMustChangePassword({ sub: 'user-uuid-123' });
187
+ * ```
188
+ */
189
+ async setMustChangePassword(dto) {
190
+ return await this.userService.setMustChangePassword(dto);
191
+ }
192
+ /**
193
+ * Update email and/or phone verification status.
194
+ *
195
+ * @param dto - Request DTO containing sub and verification status flags
196
+ * @returns Updated user object
197
+ * @throws {NAuthException} If user not found or trying to verify non-existent email/phone
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * await adminAuthService.updateVerifiedStatus({ sub: 'user-uuid', isEmailVerified: true });
202
+ * ```
203
+ */
204
+ async updateVerifiedStatus(dto) {
205
+ return await this.userService.updateVerifiedStatus(dto);
206
+ }
207
+ /**
208
+ * Administrative user creation with override capabilities
209
+ *
210
+ * @param dto - Admin signup DTO with override flags
211
+ * @returns User object and optionally generated password
212
+ * @throws {NAuthException} EMAIL_EXISTS | USERNAME_EXISTS | PHONE_EXISTS | WEAK_PASSWORD
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * const result = await adminAuthService.signup({ email: 'user@example.com', generatePassword: true });
217
+ * ```
218
+ */
219
+ async signup(dto) {
220
+ dto = await (0, dto_validator_1.ensureValidatedDto)(admin_signup_dto_1.AdminSignupDTO, dto);
221
+ const clientInfo = this.clientInfoService.get();
222
+ this.logger?.log?.(`Admin signup attempt for email: ${dto.email}`);
223
+ this.logger?.debug?.(`Admin signup details: { email: ${dto.email}, username: ${dto.username || 'none'}, ip: ${clientInfo.ipAddress} }`);
224
+ const existingUserByEmail = await this.userRepository.findOne({
225
+ where: { email: dto.email },
226
+ });
227
+ if (existingUserByEmail) {
228
+ this.logger?.warn?.(`Admin signup failed - user already exists: ${dto.email}`);
229
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.EMAIL_EXISTS, 'User with this email already exists');
230
+ }
231
+ if (dto.username) {
232
+ this.logger?.debug?.(`Checking if username exists: ${dto.username}`);
233
+ const existingUserByUsername = await this.userRepository.findOne({
234
+ where: { username: dto.username },
235
+ });
236
+ if (existingUserByUsername) {
237
+ this.logger?.warn?.(`Admin signup failed - username already exists: ${dto.username}`);
238
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.USERNAME_EXISTS, 'Username is already taken');
239
+ }
240
+ }
241
+ if (dto.phone && !this.config.signup?.allowDuplicatePhones) {
242
+ this.logger?.debug?.(`Checking if phone exists: ${dto.phone}`);
243
+ const existingUserByPhone = await this.userRepository.findOne({
244
+ where: { phone: dto.phone },
245
+ });
246
+ if (existingUserByPhone) {
247
+ this.logger?.warn?.(`Admin signup failed - phone already exists: ${dto.phone}`);
248
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PHONE_EXISTS, 'Phone number is already registered');
249
+ }
250
+ }
251
+ let passwordHash;
252
+ let generatedPassword;
253
+ if (dto.generatePassword) {
254
+ const generatedPasswordValue = (0, password_generator_1.generateSecurePassword)(16);
255
+ generatedPassword = generatedPasswordValue;
256
+ this.logger?.debug?.(`Generated password for admin-created user: ${dto.email}`);
257
+ passwordHash = await this.passwordService.hashPassword(generatedPasswordValue);
258
+ }
259
+ else {
260
+ if (!dto.password) {
261
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.WEAK_PASSWORD, 'Password is required when generatePassword is false');
262
+ }
263
+ this.logger?.debug?.('Validating password against policy');
264
+ const passwordValidation = await this.passwordService.validatePassword(dto.password, {
265
+ email: dto.email,
266
+ username: dto.username,
267
+ });
268
+ if (!passwordValidation.valid) {
269
+ this.logger?.warn?.(`Password validation failed for ${dto.email}: ${passwordValidation.errors.join(', ')}`);
270
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.WEAK_PASSWORD, passwordValidation.errors.join(', '), {
271
+ errors: passwordValidation.errors,
272
+ });
273
+ }
274
+ passwordHash = await this.passwordService.hashPassword(dto.password);
275
+ }
276
+ await this.hookRegistry.executePreSignup(dto, 'password', undefined, true);
277
+ this.logger?.debug?.(`Creating admin user record for: ${dto.email} || ${dto.username} || ${dto.phone} (isEmailVerified: ${dto.isEmailVerified || false}, isPhoneVerified: ${dto.isPhoneVerified || false})`);
278
+ const user = this.userRepository.create({
279
+ email: dto.email,
280
+ username: dto.username,
281
+ firstName: dto.firstName,
282
+ lastName: dto.lastName,
283
+ phone: dto.phone,
284
+ passwordHash,
285
+ passwordChangedAt: new Date(),
286
+ isEmailVerified: dto.isEmailVerified ?? false,
287
+ isPhoneVerified: dto.isPhoneVerified ?? false,
288
+ mustChangePassword: dto.mustChangePassword ?? false,
289
+ isActive: true,
290
+ metadata: dto.metadata,
291
+ });
292
+ let savedUser;
293
+ try {
294
+ savedUser = (await this.userRepository.save(user));
295
+ this.logger?.log?.(`Admin user created successfully: ${dto.email} (sub: ${savedUser.sub})`);
296
+ try {
297
+ await this.auditService?.recordEvent({
298
+ userId: savedUser.id,
299
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.ACCOUNT_CREATED,
300
+ eventStatus: 'INFO',
301
+ authMethod: 'admin',
302
+ metadata: {
303
+ email: savedUser.email,
304
+ username: savedUser.username || null,
305
+ createdByAdmin: true,
306
+ adminIdentifier: clientInfo.ipAddress || 'unknown',
307
+ isEmailVerified: savedUser.isEmailVerified,
308
+ isPhoneVerified: savedUser.isPhoneVerified,
309
+ mustChangePassword: savedUser.mustChangePassword,
310
+ passwordGenerated: !!generatedPassword,
311
+ },
312
+ });
313
+ }
314
+ catch (auditError) {
315
+ const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
316
+ this.logger?.error?.(`Failed to record ACCOUNT_CREATED audit event: ${errorMessage}`, {
317
+ error: auditError,
318
+ userId: savedUser.id,
319
+ });
320
+ }
321
+ }
322
+ catch (error) {
323
+ if (error && typeof error === 'object' && 'code' in error && error.code === '23505') {
324
+ const dbError = error;
325
+ if (dbError.detail?.includes('email')) {
326
+ this.logger?.warn?.(`Admin signup failed - email constraint violation: ${dto.email}`);
327
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.EMAIL_EXISTS, 'User with this email already exists');
328
+ }
329
+ else if (dbError.detail?.includes('username')) {
330
+ this.logger?.warn?.(`Admin signup failed - username constraint violation: ${dto.username}`);
331
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.USERNAME_EXISTS, 'Username is already taken');
332
+ }
333
+ else if (dbError.detail?.includes('phone')) {
334
+ this.logger?.warn?.(`Admin signup failed - phone constraint violation: ${dto.phone}`);
335
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PHONE_EXISTS, 'Phone number is already registered');
336
+ }
337
+ else {
338
+ this.logger?.error?.(`Admin signup failed - database constraint violation: ${dbError.message}`);
339
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.EMAIL_EXISTS, 'User with this information already exists', {
340
+ conflictType: 'unknown',
341
+ });
342
+ }
343
+ }
344
+ const errorMessage = error instanceof Error ? error.message : 'Unknown database error';
345
+ this.logger?.error?.(`Admin signup failed - database error: ${errorMessage}`);
346
+ throw error;
347
+ }
348
+ await this.hookRegistry.executePostSignup(savedUser, {
349
+ signupType: 'password',
350
+ adminSignup: true,
351
+ });
352
+ const userDto = user_response_dto_1.UserResponseDto.fromEntity(savedUser);
353
+ return {
354
+ user: userDto,
355
+ generatedPassword,
356
+ };
357
+ }
358
+ /**
359
+ * Administrative social user import with override capabilities
360
+ *
361
+ * @param dto - Admin social signup DTO with social account details
362
+ * @returns User object and social account confirmation
363
+ * @throws {NAuthException} EMAIL_EXISTS | USERNAME_EXISTS | PHONE_EXISTS | SOCIAL_ACCOUNT_EXISTS | WEAK_PASSWORD
364
+ *
365
+ * @example
366
+ * ```typescript
367
+ * const result = await adminAuthService.signupSocial({
368
+ * email: 'user@example.com',
369
+ * provider: 'google',
370
+ * providerId: 'google_12345',
371
+ * });
372
+ * ```
373
+ */
374
+ async signupSocial(dto) {
375
+ dto = await (0, dto_validator_1.ensureValidatedDto)(admin_signup_social_dto_1.AdminSignupSocialDTO, dto);
376
+ const clientInfo = this.clientInfoService.get();
377
+ this.logger?.log?.(`Admin social signup attempt for email: ${dto.email}, provider: ${dto.provider}`);
378
+ this.logger?.debug?.(`Admin social signup details: { email: ${dto.email}, username: ${dto.username || 'none'}, provider: ${dto.provider}, providerId: ${dto.providerId}, ip: ${clientInfo.ipAddress} }`);
379
+ const existingUserByEmail = await this.userRepository.findOne({
380
+ where: { email: dto.email },
381
+ });
382
+ if (existingUserByEmail) {
383
+ this.logger?.warn?.(`Admin social signup failed - user already exists: ${dto.email}`);
384
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.EMAIL_EXISTS, 'User with this email already exists');
385
+ }
386
+ if (dto.username) {
387
+ this.logger?.debug?.(`Checking if username exists: ${dto.username}`);
388
+ const existingUserByUsername = await this.userRepository.findOne({
389
+ where: { username: dto.username },
390
+ });
391
+ if (existingUserByUsername) {
392
+ this.logger?.warn?.(`Admin social signup failed - username already exists: ${dto.username}`);
393
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.USERNAME_EXISTS, 'Username is already taken');
394
+ }
395
+ }
396
+ if (dto.phone && !this.config.signup?.allowDuplicatePhones) {
397
+ this.logger?.debug?.(`Checking if phone exists: ${dto.phone}`);
398
+ const existingUserByPhone = await this.userRepository.findOne({
399
+ where: { phone: dto.phone },
400
+ });
401
+ if (existingUserByPhone) {
402
+ this.logger?.warn?.(`Admin social signup failed - phone already exists: ${dto.phone}`);
403
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PHONE_EXISTS, 'Phone number is already registered');
404
+ }
405
+ }
406
+ if (!this.socialAuthService) {
407
+ this.logger?.error?.('SocialAuthService not available - cannot import social user');
408
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Social authentication is not configured');
409
+ }
410
+ this.logger?.debug?.(`Checking if social account exists: ${dto.provider}:${dto.providerId}`);
411
+ const existingSocialAccount = await this.socialAuthService.findSocialAccountByProvider(dto.provider, dto.providerId);
412
+ if (existingSocialAccount) {
413
+ this.logger?.warn?.(`Admin social signup failed - social account already exists: ${dto.provider}:${dto.providerId}`);
414
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.SOCIAL_ACCOUNT_EXISTS, 'This social account is already registered');
415
+ }
416
+ let passwordHash = null;
417
+ if (dto.password) {
418
+ const passwordValidation = await this.passwordService.validatePassword(dto.password, {
419
+ email: dto.email,
420
+ username: dto.username,
421
+ });
422
+ if (!passwordValidation.valid) {
423
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.WEAK_PASSWORD, passwordValidation.errors.join(', '), {
424
+ errors: passwordValidation.errors,
425
+ });
426
+ }
427
+ passwordHash = await this.passwordService.hashPassword(dto.password);
428
+ }
429
+ await this.hookRegistry.executePreSignup(dto, 'social', dto.provider, true);
430
+ const user = this.userRepository.create({
431
+ email: dto.email,
432
+ username: dto.username,
433
+ firstName: dto.firstName,
434
+ lastName: dto.lastName,
435
+ phone: dto.phone,
436
+ passwordHash,
437
+ passwordChangedAt: passwordHash ? new Date() : null,
438
+ isEmailVerified: true,
439
+ isPhoneVerified: dto.isPhoneVerified ?? false,
440
+ mustChangePassword: dto.mustChangePassword ?? false,
441
+ isActive: true,
442
+ metadata: dto.metadata,
443
+ hasSocialAuth: true,
444
+ });
445
+ let savedUser;
446
+ try {
447
+ savedUser = (await this.userRepository.save(user));
448
+ await this.socialAuthService.createOrUpdateSocialAccount(savedUser.id, dto.provider, dto.providerId, dto.providerEmail, dto.socialMetadata);
449
+ this.logger?.log?.(`Admin social user created successfully: ${dto.email} (sub: ${savedUser.sub})`);
450
+ try {
451
+ await this.auditService?.recordEvent({
452
+ userId: savedUser.id,
453
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.ACCOUNT_CREATED,
454
+ eventStatus: 'INFO',
455
+ authMethod: `admin-social-${dto.provider}`,
456
+ metadata: {
457
+ email: savedUser.email,
458
+ username: savedUser.username || null,
459
+ createdByAdmin: true,
460
+ adminIdentifier: clientInfo.ipAddress || 'unknown',
461
+ isEmailVerified: savedUser.isEmailVerified,
462
+ isPhoneVerified: savedUser.isPhoneVerified,
463
+ mustChangePassword: savedUser.mustChangePassword,
464
+ provider: dto.provider,
465
+ providerId: dto.providerId,
466
+ hasPassword: !!dto.password,
467
+ socialImport: true,
468
+ },
469
+ });
470
+ }
471
+ catch (auditError) {
472
+ const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
473
+ this.logger?.error?.(`Failed to record ACCOUNT_CREATED audit event: ${errorMessage}`, {
474
+ error: auditError,
475
+ userId: savedUser.id,
476
+ });
477
+ }
478
+ }
479
+ catch (error) {
480
+ if (error && typeof error === 'object' && 'code' in error && error.code === '23505') {
481
+ const dbError = error;
482
+ if (dbError.detail?.includes('email')) {
483
+ this.logger?.warn?.(`Admin social signup failed - email constraint violation: ${dto.email}`);
484
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.EMAIL_EXISTS, 'User with this email already exists');
485
+ }
486
+ else if (dbError.detail?.includes('username')) {
487
+ this.logger?.warn?.(`Admin social signup failed - username constraint violation: ${dto.username}`);
488
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.USERNAME_EXISTS, 'Username is already taken');
489
+ }
490
+ else if (dbError.detail?.includes('phone')) {
491
+ this.logger?.warn?.(`Admin social signup failed - phone constraint violation: ${dto.phone}`);
492
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PHONE_EXISTS, 'Phone number is already registered');
493
+ }
494
+ else if (dbError.detail?.includes('provider') && dbError.detail?.includes('providerId')) {
495
+ this.logger?.warn?.(`Admin social signup failed - social account constraint violation: ${dto.provider}:${dto.providerId}`);
496
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.SOCIAL_ACCOUNT_EXISTS, 'This social account is already registered');
497
+ }
498
+ else {
499
+ this.logger?.error?.(`Admin social signup failed - database constraint violation: ${dbError.message}`);
500
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.EMAIL_EXISTS, 'User with this information already exists', {
501
+ conflictType: 'unknown',
502
+ });
503
+ }
504
+ }
505
+ const errorMessage = error instanceof Error ? error.message : 'Unknown database error';
506
+ this.logger?.error?.(`Admin social signup failed - database error: ${errorMessage}`);
507
+ throw error;
508
+ }
509
+ await this.hookRegistry.executePostSignup(savedUser, {
510
+ signupType: 'social',
511
+ adminSignup: true,
512
+ });
513
+ const userDto = user_response_dto_1.UserResponseDto.fromEntity(savedUser);
514
+ return {
515
+ user: userDto,
516
+ socialAccount: {
517
+ provider: dto.provider,
518
+ providerId: dto.providerId,
519
+ providerEmail: dto.providerEmail || null,
520
+ },
521
+ };
522
+ }
523
+ /**
524
+ * Global signout (admin-initiated)
525
+ *
526
+ * @param dto - Target user sub and optional forgetDevices flag
527
+ * @returns Number of sessions revoked
528
+ * @throws {NAuthException} NOT_FOUND if user not found
529
+ *
530
+ * @example
531
+ * ```typescript
532
+ * const result = await adminAuthService.logoutAll({ sub: 'user-uuid', forgetDevices: true });
533
+ * ```
534
+ */
535
+ async logoutAll(dto) {
536
+ dto = await (0, dto_validator_1.ensureValidatedDto)(admin_logout_all_dto_1.AdminLogoutAllDTO, dto);
537
+ const user = (await this.userRepository.findOne({ where: { sub: dto.sub } }));
538
+ if (!user) {
539
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
540
+ }
541
+ const revokedCount = await this.sessionService.revokeAllUserSessions(user.id, 'Admin global signout');
542
+ let revokedDevicesCount = 0;
543
+ let revokedDevices = [];
544
+ if (dto.forgetDevices &&
545
+ this.config.mfa?.rememberDevices &&
546
+ this.config.mfa?.rememberDevices !== 'never' &&
547
+ this.trustedDeviceService) {
548
+ try {
549
+ const deviceRevocationResult = await this.trustedDeviceService.revokeAllTrustedDevices(user.id);
550
+ revokedDevicesCount = deviceRevocationResult.revokedCount;
551
+ revokedDevices = deviceRevocationResult.devices;
552
+ this.logger?.log?.(`Revoked ${revokedDevicesCount} trusted device(s) for user ${user.sub} (admin forgetDevices=true)`);
553
+ if (revokedDevicesCount > 0 && this.auditService) {
554
+ try {
555
+ const userId = typeof user.id === 'number' ? user.id : parseInt(String(user.id), 10);
556
+ const clientInfo = this.clientInfoService.get();
557
+ await this.auditService.recordEvent({
558
+ userId,
559
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.DEVICE_UNTRUSTED,
560
+ eventStatus: 'SUCCESS',
561
+ description: `Admin global signout: All trusted devices revoked (${revokedDevicesCount} device(s))`,
562
+ metadata: {
563
+ reason: 'admin_global_logout_forget_devices',
564
+ initiatedBy: 'admin',
565
+ adminIdentifier: clientInfo.ipAddress || 'unknown',
566
+ revokedDevicesCount,
567
+ devices: revokedDevices.map((d) => ({
568
+ id: d.id,
569
+ deviceName: d.deviceName,
570
+ lastUsedAt: d.lastUsedAt?.toISOString() || null,
571
+ trustedUntil: d.trustedUntil?.toISOString() || null,
572
+ })),
573
+ },
574
+ });
575
+ }
576
+ catch (auditError) {
577
+ const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
578
+ this.logger?.error?.(`Failed to record DEVICE_UNTRUSTED audit event: ${errorMessage}`, {
579
+ error: auditError,
580
+ userId: user.id,
581
+ });
582
+ }
583
+ }
584
+ }
585
+ catch (error) {
586
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
587
+ this.logger?.debug?.(`Failed to revoke trusted devices on admin global logout: ${errorMessage}`, { error });
588
+ }
589
+ }
590
+ return { revokedCount };
591
+ }
592
+ /**
593
+ * Get all active sessions for a user (admin)
594
+ *
595
+ * @param dto - Contains target user sub
596
+ * @returns Array of sessions with device info, auth method, and isCurrent flag
597
+ * @throws {NAuthException} NOT_FOUND if user not found
598
+ *
599
+ * @example
600
+ * ```typescript
601
+ * const result = await adminAuthService.getUserSessions({ sub: 'user-uuid' });
602
+ * ```
603
+ */
604
+ async getUserSessions(dto) {
605
+ dto = await (0, dto_validator_1.ensureValidatedDto)(get_user_sessions_dto_1.GetUserSessionsDTO, dto);
606
+ const user = (await this.userRepository.findOne({ where: { sub: dto.sub } }));
607
+ if (!user) {
608
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
609
+ }
610
+ const clientInfo = this.clientInfoService.get();
611
+ const currentSessionId = clientInfo.sessionId ? String(clientInfo.sessionId) : null;
612
+ const sessions = await this.sessionService.findUserSessions(user.id);
613
+ const sessionInfos = sessions.map((session) => {
614
+ let authMethod = session.authMethod || null;
615
+ let authProvider = null;
616
+ if (authMethod === 'social' || authMethod?.startsWith('admin-')) {
617
+ const metadata = session.metadata || {};
618
+ authProvider = metadata.authProvider || metadata.provider || null;
619
+ if (!authProvider && authMethod && authMethod !== 'social' && !authMethod.startsWith('admin-')) {
620
+ authProvider = authMethod;
621
+ authMethod = 'social';
622
+ }
623
+ }
624
+ const isCurrent = currentSessionId !== null && String(session.id) === currentSessionId;
625
+ return {
626
+ sessionId: String(session.id),
627
+ deviceId: session.deviceId,
628
+ deviceName: session.deviceName,
629
+ deviceType: session.deviceType,
630
+ platform: session.platform,
631
+ browser: session.browser,
632
+ ipAddress: session.ipAddress,
633
+ ipCountry: session.ipCountry,
634
+ ipCity: session.ipCity,
635
+ lastActivityAt: session.lastActivityAt || session.createdAt,
636
+ createdAt: session.createdAt,
637
+ expiresAt: session.expiresAt,
638
+ isRemembered: session.isRemembered,
639
+ isCurrent,
640
+ authMethod,
641
+ authProvider,
642
+ };
643
+ });
644
+ return { sessions: sessionInfos };
645
+ }
646
+ /**
647
+ * Revoke a specific user session by ID (admin)
648
+ *
649
+ * @param dto - Contains sessionId and user sub
650
+ * @returns Success status and whether it was the current session
651
+ * @throws {NAuthException} NOT_FOUND if user not found
652
+ * @throws {NAuthException} SESSION_NOT_FOUND if session not found
653
+ * @throws {NAuthException} FORBIDDEN if session doesn't belong to user
654
+ *
655
+ * @example
656
+ * ```typescript
657
+ * await adminAuthService.revokeUserSession({ sub: 'user-uuid', sessionId: '123' });
658
+ * ```
659
+ */
660
+ async revokeUserSession(dto) {
661
+ dto = await (0, dto_validator_1.ensureValidatedDto)(admin_revoke_session_dto_1.AdminRevokeSessionDTO, dto);
662
+ const user = (await this.userRepository.findOne({ where: { sub: dto.sub } }));
663
+ if (!user) {
664
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
665
+ }
666
+ const sessionId = typeof dto.sessionId === 'string' ? parseInt(dto.sessionId, 10) : dto.sessionId;
667
+ if (isNaN(sessionId)) {
668
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.VALIDATION_FAILED, 'Invalid session ID');
669
+ }
670
+ const session = await this.sessionService.findById(sessionId);
671
+ if (!session) {
672
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.SESSION_NOT_FOUND, 'Session not found');
673
+ }
674
+ if (session.userId !== user.id) {
675
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.FORBIDDEN, 'Session does not belong to user');
676
+ }
677
+ const clientInfo = this.clientInfoService.get();
678
+ const currentSessionId = clientInfo.sessionId ? parseInt(String(clientInfo.sessionId), 10) : null;
679
+ const wasCurrentSession = currentSessionId !== null && sessionId === currentSessionId;
680
+ await this.sessionService.revokeSession(sessionId, 'Admin revoked session', {
681
+ requestedBy: dto.sub,
682
+ wasCurrentSession,
683
+ initiatedBy: 'admin',
684
+ adminIdentifier: clientInfo.ipAddress || 'unknown',
685
+ });
686
+ if (this.auditService) {
687
+ try {
688
+ await this.auditService.recordEvent({
689
+ userId: user.id,
690
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.SESSION_REVOKED,
691
+ eventStatus: 'INFO',
692
+ reason: 'admin_requested',
693
+ description: `Session revoked by admin${wasCurrentSession ? ' (current session)' : ''}`,
694
+ metadata: {
695
+ sessionId,
696
+ wasCurrentSession,
697
+ initiatedBy: 'admin',
698
+ adminIdentifier: clientInfo.ipAddress || 'unknown',
699
+ },
700
+ });
701
+ }
702
+ catch (auditError) {
703
+ const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
704
+ this.logger?.error?.(`Failed to record SESSION_REVOKED audit event: ${errorMessage}`, {
705
+ error: auditError,
706
+ userId: user.id,
707
+ });
708
+ }
709
+ }
710
+ return {
711
+ success: true,
712
+ wasCurrentSession,
713
+ };
714
+ }
715
+ /**
716
+ * Update user profile attributes (admin)
717
+ *
718
+ * @param dto - AdminUpdateUserAttributesDTO containing sub and fields to update
719
+ * @returns Updated user object
720
+ * @throws {NAuthException} If user not found or unique constraint violated
721
+ *
722
+ * @example
723
+ * ```typescript
724
+ * const user = await adminAuthService.updateUserAttributes({ sub: 'user-uuid', email: 'new@example.com' });
725
+ * ```
726
+ */
727
+ async updateUserAttributes(dto) {
728
+ return await this.userService.updateUserAttributes(dto);
729
+ }
730
+ /**
731
+ * Admin-only: Initiate a code-based password reset workflow.
732
+ *
733
+ * @param dto - Admin reset password request
734
+ * @returns Response with masked destination, expiry, and sessions revoked count
735
+ * @throws {NAuthException} NOT_FOUND when user not found
736
+ *
737
+ * @example
738
+ * ```typescript
739
+ * const result = await adminAuthService.resetPassword({ sub: 'user-uuid', deliveryMethod: 'email' });
740
+ * ```
741
+ */
742
+ async resetPassword(dto) {
743
+ dto = await (0, dto_validator_1.ensureValidatedDto)(admin_reset_password_dto_1.AdminResetPasswordDTO, dto);
744
+ this.logger?.log?.(`Admin password reset requested for sub: ${dto.sub}`);
745
+ this.logger?.debug?.(`Reset details: { sub: ${dto.sub}, deliveryMethod: ${dto.deliveryMethod ?? 'email'}, revokeSessions: ${dto.revokeSessions ?? false}, baseUrl: ${dto.baseUrl ?? 'none'}, reason: ${dto.reason ?? 'none'} }`);
746
+ const user = (await this.userRepository.findOne({ where: { sub: dto.sub } }));
747
+ if (!user) {
748
+ this.logger?.warn?.(`Admin password reset failed - user not found: ${dto.sub}`);
749
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
750
+ }
751
+ if (!this.passwordResetService) {
752
+ this.logger?.error?.('Password reset service not available');
753
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.SERVICE_UNAVAILABLE, 'Password reset service is not configured. Please configure an email provider.');
754
+ }
755
+ const revokeSessions = dto.revokeSessions ?? false;
756
+ let sessionsRevoked = 0;
757
+ if (revokeSessions) {
758
+ sessionsRevoked = await this.sessionService.revokeAllUserSessions(user.id, 'Admin initiated password reset');
759
+ this.logger?.log?.(`Revoked ${sessionsRevoked} sessions for user ${user.sub}`);
760
+ }
761
+ const delivery = dto.deliveryMethod || 'email';
762
+ const expiresIn = dto.codeExpiresIn || 3600;
763
+ const result = await this.passwordResetService.requestAdminReset(user, delivery, {
764
+ expiresIn,
765
+ baseUrl: dto.baseUrl,
766
+ });
767
+ await this.auditService?.recordEvent({
768
+ userId: user.id,
769
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.ADMIN_PASSWORD_RESET_INITIATED,
770
+ eventStatus: 'INFO',
771
+ authMethod: 'password',
772
+ description: dto.reason || 'Admin initiated password reset',
773
+ reason: dto.reason,
774
+ metadata: {
775
+ sub: dto.sub,
776
+ medium: delivery,
777
+ expiresIn,
778
+ sessionsRevoked,
779
+ hasBaseUrl: !!dto.baseUrl,
780
+ },
781
+ });
782
+ return {
783
+ success: true,
784
+ destination: result.destination,
785
+ deliveryMedium: result.deliveryMedium,
786
+ expiresIn: result.expiresIn,
787
+ sessionsRevoked: revokeSessions ? sessionsRevoked : undefined,
788
+ };
789
+ }
790
+ /**
791
+ * Complete admin-initiated password reset with a verification code.
792
+ *
793
+ * @param dto - Confirm admin reset password request
794
+ * @returns Success response
795
+ * @throws {NAuthException} NOT_FOUND | PASSWORD_RESET_CODE_INVALID | PASSWORD_RESET_CODE_EXPIRED | PASSWORD_RESET_MAX_ATTEMPTS | WEAK_PASSWORD | PASSWORD_REUSED | INVALID_CREDENTIALS
796
+ *
797
+ * @example
798
+ * ```typescript
799
+ * await adminAuthService.confirmResetPassword({ sub: 'user-uuid', code: '123456', newPassword: 'NewPass123!' });
800
+ * ```
801
+ */
802
+ async confirmResetPassword(dto) {
803
+ dto = await (0, dto_validator_1.ensureValidatedDto)(admin_reset_password_dto_1.ConfirmAdminResetPasswordDTO, dto);
804
+ this.logger?.log?.(`Confirm admin password reset for sub: ${dto.sub}`);
805
+ const user = (await this.userRepository.findOne({ where: { sub: dto.sub } }));
806
+ if (!user) {
807
+ this.logger?.warn?.(`Confirm admin reset failed - user not found: ${dto.sub}`);
808
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
809
+ }
810
+ if (!this.passwordResetService) {
811
+ this.logger?.error?.('Password reset service not available');
812
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.SERVICE_UNAVAILABLE, 'Password reset service is not configured. Please configure an email provider.');
813
+ }
814
+ await this.passwordResetService.consumeValidCode(user, dto.code, 'admin_password_reset');
815
+ await this.helpers.updateUserPassword({
816
+ user,
817
+ newPassword: dto.newPassword,
818
+ mustChangePassword: false,
819
+ revokeSessions: true,
820
+ revokeReason: 'Admin-initiated password reset completed',
821
+ audit: {
822
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.ADMIN_PASSWORD_RESET_COMPLETED,
823
+ eventStatus: 'SUCCESS',
824
+ description: 'User completed admin-initiated password reset',
825
+ metadata: {
826
+ usedCode: true,
827
+ sub: dto.sub,
828
+ },
829
+ },
830
+ }, this.passwordService, this.auditService);
831
+ return {
832
+ success: true,
833
+ };
834
+ }
835
+ /**
836
+ * Admin-only: Reset a user's password by sub.
837
+ *
838
+ * @param dto - Admin reset password request
839
+ * @returns Response with success status and session revocation count
840
+ * @throws {NAuthException} If user not found, user has no password (social-only), or password validation fails
841
+ *
842
+ * @example
843
+ * ```typescript
844
+ * const result = await adminAuthService.setPassword({ sub: 'user-uuid', newPassword: 'NewPass123!' });
845
+ * ```
846
+ */
847
+ async setPassword(dto) {
848
+ dto = await (0, dto_validator_1.ensureValidatedDto)(admin_set_password_dto_1.AdminSetPasswordDTO, dto);
849
+ this.logger?.log?.(`Admin password reset requested for sub: ${dto.sub}`);
850
+ this.logger?.debug?.(`Reset details: { sub: ${dto.sub}, mustChangePassword: ${dto.mustChangePassword ?? true}, revokeSessions: ${dto.revokeSessions ?? true} }`);
851
+ const user = (await this.userRepository.findOne({ where: { sub: dto.sub } }));
852
+ if (!user) {
853
+ this.logger?.warn?.(`Password reset failed - user not found: ${dto.sub}`);
854
+ throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
855
+ }
856
+ const mustChangePassword = dto.mustChangePassword ?? true;
857
+ const revokeSessions = dto.revokeSessions !== false;
858
+ const wasSocialOnly = !user.passwordHash;
859
+ const { sessionsRevoked } = await this.helpers.updateUserPassword({
860
+ user,
861
+ newPassword: dto.newPassword,
862
+ mustChangePassword,
863
+ revokeSessions,
864
+ revokeReason: 'Password reset by administrator',
865
+ audit: {
866
+ eventType: auth_audit_event_type_enum_1.AuthAuditEventType.PASSWORD_RESET_COMPLETED,
867
+ eventStatus: 'SUCCESS',
868
+ reason: 'admin_reset',
869
+ description: 'Password reset by administrator',
870
+ metadata: {
871
+ sub: dto.sub,
872
+ mustChangePassword,
873
+ wasSocialOnly,
874
+ },
875
+ },
876
+ }, this.passwordService, this.auditService);
877
+ return {
878
+ success: true,
879
+ mustChangePassword,
880
+ sessionsRevoked,
881
+ };
882
+ }
883
+ }
884
+ exports.AdminAuthService = AdminAuthService;
885
+ //# sourceMappingURL=admin-auth.service.js.map