mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 09:07:54 +01:00
this fixes #582
This commit is contained in:
parent
a2ff66e20f
commit
673b8774be
9 changed files with 386 additions and 213 deletions
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
|
||||
"name": "µBlock",
|
||||
"version": "0.8.5.7",
|
||||
"version": "0.8.6.0",
|
||||
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_extShortDesc__",
|
||||
|
|
|
@ -45,7 +45,7 @@ vAPI.firefox = true;
|
|||
// TODO: read these data from somewhere...
|
||||
vAPI.app = {
|
||||
name: 'µBlock',
|
||||
version: '0.8.5.7'
|
||||
version: '0.8.6.0'
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -61,27 +61,31 @@ body[dir="rtl"] #content {
|
|||
vertical-align: top;
|
||||
}
|
||||
#content table tr td:nth-of-type(1) {
|
||||
padding: 3px 0;
|
||||
text-align: center;
|
||||
}
|
||||
#content table tr td:nth-of-type(2) {
|
||||
white-space: normal;
|
||||
width: 25%;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
#content table tr td:nth-of-type(2) {
|
||||
#content table tr td:nth-of-type(3) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
#content table tr td:nth-of-type(3) {
|
||||
#content table tr td:nth-of-type(4) {
|
||||
border-right: none;
|
||||
white-space: normal;
|
||||
width: 60%;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
#content table tr td:nth-of-type(3) b {
|
||||
#content table tr td:nth-of-type(4) b {
|
||||
font-weight: normal;
|
||||
}
|
||||
#content table tr.blocked td:nth-of-type(3) b {
|
||||
#content table tr.blocked td:nth-of-type(4) b {
|
||||
background-color: rgba(192, 0, 0, 0.2);
|
||||
}
|
||||
#content table tr.allowed td:nth-of-type(3) b {
|
||||
#content table tr.allowed td:nth-of-type(4) b {
|
||||
background-color: rgba(0, 160, 0, 0.2);
|
||||
}
|
|
@ -107,7 +107,7 @@ return {
|
|||
firstUpdateAfter: 5 * oneMinute,
|
||||
nextUpdateAfter: 7 * oneHour,
|
||||
|
||||
selfieMagic: 'qidcglrwobsm',
|
||||
selfieMagic: 'knreayqtuguf',
|
||||
selfieAfter: 7 * oneMinute,
|
||||
|
||||
pageStores: {},
|
||||
|
|
|
@ -33,20 +33,29 @@
|
|||
|
||||
// https://github.com/gorhill/uBlock/issues/464
|
||||
if ( document instanceof HTMLDocument === false ) {
|
||||
//console.debug('contentscript-end.js > not a HTLMDocument');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !vAPI ) {
|
||||
//console.debug('contentscript-end.js > vAPI not found');
|
||||
return;
|
||||
}
|
||||
|
||||
if ( vAPI.canExecuteContentScript() !== true ) {
|
||||
//console.debug('contentscript-end.js > can\'t execute');
|
||||
return;
|
||||
}
|
||||
|
||||
// Pointless to execute without the start script having done its job.
|
||||
if ( !vAPI.contentscriptStartInjected ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/456
|
||||
// Already injected?
|
||||
if ( vAPI.contentscriptEndInjected ) {
|
||||
//console.debug('contentscript-end.js > content script already injected');
|
||||
return;
|
||||
}
|
||||
vAPI.contentscriptEndInjected = true;
|
||||
|
|
|
@ -36,22 +36,26 @@
|
|||
|
||||
// https://github.com/gorhill/uBlock/issues/464
|
||||
if ( document instanceof HTMLDocument === false ) {
|
||||
//console.debug('contentscript-start.js > not a HTLMDocument');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Because in case
|
||||
if ( !vAPI ) {
|
||||
//console.debug('contentscript-start.js > vAPI not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Because Safari
|
||||
if ( vAPI.canExecuteContentScript() !== true ) {
|
||||
//console.debug('contentscript-start.js > can\'t execute');
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/456
|
||||
// Already injected?
|
||||
if ( vAPI.contentscriptStartInjected ) {
|
||||
//console.debug('contentscript-start.js > content script already injected');
|
||||
return;
|
||||
}
|
||||
vAPI.contentscriptStartInjected = true;
|
||||
|
@ -139,7 +143,13 @@ var filteringHandler = function(details) {
|
|||
// The port will never be used again at this point, disconnecting allows
|
||||
// the browser to flush this script from memory.
|
||||
}
|
||||
// Do not close the port before we are done.
|
||||
|
||||
// If no filters were found, maybe the script was injected before uBlock's
|
||||
// process was fully initialized. When this happens, pages won't be
|
||||
// cleaned right after browser launch.
|
||||
vAPI.contentscriptStartInjected = !details || details.cosmeticHide.length !== 0;
|
||||
|
||||
// Cleanup before leaving
|
||||
localMessager.close();
|
||||
};
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ var renderURL = function(url, filter) {
|
|||
}
|
||||
if ( reText === '*' ) {
|
||||
reText = '\\*';
|
||||
} else if ( reText.charAt(0) === '/' && reText.slice(-1) === '/' ) {
|
||||
reText = reText.slice(1, -1);
|
||||
} else {
|
||||
reText = reText
|
||||
.replace(/\./g, '\\.')
|
||||
|
@ -87,6 +89,7 @@ var createRow = function() {
|
|||
tr.appendChild(doc.createElement('td'));
|
||||
tr.appendChild(doc.createElement('td'));
|
||||
tr.appendChild(doc.createElement('td'));
|
||||
tr.appendChild(doc.createElement('td'));
|
||||
return tr;
|
||||
};
|
||||
|
||||
|
@ -96,18 +99,26 @@ var renderLogEntry = function(entry) {
|
|||
var tr = createRow();
|
||||
if ( entry.result.charAt(1) === 'b' ) {
|
||||
tr.classList.add('blocked');
|
||||
tr.cells[0].textContent = '\u2009\u2212\u2009';
|
||||
} else if ( entry.result.charAt(1) === 'a' ) {
|
||||
tr.classList.add('allowed');
|
||||
if ( entry.result.charAt(0) === 'm' ) {
|
||||
tr.classList.add('mirrored');
|
||||
}
|
||||
tr.cells[0].textContent = '\u2009+\u2009';
|
||||
} else {
|
||||
tr.cells[0].textContent = '\u2009\u00A0\u2009';
|
||||
}
|
||||
if ( entry.type === 'main_frame' ) {
|
||||
tr.classList.add('maindoc');
|
||||
}
|
||||
tr.cells[0].textContent = entry.result.slice(3);
|
||||
tr.cells[1].textContent = entry.type;
|
||||
vAPI.insertHTML(tr.cells[2], renderURL(entry.url, entry.result));
|
||||
var filterText = entry.result.slice(3);
|
||||
if ( entry.result.lastIndexOf('sa', 0) === 0 ) {
|
||||
filterText = '@@' + filterText;
|
||||
}
|
||||
tr.cells[1].textContent = filterText;
|
||||
tr.cells[2].textContent = entry.type;
|
||||
vAPI.insertHTML(tr.cells[3], renderURL(entry.url, entry.result));
|
||||
tbody.insertBefore(tr, tbody.firstChild);
|
||||
};
|
||||
|
||||
|
|
|
@ -79,8 +79,6 @@ const AllowAnyParty = AllowAction | AnyParty;
|
|||
|
||||
var pageHostname = ''; // short-lived register
|
||||
|
||||
var reIgnoreEmpty = /^\s+$/;
|
||||
var reIgnoreComment = /^\[|^!/;
|
||||
var reHostnameRule = /^[0-9a-z][0-9a-z.-]+[0-9a-z]$/;
|
||||
var reHostnameToken = /^[0-9a-z]+/g;
|
||||
var reGoodToken = /[%0-9a-z]{2,}/g;
|
||||
|
@ -813,6 +811,61 @@ FilterManyWildcardsHostname.fromSelfie = function(s) {
|
|||
return new FilterManyWildcardsHostname(args[0], atoi(args[1]), args[2]);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Regex-based filters
|
||||
|
||||
var FilterRegex = function(s) {
|
||||
this.re = new RegExp(s);
|
||||
};
|
||||
|
||||
FilterRegex.prototype.match = function(url) {
|
||||
return this.re.test(url);
|
||||
};
|
||||
|
||||
FilterRegex.prototype.fid = '//';
|
||||
|
||||
FilterRegex.prototype.toString = function() {
|
||||
return '/' + this.re.source + '/';
|
||||
};
|
||||
|
||||
FilterRegex.prototype.toSelfie = function() {
|
||||
return this.re.source;
|
||||
};
|
||||
|
||||
FilterRegex.fromSelfie = function(s) {
|
||||
return new FilterRegex(s);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterRegexHostname = function(s, hostname) {
|
||||
this.re = new RegExp(s);
|
||||
this.hostname = hostname;
|
||||
};
|
||||
|
||||
FilterRegexHostname.prototype.match = function(url) {
|
||||
// test hostname first, it's cheaper than evaluating a regex
|
||||
return pageHostname.slice(-this.hostname.length) === this.hostname &&
|
||||
this.re.test(url);
|
||||
};
|
||||
|
||||
FilterRegexHostname.prototype.fid = '//h';
|
||||
|
||||
FilterRegexHostname.prototype.toString = function() {
|
||||
return '/' + this.re.source + '/$domain=' + this.hostname;
|
||||
};
|
||||
|
||||
FilterRegexHostname.prototype.toSelfie = function() {
|
||||
return this.re.source + '\t' +
|
||||
this.hostname;
|
||||
};
|
||||
|
||||
FilterRegexHostname.fromSelfie = function(s) {
|
||||
var pos = s.indexOf('\t');
|
||||
return new FilterRegexHostname(s.slice(0, pos), s.slice(pos + 1));
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -920,12 +973,15 @@ FilterBucket.fromSelfie = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var makeFilter = function(details, tokenBeg) {
|
||||
var makeFilter = function(details) {
|
||||
var s = details.f;
|
||||
if ( details.isRegex ) {
|
||||
return new FilterRegex(s);
|
||||
}
|
||||
var wcOffset = s.indexOf('*');
|
||||
if ( wcOffset !== -1 ) {
|
||||
if ( s.indexOf('*', wcOffset + 1) !== -1 ) {
|
||||
return details.anchor === 0 ? new FilterManyWildcards(s, tokenBeg) : null;
|
||||
return details.anchor === 0 ? new FilterManyWildcards(s, details.tokenBeg) : null;
|
||||
}
|
||||
var lSegment = s.slice(0, wcOffset);
|
||||
var rSegment = s.slice(wcOffset + 1);
|
||||
|
@ -935,10 +991,10 @@ var makeFilter = function(details, tokenBeg) {
|
|||
if ( details.anchor > 0 ) {
|
||||
return new FilterSingleWildcardRightAnchored(lSegment, rSegment);
|
||||
}
|
||||
if ( tokenBeg === 0 ) {
|
||||
if ( details.tokenBeg === 0 ) {
|
||||
return new FilterSingleWildcardPrefix0(lSegment, rSegment);
|
||||
}
|
||||
return new FilterSingleWildcard(lSegment, rSegment, tokenBeg);
|
||||
return new FilterSingleWildcard(lSegment, rSegment, details.tokenBeg);
|
||||
}
|
||||
if ( details.anchor < 0 ) {
|
||||
return new FilterPlainLeftAnchored(s);
|
||||
|
@ -949,23 +1005,26 @@ var makeFilter = function(details, tokenBeg) {
|
|||
if ( details.hostnameAnchored ) {
|
||||
return new FilterPlainHnAnchored(s);
|
||||
}
|
||||
if ( tokenBeg === 0 ) {
|
||||
if ( details.tokenBeg === 0 ) {
|
||||
return new FilterPlainPrefix0(s);
|
||||
}
|
||||
if ( tokenBeg === 1 ) {
|
||||
if ( details.tokenBeg === 1 ) {
|
||||
return new FilterPlainPrefix1(s);
|
||||
}
|
||||
return new FilterPlain(s, tokenBeg);
|
||||
return new FilterPlain(s, details.tokenBeg);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var makeHostnameFilter = function(details, tokenBeg, hostname) {
|
||||
var makeHostnameFilter = function(details, hostname) {
|
||||
var s = details.f;
|
||||
if ( details.isRegex ) {
|
||||
return new FilterRegexHostname(s, hostname);
|
||||
}
|
||||
var wcOffset = s.indexOf('*');
|
||||
if ( wcOffset !== -1 ) {
|
||||
if ( s.indexOf('*', wcOffset + 1) !== -1 ) {
|
||||
return details.anchor === 0 ? new FilterManyWildcardsHostname(s, tokenBeg, hostname) : null;
|
||||
return details.anchor === 0 ? new FilterManyWildcardsHostname(s, details.tokenBeg, hostname) : null;
|
||||
}
|
||||
var lSegment = s.slice(0, wcOffset);
|
||||
var rSegment = s.slice(wcOffset + 1);
|
||||
|
@ -975,10 +1034,10 @@ var makeHostnameFilter = function(details, tokenBeg, hostname) {
|
|||
if ( details.anchor > 0 ) {
|
||||
return new FilterSingleWildcardRightAnchoredHostname(lSegment, rSegment, hostname);
|
||||
}
|
||||
if ( tokenBeg === 0 ) {
|
||||
if ( details.tokenBeg === 0 ) {
|
||||
return new FilterSingleWildcardPrefix0Hostname(lSegment, rSegment, hostname);
|
||||
}
|
||||
return new FilterSingleWildcardHostname(lSegment, rSegment, tokenBeg, hostname);
|
||||
return new FilterSingleWildcardHostname(lSegment, rSegment, details.tokenBeg, hostname);
|
||||
}
|
||||
if ( details.anchor < 0 ) {
|
||||
return new FilterPlainLeftAnchoredHostname(s, hostname);
|
||||
|
@ -986,13 +1045,13 @@ var makeHostnameFilter = function(details, tokenBeg, hostname) {
|
|||
if ( details.anchor > 0 ) {
|
||||
return new FilterPlainRightAnchoredHostname(s, hostname);
|
||||
}
|
||||
if ( tokenBeg === 0 ) {
|
||||
if ( details.tokenBeg === 0 ) {
|
||||
return new FilterPlainPrefix0Hostname(s, hostname);
|
||||
}
|
||||
if ( tokenBeg === 1 ) {
|
||||
if ( details.tokenBeg === 1 ) {
|
||||
return new FilterPlainPrefix1Hostname(s, hostname);
|
||||
}
|
||||
return new FilterPlainHostname(s, tokenBeg, hostname);
|
||||
return new FilterPlainHostname(s, details.tokenBeg, hostname);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -1060,7 +1119,10 @@ var trimChar = function(s, c) {
|
|||
/******************************************************************************/
|
||||
|
||||
var FilterParser = function() {
|
||||
this.reHasWildcard = /[\^\*]/;
|
||||
this.reHasUppercase = /[A-Z]/;
|
||||
this.hostnames = [];
|
||||
this.notHostnames = [];
|
||||
this.types = [];
|
||||
this.reset();
|
||||
};
|
||||
|
@ -1092,8 +1154,12 @@ FilterParser.prototype.reset = function() {
|
|||
this.hostnameAnchored = false;
|
||||
this.hostnamePure = false;
|
||||
this.hostnames.length = 0;
|
||||
this.notHostname = false;
|
||||
this.notHostnames.length = 0;
|
||||
this.isRegex = false;
|
||||
this.thirdParty = false;
|
||||
this.token = '';
|
||||
this.tokenBeg = 0;
|
||||
this.tokenEnd = 0;
|
||||
this.types.length = 0;
|
||||
this.important = 0;
|
||||
this.unsupported = false;
|
||||
|
@ -1140,101 +1206,22 @@ FilterParser.prototype.parseOptParty = function(not) {
|
|||
|
||||
FilterParser.prototype.parseOptHostnames = function(raw) {
|
||||
var hostnames = raw.split('|');
|
||||
var hostname, not;
|
||||
var hostname;
|
||||
for ( var i = 0; i < hostnames.length; i++ ) {
|
||||
hostname = hostnames[i];
|
||||
not = hostname.charAt(0) === '~';
|
||||
if ( not ) {
|
||||
hostname = hostname.slice(1);
|
||||
if ( hostname.charAt(0) === '~' ) {
|
||||
this.notHostnames.push(hostname.slice(1));
|
||||
} else {
|
||||
this.hostnames.push(hostname);
|
||||
}
|
||||
// https://github.com/gorhill/uBlock/issues/191
|
||||
// Well it doesn't seem to make a whole lot of sense to have both
|
||||
// non-negated hostnames mixed with negated hostnames.
|
||||
if ( this.hostnames.length !== 0 && not !== this.notHostname ) {
|
||||
console.error('FilterContainer.parseOptHostnames(): ambiguous filter syntax: "%s"', this.f);
|
||||
this.unsupported = true;
|
||||
return;
|
||||
}
|
||||
this.notHostname = not;
|
||||
this.hostnames.push(hostname);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterParser.prototype.parse = function(s) {
|
||||
// important!
|
||||
this.reset();
|
||||
|
||||
if ( reHostnameRule.test(s) ) {
|
||||
this.f = s;
|
||||
this.hostnamePure = this.hostnameAnchored = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// element hiding filter?
|
||||
if ( s.indexOf('##') >= 0 || s.indexOf('#@') >= 0 ) {
|
||||
this.elemHiding = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// block or allow filter?
|
||||
if ( s.slice(0, 2) === '@@' ) {
|
||||
this.action = AllowAction;
|
||||
s = s.slice(2);
|
||||
}
|
||||
|
||||
// options
|
||||
var pos = s.indexOf('$');
|
||||
if ( pos > 0 ) {
|
||||
this.fopts = s.slice(pos + 1);
|
||||
s = s.slice(0, pos);
|
||||
}
|
||||
|
||||
// regex? (not supported)
|
||||
if ( s.charAt(0) === '/' && s.slice(-1) === '/' ) {
|
||||
this.unsupported = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// hostname anchoring
|
||||
if ( s.slice(0, 2) === '||' ) {
|
||||
this.hostnameAnchored = true;
|
||||
s = s.slice(2);
|
||||
}
|
||||
|
||||
// left-anchored
|
||||
if ( s.charAt(0) === '|' ) {
|
||||
this.anchor = -1;
|
||||
s = s.slice(1);
|
||||
}
|
||||
|
||||
// right-anchored
|
||||
if ( s.slice(-1) === '|' ) {
|
||||
this.anchor = 1;
|
||||
s = s.slice(0, -1);
|
||||
}
|
||||
|
||||
// normalize placeholders
|
||||
// TODO: transforming `^` into `*` is not a strict interpretation of
|
||||
// ABP syntax.
|
||||
s = s.replace(/\^/g, '*');
|
||||
s = s.replace(/\*\*+/g, '*');
|
||||
|
||||
// remove leading and trailing wildcards
|
||||
s = trimChar(s, '*');
|
||||
|
||||
// pure hostname-based?
|
||||
this.hostnamePure = this.hostnameAnchored && reHostnameRule.test(s);
|
||||
|
||||
this.f = s;
|
||||
|
||||
if ( !this.fopts ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// parse options
|
||||
var opts = this.fopts.split(',');
|
||||
FilterParser.prototype.parseOptions = function(s) {
|
||||
this.fopts = s;
|
||||
var opts = s.split(',');
|
||||
var opt, not;
|
||||
for ( var i = 0; i < opts.length; i++ ) {
|
||||
opt = opts[i];
|
||||
|
@ -1270,9 +1257,119 @@ FilterParser.prototype.parse = function(s) {
|
|||
this.unsupported = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterParser.prototype.parse = function(s) {
|
||||
// important!
|
||||
this.reset();
|
||||
|
||||
// plain hostname?
|
||||
if ( reHostnameRule.test(s) ) {
|
||||
this.f = s;
|
||||
this.hostnamePure = this.hostnameAnchored = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// element hiding filter?
|
||||
var pos = s.indexOf('#');
|
||||
if ( pos !== -1 ) {
|
||||
var c = s.charAt(pos + 1);
|
||||
if ( c === '#' || c === '@' ) {
|
||||
console.error('static-net-filtering.js > unexpected cosmetic filters');
|
||||
this.elemHiding = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// options
|
||||
pos = s.indexOf('$');
|
||||
if ( pos !== -1 ) {
|
||||
this.parseOptions(s.slice(pos + 1));
|
||||
s = s.slice(0, pos);
|
||||
}
|
||||
|
||||
// block or allow filter?
|
||||
if ( s.lastIndexOf('@@', 0) === 0 ) {
|
||||
this.action = AllowAction;
|
||||
s = s.slice(2);
|
||||
}
|
||||
|
||||
// regex?
|
||||
if ( s.charAt(0) === '/' && s.slice(-1) === '/' ) {
|
||||
this.isRegex = true;
|
||||
this.f = s.slice(1, -1);
|
||||
return this;
|
||||
}
|
||||
|
||||
// hostname anchoring
|
||||
if ( s.lastIndexOf('||', 0) === 0 ) {
|
||||
this.hostnameAnchored = true;
|
||||
s = s.slice(2);
|
||||
}
|
||||
|
||||
// left-anchored
|
||||
if ( s.charAt(0) === '|' ) {
|
||||
this.anchor = -1;
|
||||
s = s.slice(1);
|
||||
}
|
||||
|
||||
// right-anchored
|
||||
if ( s.slice(-1) === '|' ) {
|
||||
this.anchor = 1;
|
||||
s = s.slice(0, -1);
|
||||
}
|
||||
|
||||
// normalize placeholders
|
||||
// TODO: transforming `^` into `*` is not a strict interpretation of
|
||||
// ABP syntax.
|
||||
if ( this.reHasWildcard.test(s) ) {
|
||||
s = s.replace(/\^/g, '*').replace(/\*\*+/g, '*');
|
||||
s = trimChar(s, '*');
|
||||
}
|
||||
|
||||
// plain hostname?
|
||||
this.hostnamePure = this.hostnameAnchored && reHostnameRule.test(s);
|
||||
|
||||
// This might look weird but we gain memory footprint by not going through
|
||||
// toLowerCase(), at least on Chromium. Because copy-on-write?
|
||||
|
||||
this.f = this.reHasUppercase.test(s) ? s.toLowerCase() : s;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterParser.prototype.makeToken = function() {
|
||||
if ( this.isRegex ) {
|
||||
this.token = '*';
|
||||
return;
|
||||
}
|
||||
|
||||
var matches;
|
||||
|
||||
if ( this.hostnameAnchored ) {
|
||||
matches = findHostnameToken(this.f);
|
||||
if ( !matches || matches[0].length === 0 ) {
|
||||
return;
|
||||
}
|
||||
this.tokenBeg = matches.index;
|
||||
this.tokenEnd = reHostnameToken.lastIndex;
|
||||
this.token = this.f.slice(this.tokenBeg, this.tokenEnd);
|
||||
return;
|
||||
}
|
||||
|
||||
matches = findFirstGoodToken(this.f);
|
||||
if ( !matches || matches[0].length === 0 ) {
|
||||
return;
|
||||
}
|
||||
this.tokenBeg = matches.index;
|
||||
this.tokenEnd = reGoodToken.lastIndex;
|
||||
this.token = this.f.slice(this.tokenBeg, this.tokenEnd);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -1410,7 +1507,9 @@ FilterContainer.prototype.fromSelfie = function(selfie) {
|
|||
'*|': FilterSingleWildcardRightAnchored,
|
||||
'*|h': FilterSingleWildcardRightAnchoredHostname,
|
||||
'*+': FilterManyWildcards,
|
||||
'*+h': FilterManyWildcardsHostname
|
||||
'*+h': FilterManyWildcardsHostname,
|
||||
'//': FilterRegex,
|
||||
'//h': FilterRegexHostname
|
||||
};
|
||||
|
||||
var catKey, tokenKey;
|
||||
|
@ -1463,26 +1562,28 @@ FilterContainer.prototype.add = function(s) {
|
|||
// ORDER OF TESTS IS IMPORTANT!
|
||||
|
||||
// Ignore empty lines
|
||||
if ( reIgnoreEmpty.test(s) ) {
|
||||
s = s.trim();
|
||||
if ( s.length === 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore comments
|
||||
if ( reIgnoreComment.test(s) ) {
|
||||
var c = s.charAt(0);
|
||||
if ( c === '[' || c === '!' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var parsed = this.filterParser.parse(s);
|
||||
|
||||
// Ignore rules with other conditions for now
|
||||
if ( parsed.unsupported ) {
|
||||
this.rejectedCount += 1;
|
||||
// console.log('µBlock> abp-filter.js/FilterContainer.add(): unsupported filter "%s"', s);
|
||||
// Ignore element-hiding filters
|
||||
if ( parsed.elemHiding ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore element-hiding filters
|
||||
if ( parsed.elemHiding ) {
|
||||
// Ignore filters with unsupported options
|
||||
if ( parsed.unsupported ) {
|
||||
this.rejectedCount += 1;
|
||||
// console.log('µBlock> abp-filter.js/FilterContainer.add(): unsupported filter "%s"', s);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1533,95 +1634,95 @@ FilterContainer.prototype.add = function(s) {
|
|||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.addFilter = function(parsed) {
|
||||
// TODO: avoid duplicates
|
||||
|
||||
var matches = parsed.hostnameAnchored ?
|
||||
findHostnameToken(parsed.f) :
|
||||
findFirstGoodToken(parsed.f);
|
||||
if ( !matches || !matches[0].length ) {
|
||||
parsed.makeToken();
|
||||
if ( parsed.token === '' ) {
|
||||
console.error('static-net-filtering.js > FilterContainer.addFilter("%s"): can\'t tokenize', parsed.f);
|
||||
return false;
|
||||
}
|
||||
var tokenBeg = matches.index;
|
||||
var tokenEnd = parsed.hostnameAnchored ?
|
||||
reHostnameToken.lastIndex :
|
||||
reGoodToken.lastIndex;
|
||||
var filter;
|
||||
|
||||
var i = parsed.hostnames.length;
|
||||
|
||||
// Applies to specific domains
|
||||
|
||||
if ( i !== 0 && !parsed.notHostname ) {
|
||||
while ( i-- ) {
|
||||
filter = makeHostnameFilter(parsed, tokenBeg, parsed.hostnames[i]);
|
||||
if ( !filter ) {
|
||||
return false;
|
||||
}
|
||||
this.addFilterEntry(filter, parsed, AnyParty, tokenBeg, tokenEnd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var party = AnyParty;
|
||||
if ( parsed.firstParty !== parsed.thirdParty ) {
|
||||
party = parsed.firstParty ? FirstParty : ThirdParty;
|
||||
}
|
||||
|
||||
// Applies to all domains, with exception(s)
|
||||
var filter;
|
||||
var i = parsed.hostnames.length;
|
||||
var j = parsed.notHostnames.length;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/191
|
||||
// Invert the purpose of the filter for negated hostnames
|
||||
if ( i !== 0 && parsed.notHostname ) {
|
||||
filter = makeFilter(parsed, tokenBeg);
|
||||
// Applies to all domains without exceptions
|
||||
if ( i === 0 && j === 0 ) {
|
||||
filter = makeFilter(parsed);
|
||||
if ( !filter ) {
|
||||
return false;
|
||||
}
|
||||
this.addFilterEntry(filter, parsed, party);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Applies to specific domains
|
||||
if ( i !== 0 ) {
|
||||
while ( i-- ) {
|
||||
filter = makeHostnameFilter(parsed, parsed.hostnames[i]);
|
||||
if ( !filter ) {
|
||||
return false;
|
||||
}
|
||||
this.addFilterEntry(filter, parsed, party);
|
||||
}
|
||||
}
|
||||
// No exceptions
|
||||
if ( j === 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Case:
|
||||
// - applies everywhere except to specific domains
|
||||
// Example:
|
||||
// - ||adm.fwmrm.net/p/msnbc_live/$object-subrequest,third-party,domain=~msnbc.msn.com|~www.nbcnews.com
|
||||
if ( i === 0 ) {
|
||||
filter = makeFilter(parsed);
|
||||
if ( !filter ) {
|
||||
return false;
|
||||
}
|
||||
// https://github.com/gorhill/uBlock/issues/251
|
||||
// Apply third-party option if it is present
|
||||
this.addFilterEntry(filter, parsed, party, tokenBeg, tokenEnd);
|
||||
// Reverse purpose of filter
|
||||
parsed.action ^= ToggleAction;
|
||||
while ( i-- ) {
|
||||
filter = makeHostnameFilter(parsed, tokenBeg, parsed.hostnames[i]);
|
||||
if ( !filter ) {
|
||||
return false;
|
||||
}
|
||||
// https://github.com/gorhill/uBlock/issues/191#issuecomment-53654024
|
||||
// If it is a block filter, we need to reverse the order of
|
||||
// evaluation.
|
||||
if ( parsed.action === BlockAction ) {
|
||||
parsed.important = Important;
|
||||
}
|
||||
this.addFilterEntry(filter, parsed, AnyParty, tokenBeg, tokenEnd);
|
||||
this.addFilterEntry(filter, parsed, party);
|
||||
}
|
||||
|
||||
// Cases:
|
||||
// - applies everywhere except to specific domains
|
||||
// - applies to specific domains except other specific domains
|
||||
// Example:
|
||||
// - /^https?\:\/\/(?!(...)\/)/$script,third-party,xmlhttprequest,domain=photobucket.com|~secure.photobucket.com
|
||||
|
||||
// Reverse purpose of filter
|
||||
parsed.action ^= ToggleAction;
|
||||
while ( j-- ) {
|
||||
filter = makeHostnameFilter(parsed, parsed.notHostnames[j]);
|
||||
if ( !filter ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// https://github.com/gorhill/uBlock/issues/191#issuecomment-53654024
|
||||
// If it is a block filter, we need to reverse the order of
|
||||
// evaluation.
|
||||
if ( parsed.action === BlockAction ) {
|
||||
parsed.important = Important;
|
||||
}
|
||||
this.addFilterEntry(filter, parsed, party);
|
||||
}
|
||||
|
||||
// Applies to all domains without exceptions
|
||||
|
||||
filter = makeFilter(parsed, tokenBeg);
|
||||
if ( !filter ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.addFilterEntry(filter, parsed, party, tokenBeg, tokenEnd);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.addFilterEntry = function(filter, parsed, party, tokenBeg, tokenEnd) {
|
||||
var s = parsed.f;
|
||||
var tokenKey = s.slice(tokenBeg, tokenEnd);
|
||||
FilterContainer.prototype.addFilterEntry = function(filter, parsed, party) {
|
||||
var bits = parsed.action | parsed.important | party;
|
||||
if ( parsed.types.length === 0 ) {
|
||||
this.addToCategory(bits | AnyType, tokenKey, filter);
|
||||
this.addToCategory(bits | AnyType, parsed.token, filter);
|
||||
return;
|
||||
}
|
||||
var n = parsed.types.length;
|
||||
for ( var i = 0; i < n; i++ ) {
|
||||
this.addToCategory(bits | parsed.types[i], tokenKey, filter);
|
||||
this.addToCategory(bits | parsed.types[i], parsed.token, filter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1691,6 +1792,13 @@ FilterContainer.prototype.matchTokens = function(bucket, url) {
|
|||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
// Regex-based filters
|
||||
f = bucket['*'];
|
||||
if ( f !== undefined && f.match(url) !== false ) {
|
||||
return f;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -1756,7 +1864,7 @@ FilterContainer.prototype.matchStringExactType = function(context, requestURL, r
|
|||
|
||||
var type = typeNameToTypeValue[requestType];
|
||||
var categories = this.categories;
|
||||
var bucket;
|
||||
var bf = false, bucket;
|
||||
|
||||
// Tokenize only once
|
||||
this.tokenize(url);
|
||||
|
@ -1777,7 +1885,6 @@ FilterContainer.prototype.matchStringExactType = function(context, requestURL, r
|
|||
}
|
||||
|
||||
// Test against block filters
|
||||
bf = false;
|
||||
if ( bucket = categories[this.makeCategoryKey(BlockAnyParty | type)] ) {
|
||||
bf = this.matchTokens(bucket, url);
|
||||
}
|
||||
|
@ -1853,7 +1960,7 @@ FilterContainer.prototype.matchString = function(context) {
|
|||
pageHostname = context.pageHostname || '';
|
||||
|
||||
var categories = this.categories;
|
||||
var bucket;
|
||||
var bf, bucket;
|
||||
|
||||
// Tokenize only once
|
||||
this.tokenize(url);
|
||||
|
|
|
@ -374,12 +374,15 @@
|
|||
var cosmeticFilteringEngine = this.cosmeticFilteringEngine;
|
||||
var parseCosmeticFilters = this.userSettings.parseAllABPHideFilters;
|
||||
|
||||
var reIsCosmeticFilter = /#@?#/;
|
||||
var reLocalhost = /(?:^|\s)(?:localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g;
|
||||
var reAsciiSegment = /^[\x21-\x7e]+$/;
|
||||
var reIsCosmeticFilter = /#[@#]/;
|
||||
var reIsWhitespaceChar = /\s/;
|
||||
var reMaybeLocalIp = /^[\d:f]/;
|
||||
var reIsLocalhostRedirect = /\s+(?:broadcasthost|local|localhost|localhost\.localdomain)(?=\s|$)/;
|
||||
var reLocalIp = /^(?:0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)/;
|
||||
//var reAsciiSegment = /^[\x21-\x7e]+$/;
|
||||
var matches;
|
||||
var lineBeg = 0, lineEnd, currentLineBeg;
|
||||
var line, c;
|
||||
var line, lineRaw, c, pos;
|
||||
|
||||
while ( lineBeg < rawEnd ) {
|
||||
lineEnd = rawText.indexOf('\n', lineBeg);
|
||||
|
@ -393,10 +396,14 @@
|
|||
// rhill 2014-04-18: The trim is important here, as without it there
|
||||
// could be a lingering `\r` which would cause problems in the
|
||||
// following parsing code.
|
||||
line = rawText.slice(lineBeg, lineEnd).trim();
|
||||
line = lineRaw = rawText.slice(lineBeg, lineEnd).trim();
|
||||
currentLineBeg = lineBeg;
|
||||
lineBeg = lineEnd + 1;
|
||||
|
||||
if ( line.length === 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Strip comments
|
||||
c = line.charAt(0);
|
||||
if ( c === '!' || c === '[' ) {
|
||||
|
@ -404,6 +411,7 @@
|
|||
}
|
||||
|
||||
// Parse or skip cosmetic filters
|
||||
// All cosmetic filters are caught here
|
||||
if ( parseCosmeticFilters ) {
|
||||
if ( cosmeticFilteringEngine.add(line) ) {
|
||||
continue;
|
||||
|
@ -412,36 +420,59 @@
|
|||
continue;
|
||||
}
|
||||
|
||||
// Whatever else is next can be assumed to not be a cosmetic filter
|
||||
|
||||
// Most comments start in first column
|
||||
if ( c === '#' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Catch comments somewhere on the line
|
||||
// Remove:
|
||||
// ... #blah blah blah
|
||||
// ... # blah blah blah
|
||||
// Don't remove:
|
||||
// ...#blah blah blah
|
||||
// because some ABP filters uses the `#` character (URL fragment)
|
||||
pos = line.indexOf('#');
|
||||
if ( pos !== -1 && reIsWhitespaceChar.test(line.charAt(pos - 1)) ) {
|
||||
line = line.slice(0, pos).trim();
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/15
|
||||
// Ensure localhost et al. don't end up in the ubiquitous blacklist.
|
||||
// TODO: do this only if it's not an [Adblock] list
|
||||
line = line
|
||||
.replace(/\s+#.*$/, '')
|
||||
.toLowerCase()
|
||||
.replace(reLocalhost, '')
|
||||
.trim();
|
||||
// With hosts files, we need to remove local IP redirection
|
||||
if ( reMaybeLocalIp.test(c) ) {
|
||||
// Ignore hosts file redirect configuration
|
||||
// 127.0.0.1 localhost
|
||||
// 255.255.255.255 broadcasthost
|
||||
if ( reIsLocalhostRedirect.test(line) ) {
|
||||
continue;
|
||||
}
|
||||
line = line.replace(reLocalIp, '').trim();
|
||||
}
|
||||
|
||||
if ( line.length === 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The filter is whatever sequence of printable ascii character without
|
||||
// whitespaces
|
||||
matches = reAsciiSegment.exec(line);
|
||||
if ( matches === null ) {
|
||||
//console.debug('µBlock.mergeFilterList(): skipping "%s"', lineRaw);
|
||||
continue;
|
||||
}
|
||||
//matches = reAsciiSegment.exec(line);
|
||||
//if ( matches === null ) {
|
||||
// console.debug('storage.js > µBlock.mergeFilterList(): skipping "%s"', lineRaw);
|
||||
// continue;
|
||||
//}
|
||||
|
||||
// Bypass anomalies
|
||||
// For example, when a filter contains whitespace characters, or
|
||||
// whatever else outside the range of printable ascii characters.
|
||||
if ( matches[0] !== line ) {
|
||||
// console.error('"%s" !== "%s"', matches[0], line);
|
||||
continue;
|
||||
}
|
||||
//if ( matches[0] !== line ) {
|
||||
// console.error('"%s" !== "%s"', matches[0], line);
|
||||
// continue;
|
||||
//}
|
||||
|
||||
staticNetFilteringEngine.add(matches[0]);
|
||||
staticNetFilteringEngine.add(line);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -607,16 +638,17 @@
|
|||
if ( countdown !== 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/426
|
||||
// Important: remove barrier to remote fetching, this was useful only
|
||||
// for launch time.
|
||||
µb.assets.allowRemoteFetch = true;
|
||||
|
||||
vAPI.onLoadAllCompleted();
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/184
|
||||
// Check for updates not too far in the future.
|
||||
µb.updater.restart(µb.firstUpdateAfter);
|
||||
|
||||
vAPI.onLoadAllCompleted();
|
||||
};
|
||||
|
||||
// Filters are in memory.
|
||||
|
|
Loading…
Reference in a new issue