@nauth-toolkit/core 0.1.0 → 0.1.5
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/LICENSE +90 -0
- package/README.md +9 -0
- package/package.json +8 -3
- package/jest.config.js +0 -15
- package/jest.setup.ts +0 -6
- package/src/adapters/database-columns.ts +0 -165
- package/src/adapters/express.adapter.ts +0 -385
- package/src/adapters/fastify.adapter.ts +0 -416
- package/src/adapters/index.ts +0 -16
- package/src/adapters/storage.factory.ts +0 -143
- package/src/bootstrap.ts +0 -374
- package/src/dto/auth-challenge.dto.ts +0 -231
- package/src/dto/auth-response.dto.ts +0 -253
- package/src/dto/challenge-response.dto.ts +0 -234
- package/src/dto/change-password-request.dto.ts +0 -50
- package/src/dto/change-password-response.dto.ts +0 -29
- package/src/dto/change-password.dto.ts +0 -57
- package/src/dto/error-response.dto.ts +0 -136
- package/src/dto/get-available-methods.dto.ts +0 -55
- package/src/dto/get-challenge-data-response.dto.ts +0 -28
- package/src/dto/get-challenge-data.dto.ts +0 -69
- package/src/dto/get-client-info.dto.ts +0 -104
- package/src/dto/get-device-token-response.dto.ts +0 -25
- package/src/dto/get-events-by-type.dto.ts +0 -76
- package/src/dto/get-ip-address-response.dto.ts +0 -24
- package/src/dto/get-mfa-status.dto.ts +0 -94
- package/src/dto/get-risk-assessment-history.dto.ts +0 -39
- package/src/dto/get-session-id-response.dto.ts +0 -25
- package/src/dto/get-setup-data-response.dto.ts +0 -31
- package/src/dto/get-setup-data.dto.ts +0 -75
- package/src/dto/get-suspicious-activity.dto.ts +0 -42
- package/src/dto/get-user-agent-response.dto.ts +0 -23
- package/src/dto/get-user-auth-history.dto.ts +0 -95
- package/src/dto/get-user-by-email.dto.ts +0 -61
- package/src/dto/get-user-by-id.dto.ts +0 -46
- package/src/dto/get-user-devices.dto.ts +0 -53
- package/src/dto/get-user-response.dto.ts +0 -17
- package/src/dto/has-provider.dto.ts +0 -56
- package/src/dto/index.ts +0 -57
- package/src/dto/is-trusted-device-response.dto.ts +0 -34
- package/src/dto/list-providers-response.dto.ts +0 -23
- package/src/dto/login.dto.ts +0 -95
- package/src/dto/logout-all-response.dto.ts +0 -24
- package/src/dto/logout-all.dto.ts +0 -65
- package/src/dto/logout-response.dto.ts +0 -25
- package/src/dto/logout.dto.ts +0 -64
- package/src/dto/refresh-token.dto.ts +0 -36
- package/src/dto/remove-devices.dto.ts +0 -85
- package/src/dto/resend-code-response.dto.ts +0 -32
- package/src/dto/resend-code.dto.ts +0 -51
- package/src/dto/reset-password.dto.ts +0 -115
- package/src/dto/respond-challenge.dto.ts +0 -272
- package/src/dto/set-mfa-exemption.dto.ts +0 -112
- package/src/dto/set-must-change-password-response.dto.ts +0 -27
- package/src/dto/set-must-change-password.dto.ts +0 -46
- package/src/dto/set-preferred-method.dto.ts +0 -80
- package/src/dto/setup-mfa.dto.ts +0 -98
- package/src/dto/signup.dto.ts +0 -174
- package/src/dto/social-auth.dto.ts +0 -422
- package/src/dto/trust-device-response.dto.ts +0 -30
- package/src/dto/trust-device.dto.ts +0 -9
- package/src/dto/update-user-attributes-request.dto.ts +0 -51
- package/src/dto/user-response.dto.ts +0 -138
- package/src/dto/user-update.dto.ts +0 -222
- package/src/dto/verify-email.dto.ts +0 -313
- package/src/dto/verify-mfa-code.dto.ts +0 -103
- package/src/dto/verify-phone-by-sub.dto.ts +0 -78
- package/src/dto/verify-phone.dto.ts +0 -245
- package/src/entities/auth-audit.entity.ts +0 -232
- package/src/entities/challenge-session.entity.ts +0 -116
- package/src/entities/index.ts +0 -29
- package/src/entities/login-attempt.entity.ts +0 -64
- package/src/entities/mfa-device.entity.ts +0 -151
- package/src/entities/rate-limit.entity.ts +0 -44
- package/src/entities/session.entity.ts +0 -180
- package/src/entities/social-account.entity.ts +0 -96
- package/src/entities/storage-lock.entity.ts +0 -39
- package/src/entities/trusted-device.entity.ts +0 -112
- package/src/entities/user.entity.ts +0 -243
- package/src/entities/verification-token.entity.ts +0 -141
- package/src/enums/auth-audit-event-type.enum.ts +0 -360
- package/src/enums/error-codes.enum.ts +0 -420
- package/src/enums/mfa-method.enum.ts +0 -97
- package/src/enums/risk-factor.enum.ts +0 -111
- package/src/exceptions/nauth.exception.ts +0 -231
- package/src/handlers/auth.handler.ts +0 -260
- package/src/handlers/client-info.handler.ts +0 -101
- package/src/handlers/csrf.handler.ts +0 -156
- package/src/handlers/token-delivery.handler.ts +0 -118
- package/src/index.ts +0 -118
- package/src/interfaces/client-info.interface.ts +0 -85
- package/src/interfaces/config.interface.ts +0 -2135
- package/src/interfaces/entities.interface.ts +0 -226
- package/src/interfaces/index.ts +0 -15
- package/src/interfaces/logger.interface.ts +0 -283
- package/src/interfaces/mfa-provider.interface.ts +0 -154
- package/src/interfaces/oauth.interface.ts +0 -148
- package/src/interfaces/provider.interface.ts +0 -47
- package/src/interfaces/social-auth-provider.interface.ts +0 -131
- package/src/interfaces/storage-adapter.interface.ts +0 -82
- package/src/interfaces/template.interface.ts +0 -510
- package/src/interfaces/token-verifier.interface.ts +0 -110
- package/src/internal.ts +0 -178
- package/src/platform/interfaces.ts +0 -299
- package/src/schemas/auth-config.schema.ts +0 -646
- package/src/services/adaptive-mfa-decision.service.spec.ts +0 -1058
- package/src/services/adaptive-mfa-decision.service.ts +0 -457
- package/src/services/auth-audit.service.spec.ts +0 -675
- package/src/services/auth-audit.service.ts +0 -558
- package/src/services/auth-challenge-helper.service.spec.ts +0 -3227
- package/src/services/auth-challenge-helper.service.ts +0 -825
- package/src/services/auth-flow-context-builder.service.ts +0 -520
- package/src/services/auth-flow-rules.ts +0 -202
- package/src/services/auth-flow-state-definitions.ts +0 -190
- package/src/services/auth-flow-state-machine.service.ts +0 -207
- package/src/services/auth-flow-state-machine.types.ts +0 -316
- package/src/services/auth.service.spec.ts +0 -4195
- package/src/services/auth.service.ts +0 -3727
- package/src/services/challenge.service.spec.ts +0 -1363
- package/src/services/challenge.service.ts +0 -696
- package/src/services/client-info.service.spec.ts +0 -572
- package/src/services/client-info.service.ts +0 -374
- package/src/services/csrf.service.ts +0 -54
- package/src/services/email-verification.service.spec.ts +0 -1229
- package/src/services/email-verification.service.ts +0 -578
- package/src/services/geo-location.service.spec.ts +0 -603
- package/src/services/geo-location.service.ts +0 -599
- package/src/services/index.ts +0 -13
- package/src/services/jwt.service.spec.ts +0 -882
- package/src/services/jwt.service.ts +0 -621
- package/src/services/mfa-base.service.spec.ts +0 -246
- package/src/services/mfa-base.service.ts +0 -611
- package/src/services/mfa.service.spec.ts +0 -693
- package/src/services/mfa.service.ts +0 -960
- package/src/services/password.service.spec.ts +0 -166
- package/src/services/password.service.ts +0 -309
- package/src/services/phone-verification.service.spec.ts +0 -1120
- package/src/services/phone-verification.service.ts +0 -751
- package/src/services/risk-detection.service.spec.ts +0 -1292
- package/src/services/risk-detection.service.ts +0 -1012
- package/src/services/risk-scoring.service.spec.ts +0 -204
- package/src/services/risk-scoring.service.ts +0 -131
- package/src/services/session.service.spec.ts +0 -1293
- package/src/services/session.service.ts +0 -803
- package/src/services/social-account.service.spec.ts +0 -725
- package/src/services/social-auth-base.service.spec.ts +0 -418
- package/src/services/social-auth-base.service.ts +0 -581
- package/src/services/social-auth.service.spec.ts +0 -238
- package/src/services/social-auth.service.ts +0 -436
- package/src/services/social-provider-registry.service.spec.ts +0 -238
- package/src/services/social-provider-registry.service.ts +0 -122
- package/src/services/trusted-device.service.spec.ts +0 -505
- package/src/services/trusted-device.service.ts +0 -339
- package/src/storage/account-lockout-storage.service.spec.ts +0 -310
- package/src/storage/account-lockout-storage.service.ts +0 -89
- package/src/storage/index.ts +0 -3
- package/src/storage/memory-storage.adapter.ts +0 -443
- package/src/storage/rate-limit-storage.service.spec.ts +0 -247
- package/src/storage/rate-limit-storage.service.ts +0 -38
- package/src/templates/html-template.engine.spec.ts +0 -161
- package/src/templates/html-template.engine.ts +0 -688
- package/src/templates/index.ts +0 -7
- package/src/utils/common-passwords.spec.ts +0 -230
- package/src/utils/common-passwords.ts +0 -170
- package/src/utils/context-storage.ts +0 -188
- package/src/utils/cookie-names.util.ts +0 -67
- package/src/utils/cookies.util.ts +0 -94
- package/src/utils/index.ts +0 -12
- package/src/utils/ip-extractor.spec.ts +0 -330
- package/src/utils/ip-extractor.ts +0 -220
- package/src/utils/nauth-logger.spec.ts +0 -388
- package/src/utils/nauth-logger.ts +0 -215
- package/src/utils/pii-redactor.spec.ts +0 -130
- package/src/utils/pii-redactor.ts +0 -288
- package/src/utils/setup/get-repositories.ts +0 -140
- package/src/utils/setup/init-services.ts +0 -422
- package/src/utils/setup/init-social.ts +0 -189
- package/src/utils/setup/init-storage.ts +0 -94
- package/src/utils/setup/register-mfa.ts +0 -165
- package/src/utils/setup/run-nauth-migrations.ts +0 -61
- package/src/utils/token-delivery-policy.ts +0 -38
- package/src/validators/template.validator.ts +0 -219
- package/tsconfig.json +0 -37
- package/tsconfig.lint.json +0 -6
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { loadCommonPasswords, isCommonPassword, getCommonPasswordCount } from './common-passwords';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Common Passwords Utility Tests
|
|
7
|
-
*
|
|
8
|
-
* Covers:
|
|
9
|
-
* - Loading password list from file
|
|
10
|
-
* - Fallback when file not found
|
|
11
|
-
* - Password checking (case-insensitive)
|
|
12
|
-
* - Performance characteristics
|
|
13
|
-
* - Caching behavior
|
|
14
|
-
*/
|
|
15
|
-
describe('Common Passwords Utility', () => {
|
|
16
|
-
// ============================================================================
|
|
17
|
-
// Loading and Initialization
|
|
18
|
-
// ============================================================================
|
|
19
|
-
|
|
20
|
-
describe('loadCommonPasswords', () => {
|
|
21
|
-
it('should load passwords into a Set', () => {
|
|
22
|
-
const passwords = loadCommonPasswords();
|
|
23
|
-
|
|
24
|
-
expect(passwords).toBeInstanceOf(Set);
|
|
25
|
-
expect(passwords.size).toBeGreaterThan(0);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should return cached instance on subsequent calls', () => {
|
|
29
|
-
const passwords1 = loadCommonPasswords();
|
|
30
|
-
const passwords2 = loadCommonPasswords();
|
|
31
|
-
|
|
32
|
-
// Should return exact same instance (not a copy)
|
|
33
|
-
expect(passwords1).toBe(passwords2);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should contain known common passwords', () => {
|
|
37
|
-
const passwords = loadCommonPasswords();
|
|
38
|
-
|
|
39
|
-
// These should always be in the list (either from file or fallback)
|
|
40
|
-
expect(passwords.has('password')).toBe(true);
|
|
41
|
-
expect(passwords.has('123456')).toBe(true);
|
|
42
|
-
expect(passwords.has('qwerty')).toBe(true);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should handle file loading gracefully', () => {
|
|
46
|
-
const filePath = path.join(__dirname, '../data/common-passwords-10000.txt');
|
|
47
|
-
const fileExists = fs.existsSync(filePath);
|
|
48
|
-
|
|
49
|
-
const passwords = loadCommonPasswords();
|
|
50
|
-
|
|
51
|
-
if (fileExists) {
|
|
52
|
-
// If file exists, should load 10K+ passwords
|
|
53
|
-
expect(passwords.size).toBeGreaterThanOrEqual(1000);
|
|
54
|
-
} else {
|
|
55
|
-
// If file missing, should use fallback list
|
|
56
|
-
expect(passwords.size).toBeGreaterThanOrEqual(10);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// ============================================================================
|
|
62
|
-
// Password Checking
|
|
63
|
-
// ============================================================================
|
|
64
|
-
|
|
65
|
-
describe('isCommonPassword', () => {
|
|
66
|
-
it('should identify common passwords', () => {
|
|
67
|
-
expect(isCommonPassword('password')).toBe(true);
|
|
68
|
-
expect(isCommonPassword('password123')).toBe(true);
|
|
69
|
-
expect(isCommonPassword('12345678')).toBe(true);
|
|
70
|
-
expect(isCommonPassword('qwerty')).toBe(true);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should be case-insensitive', () => {
|
|
74
|
-
expect(isCommonPassword('PASSWORD')).toBe(true);
|
|
75
|
-
expect(isCommonPassword('PaSsWoRd')).toBe(true);
|
|
76
|
-
expect(isCommonPassword('QWERTY')).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should reject strong passwords', () => {
|
|
80
|
-
// These strong passwords should NOT be in common password list
|
|
81
|
-
expect(isCommonPassword('Xy9$mK2#pLq8@vN3')).toBe(false);
|
|
82
|
-
expect(isCommonPassword('correct-horse-battery-staple-2024')).toBe(false);
|
|
83
|
-
expect(isCommonPassword('MyC0mpl3x!P@ssw0rd#2024')).toBe(false);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should handle empty string', () => {
|
|
87
|
-
expect(isCommonPassword('')).toBe(false);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should handle special characters', () => {
|
|
91
|
-
// Common passwords with numbers should be detected
|
|
92
|
-
expect(isCommonPassword('password1')).toBe(true);
|
|
93
|
-
expect(isCommonPassword('password123')).toBe(true);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// ============================================================================
|
|
98
|
-
// Performance and Count
|
|
99
|
-
// ============================================================================
|
|
100
|
-
|
|
101
|
-
describe('getCommonPasswordCount', () => {
|
|
102
|
-
it('should return positive number', () => {
|
|
103
|
-
const count = getCommonPasswordCount();
|
|
104
|
-
|
|
105
|
-
expect(count).toBeGreaterThan(0);
|
|
106
|
-
expect(typeof count).toBe('number');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should match loaded set size', () => {
|
|
110
|
-
const passwords = loadCommonPasswords();
|
|
111
|
-
const count = getCommonPasswordCount();
|
|
112
|
-
|
|
113
|
-
expect(count).toBe(passwords.size);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should have at least 10 passwords', () => {
|
|
117
|
-
// Even fallback list should have 10 passwords
|
|
118
|
-
const count = getCommonPasswordCount();
|
|
119
|
-
|
|
120
|
-
expect(count).toBeGreaterThanOrEqual(10);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// ============================================================================
|
|
125
|
-
// Performance Characteristics
|
|
126
|
-
// ============================================================================
|
|
127
|
-
|
|
128
|
-
describe('Performance', () => {
|
|
129
|
-
it('should check passwords in constant time (O(1) with Set)', () => {
|
|
130
|
-
const passwords = loadCommonPasswords();
|
|
131
|
-
|
|
132
|
-
// Measure lookup time for different passwords
|
|
133
|
-
const iterations = 100000; // Increased iterations for measurable time
|
|
134
|
-
|
|
135
|
-
const start1 = performance.now();
|
|
136
|
-
for (let i = 0; i < iterations; i++) {
|
|
137
|
-
passwords.has('password');
|
|
138
|
-
}
|
|
139
|
-
const time1 = performance.now() - start1;
|
|
140
|
-
|
|
141
|
-
const start2 = performance.now();
|
|
142
|
-
for (let i = 0; i < iterations; i++) {
|
|
143
|
-
passwords.has('very-secure-password-that-definitely-is-not-common-123456789');
|
|
144
|
-
}
|
|
145
|
-
const time2 = performance.now() - start2;
|
|
146
|
-
|
|
147
|
-
// Set lookup should be O(1), so both should complete in reasonable time
|
|
148
|
-
// Both lookups should take less than 2000ms for 100K iterations (lenient for CI/system load)
|
|
149
|
-
expect(time1).toBeLessThan(2000);
|
|
150
|
-
expect(time2).toBeLessThan(2000);
|
|
151
|
-
|
|
152
|
-
// Times should be similar (within 10x of each other for O(1) behavior)
|
|
153
|
-
// This is lenient to account for V8 optimization, system variance, and CI load
|
|
154
|
-
const ratio = Math.max(time1, time2) / Math.min(time1, time2);
|
|
155
|
-
expect(ratio).toBeLessThan(10);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should handle rapid consecutive checks', () => {
|
|
159
|
-
// Should not fail or slow down with many checks
|
|
160
|
-
const testPasswords = ['password', 'secure123', 'MySecureP@ssw0rd', 'qwerty', 'admin', 'Xy9$mK2#pLq8@vN3'];
|
|
161
|
-
|
|
162
|
-
for (let i = 0; i < 1000; i++) {
|
|
163
|
-
for (const pwd of testPasswords) {
|
|
164
|
-
isCommonPassword(pwd);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// If we get here without timeout, performance is acceptable
|
|
169
|
-
expect(true).toBe(true);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// ============================================================================
|
|
174
|
-
// Integration with Password Service
|
|
175
|
-
// ============================================================================
|
|
176
|
-
|
|
177
|
-
describe('Integration', () => {
|
|
178
|
-
it('should provide API that matches PasswordService expectations', () => {
|
|
179
|
-
// PasswordService calls loadCommonPasswords() once in constructor
|
|
180
|
-
const passwords = loadCommonPasswords();
|
|
181
|
-
|
|
182
|
-
// Then uses passwords.has(password.toLowerCase()) for checking
|
|
183
|
-
expect(typeof passwords.has).toBe('function');
|
|
184
|
-
|
|
185
|
-
const testPassword = 'password123';
|
|
186
|
-
const result = passwords.has(testPassword.toLowerCase());
|
|
187
|
-
|
|
188
|
-
expect(typeof result).toBe('boolean');
|
|
189
|
-
expect(result).toBe(true);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it('should handle all lowercase storage correctly', () => {
|
|
193
|
-
const passwords = loadCommonPasswords();
|
|
194
|
-
|
|
195
|
-
// List stores everything as lowercase
|
|
196
|
-
// So checking with original case should work via toLowerCase()
|
|
197
|
-
expect(passwords.has('password')).toBe(true);
|
|
198
|
-
expect(passwords.has('PASSWORD')).toBe(false); // Not in lowercase form
|
|
199
|
-
expect(passwords.has('password'.toLowerCase())).toBe(true); // Correct usage
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// ============================================================================
|
|
204
|
-
// Environment Variable Control
|
|
205
|
-
// ============================================================================
|
|
206
|
-
|
|
207
|
-
describe('Debug Logging', () => {
|
|
208
|
-
const originalEnv = process.env.NAUTH_DEBUG;
|
|
209
|
-
|
|
210
|
-
afterEach(() => {
|
|
211
|
-
// Restore original environment
|
|
212
|
-
if (originalEnv !== undefined) {
|
|
213
|
-
process.env.NAUTH_DEBUG = originalEnv;
|
|
214
|
-
} else {
|
|
215
|
-
delete process.env.NAUTH_DEBUG;
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it('should not throw errors regardless of NAUTH_DEBUG setting', () => {
|
|
220
|
-
process.env.NAUTH_DEBUG = 'true';
|
|
221
|
-
expect(() => loadCommonPasswords()).not.toThrow();
|
|
222
|
-
|
|
223
|
-
process.env.NAUTH_DEBUG = 'false';
|
|
224
|
-
expect(() => loadCommonPasswords()).not.toThrow();
|
|
225
|
-
|
|
226
|
-
delete process.env.NAUTH_DEBUG;
|
|
227
|
-
expect(() => loadCommonPasswords()).not.toThrow();
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
});
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Common Passwords Loader
|
|
6
|
-
*
|
|
7
|
-
* Loads a curated list of common passwords from bundled file at startup.
|
|
8
|
-
* Platform-agnostic - works on Mac, Linux, Windows, Docker, serverless, etc.
|
|
9
|
-
*
|
|
10
|
-
* Security Features:
|
|
11
|
-
* - One-time load on module initialization (memory cached)
|
|
12
|
-
* - 10,000 most common passwords from SecLists
|
|
13
|
-
* - O(1) lookup performance with Set
|
|
14
|
-
* - Graceful fallback if file not found
|
|
15
|
-
* - No runtime file I/O or network calls
|
|
16
|
-
* - Silent by default (won't interfere with JSON logging)
|
|
17
|
-
*
|
|
18
|
-
* Memory footprint: ~200KB for 10K passwords in Set
|
|
19
|
-
*
|
|
20
|
-
* Environment Variables:
|
|
21
|
-
* - NAUTH_DEBUG=true - Enable debug logging to stderr
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* const passwords = loadCommonPasswords();
|
|
26
|
-
* if (passwords.has('password123')) {
|
|
27
|
-
* throw new Error('Password too common');
|
|
28
|
-
* }
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
let COMMON_PASSWORDS: Set<string> | null = null;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Internal logging helper
|
|
36
|
-
*
|
|
37
|
-
* Writes to stderr (not stdout) to avoid interfering with JSON logging.
|
|
38
|
-
* Only logs if NAUTH_DEBUG environment variable is set.
|
|
39
|
-
*
|
|
40
|
-
* @param message - Message to log
|
|
41
|
-
* @param isError - Whether this is an error/warning
|
|
42
|
-
*/
|
|
43
|
-
function debugLog(message: string, isError: boolean = false): void {
|
|
44
|
-
if (process.env.NAUTH_DEBUG === 'true') {
|
|
45
|
-
const prefix = isError ? '[nauth-toolkit:WARN]' : '[nauth-toolkit:INFO]';
|
|
46
|
-
process.stderr.write(`${prefix} ${message}\n`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Minimal fallback password list
|
|
52
|
-
*
|
|
53
|
-
* Used if the main password file cannot be loaded.
|
|
54
|
-
* Contains only the most common passwords.
|
|
55
|
-
*/
|
|
56
|
-
const FALLBACK_PASSWORDS = [
|
|
57
|
-
'password',
|
|
58
|
-
'password123',
|
|
59
|
-
'123456',
|
|
60
|
-
'123456789',
|
|
61
|
-
'12345678',
|
|
62
|
-
'12345',
|
|
63
|
-
'qwerty',
|
|
64
|
-
'abc123',
|
|
65
|
-
'password1',
|
|
66
|
-
'admin',
|
|
67
|
-
'letmein',
|
|
68
|
-
'welcome',
|
|
69
|
-
'123123',
|
|
70
|
-
'monkey',
|
|
71
|
-
'1234567',
|
|
72
|
-
'password!',
|
|
73
|
-
'qwerty123',
|
|
74
|
-
'1q2w3e4r',
|
|
75
|
-
'admin123',
|
|
76
|
-
'root',
|
|
77
|
-
];
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Load common passwords from bundled file
|
|
81
|
-
*
|
|
82
|
-
* This function loads once on first call and caches the result.
|
|
83
|
-
* Subsequent calls return the cached Set immediately.
|
|
84
|
-
*
|
|
85
|
-
* File location: packages/core/src/data/common-passwords-10000.txt
|
|
86
|
-
* Format: One password per line, lowercase
|
|
87
|
-
*
|
|
88
|
-
* @returns Set of common passwords (lowercase)
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```typescript
|
|
92
|
-
* // Load passwords (cached after first call)
|
|
93
|
-
* const passwords = loadCommonPasswords();
|
|
94
|
-
*
|
|
95
|
-
* // Check if password is common
|
|
96
|
-
* if (passwords.has('mypassword'.toLowerCase())) {
|
|
97
|
-
* console.log('Password is too common');
|
|
98
|
-
* }
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
export function loadCommonPasswords(): Set<string> {
|
|
102
|
-
// Return cached version if already loaded
|
|
103
|
-
if (COMMON_PASSWORDS) {
|
|
104
|
-
return COMMON_PASSWORDS;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
// Try to load from bundled file
|
|
109
|
-
const filePath = path.join(__dirname, '../data/common-passwords-10000.txt');
|
|
110
|
-
|
|
111
|
-
if (fs.existsSync(filePath)) {
|
|
112
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
113
|
-
COMMON_PASSWORDS = new Set(
|
|
114
|
-
content
|
|
115
|
-
.split('\n')
|
|
116
|
-
.map((p) => p.trim().toLowerCase())
|
|
117
|
-
.filter((p) => p.length > 0),
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
debugLog(`Loaded ${COMMON_PASSWORDS.size} common passwords from file`);
|
|
121
|
-
return COMMON_PASSWORDS;
|
|
122
|
-
} else {
|
|
123
|
-
debugLog(`Common passwords file not found at ${filePath}, using fallback list`, true);
|
|
124
|
-
}
|
|
125
|
-
} catch (error) {
|
|
126
|
-
debugLog('Could not load common passwords file, using fallback list', true);
|
|
127
|
-
if (error instanceof Error && process.env.NAUTH_DEBUG === 'true') {
|
|
128
|
-
debugLog(`Error details: ${error.message}`, true);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Fallback to minimal list (silent by default)
|
|
133
|
-
COMMON_PASSWORDS = new Set(FALLBACK_PASSWORDS.map((p) => p.toLowerCase()));
|
|
134
|
-
debugLog(`Using fallback password list with ${COMMON_PASSWORDS.size} entries`, true);
|
|
135
|
-
|
|
136
|
-
return COMMON_PASSWORDS;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Check if a password is in the common password list
|
|
141
|
-
*
|
|
142
|
-
* Case-insensitive comparison.
|
|
143
|
-
*
|
|
144
|
-
* @param password - Password to check
|
|
145
|
-
* @returns True if password is common, false otherwise
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* ```typescript
|
|
149
|
-
* if (isCommonPassword('Password123')) {
|
|
150
|
-
* throw new Error('Password is too common');
|
|
151
|
-
* }
|
|
152
|
-
* ```
|
|
153
|
-
*/
|
|
154
|
-
export function isCommonPassword(password: string): boolean {
|
|
155
|
-
const passwords = loadCommonPasswords();
|
|
156
|
-
return passwords.has(password.toLowerCase());
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Get the size of the common password list
|
|
161
|
-
*
|
|
162
|
-
* @returns Number of passwords in the list
|
|
163
|
-
*/
|
|
164
|
-
export function getCommonPasswordCount(): number {
|
|
165
|
-
const passwords = loadCommonPasswords();
|
|
166
|
-
return passwords.size;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Load passwords on module import (cached for subsequent use)
|
|
170
|
-
loadCommonPasswords();
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Context Storage - Platform-Agnostic Async Local Storage
|
|
5
|
-
*
|
|
6
|
-
* Provides request-scoped storage using Node.js AsyncLocalStorage.
|
|
7
|
-
* Replaces nestjs-cls for platform-agnostic context management.
|
|
8
|
-
*
|
|
9
|
-
* **Features:**
|
|
10
|
-
* - Request-scoped data storage
|
|
11
|
-
* - Works across async boundaries
|
|
12
|
-
* - No framework dependencies
|
|
13
|
-
* - Type-safe storage and retrieval
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* // Store data in context
|
|
18
|
-
* ContextStorage.run(() => {
|
|
19
|
-
* ContextStorage.set('userId', '123');
|
|
20
|
-
* ContextStorage.set('clientInfo', { ip: '1.2.3.4' });
|
|
21
|
-
*
|
|
22
|
-
* // Access from any nested function
|
|
23
|
-
* const userId = ContextStorage.get<string>('userId');
|
|
24
|
-
* });
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export class ContextStorage {
|
|
28
|
-
private static als = new AsyncLocalStorage<Map<string, unknown>>();
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Run a callback within a new context
|
|
32
|
-
*
|
|
33
|
-
* Creates a new async local storage context for the callback.
|
|
34
|
-
* All ContextStorage operations within the callback will use this context.
|
|
35
|
-
*
|
|
36
|
-
* @param callback - Function to execute with context
|
|
37
|
-
* @returns Result of the callback
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```typescript
|
|
41
|
-
* const result = ContextStorage.run(() => {
|
|
42
|
-
* ContextStorage.set('key', 'value');
|
|
43
|
-
* return processRequest();
|
|
44
|
-
* });
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
static run<T>(callback: () => T): T {
|
|
48
|
-
const store = new Map<string, unknown>();
|
|
49
|
-
return this.als.run(store, callback);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Store a value in the current context
|
|
54
|
-
*
|
|
55
|
-
* @param key - Storage key
|
|
56
|
-
* @param value - Value to store
|
|
57
|
-
* @throws Error if called outside of a context (ContextStorage.run not called)
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```typescript
|
|
61
|
-
* ContextStorage.set('userId', '123');
|
|
62
|
-
* ContextStorage.set('clientInfo', { ip: '1.2.3.4', userAgent: 'Mozilla...' });
|
|
63
|
-
* ```
|
|
64
|
-
*/
|
|
65
|
-
static set<T>(key: string, value: T): void {
|
|
66
|
-
const store = this.als.getStore();
|
|
67
|
-
if (!store) {
|
|
68
|
-
throw new Error('Context not initialized. Call ContextStorage.run() first.');
|
|
69
|
-
}
|
|
70
|
-
store.set(key, value);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Retrieve a value from the current context
|
|
75
|
-
*
|
|
76
|
-
* @param key - Storage key
|
|
77
|
-
* @returns Stored value or undefined if not found
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```typescript
|
|
81
|
-
* const userId = ContextStorage.get<string>('userId');
|
|
82
|
-
* const clientInfo = ContextStorage.get<ClientInfo>('CLIENT_INFO');
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
static get<T>(key: string): T | undefined {
|
|
86
|
-
const store = this.als.getStore();
|
|
87
|
-
return store?.get(key) as T | undefined;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Check if a key exists in the current context
|
|
92
|
-
*
|
|
93
|
-
* @param key - Storage key
|
|
94
|
-
* @returns True if key exists, false otherwise
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* ```typescript
|
|
98
|
-
* if (ContextStorage.has('userId')) {
|
|
99
|
-
* const userId = ContextStorage.get<string>('userId');
|
|
100
|
-
* }
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
static has(key: string): boolean {
|
|
104
|
-
const store = this.als.getStore();
|
|
105
|
-
return store?.has(key) || false;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Delete a value from the current context
|
|
110
|
-
*
|
|
111
|
-
* @param key - Storage key
|
|
112
|
-
* @returns True if key was deleted, false if it didn't exist
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```typescript
|
|
116
|
-
* ContextStorage.delete('temporaryData');
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
static delete(key: string): boolean {
|
|
120
|
-
const store = this.als.getStore();
|
|
121
|
-
if (!store) {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
return store.delete(key);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Clear all values from the current context
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* ```typescript
|
|
132
|
-
* ContextStorage.clear();
|
|
133
|
-
* ```
|
|
134
|
-
*/
|
|
135
|
-
static clear(): void {
|
|
136
|
-
const store = this.als.getStore();
|
|
137
|
-
if (store) {
|
|
138
|
-
store.clear();
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Get all keys in the current context
|
|
144
|
-
*
|
|
145
|
-
* @returns Array of storage keys
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* ```typescript
|
|
149
|
-
* const keys = ContextStorage.keys();
|
|
150
|
-
* console.log('Stored keys:', keys);
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
static keys(): string[] {
|
|
154
|
-
const store = this.als.getStore();
|
|
155
|
-
if (!store) {
|
|
156
|
-
return [];
|
|
157
|
-
}
|
|
158
|
-
return Array.from(store.keys());
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Get the current store instance
|
|
163
|
-
*
|
|
164
|
-
* This is useful for frameworks like Fastify where hooks run independently
|
|
165
|
-
* and you need to preserve the store across hook boundaries.
|
|
166
|
-
*
|
|
167
|
-
* @returns The current Map store or undefined
|
|
168
|
-
* @internal
|
|
169
|
-
*/
|
|
170
|
-
static getStore(): Map<string, unknown> | undefined {
|
|
171
|
-
return this.als.getStore();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Enter an existing context store
|
|
176
|
-
*
|
|
177
|
-
* This allows re-entering a context that was created elsewhere,
|
|
178
|
-
* useful for frameworks where handlers run in separate scopes.
|
|
179
|
-
*
|
|
180
|
-
* @param store - The store to enter
|
|
181
|
-
* @param callback - Function to execute with the store
|
|
182
|
-
* @returns Result of the callback
|
|
183
|
-
* @internal
|
|
184
|
-
*/
|
|
185
|
-
static enterStore<T>(store: Map<string, unknown>, callback: () => T): T {
|
|
186
|
-
return this.als.run(store, callback);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cookie Name Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides consistent cookie name generation using the configured prefix.
|
|
5
|
-
* All cookie names are prefixed to avoid conflicts with other cookies.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { NAuthConfig } from '../interfaces/config.interface';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Get the cookie name prefix from config
|
|
12
|
-
* @param config - NAuth configuration
|
|
13
|
-
* @returns Cookie name prefix (default: 'nauth_')
|
|
14
|
-
*/
|
|
15
|
-
export function getCookieNamePrefix(config?: NAuthConfig): string {
|
|
16
|
-
return config?.tokenDelivery?.cookieNamePrefix || 'nauth_';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Get the access token cookie name
|
|
21
|
-
* @param config - NAuth configuration
|
|
22
|
-
* @returns Access token cookie name (default: 'nauth_access_token')
|
|
23
|
-
*/
|
|
24
|
-
export function getAccessTokenCookieName(config?: NAuthConfig): string {
|
|
25
|
-
const prefix = getCookieNamePrefix(config);
|
|
26
|
-
return `${prefix}access_token`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Get the refresh token cookie name
|
|
31
|
-
* @param config - NAuth configuration
|
|
32
|
-
* @returns Refresh token cookie name (default: 'nauth_refresh_token')
|
|
33
|
-
*/
|
|
34
|
-
export function getRefreshTokenCookieName(config?: NAuthConfig): string {
|
|
35
|
-
const prefix = getCookieNamePrefix(config);
|
|
36
|
-
return `${prefix}refresh_token`;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Get the device token cookie name
|
|
41
|
-
* @param config - NAuth configuration
|
|
42
|
-
* @returns Device token cookie name (default: 'nauth_device_token')
|
|
43
|
-
*/
|
|
44
|
-
export function getDeviceTokenCookieName(config?: NAuthConfig): string {
|
|
45
|
-
const prefix = getCookieNamePrefix(config);
|
|
46
|
-
return `${prefix}device_token`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Get the CSRF token cookie name
|
|
51
|
-
*
|
|
52
|
-
* If explicitly configured via security.csrf.cookieName, uses that value.
|
|
53
|
-
* Otherwise, uses the prefix: `${prefix}csrf_token`
|
|
54
|
-
*
|
|
55
|
-
* @param config - NAuth configuration
|
|
56
|
-
* @returns CSRF token cookie name (default: 'nauth_csrf_token')
|
|
57
|
-
*/
|
|
58
|
-
export function getCsrfTokenCookieName(config?: NAuthConfig): string {
|
|
59
|
-
// If explicitly configured, use it
|
|
60
|
-
if (config?.security?.csrf?.cookieName) {
|
|
61
|
-
return config.security.csrf.cookieName;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Otherwise, use prefix
|
|
65
|
-
const prefix = getCookieNamePrefix(config);
|
|
66
|
-
return `${prefix}csrf_token`;
|
|
67
|
-
}
|