1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-07-08 12:57:57 +02:00

Fix regression with csp=, deprecate queryprune, etc

Fixed serious regression in previous dev build in applying
`csp=` filters. Reported internally by uBO team.

Promote usage of `removeparam` in code instead of `queryprune`,
which is to be deprecated.

Removed test against previously tested hostname in
FilterHostnameDict since as per various benchmark, the
test does not really help.

Remove serialization API in Node.js code as the API is now
present in SNFE itself.
This commit is contained in:
Raymond Hill 2021-12-06 07:01:39 -05:00
parent 7888e49c00
commit d3fe0ccfe0
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
4 changed files with 43 additions and 63 deletions

View File

@ -191,25 +191,6 @@ useLists.promise = null;
/******************************************************************************/ /******************************************************************************/
class MockStorage {
constructor(serialized) {
this.map = new Map(serialized);
}
async put(assetKey, content) {
this.map.set(assetKey, content);
return ({ assetKey, content });
}
async get(assetKey) {
return ({ assetKey, content: this.map.get(assetKey) });
}
*[Symbol.iterator]() {
yield* this.map;
}
}
const fctx = new FilteringContext(); const fctx = new FilteringContext();
let snfeProxyInstance = null; let snfeProxyInstance = null;
@ -253,15 +234,12 @@ class StaticNetFilteringEngine {
return compileList(...args); return compileList(...args);
} }
async serialize() { serialize() {
const storage = new MockStorage(); return snfe.serialize();
await snfe.toSelfie(storage, 'path');
return JSON.stringify([...storage]);
} }
async deserialize(serialized) { deserialize(serialized) {
const storage = new MockStorage(JSON.parse(serialized)); return snfe.unserialize(serialized);
await snfe.fromSelfie(storage, 'path');
} }
static async create({ noPSL = false } = {}) { static async create({ noPSL = false } = {}) {

View File

@ -1308,7 +1308,7 @@ Parser.prototype.SelectorCompiler = class {
[ 'matches-css-after', ':matches-css-after' ], [ 'matches-css-after', ':matches-css-after' ],
[ 'matches-css-before', ':matches-css-before' ], [ 'matches-css-before', ':matches-css-before' ],
]); ]);
this.reSimpleSelector = /^[#.][A-Za-z_][\w-]*$/; this.reSimpleSelector = /^[#.]?[A-Za-z_][\w-]*$/;
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet#browser_compatibility // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet#browser_compatibility
// Firefox does not support constructor for CSSStyleSheet // Firefox does not support constructor for CSSStyleSheet
this.stylesheet = (( ) => { this.stylesheet = (( ) => {
@ -2100,7 +2100,7 @@ const OPTTokenPopunder = 31;
const OPTTokenPopup = 32; const OPTTokenPopup = 32;
const OPTTokenRedirect = 33; const OPTTokenRedirect = 33;
const OPTTokenRedirectRule = 34; const OPTTokenRedirectRule = 34;
const OPTTokenQueryprune = 35; const OPTTokenRemoveparam = 35;
const OPTTokenScript = 36; const OPTTokenScript = 36;
const OPTTokenShide = 37; const OPTTokenShide = 37;
const OPTTokenXhr = 38; const OPTTokenXhr = 38;
@ -2200,7 +2200,7 @@ Parser.prototype.OPTTokenOther = OPTTokenOther;
Parser.prototype.OPTTokenPing = OPTTokenPing; Parser.prototype.OPTTokenPing = OPTTokenPing;
Parser.prototype.OPTTokenPopunder = OPTTokenPopunder; Parser.prototype.OPTTokenPopunder = OPTTokenPopunder;
Parser.prototype.OPTTokenPopup = OPTTokenPopup; Parser.prototype.OPTTokenPopup = OPTTokenPopup;
Parser.prototype.OPTTokenQueryprune = OPTTokenQueryprune; Parser.prototype.OPTTokenRemoveparam = OPTTokenRemoveparam;
Parser.prototype.OPTTokenRedirect = OPTTokenRedirect; Parser.prototype.OPTTokenRedirect = OPTTokenRedirect;
Parser.prototype.OPTTokenRedirectRule = OPTTokenRedirectRule; Parser.prototype.OPTTokenRedirectRule = OPTTokenRedirectRule;
Parser.prototype.OPTTokenScript = OPTTokenScript; Parser.prototype.OPTTokenScript = OPTTokenScript;
@ -2265,11 +2265,11 @@ const netOptionTokenDescriptors = new Map([
/* synonym */ [ 'beacon', OPTTokenPing | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTNonCspableType | OPTNonRedirectableType ], /* synonym */ [ 'beacon', OPTTokenPing | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTNonCspableType | OPTNonRedirectableType ],
[ 'popunder', OPTTokenPopunder | OPTNonNetworkType | OPTNonCspableType | OPTNonRedirectableType ], [ 'popunder', OPTTokenPopunder | OPTNonNetworkType | OPTNonCspableType | OPTNonRedirectableType ],
[ 'popup', OPTTokenPopup | OPTNonNetworkType | OPTCanNegate | OPTNonCspableType | OPTNonRedirectableType ], [ 'popup', OPTTokenPopup | OPTNonNetworkType | OPTCanNegate | OPTNonCspableType | OPTNonRedirectableType ],
[ 'queryprune', OPTTokenQueryprune | OPTMayAssign | OPTModifierType | OPTNonCspableType | OPTNonRedirectableType ],
/* synonym */ [ 'removeparam', OPTTokenQueryprune | OPTMayAssign | OPTModifierType | OPTNonCspableType | OPTNonRedirectableType ],
[ 'redirect', OPTTokenRedirect | OPTMustAssign | OPTAllowMayAssign | OPTModifierType ], [ 'redirect', OPTTokenRedirect | OPTMustAssign | OPTAllowMayAssign | OPTModifierType ],
/* synonym */ [ 'rewrite', OPTTokenRedirect | OPTMustAssign | OPTAllowMayAssign | OPTModifierType ], /* synonym */ [ 'rewrite', OPTTokenRedirect | OPTMustAssign | OPTAllowMayAssign | OPTModifierType ],
[ 'redirect-rule', OPTTokenRedirectRule | OPTMustAssign | OPTAllowMayAssign | OPTModifierType | OPTNonCspableType ], [ 'redirect-rule', OPTTokenRedirectRule | OPTMustAssign | OPTAllowMayAssign | OPTModifierType | OPTNonCspableType ],
[ 'removeparam', OPTTokenRemoveparam | OPTMayAssign | OPTModifierType | OPTNonCspableType | OPTNonRedirectableType ],
/* synonym */ [ 'queryprune', OPTTokenRemoveparam | OPTMayAssign | OPTModifierType | OPTNonCspableType | OPTNonRedirectableType ],
[ 'script', OPTTokenScript | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTRedirectableType | OPTNonCspableType ], [ 'script', OPTTokenScript | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTRedirectableType | OPTNonCspableType ],
[ 'shide', OPTTokenShide | OPTNonNetworkType | OPTNonCspableType | OPTNonRedirectableType ], [ 'shide', OPTTokenShide | OPTNonNetworkType | OPTNonCspableType | OPTNonRedirectableType ],
/* synonym */ [ 'specifichide', OPTTokenShide | OPTNonNetworkType | OPTNonCspableType | OPTNonRedirectableType ], /* synonym */ [ 'specifichide', OPTTokenShide | OPTNonNetworkType | OPTNonCspableType | OPTNonRedirectableType ],
@ -2324,11 +2324,11 @@ Parser.netOptionTokenIds = new Map([
/* synonym */ [ 'beacon', OPTTokenPing ], /* synonym */ [ 'beacon', OPTTokenPing ],
[ 'popunder', OPTTokenPopunder ], [ 'popunder', OPTTokenPopunder ],
[ 'popup', OPTTokenPopup ], [ 'popup', OPTTokenPopup ],
[ 'queryprune', OPTTokenQueryprune ],
/* synonym */ [ 'removeparam', OPTTokenQueryprune ],
[ 'redirect', OPTTokenRedirect ], [ 'redirect', OPTTokenRedirect ],
/* synonym */ [ 'rewrite', OPTTokenRedirect ], /* synonym */ [ 'rewrite', OPTTokenRedirect ],
[ 'redirect-rule', OPTTokenRedirectRule ], [ 'redirect-rule', OPTTokenRedirectRule ],
[ 'removeparam', OPTTokenRemoveparam ],
/* synonym */ [ 'queryprune', OPTTokenRemoveparam ],
[ 'script', OPTTokenScript ], [ 'script', OPTTokenScript ],
[ 'shide', OPTTokenShide ], [ 'shide', OPTTokenShide ],
/* synonym */ [ 'specifichide', OPTTokenShide ], /* synonym */ [ 'specifichide', OPTTokenShide ],
@ -2371,7 +2371,7 @@ Parser.netOptionTokenNames = new Map([
[ OPTTokenPing, 'ping' ], [ OPTTokenPing, 'ping' ],
[ OPTTokenPopunder, 'popunder' ], [ OPTTokenPopunder, 'popunder' ],
[ OPTTokenPopup, 'popup' ], [ OPTTokenPopup, 'popup' ],
[ OPTTokenQueryprune, 'removeparam' ], [ OPTTokenRemoveparam, 'removeparam' ],
[ OPTTokenRedirect, 'redirect' ], [ OPTTokenRedirect, 'redirect' ],
[ OPTTokenRedirectRule, 'redirect-rule' ], [ OPTTokenRedirectRule, 'redirect-rule' ],
[ OPTTokenScript, 'script' ], [ OPTTokenScript, 'script' ],
@ -2592,7 +2592,7 @@ const NetOptionsIterator = class {
} }
// `removeparam=`: only for network requests. // `removeparam=`: only for network requests.
{ {
const i = this.tokenPos[OPTTokenQueryprune]; const i = this.tokenPos[OPTTokenRemoveparam];
if ( i !== -1 ) { if ( i !== -1 ) {
if ( hasBits(allBits, OPTNonNetworkType) ) { if ( hasBits(allBits, OPTNonNetworkType) ) {
optSlices[i] = OPTTokenInvalid; optSlices[i] = OPTTokenInvalid;

View File

@ -1794,6 +1794,10 @@ const FilterModifierResult = class {
this.bits = (env.bits & ~RealmBitsMask) | filterData[imodifierunit+1]; this.bits = (env.bits & ~RealmBitsMask) | filterData[imodifierunit+1];
} }
get result() {
return (this.bits & AllowAction) === 0 ? 1 : 2;
}
get value() { get value() {
return this.refs.value; return this.refs.value;
} }
@ -1808,7 +1812,7 @@ const FilterModifierResult = class {
logData() { logData() {
const r = new LogData(this.bits, this.th, this.ireportedunit); const r = new LogData(this.bits, this.th, this.ireportedunit);
r.result = (this.bits & AllowAction) === 0 ? 1 : 2; r.result = this.result;
r.modifier = true; r.modifier = true;
return r; return r;
} }
@ -2005,26 +2009,28 @@ registerFilterClass(FilterCompositeAll);
const FilterHostnameDict = class { const FilterHostnameDict = class {
static getCount(idata) { static getCount(idata) {
const itrie = filterData[idata+1];
if ( itrie === 0 ) {
return filterRefs[filterData[idata+3]].length;
}
return Array.from( return Array.from(
destHNTrieContainer.trieIterator(filterData[idata+1]) destHNTrieContainer.trieIterator(filterData[idata+1])
).length; ).length;
} }
static match(idata) { static match(idata) {
const refs = filterRefs[filterData[idata+3]]; const itrie = filterData[idata+1] || this.optimize(idata);
if ( $requestHostname !== refs.$last ) { return (
const itrie = filterData[idata+1] || this.optimize(idata);
filterData[idata+2] = destHNTrieContainer filterData[idata+2] = destHNTrieContainer
.setNeedle(refs.$last = $requestHostname) .setNeedle($requestHostname)
.matches(itrie); .matches(itrie)
} ) !== -1;
return filterData[idata+2] !== -1;
} }
static add(idata, hn) { static add(idata, hn) {
const itrie = filterData[idata+1]; const itrie = filterData[idata+1];
if ( itrie === 0 ) { if ( itrie === 0 ) {
filterRefs[filterData[idata+3]].hostnames.push(hn); filterRefs[filterData[idata+3]].push(hn);
} else { } else {
destHNTrieContainer.setNeedle(hn).add(itrie); destHNTrieContainer.setNeedle(hn).add(itrie);
} }
@ -2033,9 +2039,9 @@ const FilterHostnameDict = class {
static optimize(idata) { static optimize(idata) {
const itrie = filterData[idata+1]; const itrie = filterData[idata+1];
if ( itrie !== 0 ) { return itrie; } if ( itrie !== 0 ) { return itrie; }
const refs = filterRefs[filterData[idata+3]]; const hostnames = filterRefs[filterData[idata+3]];
filterData[idata+1] = destHNTrieContainer.createTrie(refs.hostnames); filterData[idata+1] = destHNTrieContainer.createTrie(hostnames);
refs.hostnames = []; filterRefs[filterData[idata+3]] = null;
return filterData[idata+1]; return filterData[idata+1];
} }
@ -2044,16 +2050,12 @@ const FilterHostnameDict = class {
filterData[idata+0] = FilterHostnameDict.fid; // fid filterData[idata+0] = FilterHostnameDict.fid; // fid
filterData[idata+1] = 0; // itrie filterData[idata+1] = 0; // itrie
filterData[idata+2] = -1; // lastResult filterData[idata+2] = -1; // lastResult
filterData[idata+3] = filterRefAdd({ filterData[idata+3] = filterRefAdd([]); // []: hostnames
hostnames: [],
$last: '',
});
return idata; return idata;
} }
static logData(idata, details) { static logData(idata, details) {
const refs = filterRefs[filterData[idata+3]]; const hostname = $requestHostname.slice(filterData[idata+2]);
const hostname = refs.$last.slice(filterData[idata+2]);
details.pattern.push('||', hostname, '^'); details.pattern.push('||', hostname, '^');
details.regex.push( details.regex.push(
restrFromPlainPattern(hostname), restrFromPlainPattern(hostname),
@ -3031,11 +3033,11 @@ class FilterCompiler {
break; break;
case this.parser.OPTTokenNoop: case this.parser.OPTTokenNoop:
break; break;
case this.parser.OPTTokenQueryprune: case this.parser.OPTTokenRemoveparam:
if ( this.processModifierOption(id, val) === false ) { if ( this.processModifierOption(id, val) === false ) {
return false; return false;
} }
this.optionUnitBits |= this.QUERYPRUNE_BIT; this.optionUnitBits |= this.REMOVEPARAM_BIT;
break; break;
case this.parser.OPTTokenRedirect: case this.parser.OPTTokenRedirect:
if ( this.action === AllowAction ) { if ( this.action === AllowAction ) {
@ -3192,12 +3194,12 @@ class FilterCompiler {
// are not good. Avoid if possible. This has a significant positive // are not good. Avoid if possible. This has a significant positive
// impact on performance. // impact on performance.
// //
// For pattern-less queryprune filters, try to derive a pattern from // For pattern-less removeparam filters, try to derive a pattern from
// the queryprune value. // the removeparam value.
makeToken() { makeToken() {
if ( this.pattern === '*' ) { if ( this.pattern === '*' ) {
if ( this.modifyType !== this.parser.OPTTokenQueryprune ) { if ( this.modifyType !== this.parser.OPTTokenRemoveparam ) {
return; return;
} }
return this.extractTokenFromQuerypruneValue(); return this.extractTokenFromQuerypruneValue();
@ -3529,7 +3531,7 @@ FilterCompiler.prototype.DENYALLOW_BIT = 0b000000010;
FilterCompiler.prototype.HEADER_BIT = 0b000000100; FilterCompiler.prototype.HEADER_BIT = 0b000000100;
FilterCompiler.prototype.STRICT_PARTY_BIT = 0b000001000; FilterCompiler.prototype.STRICT_PARTY_BIT = 0b000001000;
FilterCompiler.prototype.CSP_BIT = 0b000010000; FilterCompiler.prototype.CSP_BIT = 0b000010000;
FilterCompiler.prototype.QUERYPRUNE_BIT = 0b000100000; FilterCompiler.prototype.REMOVEPARAM_BIT = 0b000100000;
FilterCompiler.prototype.REDIRECT_BIT = 0b001000000; FilterCompiler.prototype.REDIRECT_BIT = 0b001000000;
FilterCompiler.prototype.NOT_TYPE_BIT = 0b010000000; FilterCompiler.prototype.NOT_TYPE_BIT = 0b010000000;
FilterCompiler.prototype.IMPORTANT_BIT = 0b100000000; FilterCompiler.prototype.IMPORTANT_BIT = 0b100000000;
@ -3543,7 +3545,7 @@ FilterCompiler.prototype.FILTER_UNSUPPORTED = 2;
const FilterContainer = function() { const FilterContainer = function() {
this.compilerVersion = '2'; this.compilerVersion = '2';
this.selfieVersion = '2'; this.selfieVersion = '3';
this.MAX_TOKEN_LENGTH = MAX_TOKEN_LENGTH; this.MAX_TOKEN_LENGTH = MAX_TOKEN_LENGTH;
this.optimizeTaskId = undefined; this.optimizeTaskId = undefined;
@ -3898,8 +3900,8 @@ FilterContainer.prototype.fromSelfie = async function(storage, path) {
FilterContainer.prototype.unserialize = async function(s) { FilterContainer.prototype.unserialize = async function(s) {
const selfie = new Map(JSON.parse(s)); const selfie = new Map(JSON.parse(s));
const storage = { const storage = {
get(name) { async get(name) {
return Promise.resolve(selfie.get(name)); return { content: selfie.get(name) };
} }
}; };
return this.fromSelfie(storage, ''); return this.fromSelfie(storage, '');

View File

@ -58,7 +58,7 @@
<input type="search" placeholder="logFilterPrompt"> <input type="search" placeholder="logFilterPrompt">
<span id="filterExprButton" class="button fa-icon expanded" data-i18n-title="loggerRowFiltererBuiltinTip">angle-up</span> <span id="filterExprButton" class="button fa-icon expanded" data-i18n-title="loggerRowFiltererBuiltinTip">angle-up</span>
<div id="filterExprPicker"> <div id="filterExprPicker">
<div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\t--\t|\t<<\t|\t##" data-i18n="loggerRowFiltererBuiltinBlocked"></span><span data-filtex="\t\+\+\t|\t\*\*\t|\t#@#" data-i18n="loggerRowFiltererBuiltinAllowed"></span><span data-filtex="[$,](?:csp|queryprune|redirect-rule)=|\t\<\<\t" data-i18n="loggerRowFiltererBuiltinModified"></span></div> <div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\t--\t|\t<<\t|\t##" data-i18n="loggerRowFiltererBuiltinBlocked"></span><span data-filtex="\t\+\+\t|\t\*\*\t|\t#@#" data-i18n="loggerRowFiltererBuiltinAllowed"></span><span data-filtex="[$,](?:csp|removeparam|redirect-rule)=|\t\<\<\t" data-i18n="loggerRowFiltererBuiltinModified"></span></div>
<div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span> <div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span>
<span style="flex-direction: column;"> <span style="flex-direction: column;">
<div style="margin-bottom: 1px;"><span data-filtex="\t(?:css|(?:inline-)?font)\t">css/font</span><span data-filtex="\timage\t">image</span><span data-filtex="\tmedia\t">media</span><span data-filtex="\t(?:inline-)?script(?:ing)?\t">script</span></div> <div style="margin-bottom: 1px;"><span data-filtex="\t(?:css|(?:inline-)?font)\t">css/font</span><span data-filtex="\timage\t">image</span><span data-filtex="\tmedia\t">media</span><span data-filtex="\t(?:inline-)?script(?:ing)?\t">script</span></div>