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)
87 lines
2.5 KiB
TypeScript
87 lines
2.5 KiB
TypeScript
import { logger } from '../../logger.js';
|
|
import { SecurityLogger, SecurityLogLevel, SecurityEventType } from '../../security/index.js';
|
|
import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js';
|
|
|
|
/**
|
|
* Result of a DKIM verification
|
|
*/
|
|
export interface IDkimVerificationResult {
|
|
isValid: boolean;
|
|
domain?: string;
|
|
selector?: string;
|
|
status?: string;
|
|
details?: any;
|
|
errorMessage?: string;
|
|
signatureFields?: Record<string, string>;
|
|
}
|
|
|
|
/**
|
|
* DKIM verifier — delegates to the Rust security bridge.
|
|
*/
|
|
export class DKIMVerifier {
|
|
constructor() {}
|
|
|
|
/**
|
|
* Verify DKIM signature for an email via Rust bridge
|
|
*/
|
|
public async verify(
|
|
emailData: string,
|
|
options: {
|
|
useCache?: boolean;
|
|
returnDetails?: boolean;
|
|
} = {}
|
|
): Promise<IDkimVerificationResult> {
|
|
try {
|
|
const bridge = RustSecurityBridge.getInstance();
|
|
const results = await bridge.verifyDkim(emailData);
|
|
const first = results[0];
|
|
|
|
const result: IDkimVerificationResult = {
|
|
isValid: first?.is_valid ?? false,
|
|
domain: first?.domain ?? undefined,
|
|
selector: first?.selector ?? undefined,
|
|
status: first?.status ?? 'none',
|
|
details: options.returnDetails ? results : undefined,
|
|
};
|
|
|
|
SecurityLogger.getInstance().logEvent({
|
|
level: result.isValid ? SecurityLogLevel.INFO : SecurityLogLevel.WARN,
|
|
type: SecurityEventType.DKIM,
|
|
message: `DKIM verification ${result.isValid ? 'passed' : 'failed'} for domain ${result.domain || 'unknown'}`,
|
|
details: { selector: result.selector, status: result.status },
|
|
domain: result.domain || 'unknown',
|
|
success: result.isValid
|
|
});
|
|
|
|
logger.log(result.isValid ? 'info' : 'warn',
|
|
`DKIM verification: ${result.status} for domain ${result.domain || 'unknown'}`);
|
|
|
|
return result;
|
|
} catch (error) {
|
|
logger.log('error', `DKIM verification failed: ${error.message}`);
|
|
|
|
SecurityLogger.getInstance().logEvent({
|
|
level: SecurityLogLevel.ERROR,
|
|
type: SecurityEventType.DKIM,
|
|
message: `DKIM verification error`,
|
|
details: { error: error.message },
|
|
success: false
|
|
});
|
|
|
|
return {
|
|
isValid: false,
|
|
status: 'temperror',
|
|
errorMessage: `Verification error: ${error.message}`
|
|
};
|
|
}
|
|
}
|
|
|
|
/** No-op — Rust bridge handles its own caching */
|
|
public clearCache(): void {}
|
|
|
|
/** Always 0 — cache is managed by the Rust side */
|
|
public getCacheSize(): number {
|
|
return 0;
|
|
}
|
|
}
|