1.1.6: Migrate to .env, bugfixes

This commit is contained in:
Sefinek 2024-09-18 12:29:19 +02:00
parent 6fef5548e5
commit 140a142243
6 changed files with 74 additions and 44 deletions

View file

@ -1,13 +1,40 @@
# production or development
NODE_ENV=production
# Cloudflare: https://dash.cloudflare.com/profile/api-tokens
############################### TOKENS ###############################
# Cloudflare (https://dash.cloudflare.com/profile/api-tokens)
CLOUDFLARE_EMAIL=
CLOUDFLARE_ZONE_ID=
CLOUDFLARE_API_KEY=
CLOUDFLARE_ZONE_ID=00000000000000000000000000000000
CLOUDFLARE_API_KEY=0000000000000000000000000000000000000000
# AbuseIPDB: https://www.abuseipdb.com/account/api
ABUSEIPDB_API_KEY=
# AbuseIPDB (https://www.abuseipdb.com/account/api)
ABUSEIPDB_API_KEY=00000000000000000000000000000000000000000000000000000000000000000000000000000000
# API key for api.sefinek.net. Contact me at contact@sefinek.net to obtain it and contribute to the sefinek24/Malicious-IP-Addresses. Leave empty if you don't have a token.
SEFINEK_API_SECRET=
############################### CYCLES ###############################
# Main interval (in minutes) of each cycle.
CYCLE_INTERVAL=120
# The minimum time that must pass after reporting an IP address before it can be reported again.
# The required time is >= 15 minutes, according to AbuseIPDB API limits.
REPORTED_IP_COOLDOWN_MS=6
# The maximum URI length that can be reported to AbuseIPDB.
# If Cloudflare returns a longer URI, the API request will fail.
MAX_URL_LENGTH=920
# Additional delay (in seconds) after each successful IP report to avoid overloading the AbuseIPDB API.
SUCCESS_COOLDOWN_MS=2
# Interval for refreshing your IP address (in minutes).
# This ensures that WAF violations originating from your IP address are not reported to AbuseIPDB.
IP_REFRESH_INTERVAL=80
############################### SEFINEK API ###############################
# Report IP addresses to api.sefinek.net to support the development of the repository at https://github.com/sefinek24/Malicious-IP-Addresses. SEFINEK_API_SECRET is required if true.
REPORT_TO_SEFINEK_API=true
# How often should the log (reported_ips.csv) be analyzed and sent to the Sefinek API? In minutes.
SEFINEK_API_INTERVAL=60

View file

@ -1,26 +1,25 @@
// Main interval of each cycle.
// In production mode, it's 2 hours, and in development mode, it's 8 seconds.
const CYCLE_INTERVAL = process.env.NODE_ENV === 'production' ? 2 * 60 * 60 * 1000 : 8 * 1000;
const CYCLE_INTERVAL = process.env.NODE_ENV === 'production' ?
parseInt(process.env.CYCLE_INTERVAL) * 60 * 1000 : 8 * 1000;
// The minimum time that must pass after reporting an IP address before it can be reported again.
// The required time is >= 15 minutes, according to AbuseIPDB API limits.
const REPORTED_IP_COOLDOWN_MS = 6 * 60 * 60 * 1000; // 6h
const REPORTED_IP_COOLDOWN_MS = parseInt(process.env.REPORTED_IP_COOLDOWN_MS) * 60 * 60 * 1000;
// The maximum URI length that can be reported to AbuseIPDB.
// If Cloudflare returns a longer URI, the API request will fail.
const MAX_URL_LENGTH = 920;
const MAX_URL_LENGTH = parseInt(process.env.MAX_URL_LENGTH);
// Additional delay after each successful IP report to avoid overloading the AbuseIPDB API.
const SUCCESS_COOLDOWN_MS = 2 * 1000; // 2s
const SUCCESS_COOLDOWN_MS = parseInt(process.env.SUCCESS_COOLDOWN_MS);
// Interval for refreshing your IP address.
// This ensures that WAF violations originating from your IP address are not reported to AbuseIPDB.
const IP_REFRESH_INTERVAL = 80 * 60 * 1000; // 80m
const IP_REFRESH_INTERVAL = parseInt(process.env.IP_REFRESH_INTERVAL) * 60 * 1000;
// Report IP addresses to api.sefinek.net to support the development of the repository at https://github.com/sefinek24/Malicious-IP-Addresses. If true, please see the .env file.
const REPORT_TO_SEFINEK_API = true;
const REPORT_TO_SEFINEK_API = process.env.REPORT_TO_SEFINEK_API === 'true';
// How often should the log (reported_ips.csv) be analyzed and sent to the Sefinek API?
const SEFINEK_API_INTERVAL = process.env.NODE_ENV === 'production' ? 60 * 60 * 1000 : 5 * 1000;
const SEFINEK_API_INTERVAL = process.env.NODE_ENV === 'production' ?
parseInt(process.env.SEFINEK_API_INTERVAL) * 60 * 1000 : 5 * 1000;
module.exports = { CYCLE_INTERVAL, REPORTED_IP_COOLDOWN_MS, MAX_URL_LENGTH, SUCCESS_COOLDOWN_MS, IP_REFRESH_INTERVAL, REPORT_TO_SEFINEK_API, SEFINEK_API_INTERVAL };
module.exports = {
CYCLE_INTERVAL,
REPORTED_IP_COOLDOWN_MS,
MAX_URL_LENGTH,
SUCCESS_COOLDOWN_MS,
IP_REFRESH_INTERVAL,
REPORT_TO_SEFINEK_API,
SEFINEK_API_INTERVAL
};

View file

@ -30,16 +30,20 @@ const fetchBlockedIPs = async () => {
};
const isIPReportedRecently = (rayId, ip, reportedIPs) => {
const lastReport = reportedIPs.find(entry =>
(entry.rayId === rayId || entry.ip === ip) &&
(entry.action === 'REPORTED' || entry.action === 'TOO_MANY_REQUESTS')
);
const lastReport = reportedIPs.reduce((latest, entry) => {
if (
(entry.rayId === rayId || entry.ip === ip) &&
(entry.status === 'TOO_MANY_REQUESTS' || entry.status === 'REPORTED') &&
(!latest || entry.timestamp > latest.timestamp)
) return entry;
return latest;
}, null);
if (lastReport) {
const lastTimestamp = new Date(lastReport.timestamp).getTime();
const currentTime = Date.now();
const timeDifference = currentTime - lastTimestamp;
if (timeDifference < REPORTED_IP_COOLDOWN_MS) return { recentlyReported: true, timeDifference };
const timeDifference = Date.now() - lastReport.timestamp;
if (timeDifference < REPORTED_IP_COOLDOWN_MS) {
return { recentlyReported: true, timeDifference, reason: lastReport.status === 'TOO_MANY_REQUESTS' ? 'RATE-LIMITED' : 'REPORTED' };
}
}
return { recentlyReported: false };
@ -96,7 +100,7 @@ const reportIP = async (event, country, hostname, endpoint, userAgent, cycleErro
// Sefinek API
if (REPORT_TO_SEFINEK_API && SEFINEK_API_INTERVAL && process.env.SEFINEK_API_SECRET) {
setInterval(async () => await SefinekAPI(), SEFINEK_API_INTERVAL);
setInterval(SefinekAPI, SEFINEK_API_INTERVAL);
}
// Ready
@ -111,7 +115,7 @@ const reportIP = async (event, country, hostname, endpoint, userAgent, cycleErro
// AbuseIPDB
let cycleId = 1;
while (true) {
log('log', `===================== New Reporting Cycle (v${moduleVersion}) =====================`);
log('log', `================ New Reporting Cycle v${moduleVersion}; ID: ${cycleId} ================`);
const blockedIPEvents = await fetchBlockedIPs();
if (!blockedIPEvents) {
@ -136,12 +140,13 @@ const reportIP = async (event, country, hostname, endpoint, userAgent, cycleErro
}
const reportedIPs = readReportedIPs();
const { recentlyReported, timeDifference } = isIPReportedRecently(event.rayName, ip, reportedIPs);
const { recentlyReported, timeDifference, reason } = isIPReportedRecently(event.rayName, ip, reportedIPs);
if (recentlyReported) {
const hoursAgo = Math.floor(timeDifference / (1000 * 60 * 60));
const minutesAgo = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
const secondsAgo = Math.floor((timeDifference % (1000 * 60)) / 1000);
log('log', `${ip} was reported or rate-limited ${hoursAgo}h ${minutesAgo}m ${secondsAgo}s ago. Skipping...`);
log('log', `${ip} was ${reason} ${hoursAgo}h ${minutesAgo}m ${secondsAgo}s ago. Skipping...`);
cycleSkippedCount++;
continue;
}
@ -164,7 +169,6 @@ const reportIP = async (event, country, hostname, endpoint, userAgent, cycleErro
}
}
log('log', `Cycle Summary [${cycleId}]:`);
log('log', `- Reported IPs: ${cycleReportedCount}`);
log('log', `- Total IPs processed: ${cycleProcessedCount}`);
log('log', `- Skipped IPs: ${cycleSkippedCount}`);
@ -172,7 +176,7 @@ const reportIP = async (event, country, hostname, endpoint, userAgent, cycleErro
log('log', `- 429 Too Many Requests: ${cycleErrorCounts.blocked}`);
log('log', `- No response errors: ${cycleErrorCounts.noResponse}`);
log('log', `- Other errors: ${cycleErrorCounts.otherErrors}`);
log('log', '==================== End of Reporting Cycle ====================');
log('log', '===================== End of Reporting Cycle =====================');
log('log', `Waiting ${formatDelay(CYCLE_INTERVAL)}...`);
cycleId++;

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "waf-to-abuseipdb",
"version": "1.1.5",
"version": "1.1.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "waf-to-abuseipdb",
"version": "1.1.5",
"version": "1.1.6",
"license": "MIT",
"dependencies": {
"axios": "^1.7.7",

View file

@ -1,6 +1,6 @@
{
"name": "waf-to-abuseipdb",
"version": "1.1.5",
"version": "1.1.6",
"description": "A Node.js project that enables automatic reporting of incidents detected by Cloudflare WAF to the AbuseIPDB database.",
"keywords": [
"abuseipdb",
@ -20,7 +20,7 @@
"url": "git+https://github.com/sefinek24/Node-Cloudflare-WAF-AbuseIPDB.git"
},
"license": "MIT",
"author": "Sefinek <contact@nekosia.cat> (https://sefinek.net)",
"author": "Sefinek <contact@sefinek.net> (https://sefinek.net)",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",

View file

@ -8,7 +8,7 @@ const SEFINEK_API_URL = process.env.SEFINEK_API_URL || `${process.env.NODE_ENV =
module.exports = async () => {
const userIp = clientIp.getAddress();
const reportedIPs = readReportedIPs().filter(x => x.status === 'REPORTED' && x.ip !== userIp && !x.sefinekAPI);
if (reportedIPs.length === 0) return log('log', 'No IPs with `action Reported` and `SefinekAPI false` to send to Sefinek API');
if (reportedIPs.length === 0) return;
const uniqueLogs = reportedIPs.reduce((acc, ip) => {
if (acc.seen.has(ip.ip)) return acc;