Merge branch 'main' into v1

This commit is contained in:
mrrfv
2023-11-08 23:05:12 +01:00
8 changed files with 72 additions and 1 deletions
+3
View File
@@ -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=
+2
View File
@@ -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:
+2
View File
@@ -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
+3
View File
@@ -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");
+3
View File
@@ -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
View File
@@ -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)`);
})();
+5
View File
@@ -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)`);
})();
+49
View File
@@ -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}`);
}