update
This commit is contained in:
@ -11,6 +11,7 @@ import { UnifiedDeliveryQueue, type IQueueOptions } from './mail/delivery/classe
|
||||
import { MultiModeDeliverySystem, type IMultiModeDeliveryOptions } from './mail/delivery/classes.delivery.system.js';
|
||||
import { UnifiedRateLimiter, type IHierarchicalRateLimits } from './mail/delivery/classes.unified.rate.limiter.js';
|
||||
import { logger } from './logger.js';
|
||||
import { applyCustomEmailStorage } from './mail/delivery/classes.mta.patch.js';
|
||||
|
||||
export interface IDcRouterOptions {
|
||||
/**
|
||||
@ -25,6 +26,20 @@ export interface IDcRouterOptions {
|
||||
*/
|
||||
emailConfig?: IEmailConfig;
|
||||
|
||||
/**
|
||||
* Custom email port configuration
|
||||
* Allows configuring specific ports for email handling
|
||||
* This overrides the default port mapping in the emailConfig
|
||||
*/
|
||||
emailPortConfig?: {
|
||||
/** External to internal port mapping */
|
||||
portMapping?: Record<number, number>;
|
||||
/** Custom port configuration for specific ports */
|
||||
portSettings?: Record<number, any>;
|
||||
/** Path to store received emails */
|
||||
receivedEmailsPath?: string;
|
||||
};
|
||||
|
||||
/** TLS/certificate configuration */
|
||||
tls?: {
|
||||
/** Contact email for ACME certificates */
|
||||
@ -76,14 +91,20 @@ 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) {
|
||||
constructor(optionsArg: IDcRouterOptions, platformServiceRef?: any) {
|
||||
// Set defaults in options
|
||||
this.options = {
|
||||
...optionsArg
|
||||
};
|
||||
|
||||
// Store reference to platform service if provided
|
||||
this.platformServiceRef = platformServiceRef;
|
||||
}
|
||||
|
||||
public async start() {
|
||||
@ -96,6 +117,12 @@ export class DcRouter {
|
||||
// Set up unified email handling if configured
|
||||
if (this.options.emailConfig) {
|
||||
await this.setupUnifiedEmailHandling();
|
||||
|
||||
// Apply custom email storage configuration if available
|
||||
if (this.platformServiceRef && this.options.emailPortConfig?.receivedEmailsPath) {
|
||||
logger.log('info', 'Applying custom email storage configuration');
|
||||
applyCustomEmailStorage(this.platformServiceRef, this.options);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up DNS server if configured
|
||||
@ -222,69 +249,90 @@ export class DcRouter {
|
||||
private generateEmailRoutes(emailConfig: IEmailConfig): plugins.smartproxy.IRouteConfig[] {
|
||||
const emailRoutes: plugins.smartproxy.IRouteConfig[] = [];
|
||||
|
||||
// Get the custom port mapping if available, otherwise use defaults
|
||||
const defaultPortMapping = {
|
||||
25: 10025, // SMTP
|
||||
587: 10587, // Submission
|
||||
465: 10465 // SMTPS
|
||||
};
|
||||
|
||||
// Use custom port mapping if provided, otherwise fall back to defaults
|
||||
const portMapping = this.options.emailPortConfig?.portMapping || defaultPortMapping;
|
||||
|
||||
// Create routes for each email port
|
||||
for (const port of emailConfig.ports) {
|
||||
// Calculate the internal port using the mapping
|
||||
const internalPort = portMapping[port] || port + 10000;
|
||||
|
||||
// Create a descriptive name for the route based on the port
|
||||
let routeName = 'email-route';
|
||||
let tlsMode = 'passthrough';
|
||||
|
||||
// Handle different email ports differently
|
||||
switch (port) {
|
||||
case 25: // SMTP
|
||||
emailRoutes.push({
|
||||
name: 'smtp-route',
|
||||
match: {
|
||||
ports: [25]
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost', // Forward to internal email server
|
||||
port: 10025 // Internal email server port
|
||||
},
|
||||
// No TLS termination for port 25 (STARTTLS handled by email server)
|
||||
tls: {
|
||||
mode: 'passthrough'
|
||||
}
|
||||
}
|
||||
});
|
||||
routeName = 'smtp-route';
|
||||
tlsMode = 'passthrough'; // STARTTLS handled by email server
|
||||
break;
|
||||
|
||||
case 587: // Submission
|
||||
emailRoutes.push({
|
||||
name: 'submission-route',
|
||||
match: {
|
||||
ports: [587]
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 10587
|
||||
},
|
||||
tls: {
|
||||
mode: 'passthrough' // STARTTLS handled by email server
|
||||
}
|
||||
}
|
||||
});
|
||||
routeName = 'submission-route';
|
||||
tlsMode = 'passthrough'; // STARTTLS handled by email server
|
||||
break;
|
||||
|
||||
case 465: // SMTPS
|
||||
emailRoutes.push({
|
||||
name: 'smtps-route',
|
||||
match: {
|
||||
ports: [465]
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 10465
|
||||
},
|
||||
tls: {
|
||||
mode: 'terminate', // Terminate TLS and re-encrypt to email server
|
||||
certificate: 'auto'
|
||||
}
|
||||
routeName = 'smtps-route';
|
||||
tlsMode = 'terminate'; // Terminate TLS and re-encrypt to email server
|
||||
break;
|
||||
|
||||
default:
|
||||
routeName = `email-port-${port}-route`;
|
||||
// For unknown ports, assume passthrough by default
|
||||
tlsMode = 'passthrough';
|
||||
|
||||
// Check if we have specific settings for this port
|
||||
if (this.options.emailPortConfig?.portSettings &&
|
||||
this.options.emailPortConfig.portSettings[port]) {
|
||||
const portSettings = this.options.emailPortConfig.portSettings[port];
|
||||
|
||||
// If this port requires TLS termination, set the mode accordingly
|
||||
if (portSettings.terminateTls) {
|
||||
tlsMode = 'terminate';
|
||||
}
|
||||
});
|
||||
|
||||
// Override the route name if specified
|
||||
if (portSettings.routeName) {
|
||||
routeName = portSettings.routeName;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the route configuration
|
||||
const routeConfig: plugins.smartproxy.IRouteConfig = {
|
||||
name: routeName,
|
||||
match: {
|
||||
ports: [port]
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: {
|
||||
host: 'localhost', // Forward to internal email server
|
||||
port: internalPort
|
||||
},
|
||||
tls: {
|
||||
mode: tlsMode as any
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For TLS terminate mode, add certificate info
|
||||
if (tlsMode === 'terminate') {
|
||||
routeConfig.action.tls.certificate = 'auto';
|
||||
}
|
||||
|
||||
// Add the route to our list
|
||||
emailRoutes.push(routeConfig);
|
||||
}
|
||||
|
||||
// Add domain-specific email routes if configured
|
||||
@ -406,13 +454,16 @@ export class DcRouter {
|
||||
|
||||
const emailConfig = this.options.emailConfig;
|
||||
|
||||
// Map external ports to internal ports
|
||||
const portMapping = {
|
||||
// Map external ports to internal ports with support for custom port mapping
|
||||
const defaultPortMapping = {
|
||||
25: 10025, // SMTP
|
||||
587: 10587, // Submission
|
||||
465: 10465 // SMTPS
|
||||
};
|
||||
|
||||
// Use custom port mapping if provided, otherwise fall back to defaults
|
||||
const portMapping = this.options.emailPortConfig?.portMapping || defaultPortMapping;
|
||||
|
||||
// Create internal email server configuration
|
||||
const internalEmailConfig: IEmailConfig = {
|
||||
...emailConfig,
|
||||
@ -420,6 +471,17 @@ export class DcRouter {
|
||||
hostname: 'localhost' // Listen on localhost for SmartProxy forwarding
|
||||
};
|
||||
|
||||
// If custom MTA options are provided, merge them
|
||||
if (this.options.emailPortConfig?.portSettings) {
|
||||
// Will be used in MTA configuration
|
||||
logger.log('info', 'Custom port settings detected for email configuration');
|
||||
}
|
||||
|
||||
// Configure custom email storage path if specified
|
||||
if (this.options.emailPortConfig?.receivedEmailsPath) {
|
||||
logger.log('info', `Custom email storage path configured: ${this.options.emailPortConfig.receivedEmailsPath}`);
|
||||
}
|
||||
|
||||
try {
|
||||
// Create domain router for pattern matching
|
||||
this.domainRouter = new DomainRouter({
|
||||
|
Reference in New Issue
Block a user