@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.
- package/LICENSE +90 -0
- package/README.md +30 -0
- package/package.json +7 -2
- 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,572 +0,0 @@
|
|
|
1
|
-
import { ClientInfoService } from './client-info.service';
|
|
2
|
-
import { ClientInfo } from '../interfaces/client-info.interface';
|
|
3
|
-
import { ContextStorage } from '../utils/context-storage';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Client Info Service Unit Tests
|
|
7
|
-
*
|
|
8
|
-
* Tests the client information extraction and retrieval functionality.
|
|
9
|
-
* Uses ContextStorage (AsyncLocalStorage) for platform-agnostic context management.
|
|
10
|
-
*
|
|
11
|
-
* Covers:
|
|
12
|
-
* - All service methods (get, getIpAddress, getUserAgent, getDeviceToken, getDeviceId)
|
|
13
|
-
* - ClientInfo retrieval from context
|
|
14
|
-
* - Default values when no context exists
|
|
15
|
-
* - All optional ClientInfo fields
|
|
16
|
-
* - Edge cases (empty strings, undefined values, complete objects)
|
|
17
|
-
* - ContextStorage integration
|
|
18
|
-
*/
|
|
19
|
-
describe('ClientInfoService', () => {
|
|
20
|
-
let service: ClientInfoService;
|
|
21
|
-
|
|
22
|
-
const mockClientInfo: ClientInfo = {
|
|
23
|
-
ipAddress: '192.168.1.100',
|
|
24
|
-
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
25
|
-
deviceToken: 'device-token-123',
|
|
26
|
-
deviceName: 'My Laptop',
|
|
27
|
-
deviceType: 'desktop',
|
|
28
|
-
ipCountry: 'US',
|
|
29
|
-
ipCity: 'New York',
|
|
30
|
-
platform: 'Windows',
|
|
31
|
-
browser: 'Chrome',
|
|
32
|
-
sessionId: 123,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
beforeEach(() => {
|
|
36
|
-
service = new ClientInfoService();
|
|
37
|
-
// Clear any existing context before each test
|
|
38
|
-
ContextStorage.clear();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
afterEach(() => {
|
|
42
|
-
// Ensure context is cleared after each test
|
|
43
|
-
ContextStorage.clear();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// ============================================================================
|
|
47
|
-
// Service Initialization
|
|
48
|
-
// ============================================================================
|
|
49
|
-
|
|
50
|
-
it('should be defined', () => {
|
|
51
|
-
expect(service).toBeDefined();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// ============================================================================
|
|
55
|
-
// get() Method
|
|
56
|
-
// ============================================================================
|
|
57
|
-
|
|
58
|
-
describe('get()', () => {
|
|
59
|
-
it('should return client info from context when available', () => {
|
|
60
|
-
ContextStorage.run(() => {
|
|
61
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
62
|
-
|
|
63
|
-
const result = service.get();
|
|
64
|
-
|
|
65
|
-
expect(result).toEqual(mockClientInfo);
|
|
66
|
-
expect(result.ipAddress).toBe('192.168.1.100');
|
|
67
|
-
expect(result.userAgent).toBe('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
|
|
68
|
-
expect(result.deviceToken).toBe('device-token-123');
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should return default values when no client info in context', () => {
|
|
73
|
-
// Call outside ContextStorage.run() - no context
|
|
74
|
-
const result = service.get();
|
|
75
|
-
|
|
76
|
-
expect(result).toEqual({
|
|
77
|
-
ipAddress: 'unknown',
|
|
78
|
-
userAgent: 'unknown',
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should return default values when context returns null', () => {
|
|
83
|
-
ContextStorage.run(() => {
|
|
84
|
-
ContextStorage.set('CLIENT_INFO', null);
|
|
85
|
-
|
|
86
|
-
const result = service.get();
|
|
87
|
-
|
|
88
|
-
expect(result).toEqual({
|
|
89
|
-
ipAddress: 'unknown',
|
|
90
|
-
userAgent: 'unknown',
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should return default values when context returns undefined', () => {
|
|
96
|
-
ContextStorage.run(() => {
|
|
97
|
-
ContextStorage.set('CLIENT_INFO', undefined);
|
|
98
|
-
|
|
99
|
-
const result = service.get();
|
|
100
|
-
|
|
101
|
-
expect(result).toEqual({
|
|
102
|
-
ipAddress: 'unknown',
|
|
103
|
-
userAgent: 'unknown',
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should handle partial client info from context', () => {
|
|
109
|
-
const partialClientInfo: ClientInfo = {
|
|
110
|
-
ipAddress: '10.0.0.1',
|
|
111
|
-
userAgent: 'Test Agent',
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
ContextStorage.run(() => {
|
|
115
|
-
ContextStorage.set('CLIENT_INFO', partialClientInfo);
|
|
116
|
-
|
|
117
|
-
const result = service.get();
|
|
118
|
-
|
|
119
|
-
expect(result).toEqual(partialClientInfo);
|
|
120
|
-
expect(result.ipAddress).toBe('10.0.0.1');
|
|
121
|
-
expect(result.userAgent).toBe('Test Agent');
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should handle client info with all optional fields', () => {
|
|
126
|
-
ContextStorage.run(() => {
|
|
127
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
128
|
-
|
|
129
|
-
const result = service.get();
|
|
130
|
-
|
|
131
|
-
expect(result).toEqual(mockClientInfo);
|
|
132
|
-
expect(result.deviceToken).toBe('device-token-123');
|
|
133
|
-
expect(result.deviceName).toBe('My Laptop');
|
|
134
|
-
expect(result.deviceType).toBe('desktop');
|
|
135
|
-
expect(result.ipCountry).toBe('US');
|
|
136
|
-
expect(result.ipCity).toBe('New York');
|
|
137
|
-
expect(result.platform).toBe('Windows');
|
|
138
|
-
expect(result.browser).toBe('Chrome');
|
|
139
|
-
expect(result.sessionId).toBe(123);
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should handle client info with empty strings', () => {
|
|
144
|
-
const clientInfoWithEmptyStrings: ClientInfo = {
|
|
145
|
-
ipAddress: '',
|
|
146
|
-
userAgent: '',
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
ContextStorage.run(() => {
|
|
150
|
-
ContextStorage.set('CLIENT_INFO', clientInfoWithEmptyStrings);
|
|
151
|
-
|
|
152
|
-
const result = service.get();
|
|
153
|
-
|
|
154
|
-
expect(result.ipAddress).toBe('');
|
|
155
|
-
expect(result.userAgent).toBe('');
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('should handle client info with only required fields', () => {
|
|
160
|
-
const minimalClientInfo: ClientInfo = {
|
|
161
|
-
ipAddress: '192.168.1.1',
|
|
162
|
-
userAgent: 'Mozilla/5.0',
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
ContextStorage.run(() => {
|
|
166
|
-
ContextStorage.set('CLIENT_INFO', minimalClientInfo);
|
|
167
|
-
|
|
168
|
-
const result = service.get();
|
|
169
|
-
|
|
170
|
-
expect(result).toEqual(minimalClientInfo);
|
|
171
|
-
expect(result.deviceToken).toBeUndefined();
|
|
172
|
-
expect(result.deviceName).toBeUndefined();
|
|
173
|
-
expect(result.deviceType).toBeUndefined();
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// ============================================================================
|
|
179
|
-
// getIpAddress() Method
|
|
180
|
-
// ============================================================================
|
|
181
|
-
|
|
182
|
-
describe('getIpAddress()', () => {
|
|
183
|
-
it('should return IP address from client info', () => {
|
|
184
|
-
ContextStorage.run(() => {
|
|
185
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
186
|
-
|
|
187
|
-
const result = service.getIpAddress();
|
|
188
|
-
|
|
189
|
-
expect(result.ipAddress).toBe('192.168.1.100');
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('should return "unknown" when no client info in context', () => {
|
|
194
|
-
// Call outside ContextStorage.run() - no context
|
|
195
|
-
const result = service.getIpAddress();
|
|
196
|
-
|
|
197
|
-
expect(result.ipAddress).toBe('unknown');
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('should return IP address from partial client info', () => {
|
|
201
|
-
const partialClientInfo: ClientInfo = {
|
|
202
|
-
ipAddress: '10.0.0.1',
|
|
203
|
-
userAgent: 'Test',
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
ContextStorage.run(() => {
|
|
207
|
-
ContextStorage.set('CLIENT_INFO', partialClientInfo);
|
|
208
|
-
|
|
209
|
-
const result = service.getIpAddress();
|
|
210
|
-
|
|
211
|
-
expect(result.ipAddress).toBe('10.0.0.1');
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it('should return empty string when IP address is empty', () => {
|
|
216
|
-
const clientInfoWithEmptyIp: ClientInfo = {
|
|
217
|
-
ipAddress: '',
|
|
218
|
-
userAgent: 'Test',
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
ContextStorage.run(() => {
|
|
222
|
-
ContextStorage.set('CLIENT_INFO', clientInfoWithEmptyIp);
|
|
223
|
-
|
|
224
|
-
const result = service.getIpAddress();
|
|
225
|
-
|
|
226
|
-
expect(result.ipAddress).toBe('');
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
// ============================================================================
|
|
232
|
-
// getUserAgent() Method
|
|
233
|
-
// ============================================================================
|
|
234
|
-
|
|
235
|
-
describe('getUserAgent()', () => {
|
|
236
|
-
it('should return user agent from client info', () => {
|
|
237
|
-
ContextStorage.run(() => {
|
|
238
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
239
|
-
|
|
240
|
-
const result = service.getUserAgent();
|
|
241
|
-
|
|
242
|
-
expect(result.userAgent).toBe('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it('should return "unknown" when no client info in context', () => {
|
|
247
|
-
// Call outside ContextStorage.run() - no context
|
|
248
|
-
const result = service.getUserAgent();
|
|
249
|
-
|
|
250
|
-
expect(result.userAgent).toBe('unknown');
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it('should return user agent from partial client info', () => {
|
|
254
|
-
const partialClientInfo: ClientInfo = {
|
|
255
|
-
ipAddress: '10.0.0.1',
|
|
256
|
-
userAgent: 'Test Agent',
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
ContextStorage.run(() => {
|
|
260
|
-
ContextStorage.set('CLIENT_INFO', partialClientInfo);
|
|
261
|
-
|
|
262
|
-
const result = service.getUserAgent();
|
|
263
|
-
|
|
264
|
-
expect(result.userAgent).toBe('Test Agent');
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('should return empty string when user agent is empty', () => {
|
|
269
|
-
const clientInfoWithEmptyUA: ClientInfo = {
|
|
270
|
-
ipAddress: '10.0.0.1',
|
|
271
|
-
userAgent: '',
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
ContextStorage.run(() => {
|
|
275
|
-
ContextStorage.set('CLIENT_INFO', clientInfoWithEmptyUA);
|
|
276
|
-
|
|
277
|
-
const result = service.getUserAgent();
|
|
278
|
-
|
|
279
|
-
expect(result.userAgent).toBe('');
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
// ============================================================================
|
|
285
|
-
// getDeviceToken() Method
|
|
286
|
-
// ============================================================================
|
|
287
|
-
|
|
288
|
-
describe('getDeviceToken()', () => {
|
|
289
|
-
it('should return device token from client info when available', () => {
|
|
290
|
-
ContextStorage.run(() => {
|
|
291
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
292
|
-
|
|
293
|
-
const result = service.getDeviceToken();
|
|
294
|
-
|
|
295
|
-
expect(result.deviceToken).toBe('device-token-123');
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
it('should return undefined when device token is not provided', () => {
|
|
300
|
-
const clientInfoWithoutDeviceToken: ClientInfo = {
|
|
301
|
-
ipAddress: '192.168.1.100',
|
|
302
|
-
userAgent: 'Mozilla/5.0',
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
ContextStorage.run(() => {
|
|
306
|
-
ContextStorage.set('CLIENT_INFO', clientInfoWithoutDeviceToken);
|
|
307
|
-
|
|
308
|
-
const result = service.getDeviceToken();
|
|
309
|
-
|
|
310
|
-
expect(result.deviceToken).toBeUndefined();
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it('should return undefined when no client info in context', () => {
|
|
315
|
-
// Call outside ContextStorage.run() - no context
|
|
316
|
-
const result = service.getDeviceToken();
|
|
317
|
-
|
|
318
|
-
expect(result.deviceToken).toBeUndefined();
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it('should return device token when only device token is provided', () => {
|
|
322
|
-
const clientInfoWithDeviceToken: ClientInfo = {
|
|
323
|
-
ipAddress: '10.0.0.1',
|
|
324
|
-
userAgent: 'Test',
|
|
325
|
-
deviceToken: 'token-456',
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
ContextStorage.run(() => {
|
|
329
|
-
ContextStorage.set('CLIENT_INFO', clientInfoWithDeviceToken);
|
|
330
|
-
|
|
331
|
-
const result = service.getDeviceToken();
|
|
332
|
-
|
|
333
|
-
expect(result.deviceToken).toBe('token-456');
|
|
334
|
-
});
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
// ============================================================================
|
|
339
|
-
// getDeviceId() Method (Deprecated)
|
|
340
|
-
// ============================================================================
|
|
341
|
-
|
|
342
|
-
describe('getDeviceId()', () => {
|
|
343
|
-
it('should return undefined (deprecated method)', () => {
|
|
344
|
-
ContextStorage.run(() => {
|
|
345
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
346
|
-
|
|
347
|
-
const result = service.getDeviceId();
|
|
348
|
-
|
|
349
|
-
// Method always returns undefined (deprecated)
|
|
350
|
-
expect(result).toBeUndefined();
|
|
351
|
-
});
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
it('should return undefined even when device token is provided', () => {
|
|
355
|
-
ContextStorage.run(() => {
|
|
356
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
357
|
-
|
|
358
|
-
const result = service.getDeviceId();
|
|
359
|
-
|
|
360
|
-
// Method always returns undefined regardless of context
|
|
361
|
-
expect(result).toBeUndefined();
|
|
362
|
-
});
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
it('should return undefined when no client info in context', () => {
|
|
366
|
-
// Call outside ContextStorage.run() - no context
|
|
367
|
-
const result = service.getDeviceId();
|
|
368
|
-
|
|
369
|
-
expect(result).toBeUndefined();
|
|
370
|
-
});
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
// ============================================================================
|
|
374
|
-
// Integration with Different Request Scenarios
|
|
375
|
-
// ============================================================================
|
|
376
|
-
|
|
377
|
-
describe('Integration with different request scenarios', () => {
|
|
378
|
-
it('should handle mobile user agent', () => {
|
|
379
|
-
const mobileClientInfo: ClientInfo = {
|
|
380
|
-
ipAddress: '10.0.0.1',
|
|
381
|
-
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X)',
|
|
382
|
-
deviceType: 'mobile',
|
|
383
|
-
platform: 'iOS',
|
|
384
|
-
browser: 'Safari',
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
ContextStorage.run(() => {
|
|
388
|
-
ContextStorage.set('CLIENT_INFO', mobileClientInfo);
|
|
389
|
-
|
|
390
|
-
const result = service.get();
|
|
391
|
-
|
|
392
|
-
expect(result.ipAddress).toBe('10.0.0.1');
|
|
393
|
-
expect(result.userAgent).toContain('iPhone');
|
|
394
|
-
expect(result.deviceType).toBe('mobile');
|
|
395
|
-
expect(result.platform).toBe('iOS');
|
|
396
|
-
expect(result.browser).toBe('Safari');
|
|
397
|
-
});
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
it('should handle API client without user agent', () => {
|
|
401
|
-
const apiClientInfo: ClientInfo = {
|
|
402
|
-
ipAddress: '10.0.0.1',
|
|
403
|
-
userAgent: '',
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
ContextStorage.run(() => {
|
|
407
|
-
ContextStorage.set('CLIENT_INFO', apiClientInfo);
|
|
408
|
-
|
|
409
|
-
const result = service.get();
|
|
410
|
-
|
|
411
|
-
expect(result.ipAddress).toBe('10.0.0.1');
|
|
412
|
-
expect(result.userAgent).toBe('');
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it('should handle IPv6 addresses', () => {
|
|
417
|
-
const ipv6ClientInfo: ClientInfo = {
|
|
418
|
-
ipAddress: '2001:db8::1',
|
|
419
|
-
userAgent: 'curl/7.68.0',
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
ContextStorage.run(() => {
|
|
423
|
-
ContextStorage.set('CLIENT_INFO', ipv6ClientInfo);
|
|
424
|
-
|
|
425
|
-
const result = service.get();
|
|
426
|
-
|
|
427
|
-
expect(result.ipAddress).toBe('2001:db8::1');
|
|
428
|
-
expect(result.userAgent).toBe('curl/7.68.0');
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it('should handle tablet device type', () => {
|
|
433
|
-
const tabletClientInfo: ClientInfo = {
|
|
434
|
-
ipAddress: '10.0.0.1',
|
|
435
|
-
userAgent: 'Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X)',
|
|
436
|
-
deviceType: 'tablet',
|
|
437
|
-
platform: 'iOS',
|
|
438
|
-
browser: 'Safari',
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
ContextStorage.run(() => {
|
|
442
|
-
ContextStorage.set('CLIENT_INFO', tabletClientInfo);
|
|
443
|
-
|
|
444
|
-
const result = service.get();
|
|
445
|
-
|
|
446
|
-
expect(result.deviceType).toBe('tablet');
|
|
447
|
-
expect(result.platform).toBe('iOS');
|
|
448
|
-
});
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
it('should handle client info with geolocation data', () => {
|
|
452
|
-
const clientInfoWithGeo: ClientInfo = {
|
|
453
|
-
ipAddress: '10.0.0.1',
|
|
454
|
-
userAgent: 'Mozilla/5.0',
|
|
455
|
-
ipCountry: 'CA',
|
|
456
|
-
ipCity: 'Toronto',
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
ContextStorage.run(() => {
|
|
460
|
-
ContextStorage.set('CLIENT_INFO', clientInfoWithGeo);
|
|
461
|
-
|
|
462
|
-
const result = service.get();
|
|
463
|
-
|
|
464
|
-
expect(result.ipCountry).toBe('CA');
|
|
465
|
-
expect(result.ipCity).toBe('Toronto');
|
|
466
|
-
});
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
it('should handle client info with session ID', () => {
|
|
470
|
-
const clientInfoWithSession: ClientInfo = {
|
|
471
|
-
ipAddress: '10.0.0.1',
|
|
472
|
-
userAgent: 'Mozilla/5.0',
|
|
473
|
-
sessionId: 456,
|
|
474
|
-
};
|
|
475
|
-
|
|
476
|
-
ContextStorage.run(() => {
|
|
477
|
-
ContextStorage.set('CLIENT_INFO', clientInfoWithSession);
|
|
478
|
-
|
|
479
|
-
const result = service.get();
|
|
480
|
-
|
|
481
|
-
expect(result.sessionId).toBe(456);
|
|
482
|
-
});
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
it('should handle complete client info with all fields', () => {
|
|
486
|
-
const completeClientInfo: ClientInfo = {
|
|
487
|
-
ipAddress: '192.168.1.100',
|
|
488
|
-
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
489
|
-
deviceToken: 'device-token-789',
|
|
490
|
-
deviceName: 'Work Desktop',
|
|
491
|
-
deviceType: 'desktop',
|
|
492
|
-
ipCountry: 'GB',
|
|
493
|
-
ipCity: 'London',
|
|
494
|
-
platform: 'Windows',
|
|
495
|
-
browser: 'Firefox',
|
|
496
|
-
sessionId: 789,
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
ContextStorage.run(() => {
|
|
500
|
-
ContextStorage.set('CLIENT_INFO', completeClientInfo);
|
|
501
|
-
|
|
502
|
-
const result = service.get();
|
|
503
|
-
|
|
504
|
-
expect(result).toEqual(completeClientInfo);
|
|
505
|
-
expect(result.ipAddress).toBe('192.168.1.100');
|
|
506
|
-
expect(result.deviceToken).toBe('device-token-789');
|
|
507
|
-
expect(result.deviceName).toBe('Work Desktop');
|
|
508
|
-
expect(result.deviceType).toBe('desktop');
|
|
509
|
-
expect(result.ipCountry).toBe('GB');
|
|
510
|
-
expect(result.ipCity).toBe('London');
|
|
511
|
-
expect(result.platform).toBe('Windows');
|
|
512
|
-
expect(result.browser).toBe('Firefox');
|
|
513
|
-
expect(result.sessionId).toBe(789);
|
|
514
|
-
});
|
|
515
|
-
});
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
// ============================================================================
|
|
519
|
-
// ContextStorage Integration
|
|
520
|
-
// ============================================================================
|
|
521
|
-
|
|
522
|
-
describe('ContextStorage integration', () => {
|
|
523
|
-
it('should work across async boundaries', async () => {
|
|
524
|
-
const result = await ContextStorage.run(async () => {
|
|
525
|
-
ContextStorage.set('CLIENT_INFO', mockClientInfo);
|
|
526
|
-
|
|
527
|
-
// Simulate async operation
|
|
528
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
529
|
-
|
|
530
|
-
return service.get();
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
expect(result).toEqual(mockClientInfo);
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
it('should isolate context per run() call', () => {
|
|
537
|
-
const firstContext = {
|
|
538
|
-
ipAddress: '10.0.0.1',
|
|
539
|
-
userAgent: 'First',
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
const secondContext = {
|
|
543
|
-
ipAddress: '10.0.0.2',
|
|
544
|
-
userAgent: 'Second',
|
|
545
|
-
};
|
|
546
|
-
|
|
547
|
-
const result1 = ContextStorage.run(() => {
|
|
548
|
-
ContextStorage.set('CLIENT_INFO', firstContext);
|
|
549
|
-
return service.get();
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
const result2 = ContextStorage.run(() => {
|
|
553
|
-
ContextStorage.set('CLIENT_INFO', secondContext);
|
|
554
|
-
return service.get();
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
expect(result1.ipAddress).toBe('10.0.0.1');
|
|
558
|
-
expect(result2.ipAddress).toBe('10.0.0.2');
|
|
559
|
-
expect(result1).not.toEqual(result2);
|
|
560
|
-
});
|
|
561
|
-
|
|
562
|
-
it('should return default values when called outside context', () => {
|
|
563
|
-
// No ContextStorage.run() - should return defaults
|
|
564
|
-
const result = service.get();
|
|
565
|
-
|
|
566
|
-
expect(result).toEqual({
|
|
567
|
-
ipAddress: 'unknown',
|
|
568
|
-
userAgent: 'unknown',
|
|
569
|
-
});
|
|
570
|
-
});
|
|
571
|
-
});
|
|
572
|
-
});
|