This commit is contained in:
2025-05-21 02:17:18 +00:00
parent b1890f59ee
commit 162795802f
15 changed files with 2144 additions and 190 deletions

View File

@ -94,20 +94,16 @@ export class DcRouter {
public deliverySystem?: MultiModeDeliverySystem;
public rateLimiter?: UnifiedRateLimiter;
// Reference to the platform service for accessing MTA and other services
public platformServiceRef?: any;
// Environment access
private qenv = new plugins.qenv.Qenv('./', '.nogit/');
constructor(optionsArg: IDcRouterOptions, platformServiceRef?: any) {
constructor(optionsArg: IDcRouterOptions) {
// Set defaults in options
this.options = {
...optionsArg
};
// Store reference to platform service if provided
this.platformServiceRef = platformServiceRef;
}
public async start() {
@ -681,9 +677,6 @@ export class DcRouter {
}): Promise<boolean> {
logger.log('info', 'Configuring MTA service with custom settings');
if (!this.platformServiceRef) {
throw new Error('Platform service reference is required for MTA configuration');
}
// Update email port configuration
if (!this.options.emailPortConfig) {

File diff suppressed because it is too large Load Diff

View File

@ -11,55 +11,18 @@ import {
ReputationThreshold
} from '../../security/index.js';
export interface ISmtpServerOptions {
port: number;
key: string;
cert: string;
hostname?: string;
}
// SMTP Session States
enum SmtpState {
GREETING,
AFTER_EHLO,
MAIL_FROM,
RCPT_TO,
DATA,
DATA_RECEIVING,
FINISHED
}
// Structure to store session information
interface SmtpSession {
id: string;
state: SmtpState;
clientHostname: string;
mailFrom: string;
rcptTo: string[];
emailData: string;
useTLS: boolean;
connectionEnded: boolean;
remoteAddress: string;
secure: boolean;
authenticated: boolean;
envelope: {
mailFrom: {
address: string;
args: any;
};
rcptTo: Array<{
address: string;
args: any;
}>;
};
processingMode?: 'forward' | 'mta' | 'process';
}
import type {
ISmtpServerOptions,
ISmtpSession,
EmailProcessingMode
} from './interfaces.js';
import { SmtpState } from './interfaces.js';
export class SMTPServer {
public emailServerRef: UnifiedEmailServer;
private smtpServerOptions: ISmtpServerOptions;
private server: plugins.net.Server;
private sessions: Map<plugins.net.Socket | plugins.tls.TLSSocket, SmtpSession>;
private sessions: Map<plugins.net.Socket | plugins.tls.TLSSocket, ISmtpSession>;
private hostname: string;
constructor(emailServerRefArg: UnifiedEmailServer, optionsArg: ISmtpServerOptions) {
@ -722,6 +685,12 @@ export class SMTPServer {
try {
await this.emailServerRef.processEmailByMode(email, {
id: session.id,
state: session.state,
mailFrom: session.mailFrom,
rcptTo: session.rcptTo,
emailData: session.emailData,
useTLS: session.useTLS,
connectionEnded: session.connectionEnded,
remoteAddress: session.remoteAddress,
clientHostname: session.clientHostname,
secure: session.useTLS,

View File

@ -15,5 +15,6 @@ export type { IRateLimitConfig } from './classes.ratelimiter.js';
// Unified rate limiter
export * from './classes.unified.rate.limiter.js';
// MTA configuration helpers
export * from './classes.mta.config.js';
// SMTP client and configuration
export * from './classes.mta.config.js';
export * from './classes.smtp.client.js';

View File

@ -0,0 +1,223 @@
/**
* SMTP and email delivery interface definitions
*/
import type { Email } from '../core/classes.email.js';
/**
* SMTP session state enumeration
*/
export enum SmtpState {
GREETING = 'GREETING',
AFTER_EHLO = 'AFTER_EHLO',
MAIL_FROM = 'MAIL_FROM',
RCPT_TO = 'RCPT_TO',
DATA = 'DATA',
DATA_RECEIVING = 'DATA_RECEIVING',
FINISHED = 'FINISHED'
}
/**
* Email processing mode type
*/
export type EmailProcessingMode = 'forward' | 'mta' | 'process';
/**
* Envelope recipient information
*/
export interface IEnvelopeRecipient {
/**
* Email address of the recipient
*/
address: string;
/**
* Additional SMTP command arguments
*/
args: Record<string, string>;
}
/**
* SMTP session envelope information
*/
export interface ISmtpEnvelope {
/**
* Envelope sender (MAIL FROM) information
*/
mailFrom: {
/**
* Email address of the sender
*/
address: string;
/**
* Additional SMTP command arguments
*/
args: Record<string, string>;
};
/**
* Envelope recipients (RCPT TO) information
*/
rcptTo: IEnvelopeRecipient[];
}
/**
* SMTP Session interface - represents an active SMTP connection
*/
export interface ISmtpSession {
/**
* Unique session identifier
*/
id: string;
/**
* Current session state in the SMTP conversation
*/
state: SmtpState;
/**
* Hostname provided by the client in EHLO/HELO command
*/
clientHostname: string;
/**
* MAIL FROM email address (legacy format)
*/
mailFrom: string;
/**
* RCPT TO email addresses (legacy format)
*/
rcptTo: string[];
/**
* Raw email data being received
*/
emailData: string;
/**
* Whether the connection is using TLS
*/
useTLS: boolean;
/**
* Whether the connection has ended
*/
connectionEnded: boolean;
/**
* Remote IP address of the client
*/
remoteAddress: string;
/**
* Whether the connection is secure (TLS)
*/
secure: boolean;
/**
* Whether the client has been authenticated
*/
authenticated: boolean;
/**
* SMTP envelope information (structured format)
*/
envelope: ISmtpEnvelope;
/**
* Email processing mode to use for this session
*/
processingMode?: EmailProcessingMode;
}
/**
* SMTP authentication data
*/
export interface ISmtpAuth {
/**
* Authentication method used
*/
method: 'PLAIN' | 'LOGIN' | 'OAUTH2' | string;
/**
* Username for authentication
*/
username: string;
/**
* Password or token for authentication
*/
password: string;
}
/**
* SMTP server options
*/
export interface ISmtpServerOptions {
/**
* Port to listen on
*/
port: number;
/**
* TLS private key (PEM format)
*/
key: string;
/**
* TLS certificate (PEM format)
*/
cert: string;
/**
* Server hostname for SMTP banner
*/
hostname?: string;
/**
* Maximum size of messages in bytes
*/
maxSize?: number;
/**
* Authentication options
*/
auth?: {
/**
* Whether authentication is required
*/
required: boolean;
/**
* Allowed authentication methods
*/
methods: ('PLAIN' | 'LOGIN' | 'OAUTH2')[];
};
}
/**
* 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;
}

View File

@ -1,9 +1,9 @@
import * as plugins from '../../plugins.js';
/**
* Email processing modes
*/
export type EmailProcessingMode = 'forward' | 'mta' | 'process';
import type { EmailProcessingMode } from '../delivery/interfaces.js';
// Re-export EmailProcessingMode type
export type { EmailProcessingMode };
/**
* Consolidated email configuration interface

View File

@ -18,7 +18,6 @@ import {
import { DomainRouter } from './classes.domain.router.js';
import type {
IEmailConfig,
EmailProcessingMode,
IDomainRule
} from './classes.email.config.js';
import { Email } from '../core/classes.email.js';
@ -29,6 +28,18 @@ import * as stream from 'node:stream';
import { SMTPServer as MtaSmtpServer } from '../delivery/classes.smtpserver.js';
import { MultiModeDeliverySystem, type IMultiModeDeliveryOptions } from '../delivery/classes.delivery.system.js';
import { UnifiedDeliveryQueue, type IQueueOptions } from '../delivery/classes.delivery.queue.js';
import { SmtpState } from '../delivery/interfaces.js';
import type { EmailProcessingMode, ISmtpSession as IBaseSmtpSession } from '../delivery/interfaces.js';
/**
* Extended SMTP session interface with domain rule information
*/
export interface IExtendedSmtpSession extends ISmtpSession {
/**
* Matched domain rule for this session
*/
matchedRule?: IDomainRule;
}
/**
* Options for the unified email server
@ -78,41 +89,30 @@ export interface IUnifiedEmailServerOptions {
reputationMonitorConfig?: IReputationMonitorConfig;
}
/**
* Interface describing SMTP session data
* Extended SMTP session interface for UnifiedEmailServer
*/
export interface ISmtpSession {
id: string;
remoteAddress: string;
clientHostname: string;
secure: boolean;
authenticated: boolean;
export interface ISmtpSession extends IBaseSmtpSession {
/**
* User information if authenticated
*/
user?: {
username: string;
[key: string]: any;
};
envelope: {
mailFrom: {
address: string;
args: any;
};
rcptTo: Array<{
address: string;
args: any;
}>;
};
processingMode?: EmailProcessingMode;
/**
* Matched domain rule for this session
*/
matchedRule?: IDomainRule;
}
/**
* Authentication data for SMTP
*/
export interface IAuthData {
method: string;
username: string;
password: string;
}
import type { ISmtpAuth } from '../delivery/interfaces.js';
export type IAuthData = ISmtpAuth;
/**
* Server statistics
@ -330,6 +330,12 @@ export class UnifiedEmailServer extends EventEmitter {
// Process based on the mode
await this.processEmailByMode(email, {
id: 'session-' + Math.random().toString(36).substring(2),
state: SmtpState.FINISHED,
mailFrom: email.from,
rcptTo: email.to,
emailData: email.toRFC822String(), // Use the proper method to get the full email content
useTLS: false,
connectionEnded: true,
remoteAddress: '127.0.0.1',
clientHostname: '',
secure: false,
@ -431,7 +437,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle new SMTP connection with IP reputation checking
*/
private async onConnect(session: ISmtpSession, callback: (err?: Error) => void): Promise<void> {
private async onConnect(session: IExtendedSmtpSession, callback: (err?: Error) => void): Promise<void> {
logger.log('info', `New connection from ${session.remoteAddress}`);
// Update connection statistics
@ -498,7 +504,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle authentication (stub implementation)
*/
private onAuth(auth: IAuthData, session: ISmtpSession, callback: (err?: Error, user?: any) => void): void {
private onAuth(auth: IAuthData, session: IExtendedSmtpSession, callback: (err?: Error, user?: any) => void): void {
if (!this.options.auth || !this.options.auth.users || this.options.auth.users.length === 0) {
// No authentication configured, reject
const error = new Error('Authentication not supported');
@ -564,7 +570,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle MAIL FROM command (stub implementation)
*/
private onMailFrom(address: {address: string}, session: ISmtpSession, callback: (err?: Error) => void): void {
private onMailFrom(address: {address: string}, session: IExtendedSmtpSession, callback: (err?: Error) => void): void {
logger.log('info', `MAIL FROM: ${address.address}`);
// Validate the email address
@ -614,7 +620,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle RCPT TO command (stub implementation)
*/
private onRcptTo(address: {address: string}, session: ISmtpSession, callback: (err?: Error) => void): void {
private onRcptTo(address: {address: string}, session: IExtendedSmtpSession, callback: (err?: Error) => void): void {
logger.log('info', `RCPT TO: ${address.address}`);
// Validate the email address
@ -658,7 +664,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle incoming email data (stub implementation)
*/
private onData(stream: stream.Readable, session: ISmtpSession, callback: (err?: Error) => void): void {
private onData(stream: stream.Readable, session: IExtendedSmtpSession, callback: (err?: Error) => void): void {
logger.log('info', `Processing email data for session ${session.id}`);
const startTime = Date.now();
@ -762,7 +768,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Process email based on the determined mode
*/
public async processEmailByMode(emailData: Email | Buffer, session: ISmtpSession, mode: EmailProcessingMode): Promise<Email> {
public async processEmailByMode(emailData: Email | Buffer, session: IExtendedSmtpSession, mode: EmailProcessingMode): Promise<Email> {
// Convert Buffer to Email if needed
let email: Email;
if (Buffer.isBuffer(emailData)) {
@ -833,7 +839,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle email in forward mode (SMTP proxy)
*/
private async handleForwardMode(email: Email, session: ISmtpSession): Promise<void> {
private async handleForwardMode(email: Email, session: IExtendedSmtpSession): Promise<void> {
logger.log('info', `Handling email in forward mode for session ${session.id}`);
// Get target server information
@ -927,7 +933,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle email in MTA mode (programmatic processing)
*/
private async handleMtaMode(email: Email, session: ISmtpSession): Promise<void> {
private async handleMtaMode(email: Email, session: IExtendedSmtpSession): Promise<void> {
logger.log('info', `Handling email in MTA mode for session ${session.id}`);
try {
@ -1022,7 +1028,7 @@ export class UnifiedEmailServer extends EventEmitter {
/**
* Handle email in process mode (store-and-forward with scanning)
*/
private async handleProcessMode(email: Email, session: ISmtpSession): Promise<void> {
private async handleProcessMode(email: Email, session: IExtendedSmtpSession): Promise<void> {
logger.log('info', `Handling email in process mode for session ${session.id}`);
try {

View File

@ -6,8 +6,7 @@ import { TemplateManager } from '../core/classes.templatemanager.js';
import { EmailValidator } from '../core/classes.emailvalidator.js';
import { BounceManager } from '../core/classes.bouncemanager.js';
import { logger } from '../../logger.js';
// Import types from platform interfaces
import type { default as platformInterfaces } from '../../types/platform.interfaces.js';
// Import types from router interfaces
import { UnifiedEmailServer } from '../routing/classes.unified.email.server.js';
import { DomainRouter } from '../routing/classes.domain.router.js';
import { Email } from '../core/classes.email.js';
@ -144,7 +143,6 @@ export interface IEmailServiceStats {
* Email service with MTA support
*/
export class EmailService {
public platformServiceRef: any; // Reference to platform service
// typedrouter
public typedrouter = new plugins.typedrequest.TypedRouter();
@ -166,9 +164,7 @@ export class EmailService {
// configuration
private config: IEmailConfig;
constructor(platformServiceRefArg: any, options: IEmailConfig = {}) {
this.platformServiceRef = platformServiceRefArg;
this.platformServiceRef.typedrouter.addTypedRouter(this.typedrouter);
constructor(options: IEmailConfig = {}) {
// Validate and apply defaults to configuration
const validationResult = ConfigValidator.validate(options, emailConfigSchema);

View File

@ -1,21 +1,16 @@
import * as plugins from '../plugins.js';
import * as paths from '../paths.js';
import { logger } from '../logger.js';
// Import types from platform interfaces
import type { default as platformInterfaces } from '../types/platform.interfaces.js';
import type { ISmsConfig } from '../config/sms.config.js';
import { ConfigValidator, smsConfigSchema } from '../config/index.js';
export class SmsService {
public platformServiceRef: any; // Platform service reference, using any to avoid dependency
public projectinfo: plugins.projectinfo.ProjectInfo;
public typedrouter = new plugins.typedrequest.TypedRouter();
public config: ISmsConfig;
constructor(platformServiceRefArg: any, options: ISmsConfig) {
this.platformServiceRef = platformServiceRefArg;
constructor(options: ISmsConfig) {
// Validate and apply defaults to configuration
const validationResult = ConfigValidator.validate(options, smsConfigSchema);
@ -27,7 +22,6 @@ export class SmsService {
this.config = validationResult.config;
// Add router to platform service
this.platformServiceRef.typedrouter.addTypedRouter(this.typedrouter);
}
/**

View File

@ -1,19 +0,0 @@
/**
* Minimal platform interfaces to support transition
*/
/**
* Dummy placeholder for SzPlatformService interface
*/
export interface SzPlatformService {
// Empty interface for now
typedrouter?: any;
}
// Create a default export with an object that has the SzPlatformService property
const interfaces = {
// Add a dummy constructor function that returns an empty object
SzPlatformService: function() { return {}; }
};
export default interfaces;