@push.rocks/smartproxy 19.4.2 → 19.5.2

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 (32) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/proxies/http-proxy/handlers/index.d.ts +1 -2
  3. package/dist_ts/proxies/http-proxy/handlers/index.js +3 -3
  4. package/dist_ts/proxies/smart-proxy/certificate-manager.js +30 -25
  5. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +9 -40
  6. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  7. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -10
  8. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +69 -43
  9. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +2 -2
  10. package/dist_ts/proxies/smart-proxy/utils/index.js +3 -3
  11. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +61 -20
  12. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +240 -45
  13. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +0 -18
  14. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +4 -43
  15. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +14 -15
  16. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +10 -31
  17. package/package.json +7 -7
  18. package/readme.hints.md +38 -1
  19. package/readme.plan.md +314 -382
  20. package/readme.plan2.md +764 -0
  21. package/ts/00_commitinfo_data.ts +1 -1
  22. package/ts/proxies/http-proxy/handlers/index.ts +1 -2
  23. package/ts/proxies/smart-proxy/certificate-manager.ts +29 -23
  24. package/ts/proxies/smart-proxy/models/route-types.ts +12 -56
  25. package/ts/proxies/smart-proxy/route-connection-handler.ts +73 -60
  26. package/ts/proxies/smart-proxy/utils/index.ts +0 -2
  27. package/ts/proxies/smart-proxy/utils/route-helpers.ts +278 -61
  28. package/ts/proxies/smart-proxy/utils/route-patterns.ts +6 -56
  29. package/ts/proxies/smart-proxy/utils/route-utils.ts +12 -15
  30. package/ts/proxies/smart-proxy/utils/route-validators.ts +9 -31
  31. package/ts/proxies/http-proxy/handlers/redirect-handler.ts +0 -105
  32. package/ts/proxies/http-proxy/handlers/static-handler.ts +0 -261
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartproxy',
6
- version: '19.4.2',
6
+ version: '19.5.2',
7
7
  description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
8
8
  }
@@ -2,5 +2,4 @@
2
2
  * HTTP handlers for various route types
3
3
  */
4
4
 
5
- export { RedirectHandler } from './redirect-handler.js';
6
- export { StaticHandler } from './static-handler.js';
5
+ // Empty - all handlers have been removed
@@ -5,6 +5,7 @@ import type { IAcmeOptions } from './models/interfaces.js';
5
5
  import { CertStore } from './cert-store.js';
6
6
  import type { AcmeStateManager } from './acme-state-manager.js';
7
7
  import { logger } from '../../core/utils/logger.js';
8
+ import { SocketHandlers } from './utils/route-helpers.js';
8
9
 
9
10
  export interface ICertStatus {
10
11
  domain: string;
@@ -693,22 +694,24 @@ export class SmartCertManager {
693
694
  path: '/.well-known/acme-challenge/*'
694
695
  },
695
696
  action: {
696
- type: 'static',
697
- handler: async (context) => {
697
+ type: 'socket-handler',
698
+ socketHandler: SocketHandlers.httpServer((req, res) => {
698
699
  // Extract the token from the path
699
- const token = context.path?.split('/').pop();
700
+ const token = req.url?.split('/').pop();
700
701
  if (!token) {
701
- return { status: 404, body: 'Not found' };
702
+ res.status(404);
703
+ res.send('Not found');
704
+ return;
702
705
  }
703
706
 
704
707
  // Create mock request/response objects for SmartAcme
708
+ let responseData: any = null;
705
709
  const mockReq = {
706
- url: context.path,
707
- method: 'GET',
708
- headers: context.headers || {}
710
+ url: req.url,
711
+ method: req.method,
712
+ headers: req.headers
709
713
  };
710
714
 
711
- let responseData: any = null;
712
715
  const mockRes = {
713
716
  statusCode: 200,
714
717
  setHeader: (name: string, value: string) => {},
@@ -718,24 +721,27 @@ export class SmartCertManager {
718
721
  };
719
722
 
720
723
  // Use SmartAcme's handler
721
- const handled = await new Promise<boolean>((resolve) => {
724
+ const handleAcme = () => {
722
725
  http01Handler.handleRequest(mockReq as any, mockRes as any, () => {
723
- resolve(false);
726
+ // Not handled by ACME
727
+ res.status(404);
728
+ res.send('Not found');
724
729
  });
725
- // Give it a moment to process
726
- setTimeout(() => resolve(true), 100);
727
- });
730
+
731
+ // Give it a moment to process, then send response
732
+ setTimeout(() => {
733
+ if (responseData) {
734
+ res.header('Content-Type', 'text/plain');
735
+ res.send(String(responseData));
736
+ } else {
737
+ res.status(404);
738
+ res.send('Not found');
739
+ }
740
+ }, 100);
741
+ };
728
742
 
729
- if (handled && responseData) {
730
- return {
731
- status: mockRes.statusCode,
732
- headers: { 'Content-Type': 'text/plain' },
733
- body: responseData
734
- };
735
- } else {
736
- return { status: 404, body: 'Not found' };
737
- }
738
- }
743
+ handleAcme();
744
+ })
739
745
  }
740
746
  };
741
747
 
@@ -2,11 +2,20 @@ import * as plugins from '../../../plugins.js';
2
2
  // Certificate types removed - use local definition
3
3
  import type { TForwardingType } from '../../../forwarding/config/forwarding-types.js';
4
4
  import type { PortRange } from '../../../proxies/nftables-proxy/models/interfaces.js';
5
+ import type { IRouteContext } from '../../../core/models/route-context.js';
6
+
7
+ // Re-export IRouteContext for convenience
8
+ export type { IRouteContext };
5
9
 
6
10
  /**
7
11
  * Supported action types for route configurations
8
12
  */
9
- export type TRouteActionType = 'forward' | 'redirect' | 'block' | 'static';
13
+ export type TRouteActionType = 'forward' | 'socket-handler';
14
+
15
+ /**
16
+ * Socket handler function type
17
+ */
18
+ export type TSocketHandler = (socket: plugins.net.Socket, context: IRouteContext) => void | Promise<void>;
10
19
 
11
20
  /**
12
21
  * TLS handling modes for route configurations
@@ -35,36 +44,6 @@ export interface IRouteMatch {
35
44
  headers?: Record<string, string | RegExp>; // Match specific HTTP headers
36
45
  }
37
46
 
38
- /**
39
- * Context provided to port and host mapping functions
40
- */
41
- export interface IRouteContext {
42
- // Connection information
43
- port: number; // The matched incoming port
44
- domain?: string; // The domain from SNI or Host header
45
- clientIp: string; // The client's IP address
46
- serverIp: string; // The server's IP address
47
- path?: string; // URL path (for HTTP connections)
48
- query?: string; // Query string (for HTTP connections)
49
- headers?: Record<string, string>; // HTTP headers (for HTTP connections)
50
- method?: string; // HTTP method (for HTTP connections)
51
-
52
- // TLS information
53
- isTls: boolean; // Whether the connection is TLS
54
- tlsVersion?: string; // TLS version if applicable
55
-
56
- // Route information
57
- routeName?: string; // The name of the matched route
58
- routeId?: string; // The ID of the matched route
59
-
60
- // Target information (resolved from dynamic mapping)
61
- targetHost?: string | string[]; // The resolved target host(s)
62
- targetPort?: number; // The resolved target port
63
-
64
- // Additional properties
65
- timestamp: number; // The request timestamp
66
- connectionId: string; // Unique connection identifier
67
- }
68
47
 
69
48
  /**
70
49
  * Target configuration for forwarding
@@ -84,15 +63,6 @@ export interface IRouteAcme {
84
63
  renewBeforeDays?: number; // Days before expiry to renew (default: 30)
85
64
  }
86
65
 
87
- /**
88
- * Static route handler response
89
- */
90
- export interface IStaticResponse {
91
- status: number;
92
- headers?: Record<string, string>;
93
- body: string | Buffer;
94
- }
95
-
96
66
  /**
97
67
  * TLS configuration for route actions
98
68
  */
@@ -112,14 +82,6 @@ export interface IRouteTls {
112
82
  sessionTimeout?: number; // TLS session timeout in seconds
113
83
  }
114
84
 
115
- /**
116
- * Redirect configuration for route actions
117
- */
118
- export interface IRouteRedirect {
119
- to: string; // URL or template with {domain}, {port}, etc.
120
- status: 301 | 302 | 307 | 308;
121
- }
122
-
123
85
  /**
124
86
  * Authentication options
125
87
  */
@@ -265,12 +227,6 @@ export interface IRouteAction {
265
227
  // TLS handling
266
228
  tls?: IRouteTls;
267
229
 
268
- // For redirects
269
- redirect?: IRouteRedirect;
270
-
271
- // For static files
272
- static?: IRouteStaticFiles;
273
-
274
230
  // WebSocket support
275
231
  websocket?: IRouteWebSocket;
276
232
 
@@ -295,8 +251,8 @@ export interface IRouteAction {
295
251
  // NFTables-specific options
296
252
  nftables?: INfTablesOptions;
297
253
 
298
- // Handler function for static routes
299
- handler?: (context: IRouteContext) => Promise<IStaticResponse>;
254
+ // Socket handler function (when type is 'socket-handler')
255
+ socketHandler?: TSocketHandler;
300
256
  }
301
257
 
302
258
  /**
@@ -10,7 +10,6 @@ import { HttpProxyBridge } from './http-proxy-bridge.js';
10
10
  import { TimeoutManager } from './timeout-manager.js';
11
11
  import { RouteManager } from './route-manager.js';
12
12
  import type { ForwardingHandler } from '../../forwarding/handlers/base-handler.js';
13
- import { RedirectHandler, StaticHandler } from '../http-proxy/handlers/index.js';
14
13
 
15
14
  /**
16
15
  * Handles new connection processing and setup logic with support for route-based configuration
@@ -389,14 +388,13 @@ export class RouteConnectionHandler {
389
388
  case 'forward':
390
389
  return this.handleForwardAction(socket, record, route, initialChunk);
391
390
 
392
- case 'redirect':
393
- return this.handleRedirectAction(socket, record, route);
394
-
395
- case 'block':
396
- return this.handleBlockAction(socket, record, route);
397
-
398
- case 'static':
399
- this.handleStaticAction(socket, record, route, initialChunk);
391
+ case 'socket-handler':
392
+ logger.log('info', `Handling socket-handler action for route ${route.name}`, {
393
+ connectionId,
394
+ routeName: route.name,
395
+ component: 'route-handler'
396
+ });
397
+ this.handleSocketHandlerAction(socket, record, route, initialChunk);
400
398
  return;
401
399
 
402
400
  default:
@@ -710,70 +708,85 @@ export class RouteConnectionHandler {
710
708
  }
711
709
 
712
710
  /**
713
- * Handle a redirect action for a route
711
+ * Handle a socket-handler action for a route
714
712
  */
715
- private handleRedirectAction(
713
+ private async handleSocketHandlerAction(
716
714
  socket: plugins.net.Socket,
717
715
  record: IConnectionRecord,
718
- route: IRouteConfig
719
- ): void {
720
- // For TLS connections, we can't do redirects at the TCP level
721
- if (record.isTLS) {
722
- logger.log('warn', `Cannot redirect TLS connection ${record.id} at TCP level`, {
723
- connectionId: record.id,
716
+ route: IRouteConfig,
717
+ initialChunk?: Buffer
718
+ ): Promise<void> {
719
+ const connectionId = record.id;
720
+
721
+ if (!route.action.socketHandler) {
722
+ logger.log('error', 'socket-handler action missing socketHandler function', {
723
+ connectionId,
724
+ routeName: route.name,
724
725
  component: 'route-handler'
725
726
  });
726
- socket.end();
727
- this.connectionManager.cleanupConnection(record, 'tls_redirect_error');
727
+ socket.destroy();
728
+ this.connectionManager.cleanupConnection(record, 'missing_handler');
728
729
  return;
729
730
  }
730
-
731
- // Delegate to HttpProxy's RedirectHandler
732
- RedirectHandler.handleRedirect(socket, route, {
731
+
732
+ // Create route context for the handler
733
+ const routeContext = this.createRouteContext({
733
734
  connectionId: record.id,
734
- connectionManager: this.connectionManager,
735
- settings: this.settings
735
+ port: record.localPort,
736
+ domain: record.lockedDomain,
737
+ clientIp: record.remoteIP,
738
+ serverIp: socket.localAddress || '',
739
+ isTls: record.isTLS || false,
740
+ tlsVersion: record.tlsVersion,
741
+ routeName: route.name,
742
+ routeId: route.id,
736
743
  });
737
- }
738
-
739
- /**
740
- * Handle a block action for a route
741
- */
742
- private handleBlockAction(
743
- socket: plugins.net.Socket,
744
- record: IConnectionRecord,
745
- route: IRouteConfig
746
- ): void {
747
- const connectionId = record.id;
748
-
749
- if (this.settings.enableDetailedLogging) {
750
- logger.log('info', `Blocking connection ${connectionId} based on route '${route.name || 'unnamed'}'`, {
744
+
745
+ try {
746
+ // Call the handler with socket AND context
747
+ const result = route.action.socketHandler(socket, routeContext);
748
+
749
+ // Handle async handlers properly
750
+ if (result instanceof Promise) {
751
+ result
752
+ .then(() => {
753
+ // Emit initial chunk after async handler completes
754
+ if (initialChunk && initialChunk.length > 0) {
755
+ socket.emit('data', initialChunk);
756
+ }
757
+ })
758
+ .catch(error => {
759
+ logger.log('error', 'Socket handler error', {
760
+ connectionId,
761
+ routeName: route.name,
762
+ error: error.message,
763
+ component: 'route-handler'
764
+ });
765
+ if (!socket.destroyed) {
766
+ socket.destroy();
767
+ }
768
+ this.connectionManager.cleanupConnection(record, 'handler_error');
769
+ });
770
+ } else {
771
+ // For sync handlers, emit on next tick
772
+ if (initialChunk && initialChunk.length > 0) {
773
+ process.nextTick(() => {
774
+ socket.emit('data', initialChunk);
775
+ });
776
+ }
777
+ }
778
+ } catch (error) {
779
+ logger.log('error', 'Socket handler error', {
751
780
  connectionId,
752
- routeName: route.name || 'unnamed',
781
+ routeName: route.name,
782
+ error: error.message,
753
783
  component: 'route-handler'
754
784
  });
785
+ if (!socket.destroyed) {
786
+ socket.destroy();
787
+ }
788
+ this.connectionManager.cleanupConnection(record, 'handler_error');
755
789
  }
756
-
757
- // Simply close the connection
758
- socket.end();
759
- this.connectionManager.initiateCleanupOnce(record, 'route_blocked');
760
- }
761
-
762
- /**
763
- * Handle a static action for a route
764
- */
765
- private async handleStaticAction(
766
- socket: plugins.net.Socket,
767
- record: IConnectionRecord,
768
- route: IRouteConfig,
769
- initialChunk?: Buffer
770
- ): Promise<void> {
771
- // Delegate to HttpProxy's StaticHandler
772
- await StaticHandler.handleStatic(socket, route, {
773
- connectionId: record.id,
774
- connectionManager: this.connectionManager,
775
- settings: this.settings
776
- }, record, initialChunk);
777
790
  }
778
791
 
779
792
  /**
@@ -19,7 +19,6 @@ import {
19
19
  createWebSocketRoute as createWebSocketPatternRoute,
20
20
  createLoadBalancerRoute as createLoadBalancerPatternRoute,
21
21
  createApiGatewayRoute,
22
- createStaticFileServerRoute,
23
22
  addRateLimiting,
24
23
  addBasicAuth,
25
24
  addJwtAuth
@@ -29,7 +28,6 @@ export {
29
28
  createWebSocketPatternRoute,
30
29
  createLoadBalancerPatternRoute,
31
30
  createApiGatewayRoute,
32
- createStaticFileServerRoute,
33
31
  addRateLimiting,
34
32
  addBasicAuth,
35
33
  addJwtAuth