email-amazon/email-worker-nodejs/src/email/blocklist.ts

63 lines
1.9 KiB
TypeScript

/**
* 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>" → "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<Record<string, boolean>> {
const patternsByRecipient = await this.dynamodb.batchGetBlockedPatterns(recipients);
// Alle übergebenen Adressen bereinigen
const sendersClean = senders.map(s => extractAddress(s)).filter(Boolean);
const result: Record<string, boolean> = {};
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;
}
}