From 53fc370774ef1757887e21faef54866366a6656d Mon Sep 17 00:00:00 2001 From: SukkaW Date: Sun, 7 Jan 2024 22:34:58 +0800 Subject: [PATCH] Fix: force normalize reject domains --- Build/build-reject-domainset.ts | 6 ++--- Build/lib/get-phishing-domains.ts | 9 +++++--- Build/lib/parse-filter.ts | 20 ++++++++--------- Build/lib/reject-data-source.ts | 36 +++++++++++++++--------------- bun.lockb | Bin 92178 -> 93306 bytes package.json | 3 ++- 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/Build/build-reject-domainset.ts b/Build/build-reject-domainset.ts index 2c53c11d..d109c1ab 100644 --- a/Build/build-reject-domainset.ts +++ b/Build/build-reject-domainset.ts @@ -32,12 +32,12 @@ export const buildRejectDomainSet = task(import.meta.path, async () => { const [gorhill] = await Promise.all([ getGorhillPublicSuffixPromise(), // Parse from remote hosts & domain lists - ...HOSTS.map(entry => processHosts(entry[0], entry[1], entry[2], entry[3]).then(hosts => { + ...HOSTS.map(entry => processHosts(entry[0], entry[1], entry[2]).then(hosts => { hosts.forEach(host => { domainSets.add(host); }); })), - ...DOMAIN_LISTS.map(entry => processDomainLists(entry[0], entry[1], entry[2], entry[3])), + ...DOMAIN_LISTS.map(entry => processDomainLists(entry[0], entry[1], entry[2])), ...ADGUARD_FILTERS.map(input => { const promise = typeof input === 'string' ? processFilterRules(input) @@ -154,7 +154,7 @@ export const buildRejectDomainSet = task(import.meta.path, async () => { dudupedDominArray.reduce>((acc, cur) => { const suffix = tldts.getDomain(cur, { allowPrivateDomains: false, detectIp: false, validateHostname: false }); if (suffix) { - acc[suffix] = (acc[suffix] ?? 0) + 1; + acc[suffix] = (acc[suffix] || 0) + 1; } return acc; }, {}) diff --git a/Build/lib/get-phishing-domains.ts b/Build/lib/get-phishing-domains.ts index db0a0209..3ca9a54d 100644 --- a/Build/lib/get-phishing-domains.ts +++ b/Build/lib/get-phishing-domains.ts @@ -6,6 +6,7 @@ import { createTrie } from './trie'; import { createCachedGorhillGetDomain } from './cached-tld-parse'; import { processLine } from './process-line'; import { TTL } from './cache-filesystem'; +import { isCI } from 'ci-info'; const WHITELIST_DOMAIN = new Set([ 'w3s.link', @@ -85,11 +86,13 @@ const BLACK_TLD = new Set([ export const getPhishingDomains = () => traceAsync('get phishing domains', async () => { const [domainSet, domainSet2, gorhill] = await Promise.all([ - processDomainLists('https://curbengh.github.io/phishing-filter/phishing-filter-domains.txt', true, false, TTL.THREE_HOURS()), - processDomainLists('https://phishing.army/download/phishing_army_blocklist.txt', true, true, TTL.THREE_HOURS()), + processDomainLists('https://curbengh.github.io/phishing-filter/phishing-filter-domains.txt', true, TTL.THREE_HOURS()), + isCI + ? processDomainLists('https://phishing.army/download/phishing_army_blocklist.txt', true, TTL.THREE_HOURS()) + : null, getGorhillPublicSuffixPromise() ]); - domainSet2.forEach((domain) => domainSet.add(domain)); + domainSet2?.forEach((domain) => domainSet.add(domain)); traceSync.skip('* whitelisting phishing domains', () => { const trieForRemovingWhiteListed = createTrie(domainSet); diff --git a/Build/lib/parse-filter.ts b/Build/lib/parse-filter.ts index ee828a83..74e4bc63 100644 --- a/Build/lib/parse-filter.ts +++ b/Build/lib/parse-filter.ts @@ -11,10 +11,10 @@ import { normalizeDomain } from './normalize-domain'; import { fetchAssets } from './fetch-assets'; import { deserializeSet, fsCache, serializeSet } from './cache-filesystem'; -const DEBUG_DOMAIN_TO_FIND: string | null = '.j3.4z0vc.chileinsumos.cl'; // example.com | null +const DEBUG_DOMAIN_TO_FIND: string | null = null; // example.com | null let foundDebugDomain = false; -export function processDomainLists(domainListsUrl: string, includeAllSubDomain = false, skipDomainCheck = false, ttl: number | null = null) { +export function processDomainLists(domainListsUrl: string, includeAllSubDomain = false, ttl: number | null = null) { return traceAsync(`- processDomainLists: ${domainListsUrl}`, () => fsCache.apply( domainListsUrl, async () => { @@ -23,11 +23,7 @@ export function processDomainLists(domainListsUrl: string, includeAllSubDomain = for await (const line of await fetchRemoteTextByLine(domainListsUrl)) { let domainToAdd = processLine(line); if (!domainToAdd) continue; - - if (!skipDomainCheck) { - domainToAdd = normalizeDomain(domainToAdd); - } - + domainToAdd = normalizeDomain(domainToAdd); if (!domainToAdd) continue; if (DEBUG_DOMAIN_TO_FIND && domainToAdd.includes(DEBUG_DOMAIN_TO_FIND)) { @@ -48,7 +44,7 @@ export function processDomainLists(domainListsUrl: string, includeAllSubDomain = } )); } -export function processHosts(hostsUrl: string, includeAllSubDomain = false, skipDomainCheck = false, ttl: number | null = null) { +export function processHosts(hostsUrl: string, includeAllSubDomain = false, ttl: number | null = null) { return traceAsync(`- processHosts: ${hostsUrl}`, () => fsCache.apply( hostsUrl, async () => { @@ -71,10 +67,12 @@ export function processHosts(hostsUrl: string, includeAllSubDomain = false, skip foundDebugDomain = true; } - const domainToAdd = skipDomainCheck ? _domain : normalizeDomain(_domain); - if (domainToAdd) { - domainSets.add(includeAllSubDomain ? `.${domainToAdd}` : domainToAdd); + const domainToAdd = normalizeDomain(_domain); + if (!domainToAdd) { + continue; } + + domainSets.add(includeAllSubDomain ? `.${domainToAdd}` : domainToAdd); } console.log(picocolors.gray('[process hosts]'), picocolors.gray(hostsUrl), picocolors.gray(domainSets.size)); diff --git a/Build/lib/reject-data-source.ts b/Build/lib/reject-data-source.ts index 95f0df52..03687295 100644 --- a/Build/lib/reject-data-source.ts +++ b/Build/lib/reject-data-source.ts @@ -1,21 +1,21 @@ import { TTL } from './cache-filesystem'; export const HOSTS = [ - ['https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext', true, false, TTL.THREE_HOURS()], - ['https://someonewhocares.org/hosts/hosts', true, false, TTL.THREE_HOURS()], + ['https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext', true, TTL.THREE_HOURS()], + ['https://someonewhocares.org/hosts/hosts', true, TTL.THREE_HOURS()], // no coin list is not actively maintained, but it updates daily when being maintained, so we set a 3 days cache ttl - ['https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/hosts.txt', false, false, TTL.THREE_DAYS()], + ['https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/hosts.txt', false, TTL.THREE_DAYS()], // have not been updated for more than a year, so we set a 14 days cache ttl - ['https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt', true, false, TTL.TWO_WEEKS()], - ['https://raw.githubusercontent.com/jerryn70/GoodbyeAds/master/Extension/GoodbyeAds-Xiaomi-Extension.txt', false, false, TTL.THREE_DAYS()], - ['https://raw.githubusercontent.com/jerryn70/GoodbyeAds/master/Extension/GoodbyeAds-Huawei-AdBlock.txt', false, false, TTL.THREE_DAYS()], + ['https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt', true, TTL.TWO_WEEKS()], + ['https://raw.githubusercontent.com/jerryn70/GoodbyeAds/master/Extension/GoodbyeAds-Xiaomi-Extension.txt', false, TTL.THREE_DAYS()], + ['https://raw.githubusercontent.com/jerryn70/GoodbyeAds/master/Extension/GoodbyeAds-Huawei-AdBlock.txt', false, TTL.THREE_DAYS()], // ad-wars is not actively maintained, so we set a 7 days cache ttl - ['https://raw.githubusercontent.com/jdlingyu/ad-wars/master/hosts', false, false, TTL.ONE_WEEK()], - ['https://raw.githubusercontent.com/durablenapkin/block/master/luminati.txt', true, false, TTL.THREE_HOURS()], + ['https://raw.githubusercontent.com/jdlingyu/ad-wars/master/hosts', false, TTL.ONE_WEEK()], + ['https://raw.githubusercontent.com/durablenapkin/block/master/luminati.txt', true, TTL.THREE_HOURS()], // Curben's UrlHaus Malicious URL Blocklist // 'https://curbengh.github.io/urlhaus-filter/urlhaus-filter-agh-online.txt', // 'https://urlhaus-filter.pages.dev/urlhaus-filter-agh-online.txt', - ['https://curbengh.github.io/urlhaus-filter/urlhaus-filter-hosts.txt', true, true, TTL.THREE_HOURS()], + ['https://curbengh.github.io/urlhaus-filter/urlhaus-filter-hosts.txt', true, TTL.THREE_HOURS()], // Curben's Phishing URL Blocklist // Covered by lib/get-phishing-domains.ts // 'https://curbengh.github.io/phishing-filter/phishing-filter-agh.txt' @@ -25,26 +25,26 @@ export const HOSTS = [ // 'https://curbengh.github.io/pup-filter/pup-filter-agh.txt' // 'https://pup-filter.pages.dev/pup-filter-agh.txt' // The PUP filter has paused the update since 2023-05, so we set a 14 days cache ttl - ['https://curbengh.github.io/pup-filter/pup-filter-hosts.txt', true, true, TTL.TWO_WEEKS()] + ['https://curbengh.github.io/pup-filter/pup-filter-hosts.txt', true, TTL.TWO_WEEKS()] ] as const; export const DOMAIN_LISTS = [ // CoinBlockerList // Although the hosts file is still actively maintained, the hosts_browser file is not updated since 2021-07, so we set a 14 days cache ttl - ['https://zerodot1.gitlab.io/CoinBlockerLists/list_browser.txt', true, true, TTL.TWO_WEEKS()], + ['https://zerodot1.gitlab.io/CoinBlockerLists/list_browser.txt', true, TTL.TWO_WEEKS()], // BarbBlock // The barbblock list has never been updated since 2019-05, so we set a 14 days cache ttl - ['https://paulgb.github.io/BarbBlock/blacklists/domain-list.txt', true, true, TTL.TWO_WEEKS()], + ['https://paulgb.github.io/BarbBlock/blacklists/domain-list.txt', true, TTL.TWO_WEEKS()], // DigitalSide Threat-Intel - OSINT Hub // Update once per day - ['https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt', true, true, TTL.ONE_DAY()], + ['https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt', true, TTL.ONE_DAY()], // AdGuard CNAME Filter Combined // Update on a 7 days basis, so we add a 3 hours cache ttl - ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_ads_justdomains.txt', true, true, TTL.THREE_DAYS()], - ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_trackers_justdomains.txt', true, true, TTL.THREE_DAYS()], - ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_clickthroughs_justdomains.txt', true, true, TTL.THREE_DAYS()], - ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_microsites_justdomains.txt', true, true, TTL.THREE_DAYS()], - ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_mail_trackers_justdomains.txt', true, true, TTL.THREE_DAYS()] + ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_ads_justdomains.txt', true, TTL.THREE_DAYS()], + ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_trackers_justdomains.txt', true, TTL.THREE_DAYS()], + ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_clickthroughs_justdomains.txt', true, TTL.THREE_DAYS()], + ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_microsites_justdomains.txt', true, TTL.THREE_DAYS()], + ['https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_mail_trackers_justdomains.txt', true, TTL.THREE_DAYS()] ] as const; export const ADGUARD_FILTERS = [ diff --git a/bun.lockb b/bun.lockb index 8dba67e4d25bd8416e3731091edf27d7d333231a..b31b682b40d2cad0c0b95729307b6d884b3481a9 100755 GIT binary patch delta 14025 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 SeY*VoID9m>RL17B*Zv2B{!xhl delta 13345 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