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:
2025-05-19 22:07:08 +00:00
parent 84c5d0a69e
commit 91018173b0
12 changed files with 623 additions and 12 deletions

View File

@ -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

View File

@ -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'

View File

@ -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);
}
/**

View File

@ -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(() => {