/** * Sender blocklist checking with wildcard / glob support * * Uses picomatch for pattern matching (equivalent to Python's fnmatch). * Patterns are stored per-recipient in DynamoDB. */ import picomatch from 'picomatch'; import type { DynamoDBHandler } from '../aws/dynamodb.js'; import { log } from '../logger.js'; /** * Extract the bare email address from a From header value. * "John Doe " → "john@example.com" */ function extractAddress(sender: string): string { const match = sender.match(/<([^>]+)>/); const addr = match ? match[1] : sender; return addr.trim().toLowerCase(); } export class BlocklistChecker { constructor(private dynamodb: DynamoDBHandler) {} /** * Batch-check whether a sender is blocked for each recipient. * Uses a single batch DynamoDB call for efficiency. */ async batchCheckBlockedSenders( recipients: string[], senders: string[], // <-- Geändert zu Array workerName: string, ): Promise> { const patternsByRecipient = await this.dynamodb.batchGetBlockedPatterns(recipients); // Alle übergebenen Adressen bereinigen const sendersClean = senders.map(s => extractAddress(s)).filter(Boolean); const result: Record = {}; for (const recipient of recipients) { const patterns = patternsByRecipient[recipient] ?? []; let isBlocked = false; for (const pattern of patterns) { for (const senderClean of sendersClean) { if (picomatch.isMatch(senderClean, pattern.toLowerCase())) { log( `⛔ BLOCKED: Sender ${senderClean} matches pattern '${pattern}' for inbox ${recipient}`, 'WARNING', workerName, ); isBlocked = true; break; } } if (isBlocked) break; } result[recipient] = isBlocked; } return result; } }