import * as plugins from '../../plugins.js'; import { NetworkProxy } from '../network-proxy/index.js'; import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js'; import type { IRouteConfig } from './models/route-types.js'; export class NetworkProxyBridge { private networkProxy: NetworkProxy | null = null; constructor(private settings: ISmartProxyOptions) {} /** * Get the NetworkProxy instance */ public getNetworkProxy(): NetworkProxy | null { return this.networkProxy; } /** * Initialize NetworkProxy instance */ public async initialize(): Promise { if (!this.networkProxy && this.settings.useNetworkProxy && this.settings.useNetworkProxy.length > 0) { const networkProxyOptions: any = { port: this.settings.networkProxyPort!, portProxyIntegration: true, logLevel: this.settings.enableDetailedLogging ? 'debug' : 'info' }; this.networkProxy = new NetworkProxy(networkProxyOptions); console.log(`Initialized NetworkProxy on port ${this.settings.networkProxyPort}`); // Apply route configurations to NetworkProxy await this.syncRoutesToNetworkProxy(this.settings.routes || []); } } /** * Sync routes to NetworkProxy */ public async syncRoutesToNetworkProxy(routes: IRouteConfig[]): Promise { if (!this.networkProxy) return; // Convert routes to NetworkProxy format const networkProxyConfigs = routes .filter(route => { // Check if this route matches any of the specified network proxy ports const routePorts = Array.isArray(route.match.ports) ? route.match.ports : [route.match.ports]; return routePorts.some(port => this.settings.useNetworkProxy?.includes(port) ); }) .map(route => this.routeToNetworkProxyConfig(route)); // Apply configurations to NetworkProxy await this.networkProxy.updateRouteConfigs(networkProxyConfigs); } /** * Convert route to NetworkProxy configuration */ private routeToNetworkProxyConfig(route: IRouteConfig): any { // Convert route to NetworkProxy domain config format return { domain: route.match.domains?.[0] || '*', target: route.action.target, tls: route.action.tls, security: route.action.security }; } /** * Check if connection should use NetworkProxy */ public shouldUseNetworkProxy(connection: IConnectionRecord, routeMatch: any): boolean { // Only use NetworkProxy for TLS termination return ( routeMatch.route.action.tls?.mode === 'terminate' || routeMatch.route.action.tls?.mode === 'terminate-and-reencrypt' ) && this.networkProxy !== null; } /** * Forward connection to NetworkProxy */ public async forwardToNetworkProxy( connectionId: string, socket: plugins.net.Socket, record: IConnectionRecord, initialChunk: Buffer, networkProxyPort: number, cleanupCallback: (reason: string) => void ): Promise { if (!this.networkProxy) { throw new Error('NetworkProxy not initialized'); } const proxySocket = new plugins.net.Socket(); await new Promise((resolve, reject) => { proxySocket.connect(networkProxyPort, 'localhost', () => { console.log(`[${connectionId}] Connected to NetworkProxy for termination`); resolve(); }); proxySocket.on('error', reject); }); // Send initial chunk if present if (initialChunk) { proxySocket.write(initialChunk); } // Pipe the sockets together socket.pipe(proxySocket); proxySocket.pipe(socket); // Handle cleanup const cleanup = (reason: string) => { socket.unpipe(proxySocket); proxySocket.unpipe(socket); proxySocket.destroy(); cleanupCallback(reason); }; socket.on('end', () => cleanup('socket_end')); socket.on('error', () => cleanup('socket_error')); proxySocket.on('end', () => cleanup('proxy_end')); proxySocket.on('error', () => cleanup('proxy_error')); } /** * Start NetworkProxy */ public async start(): Promise { if (this.networkProxy) { await this.networkProxy.start(); } } /** * Stop NetworkProxy */ public async stop(): Promise { if (this.networkProxy) { await this.networkProxy.stop(); this.networkProxy = null; } } }