@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,374 +0,0 @@
|
|
|
1
|
-
import { ClientInfo } from '../interfaces/client-info.interface';
|
|
2
|
-
import { ContextStorage } from '../utils/context-storage';
|
|
3
|
-
import {
|
|
4
|
-
GetClientInfoResponseDTO,
|
|
5
|
-
GetIpAddressResponseDTO,
|
|
6
|
-
GetUserAgentResponseDTO,
|
|
7
|
-
GetDeviceTokenResponseDTO,
|
|
8
|
-
GetSessionIdResponseDTO,
|
|
9
|
-
} from '../dto';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Client Info Service
|
|
13
|
-
*
|
|
14
|
-
* Provides transparent access to client information (IP address, user agent, device info)
|
|
15
|
-
* from the current request context using async local storage.
|
|
16
|
-
*
|
|
17
|
-
* This service eliminates the need to pass IP addresses and user agents as parameters
|
|
18
|
-
* to authentication methods. The library handles this automatically, just like AWS Cognito.
|
|
19
|
-
*
|
|
20
|
-
* **Key Features:**
|
|
21
|
-
* - Transparent access to client metadata
|
|
22
|
-
* - No parameters needed in service methods
|
|
23
|
-
* - Works across async boundaries
|
|
24
|
-
* - Type-safe with TypeScript
|
|
25
|
-
* - Thread-safe with async local storage
|
|
26
|
-
* - Platform-agnostic (no framework dependencies)
|
|
27
|
-
*
|
|
28
|
-
* **Usage:**
|
|
29
|
-
* ```typescript
|
|
30
|
-
* export class AuthService {
|
|
31
|
-
* constructor(private clientInfoService: ClientInfoService) {}
|
|
32
|
-
*
|
|
33
|
-
* async login(dto: LoginDTO) {
|
|
34
|
-
* // Get client info from context (no parameters needed!)
|
|
35
|
-
* const clientInfo = this.clientInfoService.get();
|
|
36
|
-
*
|
|
37
|
-
* // Use it
|
|
38
|
-
* logger.debug('IP Address:', clientInfo.ipAddress);
|
|
39
|
-
* logger.debug('User Agent:', clientInfo.userAgent);
|
|
40
|
-
* }
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* **Note:**
|
|
45
|
-
* This service must be called within the context of an HTTP request.
|
|
46
|
-
* If called outside a request context (e.g., cron jobs, CLI), it will
|
|
47
|
-
* return a default ClientInfo object with 'unknown' values.
|
|
48
|
-
*/
|
|
49
|
-
export class ClientInfoService {
|
|
50
|
-
constructor() {
|
|
51
|
-
// No dependencies - uses static ContextStorage
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get client information from the current request context
|
|
56
|
-
*
|
|
57
|
-
* This method retrieves client metadata that was automatically extracted
|
|
58
|
-
* by ClientInfoInterceptor and stored in async local storage.
|
|
59
|
-
*
|
|
60
|
-
* @returns Response DTO with client information
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* ```typescript
|
|
64
|
-
* const result = this.clientInfoService.get();
|
|
65
|
-
* logger.debug('IP Address:', result.ipAddress); // 192.168.1.100
|
|
66
|
-
* logger.debug('User Agent:', result.userAgent); // Mozilla/5.0 ...
|
|
67
|
-
* ```
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```typescript
|
|
71
|
-
* // If called outside request context (e.g., cron job)
|
|
72
|
-
* const result = this.clientInfoService.get();
|
|
73
|
-
* logger.debug('IP Address:', result.ipAddress); // 'unknown'
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
get(): GetClientInfoResponseDTO {
|
|
77
|
-
const clientInfo = ContextStorage.get<ClientInfo>('CLIENT_INFO');
|
|
78
|
-
|
|
79
|
-
// If no client info in context (e.g., cron job, CLI), return default
|
|
80
|
-
if (!clientInfo) {
|
|
81
|
-
return {
|
|
82
|
-
ipAddress: 'unknown',
|
|
83
|
-
userAgent: 'unknown',
|
|
84
|
-
} as GetClientInfoResponseDTO;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return clientInfo as GetClientInfoResponseDTO;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get IP address from the current request context
|
|
92
|
-
*
|
|
93
|
-
* Convenience method to get just the IP address without the full ClientInfo object.
|
|
94
|
-
*
|
|
95
|
-
* @returns Response DTO with IP address
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* ```typescript
|
|
99
|
-
* const result = this.clientInfoService.getIpAddress();
|
|
100
|
-
* logger.debug('IP Address:', result.ipAddress); // 192.168.1.100
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
getIpAddress(): GetIpAddressResponseDTO {
|
|
104
|
-
return {
|
|
105
|
-
ipAddress: this.get().ipAddress,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Get user agent from the current request context
|
|
111
|
-
*
|
|
112
|
-
* Convenience method to get just the user agent without the full ClientInfo object.
|
|
113
|
-
*
|
|
114
|
-
* @returns Response DTO with user agent
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* ```typescript
|
|
118
|
-
* const result = this.clientInfoService.getUserAgent();
|
|
119
|
-
* logger.debug('User Agent:', result.userAgent); // Mozilla/5.0 (Windows NT 10.0; Win64; x64)...
|
|
120
|
-
* ```
|
|
121
|
-
*/
|
|
122
|
-
getUserAgent(): GetUserAgentResponseDTO {
|
|
123
|
-
return {
|
|
124
|
-
userAgent: this.get().userAgent,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Get device token from the current request context
|
|
130
|
-
*
|
|
131
|
-
* Convenience method to get just the device token (for trusted device feature).
|
|
132
|
-
*
|
|
133
|
-
* @returns Response DTO with device token
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* ```typescript
|
|
137
|
-
* const result = this.clientInfoService.getDeviceToken();
|
|
138
|
-
* if (result.deviceToken) {
|
|
139
|
-
* logger.debug('Device token:', result.deviceToken);
|
|
140
|
-
* }
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
|
-
getDeviceToken(): GetDeviceTokenResponseDTO {
|
|
144
|
-
return {
|
|
145
|
-
deviceToken: this.get().deviceToken,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Get device ID from the current request context (deprecated)
|
|
151
|
-
*
|
|
152
|
-
* @deprecated Use getDeviceToken() instead. deviceId was removed from ClientInfo for security.
|
|
153
|
-
* @returns Always undefined (deviceId not available from clientInfo - use session.deviceId if needed)
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* ```typescript
|
|
157
|
-
* const deviceId = this.clientInfoService.getDeviceId();
|
|
158
|
-
* // Always returns undefined
|
|
159
|
-
* ```
|
|
160
|
-
*/
|
|
161
|
-
getDeviceId(): string | undefined {
|
|
162
|
-
// deviceId removed from ClientInfo interface - use session.deviceId if needed
|
|
163
|
-
return undefined;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Get session ID from the current request context
|
|
168
|
-
*
|
|
169
|
-
* Convenience method to get just the session ID (extracted from JWT token after authentication).
|
|
170
|
-
*
|
|
171
|
-
* @returns Response DTO with session ID
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* ```typescript
|
|
175
|
-
* const result = this.clientInfoService.getSessionId();
|
|
176
|
-
* if (result.sessionId) {
|
|
177
|
-
* logger.debug('Session ID:', result.sessionId);
|
|
178
|
-
* }
|
|
179
|
-
* ```
|
|
180
|
-
*/
|
|
181
|
-
getSessionId(): GetSessionIdResponseDTO {
|
|
182
|
-
return {
|
|
183
|
-
sessionId: this.get().sessionId,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Get response object from the current request context
|
|
189
|
-
*
|
|
190
|
-
* Returns the HTTP response object that was stored by the framework interceptor.
|
|
191
|
-
* Used internally by services to perform response operations like clearing cookies.
|
|
192
|
-
*
|
|
193
|
-
* @returns Response object with cookie manipulation methods, or null if not available
|
|
194
|
-
* @internal - Used by core services, not by application code
|
|
195
|
-
*
|
|
196
|
-
* @example
|
|
197
|
-
* ```typescript
|
|
198
|
-
* const response = this.clientInfoService.getResponse();
|
|
199
|
-
* if (response?.clearCookie) {
|
|
200
|
-
* response.clearCookie('my_cookie');
|
|
201
|
-
* }
|
|
202
|
-
* ```
|
|
203
|
-
*/
|
|
204
|
-
getResponse(): { clearCookie?: (name: string, options?: unknown) => void } | null {
|
|
205
|
-
return ContextStorage.get<{ clearCookie?: (name: string, options?: unknown) => void }>('HTTP_RESPONSE') || null;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Parse user-agent string to extract browser, platform, and device information
|
|
210
|
-
*
|
|
211
|
-
* This method is used internally by interceptors to populate ClientInfo.
|
|
212
|
-
* Services should use ClientInfoService.get() to access parsed information.
|
|
213
|
-
*
|
|
214
|
-
* @param userAgent - User-agent string from HTTP request
|
|
215
|
-
* @returns Parsed user-agent information
|
|
216
|
-
* @internal - Used by interceptors, not by application code
|
|
217
|
-
*/
|
|
218
|
-
parseUserAgent(userAgent?: string | null): {
|
|
219
|
-
browser: string | null;
|
|
220
|
-
platform: string | null;
|
|
221
|
-
deviceType: 'desktop' | 'mobile' | 'tablet' | null;
|
|
222
|
-
deviceName: string | null;
|
|
223
|
-
} {
|
|
224
|
-
if (!userAgent || typeof userAgent !== 'string' || userAgent.trim() === '') {
|
|
225
|
-
return {
|
|
226
|
-
browser: null,
|
|
227
|
-
platform: null,
|
|
228
|
-
deviceType: null,
|
|
229
|
-
deviceName: null,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const ua = userAgent.toLowerCase();
|
|
234
|
-
|
|
235
|
-
// ============================================================================
|
|
236
|
-
// Detect Device Type
|
|
237
|
-
// ============================================================================
|
|
238
|
-
let deviceType: 'desktop' | 'mobile' | 'tablet' | null = null;
|
|
239
|
-
|
|
240
|
-
// Mobile devices
|
|
241
|
-
if (/mobile|android|iphone|ipod|blackberry|opera|mini|windows\s+phone|palm|iemobile/i.test(ua)) {
|
|
242
|
-
// Tablets
|
|
243
|
-
if (/tablet|ipad|playbook|silk|kindle/i.test(ua)) {
|
|
244
|
-
deviceType = 'tablet';
|
|
245
|
-
} else {
|
|
246
|
-
deviceType = 'mobile';
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
deviceType = 'desktop';
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// ============================================================================
|
|
253
|
-
// Detect Platform/OS
|
|
254
|
-
// ============================================================================
|
|
255
|
-
let platform: string | null = null;
|
|
256
|
-
|
|
257
|
-
if (/windows/i.test(ua)) {
|
|
258
|
-
if (/windows nt 10/i.test(ua)) {
|
|
259
|
-
platform = 'Windows 10';
|
|
260
|
-
} else if (/windows nt 11/i.test(ua)) {
|
|
261
|
-
platform = 'Windows 11';
|
|
262
|
-
} else if (/windows nt 6.3/i.test(ua)) {
|
|
263
|
-
platform = 'Windows 8.1';
|
|
264
|
-
} else if (/windows nt 6.2/i.test(ua)) {
|
|
265
|
-
platform = 'Windows 8';
|
|
266
|
-
} else if (/windows nt 6.1/i.test(ua)) {
|
|
267
|
-
platform = 'Windows 7';
|
|
268
|
-
} else {
|
|
269
|
-
platform = 'Windows';
|
|
270
|
-
}
|
|
271
|
-
} else if (/macintosh|mac os x/i.test(ua)) {
|
|
272
|
-
const match = ua.match(/mac os x (\d+)[._](\d+)/);
|
|
273
|
-
if (match) {
|
|
274
|
-
const major = parseInt(match[1], 10);
|
|
275
|
-
// Convert to macOS version names (approximate)
|
|
276
|
-
if (major >= 13) {
|
|
277
|
-
platform = 'macOS Ventura+';
|
|
278
|
-
} else if (major >= 12) {
|
|
279
|
-
platform = 'macOS Monterey';
|
|
280
|
-
} else if (major >= 11) {
|
|
281
|
-
platform = 'macOS Big Sur';
|
|
282
|
-
} else {
|
|
283
|
-
platform = 'macOS';
|
|
284
|
-
}
|
|
285
|
-
} else {
|
|
286
|
-
platform = 'macOS';
|
|
287
|
-
}
|
|
288
|
-
} else if (/iphone|ipad|ipod/i.test(ua)) {
|
|
289
|
-
const match = ua.match(/os (\d+)[._](\d+)/);
|
|
290
|
-
if (match) {
|
|
291
|
-
platform = `iOS ${match[1]}.${match[2]}`;
|
|
292
|
-
} else {
|
|
293
|
-
platform = 'iOS';
|
|
294
|
-
}
|
|
295
|
-
} else if (/android/i.test(ua)) {
|
|
296
|
-
const match = ua.match(/android (\d+)[._](\d+)/);
|
|
297
|
-
if (match) {
|
|
298
|
-
platform = `Android ${match[1]}.${match[2]}`;
|
|
299
|
-
} else {
|
|
300
|
-
platform = 'Android';
|
|
301
|
-
}
|
|
302
|
-
} else if (/linux/i.test(ua)) {
|
|
303
|
-
platform = 'Linux';
|
|
304
|
-
} else if (/ubuntu/i.test(ua)) {
|
|
305
|
-
platform = 'Ubuntu';
|
|
306
|
-
} else if (/fedora/i.test(ua)) {
|
|
307
|
-
platform = 'Fedora';
|
|
308
|
-
} else {
|
|
309
|
-
platform = null;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// ============================================================================
|
|
313
|
-
// Detect Browser
|
|
314
|
-
// ============================================================================
|
|
315
|
-
let browser: string | null = null;
|
|
316
|
-
|
|
317
|
-
if (/edg/i.test(ua)) {
|
|
318
|
-
browser = 'Edge';
|
|
319
|
-
} else if (/chrome/i.test(ua) && !/edg/i.test(ua)) {
|
|
320
|
-
const match = ua.match(/chrome\/(\d+)/);
|
|
321
|
-
browser = match ? `Chrome ${match[1]}` : 'Chrome';
|
|
322
|
-
} else if (/safari/i.test(ua) && !/chrome/i.test(ua)) {
|
|
323
|
-
const match = ua.match(/version\/(\d+)/);
|
|
324
|
-
browser = match ? `Safari ${match[1]}` : 'Safari';
|
|
325
|
-
} else if (/firefox/i.test(ua)) {
|
|
326
|
-
const match = ua.match(/firefox\/(\d+)/);
|
|
327
|
-
browser = match ? `Firefox ${match[1]}` : 'Firefox';
|
|
328
|
-
} else if (/opera|opr/i.test(ua)) {
|
|
329
|
-
browser = 'Opera';
|
|
330
|
-
} else if (/msie|trident/i.test(ua)) {
|
|
331
|
-
browser = 'Internet Explorer';
|
|
332
|
-
} else if (/brave/i.test(ua)) {
|
|
333
|
-
browser = 'Brave';
|
|
334
|
-
} else {
|
|
335
|
-
browser = null;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// ============================================================================
|
|
339
|
-
// Generate Device Name
|
|
340
|
-
// ============================================================================
|
|
341
|
-
let deviceName: string | null = null;
|
|
342
|
-
|
|
343
|
-
if (browser && platform) {
|
|
344
|
-
deviceName = `${browser} on ${platform}`;
|
|
345
|
-
} else if (browser) {
|
|
346
|
-
deviceName = browser;
|
|
347
|
-
} else if (platform) {
|
|
348
|
-
deviceName = platform;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Special cases for mobile devices
|
|
352
|
-
if (deviceType === 'mobile' || deviceType === 'tablet') {
|
|
353
|
-
if (/iphone/i.test(ua)) {
|
|
354
|
-
const modelMatch = ua.match(/iphone(\d+),?(\d+)?/);
|
|
355
|
-
if (modelMatch) {
|
|
356
|
-
deviceName = `iPhone ${modelMatch[1]}${modelMatch[2] ? ` ${modelMatch[2]}` : ''} on ${platform || 'iOS'}`;
|
|
357
|
-
} else {
|
|
358
|
-
deviceName = `iPhone on ${platform || 'iOS'}`;
|
|
359
|
-
}
|
|
360
|
-
} else if (/ipad/i.test(ua)) {
|
|
361
|
-
deviceName = `iPad on ${platform || 'iOS'}`;
|
|
362
|
-
} else if (/android/i.test(ua)) {
|
|
363
|
-
deviceName = `${browser || 'Android'} on ${platform || 'Android'}`;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return {
|
|
368
|
-
browser,
|
|
369
|
-
platform,
|
|
370
|
-
deviceType,
|
|
371
|
-
deviceName,
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSRF Protection Service
|
|
3
|
-
*
|
|
4
|
-
* Handles CSRF token generation and validation for cookie-based authentication.
|
|
5
|
-
* Uses cryptographically secure random tokens.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as crypto from 'crypto';
|
|
9
|
-
import { NAuthConfig } from '../index';
|
|
10
|
-
|
|
11
|
-
export class CsrfService {
|
|
12
|
-
private readonly cookieName: string;
|
|
13
|
-
private readonly headerName: string;
|
|
14
|
-
private readonly cookieOptions: any;
|
|
15
|
-
|
|
16
|
-
constructor(config: NAuthConfig) {
|
|
17
|
-
this.cookieName = config.security?.csrf?.cookieName || 'nauth_csrf_token';
|
|
18
|
-
this.headerName = config.security?.csrf?.headerName || 'x-csrf-token';
|
|
19
|
-
this.cookieOptions = config.security?.csrf?.cookieOptions || {};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Generate a new CSRF token
|
|
24
|
-
* @returns Random 32-byte token as hex string
|
|
25
|
-
*/
|
|
26
|
-
generateToken(): string {
|
|
27
|
-
return crypto.randomBytes(32).toString('hex');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Validate CSRF token
|
|
32
|
-
* Compares token from request header with token from cookie.
|
|
33
|
-
* Uses constant-time comparison to prevent timing attacks.
|
|
34
|
-
*/
|
|
35
|
-
validateToken(headerToken: string, cookieToken: string): boolean {
|
|
36
|
-
if (!headerToken || !cookieToken) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
// Constant-time comparison
|
|
40
|
-
return crypto.timingSafeEqual(Buffer.from(headerToken), Buffer.from(cookieToken));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
getCookieName(): string {
|
|
44
|
-
return this.cookieName;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
getHeaderName(): string {
|
|
48
|
-
return this.headerName;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
getCookieOptions(): any {
|
|
52
|
-
return this.cookieOptions;
|
|
53
|
-
}
|
|
54
|
-
}
|