@nauth-toolkit/core 0.1.0 → 0.1.3

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 (184) hide show
  1. package/LICENSE +90 -0
  2. package/README.md +30 -0
  3. package/package.json +7 -2
  4. package/jest.config.js +0 -15
  5. package/jest.setup.ts +0 -6
  6. package/src/adapters/database-columns.ts +0 -165
  7. package/src/adapters/express.adapter.ts +0 -385
  8. package/src/adapters/fastify.adapter.ts +0 -416
  9. package/src/adapters/index.ts +0 -16
  10. package/src/adapters/storage.factory.ts +0 -143
  11. package/src/bootstrap.ts +0 -374
  12. package/src/dto/auth-challenge.dto.ts +0 -231
  13. package/src/dto/auth-response.dto.ts +0 -253
  14. package/src/dto/challenge-response.dto.ts +0 -234
  15. package/src/dto/change-password-request.dto.ts +0 -50
  16. package/src/dto/change-password-response.dto.ts +0 -29
  17. package/src/dto/change-password.dto.ts +0 -57
  18. package/src/dto/error-response.dto.ts +0 -136
  19. package/src/dto/get-available-methods.dto.ts +0 -55
  20. package/src/dto/get-challenge-data-response.dto.ts +0 -28
  21. package/src/dto/get-challenge-data.dto.ts +0 -69
  22. package/src/dto/get-client-info.dto.ts +0 -104
  23. package/src/dto/get-device-token-response.dto.ts +0 -25
  24. package/src/dto/get-events-by-type.dto.ts +0 -76
  25. package/src/dto/get-ip-address-response.dto.ts +0 -24
  26. package/src/dto/get-mfa-status.dto.ts +0 -94
  27. package/src/dto/get-risk-assessment-history.dto.ts +0 -39
  28. package/src/dto/get-session-id-response.dto.ts +0 -25
  29. package/src/dto/get-setup-data-response.dto.ts +0 -31
  30. package/src/dto/get-setup-data.dto.ts +0 -75
  31. package/src/dto/get-suspicious-activity.dto.ts +0 -42
  32. package/src/dto/get-user-agent-response.dto.ts +0 -23
  33. package/src/dto/get-user-auth-history.dto.ts +0 -95
  34. package/src/dto/get-user-by-email.dto.ts +0 -61
  35. package/src/dto/get-user-by-id.dto.ts +0 -46
  36. package/src/dto/get-user-devices.dto.ts +0 -53
  37. package/src/dto/get-user-response.dto.ts +0 -17
  38. package/src/dto/has-provider.dto.ts +0 -56
  39. package/src/dto/index.ts +0 -57
  40. package/src/dto/is-trusted-device-response.dto.ts +0 -34
  41. package/src/dto/list-providers-response.dto.ts +0 -23
  42. package/src/dto/login.dto.ts +0 -95
  43. package/src/dto/logout-all-response.dto.ts +0 -24
  44. package/src/dto/logout-all.dto.ts +0 -65
  45. package/src/dto/logout-response.dto.ts +0 -25
  46. package/src/dto/logout.dto.ts +0 -64
  47. package/src/dto/refresh-token.dto.ts +0 -36
  48. package/src/dto/remove-devices.dto.ts +0 -85
  49. package/src/dto/resend-code-response.dto.ts +0 -32
  50. package/src/dto/resend-code.dto.ts +0 -51
  51. package/src/dto/reset-password.dto.ts +0 -115
  52. package/src/dto/respond-challenge.dto.ts +0 -272
  53. package/src/dto/set-mfa-exemption.dto.ts +0 -112
  54. package/src/dto/set-must-change-password-response.dto.ts +0 -27
  55. package/src/dto/set-must-change-password.dto.ts +0 -46
  56. package/src/dto/set-preferred-method.dto.ts +0 -80
  57. package/src/dto/setup-mfa.dto.ts +0 -98
  58. package/src/dto/signup.dto.ts +0 -174
  59. package/src/dto/social-auth.dto.ts +0 -422
  60. package/src/dto/trust-device-response.dto.ts +0 -30
  61. package/src/dto/trust-device.dto.ts +0 -9
  62. package/src/dto/update-user-attributes-request.dto.ts +0 -51
  63. package/src/dto/user-response.dto.ts +0 -138
  64. package/src/dto/user-update.dto.ts +0 -222
  65. package/src/dto/verify-email.dto.ts +0 -313
  66. package/src/dto/verify-mfa-code.dto.ts +0 -103
  67. package/src/dto/verify-phone-by-sub.dto.ts +0 -78
  68. package/src/dto/verify-phone.dto.ts +0 -245
  69. package/src/entities/auth-audit.entity.ts +0 -232
  70. package/src/entities/challenge-session.entity.ts +0 -116
  71. package/src/entities/index.ts +0 -29
  72. package/src/entities/login-attempt.entity.ts +0 -64
  73. package/src/entities/mfa-device.entity.ts +0 -151
  74. package/src/entities/rate-limit.entity.ts +0 -44
  75. package/src/entities/session.entity.ts +0 -180
  76. package/src/entities/social-account.entity.ts +0 -96
  77. package/src/entities/storage-lock.entity.ts +0 -39
  78. package/src/entities/trusted-device.entity.ts +0 -112
  79. package/src/entities/user.entity.ts +0 -243
  80. package/src/entities/verification-token.entity.ts +0 -141
  81. package/src/enums/auth-audit-event-type.enum.ts +0 -360
  82. package/src/enums/error-codes.enum.ts +0 -420
  83. package/src/enums/mfa-method.enum.ts +0 -97
  84. package/src/enums/risk-factor.enum.ts +0 -111
  85. package/src/exceptions/nauth.exception.ts +0 -231
  86. package/src/handlers/auth.handler.ts +0 -260
  87. package/src/handlers/client-info.handler.ts +0 -101
  88. package/src/handlers/csrf.handler.ts +0 -156
  89. package/src/handlers/token-delivery.handler.ts +0 -118
  90. package/src/index.ts +0 -118
  91. package/src/interfaces/client-info.interface.ts +0 -85
  92. package/src/interfaces/config.interface.ts +0 -2135
  93. package/src/interfaces/entities.interface.ts +0 -226
  94. package/src/interfaces/index.ts +0 -15
  95. package/src/interfaces/logger.interface.ts +0 -283
  96. package/src/interfaces/mfa-provider.interface.ts +0 -154
  97. package/src/interfaces/oauth.interface.ts +0 -148
  98. package/src/interfaces/provider.interface.ts +0 -47
  99. package/src/interfaces/social-auth-provider.interface.ts +0 -131
  100. package/src/interfaces/storage-adapter.interface.ts +0 -82
  101. package/src/interfaces/template.interface.ts +0 -510
  102. package/src/interfaces/token-verifier.interface.ts +0 -110
  103. package/src/internal.ts +0 -178
  104. package/src/platform/interfaces.ts +0 -299
  105. package/src/schemas/auth-config.schema.ts +0 -646
  106. package/src/services/adaptive-mfa-decision.service.spec.ts +0 -1058
  107. package/src/services/adaptive-mfa-decision.service.ts +0 -457
  108. package/src/services/auth-audit.service.spec.ts +0 -675
  109. package/src/services/auth-audit.service.ts +0 -558
  110. package/src/services/auth-challenge-helper.service.spec.ts +0 -3227
  111. package/src/services/auth-challenge-helper.service.ts +0 -825
  112. package/src/services/auth-flow-context-builder.service.ts +0 -520
  113. package/src/services/auth-flow-rules.ts +0 -202
  114. package/src/services/auth-flow-state-definitions.ts +0 -190
  115. package/src/services/auth-flow-state-machine.service.ts +0 -207
  116. package/src/services/auth-flow-state-machine.types.ts +0 -316
  117. package/src/services/auth.service.spec.ts +0 -4195
  118. package/src/services/auth.service.ts +0 -3727
  119. package/src/services/challenge.service.spec.ts +0 -1363
  120. package/src/services/challenge.service.ts +0 -696
  121. package/src/services/client-info.service.spec.ts +0 -572
  122. package/src/services/client-info.service.ts +0 -374
  123. package/src/services/csrf.service.ts +0 -54
  124. package/src/services/email-verification.service.spec.ts +0 -1229
  125. package/src/services/email-verification.service.ts +0 -578
  126. package/src/services/geo-location.service.spec.ts +0 -603
  127. package/src/services/geo-location.service.ts +0 -599
  128. package/src/services/index.ts +0 -13
  129. package/src/services/jwt.service.spec.ts +0 -882
  130. package/src/services/jwt.service.ts +0 -621
  131. package/src/services/mfa-base.service.spec.ts +0 -246
  132. package/src/services/mfa-base.service.ts +0 -611
  133. package/src/services/mfa.service.spec.ts +0 -693
  134. package/src/services/mfa.service.ts +0 -960
  135. package/src/services/password.service.spec.ts +0 -166
  136. package/src/services/password.service.ts +0 -309
  137. package/src/services/phone-verification.service.spec.ts +0 -1120
  138. package/src/services/phone-verification.service.ts +0 -751
  139. package/src/services/risk-detection.service.spec.ts +0 -1292
  140. package/src/services/risk-detection.service.ts +0 -1012
  141. package/src/services/risk-scoring.service.spec.ts +0 -204
  142. package/src/services/risk-scoring.service.ts +0 -131
  143. package/src/services/session.service.spec.ts +0 -1293
  144. package/src/services/session.service.ts +0 -803
  145. package/src/services/social-account.service.spec.ts +0 -725
  146. package/src/services/social-auth-base.service.spec.ts +0 -418
  147. package/src/services/social-auth-base.service.ts +0 -581
  148. package/src/services/social-auth.service.spec.ts +0 -238
  149. package/src/services/social-auth.service.ts +0 -436
  150. package/src/services/social-provider-registry.service.spec.ts +0 -238
  151. package/src/services/social-provider-registry.service.ts +0 -122
  152. package/src/services/trusted-device.service.spec.ts +0 -505
  153. package/src/services/trusted-device.service.ts +0 -339
  154. package/src/storage/account-lockout-storage.service.spec.ts +0 -310
  155. package/src/storage/account-lockout-storage.service.ts +0 -89
  156. package/src/storage/index.ts +0 -3
  157. package/src/storage/memory-storage.adapter.ts +0 -443
  158. package/src/storage/rate-limit-storage.service.spec.ts +0 -247
  159. package/src/storage/rate-limit-storage.service.ts +0 -38
  160. package/src/templates/html-template.engine.spec.ts +0 -161
  161. package/src/templates/html-template.engine.ts +0 -688
  162. package/src/templates/index.ts +0 -7
  163. package/src/utils/common-passwords.spec.ts +0 -230
  164. package/src/utils/common-passwords.ts +0 -170
  165. package/src/utils/context-storage.ts +0 -188
  166. package/src/utils/cookie-names.util.ts +0 -67
  167. package/src/utils/cookies.util.ts +0 -94
  168. package/src/utils/index.ts +0 -12
  169. package/src/utils/ip-extractor.spec.ts +0 -330
  170. package/src/utils/ip-extractor.ts +0 -220
  171. package/src/utils/nauth-logger.spec.ts +0 -388
  172. package/src/utils/nauth-logger.ts +0 -215
  173. package/src/utils/pii-redactor.spec.ts +0 -130
  174. package/src/utils/pii-redactor.ts +0 -288
  175. package/src/utils/setup/get-repositories.ts +0 -140
  176. package/src/utils/setup/init-services.ts +0 -422
  177. package/src/utils/setup/init-social.ts +0 -189
  178. package/src/utils/setup/init-storage.ts +0 -94
  179. package/src/utils/setup/register-mfa.ts +0 -165
  180. package/src/utils/setup/run-nauth-migrations.ts +0 -61
  181. package/src/utils/token-delivery-policy.ts +0 -38
  182. package/src/validators/template.validator.ts +0 -219
  183. package/tsconfig.json +0 -37
  184. package/tsconfig.lint.json +0 -6
@@ -1,388 +0,0 @@
1
- import { LoggerService, NAuthLoggerConfig } from '../interfaces/config.interface';
2
- import { NAuthLogger } from './nauth-logger';
3
-
4
- /**
5
- * NAuthLogger Unit Tests
6
- *
7
- * Tests the NAuthLogger wrapper functionality including:
8
- * - Message prefixing
9
- * - PII redaction
10
- * - Log level filtering
11
- * - Silent mode
12
- * - Different logger configurations
13
- */
14
- describe('NAuthLogger', () => {
15
- let mockLogger: jest.Mocked<LoggerService>;
16
- let logger: NAuthLogger;
17
-
18
- beforeEach(() => {
19
- mockLogger = {
20
- log: jest.fn(),
21
- error: jest.fn(),
22
- warn: jest.fn(),
23
- debug: jest.fn(),
24
- verbose: jest.fn(),
25
- };
26
- });
27
-
28
- afterEach(() => {
29
- jest.clearAllMocks();
30
- });
31
-
32
- describe('Constructor', () => {
33
- it('should create logger in silent mode when no config provided', () => {
34
- const logger = new NAuthLogger();
35
-
36
- expect(logger.isEnabled()).toBe(false);
37
- expect(logger.isPiiRedactionEnabled()).toBe(true);
38
- });
39
-
40
- it('should create logger with LoggerService instance directly', () => {
41
- const logger = new NAuthLogger(mockLogger);
42
-
43
- expect(logger.isEnabled()).toBe(true);
44
- expect(logger.isPiiRedactionEnabled()).toBe(true);
45
- });
46
-
47
- it('should create logger with LoggerConfig object', () => {
48
- const config: NAuthLoggerConfig = {
49
- instance: mockLogger,
50
- enablePiiRedaction: true,
51
- logLevel: 'debug',
52
- };
53
- const logger = new NAuthLogger(config);
54
-
55
- expect(logger.isEnabled()).toBe(true);
56
- expect(logger.isPiiRedactionEnabled()).toBe(true);
57
- });
58
-
59
- it('should disable PII redaction when configured', () => {
60
- const config: NAuthLoggerConfig = {
61
- instance: mockLogger,
62
- enablePiiRedaction: false,
63
- };
64
- const logger = new NAuthLogger(config);
65
-
66
- expect(logger.isPiiRedactionEnabled()).toBe(false);
67
- });
68
- });
69
-
70
- describe('Message Processing', () => {
71
- beforeEach(() => {
72
- logger = new NAuthLogger(mockLogger);
73
- });
74
-
75
- it('should add NAUTH: prefix to string messages', () => {
76
- logger.log('Test message');
77
-
78
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Test message');
79
- });
80
-
81
- it('should add NAUTH: prefix to object messages', () => {
82
- const obj = { key: 'value' };
83
- logger.log(obj);
84
-
85
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: {"key":"value"}');
86
- });
87
-
88
- it('should add NAUTH: prefix to non-string messages', () => {
89
- logger.log(123);
90
-
91
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: 123');
92
- });
93
-
94
- it('should redact PII in messages when enabled', () => {
95
- logger.log('User email@example.com logged in from 192.168.1.1');
96
-
97
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: User e***@***.com logged in from 192.168.1.***');
98
- });
99
-
100
- it('should not redact PII in messages when disabled', () => {
101
- const config: NAuthLoggerConfig = {
102
- instance: mockLogger,
103
- enablePiiRedaction: false,
104
- };
105
- logger = new NAuthLogger(config);
106
-
107
- logger.log('User email@example.com logged in');
108
-
109
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: User email@example.com logged in');
110
- });
111
- });
112
-
113
- describe('Parameter Processing', () => {
114
- beforeEach(() => {
115
- logger = new NAuthLogger(mockLogger);
116
- });
117
-
118
- it('should redact PII in string parameters', () => {
119
- logger.log('Message', 'email@example.com');
120
-
121
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Message', 'e***@***.com');
122
- });
123
-
124
- it('should redact PII in object parameters', () => {
125
- const param = { email: 'test@example.com', ip: '192.168.1.1' };
126
- logger.log('Message', param);
127
-
128
- const expectedParam = { email: 't***@***.com', ip: '192.168.1.***' };
129
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Message', expectedParam);
130
- });
131
-
132
- it('should handle multiple parameters', () => {
133
- logger.log('Message', 'email@example.com', { token: 'secret123' }, 123);
134
-
135
- // Object parameters are stringified and redacted, then parsed back
136
- // Token 'secret123' is too short to match JWT pattern, so it won't be redacted
137
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Message', 'e***@***.com', { token: 'secret123' }, 123);
138
- });
139
-
140
- it('should not process parameters when PII redaction is disabled', () => {
141
- const config: NAuthLoggerConfig = {
142
- instance: mockLogger,
143
- enablePiiRedaction: false,
144
- };
145
- logger = new NAuthLogger(config);
146
-
147
- logger.log('Message', 'email@example.com');
148
-
149
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Message', 'email@example.com');
150
- });
151
- });
152
-
153
- describe('Log Levels', () => {
154
- it('should log all levels when no log level is set', () => {
155
- logger = new NAuthLogger(mockLogger);
156
-
157
- logger.log('test');
158
- logger.error('test');
159
- logger.warn('test');
160
- logger.debug('test');
161
- logger.verbose('test');
162
-
163
- expect(mockLogger.log).toHaveBeenCalled();
164
- expect(mockLogger.error).toHaveBeenCalled();
165
- expect(mockLogger.warn).toHaveBeenCalled();
166
- expect(mockLogger.debug).toHaveBeenCalled();
167
- expect(mockLogger.verbose).toHaveBeenCalled();
168
- });
169
-
170
- it('should filter debug and verbose when log level is warn', () => {
171
- const config: NAuthLoggerConfig = {
172
- instance: mockLogger,
173
- logLevel: 'warn',
174
- };
175
- logger = new NAuthLogger(config);
176
-
177
- logger.error('test'); // Should log (error <= warn)
178
- logger.warn('test'); // Should log (warn <= warn)
179
- logger.log('test'); // Should not log (log > warn)
180
- logger.debug('test'); // Should not log (debug > warn)
181
- logger.verbose('test'); // Should not log (verbose > warn)
182
-
183
- expect(mockLogger.error).toHaveBeenCalled();
184
- expect(mockLogger.warn).toHaveBeenCalled();
185
- expect(mockLogger.log).not.toHaveBeenCalled();
186
- expect(mockLogger.debug).not.toHaveBeenCalled();
187
- expect(mockLogger.verbose).not.toHaveBeenCalled();
188
- });
189
-
190
- it('should filter all except error when log level is error', () => {
191
- const config: NAuthLoggerConfig = {
192
- instance: mockLogger,
193
- logLevel: 'error',
194
- };
195
- logger = new NAuthLogger(config);
196
-
197
- logger.error('test'); // Should log
198
- logger.log('test'); // Should not log
199
- logger.warn('test'); // Should not log
200
- logger.debug('test'); // Should not log
201
- logger.verbose('test'); // Should not log
202
-
203
- expect(mockLogger.error).toHaveBeenCalled();
204
- expect(mockLogger.log).not.toHaveBeenCalled();
205
- expect(mockLogger.warn).not.toHaveBeenCalled();
206
- expect(mockLogger.debug).not.toHaveBeenCalled();
207
- expect(mockLogger.verbose).not.toHaveBeenCalled();
208
- });
209
- });
210
-
211
- describe('Silent Mode', () => {
212
- beforeEach(() => {
213
- logger = new NAuthLogger(); // No logger provided
214
- });
215
-
216
- it('should not call any logger methods in silent mode', () => {
217
- logger.log('test');
218
- logger.error('test');
219
- logger.warn('test');
220
- logger.debug('test');
221
- logger.verbose('test');
222
-
223
- // No calls should be made since no logger was provided
224
- });
225
-
226
- it('should return undefined from all log methods in silent mode', () => {
227
- expect(logger.log('test')).toBeUndefined();
228
- expect(logger.error('test')).toBeUndefined();
229
- expect(logger.warn('test')).toBeUndefined();
230
- expect(logger.debug('test')).toBeUndefined();
231
- expect(logger.verbose('test')).toBeUndefined();
232
- });
233
- });
234
-
235
- describe('Method-specific behavior', () => {
236
- beforeEach(() => {
237
- logger = new NAuthLogger(mockLogger);
238
- });
239
-
240
- describe('debug()', () => {
241
- it('should not call debug if logger does not support debug method', () => {
242
- delete (mockLogger as any).debug;
243
- logger.debug('test');
244
-
245
- // Should not throw error
246
- expect(true).toBe(true);
247
- });
248
-
249
- it('should call debug when available', () => {
250
- logger.debug('test message');
251
-
252
- expect(mockLogger.debug).toHaveBeenCalledWith('NAUTH: test message');
253
- });
254
- });
255
-
256
- describe('verbose()', () => {
257
- it('should not call verbose if logger does not support verbose method', () => {
258
- delete (mockLogger as any).verbose;
259
- logger.verbose('test');
260
-
261
- // Should not throw error
262
- expect(true).toBe(true);
263
- });
264
-
265
- it('should call verbose when available', () => {
266
- logger.verbose('test message');
267
-
268
- expect(mockLogger.verbose).toHaveBeenCalledWith('NAUTH: test message');
269
- });
270
- });
271
- });
272
-
273
- describe('Edge Cases', () => {
274
- beforeEach(() => {
275
- logger = new NAuthLogger(mockLogger);
276
- });
277
-
278
- it('should handle null messages', () => {
279
- logger.log(null);
280
-
281
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: null');
282
- });
283
-
284
- it('should handle undefined messages', () => {
285
- logger.log(undefined);
286
-
287
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: undefined');
288
- });
289
-
290
- it('should handle empty string messages', () => {
291
- logger.log('');
292
-
293
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: ');
294
- });
295
-
296
- it('should handle circular references in objects', () => {
297
- const obj: any = { key: 'value' };
298
- obj.self = obj; // Circular reference
299
-
300
- // Should not throw error, should handle gracefully
301
- expect(() => logger.log('message', obj)).not.toThrow();
302
- expect(mockLogger.log).toHaveBeenCalled();
303
- // Should handle circular reference by converting to safe string
304
- const callArgs = mockLogger.log.mock.calls[0];
305
- expect(callArgs[1]).toBe('[Object with circular reference or invalid JSON]');
306
- });
307
-
308
- it('should handle malformed JSON in parameters', () => {
309
- const malformedParam = {
310
- toJSON: () => {
311
- throw new Error('Bad JSON');
312
- },
313
- };
314
-
315
- // The logger catches JSON.stringify errors (toJSON throwing) and handles them gracefully
316
- expect(() => logger.log('message', malformedParam)).not.toThrow();
317
- expect(mockLogger.log).toHaveBeenCalled();
318
- const callArgs = mockLogger.log.mock.calls[0];
319
- expect(callArgs[1]).toBe('[Object with circular reference or invalid JSON]');
320
- });
321
-
322
- it('should handle empty parameters array', () => {
323
- logger.log('message');
324
-
325
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: message');
326
- });
327
-
328
- it('should handle invalid log levels gracefully', () => {
329
- const config: NAuthLoggerConfig = {
330
- instance: mockLogger,
331
- logLevel: 'invalid' as any,
332
- };
333
- logger = new NAuthLogger(config);
334
-
335
- // When logLevel is invalid, indexOf returns -1, which means nothing will log
336
- // This is expected behavior - invalid levels should not log
337
- logger.debug('test');
338
- expect(mockLogger.debug).not.toHaveBeenCalled();
339
- });
340
- });
341
-
342
- describe('PII Redaction Integration', () => {
343
- beforeEach(() => {
344
- logger = new NAuthLogger(mockLogger);
345
- });
346
-
347
- it('should redact emails in messages', () => {
348
- logger.log('Contact user@test.com for support');
349
-
350
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Contact u***@***.com for support');
351
- });
352
-
353
- it('should redact IP addresses in messages', () => {
354
- logger.log('Request from 192.168.1.100');
355
-
356
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Request from 192.168.1.***');
357
- });
358
-
359
- it('should redact tokens in messages', () => {
360
- // JWT tokens have dots that get redacted separately - each part (before/after dot) matches JWT pattern
361
- logger.log('Using token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0');
362
-
363
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Using token [REDACTED_TOKEN].[REDACTED_TOKEN]');
364
- });
365
-
366
- it('should redact phone numbers in messages', () => {
367
- logger.log('Call +1234567890');
368
-
369
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: Call +123***7890');
370
- });
371
-
372
- it('should redact names in messages', () => {
373
- // Name redaction only works in specific JSON patterns, not in plain text
374
- // This test verifies names are logged as-is in plain text messages
375
- logger.log('User John Doe signed up');
376
-
377
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: User John Doe signed up');
378
- });
379
-
380
- it('should redact passwords when PII redaction is enabled', () => {
381
- // Password redaction works on JSON-like patterns: password="value" or password: "value"
382
- // Plain text "Password is ..." doesn't match the pattern
383
- logger.log('password: mySecret123');
384
-
385
- expect(mockLogger.log).toHaveBeenCalledWith('NAUTH: password=[REDACTED]');
386
- });
387
- });
388
- });
@@ -1,215 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { LoggerService, NAuthLoggerConfig } from '../interfaces/config.interface';
3
- import { PiiRedactor } from './pii-redactor';
4
-
5
- /**
6
- * NAuth Logger Wrapper
7
- *
8
- * Wraps any NestJS-compatible logger and adds features:
9
- * 1. "NAUTH:" prefix to all messages for easy identification
10
- * 2. Automatic PII redaction (emails, IPs, tokens, etc.) - enabled by default
11
- * 3. Optional log level filtering
12
- * 4. Silent mode if no logger is provided
13
- *
14
- * This allows nauth-toolkit to integrate seamlessly with the consuming application's
15
- * logging infrastructure while maintaining security and compliance.
16
- *
17
- * @example
18
- * ```typescript
19
- * // With NestJS built-in logger (PII redaction enabled by default)
20
- * const logger = new NAuthLogger(new Logger('MyApp'));
21
- * logger.log('User user@example.com signed up');
22
- * // Output: [MyApp] NAUTH: User u***@***.com signed up
23
- *
24
- * // With config options
25
- * const logger = new NAuthLogger({
26
- * instance: new Logger('MyApp'),
27
- * enablePiiRedaction: true, // Default
28
- * logLevel: 'debug'
29
- * });
30
- *
31
- * // Disable PII redaction (debugging only)
32
- * const logger = new NAuthLogger({
33
- * instance: myLogger,
34
- * enablePiiRedaction: false
35
- * });
36
- *
37
- * // Silent mode (no logger provided)
38
- * const logger = new NAuthLogger();
39
- * logger.log('This will not be logged'); // No output
40
- * ```
41
- */
42
- export class NAuthLogger implements LoggerService {
43
- private static readonly PREFIX = 'NAUTH:';
44
-
45
- private readonly logger?: LoggerService;
46
- private readonly piiRedactor: PiiRedactor;
47
- private readonly enablePiiRedaction: boolean;
48
- private readonly logLevel?: string;
49
-
50
- constructor(config?: LoggerService | NAuthLoggerConfig) {
51
- if (!config) {
52
- // Silent mode
53
- this.logger = undefined;
54
- this.enablePiiRedaction = true;
55
- this.piiRedactor = new PiiRedactor();
56
- } else if ('instance' in config) {
57
- // LoggerConfig object
58
- this.logger = config.instance;
59
- this.enablePiiRedaction = config.enablePiiRedaction !== false; // Default: true
60
- this.logLevel = config.logLevel;
61
- this.piiRedactor = new PiiRedactor({
62
- redactEmails: this.enablePiiRedaction,
63
- redactIpAddresses: this.enablePiiRedaction,
64
- redactTokens: this.enablePiiRedaction,
65
- redactPhoneNumbers: this.enablePiiRedaction,
66
- redactNames: this.enablePiiRedaction,
67
- redactPasswords: true, // Always redact passwords
68
- });
69
- } else {
70
- // LoggerService instance directly
71
- this.logger = config;
72
- this.enablePiiRedaction = true; // Default: enabled
73
- this.piiRedactor = new PiiRedactor();
74
- }
75
- }
76
-
77
- /**
78
- * Log a message (info level)
79
- */
80
- log(message: any, ...optionalParams: any[]): any {
81
- if (!this.logger || !this.shouldLog('log')) return;
82
-
83
- const processedMessage = this.processMessage(message);
84
- const processedParams = this.processParams(optionalParams);
85
- return this.logger.log(processedMessage, ...processedParams);
86
- }
87
-
88
- /**
89
- * Log an error message
90
- */
91
- error(message: any, ...optionalParams: any[]): any {
92
- if (!this.logger || !this.shouldLog('error')) return;
93
-
94
- const processedMessage = this.processMessage(message);
95
- const processedParams = this.processParams(optionalParams);
96
- return this.logger.error(processedMessage, ...processedParams);
97
- }
98
-
99
- /**
100
- * Log a warning message
101
- */
102
- warn(message: any, ...optionalParams: any[]): any {
103
- if (!this.logger || !this.shouldLog('warn')) return;
104
-
105
- const processedMessage = this.processMessage(message);
106
- const processedParams = this.processParams(optionalParams);
107
- return this.logger.warn(processedMessage, ...processedParams);
108
- }
109
-
110
- /**
111
- * Log a debug message
112
- */
113
- debug(message: any, ...optionalParams: any[]): any {
114
- if (!this.logger || !this.logger.debug || !this.shouldLog('debug')) return;
115
-
116
- const processedMessage = this.processMessage(message);
117
- const processedParams = this.processParams(optionalParams);
118
- return this.logger.debug(processedMessage, ...processedParams);
119
- }
120
-
121
- /**
122
- * Log a verbose message
123
- */
124
- verbose(message: any, ...optionalParams: any[]): any {
125
- if (!this.logger || !this.logger.verbose || !this.shouldLog('verbose')) return;
126
-
127
- const processedMessage = this.processMessage(message);
128
- const processedParams = this.processParams(optionalParams);
129
- return this.logger.verbose(processedMessage, ...processedParams);
130
- }
131
-
132
- /**
133
- * Process message: add prefix and apply PII redaction
134
- * @private
135
- */
136
- private processMessage(message: any): any {
137
- let processedMessage: string;
138
-
139
- if (typeof message === 'string') {
140
- processedMessage = message;
141
- } else if (typeof message === 'object') {
142
- // For objects, stringify then redact
143
- processedMessage = JSON.stringify(message);
144
- } else {
145
- processedMessage = String(message);
146
- }
147
-
148
- // Apply PII redaction if enabled
149
- if (this.enablePiiRedaction) {
150
- processedMessage = this.piiRedactor.redactMessage(processedMessage);
151
- }
152
-
153
- // Add NAUTH: prefix
154
- return `${NAuthLogger.PREFIX} ${processedMessage}`;
155
- }
156
-
157
- /**
158
- * Process optional parameters: apply PII redaction
159
- * @private
160
- */
161
- private processParams(params: any[]): any[] {
162
- if (!this.enablePiiRedaction || params.length === 0) {
163
- return params;
164
- }
165
-
166
- return params.map((param) => {
167
- if (typeof param === 'string') {
168
- return this.piiRedactor.redactMessage(param);
169
- } else if (typeof param === 'object') {
170
- // For objects, stringify, redact, then parse back
171
- try {
172
- const stringified = JSON.stringify(param);
173
- const redacted = this.piiRedactor.redactMessage(stringified);
174
- try {
175
- return JSON.parse(redacted);
176
- } catch {
177
- return redacted;
178
- }
179
- } catch {
180
- // Handle circular references or other JSON.stringify errors (e.g., toJSON throwing)
181
- return '[Object with circular reference or invalid JSON]';
182
- }
183
- }
184
- return param;
185
- });
186
- }
187
-
188
- /**
189
- * Check if message should be logged based on log level
190
- * @private
191
- */
192
- private shouldLog(level: string): boolean {
193
- if (!this.logLevel) return true; // No filter, log everything
194
-
195
- const levels = ['error', 'warn', 'log', 'debug', 'verbose'];
196
- const configLevel = levels.indexOf(this.logLevel);
197
- const messageLevel = levels.indexOf(level);
198
-
199
- return messageLevel <= configLevel;
200
- }
201
-
202
- /**
203
- * Check if logger is enabled
204
- */
205
- isEnabled(): boolean {
206
- return !!this.logger;
207
- }
208
-
209
- /**
210
- * Check if PII redaction is enabled
211
- */
212
- isPiiRedactionEnabled(): boolean {
213
- return this.enablePiiRedaction;
214
- }
215
- }