BREAKING CHANGE(rust-bridge): make Rust the primary security backend, remove all TS fallbacks
Some checks failed
CI / Build Test (Current Platform) (push) Failing after 4s
CI / Type Check & Lint (push) Failing after 6s
CI / Build All Platforms (push) Failing after 4s

Phase 3 of the Rust migration: the Rust security bridge is now mandatory
and all TypeScript security fallback implementations have been removed.

- UnifiedEmailServer.start() throws if Rust bridge fails to start
- SpfVerifier gutted to thin wrapper (parseSpfRecord stays in TS)
- DKIMVerifier gutted to thin wrapper delegating to bridge.verifyDkim()
- IPReputationChecker delegates to bridge.checkIpReputation(), keeps LRU cache
- DmarcVerifier keeps alignment logic (works with pre-computed results)
- DKIM signing via bridge.signDkim() in all 4 locations
- Removed mailauth and ip packages from plugins.ts (~1,200 lines deleted)
This commit is contained in:
2026-02-10 20:30:43 +00:00
parent ffe294643c
commit b82468ab1e
24 changed files with 457 additions and 2695 deletions

View File

@@ -12,6 +12,7 @@ import { UnifiedDeliveryQueue, type IQueueItem } from './classes.delivery.queue.
import type { Email } from '../core/classes.email.js';
import type { UnifiedEmailServer } from '../routing/classes.unified.email.server.js';
import type { SmtpClient } from './smtpclient/smtp-client.js';
import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js';
/**
* Delivery status enumeration
@@ -763,33 +764,24 @@ export class MultiModeDeliverySystem extends EventEmitter {
try {
// Ensure DKIM keys exist for the domain
await this.emailServer.dkimCreator.handleDKIMKeysForDomain(domainName);
// Get the private key
const dkimPrivateKey = (await this.emailServer.dkimCreator.readDKIMKeys(domainName)).privateKey;
// Convert Email to raw format for signing
const rawEmail = email.toRFC822String();
// Sign the email
const dkimPrivateKey = (await this.emailServer.dkimCreator.readDKIMKeys(domainName)).privateKey;
const signResult = await plugins.dkimSign(rawEmail, {
signingDomain: domainName,
// Sign via Rust bridge
const bridge = RustSecurityBridge.getInstance();
const signResult = await bridge.signDkim({
rawMessage: rawEmail,
domain: domainName,
selector: keySelector,
privateKey: dkimPrivateKey,
canonicalization: 'relaxed/relaxed',
algorithm: 'rsa-sha256',
signTime: new Date(),
signatureData: [
{
signingDomain: domainName,
selector: keySelector,
privateKey: dkimPrivateKey,
algorithm: 'rsa-sha256',
canonicalization: 'relaxed/relaxed'
}
]
});
// Add the DKIM-Signature header to the email
if (signResult.signatures) {
email.addHeader('DKIM-Signature', signResult.signatures);
if (signResult.header) {
email.addHeader('DKIM-Signature', signResult.header);
logger.log('info', `Successfully added DKIM signature for ${domainName}`);
}
} catch (error) {

View File

@@ -1,5 +1,6 @@
import * as plugins from '../../plugins.js';
import type { UnifiedEmailServer } from '../routing/classes.unified.email.server.js';
import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js';
interface Headers {
[key: string]: string;
@@ -28,24 +29,13 @@ export class EmailSignJob {
public async getSignatureHeader(emailMessage: string): Promise<string> {
const privateKey = await this.loadPrivateKey();
const signResult = await plugins.dkimSign(emailMessage, {
signingDomain: this.jobOptions.domain,
const bridge = RustSecurityBridge.getInstance();
const signResult = await bridge.signDkim({
rawMessage: emailMessage,
domain: this.jobOptions.domain,
selector: this.jobOptions.selector,
privateKey,
canonicalization: 'relaxed/relaxed',
algorithm: 'rsa-sha256',
signTime: new Date(),
signatureData: [
{
signingDomain: this.jobOptions.domain,
selector: this.jobOptions.selector,
privateKey,
algorithm: 'rsa-sha256',
canonicalization: 'relaxed/relaxed',
},
],
});
const signature = signResult.signatures;
return signature;
return signResult.header;
}
}

View File

@@ -1,10 +1,11 @@
import * as plugins from '../../plugins.js';
import { logger } from '../../logger.js';
import {
SecurityLogger,
SecurityLogLevel,
SecurityEventType
import {
SecurityLogger,
SecurityLogLevel,
SecurityEventType
} from '../../security/index.js';
import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js';
import {
MtaConnectionError,
@@ -844,42 +845,22 @@ export class SmtpClient {
try {
logger.log('debug', `Signing email with DKIM for domain ${this.options.dkim.domain}`);
// Format email for DKIM signing
const { dkimSign } = plugins;
const emailContent = await this.getFormattedEmail(email);
// Sign email
const signOptions = {
signingDomain: this.options.dkim.domain,
// Sign via Rust bridge
const bridge = RustSecurityBridge.getInstance();
const signResult = await bridge.signDkim({
rawMessage: emailContent,
domain: this.options.dkim.domain,
selector: this.options.dkim.selector,
privateKey: this.options.dkim.privateKey,
canonicalization: 'relaxed/relaxed' as const,
algorithm: 'rsa-sha256' as const,
signTime: new Date(),
signatureData: [
{
signingDomain: this.options.dkim.domain,
selector: this.options.dkim.selector,
privateKey: this.options.dkim.privateKey,
algorithm: 'rsa-sha256',
canonicalization: 'relaxed/relaxed',
}
]
};
});
const signResult = await dkimSign(emailContent, signOptions);
// Add DKIM-Signature header from the signing result
if (signResult.signatures) {
const dkimHeader = signResult.signatures.split('\r\n')
.find(line => line.startsWith('DKIM-Signature: '));
if (dkimHeader) {
email.addHeader('DKIM-Signature', dkimHeader.substring('DKIM-Signature: '.length));
}
if (signResult.header) {
email.addHeader('DKIM-Signature', signResult.header);
}
logger.log('debug', 'DKIM signature applied successfully');
} catch (error) {
logger.log('error', `Failed to apply DKIM signature: ${error.message}`);