@nauth-toolkit/mfa-totp 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.
- package/dist/nestjs/index.d.ts +5 -0
- package/dist/nestjs/index.d.ts.map +1 -1
- package/dist/nestjs/index.js +6 -0
- package/dist/nestjs/index.js.map +1 -1
- package/dist/nestjs/totp-mfa.module.d.ts +20 -0
- package/dist/nestjs/totp-mfa.module.d.ts.map +1 -1
- package/dist/nestjs/totp-mfa.module.js +27 -1
- package/dist/nestjs/totp-mfa.module.js.map +1 -1
- package/dist/src/dto/mfa.dto.d.ts +476 -0
- package/dist/src/dto/mfa.dto.d.ts.map +1 -1
- package/dist/src/dto/mfa.dto.js +9 -0
- package/dist/src/dto/mfa.dto.js.map +1 -1
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/totp-mfa-provider.service.d.ts +81 -1
- package/dist/src/totp-mfa-provider.service.d.ts.map +1 -1
- package/dist/src/totp-mfa-provider.service.js +101 -3
- package/dist/src/totp-mfa-provider.service.js.map +1 -1
- package/dist/src/totp.service.d.ts +158 -0
- package/dist/src/totp.service.d.ts.map +1 -1
- package/dist/src/totp.service.js +184 -1
- package/dist/src/totp.service.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/src/totp.service.js
CHANGED
|
@@ -37,6 +37,28 @@ exports.TOTPService = void 0;
|
|
|
37
37
|
const otplib_1 = require("otplib");
|
|
38
38
|
const QRCode = __importStar(require("qrcode"));
|
|
39
39
|
const core_1 = require("@nauth-toolkit/core");
|
|
40
|
+
/**
|
|
41
|
+
* TOTP (Time-based One-Time Password) Service
|
|
42
|
+
*
|
|
43
|
+
* Handles authenticator app functionality including:
|
|
44
|
+
* - Secret generation for new TOTP devices
|
|
45
|
+
* - QR code generation for easy setup
|
|
46
|
+
* - TOTP code validation with time window
|
|
47
|
+
* - Compatible with Google Authenticator, Authy, 1Password, etc.
|
|
48
|
+
*
|
|
49
|
+
* Uses industry-standard TOTP (RFC 6238) with configurable parameters.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* // Generate TOTP setup
|
|
54
|
+
* const setup = await totpService.generateSecret('user@example.com');
|
|
55
|
+
* // Returns: { secret, qrCode, manualEntryKey, issuer, accountName }
|
|
56
|
+
*
|
|
57
|
+
* // Verify TOTP code
|
|
58
|
+
* const isValid = totpService.verifyCode('base32secret', '123456');
|
|
59
|
+
* // Returns: true if code is valid
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
40
62
|
class TOTPService {
|
|
41
63
|
config;
|
|
42
64
|
logger;
|
|
@@ -49,32 +71,80 @@ class TOTPService {
|
|
|
49
71
|
constructor(config, logger) {
|
|
50
72
|
this.config = config;
|
|
51
73
|
this.logger = logger;
|
|
74
|
+
// Configure otplib with settings from config
|
|
52
75
|
this.configureAuthenticator();
|
|
53
76
|
}
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// Configuration
|
|
79
|
+
// ============================================================================
|
|
80
|
+
/**
|
|
81
|
+
* Configure otplib authenticator with config settings
|
|
82
|
+
*
|
|
83
|
+
* Applies TOTP configuration from NAuthConfig or uses defaults.
|
|
84
|
+
* Called during service initialization.
|
|
85
|
+
*
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
54
88
|
configureAuthenticator() {
|
|
55
89
|
const totpConfig = this.getTOTPConfig();
|
|
56
90
|
otplib_1.authenticator.options = {
|
|
57
91
|
step: totpConfig.stepSeconds,
|
|
58
92
|
window: totpConfig.window,
|
|
59
93
|
digits: totpConfig.digits,
|
|
60
|
-
algorithm: totpConfig.algorithm,
|
|
94
|
+
algorithm: totpConfig.algorithm, // Type cast - otplib types don't match our config
|
|
61
95
|
};
|
|
62
96
|
this.logger?.debug?.(`TOTP configured: step=${totpConfig.stepSeconds}s, window=${totpConfig.window}, digits=${totpConfig.digits}`);
|
|
63
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Get TOTP configuration with defaults
|
|
100
|
+
*
|
|
101
|
+
* @returns Complete TOTP configuration
|
|
102
|
+
* @private
|
|
103
|
+
*/
|
|
64
104
|
getTOTPConfig() {
|
|
65
105
|
return {
|
|
66
106
|
...this.defaultConfig,
|
|
67
107
|
...this.config.mfa?.totp,
|
|
68
108
|
};
|
|
69
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Get issuer name for TOTP URIs
|
|
112
|
+
*
|
|
113
|
+
* @returns Issuer name from config or default
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
70
116
|
getIssuer() {
|
|
71
117
|
return this.config.mfa?.issuer || 'nauth-toolkit';
|
|
72
118
|
}
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// Secret Generation
|
|
121
|
+
// ============================================================================
|
|
122
|
+
/**
|
|
123
|
+
* Generate TOTP secret and QR code for user setup
|
|
124
|
+
*
|
|
125
|
+
* Creates a new TOTP secret, generates QR code and manual entry key.
|
|
126
|
+
* User must scan QR code with authenticator app to complete setup.
|
|
127
|
+
*
|
|
128
|
+
* @param accountName - User's email or username (displayed in authenticator app)
|
|
129
|
+
* @returns Setup information including QR code and secret
|
|
130
|
+
* @throws {BadRequestException} If QR code generation fails
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const setup = await totpService.generateSecret('user@example.com');
|
|
135
|
+
* // Client displays QR code and manual entry key
|
|
136
|
+
* // User scans QR with Google Authenticator, Authy, etc.
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
73
139
|
async generateSecret(accountName) {
|
|
74
140
|
this.logger?.log?.(`Generating TOTP secret for: ${accountName}`);
|
|
141
|
+
// Generate base32-encoded secret
|
|
75
142
|
const secret = otplib_1.authenticator.generateSecret();
|
|
143
|
+
// Get issuer name
|
|
76
144
|
const issuer = this.getIssuer();
|
|
145
|
+
// Generate otpauth URI for QR code
|
|
77
146
|
const otpauthUrl = otplib_1.authenticator.keyuri(accountName, issuer, secret);
|
|
147
|
+
// Generate QR code as data URL
|
|
78
148
|
let qrCode;
|
|
79
149
|
try {
|
|
80
150
|
qrCode = await QRCode.toDataURL(otpauthUrl);
|
|
@@ -83,6 +153,7 @@ class TOTPService {
|
|
|
83
153
|
this.logger?.error?.('Failed to generate QR code', error);
|
|
84
154
|
throw new core_1.NAuthException(core_1.AuthErrorCode.INTERNAL_ERROR, 'Failed to generate QR code');
|
|
85
155
|
}
|
|
156
|
+
// Format secret for manual entry (groups of 4 characters)
|
|
86
157
|
const manualEntryKey = this.formatSecretForManualEntry(secret);
|
|
87
158
|
this.logger?.log?.(`TOTP secret generated successfully for: ${accountName}`);
|
|
88
159
|
return {
|
|
@@ -93,16 +164,58 @@ class TOTPService {
|
|
|
93
164
|
accountName,
|
|
94
165
|
};
|
|
95
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Format secret for manual entry
|
|
169
|
+
*
|
|
170
|
+
* Converts base32 secret into groups of 4 characters for easy manual input.
|
|
171
|
+
*
|
|
172
|
+
* @param secret - Base32-encoded secret
|
|
173
|
+
* @returns Formatted secret (e.g., 'ABCD EFGH IJKL MNOP')
|
|
174
|
+
* @private
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* formatSecretForManualEntry('ABCDEFGHIJKLMNOP')
|
|
179
|
+
* // Returns: 'ABCD EFGH IJKL MNOP'
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
96
182
|
formatSecretForManualEntry(secret) {
|
|
97
183
|
return secret.match(/.{1,4}/g)?.join(' ') || secret;
|
|
98
184
|
}
|
|
185
|
+
// ============================================================================
|
|
186
|
+
// Code Verification
|
|
187
|
+
// ============================================================================
|
|
188
|
+
/**
|
|
189
|
+
* Verify TOTP code against secret
|
|
190
|
+
*
|
|
191
|
+
* Validates a 6-digit TOTP code using time-based verification.
|
|
192
|
+
* Checks current time step plus configured window (before/after).
|
|
193
|
+
*
|
|
194
|
+
* SECURITY: Uses time window to account for clock drift and user delay.
|
|
195
|
+
* Default window of 1 checks 3 time steps (current, ±1).
|
|
196
|
+
*
|
|
197
|
+
* @param secret - Base32-encoded TOTP secret
|
|
198
|
+
* @param code - 6-digit TOTP code from authenticator app
|
|
199
|
+
* @returns True if code is valid within time window
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // User enters code from Google Authenticator
|
|
204
|
+
* const isValid = totpService.verifyCode(user.totpSecret, '123456');
|
|
205
|
+
* if (isValid) {
|
|
206
|
+
* // Grant access
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
99
210
|
verifyCode(secret, code) {
|
|
100
211
|
try {
|
|
212
|
+
// Remove spaces and validate format
|
|
101
213
|
const cleanCode = code.replace(/\s/g, '');
|
|
102
214
|
if (!/^\d{6}$/.test(cleanCode)) {
|
|
103
215
|
this.logger?.warn?.('Invalid TOTP code format');
|
|
104
216
|
return false;
|
|
105
217
|
}
|
|
218
|
+
// Verify code using otplib
|
|
106
219
|
const isValid = otplib_1.authenticator.verify({
|
|
107
220
|
token: cleanCode,
|
|
108
221
|
secret,
|
|
@@ -120,7 +233,25 @@ class TOTPService {
|
|
|
120
233
|
return false;
|
|
121
234
|
}
|
|
122
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Verify TOTP code with additional validation
|
|
238
|
+
*
|
|
239
|
+
* Extended verification that checks code format and provides detailed error messages.
|
|
240
|
+
*
|
|
241
|
+
* @param secret - Base32-encoded TOTP secret
|
|
242
|
+
* @param code - TOTP code to verify
|
|
243
|
+
* @returns Verification result with error message if invalid
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* const result = totpService.verifyCodeWithDetails(secret, '123456');
|
|
248
|
+
* if (!result.valid) {
|
|
249
|
+
* throw new BadRequestException(result.error);
|
|
250
|
+
* }
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
123
253
|
verifyCodeWithDetails(secret, code) {
|
|
254
|
+
// Validate code format
|
|
124
255
|
const cleanCode = code.replace(/\s/g, '');
|
|
125
256
|
if (!cleanCode) {
|
|
126
257
|
return { valid: false, error: 'Code is required' };
|
|
@@ -128,30 +259,82 @@ class TOTPService {
|
|
|
128
259
|
if (!/^\d{6}$/.test(cleanCode)) {
|
|
129
260
|
return { valid: false, error: 'Code must be 6 digits' };
|
|
130
261
|
}
|
|
262
|
+
// Verify secret format
|
|
131
263
|
if (!secret || secret.length < 16) {
|
|
132
264
|
return { valid: false, error: 'Invalid secret' };
|
|
133
265
|
}
|
|
266
|
+
// Verify code
|
|
134
267
|
const isValid = this.verifyCode(secret, cleanCode);
|
|
135
268
|
if (!isValid) {
|
|
136
269
|
return { valid: false, error: 'Invalid or expired code' };
|
|
137
270
|
}
|
|
138
271
|
return { valid: true };
|
|
139
272
|
}
|
|
273
|
+
// ============================================================================
|
|
274
|
+
// Utility Methods
|
|
275
|
+
// ============================================================================
|
|
276
|
+
/**
|
|
277
|
+
* Generate current TOTP code for secret
|
|
278
|
+
*
|
|
279
|
+
* FOR TESTING ONLY - Do not use in production authentication flow.
|
|
280
|
+
* This method generates the current valid code for a secret.
|
|
281
|
+
*
|
|
282
|
+
* @param secret - Base32-encoded TOTP secret
|
|
283
|
+
* @returns Current 6-digit TOTP code
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* // Testing only
|
|
288
|
+
* const code = totpService.generateCode(secret);
|
|
289
|
+
* // Returns: '123456'
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
140
292
|
generateCode(secret) {
|
|
141
293
|
return otplib_1.authenticator.generate(secret);
|
|
142
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Validate secret format
|
|
297
|
+
*
|
|
298
|
+
* Checks if a secret is valid base32 and has sufficient length.
|
|
299
|
+
*
|
|
300
|
+
* @param secret - Secret to validate
|
|
301
|
+
* @returns True if secret is valid
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* if (!totpService.isValidSecret(secret)) {
|
|
306
|
+
* throw new BadRequestException('Invalid TOTP secret');
|
|
307
|
+
* }
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
143
310
|
isValidSecret(secret) {
|
|
144
311
|
if (!secret || typeof secret !== 'string') {
|
|
145
312
|
return false;
|
|
146
313
|
}
|
|
314
|
+
// Check minimum length (16 characters for 80 bits of entropy)
|
|
147
315
|
if (secret.length < 16) {
|
|
148
316
|
return false;
|
|
149
317
|
}
|
|
318
|
+
// Check if valid base32 (A-Z, 2-7, no padding for otplib)
|
|
150
319
|
if (!/^[A-Z2-7]+$/.test(secret)) {
|
|
151
320
|
return false;
|
|
152
321
|
}
|
|
153
322
|
return true;
|
|
154
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Get time remaining until next code
|
|
326
|
+
*
|
|
327
|
+
* Returns seconds until the current TOTP code expires.
|
|
328
|
+
* Useful for UI countdowns.
|
|
329
|
+
*
|
|
330
|
+
* @returns Seconds remaining (0-30 for default 30s step)
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* ```typescript
|
|
334
|
+
* const remaining = totpService.getTimeRemaining();
|
|
335
|
+
* // Returns: 15 (seconds until code changes)
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
155
338
|
getTimeRemaining() {
|
|
156
339
|
const totpConfig = this.getTOTPConfig();
|
|
157
340
|
const now = Math.floor(Date.now() / 1000);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"totp.service.js","sourceRoot":"","sources":["../../src/totp.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAAuC;AACvC,+CAAiC;AACjC,8CAA0G;
|
|
1
|
+
{"version":3,"file":"totp.service.js","sourceRoot":"","sources":["../../src/totp.service.ts"],"names":[],"mappings":"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"}
|