[mv3] Bypass cosmetic filtering when top context is set to no-filtering

Related issue:
https://github.com/uBlockOrigin/uBOL-home/issues/20

Specific cosmetic filtering will be bypassed when hostname of top context
matches an entry in the no-filtering set.

This doesn't completely solve the issue:
- The browser platform must support `document.location.ancestorOrigins`
- This solution can't be applied to scriptlets
This commit is contained in:
Raymond Hill 2025-12-15 16:15:13 -05:00
parent 92737bfdfe
commit a23561d79e
No known key found for this signature in database
GPG key ID: F5630CAE62A14316

View file

@ -43,6 +43,8 @@
}).filter(a => a !== undefined);
})();
isolatedAPI.topHostname = hostnameStack.at(-1)?.hnparts.join('.') ?? '';
const forEachHostname = (entry, callback, details) => {
const hnparts = entry.hnparts;
const hnpartslen = hnparts.length;
@ -81,6 +83,9 @@
if ( typeof api === 'object' ) { return; }
const cosmeticAPI = self.cosmeticAPI = {};
const { isolatedAPI } = self;
const { topHostname } = isolatedAPI;
const thisHostname = document.location.hostname || '';
const sessionRead = async function(key) {
try {
@ -145,18 +150,29 @@
const data = await localRead(`css.${realm}.${rulesetId}`);
if ( typeof data !== 'object' || data === null ) { return; }
data.result = result;
self.isolatedAPI.forEachHostname(lookupHostname, data);
isolatedAPI.forEachHostname(lookupHostname, data);
};
const fillCache = async function(realm, rulesetIds) {
const selectors = new Set();
const exceptions = new Set();
const result = { selectors, exceptions };
await Promise.all(rulesetIds.map(a => selectorsFromRuleset(realm, a, result)));
const [ filteringModeDetails ] = await Promise.all([
localRead('filteringModeDetails'),
...rulesetIds.map(a => selectorsFromRuleset(realm, a, result)),
]);
const skip = filteringModeDetails?.none.some(a => {
if ( topHostname.endsWith(a) === false ) { return false; }
const n = a.length;
return topHostname.length === n || topHostname.at(-n-1) === '.';
});
for ( const selector of exceptions ) {
selectors.delete(selector);
}
cacheEntry[cacheSlots[realm]] = Array.from(selectors).map(a =>
if ( skip ) {
selectors.clear();
}
cacheEntry[realm.charAt(0)] = Array.from(selectors).map(a =>
a.startsWith('{') ? JSON.parse(a) : a
);
};
@ -165,14 +181,14 @@
cacheEntry = await sessionRead(cacheKey) || {};
};
const cacheSlots = { 'specific': 's', 'procedural': 'p' };
const cacheKey = `cache.css.${document.location.hostname || ''}`;
const cacheKey =
`cache.css.${thisHostname || ''}${topHostname !== thisHostname ? `/${topHostname}` : ''}`;
let clientCount = 0;
let cacheEntry;
cosmeticAPI.getSelectors = async function(realm, rulesetIds) {
clientCount += 1;
const slot = cacheSlots[realm];
const slot = realm.charAt(0);
if ( cacheEntry === undefined ) {
cacheEntry = readCache();
}