feat(mailer-smtp): add SCRAM-SHA-256 auth, Ed25519 DKIM, opportunistic TLS, SNI cert selection, pipelining and delivery/bridge improvements
This commit is contained in:
@@ -95,11 +95,12 @@ interface ISmtpSendOptions {
|
||||
domain?: string;
|
||||
auth?: { user: string; pass: string; method?: string };
|
||||
email: IOutboundEmail;
|
||||
dkim?: { domain: string; selector: string; privateKey: string };
|
||||
dkim?: { domain: string; selector: string; privateKey: string; keyType?: string };
|
||||
connectionTimeoutSecs?: number;
|
||||
socketTimeoutSecs?: number;
|
||||
poolKey?: string;
|
||||
maxPoolConnections?: number;
|
||||
tlsOpportunistic?: boolean;
|
||||
}
|
||||
|
||||
interface ISmtpSendRawOptions {
|
||||
@@ -147,6 +148,7 @@ interface ISmtpServerConfig {
|
||||
securePort?: number;
|
||||
tlsCertPem?: string;
|
||||
tlsKeyPem?: string;
|
||||
additionalTlsCerts?: Array<{ domains: string[]; certPem: string; keyPem: string }>;
|
||||
maxMessageSize?: number;
|
||||
maxConnections?: number;
|
||||
maxRecipients?: number;
|
||||
@@ -193,6 +195,13 @@ interface IAuthRequestEvent {
|
||||
remoteAddr: string;
|
||||
}
|
||||
|
||||
interface IScramCredentialRequestEvent {
|
||||
correlationId: string;
|
||||
sessionId: string;
|
||||
username: string;
|
||||
remoteAddr: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe command map for the mailer-bin IPC bridge.
|
||||
*/
|
||||
@@ -222,7 +231,7 @@ type TMailerCommands = {
|
||||
result: IDkimVerificationResult[];
|
||||
};
|
||||
signDkim: {
|
||||
params: { rawMessage: string; domain: string; selector?: string; privateKey: string };
|
||||
params: { rawMessage: string; domain: string; selector?: string; privateKey: string; keyType?: string };
|
||||
result: { header: string; signedMessage: string };
|
||||
};
|
||||
checkSpf: {
|
||||
@@ -273,6 +282,17 @@ type TMailerCommands = {
|
||||
};
|
||||
result: { resolved: boolean };
|
||||
};
|
||||
scramCredentialResult: {
|
||||
params: {
|
||||
correlationId: string;
|
||||
found: boolean;
|
||||
salt?: string;
|
||||
iterations?: number;
|
||||
storedKey?: string;
|
||||
serverKey?: string;
|
||||
};
|
||||
result: { resolved: boolean };
|
||||
};
|
||||
configureRateLimits: {
|
||||
params: IRateLimitConfig;
|
||||
result: { configured: boolean };
|
||||
@@ -706,12 +726,13 @@ export class RustSecurityBridge extends EventEmitter {
|
||||
return this.bridge.sendCommand('verifyDkim', { rawMessage });
|
||||
}
|
||||
|
||||
/** Sign an email with DKIM. */
|
||||
/** Sign an email with DKIM (RSA or Ed25519). */
|
||||
public async signDkim(opts: {
|
||||
rawMessage: string;
|
||||
domain: string;
|
||||
selector?: string;
|
||||
privateKey: string;
|
||||
keyType?: string;
|
||||
}): Promise<{ header: string; signedMessage: string }> {
|
||||
this.ensureRunning();
|
||||
return this.bridge.sendCommand('signDkim', opts);
|
||||
@@ -829,6 +850,22 @@ export class RustSecurityBridge extends EventEmitter {
|
||||
await this.bridge.sendCommand('authResult', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send SCRAM credentials back to the Rust SMTP server.
|
||||
* Values (salt, storedKey, serverKey) must be base64-encoded.
|
||||
*/
|
||||
public async sendScramCredentialResult(opts: {
|
||||
correlationId: string;
|
||||
found: boolean;
|
||||
salt?: string;
|
||||
iterations?: number;
|
||||
storedKey?: string;
|
||||
serverKey?: string;
|
||||
}): Promise<void> {
|
||||
this.ensureRunning();
|
||||
await this.bridge.sendCommand('scramCredentialResult', opts);
|
||||
}
|
||||
|
||||
/** Update rate limit configuration at runtime. */
|
||||
public async configureRateLimits(config: IRateLimitConfig): Promise<void> {
|
||||
this.ensureRunning();
|
||||
@@ -855,6 +892,14 @@ export class RustSecurityBridge extends EventEmitter {
|
||||
this.bridge.on('management:authRequest', handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler for scramCredentialRequest events from the Rust SMTP server.
|
||||
* The handler must call sendScramCredentialResult() with the correlationId.
|
||||
*/
|
||||
public onScramCredentialRequest(handler: (data: IScramCredentialRequestEvent) => void): void {
|
||||
this.bridge.on('management:scramCredentialRequest', handler);
|
||||
}
|
||||
|
||||
/** Remove an emailReceived event handler. */
|
||||
public offEmailReceived(handler: (data: IEmailReceivedEvent) => void): void {
|
||||
this.bridge.off('management:emailReceived', handler);
|
||||
@@ -864,6 +909,11 @@ export class RustSecurityBridge extends EventEmitter {
|
||||
public offAuthRequest(handler: (data: IAuthRequestEvent) => void): void {
|
||||
this.bridge.off('management:authRequest', handler);
|
||||
}
|
||||
|
||||
/** Remove a scramCredentialRequest event handler. */
|
||||
public offScramCredentialRequest(handler: (data: IScramCredentialRequestEvent) => void): void {
|
||||
this.bridge.off('management:scramCredentialRequest', handler);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-export interfaces for consumers
|
||||
@@ -882,6 +932,7 @@ export type {
|
||||
IEmailData,
|
||||
IEmailReceivedEvent,
|
||||
IAuthRequestEvent,
|
||||
IScramCredentialRequestEvent,
|
||||
IOutboundEmail,
|
||||
ISmtpSendResult,
|
||||
ISmtpSendOptions,
|
||||
|
||||
Reference in New Issue
Block a user