import * as plugins from './plugins.js'; /** * Configuration options for TLS in SMTP connections */ export interface ISmtpTlsOptions { /** Enable TLS for this SMTP port */ enabled: boolean; /** Whether to use STARTTLS (upgrade plain connection) or implicit TLS */ useStartTls?: boolean; /** Required TLS protocol version (defaults to TLSv1.2) */ minTlsVersion?: 'TLSv1.0' | 'TLSv1.1' | 'TLSv1.2' | 'TLSv1.3'; /** TLS ciphers to allow (comma-separated list) */ allowedCiphers?: string; /** Whether to require client certificate for authentication */ requireClientCert?: boolean; /** Whether to verify client certificate if provided */ verifyClientCert?: boolean; } /** * Rate limiting options for SMTP connections */ export interface ISmtpRateLimitOptions { /** Maximum connections per minute from a single IP */ maxConnectionsPerMinute?: number; /** Maximum concurrent connections from a single IP */ maxConcurrentConnections?: number; /** Maximum emails per minute from a single IP */ maxEmailsPerMinute?: number; /** Maximum recipients per email */ maxRecipientsPerEmail?: number; /** Maximum email size in bytes */ maxEmailSize?: number; /** Action to take when rate limit is exceeded (default: 'tempfail') */ rateLimitAction?: 'tempfail' | 'drop' | 'delay'; } /** * Configuration for a specific SMTP port */ export interface ISmtpPortSettings { /** The port number to listen on */ port: number; /** Whether this port is enabled */ enabled?: boolean; /** Port description (e.g., "Submission Port") */ description?: string; /** Whether to require authentication for this port */ requireAuth?: boolean; /** TLS options for this port */ tls?: ISmtpTlsOptions; /** Rate limiting settings for this port */ rateLimit?: ISmtpRateLimitOptions; /** Maximum message size in bytes for this port */ maxMessageSize?: number; /** Whether to enable SMTP extensions like PIPELINING, 8BITMIME, etc. */ smtpExtensions?: { /** Enable PIPELINING extension */ pipelining?: boolean; /** Enable 8BITMIME extension */ eightBitMime?: boolean; /** Enable SIZE extension */ size?: boolean; /** Enable ENHANCEDSTATUSCODES extension */ enhancedStatusCodes?: boolean; /** Enable DSN extension */ dsn?: boolean; }; /** Custom SMTP greeting banner */ banner?: string; } /** * Configuration manager for SMTP ports */ export class SmtpPortConfig { /** Port configurations */ private portConfigs: Map = new Map(); /** Default port configurations */ private static readonly DEFAULT_CONFIGS: Record> = { // Port 25: Standard SMTP 25: { description: 'Standard SMTP', requireAuth: false, tls: { enabled: true, useStartTls: true, minTlsVersion: 'TLSv1.2' }, rateLimit: { maxConnectionsPerMinute: 60, maxConcurrentConnections: 10, maxEmailsPerMinute: 30 }, maxMessageSize: 20 * 1024 * 1024 // 20MB }, // Port 587: Submission 587: { description: 'Submission Port', requireAuth: true, tls: { enabled: true, useStartTls: true, minTlsVersion: 'TLSv1.2' }, rateLimit: { maxConnectionsPerMinute: 100, maxConcurrentConnections: 20, maxEmailsPerMinute: 60 }, maxMessageSize: 50 * 1024 * 1024 // 50MB }, // Port 465: SMTPS (Legacy Implicit TLS) 465: { description: 'SMTPS (Implicit TLS)', requireAuth: true, tls: { enabled: true, useStartTls: false, minTlsVersion: 'TLSv1.2' }, rateLimit: { maxConnectionsPerMinute: 100, maxConcurrentConnections: 20, maxEmailsPerMinute: 60 }, maxMessageSize: 50 * 1024 * 1024 // 50MB } }; /** * Create a new SmtpPortConfig * @param initialConfigs Optional initial port configurations */ constructor(initialConfigs?: ISmtpPortSettings[]) { // Initialize with default configurations for standard SMTP ports this.initializeDefaults(); // Apply custom configurations if provided if (initialConfigs) { for (const config of initialConfigs) { this.setPortConfig(config); } } } /** * Initialize port configurations with defaults */ private initializeDefaults(): void { // Set up default configurations for standard SMTP ports: 25, 587, 465 Object.entries(SmtpPortConfig.DEFAULT_CONFIGS).forEach(([portStr, defaults]) => { const port = parseInt(portStr, 10); this.portConfigs.set(port, { port, enabled: true, ...defaults }); }); } /** * Get configuration for a specific port * @param port Port number * @returns Port configuration or null if not found */ public getPortConfig(port: number): ISmtpPortSettings | null { return this.portConfigs.get(port) || null; } /** * Get all configured ports * @returns Array of port configurations */ public getAllPortConfigs(): ISmtpPortSettings[] { return Array.from(this.portConfigs.values()); } /** * Get only enabled port configurations * @returns Array of enabled port configurations */ public getEnabledPortConfigs(): ISmtpPortSettings[] { return this.getAllPortConfigs().filter(config => config.enabled !== false); } /** * Set configuration for a specific port * @param config Port configuration */ public setPortConfig(config: ISmtpPortSettings): void { // Get existing config if any const existingConfig = this.portConfigs.get(config.port) || { port: config.port }; // Merge with new configuration this.portConfigs.set(config.port, { ...existingConfig, ...config }); } /** * Remove configuration for a specific port * @param port Port number * @returns Whether the configuration was removed */ public removePortConfig(port: number): boolean { return this.portConfigs.delete(port); } /** * Disable a specific port * @param port Port number * @returns Whether the port was disabled */ public disablePort(port: number): boolean { const config = this.portConfigs.get(port); if (config) { config.enabled = false; return true; } return false; } /** * Enable a specific port * @param port Port number * @returns Whether the port was enabled */ public enablePort(port: number): boolean { const config = this.portConfigs.get(port); if (config) { config.enabled = true; return true; } return false; } /** * Convert port configurations to SmartProxy routes * @returns Array of SmartProxy routes */ public toSmartProxyRoutes(): plugins.smartproxy.IRouteConfig[] { const enabledPorts = this.getEnabledPortConfigs(); const routes: plugins.smartproxy.IRouteConfig[] = []; // Add configured ports as routes for (const portConfig of enabledPorts) { // Create a route for each SMTP port const route: plugins.smartproxy.IRouteConfig = { name: `smtp-port-${portConfig.port}`, match: { ports: [portConfig.port] }, action: { type: 'forward', target: { host: 'localhost', port: portConfig.port + 10000 // Map to internal port (e.g., 25 -> 10025) } } }; // Apply TLS settings if (portConfig.port === 465 && portConfig.tls?.enabled) { // For implicit TLS on port 465 route.action.tls = { mode: 'terminate', certificate: 'auto' }; } else if (portConfig.tls?.useStartTls) { // For STARTTLS on ports 25 and 587 route.action.tls = { mode: 'passthrough' }; } routes.push(route); } return routes; } /** * Apply port configurations to SmartProxy settings * @param smartProxy SmartProxy instance * @deprecated Use toSmartProxyRoutes() instead to generate routes */ public applyToSmartProxy(smartProxy: plugins.smartproxy.SmartProxy): void { console.warn('SmtpPortConfig.applyToSmartProxy() is deprecated. Use toSmartProxyRoutes() instead.'); // This method is deprecated and no longer functional } }