From a742f09dd4ba37d748c962bed171ddd84bf046ea Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 6 Feb 2017 15:34:31 -0500 Subject: [PATCH 01/18] fix #2360 --- src/js/traffic.js | 62 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/src/js/traffic.js b/src/js/traffic.js index 29918bfbe0073..76c5ae73d4fa6 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -443,17 +443,22 @@ var processCSP = function(pageStore, details) { blockInlineScript = µb.isBlockResult(inlineScriptResult); } - context.requestType = 'websocket'; µb.staticNetFilteringEngine.matchStringExactType(context, requestURL, 'websocket'); var websocketResult = µb.staticNetFilteringEngine.toResultString(loggerEnabled), blockWebsocket = µb.isBlockResult(websocketResult); + // https://github.com/gorhill/uBlock/issues/2360 + µb.staticNetFilteringEngine.matchStringExactType(context, 'blob:', 'script'); + var workerResult = µb.staticNetFilteringEngine.toResultString(loggerEnabled), + blockWorker = µb.isBlockResult(workerResult); + var headersChanged; - if ( blockInlineScript || blockWebsocket ) { + if ( blockInlineScript || blockWebsocket || blockWorker ) { headersChanged = foilWithCSP( details.responseHeaders, blockInlineScript, - blockWebsocket + blockWebsocket, + blockWorker ); } @@ -480,6 +485,17 @@ var processCSP = function(pageStore, details) { context.pageHostname ); } + if ( workerResult !== '' ) { + µb.logger.writeOne( + tabId, + 'net', + workerResult, + 'worker', + requestURL, + context.rootHostname, + context.pageHostname + ); + } } context.dispose(); @@ -524,26 +540,38 @@ var foilLargeMediaElement = function(pageStore, details) { /******************************************************************************/ -var foilWithCSP = function(headers, noInlineScript, noWebsocket) { - var i = headerIndexFromName('content-security-policy', headers), +var foilWithCSP = function(headers, noInlineScript, noWebsocket, noWorker) { + var me = foilWithCSP, + i = headerIndexFromName('content-security-policy', headers), before = i === -1 ? '' : headers[i].value.trim(), after = before; if ( noInlineScript ) { after = foilWithCSPDirective( after, - /script-src[^;]*;?\s*/, + me.reScriptSrc, "script-src 'unsafe-eval' *", - /'unsafe-inline'\s*|'nonce-[^']+'\s*/g + me.reScriptSrcRemove ); } if ( noWebsocket ) { after = foilWithCSPDirective( after, - /connect-src[^;]*;?\s*/, + me.reConnectSrc, 'connect-src http:', - /wss?:[^\s]*\s*/g + me.reConnectSrcRemove + ); + } + + // https://www.w3.org/TR/CSP2/#directive-child-src + // https://www.w3.org/TR/CSP3/#directive-worker-src + if ( noWorker ) { + after = foilWithCSPDirective( + after, + me.reWorkerSrc, + 'child-src http:', + me.reWorkerSrcRemove ); } @@ -556,9 +584,9 @@ var foilWithCSP = function(headers, noInlineScript, noWebsocket) { // https://w3c.github.io/webappsec-csp/#directive-frame-src after = foilWithCSPDirective( after, - /frame-src[^;]*;?\s*/, + me.reFrameSrc, 'frame-src http:', - /data:[^\s]*\s*|blob:[^\s]*\s*/g + me.reFrameSrcRemove ); } @@ -573,6 +601,18 @@ var foilWithCSP = function(headers, noInlineScript, noWebsocket) { return changed; }; +(function() { + var fn = foilWithCSP; + fn.reScriptSrc = /script-src[^;]*;?\s*/; + fn.reScriptSrcRemove = /'unsafe-inline'\s*|'nonce-[^']+'\s*/g; + fn.reConnectSrc = /connect-src[^;]*;?\s*/; + fn.reConnectSrcRemove = /wss?:[^\s]*\s*/g; + fn.reWorkerSrc = /child-src[^;]*;?\s*/; + fn.reWorkerSrcRemove = /blob:[^\s]*\s*/g; + fn.reFrameSrc = /frame-src[^;]*;?\s*/; + fn.reFrameSrcRemove = /data:[^\s]*\s*|blob:[^\s]*\s*/g; +})(); + /******************************************************************************/ // Past issues to keep in mind: From 1d705485e9c855b7c113f6cd7114dcd8e0abeeac Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 6 Feb 2017 15:36:34 -0500 Subject: [PATCH 02/18] update max version info --- platform/firefox/install.rdf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/firefox/install.rdf b/platform/firefox/install.rdf index 2307fcac62f09..8cb7a2edd6beb 100644 --- a/platform/firefox/install.rdf +++ b/platform/firefox/install.rdf @@ -39,7 +39,7 @@ {{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}} 2.21 - 2.40.* + * @@ -48,7 +48,7 @@ {{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}} 25.0 - 26.* + 27.* From 48b3ba161b405be6b59e0ac6d4a0f57b20ad59ab Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 6 Feb 2017 15:38:39 -0500 Subject: [PATCH 03/18] new version for dev build --- platform/chromium/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json index b17c8120e87d7..b6f4067097a5a 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "uBlock Origin", - "version": "1.11.0", + "version": "1.11.1.0", "default_locale": "en", "description": "__MSG_extShortDesc__", From 7176ecb3e73522396acc1db498ab2af44ff0f6c6 Mon Sep 17 00:00:00 2001 From: gorhill Date: Tue, 7 Feb 2017 08:05:39 -0500 Subject: [PATCH 04/18] code review of fix to #2360 --- src/js/traffic.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/js/traffic.js b/src/js/traffic.js index 76c5ae73d4fa6..303a6872fa1e2 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -430,28 +430,29 @@ var processCSP = function(pageStore, details) { loggerEnabled = µb.logger.isEnabled(); var context = pageStore.createContextFromPage(); - context.requestURL = requestURL; context.requestHostname = µb.URI.hostnameFromURI(requestURL); if ( details.type !== 'main_frame' ) { context.pageHostname = context.pageDomain = context.requestHostname; } - var inlineScriptResult, blockInlineScript; + var inlineScriptResult, blockInlineScript, + workerResult, blockWorker; if ( details.type !== 'script' ) { context.requestType = 'inline-script'; + context.requestURL = requestURL; inlineScriptResult = pageStore.filterRequestNoCache(context); blockInlineScript = µb.isBlockResult(inlineScriptResult); + // https://github.com/gorhill/uBlock/issues/2360 + context.requestType = 'script'; + context.requestURL = 'blob:'; + workerResult = pageStore.filterRequestNoCache(context); + blockWorker = µb.isBlockResult(workerResult); } µb.staticNetFilteringEngine.matchStringExactType(context, requestURL, 'websocket'); var websocketResult = µb.staticNetFilteringEngine.toResultString(loggerEnabled), blockWebsocket = µb.isBlockResult(websocketResult); - // https://github.com/gorhill/uBlock/issues/2360 - µb.staticNetFilteringEngine.matchStringExactType(context, 'blob:', 'script'); - var workerResult = µb.staticNetFilteringEngine.toResultString(loggerEnabled), - blockWorker = µb.isBlockResult(workerResult); - var headersChanged; if ( blockInlineScript || blockWebsocket || blockWorker ) { headersChanged = foilWithCSP( From cbca48307c50d4e243462c4c86af03453bbdf766 Mon Sep 17 00:00:00 2001 From: gorhill Date: Thu, 9 Feb 2017 13:33:32 -0500 Subject: [PATCH 05/18] fix https://github.com/gorhill/uBlock/pull/2314#issuecomment-278716960 --- src/js/messaging.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/js/messaging.js b/src/js/messaging.js index 20ec0e3ca11c4..776cf192838c9 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -987,6 +987,10 @@ var onMessage = function(request, sender, callback) { case 'purgeCache': µb.assets.purge(request.assetKey); µb.assets.remove('compiled/' + request.assetKey); + // https://github.com/gorhill/uBlock/pull/2314#issuecomment-278716960 + if ( request.assetKey === 'ublock-filters' ) { + µb.assets.purge('ublock-resources'); + } break; case 'readHiddenSettings': From 1e1508cdd2d639cc8e669053a5dcec39d887224b Mon Sep 17 00:00:00 2001 From: gorhill Date: Sat, 11 Feb 2017 11:44:18 -0500 Subject: [PATCH 06/18] code review of dynamic URL filtering engine --- src/js/url-net-filtering.js | 258 +++++++++++++----------------------- 1 file changed, 94 insertions(+), 164 deletions(-) diff --git a/src/js/url-net-filtering.js b/src/js/url-net-filtering.js index a027cec69e047..2891a268b6a26 100644 --- a/src/js/url-net-filtering.js +++ b/src/js/url-net-filtering.js @@ -1,7 +1,7 @@ /******************************************************************************* - uBlock - a browser extension to black/white list requests. - Copyright (C) 2015 Raymond Hill + uBlock Origin - a browser extension to black/white list requests. + Copyright (C) 2015-2017 Raymond Hill This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -/* global µBlock */ +'use strict'; /******************************************************************************/ @@ -28,16 +28,12 @@ µBlock.URLNetFiltering = (function() { -'use strict'; - /******************************************************************************* -buckets: map of [origin + urlkey + type] - bucket: array of rule entry, sorted from shorter to longer url - +buckets: map of [hostname + type] + bucket: array of rule entries, sorted from shorter to longer url rule entry: { url, action } - *******************************************************************************/ /******************************************************************************/ @@ -63,13 +59,13 @@ var RuleEntry = function(url, action) { /******************************************************************************/ -var indexOfURL = function(urls, url) { +var indexOfURL = function(entries, url) { // TODO: binary search -- maybe, depends on common use cases - var urlLen = url.length; - var entry; - // urls must be ordered by increasing length. - for ( var i = 0; i< urls.length; i++ ) { - entry = urls[i]; + var urlLen = url.length, + entry; + // URLs must be ordered by increasing length. + for ( var i = 0; i < entries.length; i++ ) { + entry = entries[i]; if ( entry.url.length > urlLen ) { break; } @@ -82,30 +78,31 @@ var indexOfURL = function(urls, url) { /******************************************************************************/ -var indexOfMatch = function(urls, url) { - // TODO: binary search -- maybe, depends on common use cases - var urlLen = url.length; - var i = urls.length; - var entry; +var indexOfMatch = function(entries, url) { + var urlLen = url.length, + i = entries.length; while ( i-- ) { - entry = urls[i]; - if ( entry.url.length > urlLen ) { - continue; - } - if ( url.startsWith(entry.url) ) { - return i; + if ( entries[i].url.length <= urlLen ) { + break; } } + if ( i !== -1 ) { + do { + if ( url.startsWith(entries[i].url) ) { + return i; + } + } while ( i-- ); + } return -1; }; /******************************************************************************/ -var indexFromLength = function(urls, len) { +var indexFromLength = function(entries, len) { // TODO: binary search -- maybe, depends on common use cases - // urls must be ordered by increasing length. - for ( var i = 0; i< urls.length; i++ ) { - if ( urls[i].url.length > len ) { + // URLs must be ordered by increasing length. + for ( var i = 0; i < entries.length; i++ ) { + if ( entries[i].url.length > len ) { return i; } } @@ -114,43 +111,26 @@ var indexFromLength = function(urls, len) { /******************************************************************************/ -var addRuleEntry = function(urls, url, action) { - var entry = new RuleEntry(url, action); - var i = indexFromLength(urls, url.length); +var addRuleEntry = function(entries, url, action) { + var entry = new RuleEntry(url, action), + i = indexFromLength(entries, url.length); if ( i === -1 ) { - urls.push(entry); + entries.push(entry); } else { - urls.splice(i, 0, entry); + entries.splice(i, 0, entry); } }; /******************************************************************************/ -var urlKeyFromURL = function(url) { - // Experimental: running benchmarks first - //if ( url === '*' ) { - // return url; - //} - var match = reURLKey.exec(url); - return match !== null ? match[0] : ''; -}; - -var reURLKey = /^[a-z]+:\/\/[^\/?#]+/; - -/******************************************************************************/ - var URLNetFiltering = function() { this.reset(); }; /******************************************************************************/ -// rules: -// origin + urlkey + type => urls -// urls = collection of urls to match - URLNetFiltering.prototype.reset = function() { - this.rules = Object.create(null); + this.rules = new Map(); // registers, filled with result of last evaluation this.context = ''; this.url = ''; @@ -161,20 +141,24 @@ URLNetFiltering.prototype.reset = function() { /******************************************************************************/ URLNetFiltering.prototype.assign = function(other) { - var thisRules = this.rules; - var otherRules = other.rules; - var k; - + var thisRules = this.rules, + otherRules = other.rules, + iter, item; // Remove rules not in other - for ( k in thisRules ) { - if ( otherRules[k] === undefined ) { - delete thisRules[k]; + iter = thisRules.entries(); + for (;;) { + item = iter.next(); + if ( item.done ) { break; } + if ( otherRules.has(item.value) === false ) { + thisRules.delete(item.value); } } - // Add/change rules in other - for ( k in otherRules ) { - thisRules[k] = otherRules[k].slice(); + iter = otherRules.entries(); + for (;;) { + item = iter.next(); + if ( item.done ) { break; } + thisRules.set(item.value[0], item.value[1].slice()); } }; @@ -184,117 +168,77 @@ URLNetFiltering.prototype.setRule = function(srcHostname, url, type, action) { if ( action === 0 ) { return this.removeRule(srcHostname, url, type); } - - var urlKey = urlKeyFromURL(url); - if ( urlKey === '' ) { - return false; + var bucketKey = srcHostname + ' ' + type, + entries = this.rules.get(bucketKey); + if ( entries === undefined ) { + entries = []; + this.rules.set(bucketKey, entries); } - - var bucketKey = srcHostname + ' ' + urlKey + ' ' + type; - var urls = this.rules[bucketKey]; - if ( urls === undefined ) { - urls = this.rules[bucketKey] = []; - } - - var entry; - var i = indexOfURL(urls, url); + var i = indexOfURL(entries, url), + entry; if ( i !== -1 ) { - entry = urls[i]; - if ( entry.action === action ) { - return false; - } + entry = entries[i]; + if ( entry.action === action ) { return false; } entry.action = action; - return true; + } else { + addRuleEntry(entries, url, action); } - - addRuleEntry(urls, url, action); return true; }; /******************************************************************************/ URLNetFiltering.prototype.removeRule = function(srcHostname, url, type) { - var urlKey = urlKeyFromURL(url); - if ( urlKey === '' ) { - return false; - } - - var bucketKey = srcHostname + ' ' + urlKey + ' ' + type; - var urls = this.rules[bucketKey]; - if ( urls === undefined ) { + var bucketKey = srcHostname + ' ' + type, + entries = this.rules.get(bucketKey); + if ( entries === undefined ) { return false; } - - var i = indexOfURL(urls, url); + var i = indexOfURL(entries, url); if ( i === -1 ) { return false; } - - urls.splice(i, 1); - if ( urls.length === 0 ) { - delete this.rules[bucketKey]; + entries.splice(i, 1); + if ( entries.length === 0 ) { + this.rules.delete(bucketKey); } - return true; }; /******************************************************************************/ URLNetFiltering.prototype.evaluateZ = function(context, target, type) { - var urlKey = urlKeyFromURL(target); - if ( urlKey === '' ) { - this.r = 0; + this.r = 0; + if ( this.rules.size === 0 ) { return this; } - - var urls, pos, i, entry, keyShard; - + var entries, pos, i, entry; for (;;) { this.context = context; - keyShard = context + ' ' + urlKey; - if ( (urls = this.rules[keyShard + ' ' + type]) ) { - i = indexOfMatch(urls, target); + if ( (entries = this.rules.get(context + ' ' + type)) ) { + i = indexOfMatch(entries, target); if ( i !== -1 ) { - entry = urls[i]; + entry = entries[i]; this.url = entry.url; this.type = type; this.r = entry.action; return this; } } - if ( (urls = this.rules[keyShard + ' *']) ) { - i = indexOfMatch(urls, target); + if ( (entries = this.rules.get(context + ' *')) ) { + i = indexOfMatch(entries, target); if ( i !== -1 ) { - entry = urls[i]; + entry = entries[i]; this.url = entry.url; this.type = '*'; this.r = entry.action; return this; } } - /* Experimental: running benchmarks first - if ( urls = this.rules[context + ' * ' + type] ) { - entry = urls[0]; - this.url = '*'; - this.type = type; - this.r = entry.action; - return this; - } - if ( urls = this.rules[context + ' * *'] ) { - entry = urls[0]; - this.url = this.type = '*'; - this.r = entry.action; - return this; - } - */ - if ( context === '*' ) { - break; - } + if ( context === '*' ) { break; } pos = context.indexOf('.'); context = pos !== -1 ? context.slice(pos + 1) : '*'; } - - this.r = 0; return this; }; @@ -350,16 +294,20 @@ URLNetFiltering.prototype.copyRules = function(other, context, urls, type) { // "url-filtering:" hostname url type action URLNetFiltering.prototype.toString = function() { - var out = []; - var pos, hn, type, urls, i, entry; - for ( var bucketKey in this.rules ) { - pos = bucketKey.indexOf(' '); - hn = bucketKey.slice(0, pos); - pos = bucketKey.lastIndexOf(' '); - type = bucketKey.slice(pos + 1); - urls = this.rules[bucketKey]; - for ( i = 0; i < urls.length; i++ ) { - entry = urls[i]; + var out = [], + iter = this.rules.entries(), + item, key, pos, hn, type, entries, i, entry; + for (;;) { + item = iter.next(); + if ( item.done ) { break; } + key = item.value[0]; + pos = key.indexOf(' '); + hn = key.slice(0, pos); + pos = key.lastIndexOf(' '); + type = key.slice(pos + 1); + entries = item.value[1]; + for ( i = 0; i < entries.length; i++ ) { + entry = entries[i]; out.push( hn + ' ' + entry.url + ' ' + @@ -374,46 +322,28 @@ URLNetFiltering.prototype.toString = function() { /******************************************************************************/ URLNetFiltering.prototype.fromString = function(text) { - var textEnd = text.length; - var lineBeg = 0, lineEnd; - var line, fields; - this.reset(); - while ( lineBeg < textEnd ) { - lineEnd = text.indexOf('\n', lineBeg); - if ( lineEnd < 0 ) { - lineEnd = text.indexOf('\r', lineBeg); - if ( lineEnd < 0 ) { - lineEnd = textEnd; - } - } - line = text.slice(lineBeg, lineEnd).trim(); - lineBeg = lineEnd + 1; - - if ( line === '' ) { - continue; - } - + var lineIter = new µBlock.LineIterator(text), + line, fields; + while ( lineIter.eot() === false ) { + line = lineIter.next().trim(); + if ( line === '' ) { continue; } // Coarse test if ( line.indexOf('://') === -1 ) { continue; } - fields = line.split(/\s+/); if ( fields.length !== 4 ) { continue; } - // Finer test if ( fields[1].indexOf('://') === -1 ) { continue; } - if ( nameToActionMap.hasOwnProperty(fields[3]) === false ) { continue; } - this.setRule(fields[0], fields[1], fields[2], nameToActionMap[fields[3]]); } }; From 28084e1dc9bbe4d615347c474aea64f8e2f1a193 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 12 Feb 2017 15:53:40 -0500 Subject: [PATCH 07/18] code review: marginal performance improvement --- src/js/contentscript.js | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/js/contentscript.js b/src/js/contentscript.js index bf3729b708ce5..c4d29e5748fe5 100644 --- a/src/js/contentscript.js +++ b/src/js/contentscript.js @@ -1,7 +1,7 @@ /******************************************************************************* uBlock Origin - a browser extension to block requests. - Copyright (C) 2014-2016 Raymond Hill + Copyright (C) 2014-2017 Raymond Hill This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1533,36 +1533,48 @@ vAPI.domSurveyor = (function() { var surveyPhase1 = function(addedNodes) { var t0 = window.performance.now(), - nodes = selectNodes('[class],[id]', addedNodes), + rews = reWhitespace, qq = queriedSelectors, ll = lowGenericSelectors, - node, v, vv, j, - i = nodes.length; + lli = ll.length, + nodes, i, node, v, vv, j; + nodes = selectNodes('[id]', addedNodes); + i = nodes.length; while ( i-- ) { node = nodes[i]; - if ( node.nodeType !== 1 ) { continue; } v = node.id; - if ( v !== '' && typeof v === 'string' ) { - v = '#' + v.trim(); - if ( v !== '#' && !qq.has(v) ) { ll.push(v); qq.add(v); } + if ( typeof v !== 'string' ) { continue; } + v = '#' + v.trim(); + if ( !qq.has(v) && v.length !== 1 ) { + ll[lli] = v; lli++; qq.add(v); } + } + nodes = selectNodes('[class]', addedNodes); + i = nodes.length; + while ( i-- ) { + node = nodes[i]; vv = node.className; - if ( vv === '' || typeof vv !== 'string' ) { continue; } - if ( /\s/.test(vv) === false ) { + if ( typeof vv !== 'string' ) { continue; } + if ( !rews.test(vv) ) { v = '.' + vv; - if ( !qq.has(v) ) { ll.push(v); qq.add(v); } + if ( !qq.has(v) && v.length !== 1 ) { + ll[lli] = v; lli++; qq.add(v); + } } else { vv = node.classList; j = vv.length; while ( j-- ) { v = '.' + vv[j]; - if ( !qq.has(v) ) { ll.push(v); qq.add(v); } + if ( !qq.has(v) ) { + ll[lli] = v; lli++; qq.add(v); + } } } } surveyCost += window.performance.now() - t0; surveyPhase2(addedNodes); }; + var reWhitespace = /\s/; var domChangedHandler = function(addedNodes) { if ( cosmeticSurveyingMissCount > 255 ) { From 1c4347d69d540916b609835dd63c56a11ab7b2e5 Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 13 Feb 2017 08:33:10 -0500 Subject: [PATCH 08/18] element picker improvement: to not discard class information when an id is available Use class(es) whenever available instead of the id when selecting a broad cosmetic filter (ctrl-click). When asking for a broad cosmetic filter, using the id instead of whatever available class(es) is limiting usefulness. The change here address this. Example of use case: open . Now how to remove all signature widgets from all posts? Without the change here, this was not possible without opening the browser's inspector, finding out and manually typing whatever class is used to identify the signature's root element. With this commit, ctrl-click will now use whatever class information exist instead of the id. --- src/js/scriptlets/element-picker.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/js/scriptlets/element-picker.js b/src/js/scriptlets/element-picker.js index 80d0b4aa49fda..1ab7e12d7f7b2 100644 --- a/src/js/scriptlets/element-picker.js +++ b/src/js/scriptlets/element-picker.js @@ -489,13 +489,11 @@ var cosmeticFilterFromElement = function(elem) { } // Class(es) - if ( selector === '' ) { - v = elem.classList; - if ( v ) { - i = v.length || 0; - while ( i-- ) { - selector += '.' + CSS.escape(v.item(i)); - } + v = elem.classList; + if ( v ) { + i = v.length || 0; + while ( i-- ) { + selector += '.' + CSS.escape(v.item(i)); } } @@ -1036,13 +1034,22 @@ var candidateFromFilterChoice = function(filterChoice) { // - Do not compute exact path. // - Discard narrowing directives. if ( filterChoice.modifier ) { - return filter.replace(/:nth-of-type\(\d+\)/, ''); + filter = filter.replace(/:nth-of-type\(\d+\)/, ''); + // Remove the id if one or more classes exist. + if ( filter.charAt(2) === '#' && filter.indexOf('.') !== -1 ) { + filter = filter.replace(/#[^#.]+/, ''); + } + return filter; } // Return path: the target element, then all siblings prepended var selector = '', joiner = ''; for ( ; slot < filters.length; slot++ ) { filter = filters[slot]; + // Remove all classes when an id exists. + if ( filter.charAt(2) === '#' ) { + filter = filter.replace(/\..+$/, ''); + } selector = filter.slice(2) + joiner + selector; // Stop at any element with an id: these are unique in a web page if ( filter.lastIndexOf('###', 0) === 0 ) { From ea8cca144560546ee649a377b3fd5af5338fff09 Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 13 Feb 2017 08:56:42 -0500 Subject: [PATCH 09/18] new revision for dev build --- platform/chromium/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json index b6f4067097a5a..af3c1f9761745 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "uBlock Origin", - "version": "1.11.1.0", + "version": "1.11.1.1", "default_locale": "en", "description": "__MSG_extShortDesc__", From 2d3cc2be264eec9c9f5d638f1bbc559784a05268 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Thu, 16 Feb 2017 12:47:12 -0500 Subject: [PATCH 10/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72b4f7f996708..189232fcb4dca 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ You can install the latest version [manually](https://github.com/gorhill/uBlock/ It is expected that uBlock Origin is compatible with any Chromium-based browsers. -**Important:** Chromium-based browsers do not relay [websocket connections](https://en.wikipedia.org/wiki/WebSocket) to the extension API. This means websites can use websocket connections to bypass uBO (or any other blocker). This can be remediated by installing uBO's companion extension [uBO-WebSocket](https://github.com/gorhill/uBO-WebSocket). +**Important:** Chromium-based browsers do not relay [websocket connections](https://en.wikipedia.org/wiki/WebSocket) to the extension API. This means websites can use websocket connections to bypass uBO (or any other blocker). This can be remediated by installing uBO's companion extension [uBO-Extra](https://github.com/gorhill/uBO-Extra). #### Firefox / Firefox for Android From 39f9d11ec52fa0da5ae96b9f670c08b651d26925 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sat, 18 Feb 2017 09:01:36 -0500 Subject: [PATCH 11/18] prepare uBO for fix to https://github.com/gorhill/uBO-Extra/issues/29 --- platform/chromium/vapi-background.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 63290d47b6ab0..2a4fdd66dfc61 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -976,16 +976,23 @@ vAPI.net.registerListeners = function() { // logger, etc. // Counterpart of following block of code is found in "vapi-client.js" -- // search for "https://github.com/gorhill/uBlock/issues/1497". + // + // Once uBO 1.11.1 and uBO-Extra 2.12 are widespread, the image-based + // handling code can be removed. var onBeforeWebsocketRequest = function(details) { + if ( (details.type !== 'image') && + (details.method !== 'HEAD' || details.type !== 'xmlhttprequest') + ) { + return; + } + var requestURL = details.url, + matches = /[?&]u(?:rl)?=([^&]+)/.exec(requestURL); + if ( matches === null ) { return; } details.type = 'websocket'; - var requestURL = details.url; - var matches = /[?&]url=([^&]+)/.exec(requestURL); details.url = decodeURIComponent(matches[1]); var r = onBeforeRequestClient(details); - // Blocked? if ( r && r.cancel ) { return r; } - // Try to redirect to the URL of an image already present in the - // document, or a 1x1 data: URL if none is present. + // Redirect to the provided URL, or a 1x1 data: URI if none provided. matches = /[?&]r=([^&]+)/.exec(requestURL); return { redirectUrl: matches !== null ? @@ -997,11 +1004,9 @@ vAPI.net.registerListeners = function() { var onBeforeRequestClient = this.onBeforeRequest.callback; var onBeforeRequest = function(details) { // https://github.com/gorhill/uBlock/issues/1497 - if ( - details.type === 'image' && - details.url.endsWith('ubofix=f41665f3028c7fd10eecf573336216d3') - ) { - return onBeforeWebsocketRequest(details); + if ( details.url.endsWith('ubofix=f41665f3028c7fd10eecf573336216d3') ) { + var r = onBeforeWebsocketRequest(details); + if ( r !== undefined ) { return r; } } normalizeRequestDetails(details); From 414f3a98b79098796123813f7c85aac164f08211 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sat, 18 Feb 2017 09:03:02 -0500 Subject: [PATCH 12/18] new revision for release candidate --- platform/chromium/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json index af3c1f9761745..8e29fb8c56c35 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "uBlock Origin", - "version": "1.11.1.1", + "version": "1.11.1.100", "default_locale": "en", "description": "__MSG_extShortDesc__", From e2fd7e48c81886f2dba42020891e070a0daae846 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 19 Feb 2017 10:06:35 -0500 Subject: [PATCH 13/18] fix #2388 --- dist/description/description-da.txt | 6 +++--- src/_locales/ar/messages.json | 2 +- src/_locales/da/messages.json | 6 +++--- src/_locales/eo/messages.json | 4 ++-- src/_locales/he/messages.json | 2 +- src/_locales/pt_BR/messages.json | 2 +- src/_locales/sv/messages.json | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dist/description/description-da.txt b/dist/description/description-da.txt index 320a7bb9a460f..0eb6f46f4ba62 100644 --- a/dist/description/description-da.txt +++ b/dist/description/description-da.txt @@ -1,8 +1,8 @@ En effektiv blocker: let på hukommelse og CPU forbrug,. Kan indlæse og anvende tusindvis af flere filtre end andre populære blockere derude. -Illustreret oversigt over effektiviteten: https://github.com/gorhill/uBlock/wiki/uBlock-vs.-ABP :-Efficiency-compared +Illustreret oversigt over effektiviteten: https://github.com/gorhill/uBlock/wiki/uBlock-vs.-ABP:-Efficiency-compared -Anvendelse: Den Store power knap i pop-up-vinduet kan permanent deaktivere/aktivere uBlock på det aktuelle websted. Dette gælder kun for det aktuelle websted, det er ikke en global afbryderknap. +Anvendelse: Den store tænd-sluk-knap i pop op-vinduet bruges til permanent at deaktivere/aktivere uBlock på det aktuelle websted. Dette gælder kun for det aktuelle websted, det er ikke en global afbryderknap. *** @@ -24,7 +24,7 @@ Flere lister er tilgængelige hvis du ønsker det: - Spam404 - Osv. -Selvfølgelig vil flere aktive filtre betyde højere hukommelsesforbrug. Selv efter tilføjelse af Fanboys to ekstra lister, og hpHosts’s Ad and tracking servers, har uBlock₀ stadig et lavere hukommelsesforbrug end andre blokere derude. +Selvfølgelig vil flere aktive filtre betyde højere hukommelsesforbrug. Men selv efter tilføjelse af Fanboys to ekstra lister, samt hpHosts’s Ad and tracking servers, har uBlock stadig et lavere hukommelsesforbrug end andre meget populære blockere derude. Vær desuden opmærksom på, at hvis du vælger nogle af disse ekstra lister kan det føre til højere sandsynlighed for, at webstedet bliver vist forkert - især de lister der normalt anvendes som hosts-fil. diff --git a/src/_locales/ar/messages.json b/src/_locales/ar/messages.json index 82cdca5574306..4171b441bc8ec 100644 --- a/src/_locales/ar/messages.json +++ b/src/_locales/ar/messages.json @@ -208,7 +208,7 @@ "description":"" }, "settingsAdvancedUserPrompt":{ - "message":"أنا مستخدم متقدم (قراءة إجبارية<\/a>)", + "message":"أنا مستخدم ذو خبرة (قراءة إجبارية<\/a>)", "description":"" }, "settingsAdvancedUserSettings":{ diff --git a/src/_locales/da/messages.json b/src/_locales/da/messages.json index 68b994610c549..17dc2f4e25ae0 100644 --- a/src/_locales/da/messages.json +++ b/src/_locales/da/messages.json @@ -224,7 +224,7 @@ "description":"English: " }, "settingsWebRTCIPAddressHiddenPrompt":{ - "message":"Forhindre WebRTC i at lække lokale IP-adresser", + "message":"Forhindr WebRTC i at lække lokale IP-adresser", "description":"English: " }, "settingPerSiteSwitchGroup":{ @@ -232,7 +232,7 @@ "description":"" }, "settingPerSiteSwitchGroupSynopsis":{ - "message":"Disse standardindstillinger kan overskrives på en per-side basis", + "message":"Disse standardindstillinger kan tilsidesættes for hver enkelt websted", "description":"" }, "settingsNoCosmeticFilteringPrompt":{ @@ -240,7 +240,7 @@ "description":"" }, "settingsNoLargeMediaPrompt":{ - "message":"Bloker medieelementer større end {{input: nummer}} kB", + "message":"Bloker medieelementer større end {{input: number}} kB", "description":"" }, "settingsNoRemoteFontsPrompt":{ diff --git a/src/_locales/eo/messages.json b/src/_locales/eo/messages.json index 90b5bfe67d937..ad8ac35cad8f6 100644 --- a/src/_locales/eo/messages.json +++ b/src/_locales/eo/messages.json @@ -40,7 +40,7 @@ "description":"appears as tab name in dashboard" }, "advancedSettingsPageName":{ - "message":"Advanced settings", + "message":"Altgradaj agordoj", "description":"Title for the advanced settings page" }, "popupPowerSwitchInfo":{ @@ -212,7 +212,7 @@ "description":"" }, "settingsAdvancedUserSettings":{ - "message":"advanced settings", + "message":"altgradaj agordoj", "description":"For the tooltip of a link which gives access to advanced settings" }, "settingsPrefetchingDisabledPrompt":{ diff --git a/src/_locales/he/messages.json b/src/_locales/he/messages.json index 1d8022796e6b3..c4b6e28935064 100644 --- a/src/_locales/he/messages.json +++ b/src/_locales/he/messages.json @@ -424,7 +424,7 @@ "description":"English: dynamic rule syntax and full documentation." }, "whitelistPrompt":{ - "message":"רשימת שמות המתחם שלך בהם uBlock₀ לא יהיה פעיל. רשומה אחת בכל שורה. שמות מתחם לא חוקיים לא יפורשו ולא תהיה התראה לכך.", + "message":"הרשומות ברשימה הלבנה מציינות באילו דפי אינטרנט uBlock Origin לא יהיה פעיל. רשומה אחת בכל שורה. רשומות לא חוקיות תתעלמנה בשקט ויסומנו כהערות.", "description":"English: An overview of the content of the dashboard's Whitelist pane." }, "whitelistImport":{ diff --git a/src/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json index 42fcae42696b7..28d6050f26ed8 100644 --- a/src/_locales/pt_BR/messages.json +++ b/src/_locales/pt_BR/messages.json @@ -200,7 +200,7 @@ "description":"English: Make use of context menu where appropriate" }, "settingsColorBlindPrompt":{ - "message":"Modo Daltonismo", + "message":"Modo daltonismo", "description":"English: Color-blind friendly" }, "settingsCloudStorageEnabledPrompt":{ diff --git a/src/_locales/sv/messages.json b/src/_locales/sv/messages.json index f7f8996fefbf3..51b40c8c852ba 100644 --- a/src/_locales/sv/messages.json +++ b/src/_locales/sv/messages.json @@ -76,7 +76,7 @@ "description":"English: Enter element picker mode" }, "popupTipLog":{ - "message":"Öppna loggaren", + "message":"Öppna loggen", "description":"Tooltip used for the logger icon in the panel" }, "popupTipNoPopups":{ From 2a2cbdec1f07272f6cc1fa37eb9b45c1fb47e0cd Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 19 Feb 2017 10:20:48 -0500 Subject: [PATCH 14/18] #2388: forgot to also remove extraneous space --- src/_locales/da/messages.json | 2 +- src/_locales/pt_PT/messages.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_locales/da/messages.json b/src/_locales/da/messages.json index 17dc2f4e25ae0..0c48870bff159 100644 --- a/src/_locales/da/messages.json +++ b/src/_locales/da/messages.json @@ -240,7 +240,7 @@ "description":"" }, "settingsNoLargeMediaPrompt":{ - "message":"Bloker medieelementer større end {{input: number}} kB", + "message":"Bloker medieelementer større end {{input:number}} kB", "description":"" }, "settingsNoRemoteFontsPrompt":{ diff --git a/src/_locales/pt_PT/messages.json b/src/_locales/pt_PT/messages.json index e2d63b466d109..6e110e1c4d89e 100644 --- a/src/_locales/pt_PT/messages.json +++ b/src/_locales/pt_PT/messages.json @@ -560,7 +560,7 @@ "description":"English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton":{ - "message":"Restaurar por um ficheiro...", + "message":"Restaurar a partir de um ficheiro...", "description":"English: Restore from file..." }, "aboutResetDataButton":{ @@ -568,7 +568,7 @@ "description":"English: Reset to default settings..." }, "aboutRestoreDataConfirm":{ - "message":"Todas as suas definições serão substituídas utilizando os dados da cópia de segurança de {{time}}, e uBlock₀ irá reiniciar.\n\nSubstituir todas as definições existentes utilizando os dados da cópia de segurança?", + "message":"Todas as suas definições serão substituídas utilizando os dados da cópia de segurança de {{time}}, e o uBlock₀ irá reiniciar.\n\nSubstituir todas as definições existentes utilizando os dados da cópia de segurança?", "description":"Message asking user to confirm restore" }, "aboutRestoreDataError":{ From 798e21de3640b9684d504e4c44384196e0e1e014 Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 27 Feb 2017 16:29:36 -0500 Subject: [PATCH 15/18] fix #2414 --- src/epicker.html | 6 +++--- src/js/scriptlets/element-picker.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/epicker.html b/src/epicker.html index fc1f34e520a3a..42df6414195b6 100644 --- a/src/epicker.html +++ b/src/epicker.html @@ -78,7 +78,7 @@ resize: none; width: 100%; } -section > div:first-child > textarea + div { +#resultsetCount { background-color: #aaa; bottom: 0; color: white; @@ -86,7 +86,7 @@ position: absolute; right: 0; } -section.invalidFilter > div:first-child > textarea + div { +section.invalidFilter #resultsetCount { background-color: red; } section > div:first-child + div { @@ -183,7 +183,7 @@
-
+