68 lines
2.1 KiB
JavaScript
68 lines
2.1 KiB
JavaScript
const logger = require('./logger');
|
|
const BANNED_DOMAINS = new Set();
|
|
const DOMAIN_REQUEST_COUNTS = new Map();
|
|
const RATE_LIMIT = 10; // 每分钟10封邮件
|
|
const TIME_WINDOW = 60 * 1000; // 1分钟
|
|
const BAN_DURATION = 5 * 60 * 1000; // 5分钟
|
|
|
|
function getDomainFromEmail(sender) {
|
|
if (!sender) {
|
|
return null;
|
|
}
|
|
|
|
let emailAddress = sender;
|
|
|
|
// 检查 "Name <email@domain.com>" 格式
|
|
const match = sender.match(/<([^>]+)>/);
|
|
if (match && match[1]) {
|
|
emailAddress = match[1]; // 提取 'email@domain.com'
|
|
}
|
|
|
|
// 现在,从(可能已清理的)电子邮件地址中提取域名
|
|
if (!emailAddress.includes('@')) {
|
|
return null;
|
|
}
|
|
|
|
return emailAddress.split('@')[1];
|
|
}
|
|
|
|
function isRateLimited(sender) {
|
|
const domain = getDomainFromEmail(sender);
|
|
if (!domain) {
|
|
// 如果无法从发件人中提取域名,则不进行速率限制
|
|
return false;
|
|
}
|
|
|
|
if (BANNED_DOMAINS.has(domain)) {
|
|
logger.warn(`Domain ${domain} is currently banned, rejecting email.`, { domain, action: 'reject-banned-domain' });
|
|
return true;
|
|
}
|
|
|
|
const now = Date.now();
|
|
const requests = DOMAIN_REQUEST_COUNTS.get(domain) || [];
|
|
|
|
// 过滤掉时间窗口之外的旧请求
|
|
const recentRequests = requests.filter(timestamp => now - timestamp < TIME_WINDOW);
|
|
|
|
if (recentRequests.length >= RATE_LIMIT) {
|
|
logger.warn(`Domain ${domain} has exceeded the rate limit. Banning for ${BAN_DURATION / 1000} seconds.`, { domain, action: 'ban-domain' });
|
|
BANNED_DOMAINS.add(domain);
|
|
// 设置解封计时器
|
|
setTimeout(() => {
|
|
BANNED_DOMAINS.delete(domain);
|
|
logger.info(`Domain ${domain} has been unbanned.`, { domain, action: 'unban-domain' });
|
|
}, BAN_DURATION);
|
|
// 清空该域名的请求记录
|
|
DOMAIN_REQUEST_COUNTS.delete(domain);
|
|
return true;
|
|
}
|
|
|
|
// 记录当前请求时间
|
|
recentRequests.push(now);
|
|
DOMAIN_REQUEST_COUNTS.set(domain, recentRequests);
|
|
|
|
return false;
|
|
}
|
|
|
|
module.exports = { isRateLimited };
|