mirror of https://github.com/gorhill/uBlock.git
Add support for exception of `document` to bypass strict-blocking
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/1501 Exception filters for `document` option are complying with uBO's own semantic for `document` option, i.e. an exception filter for `document` option will only allow to bypass a block filter for `document` (either explicit or implicit) and nothing else. Exception filters using `document` option are *not* compatible with ABP's interpretation of these filters. Whereas in ABP the purpose of a `document` exception filter is to wholly disable content blocking, in uBO the same filter will just cause strict-blocking to be disabled while leaving content blocking intact. Additionally, the logger was fixed to properly report pages which are being strict-blocked.
This commit is contained in:
parent
96049f147e
commit
3af1120082
|
@ -1348,6 +1348,7 @@ vAPI.messaging.listen({
|
||||||
|
|
||||||
const µb = µBlock;
|
const µb = µBlock;
|
||||||
const extensionOriginURL = vAPI.getURL('');
|
const extensionOriginURL = vAPI.getURL('');
|
||||||
|
const documentBlockedURL = vAPI.getURL('document-blocked.html');
|
||||||
|
|
||||||
const getLoggerData = async function(details, activeTabId, callback) {
|
const getLoggerData = async function(details, activeTabId, callback) {
|
||||||
const response = {
|
const response = {
|
||||||
|
@ -1360,18 +1361,24 @@ const getLoggerData = async function(details, activeTabId, callback) {
|
||||||
};
|
};
|
||||||
if ( µb.pageStoresToken !== details.tabIdsToken ) {
|
if ( µb.pageStoresToken !== details.tabIdsToken ) {
|
||||||
const tabIds = new Map();
|
const tabIds = new Map();
|
||||||
for ( const entry of µb.pageStores ) {
|
for ( const [ tabId, pageStore ] of µb.pageStores ) {
|
||||||
const pageStore = entry[1];
|
const { rawURL } = pageStore;
|
||||||
if ( pageStore.rawURL.startsWith(extensionOriginURL) ) { continue; }
|
if (
|
||||||
tabIds.set(entry[0], pageStore.title);
|
rawURL.startsWith(extensionOriginURL) === false ||
|
||||||
|
rawURL.startsWith(documentBlockedURL)
|
||||||
|
) {
|
||||||
|
tabIds.set(tabId, pageStore.title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
response.tabIds = Array.from(tabIds);
|
response.tabIds = Array.from(tabIds);
|
||||||
}
|
}
|
||||||
if ( activeTabId ) {
|
if ( activeTabId ) {
|
||||||
const pageStore = µb.pageStoreFromTabId(activeTabId);
|
const pageStore = µb.pageStoreFromTabId(activeTabId);
|
||||||
|
const rawURL = pageStore && pageStore.rawURL;
|
||||||
if (
|
if (
|
||||||
pageStore === null ||
|
rawURL === null ||
|
||||||
pageStore.rawURL.startsWith(extensionOriginURL)
|
rawURL.startsWith(extensionOriginURL) &&
|
||||||
|
rawURL.startsWith(documentBlockedURL) === false
|
||||||
) {
|
) {
|
||||||
response.activeTabId = undefined;
|
response.activeTabId = undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4131,7 +4131,20 @@ FilterContainer.prototype.matchStringReverse = function(type, url) {
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/519
|
// https://github.com/chrisaljoudi/uBlock/issues/519
|
||||||
// Use exact type match for anything beyond `other`. Also, be prepared to
|
// Use exact type match for anything beyond `other`. Also, be prepared to
|
||||||
// support unknown types.
|
// support unknown types.
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/1501
|
||||||
|
// Add support to evaluate allow realm before block realm.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a URL string using filtering context.
|
||||||
|
* @param {FilteringContext} fctxt - The filtering context
|
||||||
|
* @param {integer} [modifier=0] - A bit vector modifying the behavior of the
|
||||||
|
* matching algorithm:
|
||||||
|
* Bit 0: match exact type.
|
||||||
|
* Bit 1: lookup allow realm regardless of whether there was a match in
|
||||||
|
* block realm.
|
||||||
|
*
|
||||||
|
* @returns {integer} 0=no match, 1=block, 2=allow (exeption)
|
||||||
|
*/
|
||||||
FilterContainer.prototype.matchString = function(fctxt, modifiers = 0) {
|
FilterContainer.prototype.matchString = function(fctxt, modifiers = 0) {
|
||||||
let typeValue = typeNameToTypeValue[fctxt.type];
|
let typeValue = typeNameToTypeValue[fctxt.type];
|
||||||
if ( modifiers === 0 ) {
|
if ( modifiers === 0 ) {
|
||||||
|
@ -4159,17 +4172,18 @@ FilterContainer.prototype.matchString = function(fctxt, modifiers = 0) {
|
||||||
$docEntity.reset();
|
$docEntity.reset();
|
||||||
$requestHostname = fctxt.getHostname();
|
$requestHostname = fctxt.getHostname();
|
||||||
|
|
||||||
// Important block filters.
|
// Important block realm.
|
||||||
if ( this.realmMatchString(BlockImportant, typeValue, partyBits) ) {
|
if ( this.realmMatchString(BlockImportant, typeValue, partyBits) ) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// Block filters
|
|
||||||
if ( this.realmMatchString(BlockAction, typeValue, partyBits) ) {
|
// Evaluate block realm before allow realm.
|
||||||
// Exception filters
|
const r = this.realmMatchString(BlockAction, typeValue, partyBits);
|
||||||
|
if ( r || (modifiers & 0b0010) !== 0 ) {
|
||||||
if ( this.realmMatchString(AllowAction, typeValue, partyBits) ) {
|
if ( this.realmMatchString(AllowAction, typeValue, partyBits) ) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
return 1;
|
if ( r ) { return 1; }
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -172,37 +172,9 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static filtering: We always need the long-form result here.
|
// Static filtering
|
||||||
const snfe = µb.staticNetFilteringEngine;
|
|
||||||
|
|
||||||
// Check for specific block
|
|
||||||
if ( result === 0 ) {
|
if ( result === 0 ) {
|
||||||
result = snfe.matchString(fctxt, 0b0001);
|
({ result, logData } = shouldStrictBlock(fctxt, loggerEnabled));
|
||||||
if ( result !== 0 || loggerEnabled ) {
|
|
||||||
logData = snfe.toLogData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for generic block
|
|
||||||
if ( result === 0 ) {
|
|
||||||
fctxt.type = 'no_type';
|
|
||||||
result = snfe.matchString(fctxt, 0b0001);
|
|
||||||
if ( result !== 0 || loggerEnabled ) {
|
|
||||||
logData = snfe.toLogData();
|
|
||||||
}
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/1128
|
|
||||||
// Do not block if the match begins after the hostname, except when
|
|
||||||
// the filter is specifically of type `other`.
|
|
||||||
// https://github.com/gorhill/uBlock/issues/490
|
|
||||||
// Removing this for the time being, will need a new, dedicated type.
|
|
||||||
if (
|
|
||||||
result === 1 &&
|
|
||||||
toBlockDocResult(requestURL, requestHostname, logData) === false
|
|
||||||
) {
|
|
||||||
result = 0;
|
|
||||||
logData = undefined;
|
|
||||||
}
|
|
||||||
fctxt.type = 'main_frame';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageStore = µb.bindTabToPageStore(fctxt.tabId, 'beforeRequest');
|
const pageStore = µb.bindTabToPageStore(fctxt.tabId, 'beforeRequest');
|
||||||
|
@ -221,7 +193,7 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
||||||
result !== 1 &&
|
result !== 1 &&
|
||||||
trusted === false &&
|
trusted === false &&
|
||||||
pageStore !== null &&
|
pageStore !== null &&
|
||||||
snfe.hasQuery(fctxt)
|
µb.staticNetFilteringEngine.hasQuery(fctxt)
|
||||||
) {
|
) {
|
||||||
pageStore.redirectNonBlockedRequest(fctxt);
|
pageStore.redirectNonBlockedRequest(fctxt);
|
||||||
}
|
}
|
||||||
|
@ -263,16 +235,109 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Strict blocking through static filtering
|
||||||
|
//
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/1128
|
||||||
|
// Do not block if the match begins after the hostname,
|
||||||
|
// except when the filter is specifically of type `other`.
|
||||||
|
// https://github.com/gorhill/uBlock/issues/490
|
||||||
|
// Removing this for the time being, will need a new, dedicated type.
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/1501
|
||||||
|
// Support explicit exception filters.
|
||||||
|
//
|
||||||
|
// Let result of match for specific `document` type be `rs`
|
||||||
|
// Let result of match for no specific type be `rg` *after* going through
|
||||||
|
// confirmation necessary for implicit matches
|
||||||
|
// Let `important` be `i`
|
||||||
|
// Let final result be logical combination of `rs` and `rg` as follow:
|
||||||
|
//
|
||||||
|
// | rs |
|
||||||
|
// +--------+--------+--------+--------|
|
||||||
|
// | 0 | 1 | 1i | 2 |
|
||||||
|
// --------+--------+--------+--------+--------+--------|
|
||||||
|
// | 0 | rg | rs | rs | rs |
|
||||||
|
// rg | 1 | rg | rs | rs | rs |
|
||||||
|
// | 1i | rg | rg | rs | rg |
|
||||||
|
// | 2 | rg | rg | rs | rs |
|
||||||
|
// --------+--------+--------+--------+--------+--------+
|
||||||
|
|
||||||
|
const shouldStrictBlock = function(fctxt, loggerEnabled) {
|
||||||
|
const µb = µBlock;
|
||||||
|
const snfe = µb.staticNetFilteringEngine;
|
||||||
|
|
||||||
|
// Explicit filtering: `document` option
|
||||||
|
const rs = snfe.matchString(fctxt, 0b0011);
|
||||||
|
const is = rs === 1 && snfe.isBlockImportant();
|
||||||
|
let lds;
|
||||||
|
if ( rs !== 0 && loggerEnabled ) {
|
||||||
|
lds = snfe.toLogData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// | rs |
|
||||||
|
// +--------+--------+--------+--------|
|
||||||
|
// | 0 | 1 | 1i | 2 |
|
||||||
|
// --------+--------+--------+--------+--------+--------|
|
||||||
|
// | 0 | rg | rs | x | rs |
|
||||||
|
// rg | 1 | rg | rs | x | rs |
|
||||||
|
// | 1i | rg | rg | x | rg |
|
||||||
|
// | 2 | rg | rg | x | rs |
|
||||||
|
// --------+--------+--------+--------+--------+--------+
|
||||||
|
if ( rs === 1 && is ) {
|
||||||
|
return { result: rs, logData: lds };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implicit filtering: no `document` option
|
||||||
|
fctxt.type = 'no_type';
|
||||||
|
let rg = snfe.matchString(fctxt, 0b0011);
|
||||||
|
fctxt.type = 'main_frame';
|
||||||
|
const ig = rg === 1 && snfe.isBlockImportant();
|
||||||
|
let ldg;
|
||||||
|
if ( rg !== 0 || loggerEnabled ) {
|
||||||
|
ldg = snfe.toLogData();
|
||||||
|
if ( rg === 1 && validateStrictBlock(fctxt, ldg) === false ) {
|
||||||
|
rg = 0; ldg = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// | rs |
|
||||||
|
// +--------+--------+--------+--------|
|
||||||
|
// | 0 | 1 | 1i | 2 |
|
||||||
|
// --------+--------+--------+--------+--------+--------|
|
||||||
|
// | 0 | x | rs | - | rs |
|
||||||
|
// rg | 1 | x | rs | - | rs |
|
||||||
|
// | 1i | x | x | - | x |
|
||||||
|
// | 2 | x | x | - | rs |
|
||||||
|
// --------+--------+--------+--------+--------+--------+
|
||||||
|
if ( rs === 0 || rg === 1 && ig || rg === 2 && rs !== 2 ) {
|
||||||
|
return { result: rg, logData: ldg };
|
||||||
|
}
|
||||||
|
|
||||||
|
// | rs |
|
||||||
|
// +--------+--------+--------+--------|
|
||||||
|
// | 0 | 1 | 1i | 2 |
|
||||||
|
// --------+--------+--------+--------+--------+--------|
|
||||||
|
// | 0 | - | x | - | x |
|
||||||
|
// rg | 1 | - | x | - | x |
|
||||||
|
// | 1i | - | - | - | - |
|
||||||
|
// | 2 | - | - | - | x |
|
||||||
|
// --------+--------+--------+--------+--------+--------+
|
||||||
|
return { result: rs, logData: lds };
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/3208
|
// https://github.com/gorhill/uBlock/issues/3208
|
||||||
// Mind case insensitivity.
|
// Mind case insensitivity.
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1147
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/1147
|
||||||
// Do not strict-block if the filter pattern does not contain at least one
|
// Do not strict-block if the filter pattern does not contain at least one
|
||||||
// token character.
|
// token character.
|
||||||
const toBlockDocResult = function(url, hostname, logData) {
|
|
||||||
|
const validateStrictBlock = function(fctxt, logData) {
|
||||||
if ( typeof logData.regex !== 'string' ) { return false; }
|
if ( typeof logData.regex !== 'string' ) { return false; }
|
||||||
if ( typeof logData.raw === 'string' && /\w/.test(logData.raw) === false ) {
|
if ( typeof logData.raw === 'string' && /\w/.test(logData.raw) === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const url = fctxt.url;
|
||||||
const re = new RegExp(logData.regex, 'i');
|
const re = new RegExp(logData.regex, 'i');
|
||||||
const match = re.exec(url.toLowerCase());
|
const match = re.exec(url.toLowerCase());
|
||||||
if ( match === null ) { return false; }
|
if ( match === null ) { return false; }
|
||||||
|
@ -283,6 +348,7 @@ const toBlockDocResult = function(url, hostname, logData) {
|
||||||
// hostname.
|
// hostname.
|
||||||
// https://github.com/uBlockOrigin/uAssets/issues/7619#issuecomment-653010310
|
// https://github.com/uBlockOrigin/uAssets/issues/7619#issuecomment-653010310
|
||||||
// Also match FQDN.
|
// Also match FQDN.
|
||||||
|
const hostname = fctxt.getHostname();
|
||||||
const hnpos = url.indexOf(hostname);
|
const hnpos = url.indexOf(hostname);
|
||||||
const hnlen = hostname.length;
|
const hnlen = hostname.length;
|
||||||
const end = match.index + match[0].length - hnpos - hnlen;
|
const end = match.index + match[0].length - hnpos - hnlen;
|
||||||
|
|
Loading…
Reference in New Issue