diff --git a/cf_list_create.js b/cf_list_create.js index 87d86db..bdef4eb 100644 --- a/cf_list_create.js +++ b/cf_list_create.js @@ -1,6 +1,6 @@ import fs from 'fs'; import { DRY_RUN, LIST_ITEM_LIMIT } from './lib/constants.js'; -import { createZeroTrustLists } from './lib/helpers.js'; +import { createZeroTrustLists } from './lib/api.js'; if (!process.env.CI) console.log(`List item limit set to ${LIST_ITEM_LIMIT}`); diff --git a/lib/api.js b/lib/api.js new file mode 100644 index 0000000..bd5cbfd --- /dev/null +++ b/lib/api.js @@ -0,0 +1,81 @@ +import { FAST_MODE, LIST_ITEM_SIZE } from "./constants.js"; +import { requestGateway } from "./helpers.js"; + +/** + * Creates a Zero Trust list. + * + * API docs: https://developers.cloudflare.com/api/operations/zero-trust-lists-create-zero-trust-list + * @param {string} name The name of the list. + * @param {Object[]} items The domains in the list. + * @param {string} items[].value The domain of an entry. + * @returns {Promise} + */ +const createZeroTrustList = (name, items) => + requestGateway(`/lists`, { + method: "POST", + body: JSON.stringify({ + name, + type: "DOMAIN", + items, + }), + }); + +/** + * Creates Zero Trust lists sequentially. + * @param {string[]} items The domains. + */ +const createZeroTrustListsOneByOne = async (items) => { + let totalListNumber = Math.ceil(items.length / LIST_ITEM_SIZE); + + for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) { + const chunk = items + .slice(i, i + LIST_ITEM_SIZE) + .map((item) => ({ value: item })); + const listName = `CGPS List - Chunk ${listNumber}`; + + try { + await createZeroTrustList(listName, chunk); + await sleep(); + totalListNumber--; + listNumber++; + console.log(`Created ${listName} list - ${totalListNumber} left`); + } catch (err) { + console.error(`Could not create ${listName} - ${err.toString()}`); + } + } +}; + +/** + * Creates all Zero Trust lists at once. + * @param {string[]} items The domains. + */ +const createZeroTrustListsAtOnce = async (items) => { + const totalListNumber = Math.ceil(items.length / LIST_ITEM_SIZE); + const requests = []; + + for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) { + const chunk = items + .slice(i, i + LIST_ITEM_SIZE) + .map((item) => ({ value: item })); + const listName = `CGPS List - Chunk ${listNumber}`; + + requests.push(createZeroTrustList(listName, chunk)); + listNumber++; + } + + await Promise.all(requests); + console.log(`Created ${totalListNumber} lists`); +}; + +/** + * Create Zero Trust lists. + * @param {string[]} items The domains. + * @returns {Promise} + */ +export const createZeroTrustLists = (items) => { + if (FAST_MODE) { + return createZeroTrustListsAtOnce(items); + } + + return createZeroTrustListsOneByOne(items); +}; diff --git a/lib/constants.js b/lib/constants.js index 9b528f3..5a77df5 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,10 +1,6 @@ -import { isDev } from "./utils.js"; +import dotenv from "dotenv"; -if (isDev()) { - const dotenv = await import("dotenv"); - - dotenv.config(); -} +dotenv.config(); export const API_TOKEN = process.env.CLOUDFLARE_API_KEY; diff --git a/lib/helpers.js b/lib/helpers.js index 15e23d0..69ea096 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,16 +1,13 @@ -import { - ACCOUNT_EMAIL, - ACCOUNT_ID, - API_HOST, - API_TOKEN, - FAST_MODE, - LIST_ITEM_SIZE, -} from "./constants.js"; -import { sleep } from "./utils.js"; +import { ACCOUNT_EMAIL, ACCOUNT_ID, API_HOST, API_TOKEN } from "./constants.js"; +/** + * Fires request to the specified URL. + * @param {string} url The URL to which the request will be fired. + * @param {RequestInit} options The options to be passed to `fetch`. + * @returns {Promise} + */ const request = async (url, options) => { const response = await fetch(url, { - method: "GET", headers: { Authorization: `Bearer ${API_TOKEN}`, "Content-Type": "application/json", @@ -23,62 +20,11 @@ const request = async (url, options) => { return response.json(); }; -const createZeroTrustList = (name, items) => { - // https://developers.cloudflare.com/api/operations/zero-trust-lists-create-zero-trust-list - - return request(`${API_HOST}/accounts/${ACCOUNT_ID}/gateway/lists`, { - method: "POST", - body: JSON.stringify({ - name, - type: "DOMAIN", - items, - }), - }); -}; - -const createZeroTrustListsOneByOne = async (items) => { - let totalListNumber = Math.ceil(items.length / LIST_ITEM_SIZE); - - for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) { - const chunk = items - .slice(i, i + LIST_ITEM_SIZE) - .map((item) => ({ value: item })); - const listName = `CGPS List - Chunk ${listNumber}`; - - try { - await createZeroTrustList(listName, chunk); - await sleep(); - totalListNumber--; - listNumber++; - console.log(`Created ${listName} list - ${totalListNumber} left`); - } catch (err) { - console.error(`Could not create ${listName} - ${err.toString()}`); - } - } -}; - -const createZeroTrustListsAtOnce = async (items) => { - let totalListNumber = Math.ceil(items.length / LIST_ITEM_SIZE); - const requests = []; - - for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) { - const chunk = items - .slice(i, i + LIST_ITEM_SIZE) - .map((item) => ({ value: item })); - const listName = `CGPS List - Chunk ${listNumber}`; - - requests.push(createZeroTrustList(listName, chunk)); - listNumber++; - } - - await Promise.all(requests); - console.log(`Created ${totalListNumber} lists`); -}; - -export const createZeroTrustLists = (items) => { - if (FAST_MODE) { - return createZeroTrustListsAtOnce(items); - } - - return createZeroTrustListsOneByOne(items); -}; +/** + * Fires request to the Zero Trust gateway. + * @param {string} path The path which will be appended to the request URL. + * @param {RequestInit} options The options to be passed to `fetch`. + * @returns {Promise} + */ +export const requestGateway = (path, options) => + request(`${API_HOST}/accounts/${ACCOUNT_ID}/gateway${path}`, options); diff --git a/lib/utils.js b/lib/utils.js index f717822..9c1037f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,4 +1,6 @@ -export const isDev = () => process.env.NODE_ENV !== "production"; - +/** + * Sleeps for a specified amount of time. + * @param {number} [ms=350] The amount of time in ms. + */ export const sleep = (ms = 350) => new Promise((resolve) => setTimeout(resolve, ms));