/** * SMTP Server * Core implementation for the refactored SMTP server */ import * as plugins from '../../../plugins.js'; import { SmtpState } from './interfaces.js'; import { SessionManager } from './session-manager.js'; import { ConnectionManager } from './connection-manager.js'; import { CommandHandler } from './command-handler.js'; import { DataHandler } from './data-handler.js'; import { TlsHandler } from './tls-handler.js'; import { SecurityHandler } from './security-handler.js'; import { SMTP_DEFAULTS } from './constants.js'; import { mergeWithDefaults } from './utils/helpers.js'; import { SmtpLogger } from './utils/logging.js'; import { adaptiveLogger } from './utils/adaptive-logging.js'; import { UnifiedEmailServer } from '../../routing/classes.unified.email.server.js'; /** * SMTP Server implementation * The main server class that coordinates all components */ export class SmtpServer { /** * Email server reference */ emailServer; /** * Session manager */ sessionManager; /** * Connection manager */ connectionManager; /** * Command handler */ commandHandler; /** * Data handler */ dataHandler; /** * TLS handler */ tlsHandler; /** * Security handler */ securityHandler; /** * SMTP server options */ options; /** * Net server instance */ server = null; /** * Secure server instance */ secureServer = null; /** * Whether the server is running */ running = false; /** * Server recovery state */ recoveryState = { /** * Whether recovery is in progress */ recovering: false, /** * Number of consecutive connection failures */ connectionFailures: 0, /** * Last recovery attempt timestamp */ lastRecoveryAttempt: 0, /** * Recovery cooldown in milliseconds */ recoveryCooldown: 5000, /** * Maximum recovery attempts before giving up */ maxRecoveryAttempts: 3, /** * Current recovery attempt */ currentRecoveryAttempt: 0 }; /** * Creates a new SMTP server * @param config - Server configuration */ constructor(config) { this.emailServer = config.emailServer; this.options = mergeWithDefaults(config.options); // Create components - all components now receive the SMTP server instance this.sessionManager = config.sessionManager || new SessionManager({ socketTimeout: this.options.socketTimeout, connectionTimeout: this.options.connectionTimeout, cleanupInterval: this.options.cleanupInterval }); this.securityHandler = config.securityHandler || new SecurityHandler(this); this.tlsHandler = config.tlsHandler || new TlsHandler(this); this.dataHandler = config.dataHandler || new DataHandler(this); this.commandHandler = config.commandHandler || new CommandHandler(this); this.connectionManager = config.connectionManager || new ConnectionManager(this); } /** * Start the SMTP server * @returns Promise that resolves when server is started */ async listen() { if (this.running) { throw new Error('SMTP server is already running'); } try { // Create the server this.server = plugins.net.createServer((socket) => { // Check IP reputation before handling connection this.securityHandler.checkIpReputation(socket) .then(allowed => { if (allowed) { this.connectionManager.handleNewConnection(socket); } else { // Close connection if IP is not allowed socket.destroy(); } }) .catch(error => { SmtpLogger.error(`IP reputation check error: ${error instanceof Error ? error.message : String(error)}`, { remoteAddress: socket.remoteAddress, error: error instanceof Error ? error : new Error(String(error)) }); // Allow connection on error (fail open) this.connectionManager.handleNewConnection(socket); }); }); // Set up error handling with recovery this.server.on('error', (err) => { SmtpLogger.error(`SMTP server error: ${err.message}`, { error: err }); // Try to recover from specific errors if (this.shouldAttemptRecovery(err)) { this.attemptServerRecovery('standard', err); } }); // Start listening await new Promise((resolve, reject) => { if (!this.server) { reject(new Error('Server not initialized')); return; } this.server.listen(this.options.port, this.options.host, () => { SmtpLogger.info(`SMTP server listening on ${this.options.host || '0.0.0.0'}:${this.options.port}`); resolve(); }); this.server.on('error', reject); }); // Start secure server if configured if (this.options.securePort && this.tlsHandler.isTlsEnabled()) { try { // Import the secure server creation utility from our new module // This gives us better certificate handling and error resilience const { createSecureTlsServer } = await import('./secure-server.js'); // Create secure server with the certificates // This uses a more robust approach to certificate loading and validation this.secureServer = createSecureTlsServer({ key: this.options.key, cert: this.options.cert, ca: this.options.ca }); SmtpLogger.info(`Created secure TLS server for port ${this.options.securePort}`); if (this.secureServer) { // Use explicit error handling for secure connections this.secureServer.on('tlsClientError', (err, tlsSocket) => { SmtpLogger.error(`TLS client error: ${err.message}`, { error: err, remoteAddress: tlsSocket.remoteAddress, remotePort: tlsSocket.remotePort, stack: err.stack }); // No need to destroy, the error event will handle that }); // Register the secure connection handler this.secureServer.on('secureConnection', (socket) => { SmtpLogger.info(`New secure connection from ${socket.remoteAddress}:${socket.remotePort}`, { protocol: socket.getProtocol(), cipher: socket.getCipher()?.name }); // Check IP reputation before handling connection this.securityHandler.checkIpReputation(socket) .then(allowed => { if (allowed) { // Pass the connection to the connection manager this.connectionManager.handleNewSecureConnection(socket); } else { // Close connection if IP is not allowed socket.destroy(); } }) .catch(error => { SmtpLogger.error(`IP reputation check error: ${error instanceof Error ? error.message : String(error)}`, { remoteAddress: socket.remoteAddress, error: error instanceof Error ? error : new Error(String(error)), stack: error instanceof Error ? error.stack : 'No stack trace available' }); // Allow connection on error (fail open) this.connectionManager.handleNewSecureConnection(socket); }); }); // Global error handler for the secure server with recovery this.secureServer.on('error', (err) => { SmtpLogger.error(`SMTP secure server error: ${err.message}`, { error: err, stack: err.stack }); // Try to recover from specific errors if (this.shouldAttemptRecovery(err)) { this.attemptServerRecovery('secure', err); } }); // Start listening on secure port await new Promise((resolve, reject) => { if (!this.secureServer) { reject(new Error('Secure server not initialized')); return; } this.secureServer.listen(this.options.securePort, this.options.host, () => { SmtpLogger.info(`SMTP secure server listening on ${this.options.host || '0.0.0.0'}:${this.options.securePort}`); resolve(); }); // Only use error event for startup issues this.secureServer.once('error', reject); }); } else { SmtpLogger.warn('Failed to create secure server, TLS may not be properly configured'); } } catch (error) { SmtpLogger.error(`Error setting up secure server: ${error instanceof Error ? error.message : String(error)}`, { error: error instanceof Error ? error : new Error(String(error)), stack: error instanceof Error ? error.stack : 'No stack trace available' }); } } this.running = true; } catch (error) { SmtpLogger.error(`Failed to start SMTP server: ${error instanceof Error ? error.message : String(error)}`, { error: error instanceof Error ? error : new Error(String(error)) }); // Clean up on error this.close(); throw error; } } /** * Stop the SMTP server * @returns Promise that resolves when server is stopped */ async close() { if (!this.running) { return; } SmtpLogger.info('Stopping SMTP server'); try { // Close all active connections this.connectionManager.closeAllConnections(); // Clear all sessions this.sessionManager.clearAllSessions(); // Clean up adaptive logger to prevent hanging timers adaptiveLogger.destroy(); // Destroy all components to clean up their resources await this.destroy(); // Close servers const closePromises = []; if (this.server) { closePromises.push(new Promise((resolve, reject) => { if (!this.server) { resolve(); return; } this.server.close((err) => { if (err) { reject(err); } else { resolve(); } }); })); } if (this.secureServer) { closePromises.push(new Promise((resolve, reject) => { if (!this.secureServer) { resolve(); return; } this.secureServer.close((err) => { if (err) { reject(err); } else { resolve(); } }); })); } // Add timeout to prevent hanging on close await Promise.race([ Promise.all(closePromises), new Promise((resolve) => { setTimeout(() => { SmtpLogger.warn('Server close timed out after 3 seconds, forcing shutdown'); resolve(); }, 3000); }) ]); this.server = null; this.secureServer = null; this.running = false; SmtpLogger.info('SMTP server stopped'); } catch (error) { SmtpLogger.error(`Error stopping SMTP server: ${error instanceof Error ? error.message : String(error)}`, { error: error instanceof Error ? error : new Error(String(error)) }); throw error; } } /** * Get the session manager * @returns Session manager instance */ getSessionManager() { return this.sessionManager; } /** * Get the connection manager * @returns Connection manager instance */ getConnectionManager() { return this.connectionManager; } /** * Get the command handler * @returns Command handler instance */ getCommandHandler() { return this.commandHandler; } /** * Get the data handler * @returns Data handler instance */ getDataHandler() { return this.dataHandler; } /** * Get the TLS handler * @returns TLS handler instance */ getTlsHandler() { return this.tlsHandler; } /** * Get the security handler * @returns Security handler instance */ getSecurityHandler() { return this.securityHandler; } /** * Get the server options * @returns SMTP server options */ getOptions() { return this.options; } /** * Get the email server reference * @returns Email server instance */ getEmailServer() { return this.emailServer; } /** * Check if the server is running * @returns Whether the server is running */ isRunning() { return this.running; } /** * Check if we should attempt to recover from an error * @param error - The error that occurred * @returns Whether recovery should be attempted */ shouldAttemptRecovery(error) { // Skip recovery if we're already in recovery mode if (this.recoveryState.recovering) { return false; } // Check if we've reached the maximum number of recovery attempts if (this.recoveryState.currentRecoveryAttempt >= this.recoveryState.maxRecoveryAttempts) { SmtpLogger.warn('Maximum recovery attempts reached, not attempting further recovery'); return false; } // Check if enough time has passed since the last recovery attempt const now = Date.now(); if (now - this.recoveryState.lastRecoveryAttempt < this.recoveryState.recoveryCooldown) { SmtpLogger.warn('Recovery cooldown period not elapsed, skipping recovery attempt'); return false; } // Recoverable errors include: // - EADDRINUSE: Address already in use (port conflict) // - ECONNRESET: Connection reset by peer // - EPIPE: Broken pipe // - ETIMEDOUT: Connection timed out const recoverableErrors = [ 'EADDRINUSE', 'ECONNRESET', 'EPIPE', 'ETIMEDOUT', 'ECONNABORTED', 'EPROTO', 'EMFILE' // Too many open files ]; // Check if this is a recoverable error const errorCode = error.code; return recoverableErrors.includes(errorCode); } /** * Attempt to recover the server after a critical error * @param serverType - The type of server to recover ('standard' or 'secure') * @param error - The error that triggered recovery */ async attemptServerRecovery(serverType, error) { // Set recovery flag to prevent multiple simultaneous recovery attempts if (this.recoveryState.recovering) { SmtpLogger.warn('Recovery already in progress, skipping new recovery attempt'); return; } this.recoveryState.recovering = true; this.recoveryState.lastRecoveryAttempt = Date.now(); this.recoveryState.currentRecoveryAttempt++; SmtpLogger.info(`Attempting server recovery for ${serverType} server after error: ${error.message}`, { attempt: this.recoveryState.currentRecoveryAttempt, maxAttempts: this.recoveryState.maxRecoveryAttempts, errorCode: error.code }); try { // Determine which server to restart const isStandardServer = serverType === 'standard'; // Close the affected server if (isStandardServer && this.server) { await new Promise((resolve) => { if (!this.server) { resolve(); return; } // First try a clean shutdown this.server.close((err) => { if (err) { SmtpLogger.warn(`Error during server close in recovery: ${err.message}`); } resolve(); }); // Set a timeout to force close setTimeout(() => { resolve(); }, 3000); }); this.server = null; } else if (!isStandardServer && this.secureServer) { await new Promise((resolve) => { if (!this.secureServer) { resolve(); return; } // First try a clean shutdown this.secureServer.close((err) => { if (err) { SmtpLogger.warn(`Error during secure server close in recovery: ${err.message}`); } resolve(); }); // Set a timeout to force close setTimeout(() => { resolve(); }, 3000); }); this.secureServer = null; } // Short delay before restarting await new Promise((resolve) => setTimeout(resolve, 1000)); // Clean up any lingering connections this.connectionManager.closeAllConnections(); this.sessionManager.clearAllSessions(); // Restart the affected server if (isStandardServer) { // Create and start the standard server this.server = plugins.net.createServer((socket) => { // Check IP reputation before handling connection this.securityHandler.checkIpReputation(socket) .then(allowed => { if (allowed) { this.connectionManager.handleNewConnection(socket); } else { // Close connection if IP is not allowed socket.destroy(); } }) .catch(error => { SmtpLogger.error(`IP reputation check error: ${error instanceof Error ? error.message : String(error)}`, { remoteAddress: socket.remoteAddress, error: error instanceof Error ? error : new Error(String(error)) }); // Allow connection on error (fail open) this.connectionManager.handleNewConnection(socket); }); }); // Set up error handling with recovery this.server.on('error', (err) => { SmtpLogger.error(`SMTP server error after recovery: ${err.message}`, { error: err }); // Try to recover again if needed if (this.shouldAttemptRecovery(err)) { this.attemptServerRecovery('standard', err); } }); // Start listening again await new Promise((resolve, reject) => { if (!this.server) { reject(new Error('Server not initialized during recovery')); return; } this.server.listen(this.options.port, this.options.host, () => { SmtpLogger.info(`SMTP server recovered and listening on ${this.options.host || '0.0.0.0'}:${this.options.port}`); resolve(); }); // Only use error event for startup issues during recovery this.server.once('error', (err) => { SmtpLogger.error(`Failed to restart server during recovery: ${err.message}`); reject(err); }); }); } else if (this.options.securePort && this.tlsHandler.isTlsEnabled()) { // Try to recreate the secure server try { // Import the secure server creation utility const { createSecureTlsServer } = await import('./secure-server.js'); // Create secure server with the certificates this.secureServer = createSecureTlsServer({ key: this.options.key, cert: this.options.cert, ca: this.options.ca }); if (this.secureServer) { SmtpLogger.info(`Created secure TLS server for port ${this.options.securePort} during recovery`); // Use explicit error handling for secure connections this.secureServer.on('tlsClientError', (err, tlsSocket) => { SmtpLogger.error(`TLS client error after recovery: ${err.message}`, { error: err, remoteAddress: tlsSocket.remoteAddress, remotePort: tlsSocket.remotePort, stack: err.stack }); }); // Register the secure connection handler this.secureServer.on('secureConnection', (socket) => { // Check IP reputation before handling connection this.securityHandler.checkIpReputation(socket) .then(allowed => { if (allowed) { // Pass the connection to the connection manager this.connectionManager.handleNewSecureConnection(socket); } else { // Close connection if IP is not allowed socket.destroy(); } }) .catch(error => { SmtpLogger.error(`IP reputation check error after recovery: ${error instanceof Error ? error.message : String(error)}`, { remoteAddress: socket.remoteAddress, error: error instanceof Error ? error : new Error(String(error)) }); // Allow connection on error (fail open) this.connectionManager.handleNewSecureConnection(socket); }); }); // Global error handler for the secure server with recovery this.secureServer.on('error', (err) => { SmtpLogger.error(`SMTP secure server error after recovery: ${err.message}`, { error: err, stack: err.stack }); // Try to recover again if needed if (this.shouldAttemptRecovery(err)) { this.attemptServerRecovery('secure', err); } }); // Start listening on secure port again await new Promise((resolve, reject) => { if (!this.secureServer) { reject(new Error('Secure server not initialized during recovery')); return; } this.secureServer.listen(this.options.securePort, this.options.host, () => { SmtpLogger.info(`SMTP secure server recovered and listening on ${this.options.host || '0.0.0.0'}:${this.options.securePort}`); resolve(); }); // Only use error event for startup issues during recovery this.secureServer.once('error', (err) => { SmtpLogger.error(`Failed to restart secure server during recovery: ${err.message}`); reject(err); }); }); } else { SmtpLogger.warn('Failed to create secure server during recovery'); } } catch (error) { SmtpLogger.error(`Error setting up secure server during recovery: ${error instanceof Error ? error.message : String(error)}`); } } // Recovery successful SmtpLogger.info('Server recovery completed successfully'); } catch (recoveryError) { SmtpLogger.error(`Server recovery failed: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`, { error: recoveryError instanceof Error ? recoveryError : new Error(String(recoveryError)), attempt: this.recoveryState.currentRecoveryAttempt, maxAttempts: this.recoveryState.maxRecoveryAttempts }); } finally { // Reset recovery flag this.recoveryState.recovering = false; } } /** * Clean up all component resources */ async destroy() { SmtpLogger.info('Destroying SMTP server components'); // Destroy all components in parallel const destroyPromises = []; if (this.sessionManager && typeof this.sessionManager.destroy === 'function') { destroyPromises.push(Promise.resolve(this.sessionManager.destroy())); } if (this.connectionManager && typeof this.connectionManager.destroy === 'function') { destroyPromises.push(Promise.resolve(this.connectionManager.destroy())); } if (this.commandHandler && typeof this.commandHandler.destroy === 'function') { destroyPromises.push(Promise.resolve(this.commandHandler.destroy())); } if (this.dataHandler && typeof this.dataHandler.destroy === 'function') { destroyPromises.push(Promise.resolve(this.dataHandler.destroy())); } if (this.tlsHandler && typeof this.tlsHandler.destroy === 'function') { destroyPromises.push(Promise.resolve(this.tlsHandler.destroy())); } if (this.securityHandler && typeof this.securityHandler.destroy === 'function') { destroyPromises.push(Promise.resolve(this.securityHandler.destroy())); } await Promise.all(destroyPromises); // Destroy the adaptive logger singleton to clean up its timer const { adaptiveLogger } = await import('./utils/adaptive-logging.js'); if (adaptiveLogger && typeof adaptiveLogger.destroy === 'function') { adaptiveLogger.destroy(); } // Clear recovery state this.recoveryState = { recovering: false, connectionFailures: 0, lastRecoveryAttempt: 0, recoveryCooldown: 5000, maxRecoveryAttempts: 3, currentRecoveryAttempt: 0 }; SmtpLogger.info('All SMTP server components destroyed'); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic210cC1zZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9tYWlsL2RlbGl2ZXJ5L3NtdHBzZXJ2ZXIvc210cC1zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxLQUFLLE9BQU8sTUFBTSxxQkFBcUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFHNUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzVELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDaEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDdkQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUVuRjs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUNyQjs7T0FFRztJQUNLLFdBQVcsQ0FBcUI7SUFFeEM7O09BRUc7SUFDSyxjQUFjLENBQWtCO0lBRXhDOztPQUVHO0lBQ0ssaUJBQWlCLENBQXFCO0lBRTlDOztPQUVHO0lBQ0ssY0FBYyxDQUFrQjtJQUV4Qzs7T0FFRztJQUNLLFdBQVcsQ0FBZTtJQUVsQzs7T0FF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