Merge pull request #50 from hlqviet/refactor/domain-processing

Further enhance the domain processing code
This commit is contained in:
mrrfv
2023-11-19 13:47:40 +01:00
committed by GitHub
4 changed files with 73 additions and 55 deletions
+29 -37
View File
@@ -17,6 +17,7 @@ import {
extractDomain, extractDomain,
isComment, isComment,
isValidDomain, isValidDomain,
memoize,
readFile, readFile,
} from "./lib/utils.js"; } from "./lib/utils.js";
@@ -33,6 +34,7 @@ let processedDomainCount = 0;
let unnecessaryDomainCount = 0; let unnecessaryDomainCount = 0;
let duplicateDomainCount = 0; let duplicateDomainCount = 0;
let allowedDomainCount = 0; let allowedDomainCount = 0;
const memoizedNormalizeDomain = memoize(normalizeDomain);
// Read allowlist // Read allowlist
console.log(`Processing ${allowlistFilename}`); console.log(`Processing ${allowlistFilename}`);
@@ -43,7 +45,7 @@ await readFile(resolve(`./${allowlistFilename}`), (line) => {
if (isComment(_line)) return; if (isComment(_line)) return;
const domain = normalizeDomain(_line, true); const domain = memoizedNormalizeDomain(_line, true);
if (!isValidDomain(domain)) return; if (!isValidDomain(domain)) return;
@@ -65,7 +67,7 @@ await readFile(resolve(`./${blocklistFilename}`), (line, rl) => {
if (isComment(_line)) return; if (isComment(_line)) return;
// Remove prefixes and suffixes in hosts, wildcard or adblock format // Remove prefixes and suffixes in hosts, wildcard or adblock format
const domain = normalizeDomain(_line); const domain = memoizedNormalizeDomain(_line);
// Check if it is a valid domain which is not a URL or does not contain // Check if it is a valid domain which is not a URL or does not contain
// characters like * in the middle of the domain // characters like * in the middle of the domain
@@ -73,40 +75,31 @@ await readFile(resolve(`./${blocklistFilename}`), (line, rl) => {
processedDomainCount++; processedDomainCount++;
// Get all the levels of the domain and check from the highest
// because we are blocking all subdomains
// Example: fourth.third.example.com => ["example.com", "third.example.com", "fourth.third.example.com"]
const anyDomainExists = extractDomain(domain)
.reverse()
.some((item) => {
if (blocklist.has(item)) {
if (item === domain) {
// The exact domain is already blocked
console.log(`Found ${item} in blocklist already - Skipping`);
duplicateDomainCount++;
} else {
// The higher-level domain is already blocked
// so it's not necessary to block this domain
console.log(
`Found ${item} in blocklist already - Skipping ${domain}`
);
unnecessaryDomainCount++;
}
return true;
}
return false;
});
if (anyDomainExists) return;
if (allowlist.has(domain)) { if (allowlist.has(domain)) {
console.log(`Found ${domain} in allowlist - Skipping`); console.log(`Found ${domain} in allowlist - Skipping`);
allowedDomainCount++; allowedDomainCount++;
return; return;
} }
if (blocklist.has(domain)) {
console.log(`Found ${domain} in blocklist already - Skipping`);
duplicateDomainCount++;
return;
}
// Get all the levels of the domain and check from the highest
// because we are blocking all subdomains
// Example: fourth.third.example.com => ["example.com", "third.example.com", "fourth.third.example.com"]
for (const item of extractDomain(domain).slice(1)) {
if (!blocklist.has(item)) continue;
// The higher-level domain is already blocked
// so it's not necessary to block this domain
console.log(`Found ${item} in blocklist already - Skipping ${domain}`);
unnecessaryDomainCount++;
return;
}
blocklist.set(domain, 1); blocklist.set(domain, 1);
domains.push(domain); domains.push(domain);
@@ -124,8 +117,8 @@ console.log("\n\n");
console.log(`Number of processed domains: ${processedDomainCount}`); console.log(`Number of processed domains: ${processedDomainCount}`);
console.log(`Number of duplicate domains: ${duplicateDomainCount}`); console.log(`Number of duplicate domains: ${duplicateDomainCount}`);
console.log(`Number of unnecessary domains: ${unnecessaryDomainCount}`); console.log(`Number of unnecessary domains: ${unnecessaryDomainCount}`);
console.log(`Number of blocked domains: ${domains.length}`);
console.log(`Number of allowed domains: ${allowedDomainCount}`); console.log(`Number of allowed domains: ${allowedDomainCount}`);
console.log(`Number of blocked domains: ${domains.length}`);
console.log(`Number of lists to be created: ${numberOfLists}`); console.log(`Number of lists to be created: ${numberOfLists}`);
console.log("\n\n"); console.log("\n\n");
@@ -143,12 +136,11 @@ console.log("\n\n");
if (FAST_MODE) { if (FAST_MODE) {
await createZeroTrustListsAtOnce(domains); await createZeroTrustListsAtOnce(domains);
// TODO: make this less repetitive } else {
await notifyWebhook(`CF List Create script finished running (${domains.length} domains, ${numberOfLists} lists)`); await createZeroTrustListsOneByOne(domains);
return;
} }
await createZeroTrustListsOneByOne(domains); await notifyWebhook(
`CF List Create script finished running (${domains.length} domains, ${numberOfLists} lists)`
await notifyWebhook(`CF List Create script finished running (${domains.length} domains, ${numberOfLists} lists)`); );
})(); })();
+1
View File
@@ -38,6 +38,7 @@ const downloadLists = async (filename, urls) => {
} catch (err) { } catch (err) {
console.error(`An error occurred while processing ${filename}:\n`, err); console.error(`An error occurred while processing ${filename}:\n`, err);
console.error("URLs:\n", urls); console.error("URLs:\n", urls);
throw err;
} }
}; };
+6
View File
@@ -51,6 +51,7 @@ export const createZeroTrustListsOneByOne = async (items) => {
console.log(`Created "${listName}" list - ${totalListNumber} left`); console.log(`Created "${listName}" list - ${totalListNumber} left`);
} catch (err) { } catch (err) {
console.error(`Could not create "${listName}" - ${err.toString()}`); console.error(`Could not create "${listName}" - ${err.toString()}`);
throw err;
} }
} }
}; };
@@ -77,6 +78,7 @@ export const createZeroTrustListsAtOnce = async (items) => {
console.log("Created lists successfully"); console.log("Created lists successfully");
} catch (err) { } catch (err) {
console.error(`Error occurred while creating lists - ${err.toString()}`); console.error(`Error occurred while creating lists - ${err.toString()}`);
throw err;
} }
}; };
@@ -106,6 +108,7 @@ export const deleteZeroTrustListsOneByOne = async (lists) => {
console.log(`Deleted ${name} list - ${totalListNumber} left`); console.log(`Deleted ${name} list - ${totalListNumber} left`);
} catch (err) { } catch (err) {
console.error(`Could not delete ${name} - ${err.toString()}`); console.error(`Could not delete ${name} - ${err.toString()}`);
throw err;
} }
} }
}; };
@@ -124,6 +127,7 @@ export const deleteZeroTrustListsAtOnce = async (lists) => {
console.log("Deleted lists successfully"); console.log("Deleted lists successfully");
} catch (err) { } catch (err) {
console.error(`Error occurred while deleting lists - ${err.toString()}`); console.error(`Error occurred while deleting lists - ${err.toString()}`);
throw err;
} }
}; };
@@ -161,6 +165,7 @@ export const createZeroTrustRule = async (wirefilterExpression) => {
console.log("Created rule successfully"); console.log("Created rule successfully");
} catch (err) { } catch (err) {
console.error(`Error occurred while creating rule - ${err.toString()}`); console.error(`Error occurred while creating rule - ${err.toString()}`);
throw err;
} }
}; };
@@ -180,5 +185,6 @@ export const deleteZeroTrustRule = async (id) => {
console.log("Deleted rule successfully"); console.log("Deleted rule successfully");
} catch (err) { } catch (err) {
console.error(`Error occurred while deleting rule - ${err.toString()}`); console.error(`Error occurred while deleting rule - ${err.toString()}`);
throw err;
} }
}; };
+37 -18
View File
@@ -19,18 +19,18 @@ export const isValidDomain = (value) =>
* @param {string} domain The domain to be extracted. * @param {string} domain The domain to be extracted.
* @returns {string[]} * @returns {string[]}
*/ */
export const extractDomain = (domain) => export const extractDomain = (domain) => {
domain.split(".").reduce((previous, current, index, array) => { const parts = domain.split(".");
const nextIndex = index + 1; const extractedDomains = [];
if (nextIndex > array.length - 1) return previous; for (let i = 0; i < parts.length; i++) {
const subdomains = parts.slice(i).join(".");
const domain = [current, ...array.slice(nextIndex)].join("."); extractedDomains.unshift(subdomains);
}
previous.push(domain); return extractedDomains;
};
return previous;
}, []);
/** /**
* Checks if the value is a comment. * Checks if the value is a comment.
@@ -49,19 +49,16 @@ export const isComment = (value) =>
* @param {string[]} urls The URLs to the files to be downloaded. * @param {string[]} urls The URLs to the files to be downloaded.
*/ */
export const downloadFiles = async (filePath, urls) => { export const downloadFiles = async (filePath, urls) => {
const writeStream = createWriteStream(filePath, { flags: "a" });
const responses = await Promise.all(urls.map((url) => fetch(url))); const responses = await Promise.all(urls.map((url) => fetch(url)));
for (const response of responses) { for (const response of responses) {
const readable = ReadStream.from(response.body, { const writeStream = createWriteStream(filePath, { flags: "a" });
autoDestroy: true,
});
readable.on("end", () => { ReadStream.from(response.body)
writeStream.write("\n"); .on("end", () => {
}); writeStream.write("\n");
})
readable.pipe(writeStream, { end: false }); .pipe(writeStream);
} }
}; };
@@ -90,5 +87,27 @@ export const readFile = async (filePath, onLine) => {
console.error( console.error(
`Error occurred while reading ${basename(filePath)} - ${err.toString()}` `Error occurred while reading ${basename(filePath)} - ${err.toString()}`
); );
throw err;
} }
}; };
/**
* Memoizes a function
* @template T The argument type of the function.
* @template R The return type of the function.
* @param {(...fnArgs: T[]) => R} fn The function to be memoized.
*/
export const memoize = (fn) => {
const cache = new Map();
return (...args) => {
const key = args.join("-");
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
};