Files
smartmta/dist_ts/mail/delivery/smtpserver/utils/logging.js

181 lines
12 KiB
JavaScript
Raw Normal View History

2026-02-10 15:54:09 +00:00
/**
* 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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