@push.rocks/smartproxy 22.4.2 → 23.0.0

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 (101) hide show
  1. package/changelog.md +36 -0
  2. package/dist_rust/rustproxy +0 -0
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/index.d.ts +1 -6
  5. package/dist_ts/index.js +3 -11
  6. package/dist_ts/protocols/common/fragment-handler.js +5 -1
  7. package/dist_ts/proxies/index.d.ts +1 -6
  8. package/dist_ts/proxies/index.js +2 -8
  9. package/dist_ts/proxies/smart-proxy/index.d.ts +5 -10
  10. package/dist_ts/proxies/smart-proxy/index.js +7 -13
  11. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -2
  12. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  13. package/dist_ts/proxies/smart-proxy/route-preprocessor.d.ts +37 -0
  14. package/dist_ts/proxies/smart-proxy/route-preprocessor.js +103 -0
  15. package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +23 -0
  16. package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +104 -0
  17. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +74 -0
  18. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +146 -0
  19. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +49 -0
  20. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +259 -0
  21. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +39 -157
  22. package/dist_ts/proxies/smart-proxy/smart-proxy.js +224 -621
  23. package/dist_ts/proxies/smart-proxy/socket-handler-server.d.ts +45 -0
  24. package/dist_ts/proxies/smart-proxy/socket-handler-server.js +253 -0
  25. package/dist_ts/routing/index.d.ts +1 -1
  26. package/dist_ts/routing/index.js +3 -3
  27. package/dist_ts/routing/models/http-types.d.ts +119 -4
  28. package/dist_ts/routing/models/http-types.js +93 -5
  29. package/package.json +1 -1
  30. package/readme.md +444 -219
  31. package/ts/00_commitinfo_data.ts +1 -1
  32. package/ts/index.ts +4 -15
  33. package/ts/protocols/common/fragment-handler.ts +4 -0
  34. package/ts/proxies/index.ts +1 -12
  35. package/ts/proxies/smart-proxy/index.ts +6 -13
  36. package/ts/proxies/smart-proxy/models/interfaces.ts +6 -4
  37. package/ts/proxies/smart-proxy/models/route-types.ts +0 -2
  38. package/ts/proxies/smart-proxy/route-preprocessor.ts +122 -0
  39. package/ts/proxies/smart-proxy/rust-binary-locator.ts +112 -0
  40. package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +161 -0
  41. package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +310 -0
  42. package/ts/proxies/smart-proxy/smart-proxy.ts +282 -798
  43. package/ts/proxies/smart-proxy/socket-handler-server.ts +279 -0
  44. package/ts/routing/index.ts +2 -2
  45. package/ts/routing/models/http-types.ts +147 -4
  46. package/dist_ts/proxies/nftables-proxy/index.d.ts +0 -6
  47. package/dist_ts/proxies/nftables-proxy/index.js +0 -7
  48. package/dist_ts/proxies/nftables-proxy/models/errors.d.ts +0 -15
  49. package/dist_ts/proxies/nftables-proxy/models/errors.js +0 -28
  50. package/dist_ts/proxies/nftables-proxy/models/index.d.ts +0 -5
  51. package/dist_ts/proxies/nftables-proxy/models/index.js +0 -6
  52. package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +0 -75
  53. package/dist_ts/proxies/nftables-proxy/models/interfaces.js +0 -5
  54. package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +0 -124
  55. package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +0 -1374
  56. package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +0 -9
  57. package/dist_ts/proxies/nftables-proxy/utils/index.js +0 -12
  58. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +0 -66
  59. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +0 -131
  60. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +0 -39
  61. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +0 -112
  62. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +0 -59
  63. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +0 -130
  64. package/ts/proxies/http-proxy/connection-pool.ts +0 -228
  65. package/ts/proxies/http-proxy/context-creator.ts +0 -145
  66. package/ts/proxies/http-proxy/default-certificates.ts +0 -150
  67. package/ts/proxies/http-proxy/function-cache.ts +0 -279
  68. package/ts/proxies/http-proxy/handlers/index.ts +0 -5
  69. package/ts/proxies/http-proxy/http-proxy.ts +0 -669
  70. package/ts/proxies/http-proxy/http-request-handler.ts +0 -331
  71. package/ts/proxies/http-proxy/http2-request-handler.ts +0 -255
  72. package/ts/proxies/http-proxy/index.ts +0 -18
  73. package/ts/proxies/http-proxy/models/http-types.ts +0 -148
  74. package/ts/proxies/http-proxy/models/index.ts +0 -5
  75. package/ts/proxies/http-proxy/models/types.ts +0 -125
  76. package/ts/proxies/http-proxy/request-handler.ts +0 -878
  77. package/ts/proxies/http-proxy/security-manager.ts +0 -413
  78. package/ts/proxies/http-proxy/websocket-handler.ts +0 -581
  79. package/ts/proxies/nftables-proxy/index.ts +0 -6
  80. package/ts/proxies/nftables-proxy/models/errors.ts +0 -30
  81. package/ts/proxies/nftables-proxy/models/index.ts +0 -5
  82. package/ts/proxies/nftables-proxy/models/interfaces.ts +0 -94
  83. package/ts/proxies/nftables-proxy/nftables-proxy.ts +0 -1754
  84. package/ts/proxies/nftables-proxy/utils/index.ts +0 -38
  85. package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +0 -162
  86. package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +0 -125
  87. package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +0 -156
  88. package/ts/proxies/smart-proxy/acme-state-manager.ts +0 -112
  89. package/ts/proxies/smart-proxy/cert-store.ts +0 -92
  90. package/ts/proxies/smart-proxy/certificate-manager.ts +0 -895
  91. package/ts/proxies/smart-proxy/connection-manager.ts +0 -809
  92. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +0 -213
  93. package/ts/proxies/smart-proxy/metrics-collector.ts +0 -453
  94. package/ts/proxies/smart-proxy/nftables-manager.ts +0 -271
  95. package/ts/proxies/smart-proxy/port-manager.ts +0 -358
  96. package/ts/proxies/smart-proxy/route-connection-handler.ts +0 -1712
  97. package/ts/proxies/smart-proxy/route-orchestrator.ts +0 -297
  98. package/ts/proxies/smart-proxy/security-manager.ts +0 -269
  99. package/ts/proxies/smart-proxy/throughput-tracker.ts +0 -138
  100. package/ts/proxies/smart-proxy/timeout-manager.ts +0 -196
  101. package/ts/proxies/smart-proxy/tls-manager.ts +0 -171
@@ -1,413 +0,0 @@
1
- import type { ILogger } from './models/types.js';
2
- import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
3
- import type { IRouteContext } from '../../core/models/route-context.js';
4
- import {
5
- isIPAuthorized,
6
- normalizeIP,
7
- parseBasicAuthHeader,
8
- cleanupExpiredRateLimits,
9
- type IRateLimitInfo
10
- } from '../../core/utils/security-utils.js';
11
-
12
- /**
13
- * Manages security features for the HttpProxy
14
- * Implements IP filtering, rate limiting, and authentication.
15
- * Uses shared utilities from security-utils.ts.
16
- */
17
- export class SecurityManager {
18
- // Cache IP filtering results to avoid constant regex matching
19
- private ipFilterCache: Map<string, Map<string, boolean>> = new Map();
20
-
21
- // Store rate limits per route and key
22
- private rateLimits: Map<string, Map<string, IRateLimitInfo>> = new Map();
23
-
24
- // Connection tracking by IP
25
- private connectionsByIP: Map<string, Set<string>> = new Map();
26
- private connectionRateByIP: Map<string, number[]> = new Map();
27
-
28
- constructor(
29
- private logger: ILogger,
30
- private routes: IRouteConfig[] = [],
31
- private maxConnectionsPerIP: number = 100,
32
- private connectionRateLimitPerMinute: number = 300
33
- ) {
34
- // Start periodic cleanup for connection tracking
35
- this.startPeriodicIpCleanup();
36
- }
37
-
38
- /**
39
- * Update the routes configuration
40
- */
41
- public setRoutes(routes: IRouteConfig[]): void {
42
- this.routes = routes;
43
- // Reset caches when routes change
44
- this.ipFilterCache.clear();
45
- }
46
-
47
- /**
48
- * Check if a client is allowed to access a specific route
49
- *
50
- * @param route The route to check access for
51
- * @param context The route context with client information
52
- * @returns True if access is allowed, false otherwise
53
- */
54
- public isAllowed(route: IRouteConfig, context: IRouteContext): boolean {
55
- if (!route.security) {
56
- return true; // No security restrictions
57
- }
58
-
59
- // --- IP filtering ---
60
- if (!this.isIpAllowed(route, context.clientIp)) {
61
- this.logger.debug(`IP ${context.clientIp} is blocked for route ${route.name || 'unnamed'}`);
62
- return false;
63
- }
64
-
65
- // --- Rate limiting ---
66
- if (route.security.rateLimit?.enabled && !this.isWithinRateLimit(route, context)) {
67
- this.logger.debug(`Rate limit exceeded for route ${route.name || 'unnamed'}`);
68
- return false;
69
- }
70
-
71
- // --- Basic Auth (handled at HTTP level) ---
72
- // Basic auth is not checked here as it requires HTTP headers
73
- // and is handled in the RequestHandler
74
-
75
- return true;
76
- }
77
-
78
- /**
79
- * Check if an IP is allowed based on route security settings
80
- */
81
- private isIpAllowed(route: IRouteConfig, clientIp: string): boolean {
82
- if (!route.security) {
83
- return true; // No security restrictions
84
- }
85
-
86
- const routeId = route.name || 'unnamed';
87
-
88
- // Check cache first
89
- if (!this.ipFilterCache.has(routeId)) {
90
- this.ipFilterCache.set(routeId, new Map());
91
- }
92
-
93
- const routeCache = this.ipFilterCache.get(routeId)!;
94
- if (routeCache.has(clientIp)) {
95
- return routeCache.get(clientIp)!;
96
- }
97
-
98
- // Use shared utility for IP authorization
99
- const allowed = isIPAuthorized(
100
- clientIp,
101
- route.security.ipAllowList,
102
- route.security.ipBlockList
103
- );
104
-
105
- // Cache the result
106
- routeCache.set(clientIp, allowed);
107
-
108
- return allowed;
109
- }
110
-
111
- /**
112
- * Check if request is within rate limit
113
- */
114
- private isWithinRateLimit(route: IRouteConfig, context: IRouteContext): boolean {
115
- if (!route.security?.rateLimit?.enabled) {
116
- return true;
117
- }
118
-
119
- const rateLimit = route.security.rateLimit;
120
- const routeId = route.name || 'unnamed';
121
-
122
- // Determine rate limit key (by IP, path, or header)
123
- let key = context.clientIp; // Default to IP
124
-
125
- if (rateLimit.keyBy === 'path' && context.path) {
126
- key = `${context.clientIp}:${context.path}`;
127
- } else if (rateLimit.keyBy === 'header' && rateLimit.headerName && context.headers) {
128
- const headerValue = context.headers[rateLimit.headerName.toLowerCase()];
129
- if (headerValue) {
130
- key = `${context.clientIp}:${headerValue}`;
131
- }
132
- }
133
-
134
- // Get or create rate limit tracking for this route
135
- if (!this.rateLimits.has(routeId)) {
136
- this.rateLimits.set(routeId, new Map());
137
- }
138
-
139
- const routeLimits = this.rateLimits.get(routeId)!;
140
- const now = Date.now();
141
-
142
- // Get or create rate limit tracking for this key
143
- let limit = routeLimits.get(key);
144
- if (!limit || limit.expiry < now) {
145
- // Create new rate limit or reset expired one
146
- limit = {
147
- count: 1,
148
- expiry: now + (rateLimit.window * 1000)
149
- };
150
- routeLimits.set(key, limit);
151
- return true;
152
- }
153
-
154
- // Increment the counter
155
- limit.count++;
156
-
157
- // Check if rate limit is exceeded
158
- return limit.count <= rateLimit.maxRequests;
159
- }
160
-
161
- /**
162
- * Clean up expired rate limits
163
- * Should be called periodically to prevent memory leaks
164
- */
165
- public cleanupExpiredRateLimits(): void {
166
- cleanupExpiredRateLimits(this.rateLimits, {
167
- info: this.logger.info.bind(this.logger),
168
- warn: this.logger.warn.bind(this.logger),
169
- error: this.logger.error.bind(this.logger),
170
- debug: this.logger.debug?.bind(this.logger)
171
- });
172
- }
173
-
174
- /**
175
- * Check basic auth credentials
176
- *
177
- * @param route The route to check auth for
178
- * @param username The provided username
179
- * @param password The provided password
180
- * @returns True if credentials are valid, false otherwise
181
- */
182
- public checkBasicAuth(route: IRouteConfig, username: string, password: string): boolean {
183
- if (!route.security?.basicAuth?.enabled) {
184
- return true;
185
- }
186
-
187
- const basicAuth = route.security.basicAuth;
188
-
189
- // Check credentials against configured users
190
- for (const user of basicAuth.users) {
191
- if (user.username === username && user.password === password) {
192
- return true;
193
- }
194
- }
195
-
196
- return false;
197
- }
198
-
199
- /**
200
- * Verify a JWT token
201
- *
202
- * @param route The route to verify the token for
203
- * @param token The JWT token to verify
204
- * @returns True if the token is valid, false otherwise
205
- */
206
- public verifyJwtToken(route: IRouteConfig, token: string): boolean {
207
- if (!route.security?.jwtAuth?.enabled) {
208
- return true;
209
- }
210
-
211
- try {
212
- const jwtAuth = route.security.jwtAuth;
213
-
214
- // Verify structure
215
- const parts = token.split('.');
216
- if (parts.length !== 3) {
217
- return false;
218
- }
219
-
220
- // Decode payload
221
- const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString());
222
-
223
- // Check expiration
224
- if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) {
225
- return false;
226
- }
227
-
228
- // Check issuer
229
- if (jwtAuth.issuer && payload.iss !== jwtAuth.issuer) {
230
- return false;
231
- }
232
-
233
- // Check audience
234
- if (jwtAuth.audience && payload.aud !== jwtAuth.audience) {
235
- return false;
236
- }
237
-
238
- // Note: In a real implementation, you'd also verify the signature
239
- // using the secret and algorithm specified in jwtAuth
240
-
241
- return true;
242
- } catch (err) {
243
- this.logger.error(`Error verifying JWT: ${err}`);
244
- return false;
245
- }
246
- }
247
-
248
- /**
249
- * Get connections count by IP (checks normalized variants)
250
- */
251
- public getConnectionCountByIP(ip: string): number {
252
- // Check all normalized variants of the IP
253
- const variants = normalizeIP(ip);
254
- for (const variant of variants) {
255
- const connections = this.connectionsByIP.get(variant);
256
- if (connections) {
257
- return connections.size;
258
- }
259
- }
260
- return 0;
261
- }
262
-
263
- /**
264
- * Check and update connection rate for an IP
265
- * @returns true if within rate limit, false if exceeding limit
266
- */
267
- public checkConnectionRate(ip: string): boolean {
268
- const now = Date.now();
269
- const minute = 60 * 1000;
270
-
271
- // Find existing rate tracking (check normalized variants)
272
- const variants = normalizeIP(ip);
273
- let existingKey: string | null = null;
274
- for (const variant of variants) {
275
- if (this.connectionRateByIP.has(variant)) {
276
- existingKey = variant;
277
- break;
278
- }
279
- }
280
-
281
- const key = existingKey || ip;
282
-
283
- if (!this.connectionRateByIP.has(key)) {
284
- this.connectionRateByIP.set(key, [now]);
285
- return true;
286
- }
287
-
288
- // Get timestamps and filter out entries older than 1 minute
289
- const timestamps = this.connectionRateByIP.get(key)!.filter((time) => now - time < minute);
290
- timestamps.push(now);
291
- this.connectionRateByIP.set(key, timestamps);
292
-
293
- // Check if rate exceeds limit
294
- return timestamps.length <= this.connectionRateLimitPerMinute;
295
- }
296
-
297
- /**
298
- * Track connection by IP
299
- */
300
- public trackConnectionByIP(ip: string, connectionId: string): void {
301
- // Check if any variant already exists
302
- const variants = normalizeIP(ip);
303
- let existingKey: string | null = null;
304
-
305
- for (const variant of variants) {
306
- if (this.connectionsByIP.has(variant)) {
307
- existingKey = variant;
308
- break;
309
- }
310
- }
311
-
312
- const key = existingKey || ip;
313
- if (!this.connectionsByIP.has(key)) {
314
- this.connectionsByIP.set(key, new Set());
315
- }
316
- this.connectionsByIP.get(key)!.add(connectionId);
317
- }
318
-
319
- /**
320
- * Remove connection tracking for an IP
321
- */
322
- public removeConnectionByIP(ip: string, connectionId: string): void {
323
- // Check all variants to find where the connection is tracked
324
- const variants = normalizeIP(ip);
325
-
326
- for (const variant of variants) {
327
- if (this.connectionsByIP.has(variant)) {
328
- const connections = this.connectionsByIP.get(variant)!;
329
- connections.delete(connectionId);
330
- if (connections.size === 0) {
331
- this.connectionsByIP.delete(variant);
332
- }
333
- break;
334
- }
335
- }
336
- }
337
-
338
- /**
339
- * Check if IP should be allowed considering connection rate and max connections
340
- * @returns Object with result and reason
341
- */
342
- public validateIP(ip: string): { allowed: boolean; reason?: string } {
343
- // Check connection count limit
344
- if (this.getConnectionCountByIP(ip) >= this.maxConnectionsPerIP) {
345
- return {
346
- allowed: false,
347
- reason: `Maximum connections per IP (${this.maxConnectionsPerIP}) exceeded`
348
- };
349
- }
350
-
351
- // Check connection rate limit
352
- if (!this.checkConnectionRate(ip)) {
353
- return {
354
- allowed: false,
355
- reason: `Connection rate limit (${this.connectionRateLimitPerMinute}/min) exceeded`
356
- };
357
- }
358
-
359
- return { allowed: true };
360
- }
361
-
362
- /**
363
- * Clears all IP tracking data (for shutdown)
364
- */
365
- public clearIPTracking(): void {
366
- this.connectionsByIP.clear();
367
- this.connectionRateByIP.clear();
368
- }
369
-
370
- /**
371
- * Start periodic cleanup of IP tracking data
372
- */
373
- private startPeriodicIpCleanup(): void {
374
- // Clean up IP tracking data every minute
375
- setInterval(() => {
376
- this.performIpCleanup();
377
- }, 60000).unref();
378
- }
379
-
380
- /**
381
- * Perform cleanup of expired IP data
382
- */
383
- private performIpCleanup(): void {
384
- const now = Date.now();
385
- const minute = 60 * 1000;
386
- let cleanedRateLimits = 0;
387
- let cleanedIPs = 0;
388
-
389
- // Clean up expired rate limit timestamps
390
- for (const [ip, timestamps] of this.connectionRateByIP.entries()) {
391
- const validTimestamps = timestamps.filter((time) => now - time < minute);
392
-
393
- if (validTimestamps.length === 0) {
394
- this.connectionRateByIP.delete(ip);
395
- cleanedRateLimits++;
396
- } else if (validTimestamps.length < timestamps.length) {
397
- this.connectionRateByIP.set(ip, validTimestamps);
398
- }
399
- }
400
-
401
- // Clean up IPs with no active connections
402
- for (const [ip, connections] of this.connectionsByIP.entries()) {
403
- if (connections.size === 0) {
404
- this.connectionsByIP.delete(ip);
405
- cleanedIPs++;
406
- }
407
- }
408
-
409
- if (cleanedRateLimits > 0 || cleanedIPs > 0) {
410
- this.logger.debug(`IP cleanup: removed ${cleanedIPs} IPs and ${cleanedRateLimits} rate limits`);
411
- }
412
- }
413
- }