@nauth-toolkit/mfa-sms 0.1.13 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,118 @@
1
1
  import { Repository } from 'typeorm';
2
2
  import { BaseMFADevice, BaseUser, IUser, NAuthConfig, NAuthLogger, PhoneVerificationService, MFAMethod } from '@nauth-toolkit/core';
3
3
  import { BaseMFAProviderService } from '@nauth-toolkit/core/internal';
4
+ /**
5
+ * SMS MFA Provider Service
6
+ *
7
+ * Implements SMS-based MFA method.
8
+ * Extends BaseMFAProviderService to provide SMS-specific functionality.
9
+ *
10
+ * This service handles:
11
+ * - SMS code sending during setup and authentication
12
+ * - SMS code verification
13
+ * - MFA device creation for SMS
14
+ *
15
+ * Requires PhoneVerificationService from core (available when SMS provider is configured).
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * @Module({
20
+ * imports: [SMSMFAModule],
21
+ * })
22
+ * export class AppModule {}
23
+ * ```
24
+ */
4
25
  export declare class SMSMFAProviderService extends BaseMFAProviderService {
5
26
  private readonly phoneVerificationService?;
6
27
  readonly methodName = MFAMethod.SMS;
7
- constructor(mfaDeviceRepository: Repository<BaseMFADevice>, userRepository: Repository<BaseUser>, config: NAuthConfig, logger: NAuthLogger, passwordService: unknown, phoneVerificationService?: PhoneVerificationService | undefined, challengeService?: unknown, auditService?: unknown, clientInfoService?: unknown);
28
+ constructor(mfaDeviceRepository: Repository<BaseMFADevice>, userRepository: Repository<BaseUser>, config: NAuthConfig, logger: NAuthLogger, passwordService: unknown, phoneVerificationService?: PhoneVerificationService | undefined, challengeService?: unknown, // ChallengeService (optional)
29
+ auditService?: unknown, // AuthAuditService (optional)
30
+ clientInfoService?: unknown);
31
+ /**
32
+ * Setup SMS MFA for user
33
+ *
34
+ * Sends verification code to phone number, or auto-completes setup if phone is already verified.
35
+ * User must verify code to complete setup (unless phone is already verified).
36
+ *
37
+ * @param user - User setting up SMS MFA
38
+ * @param setupData - Setup data (must be SetupSMSMFADTO)
39
+ * @returns Setup result with deviceId if auto-completed, or maskedPhone if code was sent
40
+ * @throws {NAuthException} If SMS is not enabled or phone verification service unavailable
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const result = await provider.setup(user, {
45
+ * phoneNumber: '+1234567890',
46
+ * deviceName: 'My Phone'
47
+ * });
48
+ * // If phone verified: { deviceId: 123, autoCompleted: true }
49
+ * // If phone not verified: { maskedPhone: '***-***-7890' } (SMS code sent)
50
+ * ```
51
+ */
8
52
  setup(user: IUser, setupData?: unknown): Promise<{
9
53
  deviceId: number;
10
54
  autoCompleted: true;
11
55
  } | {
12
56
  maskedPhone: string;
13
57
  }>;
58
+ /**
59
+ * Verify and complete SMS MFA setup
60
+ *
61
+ * Validates the SMS code and stores the device if valid.
62
+ * Enables MFA for user if this is their first device.
63
+ *
64
+ * **Race Condition Safety:**
65
+ * Device creation uses transaction with pessimistic locking to prevent duplicates.
66
+ * If device already exists (e.g., from concurrent request), returns existing device.
67
+ * Database unique constraint (userId, type) provides final safety net.
68
+ *
69
+ * @param user - User completing SMS MFA setup
70
+ * @param verificationData - Verification data (must be VerifySMSMFASetupDTO)
71
+ * @param deviceName - Optional device name override
72
+ * @returns MFA device ID (created or existing)
73
+ * @throws {NAuthException} If code is invalid
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const deviceId = await provider.verifySetup(user, {
78
+ * phoneNumber: '+1234567890',
79
+ * code: '123456'
80
+ * });
81
+ * ```
82
+ */
14
83
  verifySetup(user: IUser, verificationData: unknown, deviceName?: string): Promise<number>;
84
+ /**
85
+ * Verify SMS code during authentication
86
+ *
87
+ * Validates the SMS code for an existing device.
88
+ *
89
+ * @param user - User being authenticated
90
+ * @param code - SMS code (string)
91
+ * @param deviceId - Optional device ID to verify against
92
+ * @returns True if verification succeeds
93
+ * @throws {NAuthException} If device not found or verification fails
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * const isValid = await provider.verify(user, '123456');
98
+ * ```
99
+ */
15
100
  verify(user: IUser, code: unknown, deviceId?: number): Promise<boolean>;
101
+ /**
102
+ * Send SMS code for MFA verification
103
+ *
104
+ * Called during login MFA challenge to send code to registered phone.
105
+ *
106
+ * @param user - User requesting SMS code
107
+ * @returns Masked phone number where code was sent
108
+ * @throws {NAuthException} If no SMS device registered or phone verification service unavailable
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const maskedPhone = await provider.sendChallenge(user);
113
+ * // Returns: '***-***-1234'
114
+ * ```
115
+ */
16
116
  sendChallenge(user: IUser): Promise<string>;
17
117
  }
18
118
  //# sourceMappingURL=sms-mfa-provider.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sms-mfa-provider.service.d.ts","sourceRoot":"","sources":["../../src/sms-mfa-provider.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EACL,aAAa,EACb,QAAQ,EACR,KAAK,EACL,WAAW,EACX,WAAW,EAGX,wBAAwB,EACxB,SAAS,EAGV,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAyBtE,qBAAa,qBAAsB,SAAQ,sBAAsB;IAS7D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAR5C,QAAQ,CAAC,UAAU,iBAAiB;gBAGlC,mBAAmB,EAAE,UAAU,CAAC,aAAa,CAAC,EAC9C,cAAc,EAAE,UAAU,CAAC,QAAQ,CAAC,EACpC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,OAAO,EACP,wBAAwB,CAAC,EAAE,wBAAwB,YAAA,EACpE,gBAAgB,CAAC,EAAE,OAAO,EAC1B,YAAY,CAAC,EAAE,OAAO,EACtB,iBAAiB,CAAC,EAAE,OAAO;IAmCvB,KAAK,CACT,IAAI,EAAE,KAAK,EACX,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAkGzE,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwFzF,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkFvE,aAAa,CAAC,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;CA2ClD"}
1
+ {"version":3,"file":"sms-mfa-provider.service.d.ts","sourceRoot":"","sources":["../../src/sms-mfa-provider.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EACL,aAAa,EACb,QAAQ,EACR,KAAK,EACL,WAAW,EACX,WAAW,EAGX,wBAAwB,EACxB,SAAS,EAGV,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGtE;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,qBAAa,qBAAsB,SAAQ,sBAAsB;IAS7D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAR5C,QAAQ,CAAC,UAAU,iBAAiB;gBAGlC,mBAAmB,EAAE,UAAU,CAAC,aAAa,CAAC,EAC9C,cAAc,EAAE,UAAU,CAAC,QAAQ,CAAC,EACpC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,OAAO,EACP,wBAAwB,CAAC,EAAE,wBAAwB,YAAA,EACpE,gBAAgB,CAAC,EAAE,OAAO,EAAE,8BAA8B;IAC1D,YAAY,CAAC,EAAE,OAAO,EAAE,8BAA8B;IACtD,iBAAiB,CAAC,EAAE,OAAO;IAc7B;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,KAAK,CACT,IAAI,EAAE,KAAK,EACX,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAyE/E;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwE/F;;;;;;;;;;;;;;;OAeG;IACG,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmE7E;;;;;;;;;;;;;;OAcG;IACG,aAAa,CAAC,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;CA2ClD"}
@@ -1,38 +1,95 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SMSMFAProviderService = void 0;
4
+ // Public API imports
4
5
  const core_1 = require("@nauth-toolkit/core");
6
+ // Internal API imports (for provider implementations)
5
7
  const internal_1 = require("@nauth-toolkit/core/internal");
8
+ /**
9
+ * SMS MFA Provider Service
10
+ *
11
+ * Implements SMS-based MFA method.
12
+ * Extends BaseMFAProviderService to provide SMS-specific functionality.
13
+ *
14
+ * This service handles:
15
+ * - SMS code sending during setup and authentication
16
+ * - SMS code verification
17
+ * - MFA device creation for SMS
18
+ *
19
+ * Requires PhoneVerificationService from core (available when SMS provider is configured).
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * @Module({
24
+ * imports: [SMSMFAModule],
25
+ * })
26
+ * export class AppModule {}
27
+ * ```
28
+ */
6
29
  class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
7
30
  phoneVerificationService;
8
31
  methodName = core_1.MFAMethod.SMS;
9
- constructor(mfaDeviceRepository, userRepository, config, logger, passwordService, phoneVerificationService, challengeService, auditService, clientInfoService) {
32
+ constructor(mfaDeviceRepository, userRepository, config, logger, passwordService, phoneVerificationService, challengeService, // ChallengeService (optional)
33
+ auditService, // AuthAuditService (optional)
34
+ clientInfoService) {
10
35
  super(mfaDeviceRepository, userRepository, config, logger, passwordService, challengeService, auditService, clientInfoService);
11
36
  this.phoneVerificationService = phoneVerificationService;
12
37
  }
38
+ /**
39
+ * Setup SMS MFA for user
40
+ *
41
+ * Sends verification code to phone number, or auto-completes setup if phone is already verified.
42
+ * User must verify code to complete setup (unless phone is already verified).
43
+ *
44
+ * @param user - User setting up SMS MFA
45
+ * @param setupData - Setup data (must be SetupSMSMFADTO)
46
+ * @returns Setup result with deviceId if auto-completed, or maskedPhone if code was sent
47
+ * @throws {NAuthException} If SMS is not enabled or phone verification service unavailable
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const result = await provider.setup(user, {
52
+ * phoneNumber: '+1234567890',
53
+ * deviceName: 'My Phone'
54
+ * });
55
+ * // If phone verified: { deviceId: 123, autoCompleted: true }
56
+ * // If phone not verified: { maskedPhone: '***-***-7890' } (SMS code sent)
57
+ * ```
58
+ */
13
59
  async setup(user, setupData) {
14
60
  this.logger?.log?.(`Setting up SMS MFA for user: ${user.sub}`);
61
+ // Check if SMS is allowed
15
62
  if (!this.isMethodAllowed()) {
16
63
  throw new core_1.NAuthException(core_1.AuthErrorCode.VALIDATION_FAILED, 'SMS MFA is not enabled', { feature: 'sms-mfa' });
17
64
  }
18
65
  const dto = setupData;
19
66
  const userEntity = user;
20
67
  const isPhoneVerified = userEntity.isPhoneVerified || false;
68
+ // Get phone number from setupData or user object
21
69
  const phoneNumber = dto?.phoneNumber || userEntity.phone;
22
70
  if (!phoneNumber) {
23
71
  throw new core_1.NAuthException(core_1.AuthErrorCode.PHONE_REQUIRED, 'Phone number is required for SMS MFA setup. Please provide a phone number.');
24
72
  }
73
+ // ============================================================================
74
+ // Special case: If phone is already verified, auto-complete MFA setup
75
+ // No SMS code needed - create device directly
76
+ // ============================================================================
25
77
  if (isPhoneVerified) {
26
78
  this.logger?.log?.(`Phone already verified for user ${user.sub}, auto-completing SMS MFA setup`);
79
+ // Auto-create MFA device without code verification
27
80
  const deviceId = await this.verifySetup(user, {
28
81
  phoneNumber,
29
- code: '',
82
+ code: '', // Code not needed when phone is verified
30
83
  }, dto?.deviceName);
31
84
  return { deviceId, autoCompleted: true };
32
85
  }
86
+ // Phone not verified - send SMS verification code
87
+ // Check if phone verification service is available
33
88
  if (!this.phoneVerificationService) {
34
89
  throw new core_1.NAuthException(core_1.AuthErrorCode.VALIDATION_FAILED, 'Phone verification service is not available. SMS provider must be configured.');
35
90
  }
91
+ // Send SMS verification code (phone not verified, so code is required)
92
+ // Link verification token to challenge session if provided in setupData
36
93
  const sendDto = new core_1.SendVerificationSMSDTO();
37
94
  sendDto.sub = user.sub;
38
95
  const setupDataWithSession = setupData;
@@ -46,8 +103,34 @@ class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
46
103
  await this.phoneVerificationService.sendVerificationSMS(sendDto);
47
104
  const maskedPhone = this.maskPhone(phoneNumber);
48
105
  this.logger?.log?.(`SMS MFA code sent to: ${maskedPhone}`);
106
+ // Return masked phone for frontend display
49
107
  return { maskedPhone };
50
108
  }
109
+ /**
110
+ * Verify and complete SMS MFA setup
111
+ *
112
+ * Validates the SMS code and stores the device if valid.
113
+ * Enables MFA for user if this is their first device.
114
+ *
115
+ * **Race Condition Safety:**
116
+ * Device creation uses transaction with pessimistic locking to prevent duplicates.
117
+ * If device already exists (e.g., from concurrent request), returns existing device.
118
+ * Database unique constraint (userId, type) provides final safety net.
119
+ *
120
+ * @param user - User completing SMS MFA setup
121
+ * @param verificationData - Verification data (must be VerifySMSMFASetupDTO)
122
+ * @param deviceName - Optional device name override
123
+ * @returns MFA device ID (created or existing)
124
+ * @throws {NAuthException} If code is invalid
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const deviceId = await provider.verifySetup(user, {
129
+ * phoneNumber: '+1234567890',
130
+ * code: '123456'
131
+ * });
132
+ * ```
133
+ */
51
134
  async verifySetup(user, verificationData, deviceName) {
52
135
  this.logger?.log?.(`Verifying SMS MFA setup for user: ${user.sub}`);
53
136
  const dto = verificationData;
@@ -55,7 +138,12 @@ class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
55
138
  const userId = userEntity.id;
56
139
  const userMfaEnabled = userEntity.mfaEnabled || false;
57
140
  const isPhoneVerified = userEntity.isPhoneVerified || false;
141
+ // ============================================================================
142
+ // Special case: If phone is already verified, skip code verification
143
+ // This improves UX by avoiding redundant SMS verification after phone verification
144
+ // ============================================================================
58
145
  if (!isPhoneVerified) {
146
+ // Phone not verified - verify SMS code (this will also mark phone as verified)
59
147
  if (!this.phoneVerificationService) {
60
148
  throw new core_1.NAuthException(core_1.AuthErrorCode.VALIDATION_FAILED, 'Phone verification service is not available. SMS provider must be configured.');
61
149
  }
@@ -63,6 +151,7 @@ class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
63
151
  throw new core_1.NAuthException(core_1.AuthErrorCode.VALIDATION_FAILED, 'Verification code is required');
64
152
  }
65
153
  try {
154
+ // Verify phone with code - this will mark phone as verified in the database
66
155
  const verifyDto = new core_1.VerifyPhoneWithCodeBySubDTO();
67
156
  verifyDto.sub = user.sub;
68
157
  verifyDto.code = dto.code;
@@ -70,26 +159,52 @@ class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
70
159
  this.logger?.log?.(`Phone verified during SMS MFA setup for user ${user.sub} - phone is now marked as verified in database`);
71
160
  }
72
161
  catch (error) {
162
+ // Re-throw with more specific error message
73
163
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
74
164
  this.logger?.error?.(`Failed to verify phone during SMS MFA setup for user ${user.sub}: ${errorMessage}`, error);
75
165
  throw new core_1.NAuthException(core_1.AuthErrorCode.VERIFICATION_CODE_INVALID, 'Invalid SMS code');
76
166
  }
77
167
  }
78
168
  else {
169
+ // Phone already verified - skip code verification
79
170
  this.logger?.log?.(`Phone already verified for user ${user.sub}, skipping SMS code verification during MFA setup`);
80
171
  }
172
+ // ============================================================================
173
+ // Create MFA device (transaction-safe with duplicate prevention)
174
+ // ============================================================================
175
+ // createDevice() uses pessimistic locking to prevent race conditions
176
+ // If device already exists, returns existing device instead of creating duplicate
177
+ // Database unique constraint (userId, type) provides additional safety
81
178
  const device = await this.createDevice(userId, {
82
179
  name: deviceName || 'SMS Phone',
83
180
  phoneNumber: dto.phoneNumber,
84
181
  isActive: true,
85
- isPrimary: !userMfaEnabled,
182
+ isPrimary: !userMfaEnabled, // First device becomes primary
86
183
  });
184
+ // Enable MFA if not already enabled
87
185
  await this.enableMFAForUser(user);
88
186
  this.logger?.log?.(`SMS MFA setup completed for user: ${user.sub}`);
89
187
  return device.id;
90
188
  }
189
+ /**
190
+ * Verify SMS code during authentication
191
+ *
192
+ * Validates the SMS code for an existing device.
193
+ *
194
+ * @param user - User being authenticated
195
+ * @param code - SMS code (string)
196
+ * @param deviceId - Optional device ID to verify against
197
+ * @returns True if verification succeeds
198
+ * @throws {NAuthException} If device not found or verification fails
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * const isValid = await provider.verify(user, '123456');
203
+ * ```
204
+ */
91
205
  async verify(user, code, deviceId) {
92
206
  this.logger?.log?.(`Verifying SMS code for user: ${user.sub}`);
207
+ // Check if phone verification service is available
93
208
  if (!this.phoneVerificationService) {
94
209
  this.logger?.warn?.('SMS verification attempted but phone verification service is not available');
95
210
  return false;
@@ -99,11 +214,21 @@ class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
99
214
  this.logger?.warn?.('Invalid SMS code format');
100
215
  return false;
101
216
  }
217
+ // Get user entity
102
218
  const userEntity = user;
103
219
  const userId = userEntity.id;
104
220
  const isPhoneVerified = userEntity.isPhoneVerified || false;
221
+ // Find device (optional - SMS verification uses phone verification service)
105
222
  const device = deviceId ? await this.findDevice(userId, deviceId) : null;
223
+ // Verify SMS code using phone verification service
106
224
  try {
225
+ // ============================================================================
226
+ // MFA Verification: Verify SMS code for authentication
227
+ // Note: verifyPhoneWithCodeBySub only marks phone as verified if not already verified.
228
+ // This avoids unnecessary database writes and updatedAt timestamp changes.
229
+ // 1. During MFA setup (verifySetup): We check isPhoneVerified first, so it only marks if not verified
230
+ // 2. During MFA login (verify): If phone is already verified, no user table update occurs
231
+ // ============================================================================
107
232
  const verifyDto = new core_1.VerifyPhoneWithCodeBySubDTO();
108
233
  verifyDto.sub = user.sub;
109
234
  verifyDto.code = smsCode;
@@ -114,6 +239,7 @@ class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
114
239
  else {
115
240
  this.logger?.log?.(`SMS code verified for MFA (phone already verified) for user: ${user.sub}`);
116
241
  }
242
+ // Update device usage if device found
117
243
  if (device) {
118
244
  await this.updateDeviceUsage(device.id);
119
245
  }
@@ -121,30 +247,55 @@ class SMSMFAProviderService extends internal_1.BaseMFAProviderService {
121
247
  return true;
122
248
  }
123
249
  catch (error) {
250
+ // Re-throw NAuthException to preserve specific error codes (e.g., VERIFY_TOO_MANY_ATTEMPTS)
251
+ // This allows the calling code to handle rate limiting and other specific errors correctly
124
252
  if (error instanceof core_1.NAuthException) {
125
253
  throw error;
126
254
  }
255
+ // For unexpected errors, log and return false (generic failure)
127
256
  const errorMessage = error instanceof Error ? error.message : String(error);
128
257
  const errorCode = error?.code || 'UNKNOWN';
129
258
  this.logger?.warn?.(`SMS code verification failed for user: ${user.sub}, code: ${smsCode}, error: ${errorCode} - ${errorMessage}`);
130
259
  return false;
131
260
  }
132
261
  }
262
+ /**
263
+ * Send SMS code for MFA verification
264
+ *
265
+ * Called during login MFA challenge to send code to registered phone.
266
+ *
267
+ * @param user - User requesting SMS code
268
+ * @returns Masked phone number where code was sent
269
+ * @throws {NAuthException} If no SMS device registered or phone verification service unavailable
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * const maskedPhone = await provider.sendChallenge(user);
274
+ * // Returns: '***-***-1234'
275
+ * ```
276
+ */
133
277
  async sendChallenge(user) {
134
278
  this.logger?.log?.(`Sending SMS MFA code for user: ${user.sub}`);
279
+ // Get user entity
135
280
  const userEntity = user;
136
281
  const userId = userEntity.id;
282
+ // Find active SMS device
137
283
  const device = await this.findDevice(userId);
138
284
  if (!device) {
139
285
  throw new core_1.NAuthException(core_1.AuthErrorCode.NOT_FOUND, 'No SMS device registered', { deviceType: 'sms' });
140
286
  }
287
+ // Get phone number from device or fall back to user phone
288
+ // Fallback handles legacy devices where phoneNumber field might be null
141
289
  const phoneNumber = device.phoneNumber || userEntity.phone;
142
290
  if (!phoneNumber) {
143
291
  throw new core_1.NAuthException(core_1.AuthErrorCode.VALIDATION_FAILED, 'No phone number found for SMS MFA. Please update your profile or re-setup SMS MFA.', { deviceType: 'sms' });
144
292
  }
293
+ // Check if phone verification service is available
145
294
  if (!this.phoneVerificationService) {
146
295
  throw new core_1.NAuthException(core_1.AuthErrorCode.VALIDATION_FAILED, 'Phone verification service is not available. SMS provider must be configured.');
147
296
  }
297
+ // Send SMS code for MFA verification
298
+ // Always send codes for MFA verification (even if phone is already verified)
148
299
  const sendDto = new core_1.SendVerificationSMSDTO();
149
300
  sendDto.sub = user.sub;
150
301
  sendDto.skipAlreadyVerifiedCheck = true;
@@ -1 +1 @@
1
- {"version":3,"file":"sms-mfa-provider.service.js","sourceRoot":"","sources":["../../src/sms-mfa-provider.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sms-mfa-provider.service.js","sourceRoot":"","sources":["../../src/sms-mfa-provider.service.ts"],"names":[],"mappings":"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"}