295 lines
8.2 KiB
TypeScript
295 lines
8.2 KiB
TypeScript
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<number, ISmtpPortSettings> = new Map();
|
|
|
|
/** Default port configurations */
|
|
private static readonly DEFAULT_CONFIGS: Record<number, Partial<ISmtpPortSettings>> = {
|
|
// 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
|
|
}
|
|
} |