cloudflare-discord-notifs/index.js

113 lines
4.6 KiB
JavaScript

require('dotenv').config();
const axios = require('axios').default;
const fs = require('fs');
const Discord = require('discord.js');
const API_BASE_URL = 'https://api.cloudflare.com/client/v4';
const { CF_TOKEN, CF_ZONES_BLACKLIST, WEBHOOK_ID, WEBHOOK_SECRET } = process.env;
if (!CF_TOKEN)
return console.log("Error: Env var 'CF_TOKEN' is not set");
if (!WEBHOOK_ID)
return console.log("Error: Env var 'WEBHOOK_ID' is not set");
if (!WEBHOOK_SECRET)
return console.log("Error: Env var 'WEBHOOK_SECRET' is not set");
if (CF_ZONES_BLACKLIST)
console.log("Info: 'CF_ZONES_BLACKLIST' is set");
const client = new Discord.WebhookClient(WEBHOOK_ID, WEBHOOK_SECRET);
const ZONES_BLACKLIST = CF_ZONES_BLACKLIST?.split(',') || [];
async function refresh(zone) {
if (!fs.existsSync('./last_request')) await fs.promises.writeFile('./last_request', '' + (Date.now() - (1000 * 60 * 60 * 24) + 10000));
let lowerDate = new Date();
let upperDate = new Date();
lowerDate.setTime(await fs.promises.readFile('./last_request'));
if (upperDate.getTime() - lowerDate.getTime() > 1000 * 60 * 60 * 24) lowerDate.setTime((Date.now() - (1000 * 60 * 60 * 24) + 10000));
let payload = `{ "query":
"query ListFirewallEvents($zoneTag: string, $filter: FirewallEventsAdaptiveFilter_InputObject) {
viewer {
zones(filter: { zoneTag: $zoneTag }) {
firewallEventsAdaptive(
filter: $filter
limit: 10
orderBy: [datetime_DESC]
) {
action
clientCountryName
clientIP
clientIPClass
clientRequestHTTPHost
clientRequestHTTPMethodName
clientRequestScheme
clientRequestPath
clientRequestQuery
datetime
source
userAgent
clientRefererHost
clientRefererPath
ruleId
}
}
}
}",
"variables": {
"zoneTag": "${zone.id}",
"filter": {
"datetime_geq": "${lowerDate.toISOString()}",
"datetime_leq": "${upperDate.toISOString()}"
}
}
}`.replace(/\n/g, '');
let res = await axios.post(
`${API_BASE_URL}/graphql/`,
payload,
{
headers: {
'Authorization': `Bearer ${CF_TOKEN}`
}
}
);
let eventsPerZone = res.data.data?.viewer?.zones;
if (!(eventsPerZone instanceof Array))
return console.log(res.data);
await fs.promises.writeFile('./last_request', '' + upperDate.getTime());
eventsPerZone.forEach(events => {
events.firewallEventsAdaptive.forEach(event => {
console.log(`[${zone.name}] Info: New firewall event`);
client.send(
new Discord.MessageEmbed()
.setTitle('Retard deflected')
.setColor('#f6821f')
.setAuthor(`Cloudflare - ${event.clientRequestHTTPHost || zone.name}`, 'https://pbs.twimg.com/profile_images/1313131647315910666/opulcRqc.jpg')
.setDescription(`${event.source} - ${event.ruleId}`)
.addField('Firewall Action', event.action, true)
.addField('IP Address', `${event.clientIP} (${event.clientCountryName}` +
`${event.clientIPClass != 'unknown' ? ` - ${event.clientIPClass}` : ''})`, true)
.addField('\u200b', '\u200b')
.addField('Request', `${event.clientRequestHTTPMethodName} ${event.clientRequestPath}${event.clientRequestQuery}` +
`${event.clientRefererHost ? `\nReferer: ${event.clientRefererHost}${event.clientRefererPath}` : ''}`, true)
.addField('User Agent', `${event.userAgent}`, true)
.setTimestamp(event.datetime)
)
});
});
}
(async () => {
let { data: zones } = await axios.get(`${API_BASE_URL}/zones`, { headers: { 'Authorization': 'Bearer ' + CF_TOKEN } });
if (!zones.result) return console.log(zones);
let total = 0;
zones.result.forEach(async zone => {
if (ZONES_BLACKLIST.indexOf(zone.id) == -1) {
total++;
refresh(zone);
setInterval(() => refresh(zone), 1000 * 15);
}
});
console.log(`Info: Monitoring ${total} zone${total != 1 ? 's' : ''}`);
})();