This commit is contained in:
2025-05-23 00:06:07 +00:00
parent f058b2d1e7
commit 4905595cbb
7 changed files with 351 additions and 99 deletions

View File

@ -4,7 +4,7 @@
*/
import * as plugins from '../../../plugins.js';
import type { ITlsHandler, ISmtpServer } from './interfaces.js';
import type { ITlsHandler, ISmtpServer, ISmtpSession } from './interfaces.js';
import { SmtpResponseCode, SecurityEventType, SecurityLogLevel } from './constants.js';
import { SmtpLogger } from './utils/logging.js';
import { getSocketDetails, getTlsDetails } from './utils/helpers.js';
@ -30,6 +30,11 @@ export class TlsHandler implements ITlsHandler {
*/
private certificates: ICertificateData;
/**
* TLS options
*/
private options: plugins.tls.TlsOptions;
/**
* Creates a new TLS handler
* @param smtpServer - SMTP server instance
@ -38,13 +43,13 @@ export class TlsHandler implements ITlsHandler {
this.smtpServer = smtpServer;
// Initialize certificates
const options = this.smtpServer.getOptions();
const serverOptions = this.smtpServer.getOptions();
try {
// Try to load certificates from provided options
this.certificates = loadCertificatesFromString({
key: options.key,
cert: options.cert,
ca: options.ca
key: serverOptions.key,
cert: serverOptions.cert,
ca: serverOptions.ca
});
SmtpLogger.info('Successfully loaded TLS certificates');
@ -54,30 +59,27 @@ export class TlsHandler implements ITlsHandler {
// Fall back to self-signed certificates for testing
this.certificates = generateSelfSignedCertificates();
}
// Initialize TLS options
this.options = createTlsOptions(this.certificates);
}
/**
* Handle STARTTLS command
* @param socket - Client socket
*/
public handleStartTls(socket: plugins.net.Socket | plugins.tls.TLSSocket): void {
// Get the session for this socket
const session = this.smtpServer.getSessionManager().getSession(socket);
if (!session) {
this.sendResponse(socket, `${SmtpResponseCode.LOCAL_ERROR} Internal server error - session not found`);
return;
}
public async handleStartTls(socket: plugins.net.Socket, session: ISmtpSession): Promise<plugins.tls.TLSSocket | null> {
// Check if already using TLS
if (session.useTLS) {
this.sendResponse(socket, `${SmtpResponseCode.BAD_SEQUENCE} TLS already active`);
return;
return null;
}
// Check if we have the necessary TLS certificates
if (!this.isTlsEnabled()) {
this.sendResponse(socket, `${SmtpResponseCode.TLS_UNAVAILABLE_TEMP} TLS not available`);
return;
return null;
}
// Send ready for TLS response
@ -85,7 +87,8 @@ export class TlsHandler implements ITlsHandler {
// Upgrade the connection to TLS
try {
this.startTLS(socket);
const tlsSocket = await this.startTLS(socket);
return tlsSocket;
} catch (error) {
SmtpLogger.error(`STARTTLS negotiation failed: ${error instanceof Error ? error.message : String(error)}`, {
sessionId: session.id,
@ -101,6 +104,8 @@ export class TlsHandler implements ITlsHandler {
{ error: error instanceof Error ? error.message : String(error) },
session.remoteAddress
);
return null;
}
}
@ -108,7 +113,7 @@ export class TlsHandler implements ITlsHandler {
* Upgrade a connection to TLS
* @param socket - Client socket
*/
public async startTLS(socket: plugins.net.Socket): Promise<void> {
public async startTLS(socket: plugins.net.Socket): Promise<plugins.tls.TLSSocket> {
// Get the session for this socket
const session = this.smtpServer.getSessionManager().getSession(socket);
@ -120,11 +125,11 @@ export class TlsHandler implements ITlsHandler {
SmtpLogger.info('Using enhanced STARTTLS implementation');
// Use the enhanced STARTTLS handler with better error handling and socket management
const options = this.smtpServer.getOptions();
const serverOptions = this.smtpServer.getOptions();
const tlsSocket = await performStartTLS(socket, {
key: options.key,
cert: options.cert,
ca: options.ca,
key: serverOptions.key,
cert: serverOptions.cert,
ca: serverOptions.ca,
session: session,
sessionManager: this.smtpServer.getSessionManager(),
connectionManager: this.smtpServer.getConnectionManager(),
@ -180,7 +185,10 @@ export class TlsHandler implements ITlsHandler {
sessionId: session?.id,
remoteAddress: socket.remoteAddress
});
throw new Error('Failed to create TLS socket');
}
return tlsSocket;
} catch (error) {
// Log STARTTLS failure
SmtpLogger.error(`Failed to upgrade connection to TLS: ${error instanceof Error ? error.message : String(error)}`, {
@ -206,6 +214,7 @@ export class TlsHandler implements ITlsHandler {
// Destroy the socket on error
socket.destroy();
throw error;
}
}
@ -312,6 +321,20 @@ export class TlsHandler implements ITlsHandler {
}
}
/**
* Check if TLS is available (interface requirement)
*/
public isTlsAvailable(): boolean {
return this.isTlsEnabled();
}
/**
* Get TLS options (interface requirement)
*/
public getTlsOptions(): plugins.tls.TlsOptions {
return this.options;
}
/**
* Clean up resources
*/