update
This commit is contained in:
@ -171,7 +171,11 @@ export class CommandHandler implements ICommandHandler {
|
||||
if (this.tlsHandler && this.tlsHandler.isTlsEnabled()) {
|
||||
this.tlsHandler.handleStartTls(socket);
|
||||
} else {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.COMMAND_NOT_IMPLEMENTED} STARTTLS not available`);
|
||||
SmtpLogger.warn('STARTTLS requested but TLS is not enabled', {
|
||||
remoteAddress: socket.remoteAddress,
|
||||
remotePort: socket.remotePort
|
||||
});
|
||||
this.sendResponse(socket, `${SmtpResponseCode.TLS_UNAVAILABLE_TEMP} STARTTLS not available at this time`);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -224,8 +228,21 @@ export class CommandHandler implements ICommandHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract command and arguments from clientHostname
|
||||
// EHLO/HELO might come with the command itself in the arguments string
|
||||
let hostname = clientHostname;
|
||||
if (hostname.toUpperCase().startsWith('EHLO ') || hostname.toUpperCase().startsWith('HELO ')) {
|
||||
hostname = hostname.substring(5).trim();
|
||||
}
|
||||
|
||||
// Check for empty hostname
|
||||
if (!hostname) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.SYNTAX_ERROR_PARAMETERS} Missing domain name`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate EHLO hostname
|
||||
const validation = validateEhlo(clientHostname);
|
||||
const validation = validateEhlo(hostname);
|
||||
|
||||
if (!validation.isValid) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.SYNTAX_ERROR_PARAMETERS} ${validation.errorMessage}`);
|
||||
@ -233,7 +250,7 @@ export class CommandHandler implements ICommandHandler {
|
||||
}
|
||||
|
||||
// Update session state and client hostname
|
||||
session.clientHostname = validation.hostname || clientHostname;
|
||||
session.clientHostname = validation.hostname || hostname;
|
||||
this.sessionManager.updateSessionState(session, SmtpState.AFTER_EHLO);
|
||||
|
||||
// Set up EHLO response lines
|
||||
@ -272,14 +289,32 @@ export class CommandHandler implements ICommandHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the client has sent EHLO/HELO first
|
||||
if (session.state === SmtpState.GREETING) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.BAD_SEQUENCE} Bad sequence of commands`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if authentication is required but not provided
|
||||
if (this.options.auth && this.options.auth.required && !session.authenticated) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.AUTH_REQUIRED} Authentication required`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Special handling for commands that include "MAIL FROM:" in the args
|
||||
let processedArgs = args;
|
||||
if (args.toUpperCase().startsWith('FROM')) {
|
||||
processedArgs = args;
|
||||
} else if (args.toUpperCase().includes('MAIL FROM')) {
|
||||
// The command was already prepended to the args
|
||||
const colonIndex = args.indexOf(':');
|
||||
if (colonIndex !== -1) {
|
||||
processedArgs = args.substring(colonIndex + 1).trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Validate MAIL FROM syntax
|
||||
const validation = validateMailFrom(args);
|
||||
const validation = validateMailFrom(processedArgs);
|
||||
|
||||
if (!validation.isValid) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.SYNTAX_ERROR_PARAMETERS} ${validation.errorMessage}`);
|
||||
@ -336,8 +371,26 @@ export class CommandHandler implements ICommandHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if MAIL FROM was provided first
|
||||
if (session.state !== SmtpState.MAIL_FROM && session.state !== SmtpState.RCPT_TO) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.BAD_SEQUENCE} Bad sequence of commands`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Special handling for commands that include "RCPT TO:" in the args
|
||||
let processedArgs = args;
|
||||
if (args.toUpperCase().startsWith('TO:')) {
|
||||
processedArgs = args;
|
||||
} else if (args.toUpperCase().includes('RCPT TO')) {
|
||||
// The command was already prepended to the args
|
||||
const colonIndex = args.indexOf(':');
|
||||
if (colonIndex !== -1) {
|
||||
processedArgs = args.substring(colonIndex + 1).trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Validate RCPT TO syntax
|
||||
const validation = validateRcptTo(args);
|
||||
const validation = validateRcptTo(processedArgs);
|
||||
|
||||
if (!validation.isValid) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.SYNTAX_ERROR_PARAMETERS} ${validation.errorMessage}`);
|
||||
@ -379,6 +432,12 @@ export class CommandHandler implements ICommandHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check command sequence - DATA must follow RCPT TO
|
||||
if (session.state !== SmtpState.RCPT_TO) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.BAD_SEQUENCE} Bad sequence of commands`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have recipients
|
||||
if (!session.rcptTo.length) {
|
||||
this.sendResponse(socket, `${SmtpResponseCode.BAD_SEQUENCE} No recipients specified`);
|
||||
|
Reference in New Issue
Block a user