@push.rocks/smartproxy 20.0.1 → 21.1.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 (164) hide show
  1. package/changelog.md +26 -0
  2. package/dist_ts/core/utils/proxy-protocol.d.ts +5 -17
  3. package/dist_ts/core/utils/proxy-protocol.js +13 -97
  4. package/dist_ts/core/utils/websocket-utils.d.ts +6 -7
  5. package/dist_ts/core/utils/websocket-utils.js +10 -66
  6. package/dist_ts/detection/detectors/http-detector-v2.d.ts +33 -0
  7. package/dist_ts/detection/detectors/http-detector-v2.js +87 -0
  8. package/dist_ts/detection/detectors/http-detector.d.ts +33 -0
  9. package/dist_ts/detection/detectors/http-detector.js +89 -0
  10. package/dist_ts/detection/detectors/quick-detector.d.ts +28 -0
  11. package/dist_ts/detection/detectors/quick-detector.js +131 -0
  12. package/dist_ts/detection/detectors/routing-extractor.d.ts +28 -0
  13. package/dist_ts/detection/detectors/routing-extractor.js +122 -0
  14. package/dist_ts/detection/detectors/tls-detector-v2.d.ts +33 -0
  15. package/dist_ts/detection/detectors/tls-detector-v2.js +80 -0
  16. package/dist_ts/detection/detectors/tls-detector.d.ts +33 -0
  17. package/dist_ts/detection/detectors/tls-detector.js +106 -0
  18. package/dist_ts/detection/index.d.ts +17 -0
  19. package/dist_ts/detection/index.js +22 -0
  20. package/dist_ts/detection/models/detection-types.d.ts +87 -0
  21. package/dist_ts/detection/models/detection-types.js +5 -0
  22. package/dist_ts/detection/models/interfaces.d.ts +97 -0
  23. package/dist_ts/detection/models/interfaces.js +5 -0
  24. package/dist_ts/detection/protocol-detector-v2.d.ts +46 -0
  25. package/dist_ts/detection/protocol-detector-v2.js +116 -0
  26. package/dist_ts/detection/protocol-detector.d.ts +74 -0
  27. package/dist_ts/detection/protocol-detector.js +173 -0
  28. package/dist_ts/detection/utils/buffer-utils.d.ts +61 -0
  29. package/dist_ts/detection/utils/buffer-utils.js +127 -0
  30. package/dist_ts/detection/utils/fragment-manager.d.ts +31 -0
  31. package/dist_ts/detection/utils/fragment-manager.js +53 -0
  32. package/dist_ts/detection/utils/parser-utils.d.ts +42 -0
  33. package/dist_ts/detection/utils/parser-utils.js +63 -0
  34. package/dist_ts/index.d.ts +2 -1
  35. package/dist_ts/index.js +3 -2
  36. package/dist_ts/protocols/common/fragment-handler.d.ts +73 -0
  37. package/dist_ts/protocols/common/fragment-handler.js +117 -0
  38. package/dist_ts/protocols/common/index.d.ts +7 -0
  39. package/dist_ts/protocols/common/index.js +8 -0
  40. package/dist_ts/protocols/common/types.d.ts +68 -0
  41. package/dist_ts/protocols/common/types.js +7 -0
  42. package/dist_ts/protocols/http/constants.d.ts +119 -0
  43. package/dist_ts/protocols/http/constants.js +200 -0
  44. package/dist_ts/protocols/http/index.d.ts +7 -0
  45. package/dist_ts/protocols/http/index.js +8 -0
  46. package/dist_ts/protocols/http/parser.d.ts +58 -0
  47. package/dist_ts/protocols/http/parser.js +184 -0
  48. package/dist_ts/protocols/http/types.d.ts +62 -0
  49. package/dist_ts/protocols/http/types.js +5 -0
  50. package/dist_ts/protocols/index.d.ts +11 -0
  51. package/dist_ts/protocols/index.js +12 -0
  52. package/dist_ts/protocols/proxy/index.d.ts +6 -0
  53. package/dist_ts/protocols/proxy/index.js +7 -0
  54. package/dist_ts/protocols/proxy/parser.d.ts +44 -0
  55. package/dist_ts/protocols/proxy/parser.js +153 -0
  56. package/dist_ts/protocols/proxy/types.d.ts +47 -0
  57. package/dist_ts/protocols/proxy/types.js +6 -0
  58. package/dist_ts/protocols/tls/alerts/index.d.ts +4 -0
  59. package/dist_ts/protocols/tls/alerts/index.js +5 -0
  60. package/dist_ts/protocols/tls/alerts/tls-alert.d.ts +150 -0
  61. package/dist_ts/protocols/tls/alerts/tls-alert.js +226 -0
  62. package/dist_ts/protocols/tls/constants.d.ts +122 -0
  63. package/dist_ts/protocols/tls/constants.js +135 -0
  64. package/dist_ts/protocols/tls/index.d.ts +12 -0
  65. package/dist_ts/protocols/tls/index.js +27 -0
  66. package/dist_ts/protocols/tls/parser.d.ts +53 -0
  67. package/dist_ts/protocols/tls/parser.js +294 -0
  68. package/dist_ts/protocols/tls/sni/client-hello-parser.d.ts +100 -0
  69. package/dist_ts/protocols/tls/sni/client-hello-parser.js +463 -0
  70. package/dist_ts/protocols/tls/sni/index.d.ts +5 -0
  71. package/dist_ts/protocols/tls/sni/index.js +6 -0
  72. package/dist_ts/protocols/tls/sni/sni-extraction.d.ts +58 -0
  73. package/dist_ts/protocols/tls/sni/sni-extraction.js +275 -0
  74. package/dist_ts/protocols/tls/types.d.ts +65 -0
  75. package/dist_ts/protocols/tls/types.js +5 -0
  76. package/dist_ts/protocols/tls/utils/index.d.ts +4 -0
  77. package/dist_ts/protocols/tls/utils/index.js +5 -0
  78. package/dist_ts/protocols/tls/utils/tls-utils.d.ts +158 -0
  79. package/dist_ts/protocols/tls/utils/tls-utils.js +187 -0
  80. package/dist_ts/protocols/websocket/constants.d.ts +55 -0
  81. package/dist_ts/protocols/websocket/constants.js +58 -0
  82. package/dist_ts/protocols/websocket/index.d.ts +7 -0
  83. package/dist_ts/protocols/websocket/index.js +8 -0
  84. package/dist_ts/protocols/websocket/types.d.ts +47 -0
  85. package/dist_ts/protocols/websocket/types.js +5 -0
  86. package/dist_ts/protocols/websocket/utils.d.ts +25 -0
  87. package/dist_ts/protocols/websocket/utils.js +103 -0
  88. package/dist_ts/proxies/http-proxy/models/http-types.d.ts +25 -27
  89. package/dist_ts/proxies/http-proxy/models/http-types.js +24 -44
  90. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -0
  91. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  92. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +81 -61
  93. package/dist_ts/proxies/smart-proxy/tls-manager.js +2 -1
  94. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -2
  95. package/dist_ts/proxies/smart-proxy/utils/index.js +3 -4
  96. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +112 -8
  97. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +231 -76
  98. package/dist_ts/tls/index.d.ts +5 -7
  99. package/dist_ts/tls/index.js +8 -11
  100. package/dist_ts/tls/sni/client-hello-parser.js +3 -2
  101. package/dist_ts/tls/sni/sni-handler.js +4 -4
  102. package/dist_ts/tls/utils/tls-utils.d.ts +1 -110
  103. package/dist_ts/tls/utils/tls-utils.js +4 -116
  104. package/package.json +17 -8
  105. package/readme.md +471 -2345
  106. package/readme.plan.md +0 -0
  107. package/ts/core/utils/proxy-protocol.ts +14 -131
  108. package/ts/core/utils/websocket-utils.ts +12 -60
  109. package/ts/detection/detectors/http-detector.ts +114 -0
  110. package/ts/detection/detectors/quick-detector.ts +148 -0
  111. package/ts/detection/detectors/routing-extractor.ts +147 -0
  112. package/ts/detection/detectors/tls-detector.ts +120 -0
  113. package/ts/detection/index.ts +25 -0
  114. package/ts/detection/models/detection-types.ts +102 -0
  115. package/ts/detection/models/interfaces.ts +115 -0
  116. package/ts/detection/protocol-detector.ts +230 -0
  117. package/ts/detection/utils/buffer-utils.ts +141 -0
  118. package/ts/detection/utils/fragment-manager.ts +64 -0
  119. package/ts/detection/utils/parser-utils.ts +77 -0
  120. package/ts/index.ts +3 -2
  121. package/ts/protocols/common/fragment-handler.ts +163 -0
  122. package/ts/protocols/common/index.ts +8 -0
  123. package/ts/protocols/common/types.ts +76 -0
  124. package/ts/protocols/http/constants.ts +219 -0
  125. package/ts/protocols/http/index.ts +8 -0
  126. package/ts/protocols/http/parser.ts +219 -0
  127. package/ts/protocols/http/types.ts +70 -0
  128. package/ts/protocols/index.ts +12 -0
  129. package/ts/protocols/proxy/index.ts +7 -0
  130. package/ts/protocols/proxy/parser.ts +183 -0
  131. package/ts/protocols/proxy/types.ts +53 -0
  132. package/ts/{tls → protocols/tls}/alerts/tls-alert.ts +1 -1
  133. package/ts/protocols/tls/index.ts +37 -0
  134. package/ts/protocols/tls/sni/index.ts +6 -0
  135. package/ts/{tls → protocols/tls}/utils/tls-utils.ts +1 -1
  136. package/ts/protocols/websocket/constants.ts +60 -0
  137. package/ts/protocols/websocket/index.ts +8 -0
  138. package/ts/protocols/websocket/types.ts +53 -0
  139. package/ts/protocols/websocket/utils.ts +98 -0
  140. package/ts/proxies/http-proxy/models/http-types.ts +29 -46
  141. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -1
  142. package/ts/proxies/smart-proxy/models/route-types.ts +0 -1
  143. package/ts/proxies/smart-proxy/route-connection-handler.ts +91 -68
  144. package/ts/proxies/smart-proxy/tls-manager.ts +1 -0
  145. package/ts/proxies/smart-proxy/utils/index.ts +2 -13
  146. package/ts/proxies/smart-proxy/utils/route-helpers.ts +323 -86
  147. package/ts/tls/index.ts +8 -12
  148. package/ts/tls/sni/sni-handler.ts +3 -3
  149. package/ts/forwarding/config/forwarding-types.ts +0 -76
  150. package/ts/forwarding/config/index.ts +0 -26
  151. package/ts/forwarding/factory/forwarding-factory.ts +0 -189
  152. package/ts/forwarding/factory/index.ts +0 -5
  153. package/ts/forwarding/handlers/base-handler.ts +0 -155
  154. package/ts/forwarding/handlers/http-handler.ts +0 -163
  155. package/ts/forwarding/handlers/https-passthrough-handler.ts +0 -185
  156. package/ts/forwarding/handlers/https-terminate-to-http-handler.ts +0 -312
  157. package/ts/forwarding/handlers/https-terminate-to-https-handler.ts +0 -297
  158. package/ts/forwarding/handlers/index.ts +0 -9
  159. package/ts/forwarding/index.ts +0 -35
  160. package/ts/proxies/smart-proxy/utils/route-patterns.ts +0 -403
  161. /package/ts/{tls → protocols/tls}/alerts/index.ts +0 -0
  162. /package/ts/{tls → protocols/tls}/sni/client-hello-parser.ts +0 -0
  163. /package/ts/{tls → protocols/tls}/sni/sni-extraction.ts +0 -0
  164. /package/ts/{tls → protocols/tls}/utils/index.ts +0 -0
@@ -20,6 +20,8 @@
20
20
 
21
21
  import * as plugins from '../../../plugins.js';
22
22
  import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget, TPortRange, IRouteContext } from '../models/route-types.js';
23
+ import { mergeRouteConfigs } from './route-utils.js';
24
+ import { ProtocolDetector, HttpDetector } from '../../../detection/index.js';
23
25
 
24
26
  /**
25
27
  * Create an HTTP-only route configuration
@@ -211,26 +213,62 @@ export function createCompleteHttpsServer(
211
213
  /**
212
214
  * Create a load balancer route (round-robin between multiple backend hosts)
213
215
  * @param domains Domain(s) to match
214
- * @param hosts Array of backend hosts to load balance between
215
- * @param port Backend port
216
- * @param options Additional route options
216
+ * @param backendsOrHosts Array of backend servers OR array of host strings (legacy)
217
+ * @param portOrOptions Port number (legacy) OR options object
218
+ * @param options Additional route options (legacy)
217
219
  * @returns Route configuration object
218
220
  */
219
221
  export function createLoadBalancerRoute(
220
222
  domains: string | string[],
221
- hosts: string[],
222
- port: number,
223
- options: {
223
+ backendsOrHosts: Array<{ host: string; port: number }> | string[],
224
+ portOrOptions?: number | {
224
225
  tls?: {
225
226
  mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt';
226
227
  certificate?: 'auto' | { key: string; cert: string };
227
228
  };
229
+ useTls?: boolean;
230
+ certificate?: 'auto' | { key: string; cert: string };
231
+ algorithm?: 'round-robin' | 'least-connections' | 'ip-hash';
232
+ healthCheck?: {
233
+ path: string;
234
+ interval: number;
235
+ timeout: number;
236
+ unhealthyThreshold: number;
237
+ healthyThreshold: number;
238
+ };
228
239
  [key: string]: any;
229
- } = {}
240
+ },
241
+ options?: {
242
+ tls?: {
243
+ mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt';
244
+ certificate?: 'auto' | { key: string; cert: string };
245
+ };
246
+ [key: string]: any;
247
+ }
230
248
  ): IRouteConfig {
249
+ // Handle legacy signature: (domains, hosts[], port, options)
250
+ let backends: Array<{ host: string; port: number }>;
251
+ let finalOptions: any;
252
+
253
+ if (Array.isArray(backendsOrHosts) && backendsOrHosts.length > 0 && typeof backendsOrHosts[0] === 'string') {
254
+ // Legacy signature
255
+ const hosts = backendsOrHosts as string[];
256
+ const port = portOrOptions as number;
257
+ backends = hosts.map(host => ({ host, port }));
258
+ finalOptions = options || {};
259
+ } else {
260
+ // New signature
261
+ backends = backendsOrHosts as Array<{ host: string; port: number }>;
262
+ finalOptions = (portOrOptions as any) || {};
263
+ }
264
+
265
+ // Extract hosts and ensure all backends use the same port
266
+ const port = backends[0].port;
267
+ const hosts = backends.map(backend => backend.host);
268
+
231
269
  // Create route match
232
270
  const match: IRouteMatch = {
233
- ports: options.match?.ports || (options.tls ? 443 : 80),
271
+ ports: finalOptions.match?.ports || (finalOptions.tls || finalOptions.useTls ? 443 : 80),
234
272
  domains
235
273
  };
236
274
 
@@ -247,10 +285,18 @@ export function createLoadBalancerRoute(
247
285
  };
248
286
 
249
287
  // Add TLS configuration if provided
250
- if (options.tls) {
288
+ if (finalOptions.tls || finalOptions.useTls) {
251
289
  action.tls = {
252
- mode: options.tls.mode,
253
- certificate: options.tls.certificate || 'auto'
290
+ mode: finalOptions.tls?.mode || 'terminate',
291
+ certificate: finalOptions.tls?.certificate || finalOptions.certificate || 'auto'
292
+ };
293
+ }
294
+
295
+ // Add load balancing options
296
+ if (finalOptions.algorithm || finalOptions.healthCheck) {
297
+ action.loadBalancing = {
298
+ algorithm: finalOptions.algorithm || 'round-robin',
299
+ healthCheck: finalOptions.healthCheck
254
300
  };
255
301
  }
256
302
 
@@ -258,8 +304,8 @@ export function createLoadBalancerRoute(
258
304
  return {
259
305
  match,
260
306
  action,
261
- name: options.name || `Load Balancer for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
262
- ...options
307
+ name: finalOptions.name || `Load Balancer for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
308
+ ...finalOptions
263
309
  };
264
310
  }
265
311
 
@@ -339,34 +385,61 @@ export function createApiRoute(
339
385
  /**
340
386
  * Create a WebSocket route configuration
341
387
  * @param domains Domain(s) to match
342
- * @param wsPath WebSocket path (e.g., "/ws")
343
- * @param target Target WebSocket server host and port
344
- * @param options Additional route options
388
+ * @param targetOrPath Target server OR WebSocket path (legacy)
389
+ * @param targetOrOptions Target server (legacy) OR options
390
+ * @param options Additional route options (legacy)
345
391
  * @returns Route configuration object
346
392
  */
347
393
  export function createWebSocketRoute(
348
394
  domains: string | string[],
349
- wsPath: string,
350
- target: { host: string | string[]; port: number },
351
- options: {
395
+ targetOrPath: { host: string | string[]; port: number } | string,
396
+ targetOrOptions?: { host: string | string[]; port: number } | {
352
397
  useTls?: boolean;
353
398
  certificate?: 'auto' | { key: string; cert: string };
399
+ path?: string;
354
400
  httpPort?: number | number[];
355
401
  httpsPort?: number | number[];
356
402
  pingInterval?: number;
357
403
  pingTimeout?: number;
358
404
  name?: string;
359
405
  [key: string]: any;
360
- } = {}
406
+ },
407
+ options?: {
408
+ useTls?: boolean;
409
+ certificate?: 'auto' | { key: string; cert: string };
410
+ httpPort?: number | number[];
411
+ httpsPort?: number | number[];
412
+ pingInterval?: number;
413
+ pingTimeout?: number;
414
+ name?: string;
415
+ [key: string]: any;
416
+ }
361
417
  ): IRouteConfig {
418
+ // Handle different signatures
419
+ let target: { host: string | string[]; port: number };
420
+ let wsPath: string;
421
+ let finalOptions: any;
422
+
423
+ if (typeof targetOrPath === 'string') {
424
+ // Legacy signature: (domains, path, target, options)
425
+ wsPath = targetOrPath;
426
+ target = targetOrOptions as { host: string | string[]; port: number };
427
+ finalOptions = options || {};
428
+ } else {
429
+ // New signature: (domains, target, options)
430
+ target = targetOrPath;
431
+ finalOptions = (targetOrOptions as any) || {};
432
+ wsPath = finalOptions.path || '/ws';
433
+ }
434
+
362
435
  // Normalize WebSocket path
363
436
  const normalizedPath = wsPath.startsWith('/') ? wsPath : `/${wsPath}`;
364
437
 
365
438
  // Create route match
366
439
  const match: IRouteMatch = {
367
- ports: options.useTls
368
- ? (options.httpsPort || 443)
369
- : (options.httpPort || 80),
440
+ ports: finalOptions.useTls
441
+ ? (finalOptions.httpsPort || 443)
442
+ : (finalOptions.httpPort || 80),
370
443
  domains,
371
444
  path: normalizedPath
372
445
  };
@@ -377,16 +450,16 @@ export function createWebSocketRoute(
377
450
  targets: [target],
378
451
  websocket: {
379
452
  enabled: true,
380
- pingInterval: options.pingInterval || 30000, // 30 seconds
381
- pingTimeout: options.pingTimeout || 5000 // 5 seconds
453
+ pingInterval: finalOptions.pingInterval || 30000, // 30 seconds
454
+ pingTimeout: finalOptions.pingTimeout || 5000 // 5 seconds
382
455
  }
383
456
  };
384
457
 
385
458
  // Add TLS configuration if using HTTPS
386
- if (options.useTls) {
459
+ if (finalOptions.useTls) {
387
460
  action.tls = {
388
461
  mode: 'terminate',
389
- certificate: options.certificate || 'auto'
462
+ certificate: finalOptions.certificate || 'auto'
390
463
  };
391
464
  }
392
465
 
@@ -394,9 +467,9 @@ export function createWebSocketRoute(
394
467
  return {
395
468
  match,
396
469
  action,
397
- name: options.name || `WebSocket Route ${normalizedPath} for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
398
- priority: options.priority || 100, // Higher priority for WebSocket routes
399
- ...options
470
+ name: finalOptions.name || `WebSocket Route ${normalizedPath} for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
471
+ priority: finalOptions.priority || 100, // Higher priority for WebSocket routes
472
+ ...finalOptions
400
473
  };
401
474
  }
402
475
 
@@ -884,83 +957,91 @@ export const SocketHandlers = {
884
957
 
885
958
  /**
886
959
  * HTTP redirect handler
960
+ * Now uses the centralized detection module for HTTP parsing
887
961
  */
888
962
  httpRedirect: (locationTemplate: string, statusCode: number = 301) => (socket: plugins.net.Socket, context: IRouteContext) => {
889
- let buffer = '';
963
+ const connectionId = ProtocolDetector.createConnectionId({
964
+ socketId: context.connectionId || `${Date.now()}-${Math.random()}`
965
+ });
890
966
 
891
- socket.once('data', (data) => {
892
- buffer += data.toString();
893
-
894
- const lines = buffer.split('\r\n');
895
- const requestLine = lines[0];
896
- const [method, path] = requestLine.split(' ');
897
-
898
- const domain = context.domain || 'localhost';
899
- const port = context.port;
967
+ socket.once('data', async (data) => {
968
+ // Use detection module for parsing
969
+ const detectionResult = await ProtocolDetector.detectWithConnectionTracking(
970
+ data,
971
+ connectionId,
972
+ { extractFullHeaders: false } // We only need method and path
973
+ );
900
974
 
901
- let finalLocation = locationTemplate
902
- .replace('{domain}', domain)
903
- .replace('{port}', String(port))
904
- .replace('{path}', path)
905
- .replace('{clientIp}', context.clientIp);
906
-
907
- const message = `Redirecting to ${finalLocation}`;
908
- const response = [
909
- `HTTP/1.1 ${statusCode} ${statusCode === 301 ? 'Moved Permanently' : 'Found'}`,
910
- `Location: ${finalLocation}`,
911
- 'Content-Type: text/plain',
912
- `Content-Length: ${message.length}`,
913
- 'Connection: close',
914
- '',
915
- message
916
- ].join('\r\n');
975
+ if (detectionResult.protocol === 'http' && detectionResult.connectionInfo.path) {
976
+ const method = detectionResult.connectionInfo.method || 'GET';
977
+ const path = detectionResult.connectionInfo.path || '/';
978
+
979
+ const domain = context.domain || 'localhost';
980
+ const port = context.port;
981
+
982
+ let finalLocation = locationTemplate
983
+ .replace('{domain}', domain)
984
+ .replace('{port}', String(port))
985
+ .replace('{path}', path)
986
+ .replace('{clientIp}', context.clientIp);
987
+
988
+ const message = `Redirecting to ${finalLocation}`;
989
+ const response = [
990
+ `HTTP/1.1 ${statusCode} ${statusCode === 301 ? 'Moved Permanently' : 'Found'}`,
991
+ `Location: ${finalLocation}`,
992
+ 'Content-Type: text/plain',
993
+ `Content-Length: ${message.length}`,
994
+ 'Connection: close',
995
+ '',
996
+ message
997
+ ].join('\r\n');
998
+
999
+ socket.write(response);
1000
+ } else {
1001
+ // Not a valid HTTP request, close connection
1002
+ socket.write('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n');
1003
+ }
917
1004
 
918
- socket.write(response);
919
1005
  socket.end();
1006
+ // Clean up detection state
1007
+ ProtocolDetector.cleanupConnections();
920
1008
  });
921
1009
  },
922
1010
 
923
1011
  /**
924
1012
  * HTTP server handler for ACME challenges and other HTTP needs
1013
+ * Now uses the centralized detection module for HTTP parsing
925
1014
  */
926
1015
  httpServer: (handler: (req: { method: string; url: string; headers: Record<string, string>; body?: string }, res: { status: (code: number) => void; header: (name: string, value: string) => void; send: (data: string) => void; end: () => void }) => void) => (socket: plugins.net.Socket, context: IRouteContext) => {
927
- let buffer = '';
928
1016
  let requestParsed = false;
1017
+ const connectionId = ProtocolDetector.createConnectionId({
1018
+ socketId: context.connectionId || `${Date.now()}-${Math.random()}`
1019
+ });
929
1020
 
930
- socket.on('data', (data) => {
1021
+ const processData = async (data: Buffer) => {
931
1022
  if (requestParsed) return; // Only handle the first request
932
1023
 
933
- buffer += data.toString();
1024
+ // Use HttpDetector for parsing
1025
+ const detectionResult = await ProtocolDetector.detectWithConnectionTracking(
1026
+ data,
1027
+ connectionId,
1028
+ { extractFullHeaders: true }
1029
+ );
934
1030
 
935
- // Check if we have a complete HTTP request
936
- const headerEndIndex = buffer.indexOf('\r\n\r\n');
937
- if (headerEndIndex === -1) return; // Need more data
1031
+ if (detectionResult.protocol !== 'http' || !detectionResult.isComplete) {
1032
+ // Not a complete HTTP request yet
1033
+ return;
1034
+ }
938
1035
 
939
1036
  requestParsed = true;
1037
+ const connInfo = detectionResult.connectionInfo;
940
1038
 
941
- // Parse the HTTP request
942
- const headerPart = buffer.substring(0, headerEndIndex);
943
- const bodyPart = buffer.substring(headerEndIndex + 4);
944
-
945
- const lines = headerPart.split('\r\n');
946
- const [method, url] = lines[0].split(' ');
947
-
948
- const headers: Record<string, string> = {};
949
- for (let i = 1; i < lines.length; i++) {
950
- const colonIndex = lines[i].indexOf(':');
951
- if (colonIndex > 0) {
952
- const name = lines[i].substring(0, colonIndex).trim().toLowerCase();
953
- const value = lines[i].substring(colonIndex + 1).trim();
954
- headers[name] = value;
955
- }
956
- }
957
-
958
- // Create request object
1039
+ // Create request object from detection result
959
1040
  const req = {
960
- method: method || 'GET',
961
- url: url || '/',
962
- headers,
963
- body: bodyPart
1041
+ method: connInfo.method || 'GET',
1042
+ url: connInfo.path || '/',
1043
+ headers: connInfo.headers || {},
1044
+ body: detectionResult.remainingBuffer?.toString() || ''
964
1045
  };
965
1046
 
966
1047
  // Create response object
@@ -1021,12 +1102,168 @@ export const SocketHandlers = {
1021
1102
  res.send('Internal Server Error');
1022
1103
  }
1023
1104
  }
1024
- });
1105
+ };
1106
+
1107
+ socket.on('data', processData);
1025
1108
 
1026
1109
  socket.on('error', () => {
1027
1110
  if (!requestParsed) {
1028
1111
  socket.end();
1029
1112
  }
1030
1113
  });
1114
+
1115
+ socket.on('close', () => {
1116
+ // Clean up detection state
1117
+ ProtocolDetector.cleanupConnections();
1118
+ });
1031
1119
  }
1032
1120
  };
1121
+
1122
+ /**
1123
+ * Create an API Gateway route pattern
1124
+ * @param domains Domain(s) to match
1125
+ * @param apiBasePath Base path for API endpoints (e.g., '/api')
1126
+ * @param target Target host and port
1127
+ * @param options Additional route options
1128
+ * @returns API route configuration
1129
+ */
1130
+ export function createApiGatewayRoute(
1131
+ domains: string | string[],
1132
+ apiBasePath: string,
1133
+ target: { host: string | string[]; port: number },
1134
+ options: {
1135
+ useTls?: boolean;
1136
+ certificate?: 'auto' | { key: string; cert: string };
1137
+ addCorsHeaders?: boolean;
1138
+ [key: string]: any;
1139
+ } = {}
1140
+ ): IRouteConfig {
1141
+ // Normalize apiBasePath to ensure it starts with / and doesn't end with /
1142
+ const normalizedPath = apiBasePath.startsWith('/')
1143
+ ? apiBasePath
1144
+ : `/${apiBasePath}`;
1145
+
1146
+ // Add wildcard to path to match all API endpoints
1147
+ const apiPath = normalizedPath.endsWith('/')
1148
+ ? `${normalizedPath}*`
1149
+ : `${normalizedPath}/*`;
1150
+
1151
+ // Create base route
1152
+ const baseRoute = options.useTls
1153
+ ? createHttpsTerminateRoute(domains, target, {
1154
+ certificate: options.certificate || 'auto'
1155
+ })
1156
+ : createHttpRoute(domains, target);
1157
+
1158
+ // Add API-specific configurations
1159
+ const apiRoute: Partial<IRouteConfig> = {
1160
+ match: {
1161
+ ...baseRoute.match,
1162
+ path: apiPath
1163
+ },
1164
+ name: options.name || `API Gateway: ${apiPath} -> ${Array.isArray(target.host) ? target.host.join(', ') : target.host}:${target.port}`,
1165
+ priority: options.priority || 100 // Higher priority for specific path matching
1166
+ };
1167
+
1168
+ // Add CORS headers if requested
1169
+ if (options.addCorsHeaders) {
1170
+ apiRoute.headers = {
1171
+ response: {
1172
+ 'Access-Control-Allow-Origin': '*',
1173
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
1174
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
1175
+ 'Access-Control-Max-Age': '86400'
1176
+ }
1177
+ };
1178
+ }
1179
+
1180
+ return mergeRouteConfigs(baseRoute, apiRoute);
1181
+ }
1182
+
1183
+ /**
1184
+ * Create a rate limiting route pattern
1185
+ * @param baseRoute Base route to add rate limiting to
1186
+ * @param rateLimit Rate limiting configuration
1187
+ * @returns Route with rate limiting
1188
+ */
1189
+ export function addRateLimiting(
1190
+ baseRoute: IRouteConfig,
1191
+ rateLimit: {
1192
+ maxRequests: number;
1193
+ window: number; // Time window in seconds
1194
+ keyBy?: 'ip' | 'path' | 'header';
1195
+ headerName?: string; // Required if keyBy is 'header'
1196
+ errorMessage?: string;
1197
+ }
1198
+ ): IRouteConfig {
1199
+ return mergeRouteConfigs(baseRoute, {
1200
+ security: {
1201
+ rateLimit: {
1202
+ enabled: true,
1203
+ maxRequests: rateLimit.maxRequests,
1204
+ window: rateLimit.window,
1205
+ keyBy: rateLimit.keyBy || 'ip',
1206
+ headerName: rateLimit.headerName,
1207
+ errorMessage: rateLimit.errorMessage || 'Rate limit exceeded. Please try again later.'
1208
+ }
1209
+ }
1210
+ });
1211
+ }
1212
+
1213
+ /**
1214
+ * Create a basic authentication route pattern
1215
+ * @param baseRoute Base route to add authentication to
1216
+ * @param auth Authentication configuration
1217
+ * @returns Route with basic authentication
1218
+ */
1219
+ export function addBasicAuth(
1220
+ baseRoute: IRouteConfig,
1221
+ auth: {
1222
+ users: Array<{ username: string; password: string }>;
1223
+ realm?: string;
1224
+ excludePaths?: string[];
1225
+ }
1226
+ ): IRouteConfig {
1227
+ return mergeRouteConfigs(baseRoute, {
1228
+ security: {
1229
+ basicAuth: {
1230
+ enabled: true,
1231
+ users: auth.users,
1232
+ realm: auth.realm || 'Restricted Area',
1233
+ excludePaths: auth.excludePaths || []
1234
+ }
1235
+ }
1236
+ });
1237
+ }
1238
+
1239
+ /**
1240
+ * Create a JWT authentication route pattern
1241
+ * @param baseRoute Base route to add JWT authentication to
1242
+ * @param jwt JWT authentication configuration
1243
+ * @returns Route with JWT authentication
1244
+ */
1245
+ export function addJwtAuth(
1246
+ baseRoute: IRouteConfig,
1247
+ jwt: {
1248
+ secret: string;
1249
+ algorithm?: string;
1250
+ issuer?: string;
1251
+ audience?: string;
1252
+ expiresIn?: number; // Time in seconds
1253
+ excludePaths?: string[];
1254
+ }
1255
+ ): IRouteConfig {
1256
+ return mergeRouteConfigs(baseRoute, {
1257
+ security: {
1258
+ jwtAuth: {
1259
+ enabled: true,
1260
+ secret: jwt.secret,
1261
+ algorithm: jwt.algorithm || 'HS256',
1262
+ issuer: jwt.issuer,
1263
+ audience: jwt.audience,
1264
+ expiresIn: jwt.expiresIn,
1265
+ excludePaths: jwt.excludePaths || []
1266
+ }
1267
+ }
1268
+ });
1269
+ }
package/ts/tls/index.ts CHANGED
@@ -1,22 +1,18 @@
1
1
  /**
2
- * TLS module providing SNI extraction, TLS alerts, and other TLS-related utilities
2
+ * TLS module for smartproxy
3
+ * Re-exports protocol components and provides smartproxy-specific functionality
3
4
  */
4
5
 
5
- // Export TLS alert functionality
6
- export * from './alerts/tls-alert.js';
6
+ // Re-export all protocol components from protocols/tls
7
+ export * from '../protocols/tls/index.js';
7
8
 
8
- // Export SNI handling
9
+ // Export smartproxy-specific SNI handler
9
10
  export * from './sni/sni-handler.js';
10
- export * from './sni/sni-extraction.js';
11
- export * from './sni/client-hello-parser.js';
12
-
13
- // Export TLS utilities
14
- export * from './utils/tls-utils.js';
15
11
 
16
12
  // Create a namespace for SNI utilities
17
13
  import { SniHandler } from './sni/sni-handler.js';
18
- import { SniExtraction } from './sni/sni-extraction.js';
19
- import { ClientHelloParser } from './sni/client-hello-parser.js';
14
+ import { SniExtraction } from '../protocols/tls/sni/sni-extraction.js';
15
+ import { ClientHelloParser } from '../protocols/tls/sni/client-hello-parser.js';
20
16
 
21
17
  // Export utility objects for convenience
22
18
  export const SNI = {
@@ -30,4 +26,4 @@ export const SNI = {
30
26
  // Convenience functions
31
27
  extractSNI: SniHandler.extractSNI,
32
28
  processTlsPacket: SniHandler.processTlsPacket,
33
- };
29
+ };
@@ -4,15 +4,15 @@ import {
4
4
  TlsHandshakeType,
5
5
  TlsExtensionType,
6
6
  TlsUtils
7
- } from '../utils/tls-utils.js';
7
+ } from '../../protocols/tls/utils/tls-utils.js';
8
8
  import {
9
9
  ClientHelloParser,
10
10
  type LoggerFunction
11
- } from './client-hello-parser.js';
11
+ } from '../../protocols/tls/sni/client-hello-parser.js';
12
12
  import {
13
13
  SniExtraction,
14
14
  type ConnectionInfo
15
- } from './sni-extraction.js';
15
+ } from '../../protocols/tls/sni/sni-extraction.js';
16
16
 
17
17
  /**
18
18
  * SNI (Server Name Indication) handler for TLS connections.
@@ -1,76 +0,0 @@
1
- import type * as plugins from '../../plugins.js';
2
-
3
- /**
4
- * The primary forwarding types supported by SmartProxy
5
- * Used for configuration compatibility
6
- */
7
- export type TForwardingType =
8
- | 'http-only' // HTTP forwarding only (no HTTPS)
9
- | 'https-passthrough' // Pass-through TLS traffic (SNI forwarding)
10
- | 'https-terminate-to-http' // Terminate TLS and forward to HTTP backend
11
- | 'https-terminate-to-https'; // Terminate TLS and forward to HTTPS backend
12
-
13
- /**
14
- * Event types emitted by forwarding handlers
15
- */
16
- export enum ForwardingHandlerEvents {
17
- CONNECTED = 'connected',
18
- DISCONNECTED = 'disconnected',
19
- ERROR = 'error',
20
- DATA_FORWARDED = 'data-forwarded',
21
- HTTP_REQUEST = 'http-request',
22
- HTTP_RESPONSE = 'http-response',
23
- CERTIFICATE_NEEDED = 'certificate-needed',
24
- CERTIFICATE_LOADED = 'certificate-loaded'
25
- }
26
-
27
- /**
28
- * Base interface for forwarding handlers
29
- */
30
- export interface IForwardingHandler extends plugins.EventEmitter {
31
- initialize(): Promise<void>;
32
- handleConnection(socket: plugins.net.Socket): void;
33
- handleHttpRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void;
34
- }
35
-
36
- // Route-based helpers are now available directly from route-patterns.ts
37
- import {
38
- createHttpRoute,
39
- createHttpsTerminateRoute,
40
- createHttpsPassthroughRoute,
41
- createHttpToHttpsRedirect,
42
- createCompleteHttpsServer,
43
- createLoadBalancerRoute
44
- } from '../../proxies/smart-proxy/utils/route-patterns.js';
45
-
46
- export {
47
- createHttpRoute,
48
- createHttpsTerminateRoute,
49
- createHttpsPassthroughRoute,
50
- createHttpToHttpsRedirect,
51
- createCompleteHttpsServer,
52
- createLoadBalancerRoute
53
- };
54
-
55
- // Note: Legacy helper functions have been removed
56
- // Please use the route-based helpers instead:
57
- // - createHttpRoute
58
- // - createHttpsTerminateRoute
59
- // - createHttpsPassthroughRoute
60
- // - createHttpToHttpsRedirect
61
- import type { IRouteConfig } from '../../proxies/smart-proxy/models/route-types.js';
62
-
63
- // For backward compatibility, kept only the basic configuration interface
64
- export interface IForwardConfig {
65
- type: TForwardingType;
66
- target: {
67
- host: string | string[];
68
- port: number | 'preserve' | ((ctx: any) => number);
69
- };
70
- http?: any;
71
- https?: any;
72
- acme?: any;
73
- security?: any;
74
- advanced?: any;
75
- [key: string]: any;
76
- }