181 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			181 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | /** | ||
|  |  * SMTP Server Constants | ||
|  |  * This file contains all constants and enums used by the SMTP server | ||
|  |  */ | ||
|  | 
 | ||
|  | import { SmtpState } from '../interfaces.ts'; | ||
|  | 
 | ||
|  | // Re-export SmtpState enum from the main interfaces file
 | ||
|  | export { SmtpState }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * SMTP Response Codes | ||
|  |  * Based on RFC 5321 and common SMTP practice | ||
|  |  */ | ||
|  | export enum SmtpResponseCode { | ||
|  |   // Success codes (2xx)
 | ||
|  |   SUCCESS = 250,                    // Requested mail action okay, completed
 | ||
|  |   SYSTEM_STATUS = 211,              // System status, or system help reply
 | ||
|  |   HELP_MESSAGE = 214,               // Help message
 | ||
|  |   SERVICE_READY = 220,              // <domain> Service ready
 | ||
|  |   SERVICE_CLOSING = 221,            // <domain> Service closing transmission channel
 | ||
|  |   AUTHENTICATION_SUCCESSFUL = 235,  // Authentication successful
 | ||
|  |   OK = 250,                         // Requested mail action okay, completed
 | ||
|  |   FORWARD = 251,                    // User not local; will forward to <forward-path>
 | ||
|  |   CANNOT_VRFY = 252,                // Cannot VRFY user, but will accept message and attempt delivery
 | ||
|  |    | ||
|  |   // Intermediate codes (3xx)
 | ||
|  |   MORE_INFO_NEEDED = 334,           // Server challenge for authentication
 | ||
|  |   START_MAIL_INPUT = 354,           // Start mail input; end with <CRLF>.<CRLF>
 | ||
|  |    | ||
|  |   // Temporary error codes (4xx)
 | ||
|  |   SERVICE_NOT_AVAILABLE = 421,      // <domain> Service not available, closing transmission channel
 | ||
|  |   MAILBOX_TEMPORARILY_UNAVAILABLE = 450, // Requested mail action not taken: mailbox unavailable
 | ||
|  |   LOCAL_ERROR = 451,                // Requested action aborted: local error in processing
 | ||
|  |   INSUFFICIENT_STORAGE = 452,       // Requested action not taken: insufficient system storage
 | ||
|  |   TLS_UNAVAILABLE_TEMP = 454,       // TLS not available due to temporary reason
 | ||
|  |    | ||
|  |   // Permanent error codes (5xx)
 | ||
|  |   SYNTAX_ERROR = 500,               // Syntax error, command unrecognized
 | ||
|  |   SYNTAX_ERROR_PARAMETERS = 501,    // Syntax error in parameters or arguments
 | ||
|  |   COMMAND_NOT_IMPLEMENTED = 502,    // Command not implemented
 | ||
|  |   BAD_SEQUENCE = 503,               // Bad sequence of commands
 | ||
|  |   COMMAND_PARAMETER_NOT_IMPLEMENTED = 504, // Command parameter not implemented
 | ||
|  |   AUTH_REQUIRED = 530,              // Authentication required
 | ||
|  |   AUTH_FAILED = 535,                // Authentication credentials invalid
 | ||
|  |   MAILBOX_UNAVAILABLE = 550,        // Requested action not taken: mailbox unavailable
 | ||
|  |   USER_NOT_LOCAL = 551,             // User not local; please try <forward-path>
 | ||
|  |   EXCEEDED_STORAGE = 552,           // Requested mail action aborted: exceeded storage allocation
 | ||
|  |   MAILBOX_NAME_INVALID = 553,       // Requested action not taken: mailbox name not allowed
 | ||
|  |   TRANSACTION_FAILED = 554,         // Transaction failed
 | ||
|  |   MAIL_RCPT_PARAMETERS_INVALID = 555, // MAIL FROM/RCPT TO parameters not recognized or not implemented
 | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * SMTP Command Types | ||
|  |  */ | ||
|  | export enum SmtpCommand { | ||
|  |   HELO = 'HELO', | ||
|  |   EHLO = 'EHLO', | ||
|  |   MAIL_FROM = 'MAIL', | ||
|  |   RCPT_TO = 'RCPT', | ||
|  |   DATA = 'DATA', | ||
|  |   RSET = 'RSET', | ||
|  |   NOOP = 'NOOP', | ||
|  |   QUIT = 'QUIT', | ||
|  |   STARTTLS = 'STARTTLS', | ||
|  |   AUTH = 'AUTH', | ||
|  |   HELP = 'HELP', | ||
|  |   VRFY = 'VRFY', | ||
|  |   EXPN = 'EXPN', | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Security log event types | ||
|  |  */ | ||
|  | export enum SecurityEventType { | ||
|  |   CONNECTION = 'connection', | ||
|  |   AUTHENTICATION = 'authentication', | ||
|  |   COMMAND = 'command', | ||
|  |   DATA = 'data', | ||
|  |   IP_REPUTATION = 'ip_reputation', | ||
|  |   TLS_NEGOTIATION = 'tls_negotiation', | ||
|  |   DKIM = 'dkim', | ||
|  |   SPF = 'spf', | ||
|  |   DMARC = 'dmarc', | ||
|  |   EMAIL_VALIDATION = 'email_validation', | ||
|  |   SPAM = 'spam', | ||
|  |   ACCESS_CONTROL = 'access_control', | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Security log levels | ||
|  |  */ | ||
|  | export enum SecurityLogLevel { | ||
|  |   DEBUG = 'debug', | ||
|  |   INFO = 'info', | ||
|  |   WARN = 'warn', | ||
|  |   ERROR = 'error', | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * SMTP Server Defaults | ||
|  |  */ | ||
|  | export const SMTP_DEFAULTS = { | ||
|  |   // Default timeouts in milliseconds
 | ||
|  |   CONNECTION_TIMEOUT: 30000,       // 30 seconds
 | ||
|  |   SOCKET_TIMEOUT: 300000,          // 5 minutes
 | ||
|  |   DATA_TIMEOUT: 60000,             // 1 minute
 | ||
|  |   CLEANUP_INTERVAL: 5000,          // 5 seconds
 | ||
|  |    | ||
|  |   // Default limits
 | ||
|  |   MAX_CONNECTIONS: 100, | ||
|  |   MAX_RECIPIENTS: 100, | ||
|  |   MAX_MESSAGE_SIZE: 10485760,      // 10MB
 | ||
|  |    | ||
|  |   // Default ports
 | ||
|  |   SMTP_PORT: 25, | ||
|  |   SUBMISSION_PORT: 587, | ||
|  |   SECURE_PORT: 465, | ||
|  |    | ||
|  |   // Default hostname
 | ||
|  |   HOSTNAME: 'mail.lossless.one', | ||
|  |    | ||
|  |   // CRLF line ending required by SMTP protocol
 | ||
|  |   CRLF: '\r\n', | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * SMTP Command Patterns | ||
|  |  * Regular expressions for parsing SMTP commands | ||
|  |  */ | ||
|  | export const SMTP_PATTERNS = { | ||
|  |   // Match EHLO/HELO command: "EHLO example.com"
 | ||
|  |   // Made very permissive to handle various client implementations
 | ||
|  |   EHLO: /^(?:EHLO|HELO)\s+(.+)$/i, | ||
|  |    | ||
|  |   // Match MAIL FROM command: "MAIL FROM:<user@example.com> [PARAM=VALUE]"
 | ||
|  |   // Made more permissive with whitespace and parameter formats
 | ||
|  |   MAIL_FROM: /^MAIL\s+FROM\s*:\s*<([^>]*)>((?:\s+[a-zA-Z0-9][a-zA-Z0-9\-]*(?:=[^\s]+)?)*)$/i, | ||
|  |    | ||
|  |   // Match RCPT TO command: "RCPT TO:<user@example.com> [PARAM=VALUE]"
 | ||
|  |   // Made more permissive with whitespace and parameter formats
 | ||
|  |   RCPT_TO: /^RCPT\s+TO\s*:\s*<([^>]*)>((?:\s+[a-zA-Z0-9][a-zA-Z0-9\-]*(?:=[^\s]+)?)*)$/i, | ||
|  |    | ||
|  |   // Match parameter format: "PARAM=VALUE"
 | ||
|  |   PARAM: /\s+([A-Za-z0-9][A-Za-z0-9\-]*)(?:=([^\s]+))?/g, | ||
|  |    | ||
|  |   // Match email address format - basic validation
 | ||
|  |   // This pattern rejects common invalid formats while being permissive for edge cases
 | ||
|  |   // Checks: no spaces, has @, has domain with dot, no double dots, proper domain format
 | ||
|  |   EMAIL: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, | ||
|  |    | ||
|  |   // Match end of DATA marker: \r\n.\r\n or just .\r\n at the start of a line (to handle various client implementations)
 | ||
|  |   END_DATA: /(\r\n\.\r\n$)|(\n\.\r\n$)|(\r\n\.\n$)|(\n\.\n$)|^\.(\r\n|\n)$/, | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * SMTP Extension List | ||
|  |  * These extensions are advertised in the EHLO response | ||
|  |  */ | ||
|  | export const SMTP_EXTENSIONS = { | ||
|  |   // Basic extensions (RFC 1869)
 | ||
|  |   PIPELINING: 'PIPELINING', | ||
|  |   SIZE: 'SIZE', | ||
|  |   EIGHTBITMIME: '8BITMIME', | ||
|  |    | ||
|  |   // Security extensions
 | ||
|  |   STARTTLS: 'STARTTLS', | ||
|  |   AUTH: 'AUTH', | ||
|  |    | ||
|  |   // Additional extensions
 | ||
|  |   ENHANCEDSTATUSCODES: 'ENHANCEDSTATUSCODES', | ||
|  |   HELP: 'HELP', | ||
|  |   CHUNKING: 'CHUNKING', | ||
|  |   DSN: 'DSN', | ||
|  |    | ||
|  |   // Format an extension with a parameter
 | ||
|  |   formatExtension(name: string, parameter?: string | number): string { | ||
|  |     return parameter !== undefined ? `${name} ${parameter}` : name; | ||
|  |   } | ||
|  | }; |