diff --git a/.env.example b/.env.example index 83fcadf..a9fb3ae 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,5 @@ -CLOUDFLARE_API_KEY= +CLOUDFLARE_API_TOKEN= CLOUDFLARE_ACCOUNT_ID= -CLOUDFLARE_ACCOUNT_EMAIL= CLOUDFLARE_LIST_ITEM_LIMIT=300000 DRY_RUN=0 FAST_MODE=0 diff --git a/.github/images/create_api_token.png b/.github/images/create_api_token.png new file mode 100644 index 0000000..19350e4 Binary files /dev/null and b/.github/images/create_api_token.png differ diff --git a/README.md b/README.md index 2b728e0..cb3ac46 100644 --- a/README.md +++ b/README.md @@ -51,9 +51,8 @@ Please note that the GitHub Action downloads the recommended blocklists and whit 1. Create a new empty, private repository. Forking or public repositories are discouraged, but supported - although the script never leaks your API keys and GitHub Actions secrets are automatically redacted from the logs, it's better to be safe than sorry. 2. Create the following GitHub Actions secrets in your repository settings: -- `CLOUDFLARE_API_KEY`: Your Cloudflare API key +- `CLOUDFLARE_API_TOKEN`: Your Cloudflare API Token with Zero Trust read and write permissions - `CLOUDFLARE_ACCOUNT_ID`: Your Cloudflare account ID -- `CLOUDFLARE_ACCOUNT_EMAIL`: Your Cloudflare account email - `CLOUDFLARE_LIST_ITEM_LIMIT`: The maximum number of blocked domains allowed for your Cloudflare Zero Trust plan. Use 300000 for the free plan or if you're unsure. - `PING_URL`: /Optional/ The HTTP(S) URL to ping (using curl) after the GitHub Action has successfully updated your filters. Useful for monitoring. diff --git a/auto_update_github_action.yml b/auto_update_github_action.yml index 8223210..47a4311 100644 --- a/auto_update_github_action.yml +++ b/auto_update_github_action.yml @@ -46,8 +46,7 @@ jobs: - name: Delete old rules and lists run: npm run cloudflare-delete env: - CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }} - CLOUDFLARE_ACCOUNT_EMAIL: ${{ secrets.CLOUDFLARE_ACCOUNT_EMAIL }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }} FAST_MODE: ${{ vars.FAST_MODE }} @@ -55,8 +54,7 @@ jobs: - name: Create new rules and lists run: npm run cloudflare-create env: - CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }} - CLOUDFLARE_ACCOUNT_EMAIL: ${{ secrets.CLOUDFLARE_ACCOUNT_EMAIL }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_LIST_ITEM_LIMIT: ${{ secrets.CLOUDFLARE_LIST_ITEM_LIMIT }} FAST_MODE: ${{ vars.FAST_MODE }} diff --git a/extended_guide.md b/extended_guide.md index 3d43c3e..8b22a19 100644 --- a/extended_guide.md +++ b/extended_guide.md @@ -16,13 +16,17 @@ https://dash.cloudflare.com/1234567890abcdef1234567890abcdef In this example, `1234567890abcdef1234567890abcdef` is the account ID. -### `CLOUDFLARE_API_KEY` +### `CLOUDFLARE_API_TOKEN` -The Cloudflare API key can be found in the [Cloudflare dashboard](https://dash.cloudflare.com/) too. Click on your profile picture (or user icon) in the top right corner, then click on "API Tokens" in the sidebar. Scroll down to the "API Keys" section and click on "View" next to the Global API Key. +Cloudflare API Token can be created in your [Cloudflare profile](https://dash.cloudflare.com/profile/api-tokens): -### `CLOUDFLARE_ACCOUNT_EMAIL` +1. Click "Create Token" and click "Get Started" in the "Create Custom Token" row. +2. Enter any name for your token +3. Add Zero Trust Read and Edit permissions for your account +4. Click "Continue to summary" and click "Create Token" +5. You will see the created API Token -The Cloudflare account email is the email address you use to log in to the Cloudflare dashboard. +![Creating API Token](.github/images/create_api_token.png) ### `CLOUDFLARE_LIST_ITEM_LIMIT` diff --git a/lib/constants.js b/lib/constants.js index 9567b91..5ed46e1 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -2,7 +2,15 @@ import dotenv from "dotenv"; dotenv.config(); -export const API_TOKEN = process.env.CLOUDFLARE_API_KEY; +if (process.env.CLOUDFLARE_API_KEY) { + console.warn( + "Using Global API Key is very risky for your Cloudflare account. It is strongly recommended to create an API Token with scoped permissions instead." + ); +} + +export const API_KEY = process.env.CLOUDFLARE_API_KEY; + +export const API_TOKEN = process.env.CLOUDFLARE_API_TOKEN; export const ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID; @@ -33,12 +41,11 @@ export const LIST_TYPE = { }; export const USER_DEFINED_ALLOWLIST_URLS = process.env.ALLOWLIST_URLS - // .filter(x => x) removes empty items from the URL arrays - ? process.env.ALLOWLIST_URLS.split("\n").filter(x => x) + ? process.env.ALLOWLIST_URLS.split("\n").filter((x) => x) : undefined; export const USER_DEFINED_BLOCKLIST_URLS = process.env.BLOCKLIST_URLS - ? process.env.BLOCKLIST_URLS.split("\n").filter(x => x) + ? process.env.BLOCKLIST_URLS.split("\n").filter((x) => x) : undefined; export const RECOMMENDED_ALLOWLIST_URLS = [ diff --git a/lib/helpers.js b/lib/helpers.js index 84b4e8f..7c92111 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,4 +1,10 @@ -import { ACCOUNT_EMAIL, ACCOUNT_ID, API_HOST, API_TOKEN } from "./constants.js"; +import { + ACCOUNT_EMAIL, + ACCOUNT_ID, + API_HOST, + API_KEY, + API_TOKEN, +} from "./constants.js"; if (!globalThis.fetch) { console.warn( @@ -20,20 +26,30 @@ if (!globalThis.fetch) { * @returns {Promise} */ const request = async (url, options) => { - if (!API_TOKEN || !ACCOUNT_ID || !ACCOUNT_EMAIL) { + if (!(API_TOKEN || API_KEY) || !ACCOUNT_ID) { throw new Error( - "One or more required secrets have not been added: CLOUDFLARE_API_KEY, CLOUDFLARE_ACCOUNT_ID, and CLOUDFLARE_ACCOUNT_EMAIL" + "The following secrets are required: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID" ); } + const headers = API_TOKEN + ? { + Authorization: `Bearer ${API_TOKEN}`, + "Content-Type": "application/json", + } + : { + Authorization: `Bearer ${API_KEY}`, + "Content-Type": "application/json", + "X-Auth-Email": ACCOUNT_EMAIL, + "X-Auth-Key": API_KEY, + }; + const response = await fetch(url, { - headers: { - Authorization: `Bearer ${API_TOKEN}`, - "Content-Type": "application/json", - "X-Auth-Email": ACCOUNT_EMAIL, - "X-Auth-Key": API_TOKEN, - }, ...options, + headers: { + ...options.headers, + ...headers, + }, }); if (!response.ok) { @@ -42,8 +58,6 @@ const request = async (url, options) => { const data = await response.json(); - console.log(`HTTP request succeeded: ${data.success}`); - return data; };