initial
This commit is contained in:
655
ts/mail/delivery/smtpserver/interfaces.ts
Normal file
655
ts/mail/delivery/smtpserver/interfaces.ts
Normal file
@@ -0,0 +1,655 @@
|
||||
/**
|
||||
* SMTP Server Interfaces
|
||||
* Defines all the interfaces used by the SMTP server implementation
|
||||
*/
|
||||
|
||||
import * as plugins from '../../../plugins.ts';
|
||||
import type { Email } from '../../core/classes.email.ts';
|
||||
import type { UnifiedEmailServer } from '../../routing/classes.unified.email.server.ts';
|
||||
|
||||
// Re-export types from other modules
|
||||
import { SmtpState } from '../interfaces.ts';
|
||||
import { SmtpCommand } from './constants.ts';
|
||||
export { SmtpState, SmtpCommand };
|
||||
export type { IEnvelopeRecipient } from '../interfaces.ts';
|
||||
|
||||
/**
|
||||
* Interface for components that need cleanup
|
||||
*/
|
||||
export interface IDestroyable {
|
||||
/**
|
||||
* Clean up all resources (timers, listeners, etc)
|
||||
*/
|
||||
destroy(): void | Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* SMTP authentication credentials
|
||||
*/
|
||||
export interface ISmtpAuth {
|
||||
/**
|
||||
* Username for authentication
|
||||
*/
|
||||
username: string;
|
||||
|
||||
/**
|
||||
* Password for authentication
|
||||
*/
|
||||
password: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* SMTP envelope (sender and recipients)
|
||||
*/
|
||||
export interface ISmtpEnvelope {
|
||||
/**
|
||||
* Mail from address
|
||||
*/
|
||||
mailFrom: {
|
||||
address: string;
|
||||
args?: Record<string, string>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recipients list
|
||||
*/
|
||||
rcptTo: Array<{
|
||||
address: string;
|
||||
args?: Record<string, string>;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* SMTP session representing a client connection
|
||||
*/
|
||||
export interface ISmtpSession {
|
||||
/**
|
||||
* Unique session identifier
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Current state of the SMTP session
|
||||
*/
|
||||
state: SmtpState;
|
||||
|
||||
/**
|
||||
* Client's hostname from EHLO/HELO
|
||||
*/
|
||||
clientHostname: string | null;
|
||||
|
||||
/**
|
||||
* Whether TLS is active for this session
|
||||
*/
|
||||
secure: boolean;
|
||||
|
||||
/**
|
||||
* Authentication status
|
||||
*/
|
||||
authenticated: boolean;
|
||||
|
||||
/**
|
||||
* Authentication username if authenticated
|
||||
*/
|
||||
username?: string;
|
||||
|
||||
/**
|
||||
* Transaction envelope
|
||||
*/
|
||||
envelope: ISmtpEnvelope;
|
||||
|
||||
/**
|
||||
* When the session was created
|
||||
*/
|
||||
createdAt: Date;
|
||||
|
||||
/**
|
||||
* Last activity timestamp
|
||||
*/
|
||||
lastActivity: number;
|
||||
|
||||
/**
|
||||
* Client's IP address
|
||||
*/
|
||||
remoteAddress: string;
|
||||
|
||||
/**
|
||||
* Client's port
|
||||
*/
|
||||
remotePort: number;
|
||||
|
||||
/**
|
||||
* Additional session data
|
||||
*/
|
||||
data?: Record<string, any>;
|
||||
|
||||
/**
|
||||
* Message size if SIZE extension is used
|
||||
*/
|
||||
messageSize?: number;
|
||||
|
||||
/**
|
||||
* Server capabilities advertised to client
|
||||
*/
|
||||
capabilities?: string[];
|
||||
|
||||
/**
|
||||
* Buffer for incomplete data
|
||||
*/
|
||||
dataBuffer?: string;
|
||||
|
||||
/**
|
||||
* Flag to track if we're currently receiving DATA
|
||||
*/
|
||||
receivingData?: boolean;
|
||||
|
||||
/**
|
||||
* The raw email data being received
|
||||
*/
|
||||
rawData?: string;
|
||||
|
||||
/**
|
||||
* Greeting sent to client
|
||||
*/
|
||||
greeting?: string;
|
||||
|
||||
/**
|
||||
* Whether EHLO has been sent
|
||||
*/
|
||||
ehloSent?: boolean;
|
||||
|
||||
/**
|
||||
* Whether HELO has been sent
|
||||
*/
|
||||
heloSent?: boolean;
|
||||
|
||||
/**
|
||||
* TLS options for this session
|
||||
*/
|
||||
tlsOptions?: any;
|
||||
|
||||
/**
|
||||
* Whether TLS is being used
|
||||
*/
|
||||
useTLS?: boolean;
|
||||
|
||||
/**
|
||||
* Mail from address for this transaction
|
||||
*/
|
||||
mailFrom?: string;
|
||||
|
||||
/**
|
||||
* Recipients for this transaction
|
||||
*/
|
||||
rcptTo?: string[];
|
||||
|
||||
/**
|
||||
* Email data being received
|
||||
*/
|
||||
emailData?: string;
|
||||
|
||||
/**
|
||||
* Chunks of email data
|
||||
*/
|
||||
emailDataChunks?: string[];
|
||||
|
||||
/**
|
||||
* Timeout ID for data reception
|
||||
*/
|
||||
dataTimeoutId?: NodeJS.Timeout;
|
||||
|
||||
/**
|
||||
* Whether connection has ended
|
||||
*/
|
||||
connectionEnded?: boolean;
|
||||
|
||||
/**
|
||||
* Size of email data being received
|
||||
*/
|
||||
emailDataSize?: number;
|
||||
|
||||
/**
|
||||
* Processing mode for this session
|
||||
*/
|
||||
processingMode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Session manager interface
|
||||
*/
|
||||
export interface ISessionManager extends IDestroyable {
|
||||
/**
|
||||
* Create a new session for a socket
|
||||
*/
|
||||
createSession(socket: plugins.net.Socket | plugins.tls.TLSSocket, secure?: boolean): ISmtpSession;
|
||||
|
||||
/**
|
||||
* Get session by socket
|
||||
*/
|
||||
getSession(socket: plugins.net.Socket | plugins.tls.TLSSocket): ISmtpSession | undefined;
|
||||
|
||||
/**
|
||||
* Update session state
|
||||
*/
|
||||
updateSessionState(session: ISmtpSession, newState: SmtpState): void;
|
||||
|
||||
/**
|
||||
* Remove a session
|
||||
*/
|
||||
removeSession(socket: plugins.net.Socket | plugins.tls.TLSSocket): void;
|
||||
|
||||
/**
|
||||
* Clear all sessions
|
||||
*/
|
||||
clearAllSessions(): void;
|
||||
|
||||
/**
|
||||
* Get all active sessions
|
||||
*/
|
||||
getAllSessions(): ISmtpSession[];
|
||||
|
||||
/**
|
||||
* Get session count
|
||||
*/
|
||||
getSessionCount(): number;
|
||||
|
||||
/**
|
||||
* Update last activity for a session
|
||||
*/
|
||||
updateLastActivity(socket: plugins.net.Socket | plugins.tls.TLSSocket): void;
|
||||
|
||||
/**
|
||||
* Check for timed out sessions
|
||||
*/
|
||||
checkTimeouts(timeoutMs: number): ISmtpSession[];
|
||||
|
||||
/**
|
||||
* Update session activity timestamp
|
||||
*/
|
||||
updateSessionActivity(session: ISmtpSession): void;
|
||||
|
||||
/**
|
||||
* Replace socket in session (for TLS upgrade)
|
||||
*/
|
||||
replaceSocket(oldSocket: plugins.net.Socket | plugins.tls.TLSSocket, newSocket: plugins.net.Socket | plugins.tls.TLSSocket): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection manager interface
|
||||
*/
|
||||
export interface IConnectionManager extends IDestroyable {
|
||||
/**
|
||||
* Handle a new connection
|
||||
*/
|
||||
handleConnection(socket: plugins.net.Socket | plugins.tls.TLSSocket, secure: boolean): Promise<void>;
|
||||
|
||||
/**
|
||||
* Close all active connections
|
||||
*/
|
||||
closeAllConnections(): void;
|
||||
|
||||
/**
|
||||
* Get active connection count
|
||||
*/
|
||||
getConnectionCount(): number;
|
||||
|
||||
/**
|
||||
* Check if accepting new connections
|
||||
*/
|
||||
canAcceptConnection(): boolean;
|
||||
|
||||
/**
|
||||
* Handle new connection (legacy method name)
|
||||
*/
|
||||
handleNewConnection(socket: plugins.net.Socket): Promise<void>;
|
||||
|
||||
/**
|
||||
* Handle new secure connection (legacy method name)
|
||||
*/
|
||||
handleNewSecureConnection(socket: plugins.tls.TLSSocket): Promise<void>;
|
||||
|
||||
/**
|
||||
* Setup socket event handlers
|
||||
*/
|
||||
setupSocketEventHandlers(socket: plugins.net.Socket | plugins.tls.TLSSocket): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command handler interface
|
||||
*/
|
||||
export interface ICommandHandler extends IDestroyable {
|
||||
/**
|
||||
* Handle an SMTP command
|
||||
*/
|
||||
handleCommand(
|
||||
socket: plugins.net.Socket | plugins.tls.TLSSocket,
|
||||
command: SmtpCommand,
|
||||
args: string,
|
||||
session: ISmtpSession
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Get supported commands for current session state
|
||||
*/
|
||||
getSupportedCommands(session: ISmtpSession): SmtpCommand[];
|
||||
|
||||
/**
|
||||
* Process command (legacy method name)
|
||||
*/
|
||||
processCommand(socket: plugins.net.Socket | plugins.tls.TLSSocket, command: string): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data handler interface
|
||||
*/
|
||||
export interface IDataHandler extends IDestroyable {
|
||||
/**
|
||||
* Handle email data
|
||||
*/
|
||||
handleData(
|
||||
socket: plugins.net.Socket | plugins.tls.TLSSocket,
|
||||
data: string,
|
||||
session: ISmtpSession
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Process a complete email
|
||||
*/
|
||||
processEmail(
|
||||
rawData: string,
|
||||
session: ISmtpSession
|
||||
): Promise<Email>;
|
||||
|
||||
/**
|
||||
* Handle data received (legacy method name)
|
||||
*/
|
||||
handleDataReceived(socket: plugins.net.Socket | plugins.tls.TLSSocket, data: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Process email data (legacy method name)
|
||||
*/
|
||||
processEmailData(socket: plugins.net.Socket | plugins.tls.TLSSocket, data: string): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* TLS handler interface
|
||||
*/
|
||||
export interface ITlsHandler extends IDestroyable {
|
||||
/**
|
||||
* Handle STARTTLS command
|
||||
*/
|
||||
handleStartTls(
|
||||
socket: plugins.net.Socket,
|
||||
session: ISmtpSession
|
||||
): Promise<plugins.tls.TLSSocket | null>;
|
||||
|
||||
/**
|
||||
* Check if TLS is available
|
||||
*/
|
||||
isTlsAvailable(): boolean;
|
||||
|
||||
/**
|
||||
* Get TLS options
|
||||
*/
|
||||
getTlsOptions(): plugins.tls.TlsOptions;
|
||||
|
||||
/**
|
||||
* Check if TLS is enabled
|
||||
*/
|
||||
isTlsEnabled(): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Security handler interface
|
||||
*/
|
||||
export interface ISecurityHandler extends IDestroyable {
|
||||
/**
|
||||
* Check IP reputation
|
||||
*/
|
||||
checkIpReputation(socket: plugins.net.Socket | plugins.tls.TLSSocket): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Validate email address
|
||||
*/
|
||||
isValidEmail(email: string): boolean;
|
||||
|
||||
/**
|
||||
* Authenticate user
|
||||
*/
|
||||
authenticate(auth: ISmtpAuth): Promise<boolean>;
|
||||
}
|
||||
|
||||
/**
|
||||
* SMTP server options
|
||||
*/
|
||||
export interface ISmtpServerOptions {
|
||||
/**
|
||||
* Port to listen on
|
||||
*/
|
||||
port: number;
|
||||
|
||||
/**
|
||||
* Hostname of the server
|
||||
*/
|
||||
hostname: string;
|
||||
|
||||
/**
|
||||
* Host to bind to (optional, defaults to 0.0.0.0)
|
||||
*/
|
||||
host?: string;
|
||||
|
||||
/**
|
||||
* Secure port for TLS connections
|
||||
*/
|
||||
securePort?: number;
|
||||
|
||||
/**
|
||||
* TLS/SSL private key (PEM format)
|
||||
*/
|
||||
key?: string;
|
||||
|
||||
/**
|
||||
* TLS/SSL certificate (PEM format)
|
||||
*/
|
||||
cert?: string;
|
||||
|
||||
/**
|
||||
* CA certificates for TLS (PEM format)
|
||||
*/
|
||||
ca?: string;
|
||||
|
||||
/**
|
||||
* Maximum size of messages in bytes
|
||||
*/
|
||||
maxSize?: number;
|
||||
|
||||
/**
|
||||
* Maximum number of concurrent connections
|
||||
*/
|
||||
maxConnections?: number;
|
||||
|
||||
/**
|
||||
* Authentication options
|
||||
*/
|
||||
auth?: {
|
||||
/**
|
||||
* Whether authentication is required
|
||||
*/
|
||||
required: boolean;
|
||||
|
||||
/**
|
||||
* Allowed authentication methods
|
||||
*/
|
||||
methods: ('PLAIN' | 'LOGIN' | 'OAUTH2')[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Socket timeout in milliseconds (default: 5 minutes / 300000ms)
|
||||
*/
|
||||
socketTimeout?: number;
|
||||
|
||||
/**
|
||||
* Initial connection timeout in milliseconds (default: 30 seconds / 30000ms)
|
||||
*/
|
||||
connectionTimeout?: number;
|
||||
|
||||
/**
|
||||
* Interval for checking idle sessions in milliseconds (default: 5 seconds / 5000ms)
|
||||
* For testing, can be set lower (e.g. 1000ms) to detect timeouts more quickly
|
||||
*/
|
||||
cleanupInterval?: number;
|
||||
|
||||
/**
|
||||
* Maximum number of recipients allowed per message (default: 100)
|
||||
*/
|
||||
maxRecipients?: number;
|
||||
|
||||
/**
|
||||
* Maximum message size in bytes (default: 10MB / 10485760 bytes)
|
||||
* This is advertised in the EHLO SIZE extension
|
||||
*/
|
||||
size?: number;
|
||||
|
||||
/**
|
||||
* Timeout for the DATA command in milliseconds (default: 60000ms / 1 minute)
|
||||
* This controls how long to wait for the complete email data
|
||||
*/
|
||||
dataTimeout?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of SMTP transaction
|
||||
*/
|
||||
export interface ISmtpTransactionResult {
|
||||
/**
|
||||
* Whether the transaction was successful
|
||||
*/
|
||||
success: boolean;
|
||||
|
||||
/**
|
||||
* Error message if failed
|
||||
*/
|
||||
error?: string;
|
||||
|
||||
/**
|
||||
* Message ID if successful
|
||||
*/
|
||||
messageId?: string;
|
||||
|
||||
/**
|
||||
* Resulting email if successful
|
||||
*/
|
||||
email?: Email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for SMTP session events
|
||||
* These events are emitted by the session manager
|
||||
*/
|
||||
export interface ISessionEvents {
|
||||
created: (session: ISmtpSession, socket: plugins.net.Socket | plugins.tls.TLSSocket) => void;
|
||||
stateChanged: (session: ISmtpSession, previousState: SmtpState, newState: SmtpState) => void;
|
||||
timeout: (session: ISmtpSession, socket: plugins.net.Socket | plugins.tls.TLSSocket) => void;
|
||||
completed: (session: ISmtpSession, socket: plugins.net.Socket | plugins.tls.TLSSocket) => void;
|
||||
error: (session: ISmtpSession, error: Error) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* SMTP Server interface
|
||||
*/
|
||||
export interface ISmtpServer extends IDestroyable {
|
||||
/**
|
||||
* Start the SMTP server
|
||||
*/
|
||||
listen(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Stop the SMTP server
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Get the session manager
|
||||
*/
|
||||
getSessionManager(): ISessionManager;
|
||||
|
||||
/**
|
||||
* Get the connection manager
|
||||
*/
|
||||
getConnectionManager(): IConnectionManager;
|
||||
|
||||
/**
|
||||
* Get the command handler
|
||||
*/
|
||||
getCommandHandler(): ICommandHandler;
|
||||
|
||||
/**
|
||||
* Get the data handler
|
||||
*/
|
||||
getDataHandler(): IDataHandler;
|
||||
|
||||
/**
|
||||
* Get the TLS handler
|
||||
*/
|
||||
getTlsHandler(): ITlsHandler;
|
||||
|
||||
/**
|
||||
* Get the security handler
|
||||
*/
|
||||
getSecurityHandler(): ISecurityHandler;
|
||||
|
||||
/**
|
||||
* Get the server options
|
||||
*/
|
||||
getOptions(): ISmtpServerOptions;
|
||||
|
||||
/**
|
||||
* Get the email server reference
|
||||
*/
|
||||
getEmailServer(): UnifiedEmailServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for creating SMTP server
|
||||
*/
|
||||
export interface ISmtpServerConfig {
|
||||
/**
|
||||
* Email server instance
|
||||
*/
|
||||
emailServer: UnifiedEmailServer;
|
||||
|
||||
/**
|
||||
* Server options
|
||||
*/
|
||||
options: ISmtpServerOptions;
|
||||
|
||||
/**
|
||||
* Optional custom session manager
|
||||
*/
|
||||
sessionManager?: ISessionManager;
|
||||
|
||||
/**
|
||||
* Optional custom connection manager
|
||||
*/
|
||||
connectionManager?: IConnectionManager;
|
||||
|
||||
/**
|
||||
* Optional custom command handler
|
||||
*/
|
||||
commandHandler?: ICommandHandler;
|
||||
|
||||
/**
|
||||
* Optional custom data handler
|
||||
*/
|
||||
dataHandler?: IDataHandler;
|
||||
|
||||
/**
|
||||
* Optional custom TLS handler
|
||||
*/
|
||||
tlsHandler?: ITlsHandler;
|
||||
|
||||
/**
|
||||
* Optional custom security handler
|
||||
*/
|
||||
securityHandler?: ISecurityHandler;
|
||||
}
|
||||
Reference in New Issue
Block a user