mirror of
https://github.com/Nezumi-2711/cloudflare-gateway-pihole-scripts.git
synced 2026-09-22 13:38:37 +00:00
@@ -8,3 +8,6 @@ FAST_MODE=0
|
|||||||
# Multiline is supported: https://github.com/motdotla/dotenv#multiline-values
|
# Multiline is supported: https://github.com/motdotla/dotenv#multiline-values
|
||||||
# ALLOWLIST_URLS=
|
# ALLOWLIST_URLS=
|
||||||
# BLOCKLIST_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
|
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.
|
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.
|
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
|
### 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_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.
|
- `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.
|
- `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:
|
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_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }}
|
CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }}
|
||||||
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
FAST_MODE: ${{ vars.FAST_MODE }}
|
FAST_MODE: ${{ vars.FAST_MODE }}
|
||||||
|
|
||||||
- name: Create new rules and lists
|
- name: Create new rules and lists
|
||||||
@@ -57,6 +58,7 @@ jobs:
|
|||||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }}
|
CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }}
|
||||||
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
FAST_MODE: ${{ vars.FAST_MODE }}
|
FAST_MODE: ${{ vars.FAST_MODE }}
|
||||||
|
|
||||||
- name: Send ping request
|
- name: Send ping request
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createZeroTrustRule, getZeroTrustLists } from "./lib/api.js";
|
import { createZeroTrustRule, getZeroTrustLists } from "./lib/api.js";
|
||||||
|
import { notifyWebhook } from "./lib/helpers.js";
|
||||||
|
|
||||||
const { result: lists } = await getZeroTrustLists();
|
const { result: lists } = await getZeroTrustLists();
|
||||||
const wirefilterExpression = lists.reduce((previous, current) => {
|
const wirefilterExpression = lists.reduce((previous, current) => {
|
||||||
@@ -10,3 +11,5 @@ const wirefilterExpression = lists.reduce((previous, current) => {
|
|||||||
console.log("Creating rule...");
|
console.log("Creating rule...");
|
||||||
// Remove the trailing ' or '
|
// Remove the trailing ' or '
|
||||||
await createZeroTrustRule(wirefilterExpression.slice(0, -4));
|
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 { deleteZeroTrustRule, getZeroTrustRules } from "./lib/api.js";
|
||||||
|
import { notifyWebhook } from "./lib/helpers.js";
|
||||||
|
|
||||||
const { result: rules } = await getZeroTrustRules();
|
const { result: rules } = await getZeroTrustRules();
|
||||||
const cgpsRule = rules.find(({ name }) => name === "CGPS Filter Lists");
|
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}...`);
|
console.log(`Deleting rule ${cgpsRule.name}...`);
|
||||||
await deleteZeroTrustRule(cgpsRule.id);
|
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,
|
LIST_ITEM_SIZE,
|
||||||
PROCESSING_FILENAME,
|
PROCESSING_FILENAME,
|
||||||
} from "./lib/constants.js";
|
} from "./lib/constants.js";
|
||||||
import { normalizeDomain } from "./lib/helpers.js";
|
import { normalizeDomain, notifyWebhook } from "./lib/helpers.js";
|
||||||
import {
|
import {
|
||||||
extractDomain,
|
extractDomain,
|
||||||
isComment,
|
isComment,
|
||||||
@@ -143,8 +143,12 @@ console.log("\n\n");
|
|||||||
|
|
||||||
if (FAST_MODE) {
|
if (FAST_MODE) {
|
||||||
await createZeroTrustListsAtOnce(domains);
|
await createZeroTrustListsAtOnce(domains);
|
||||||
|
// TODO: make this less repetitive
|
||||||
|
await notifyWebhook(`CF List Create script finished running (${domains.length} domains, ${numberOfLists} lists)`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await createZeroTrustListsOneByOne(domains);
|
await createZeroTrustListsOneByOne(domains);
|
||||||
|
|
||||||
|
await notifyWebhook(`CF List Create script finished running (${domains.length} domains, ${numberOfLists} lists)`);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
getZeroTrustLists,
|
getZeroTrustLists,
|
||||||
} from "./lib/api.js";
|
} from "./lib/api.js";
|
||||||
import { FAST_MODE } from "./lib/constants.js";
|
import { FAST_MODE } from "./lib/constants.js";
|
||||||
|
import { notifyWebhook } from "./lib/helpers.js";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const { result: lists } = await getZeroTrustLists();
|
const { result: lists } = await getZeroTrustLists();
|
||||||
@@ -32,8 +33,12 @@ import { FAST_MODE } from "./lib/constants.js";
|
|||||||
|
|
||||||
if (FAST_MODE) {
|
if (FAST_MODE) {
|
||||||
await deleteZeroTrustListsAtOnce(cgpsLists);
|
await deleteZeroTrustListsAtOnce(cgpsLists);
|
||||||
|
// TODO: make this less repetitive
|
||||||
|
await notifyWebhook(`CF List Delete script finished running (${cgpsLists.length} lists)`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await deleteZeroTrustListsOneByOne(cgpsLists);
|
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;
|
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.
|
* Fires request to the specified URL.
|
||||||
* @param {string} url The URL to which the request will be fired.
|
* @param {string} url The URL to which the request will be fired.
|
||||||
@@ -53,6 +100,8 @@ const request = async (url, options) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
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}`);
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user