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; } /** * Apply port configurations to SmartProxy settings * @param smartProxy SmartProxy instance */ public applyToSmartProxy(smartProxy: plugins.smartproxy.SmartProxy): void { if (!smartProxy) return; const enabledPorts = this.getEnabledPortConfigs(); const settings = smartProxy.settings; // Initialize globalPortRanges if needed if (!settings.globalPortRanges) { settings.globalPortRanges = []; } // Add configured ports to globalPortRanges for (const portConfig of enabledPorts) { // Add port to global port ranges if not already present if (!settings.globalPortRanges.some((r) => r.from <= portConfig.port && portConfig.port <= r.to)) { settings.globalPortRanges.push({ from: portConfig.port, to: portConfig.port }); } // Apply TLS settings at SmartProxy level if (portConfig.port === 465 && portConfig.tls?.enabled) { // For implicit TLS on port 465 settings.sniEnabled = true; } } // Group ports by TLS configuration to log them const starttlsPorts = enabledPorts .filter(p => p.tls?.enabled && p.tls?.useStartTls) .map(p => p.port); const implicitTlsPorts = enabledPorts .filter(p => p.tls?.enabled && !p.tls?.useStartTls) .map(p => p.port); const nonTlsPorts = enabledPorts .filter(p => !p.tls?.enabled) .map(p => p.port); if (starttlsPorts.length > 0) { console.log(`Configured STARTTLS SMTP ports: ${starttlsPorts.join(', ')}`); } if (implicitTlsPorts.length > 0) { console.log(`Configured Implicit TLS SMTP ports: ${implicitTlsPorts.join(', ')}`); } if (nonTlsPorts.length > 0) { console.log(`Configured Plain SMTP ports: ${nonTlsPorts.join(', ')}`); } // Setup connection listeners for different port types smartProxy.on('connection', (connection) => { const port = connection.localPort; // Check which type of port this is if (implicitTlsPorts.includes(port)) { console.log(`Implicit TLS SMTP connection on port ${port} from ${connection.remoteIP}`); } else if (starttlsPorts.includes(port)) { console.log(`STARTTLS SMTP connection on port ${port} from ${connection.remoteIP}`); } else if (nonTlsPorts.includes(port)) { console.log(`Plain SMTP connection on port ${port} from ${connection.remoteIP}`); } }); console.log(`Applied SMTP port configurations to SmartProxy: ${enabledPorts.map(p => p.port).join(', ')}`); } }