/** * SMTP Logging Utilities * Provides structured logging for SMTP server components */ import * as plugins from '../../../../plugins.js'; import { logger } from '../../../../logger.js'; import { SecurityLogLevel, SecurityEventType } from '../constants.js'; /** * SMTP logger - provides structured logging for SMTP server */ export class SmtpLogger { /** * Log a message with context * @param level - Log level * @param message - Log message * @param options - Additional log options */ static log(level, message, options = {}) { // Extract error information if provided const errorInfo = options.error ? { errorMessage: options.error.message, errorStack: options.error.stack, errorName: options.error.name } : {}; // Structure log data const logData = { component: 'smtp-server', ...options, ...errorInfo }; // Remove error from log data to avoid duplication if (logData.error) { delete logData.error; } // Log through the main logger logger.log(level, message, logData); // Also console log for immediate visibility during development if (level === 'error' || level === 'warn') { console[level](`[SMTP] ${message}`, logData); } } /** * Log debug level message * @param message - Log message * @param options - Additional log options */ static debug(message, options = {}) { this.log('debug', message, options); } /** * Log info level message * @param message - Log message * @param options - Additional log options */ static info(message, options = {}) { this.log('info', message, options); } /** * Log warning level message * @param message - Log message * @param options - Additional log options */ static warn(message, options = {}) { this.log('warn', message, options); } /** * Log error level message * @param message - Log message * @param options - Additional log options */ static error(message, options = {}) { this.log('error', message, options); } /** * Log command received from client * @param command - The command string * @param socket - The client socket * @param session - The SMTP session */ static logCommand(command, socket, session) { const clientInfo = { remoteAddress: socket.remoteAddress, remotePort: socket.remotePort, secure: socket instanceof plugins.tls.TLSSocket, sessionId: session?.id, sessionState: session?.state }; this.info(`Command received: ${command}`, { ...clientInfo, command: command.split(' ')[0]?.toUpperCase() }); // Also log to console for easy debugging console.log(`← ${command}`); } /** * Log response sent to client * @param response - The response string * @param socket - The client socket */ static logResponse(response, socket) { const clientInfo = { remoteAddress: socket.remoteAddress, remotePort: socket.remotePort, secure: socket instanceof plugins.tls.TLSSocket }; // Get the response code from the beginning of the response const responseCode = response.substring(0, 3); // Log different levels based on response code if (responseCode.startsWith('2') || responseCode.startsWith('3')) { this.debug(`Response sent: ${response}`, clientInfo); } else if (responseCode.startsWith('4')) { this.warn(`Temporary error response: ${response}`, clientInfo); } else if (responseCode.startsWith('5')) { this.error(`Permanent error response: ${response}`, clientInfo); } // Also log to console for easy debugging console.log(`→ ${response}`); } /** * Log client connection event * @param socket - The client socket * @param eventType - Type of connection event (connect, close, error) * @param session - The SMTP session * @param error - Optional error object for error events */ static logConnection(socket, eventType, session, error) { const clientInfo = { remoteAddress: socket.remoteAddress, remotePort: socket.remotePort, secure: socket instanceof plugins.tls.TLSSocket, sessionId: session?.id, sessionState: session?.state }; switch (eventType) { case 'connect': this.info(`New ${clientInfo.secure ? 'secure ' : ''}connection from ${clientInfo.remoteAddress}:${clientInfo.remotePort}`, clientInfo); break; case 'close': this.info(`Connection closed from ${clientInfo.remoteAddress}:${clientInfo.remotePort}`, clientInfo); break; case 'error': this.error(`Connection error from ${clientInfo.remoteAddress}:${clientInfo.remotePort}`, { ...clientInfo, error }); break; } } /** * Log security event * @param level - Security log level * @param type - Security event type * @param message - Log message * @param details - Event details * @param ipAddress - Client IP address * @param domain - Optional domain involved * @param success - Whether the security check was successful */ static logSecurityEvent(level, type, message, details, ipAddress, domain, success) { // Map security log level to system log level const logLevel = level === SecurityLogLevel.DEBUG ? 'debug' : level === SecurityLogLevel.INFO ? 'info' : level === SecurityLogLevel.WARN ? 'warn' : 'error'; // Log the security event this.log(logLevel, message, { component: 'smtp-security', eventType: type, success, ipAddress, domain, ...details }); } } /** * Default instance for backward compatibility */ export const smtpLogger = SmtpLogger; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3RzL21haWwvZGVsaXZlcnkvc210cHNlcnZlci91dGlscy9sb2dnaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFDbEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBaUN0RTs7R0FFRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBQ3JCOzs7OztPQUtHO0lBQ0ksTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFlLEVBQUUsT0FBZSxFQUFFLFVBQTJCLEVBQUU7UUFDL0Usd0NBQXdDO1FBQ3hDLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ2hDLFlBQVksRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLE9BQU87WUFDbkMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsS0FBSztZQUMvQixTQUFTLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJO1NBQzlCLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUVQLHFCQUFxQjtRQUNyQixNQUFNLE9BQU8sR0FBRztZQUNkLFNBQVMsRUFBRSxhQUFhO1lBQ3hCLEdBQUcsT0FBTztZQUNWLEdBQUcsU0FBUztTQUNiLENBQUM7UUFFRixrREFBa0Q7UUFDbEQsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEIsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLENBQUM7UUFFRCw4QkFBOEI7UUFDOUIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXBDLCtEQUErRDtRQUMvRCxJQUFJLEtB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