mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
Improve compatibility of uritransform= with DNR syntax
The `uritransform=` option will now be converted to a proper DNR rule when the following condition are fulfilled: - The value of the `uritransform` option matches `//[replacement]/`, i.e. the pattern to match is empty, and only the replacement part is provided. - The filter pattern is a regex. Is such case, the DNR rule will be a `redirect` making use of the `regexSubstitution` property. In case the above conditions are not fulfilled, the filter will be discarded as incompatible with DNR syntax (as was the case before). This is potentially a breaking change, in cases where a filter assumed that the part to match was the start of the path part of a URL. A reminder that `uritransform` is an option which requires a trusted source, otherwise it is rejected.
This commit is contained in:
parent
25d9964b1e
commit
aaf35d9d71
5 changed files with 50 additions and 26 deletions
|
|
@ -183,7 +183,7 @@ export async function benchmarkStaticNetFiltering(options = {}) {
|
|||
if ( r === 1 ) { blockCount += 1; }
|
||||
else if ( r === 2 ) { allowCount += 1; }
|
||||
if ( r !== 1 ) {
|
||||
if ( sfne.transformRequest(fctxt) ) {
|
||||
if ( sfne.transformURL(fctxt) ) {
|
||||
redirectCount += 1;
|
||||
}
|
||||
if ( sfne.hasQuery(fctxt) ) {
|
||||
|
|
|
|||
|
|
@ -1886,7 +1886,9 @@ const onMessage = function(request, sender, callback) {
|
|||
return {
|
||||
name: assetKey,
|
||||
text: details.content,
|
||||
trustedSource: assetKey.startsWith('ublock-'),
|
||||
trustedSource: assetKey.startsWith('ublock-') ||
|
||||
assetKey === µb.userFiltersPath &&
|
||||
µb.userSettings.userFiltersTrusted,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -956,7 +956,7 @@ const PageStore = class {
|
|||
|
||||
redirectNonBlockedRequest(fctxt) {
|
||||
const directives = [];
|
||||
staticNetFilteringEngine.transformRequest(fctxt, directives);
|
||||
staticNetFilteringEngine.transformURL(fctxt, directives);
|
||||
if ( staticNetFilteringEngine.hasQuery(fctxt) ) {
|
||||
staticNetFilteringEngine.filterQuery(fctxt, directives);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -841,6 +841,11 @@ export class AstFilterParser {
|
|||
this.netOptionValueParser = new ArglistParser(',');
|
||||
this.scriptletArgListParser = new ArglistParser(',');
|
||||
this.domainRegexValueParser = new ArglistParser('/');
|
||||
this.reNetOptionTokens = new RegExp(
|
||||
`^(${Array.from(netOptionTokenDescriptors.keys())
|
||||
.map(s => escapeForRegex(s))
|
||||
.join('|')})\\b`
|
||||
);
|
||||
}
|
||||
|
||||
finish() {
|
||||
|
|
@ -1512,12 +1517,7 @@ export class AstFilterParser {
|
|||
for (;;) {
|
||||
const before = s.charAt(j-1);
|
||||
if ( before === '$' ) { return -1; }
|
||||
const after = s.charAt(j+1);
|
||||
if ( ')/|'.includes(after) === false ) {
|
||||
if ( before === '' || '"\'\\`'.includes(before) === false ) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
if ( this.reNetOptionTokens.test(s.slice(j+1)) ) { return j; }
|
||||
if ( j === start ) { break; }
|
||||
j = s.lastIndexOf('$', j-1);
|
||||
if ( j === -1 ) { break; }
|
||||
|
|
@ -3080,9 +3080,10 @@ export function parseReplaceByRegexValue(s) {
|
|||
if ( parser.transform ) {
|
||||
pattern = parser.normalizeArg(pattern);
|
||||
}
|
||||
if ( pattern === '' ) { return; }
|
||||
pattern = parser.normalizeArg(pattern, '$');
|
||||
pattern = parser.normalizeArg(pattern, ',');
|
||||
if ( pattern !== '' ) {
|
||||
pattern = parser.normalizeArg(pattern, '$');
|
||||
pattern = parser.normalizeArg(pattern, ',');
|
||||
}
|
||||
parser.nextArg(s, parser.separatorEnd);
|
||||
let replacement = s.slice(parser.argBeg, parser.argEnd);
|
||||
if ( parser.separatorEnd === parser.separatorBeg ) { return; }
|
||||
|
|
@ -3092,6 +3093,9 @@ export function parseReplaceByRegexValue(s) {
|
|||
replacement = parser.normalizeArg(replacement, '$');
|
||||
replacement = parser.normalizeArg(replacement, ',');
|
||||
const flags = s.slice(parser.separatorEnd);
|
||||
if ( pattern === '' ) {
|
||||
return { flags, replacement }
|
||||
}
|
||||
try {
|
||||
return { re: new RegExp(pattern, flags), replacement };
|
||||
} catch {
|
||||
|
|
@ -3101,7 +3105,10 @@ export function parseReplaceByRegexValue(s) {
|
|||
export function parseReplaceValue(s) {
|
||||
if ( s.startsWith('/') ) {
|
||||
const r = parseReplaceByRegexValue(s);
|
||||
if ( r ) { r.type = 'text'; }
|
||||
if ( r ) {
|
||||
if ( r.re === undefined ) { return; }
|
||||
r.type = 'text';
|
||||
}
|
||||
return r;
|
||||
}
|
||||
const pos = s.indexOf(':');
|
||||
|
|
|
|||
|
|
@ -1231,7 +1231,6 @@ class FilterRegex {
|
|||
);
|
||||
}
|
||||
if ( refs.$re.test($requestURLRaw) === false ) { return false; }
|
||||
$patternMatchLeft = $requestURLRaw.search(refs.$re);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4783,7 +4782,19 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar
|
|||
break;
|
||||
}
|
||||
case 'uritransform': {
|
||||
dnrAddRuleError(rule, `Incompatible with DNR: uritransform=${rule.__modifierValue}`);
|
||||
const parsed = sfp.parseReplaceByRegexValue(rule.__modifierValue);
|
||||
if ( parsed.re !== undefined ) {
|
||||
dnrAddRuleError(rule, `Incompatible with DNR: uritransform=${rule.__modifierValue}`);
|
||||
break;
|
||||
}
|
||||
if ( rule.condition.regexFilter === undefined ) {
|
||||
dnrAddRuleError(rule, `Incompatible with DNR (need regexFilter): uritransform=${rule.__modifierValue}`);
|
||||
break;
|
||||
}
|
||||
rule.action.type = 'redirect';
|
||||
rule.action.redirect = {
|
||||
regexSubstitution: parsed.replacement.replace(/\$(\d+)/g, '\\$1')
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 'urlskip': {
|
||||
|
|
@ -5500,7 +5511,7 @@ function compareRedirectRequests(redirectEngine, a, b) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
StaticNetFilteringEngine.prototype.transformRequest = function(fctxt, out = []) {
|
||||
StaticNetFilteringEngine.prototype.transformURL = function(fctxt, out = []) {
|
||||
const directives = this.matchAndFetchModifiers(fctxt, 'uritransform');
|
||||
if ( directives === undefined ) { return; }
|
||||
const redirectURL = new URL(fctxt.url);
|
||||
|
|
@ -5514,17 +5525,21 @@ StaticNetFilteringEngine.prototype.transformRequest = function(fctxt, out = [])
|
|||
}
|
||||
const cache = directive.cache;
|
||||
if ( cache === undefined ) { continue; }
|
||||
const before = `${redirectURL.pathname}${redirectURL.search}${redirectURL.hash}`;
|
||||
if ( cache.re.test(before) !== true ) { continue; }
|
||||
const after = before.replace(cache.re, cache.replacement);
|
||||
let { re } = cache;
|
||||
const before = redirectURL.href;
|
||||
if ( re === undefined ) {
|
||||
const logdata = directive.logData();
|
||||
if ( logdata === undefined ) { continue; }
|
||||
try { re = new RegExp(logdata.regex, cache.flags); }
|
||||
catch { continue; }
|
||||
}
|
||||
if ( re.test(before) !== true ) { continue; }
|
||||
const after = before.replace(re, cache.replacement);
|
||||
try { void new URL(after); } catch { continue; }
|
||||
if ( after === before ) { continue; }
|
||||
const hashPos = after.indexOf('#');
|
||||
redirectURL.hash = hashPos !== -1 ? after.slice(hashPos) : '';
|
||||
const afterMinusHash = hashPos !== -1 ? after.slice(0, hashPos) : after;
|
||||
const searchPos = afterMinusHash.indexOf('?');
|
||||
redirectURL.search = searchPos !== -1 ? afterMinusHash.slice(searchPos) : '';
|
||||
redirectURL.pathname = searchPos !== -1 ? after.slice(0, searchPos) : after;
|
||||
redirectURL.href = after;
|
||||
out.push(directive);
|
||||
break;
|
||||
}
|
||||
if ( out.length === 0 ) { return; }
|
||||
if ( redirectURL.href !== fctxt.url ) {
|
||||
|
|
@ -5724,7 +5739,7 @@ StaticNetFilteringEngine.prototype.test = function(details) {
|
|||
out.push('not blocked');
|
||||
}
|
||||
if ( r !== 1 ) {
|
||||
const entries = this.transformRequest(fctxt);
|
||||
const entries = this.transformURL(fctxt);
|
||||
if ( entries ) {
|
||||
for ( const entry of entries ) {
|
||||
out.push(`modified: ${entry.logData().raw}`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue