diff --git a/platform/mv3/extension/js/scripting-manager.js b/platform/mv3/extension/js/scripting-manager.js index d387622e1..e22a7c530 100644 --- a/platform/mv3/extension/js/scripting-manager.js +++ b/platform/mv3/extension/js/scripting-manager.js @@ -66,6 +66,15 @@ const arrayEq = (a = [], b = [], sort = true) => { /******************************************************************************/ +const normalizeMatches = matches => { + if ( matches.length <= 1 ) { return; } + if ( matches.includes('') === false ) { return; } + matches.length = 0; + matches.push(''); +}; + +/******************************************************************************/ + // The extensions API does not always return exactly what we fed it, so we // need to normalize some entries to be sure we properly detect changes when // comparing registered entries vs. entries to register. @@ -93,11 +102,17 @@ function registerHighGeneric(context, genericDetails) { const { before, filteringModeDetails, rulesetsDetails } = context; const excludeHostnames = []; + const includeHostnames = []; const css = []; for ( const details of rulesetsDetails ) { const hostnames = genericDetails.get(details.id); - if ( hostnames !== undefined ) { - excludeHostnames.push(...hostnames); + if ( hostnames ) { + if ( hostnames.unhide ) { + excludeHostnames.push(...hostnames.unhide); + } + if ( hostnames.hide ) { + includeHostnames.push(...hostnames.hide); + } } const count = details.css?.generichigh || 0; if ( count === 0 ) { continue; } @@ -165,12 +180,18 @@ function registerHighGeneric(context, genericDetails) { function registerGeneric(context, genericDetails) { const { before, filteringModeDetails, rulesetsDetails } = context; - const excludeHostnames = []; + const excludedByFilter = []; + const includedByFilter = []; const js = []; for ( const details of rulesetsDetails ) { const hostnames = genericDetails.get(details.id); - if ( hostnames !== undefined ) { - excludeHostnames.push(...hostnames); + if ( hostnames ) { + if ( hostnames.unhide ) { + excludedByFilter.push(...hostnames.unhide); + } + if ( hostnames.hide ) { + includedByFilter.push(...hostnames.hide); + } } const count = details.css?.generic || 0; if ( count === 0 ) { continue; } @@ -183,53 +204,86 @@ function registerGeneric(context, genericDetails) { js.push('/js/scripting/css-generic.js'); const { none, basic, optimal, complete } = filteringModeDetails; - const matches = []; - const excludeMatches = []; - if ( complete.has('all-urls') ) { - excludeMatches.push(...ut.matchesFromHostnames(none)); - excludeMatches.push(...ut.matchesFromHostnames(basic)); - excludeMatches.push(...ut.matchesFromHostnames(optimal)); - excludeMatches.push(...ut.matchesFromHostnames(excludeHostnames)); - matches.push(''); - } else { - matches.push( + const includedByMode = [ ...complete ]; + const excludedByMode = [ ...none, ...basic, ...optimal ]; + + if ( complete.has('all-urls') === false ) { + const matches = [ ...ut.matchesFromHostnames( - ut.subtractHostnameIters( - Array.from(complete), - excludeHostnames - ) - ) - ); - } - - if ( matches.length === 0 ) { return; } - - const registered = before.get('css-generic'); - before.delete('css-generic'); // Important! - - const directive = { - id: 'css-generic', - js, - allFrames: true, - matches, - excludeMatches, - runAt: 'document_idle', - }; - - // register - if ( registered === undefined ) { - context.toAdd.push(directive); + ut.subtractHostnameIters(includedByMode, excludedByFilter) + ), + ...ut.matchesFromHostnames( + ut.intersectHostnameIters(includedByMode, includedByFilter) + ), + ]; + if ( matches.length === 0 ) { return; } + const registered = before.get('css-generic-some'); + before.delete('css-generic-some'); // Important! + const directive = { + id: 'css-generic-some', + js, + allFrames: true, + matches, + runAt: 'document_idle', + }; + if ( registered === undefined ) { // register + context.toAdd.push(directive); + } else if ( // update + arrayEq(registered.js, js, false) === false || + arrayEq(registered.matches, directive.matches) === false + ) { + context.toRemove.push('css-generic-some'); + context.toAdd.push(directive); + } return; } - // update - if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + const excludeMatches = [ + ...ut.matchesFromHostnames(excludedByMode), + ...ut.matchesFromHostnames(excludedByFilter), + ]; + const registeredAll = before.get('css-generic-all'); + before.delete('css-generic-all'); // Important! + const directiveAll = { + id: 'css-generic-all', + js, + allFrames: true, + matches: [ '' ], + excludeMatches, + runAt: 'document_idle', + }; + if ( registeredAll === undefined ) { // register + context.toAdd.push(directiveAll); + } else if ( // update + arrayEq(registeredAll.js, js, false) === false || + arrayEq(registeredAll.excludeMatches, directiveAll.excludeMatches) === false ) { - context.toRemove.push('css-generic'); - context.toAdd.push(directive); + context.toRemove.push('css-generic-all'); + context.toAdd.push(directiveAll); + } + const matches = [ + ...ut.matchesFromHostnames( + ut.subtractHostnameIters(includedByFilter, excludedByMode) + ), + ]; + if ( matches.length === 0 ) { return; } + const registeredSome = before.get('css-generic-some'); + before.delete('css-generic-some'); // Important! + const directiveSome = { + id: 'css-generic-some', + js, + allFrames: true, + matches, + runAt: 'document_idle', + }; + if ( registeredSome === undefined ) { // register + context.toAdd.push(directiveSome); + } else if ( // update + arrayEq(registeredSome.js, js, false) === false || + arrayEq(registeredSome.matches, directiveSome.matches) === false + ) { + context.toRemove.push('css-generic-some'); + context.toAdd.push(directiveSome); } } @@ -253,6 +307,8 @@ function registerProcedural(context) { ]; if ( matches.length === 0 ) { return; } + normalizeMatches(matches); + js.unshift('/js/scripting/isolated-api.js'); js.push('/js/scripting/css-procedural.js'); @@ -313,6 +369,8 @@ function registerDeclarative(context) { ]; if ( matches.length === 0 ) { return; } + normalizeMatches(matches); + js.unshift('/js/scripting/isolated-api.js'); js.push('/js/scripting/css-declarative.js'); @@ -373,6 +431,8 @@ function registerSpecific(context) { ]; if ( matches.length === 0 ) { return; } + normalizeMatches(matches); + js.unshift('/js/scripting/isolated-api.js'); js.push('/js/scripting/css-specific.js'); diff --git a/platform/mv3/extension/js/utils.js b/platform/mv3/extension/js/utils.js index dfbe235f3..f6f58fb90 100644 --- a/platform/mv3/extension/js/utils.js +++ b/platform/mv3/extension/js/utils.js @@ -100,15 +100,13 @@ const subtractHostnameIters = (itera, iterb) => { /******************************************************************************/ +const matchFromHostname = hn => + hn === '*' || hn === 'all-urls' ? '' : `*://*.${hn}/*`; + const matchesFromHostnames = hostnames => { const out = []; for ( const hn of hostnames ) { - if ( hn === '*' || hn === 'all-urls' ) { - out.length = 0; - out.push(''); - break; - } - out.push(`*://*.${hn}/*`); + out.push(matchFromHostname(hn)); } return out; }; @@ -144,6 +142,7 @@ export { isDescendantHostnameOfIter, intersectHostnameIters, subtractHostnameIters, + matchFromHostname, matchesFromHostnames, hostnamesFromMatches, }; diff --git a/platform/mv3/make-rulesets.js b/platform/mv3/make-rulesets.js index 04799a23f..0a8e34c82 100644 --- a/platform/mv3/make-rulesets.js +++ b/platform/mv3/make-rulesets.js @@ -1245,14 +1245,25 @@ async function rulesetFromURLs(assetDetails) { log(rejectedCosmetic.map(line => `\t${line}`).join('\n'), true); } + const genericDetailsForRuleset = {}; if ( Array.isArray(results.network.generichideExclusions) && results.network.generichideExclusions.length !== 0 ) { - genericDetails.set( - assetDetails.id, - results.network.generichideExclusions.filter(hn => hn.endsWith('.*') === false).sort() - ); + genericDetailsForRuleset.unhide = results.network.generichideExclusions + .filter(hn => hn.endsWith('.*') === false) + .sort(); + } + if ( + Array.isArray(results.network.generichideInclusions) && + results.network.generichideInclusions.length !== 0 + ) { + genericDetailsForRuleset.hide = results.network.generichideInclusions + .filter(hn => hn.endsWith('.*') === false) + .sort(); + } + if ( genericDetailsForRuleset.unhide || genericDetailsForRuleset.hide ) { + genericDetails.set(assetDetails.id, genericDetailsForRuleset); } const genericCosmeticStats = await processGenericCosmeticFilters( @@ -1367,8 +1378,8 @@ async function main() { ], dnrURL: 'https://ublockorigin.github.io/uAssets/dnr/default.json', homeURL: 'https://github.com/uBlockOrigin/uAssets', - filters: [ - ], + filters: [` + `], }); await rulesetFromURLs({ diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js index b24f0ffa0..acfb5d144 100644 --- a/src/js/static-net-filtering.js +++ b/src/js/static-net-filtering.js @@ -4511,6 +4511,7 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar // Collect generichide filters const generichideExclusions = []; + const generichideInclusions = []; { const bucket = buckets.get(ALLOW_REALM | typeNameToTypeValue['generichide']); if ( bucket ) { @@ -4522,6 +4523,26 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar } else if ( rule.condition.requestDomains ) { generichideExclusions.push(...rule.condition.requestDomains); } + if ( rule.condition.excludedInitiatorDomains ) { + generichideInclusions.push(...rule.condition.excludedInitiatorDomains); + } else if ( rule.condition.excludedRequestDomains ) { + generichideInclusions.push(...rule.condition.excludedRequestDomains); + } + } + } + } + } + { + const bucket = buckets.get(BLOCKIMPORTANT_REALM | typeNameToTypeValue['generichide']); + if ( bucket ) { + for ( const rules of bucket.values() ) { + for ( const rule of rules ) { + if ( rule.condition === undefined ) { continue; } + if ( rule.condition.initiatorDomains ) { + generichideInclusions.push(...rule.condition.initiatorDomains); + } else if ( rule.condition.requestDomains ) { + generichideInclusions.push(...rule.condition.requestDomains); + } } } } @@ -4714,6 +4735,7 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar acceptedFilterCount: context.acceptedFilterCount, rejectedFilterCount: context.rejectedFilterCount, generichideExclusions: Array.from(new Set(generichideExclusions)), + generichideInclusions: Array.from(new Set(generichideInclusions)), }; };