From 56ba93700c092c00f869fc85129046fe096c1c00 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 8 Dec 2024 08:37:29 -0500 Subject: [PATCH] [mv3] Ensure no generic cosmetic filters end up in specific realm Related issue: https://github.com/uBlockOrigin/uBOL-home/issues/254 Cosmetic filters with only negated hostnames would end up being classified as specific, while in reality the filter is generic, with specific exceptions. This commit fixes the improper classification. Enforcing specific exception filters in the generic realm is still an issue to address. --- platform/mv3/make-rulesets.js | 13 +---- src/js/static-dnr-filtering.js | 97 +++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/platform/mv3/make-rulesets.js b/platform/mv3/make-rulesets.js index 4ea7ae6db..9df90963c 100644 --- a/platform/mv3/make-rulesets.js +++ b/platform/mv3/make-rulesets.js @@ -83,11 +83,6 @@ const uidint32 = (s) => { return parseInt(h,16) & 0x7FFFFFFF; }; -const hnSort = (a, b) => - a.split('.').reverse().join('.').localeCompare( - b.split('.').reverse().join('.') - ); - /******************************************************************************/ const stdOutput = []; @@ -681,14 +676,10 @@ function groupHostnamesBySelectors(arrayin) { const out = Array.from(contentMap).map(a => [ a[0], { a: a[1].a, - y: a[1].y ? Array.from(a[1].y).sort(hnSort) : '*', + y: a[1].y ? Array.from(a[1].y) : undefined, n: a[1].n ? Array.from(a[1].n) : undefined, } - ]).sort((a, b) => { - const ha = Array.isArray(a[1].y) ? a[1].y[0] : '*'; - const hb = Array.isArray(b[1].y) ? b[1].y[0] : '*'; - return hnSort(ha, hb); - }); + ]); return out; } diff --git a/src/js/static-dnr-filtering.js b/src/js/static-dnr-filtering.js index 636390065..9935fd161 100644 --- a/src/js/static-dnr-filtering.js +++ b/src/js/static-dnr-filtering.js @@ -90,6 +90,39 @@ const keyFromSelector = selector => { /******************************************************************************/ +function addGenericCosmeticFilter(context, selector, isException) { + if ( selector === undefined ) { return; } + if ( selector.length <= 1 ) { return; } + if ( isException ) { + if ( context.genericCosmeticExceptions === undefined ) { + context.genericCosmeticExceptions = new Set(); + } + context.genericCosmeticExceptions.add(selector); + return; + } + if ( selector.charCodeAt(0) === 0x7B /* '{' */ ) { return; } + const key = keyFromSelector(selector); + if ( key === undefined ) { + if ( context.genericHighCosmeticFilters === undefined ) { + context.genericHighCosmeticFilters = new Set(); + } + context.genericHighCosmeticFilters.add(selector); + return; + } + const type = key.charCodeAt(0); + const hash = hashFromStr(type, key.slice(1)); + if ( context.genericCosmeticFilters === undefined ) { + context.genericCosmeticFilters = new Map(); + } + let bucket = context.genericCosmeticFilters.get(hash); + if ( bucket === undefined ) { + context.genericCosmeticFilters.set(hash, bucket = []); + } + bucket.push(selector); +} + +/******************************************************************************/ + function addExtendedToDNR(context, parser) { if ( parser.isExtendedFilter() === false ) { return false; } @@ -195,35 +228,8 @@ function addExtendedToDNR(context, parser) { // Generic cosmetic filtering if ( parser.hasOptions() === false ) { - const { compiled } = parser.result; - if ( compiled === undefined ) { return; } - if ( compiled.length <= 1 ) { return; } - if ( parser.isException() ) { - if ( context.genericCosmeticExceptions === undefined ) { - context.genericCosmeticExceptions = new Set(); - } - context.genericCosmeticExceptions.add(compiled); - return; - } - if ( compiled.charCodeAt(0) === 0x7B /* '{' */ ) { return; } - const key = keyFromSelector(compiled); - if ( key === undefined ) { - if ( context.genericHighCosmeticFilters === undefined ) { - context.genericHighCosmeticFilters = new Set(); - } - context.genericHighCosmeticFilters.add(compiled); - return; - } - const type = key.charCodeAt(0); - const hash = hashFromStr(type, key.slice(1)); - if ( context.genericCosmeticFilters === undefined ) { - context.genericCosmeticFilters = new Map(); - } - let bucket = context.genericCosmeticFilters.get(hash); - if ( bucket === undefined ) { - context.genericCosmeticFilters.set(hash, bucket = []); - } - bucket.push(compiled); + const { compiled, exception } = parser.result; + addGenericCosmeticFilter(context, compiled, exception); return; } @@ -234,26 +240,22 @@ function addExtendedToDNR(context, parser) { if ( context.specificCosmeticFilters === undefined ) { context.specificCosmeticFilters = new Map(); } + const { compiled, exception, raw } = parser.result; + if ( compiled === undefined ) { + context.specificCosmeticFilters.set(`Invalid filter: ...##${raw}`, { + rejected: true + }); + return; + } + let details = context.specificCosmeticFilters.get(compiled); for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } + if ( not && exception ) { continue; } if ( isRegex(hn) ) { continue; } - let { compiled, exception, raw } = parser.result; - if ( exception ) { continue; } - let rejected; - if ( compiled === undefined ) { - rejected = `Invalid filter: ${hn}##${raw}`; - } - if ( rejected ) { - compiled = rejected; - } - let details = context.specificCosmeticFilters.get(compiled); if ( details === undefined ) { - details = {}; - if ( rejected ) { details.rejected = true; } - context.specificCosmeticFilters.set(compiled, details); + context.specificCosmeticFilters.set(compiled, details = {}); } - if ( rejected ) { continue; } - if ( not ) { + if ( exception ) { if ( details.excludeMatches === undefined ) { details.excludeMatches = []; } @@ -270,6 +272,13 @@ function addExtendedToDNR(context, parser) { } details.matches.push(hn); } + if ( details === undefined ) { return; } + if ( exception ) { return; } + if ( compiled.startsWith('{') ) { return; } + if ( details.matches === undefined || details.matches.includes('*') ) { + addGenericCosmeticFilter(context, compiled, false); + details.matches = undefined; + } } /******************************************************************************/