mirror of
https://github.com/Nezumi-2711/cloudflare-gateway-pihole-scripts.git
synced 2026-09-22 05:31:50 +00:00
@@ -8,3 +8,6 @@ FAST_MODE=0
|
||||
# Multiline is supported: https://github.com/motdotla/dotenv#multiline-values
|
||||
# ALLOWLIST_URLS=
|
||||
# BLOCKLIST_URLS=
|
||||
|
||||
# Optional Discord webhook URL to send a message to when a script is done running or if an error occurs.
|
||||
# DISCORD_WEBHOOK_URL=
|
||||
|
||||
@@ -30,6 +30,7 @@ Cloudflare Gateway allows you to create custom rules to filter HTTP, DNS, and ne
|
||||
3. Cloudflare email, API key (NOT the API token), and account ID
|
||||
4. A file containing the domains you want to block - **max 300,000 domains for the free plan** - in the working directory named `blocklist.txt`. Mullvad provides awesome [DNS blocklists](https://github.com/mullvad/dns-blocklists) that work well with this project. A script that downloads recommended blocklists, `download_lists.js`, is included.
|
||||
5. Optional: You can whitelist domains by putting them in a file `allowlist.txt`. You can also use the `get_recomended_whitelist.sh` Bash script to get the recommended whitelists.
|
||||
6. Optional: A Discord (or similar) webhook URL to send notifications to.
|
||||
|
||||
### Running locally
|
||||
|
||||
@@ -55,6 +56,7 @@ Please note that the GitHub Action downloads the recommended blocklists and whit
|
||||
- `CLOUDFLARE_ACCOUNT_ID`: Your Cloudflare account ID
|
||||
- `CLOUDFLARE_LIST_ITEM_LIMIT`: The maximum number of blocked domains allowed for your Cloudflare Zero Trust plan. Default to 300,000. Optional if you are using the free plan.
|
||||
- `PING_URL`: /Optional/ The HTTP(S) URL to ping (using curl) after the GitHub Action has successfully updated your filters. Useful for monitoring.
|
||||
- `DISCORD_WEBHOOK_URL`: /Optional/ The Discord (or similar) webhook URL to send notifications to. Good for monitoring as well.
|
||||
|
||||
3. Create the following GitHub Actions variables in your repository settings if you desire:
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ jobs:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }}
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
FAST_MODE: ${{ vars.FAST_MODE }}
|
||||
|
||||
- name: Create new rules and lists
|
||||
@@ -57,6 +58,7 @@ jobs:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }}
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
FAST_MODE: ${{ vars.FAST_MODE }}
|
||||
|
||||
- name: Send ping request
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createZeroTrustRule, getZeroTrustLists } from "./lib/api.js";
|
||||
import { notifyWebhook } from "./lib/helpers.js";
|
||||
|
||||
const { result: lists } = await getZeroTrustLists();
|
||||
const wirefilterExpression = lists.reduce((previous, current) => {
|
||||
@@ -10,3 +11,5 @@ const wirefilterExpression = lists.reduce((previous, current) => {
|
||||
console.log("Creating rule...");
|
||||
// Remove the trailing ' or '
|
||||
await createZeroTrustRule(wirefilterExpression.slice(0, -4));
|
||||
// Send a notification to the webhook
|
||||
await notifyWebhook("CF Gateway Rule Create script finished running");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { deleteZeroTrustRule, getZeroTrustRules } from "./lib/api.js";
|
||||
import { notifyWebhook } from "./lib/helpers.js";
|
||||
|
||||
const { result: rules } = await getZeroTrustRules();
|
||||
const cgpsRule = rules.find(({ name }) => name === "CGPS Filter Lists");
|
||||
@@ -14,3 +15,5 @@ const cgpsRule = rules.find(({ name }) => name === "CGPS Filter Lists");
|
||||
console.log(`Deleting rule ${cgpsRule.name}...`);
|
||||
await deleteZeroTrustRule(cgpsRule.id);
|
||||
})();
|
||||
// Send a notification to the webhook
|
||||
await notifyWebhook("CF Gateway Rule Create script finished running");
|
||||
|
||||
+5
-1
@@ -12,7 +12,7 @@ import {
|
||||
LIST_ITEM_SIZE,
|
||||
PROCESSING_FILENAME,
|
||||
} from "./lib/constants.js";
|
||||
import { normalizeDomain } from "./lib/helpers.js";
|
||||
import { normalizeDomain, notifyWebhook } from "./lib/helpers.js";
|
||||
import {
|
||||
extractDomain,
|
||||
isComment,
|
||||
@@ -143,8 +143,12 @@ console.log("\n\n");
|
||||
|
||||
if (FAST_MODE) {
|
||||
await createZeroTrustListsAtOnce(domains);
|
||||
// TODO: make this less repetitive
|
||||
await notifyWebhook(`CF List Create script finished running (${domains.length} domains, ${numberOfLists} lists)`);
|
||||
return;
|
||||
}
|
||||
|
||||
await createZeroTrustListsOneByOne(domains);
|
||||
|
||||
await notifyWebhook(`CF List Create script finished running (${domains.length} domains, ${numberOfLists} lists)`);
|
||||
})();
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
getZeroTrustLists,
|
||||
} from "./lib/api.js";
|
||||
import { FAST_MODE } from "./lib/constants.js";
|
||||
import { notifyWebhook } from "./lib/helpers.js";
|
||||
|
||||
(async () => {
|
||||
const { result: lists } = await getZeroTrustLists();
|
||||
@@ -32,8 +33,12 @@ import { FAST_MODE } from "./lib/constants.js";
|
||||
|
||||
if (FAST_MODE) {
|
||||
await deleteZeroTrustListsAtOnce(cgpsLists);
|
||||
// TODO: make this less repetitive
|
||||
await notifyWebhook(`CF List Delete script finished running (${cgpsLists.length} lists)`);
|
||||
return;
|
||||
}
|
||||
|
||||
await deleteZeroTrustListsOneByOne(cgpsLists);
|
||||
|
||||
await notifyWebhook(`CF List Delete script finished running (${cgpsLists.length} lists)`);
|
||||
})();
|
||||
|
||||
@@ -19,6 +19,53 @@ if (!globalThis.fetch) {
|
||||
globalThis.fetch = (await import("node-fetch")).default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to a Discord-compatible webhook.
|
||||
* @param {url|string} url The webhook URL.
|
||||
* @param {string} message The message to be sent.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function sendMessageToWebhook(url, message) {
|
||||
// Create the payload object with the message
|
||||
const payload = { content: message };
|
||||
|
||||
// Send a POST request to the webhook url with the payload as JSON
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
// Check if the request was successful
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error sending message to webhook:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a CGPS notification to a Discord-compatible webhook.
|
||||
* Automatically checks if the webhook URL exists.
|
||||
* @param {string} msg The message to be sent.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export async function notifyWebhook(msg) {
|
||||
// Check if the webhook URL exists
|
||||
const webhook_url = process.env.DISCORD_WEBHOOK_URL;
|
||||
|
||||
if (webhook_url || !webhook_url.startsWith('http')) {
|
||||
// Send the message to the webhook
|
||||
await sendMessageToWebhook(webhook_url, `CGPS: ${msg}`);
|
||||
}
|
||||
// Not logging the lack of a webhook URL since it's not a feature everyone would use
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires request to the specified URL.
|
||||
* @param {string} url The URL to which the request will be fired.
|
||||
@@ -53,6 +100,8 @@ const request = async (url, options) => {
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
// Send a message to the Discord webhook if it exists
|
||||
await notifyWebhook(`An HTTP error has occurred (${response.status}) while making a web request. Please check the logs for further details.`);
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user