fix(certificate-manager, smart-proxy): Fix race condition in ACME certificate provisioning and refactor certificate manager initialization to defer provisioning until after port listeners are active
This commit is contained in:
		| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@push.rocks/smartproxy', | ||||
|   version: '19.3.9', | ||||
|   version: '19.3.10', | ||||
|   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.' | ||||
| } | ||||
|   | ||||
| @@ -24,7 +24,8 @@ export class StaticHandler { | ||||
|     socket: plugins.net.Socket, | ||||
|     route: IRouteConfig, | ||||
|     context: IStaticHandlerContext, | ||||
|     record: IConnectionRecord | ||||
|     record: IConnectionRecord, | ||||
|     initialChunk?: Buffer | ||||
|   ): Promise<void> { | ||||
|     const { connectionId, connectionManager, settings } = context; | ||||
|     const logger = context.logger || createLogger(settings.logLevel || 'info'); | ||||
| @@ -239,7 +240,16 @@ export class StaticHandler { | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|     // Listen for data | ||||
|     // Process initial chunk if provided | ||||
|     if (initialChunk && initialChunk.length > 0) { | ||||
|       if (settings.enableDetailedLogging) { | ||||
|         logger.info(`[${connectionId}] Processing initial data chunk (${initialChunk.length} bytes)`); | ||||
|       } | ||||
|       // Process the initial chunk immediately | ||||
|       handleHttpData(initialChunk); | ||||
|     } | ||||
|  | ||||
|     // Listen for additional data | ||||
|     socket.on('data', handleHttpData); | ||||
|  | ||||
|     // Ensure cleanup on socket close | ||||
|   | ||||
| @@ -132,8 +132,9 @@ export class SmartCertManager { | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     // Provision certificates for all routes | ||||
|     await this.provisionAllCertificates(); | ||||
|     // Skip automatic certificate provisioning during initialization | ||||
|     // This will be called later after ports are listening | ||||
|     console.log('Certificate manager initialized. Deferring certificate provisioning until after ports are listening.'); | ||||
|      | ||||
|     // Start renewal timer | ||||
|     this.startRenewalTimer(); | ||||
| @@ -142,7 +143,7 @@ export class SmartCertManager { | ||||
|   /** | ||||
|    * Provision certificates for all routes that need them | ||||
|    */ | ||||
|   private async provisionAllCertificates(): Promise<void> { | ||||
|   public async provisionAllCertificates(): Promise<void> { | ||||
|     const certRoutes = this.routes.filter(r =>  | ||||
|       r.action.tls?.mode === 'terminate' ||  | ||||
|       r.action.tls?.mode === 'terminate-and-reencrypt' | ||||
|   | ||||
| @@ -352,7 +352,7 @@ export class RouteConnectionHandler { | ||||
|         return this.handleBlockAction(socket, record, route); | ||||
|  | ||||
|       case 'static': | ||||
|         this.handleStaticAction(socket, record, route); | ||||
|         this.handleStaticAction(socket, record, route, initialChunk); | ||||
|         return; | ||||
|  | ||||
|       default: | ||||
| @@ -674,14 +674,15 @@ export class RouteConnectionHandler { | ||||
|   private async handleStaticAction( | ||||
|     socket: plugins.net.Socket, | ||||
|     record: IConnectionRecord, | ||||
|     route: IRouteConfig | ||||
|     route: IRouteConfig, | ||||
|     initialChunk?: Buffer | ||||
|   ): Promise<void> { | ||||
|     // Delegate to HttpProxy's StaticHandler | ||||
|     await StaticHandler.handleStatic(socket, route, { | ||||
|       connectionId: record.id, | ||||
|       connectionManager: this.connectionManager, | ||||
|       settings: this.settings | ||||
|     }, record); | ||||
|     }, record, initialChunk); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|   | ||||
| @@ -350,6 +350,12 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|  | ||||
|     // Start port listeners using the PortManager | ||||
|     await this.portManager.addPorts(listeningPorts); | ||||
|      | ||||
|     // Now that ports are listening, provision any required certificates | ||||
|     if (this.certManager) { | ||||
|       console.log('Starting certificate provisioning now that ports are ready'); | ||||
|       await this.certManager.provisionAllCertificates(); | ||||
|     } | ||||
|  | ||||
|     // Set up periodic connection logging and inactivity checks | ||||
|     this.connectionLogger = setInterval(() => { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user