@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,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
|
-
}
|