forked from mrrfv/cloudflare-gateway-pihole-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcf_list_create.js
181 lines (156 loc) · 6.19 KB
/
cf_list_create.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
require("dotenv").config();
const fs = require('fs');
const axios = require('axios');
const API_TOKEN = process.env.CLOUDFLARE_API_KEY;
const ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID;
const ACCOUNT_EMAIL = process.env.CLOUDFLARE_ACCOUNT_EMAIL;
const LIST_ITEM_LIMIT = Number.isSafeInteger(Number(process.env.CLOUDFLARE_LIST_ITEM_LIMIT)) ? Number(process.env.CLOUDFLARE_LIST_ITEM_LIMIT) : 300000;
if (!process.env.CI) console.log(`List item limit set to ${LIST_ITEM_LIMIT}`);
let whitelist = []; // Define an empty array for the whitelist
// Read whitelist.csv and parse
fs.readFile('whitelist.csv', 'utf8', async (err, data) => {
if (err) {
console.warn('Error reading whitelist.csv:', err);
console.warn('Assuming whitelist is empty.')
} else {
// Convert into array and cleanup whitelist
const domainValidationPattern = /^(?!-)[A-Za-z0-9-]+([\-\.]{1}[a-z0-9]+)*\.[A-Za-z]{2,6}$/;
whitelist = data.split('\n').filter(domain => {
// Remove entire lines starting with "127.0.0.1" or "::1", empty lines or comments
return domain && !domain.startsWith('#') && !domain.startsWith('//') && !domain.startsWith('/*') && !domain.startsWith('*/') && !(domain === '\r');
}).map(domain => {
// Remove "\r", "0.0.0.0 ", "127.0.0.1 ", "::1 " and similar from domain items
return domain
.replace('\r', '')
.replace('0.0.0.0 ', '')
.replace('127.0.0.1 ', '')
.replace('::1 ', '')
.replace(':: ', '')
.replace('||', '')
.replace('@@||', '')
.replace('^$important', '')
.replace('*.', '')
.replace('^', '');
}).filter(domain => {
return domainValidationPattern.test(domain);
});
console.log(`Found ${whitelist.length} valid domains in whitelist.`);
}
});
// Read input.csv and parse domains
fs.readFile('input.csv', 'utf8', async (err, data) => {
if (err) {
console.error('Error reading input.csv:', err);
return;
}
// Convert into array and cleanup input
const domainValidationPattern = /^(?!-)[A-Za-z0-9-]+([\-\.]{1}[a-z0-9]+)*\.[A-Za-z]{2,6}$/;
let domains = data.split('\n').filter(domain => {
// Remove entire lines starting with "127.0.0.1" or "::1", empty lines or comments
return domain && !domain.startsWith('#') && !domain.startsWith('//') && !domain.startsWith('/*') && !domain.startsWith('*/') && !(domain === '\r');
}).map(domain => {
// Remove "\r", "0.0.0.0 ", "127.0.0.1 ", "::1 " and similar from domain items
return domain
.replace('\r', '')
.replace('0.0.0.0 ', '')
.replace('127.0.0.1 ', '')
.replace('::1 ', '')
.replace(':: ', '')
.replace('^', '')
.replace('||', '')
.replace('@@||', '')
.replace('^$important', '')
.replace('*.', '')
.replace('^', '');
}).filter(domain => {
return domainValidationPattern.test(domain);
});
// Check for duplicates in domains array
let uniqueDomains = [];
let seen = new Set(); // Use a set to store seen values
for (let domain of domains) {
if (!seen.has(domain)) { // If the domain is not in the set
seen.add(domain); // Add it to the set
uniqueDomains.push(domain); // Push the domain to the uniqueDomains array
} else { // If the domain is in the set
console.warn(`Duplicate domain found: ${domain} - removing`); // Log the duplicate domain
}
}
// Replace domains array with uniqueDomains array
domains = uniqueDomains;
// Remove domains from the domains array that are present in the whitelist array
domains = domains.filter(domain => {
if (whitelist.includes(domain)) {
console.warn(`Domain found in the whitelist: ${domain} - removing`);
return false;
}
return true;
});
// Trim array to 300,000 domains if it's longer than that
if (domains.length > LIST_ITEM_LIMIT) {
domains = trimArray(domains, LIST_ITEM_LIMIT);
console.warn(`More than ${LIST_ITEM_LIMIT} domains found in input.csv - input has to be trimmed`);
}
const listsToCreate = Math.ceil(domains.length / 1000);
if (!process.env.CI) console.log(`Found ${domains.length} valid domains in input.csv after cleanup - ${listsToCreate} list(s) will be created`);
// Separate domains into chunks of 1000 (Cloudflare list cap)
const chunks = chunkArray(domains, 1000);
// Create Cloudflare Zero Trust lists
for (const [index, chunk] of chunks.entries()) {
const listName = `CGPS List - Chunk ${index}`;
let properList = [];
chunk.forEach(domain => {
properList.push({ "value": domain })
});
try {
await createZeroTrustList(listName, properList, (index+1), listsToCreate);
await sleep(350); // Sleep for 350ms between list additions
} catch (error) {
console.error(`Error creating list `, process.env.CI ? "(redacted on CI)" : `"${listName}": ${error.response.data}`);
}
}
});
function trimArray(arr, size) {
return arr.slice(0, size);
}
// Function to check if a domain is valid
function isValidDomain(domain) {
const regex = /^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\.)+[A-Za-z]{2,6}$/;
return regex.test(domain);
}
// Function to split an array into chunks
function chunkArray(array, chunkSize) {
const chunks = [];
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}
return chunks;
}
// Function to create a Cloudflare Zero Trust list
async function createZeroTrustList(name, items, currentItem, totalItems) {
const response = await axios.post(
`https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/gateway/lists`,
{
name,
type: 'DOMAIN', // Set list type to DOMAIN
items,
},
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
'X-Auth-Email': ACCOUNT_EMAIL,
'X-Auth-Key': API_TOKEN,
},
}
);
const listId = response.data.result.id;
console.log(`Created Zero Trust list`, process.env.CI ? "(redacted on CI)" : `"${name}" with ID ${listId} - ${totalItems - currentItem} left`);
}
function percentage(percent, total) {
return Math.round((percent / 100) * total);
}
// Function to sleep for a specified duration
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}