63 lines
1.9 KiB
TypeScript
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;
|
|
}
|
|
}
|