From 7176ecb3e73522396acc1db498ab2af44ff0f6c6 Mon Sep 17 00:00:00 2001 From: gorhill Date: Tue, 7 Feb 2017 08:05:39 -0500 Subject: [PATCH 01/23] 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 02/23] 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 03/23] 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 04/23] 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 05/23] 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 06/23] 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 07/23] 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 08/23] 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 09/23] 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 10/23] 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 11/23] #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 12/23] 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 @@
-
+
+ + + {{ec8030f7-c20a-464f-9b0e-13a3a9e97384}} + 52.0a1 + * + + + + diff --git a/src/js/background.js b/src/js/background.js index 5cc6d8915a601..ca7fe704b39f5 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -19,54 +19,19 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ -var µBlock = (function() { // jshint ignore:line - -/******************************************************************************/ +/* global objectAssign */ -var oneSecond = 1000; -var oneMinute = 60 * oneSecond; +'use strict'; /******************************************************************************/ -var defaultExternalLists = [ - '! Examples:', - '! https://easylist-downloads.adblockplus.org/fb_annoyances_full.txt', - '! https://easylist-downloads.adblockplus.org/yt_annoyances_full.txt', - '' -].join('\n'); +var µBlock = (function() { // jshint ignore:line -/******************************************************************************/ + var oneSecond = 1000, + oneMinute = 60 * oneSecond; -return { - firstInstall: false, - - userSettings: { - advancedUserEnabled: false, - alwaysDetachLogger: false, - autoUpdate: true, - cloudStorageEnabled: false, - collapseBlocked: true, - colorBlindFriendly: false, - contextMenuEnabled: true, - dynamicFilteringEnabled: false, - externalLists: defaultExternalLists, - firewallPaneMinimized: true, - hyperlinkAuditingDisabled: true, - ignoreGenericCosmeticFilters: false, - largeMediaSize: 50, - parseAllABPHideFilters: true, - prefetchingDisabled: true, - requestLogMaxEntries: 1000, - showIconBadge: true, - tooltipsDisabled: false, - webrtcIPAddressHidden: false - }, - - hiddenSettingsDefault: { + var hiddenSettingsDefault = { assetFetchTimeout: 30, autoUpdateAssetFetchPeriod: 120, autoUpdatePeriod: 7, @@ -75,86 +40,131 @@ return { manualUpdateAssetFetchPeriod: 2000, popupFontSize: 'unset', suspendTabsUntilReady: false - }, - // This will be filled ASAP: - hiddenSettings: {}, - - // Features detection. - privacySettingsSupported: vAPI.browserSettings instanceof Object, - cloudStorageSupported: vAPI.cloud instanceof Object, - - // https://github.com/chrisaljoudi/uBlock/issues/180 - // Whitelist directives need to be loaded once the PSL is available - netWhitelist: {}, - netWhitelistModifyTime: 0, - netWhitelistDefault: [ - 'about-scheme', - 'behind-the-scene', - 'chrome-extension-scheme', - 'chrome-scheme', - 'loopconversation.about-scheme', - 'moz-extension-scheme', - 'opera-scheme', - 'vivaldi-scheme', - '' - ].join('\n'), - - localSettings: { - blockedRequestCount: 0, - allowedRequestCount: 0 - }, - localSettingsLastModified: 0, - localSettingsLastSaved: 0, - - // read-only - systemSettings: { - compiledMagic: 'fxtcjjhbhyiw', - selfieMagic: 'fxtcjjhbhyiw' - }, - - restoreBackupSettings: { - lastRestoreFile: '', - lastRestoreTime: 0, - lastBackupFile: '', - lastBackupTime: 0 - }, - - // Allows to fully customize uBO's assets, typically set through admin - // settings. The content of 'assets.json' will also tell which filter - // lists to enable by default when uBO is first installed. - assetsBootstrapLocation: 'assets/assets.json', - - userFiltersPath: 'user-filters', - pslAssetKey: 'public_suffix_list.dat', - - selectedFilterLists: [], - availableFilterLists: {}, - - selfieAfter: 23 * oneMinute, - - pageStores: {}, - pageStoresToken: 0, - - storageQuota: vAPI.storage.QUOTA_BYTES, - storageUsed: 0, - - noopFunc: function(){}, - - apiErrorCount: 0, - mouseX: -1, - mouseY: -1, - mouseURL: '', - epickerTarget: '', - epickerEprom: null, - - scriptlets: { - }, - - // so that I don't have to care for last comma - dummy: 0 -}; - -/******************************************************************************/ + }; + + return { + firstInstall: false, + + onBeforeStartQueue: [], + onStartCompletedQueue: [], + + userSettings: { + advancedUserEnabled: false, + alwaysDetachLogger: false, + autoUpdate: true, + cloudStorageEnabled: false, + collapseBlocked: true, + colorBlindFriendly: false, + contextMenuEnabled: true, + dynamicFilteringEnabled: false, + externalLists: [], + firewallPaneMinimized: true, + hyperlinkAuditingDisabled: true, + ignoreGenericCosmeticFilters: false, + largeMediaSize: 50, + parseAllABPHideFilters: true, + prefetchingDisabled: true, + requestLogMaxEntries: 1000, + showIconBadge: true, + tooltipsDisabled: false, + webrtcIPAddressHidden: false + }, + + hiddenSettingsDefault: hiddenSettingsDefault, + hiddenSettings: (function() { + var out = objectAssign({}, hiddenSettingsDefault), + json = vAPI.localStorage.getItem('hiddenSettings'); + if ( typeof json === 'string' ) { + try { + var o = JSON.parse(json); + if ( o instanceof Object ) { + for ( var k in o ) { + if ( out.hasOwnProperty(k) ) { + out[k] = o[k]; + } + } + } + } + catch(ex) { + } + } + return out; + })(), + + // Features detection. + privacySettingsSupported: vAPI.browserSettings instanceof Object, + cloudStorageSupported: vAPI.cloud instanceof Object, + + // https://github.com/chrisaljoudi/uBlock/issues/180 + // Whitelist directives need to be loaded once the PSL is available + netWhitelist: {}, + netWhitelistModifyTime: 0, + netWhitelistDefault: [ + 'about-scheme', + 'behind-the-scene', + 'chrome-extension-scheme', + 'chrome-scheme', + 'loopconversation.about-scheme', + 'moz-extension-scheme', + 'opera-scheme', + 'vivaldi-scheme', + '' + ].join('\n'), + + localSettings: { + blockedRequestCount: 0, + allowedRequestCount: 0 + }, + localSettingsLastModified: 0, + localSettingsLastSaved: 0, + + // read-only + systemSettings: { + compiledMagic: 'fxtcjjhbhyiw', + selfieMagic: 'fxtcjjhbhyiw' + }, + + restoreBackupSettings: { + lastRestoreFile: '', + lastRestoreTime: 0, + lastBackupFile: '', + lastBackupTime: 0 + }, + + // Allows to fully customize uBO's assets, typically set through admin + // settings. The content of 'assets.json' will also tell which filter + // lists to enable by default when uBO is first installed. + assetsBootstrapLocation: 'assets/assets.json', + + userFiltersPath: 'user-filters', + pslAssetKey: 'public_suffix_list.dat', + + selectedFilterLists: [], + availableFilterLists: {}, + + selfieAfter: 23 * oneMinute, + + pageStores: {}, + pageStoresToken: 0, + + storageQuota: vAPI.storage.QUOTA_BYTES, + storageUsed: 0, + + noopFunc: function(){}, + + apiErrorCount: 0, + mouseX: -1, + mouseY: -1, + mouseURL: '', + epickerTarget: '', + epickerEprom: null, + + scriptlets: { + }, + + // so that I don't have to care for last comma + dummy: 0 + }; })(); diff --git a/src/js/start.js b/src/js/start.js index 8c37217f9b439..4fabbbac234e0 100644 --- a/src/js/start.js +++ b/src/js/start.js @@ -19,7 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -/* global objectAssign, publicSuffixList */ +/* global publicSuffixList */ 'use strict'; @@ -51,6 +51,20 @@ vAPI.app.onShutdown = function() { /******************************************************************************/ +var processCallbackQueue = function(queue, callback) { + var processOne = function() { + var fn = queue.pop(); + if ( fn ) { + fn(processOne); + } else if ( typeof callback === 'function' ) { + callback(); + } + }; + processOne(); +}; + +/******************************************************************************/ + // Final initialization steps after all needed assets are in memory. // - Initialize internal state with maybe already existing tabs. // - Schedule next update operation. @@ -76,7 +90,7 @@ var onAllReady = function() { µb.contextMenu.update(null); µb.firstInstall = false; - vAPI.net.onReady(); + processCallbackQueue(µb.onStartCompletedQueue); }; /******************************************************************************/ @@ -278,31 +292,11 @@ var onAdminSettingsRestored = function() { /******************************************************************************/ -µb.hiddenSettings = (function() { - var out = objectAssign({}, µb.hiddenSettingsDefault), - json = vAPI.localStorage.getItem('hiddenSettings'); - if ( typeof json === 'string' ) { - try { - var o = JSON.parse(json); - if ( o instanceof Object ) { - for ( var k in o ) { - if ( out.hasOwnProperty(k) ) { - out[k] = o[k]; - } - } - } - } - catch(ex) { - } - } - return out; -})(); - -/******************************************************************************/ - return function() { - // https://github.com/gorhill/uBlock/issues/531 - µb.restoreAdminSettings(onAdminSettingsRestored); + processCallbackQueue(µb.onBeforeStartQueue, function() { + // https://github.com/gorhill/uBlock/issues/531 + µb.restoreAdminSettings(onAdminSettingsRestored); + }); }; /******************************************************************************/ diff --git a/src/js/traffic.js b/src/js/traffic.js index 303a6872fa1e2..da56f1a0f11f4 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -34,47 +34,41 @@ var exports = {}; /******************************************************************************/ // https://github.com/gorhill/uBlock/issues/2067 -// Experimental: Suspend tabs until uBO is fully ready. - -vAPI.net.onReady = function() { - if ( µBlock.hiddenSettings.suspendTabsUntilReady !== true ) { +// Experimental: Block everything until uBO is fully ready. +// TODO: re-work vAPI code to match more closely how listeners are +// registered with the webRequest API. This will simplify implementing +// the feature here: we could have a temporary onBeforeRequest listener +// which blocks everything until all is ready. +// This would allow to avoid the permanent special test at the top of +// the main onBeforeRequest just to implement this. +var onBeforeReady = null; + +if ( µBlock.hiddenSettings.suspendTabsUntilReady ) { + onBeforeReady = (function() { + var suspendedTabs = new Set(); + µBlock.onStartCompletedQueue.push(function(callback) { + onBeforeReady = null; + var iter = suspendedTabs.values(), + entry; + for (;;) { + entry = iter.next(); + if ( entry.done ) { break; } + vAPI.tabs.reload(entry.value); + } + callback(); + }); + return function(tabId) { + if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; } + suspendedTabs.add(tabId); + return true; + }; + })(); +} else { + µBlock.onStartCompletedQueue.push(function(callback) { vAPI.onLoadAllCompleted(); - } - var fn = onBeforeReady; - onBeforeReady = null; - if ( fn !== null ) { - fn('ready'); - } -}; - -var onBeforeReady = (function() { - var suspendedTabs = new Set(); - - var forceReloadSuspendedTabs = function() { - var iter = suspendedTabs.values(), - entry; - for (;;) { - entry = iter.next(); - if ( entry.done ) { break; } - vAPI.tabs.reload(entry.value); - } - }; - - return function(tabId) { - if ( - vAPI.isBehindTheSceneTabId(tabId) || - µBlock.hiddenSettings.suspendTabsUntilReady !== true - ) { - return; - } - if ( tabId === 'ready' ) { - forceReloadSuspendedTabs(); - return; - } - suspendedTabs.add(tabId); - return true; - }; -})(); + callback(); + }); +} /******************************************************************************/ diff --git a/tools/make-firefox-meta.py b/tools/make-firefox-meta.py index c63d48c9b3ec7..773f6a95d8128 100644 --- a/tools/make-firefox-meta.py +++ b/tools/make-firefox-meta.py @@ -31,23 +31,17 @@ def mkdirs(path): locale_path = pj(source_locale_dir, alpha2, 'messages.json') with open(locale_path, encoding='utf-8') as f: strings = json.load(f, object_pairs_hook=OrderedDict) - alpha2 = alpha2.replace('_', '-') descriptions[alpha2] = strings['extShortDesc']['message'] del strings['extShortDesc'] - language_codes.append(alpha2) - mkdirs(pj(target_locale_dir, alpha2)) - locale_path = pj(target_locale_dir, alpha2, 'messages.properties') with open(locale_path, 'wt', encoding='utf-8', newline='\n') as f: for string_name in strings: string = strings[string_name]['message'] - if alpha2 == 'en' and string_name in title_case_strings: string = string.title() - f.write(string_name) f.write(u'=') f.write(string.replace('\n', r'\n')) @@ -58,11 +52,9 @@ def mkdirs(path): with open(chrome_manifest, 'at', encoding='utf-8', newline='\n') as f: f.write(u'\nlocale ublock0 en ./locale/en/\n') - for alpha2 in language_codes: if alpha2 == 'en': continue - f.write(u'locale ublock0 ' + alpha2 + ' ./locale/' + alpha2 + '/\n') rmtree(source_locale_dir) @@ -89,15 +81,13 @@ def mkdirs(path): manifest['homepage'] = 'https://github.com/gorhill/uBlock' manifest['description'] = descriptions['en'] del descriptions['en'] -manifest['localized'] = [] +manifest['localized'] = [] t = ' ' t3 = 3 * t - for alpha2 in descriptions: if alpha2 == 'en': continue - manifest['localized'].append( '\n' + t*2 + '\n' + t3 + '' + alpha2 + '\n' + @@ -108,12 +98,10 @@ def mkdirs(path): t3 + '' + manifest['homepage'] + '\n' + t*2 + '' ) - manifest['localized'] = '\n'.join(manifest['localized']) install_rdf = pj(build_dir, 'install.rdf') with open(install_rdf, 'r+t', encoding='utf-8', newline='\n') as f: install_rdf = f.read() f.seek(0) - f.write(install_rdf.format(**manifest)) diff --git a/tools/make-firefox.sh b/tools/make-firefox.sh index 6199fb46a567c..c393e1738e55a 100755 --- a/tools/make-firefox.sh +++ b/tools/make-firefox.sh @@ -17,9 +17,6 @@ cp -R src/lib $DES/ cp -R src/_locales $DES/ cp src/*.html $DES/ -# AMO review feedback: avoid "unnecessary files or folders" in package -cat src/background.html | sed -e '/vapi-polyfill\.js/d' > $DES/background.html - mv $DES/img/icon_128.png $DES/icon.png cp platform/firefox/css/* $DES/css/ cp platform/firefox/polyfill.js $DES/js/ diff --git a/tools/make-webext-meta.py b/tools/make-webext-meta.py old mode 100755 new mode 100644 index 15df315fba517..dd21761cdc041 --- a/tools/make-webext-meta.py +++ b/tools/make-webext-meta.py @@ -2,7 +2,10 @@ import os import json +import re import sys +from io import open as uopen +from collections import OrderedDict if len(sys.argv) == 1 or not sys.argv[1]: raise SystemExit('Build dir missing.') @@ -10,7 +13,7 @@ proj_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], '..') build_dir = os.path.abspath(sys.argv[1]) -# Import version number from chromium platform +# Import data from chromium platform chromium_manifest = {} webext_manifest = {} @@ -18,7 +21,8 @@ with open(chromium_manifest_file) as f1: chromium_manifest = json.load(f1) -webext_manifest_file = os.path.join(build_dir, 'manifest.json') +# WebExtension part +webext_manifest_file = os.path.join(build_dir, 'webextension', 'manifest.json') with open(webext_manifest_file) as f2: webext_manifest = json.load(f2) @@ -27,3 +31,52 @@ with open(webext_manifest_file, 'w') as f2: json.dump(webext_manifest, f2, indent=2, separators=(',', ': '), sort_keys=True) f2.write('\n') + +# Legacy part +descriptions = OrderedDict({}) +source_locale_dir = os.path.join(build_dir, 'webextension', '_locales') +for alpha2 in sorted(os.listdir(source_locale_dir)): + locale_path = os.path.join(source_locale_dir, alpha2, 'messages.json') + with uopen(locale_path, encoding='utf-8') as f: + strings = json.load(f, object_pairs_hook=OrderedDict) + alpha2 = alpha2.replace('_', '-') + descriptions[alpha2] = strings['extShortDesc']['message'] + +webext_manifest['author'] = chromium_manifest['author']; +webext_manifest['homepage'] = 'https://github.com/gorhill/uBlock' +webext_manifest['description'] = descriptions['en'] +del descriptions['en'] + +match = re.search('^(\d+\.\d+\.\d+)(\.\d+)$', chromium_manifest['version']) +if match: + buildtype = int(match.group(2)[1:]) + if buildtype < 100: + builttype = 'b' + str(buildtype) + else: + builttype = 'rc' + str(buildtype - 100) + webext_manifest['version'] = match.group(1) + builttype + +webext_manifest['localized'] = [] +t = ' ' +t3 = 3 * t +for alpha2 in descriptions: + if alpha2 == 'en': + continue + webext_manifest['localized'].append( + '\n' + t*2 + '\n' + + t3 + '' + alpha2 + '\n' + + t3 + '' + webext_manifest['name'] + '\n' + + t3 + '' + descriptions[alpha2] + '\n' + + t3 + '' + webext_manifest['author'] + '\n' + + # t3 + '' + ??? + '\n' + + t3 + '' + webext_manifest['homepage'] + '\n' + + t*2 + '' + ) +webext_manifest['localized'] = '\n'.join(webext_manifest['localized']) + +install_rdf = os.path.join(build_dir, 'install.rdf') +with uopen(install_rdf, 'r+t', encoding='utf-8', newline='\n') as f: + install_rdf = f.read() + f.seek(0) + f.write(install_rdf.format(**webext_manifest)) + f.truncate() diff --git a/tools/make-webext.sh b/tools/make-webext.sh index 8304b721bfd30..6166bcef25b1e 100755 --- a/tools/make-webext.sh +++ b/tools/make-webext.sh @@ -7,32 +7,39 @@ echo "*** uBlock0.webext: Copying files" DES=dist/build/uBlock0.webext rm -rf $DES -mkdir -p $DES +mkdir -p $DES/webextension -bash ./tools/make-assets.sh $DES +bash ./tools/make-assets.sh $DES/webextension -cp -R src/css $DES/ -cp -R src/img $DES/ -cp -R src/js $DES/ -cp -R src/lib $DES/ -cp -R src/_locales $DES/ -cp -R $DES/_locales/nb $DES/_locales/no -cp src/*.html $DES/ -cp platform/chromium/*.js $DES/js/ -cp -R platform/chromium/img $DES/ -cp platform/chromium/*.html $DES/ -cp platform/chromium/*.json $DES/ -cp platform/webext/polyfill.js $DES/js/ -cp platform/webext/manifest.json $DES/ -cp LICENSE.txt $DES/ +cp -R src/css $DES/webextension/ +cp -R src/img $DES/webextension/ +cp -R src/js $DES/webextension/ +cp -R src/lib $DES/webextension/ +cp -R src/_locales $DES/webextension/ +cp -R $DES/webextension/_locales/nb $DES/webextension/_locales/no +cp src/*.html $DES/webextension/ +cp platform/chromium/*.js $DES/webextension/js/ +cp -R platform/chromium/img $DES/webextension/ +cp platform/chromium/*.html $DES/webextension/ +cp platform/chromium/*.json $DES/webextension/ +cp platform/webext/polyfill.js $DES/webextension/js/ +cp LICENSE.txt $DES/webextension/ + +cp platform/webext/background.html $DES/webextension/ +cp platform/webext/from-legacy.js $DES/webextension/js/ +cp platform/webext/manifest.json $DES/webextension/ +cp platform/webext/bootstrap.js $DES/ +cp platform/webext/chrome.manifest $DES/ +cp platform/webext/install.rdf $DES/ +mv $DES/webextension/img/icon_128.png $DES/icon.png echo "*** uBlock0.webext: Generating meta..." python tools/make-webext-meta.py $DES/ if [ "$1" = all ]; then echo "*** uBlock0.webext: Creating package..." - pushd $(dirname $DES/) > /dev/null - zip uBlock0.webext.zip -qr $(basename $DES/)/* + pushd $DES > /dev/null + zip ../$(basename $DES).zip -qr * popd > /dev/null fi From d7c1f2f919c2077607f558f0aba4a2d21029bb24 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 5 Mar 2017 12:12:58 -0500 Subject: [PATCH 17/23] fix sync storage for Firefox webext (#622) --- platform/chromium/vapi-background.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 99e5e6b9247d1..307f9e513bde3 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -1312,10 +1312,13 @@ vAPI.cloud = (function() { var maxChunkCountPerItem = Math.floor(512 * 0.75) & ~(chunkCountPerFetch - 1); // Mind chrome.storage.sync.QUOTA_BYTES_PER_ITEM (8192 at time of writing) - var maxChunkSize = Math.floor(chrome.storage.sync.QUOTA_BYTES_PER_ITEM * 0.75); + var maxChunkSize = Math.floor(chrome.storage.sync.QUOTA_BYTES_PER_ITEM * 0.75 || 6144); // Mind chrome.storage.sync.QUOTA_BYTES (128 kB at time of writing) - var maxStorageSize = chrome.storage.sync.QUOTA_BYTES; + // Firefox: + // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/sync + // > You can store up to 100KB of data using this API/ + var maxStorageSize = chrome.storage.sync.QUOTA_BYTES || 102400; var options = { defaultDeviceName: window.navigator.platform, From 50158265469d68efd45e7ddfb221e7f9d7a65896 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 5 Mar 2017 12:54:47 -0500 Subject: [PATCH 18/23] fix #2267 --- src/js/assets.js | 62 +++++++++++++++++++++++--------------------- src/js/background.js | 3 ++- src/js/storage.js | 22 +++++++++++++--- 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/js/assets.js b/src/js/assets.js index 1e13848cfec66..eb44ac1c32ce5 100644 --- a/src/js/assets.js +++ b/src/js/assets.js @@ -64,10 +64,8 @@ var fireNotification = function(topic, details) { /******************************************************************************/ -var getTextFileFromURL = function(url, onLoad, onError) { - if ( reIsExternalPath.test(url) === false ) { - url = vAPI.getURL(url); - } +api.fetchText = function(url, onLoad, onError) { + var actualUrl = reIsExternalPath.test(url) ? url : vAPI.getURL(url); if ( typeof onError !== 'function' ) { onError = onLoad; @@ -77,28 +75,34 @@ var getTextFileFromURL = function(url, onLoad, onError) { var onResponseReceived = function() { this.onload = this.onerror = this.ontimeout = null; // xhr for local files gives status 0, but actually succeeds - var status = this.status || 200; - if ( status < 200 || status >= 300 ) { - return onError.call(this); + var details = { + url: url, + content: '', + statusCode: this.status || 200, + statusText: this.statusText || '' + }; + if ( details.statusCode < 200 || details.statusCode >= 300 ) { + return onError.call(null, details); } // consider an empty result to be an error if ( stringIsNotEmpty(this.responseText) === false ) { - return onError.call(this); + return onError.call(null, details); } // we never download anything else than plain text: discard if response // appears to be a HTML document: could happen when server serves // some kind of error page I suppose var text = this.responseText.trim(); if ( text.startsWith('<') && text.endsWith('>') ) { - return onError.call(this); + return onError.call(null, details); } - return onLoad.call(this); + details.content = this.responseText; + return onLoad.call(null, details); }; var onErrorReceived = function() { this.onload = this.onerror = this.ontimeout = null; - µBlock.logger.writeOne('', 'error', errorCantConnectTo.replace('{{msg}}', url)); - onError.call(this); + µBlock.logger.writeOne('', 'error', errorCantConnectTo.replace('{{msg}}', actualUrl)); + onError.call(null, { url: url, content: '' }); }; // Be ready for thrown exceptions: @@ -106,7 +110,7 @@ var getTextFileFromURL = function(url, onLoad, onError) { // `file:///` on Chromium 40 results in an exception being thrown. var xhr = new XMLHttpRequest(); try { - xhr.open('get', url, true); + xhr.open('get', actualUrl, true); xhr.timeout = µBlock.hiddenSettings.assetFetchTimeout * 1000 || 30000; xhr.onload = onResponseReceived; xhr.onerror = onErrorReceived; @@ -405,10 +409,10 @@ var getAssetSourceRegistry = function(callback) { // First-install case. var createRegistry = function() { - getTextFileFromURL( + api.fetchText( µBlock.assetsBootstrapLocation || 'assets/assets.json', - function() { - updateAssetSourceRegistry(this.responseText, true); + function(details) { + updateAssetSourceRegistry(details.content, true); registryReady(); } ); @@ -757,21 +761,21 @@ api.get = function(assetKey, options, callback) { if ( !contentURL ) { return reportBack('', 'E_NOTFOUND'); } - getTextFileFromURL(contentURL, onContentLoaded, onContentNotLoaded); + api.fetchText(contentURL, onContentLoaded, onContentNotLoaded); }; - var onContentLoaded = function() { - if ( stringIsNotEmpty(this.responseText) === false ) { + var onContentLoaded = function(details) { + if ( stringIsNotEmpty(details.content) === false ) { onContentNotLoaded(); return; } if ( reIsExternalPath.test(contentURL) && options.dontCache !== true ) { assetCacheWrite(assetKey, { - content: this.responseText, + content: details.content, url: contentURL }); } - reportBack(this.responseText); + reportBack(details.content); }; var onCachedContentLoaded = function(details) { @@ -811,23 +815,23 @@ var getRemote = function(assetKey, callback) { callback(details); }; - var onRemoteContentLoaded = function() { - if ( stringIsNotEmpty(this.responseText) === false ) { + var onRemoteContentLoaded = function(details) { + if ( stringIsNotEmpty(details.content) === false ) { registerAssetSource(assetKey, { error: { time: Date.now(), error: 'No content' } }); tryLoading(); return; } assetCacheWrite(assetKey, { - content: this.responseText, + content: details.content, url: contentURL }); registerAssetSource(assetKey, { error: undefined }); - reportBack(this.responseText); + reportBack(details.content); }; - var onRemoteContentError = function() { - var text = this.statusText; - if ( this.status === 0 ) { + var onRemoteContentError = function(details) { + var text = details.statusText; + if ( details.statusCode === 0 ) { text = 'network error'; } registerAssetSource(assetKey, { error: { time: Date.now(), error: text } }); @@ -841,7 +845,7 @@ var getRemote = function(assetKey, callback) { if ( !contentURL ) { return reportBack('', 'E_NOTFOUND'); } - getTextFileFromURL(contentURL, onRemoteContentLoaded, onRemoteContentError); + api.fetchText(contentURL, onRemoteContentLoaded, onRemoteContentError); }; getAssetSourceRegistry(function(registry) { diff --git a/src/js/background.js b/src/js/background.js index ca7fe704b39f5..4e69a949855f3 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -39,7 +39,8 @@ var µBlock = (function() { // jshint ignore:line ignoreScriptInjectFilters: false, manualUpdateAssetFetchPeriod: 2000, popupFontSize: 'unset', - suspendTabsUntilReady: false + suspendTabsUntilReady: false, + userResourcesLocation: 'unset' }; return { diff --git a/src/js/storage.js b/src/js/storage.js index bfba9d2ea560c..d76c5c9bb3144 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -818,17 +818,33 @@ /******************************************************************************/ µBlock.loadRedirectResources = function(callback) { - var µb = this; + var µb = this, + content = ''; if ( typeof callback !== 'function' ) { callback = this.noopFunc; } + var onDone = function() { + µb.redirectEngine.resourcesFromString(content); + callback(); + }; + + var onUserResourcesLoaded = function(details) { + if ( details.content !== '' ) { + content += '\n\n' + details.content; + } + onDone(); + }; + var onResourcesLoaded = function(details) { if ( details.content !== '' ) { - µb.redirectEngine.resourcesFromString(details.content); + content = details.content; } - callback(); + if ( µb.hiddenSettings.userResourcesLocation === 'unset' ) { + return onDone(); + } + µb.assets.fetchText(µb.hiddenSettings.userResourcesLocation, onUserResourcesLoaded); }; this.assets.get('ublock-resources', onResourcesLoaded); From 4c832718d3c2348f347774441a15919d3a19c87f Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 5 Mar 2017 14:32:53 -0500 Subject: [PATCH 19/23] 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 0eb0f71835b0c..90a216018c51e 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "uBlock Origin", - "version": "1.11.2", + "version": "1.11.3.0", "default_locale": "en", "description": "__MSG_extShortDesc__", From c271fbbd0d2b4ae6a74a5aa387e549f68fea1064 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 5 Mar 2017 17:20:28 -0500 Subject: [PATCH 20/23] code review: remove old cruft --- platform/chromium/vapi-background.js | 88 ++++++++++------------------ 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 307f9e513bde3..c028540bc99ed 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -1092,64 +1092,40 @@ vAPI.net.registerListeners = function() { return onHeadersReceivedClient(details); }; + var urls, types; + + if ( onBeforeRequest ) { + urls = this.onBeforeRequest.urls || ['']; + types = this.onBeforeRequest.types || undefined; + wrApi.onBeforeRequest.addListener( + onBeforeRequest, + { urls: urls, types: types }, + this.onBeforeRequest.extra + ); + } - var installListeners = (function() { - //listener = function(details) { - // quickProfiler.start('onBeforeRequest'); - // var r = onBeforeRequest(details); - // quickProfiler.stop(); - // return r; - //}; - var urls, types; - - if ( - onBeforeRequest && - wrApi.onBeforeRequest.hasListener(onBeforeRequest) === false - ) { - urls = this.onBeforeRequest.urls || ['']; - types = this.onBeforeRequest.types || undefined; - wrApi.onBeforeRequest.addListener( - onBeforeRequest, - { urls: urls, types: types }, - this.onBeforeRequest.extra - ); - } - - // Chromium 48 and lower does not support `ping` type. - // Chromium 56 and higher does support `csp_report` stype. - if ( - onBeforeSendHeaders && - wrApi.onBeforeSendHeaders.hasListener(onBeforeSendHeaders) === false - ) { - wrApi.onBeforeSendHeaders.addListener( - onBeforeSendHeaders, - { - 'urls': [ '' ], - 'types': [ 'ping' ] - }, - [ 'blocking', 'requestHeaders' ] - ); - } - - if ( - onHeadersReceived && - wrApi.onHeadersReceived.hasListener(onHeadersReceived) === false - ) { - urls = this.onHeadersReceived.urls || ['']; - types = onHeadersReceivedTypes; - wrApi.onHeadersReceived.addListener( - onHeadersReceived, - { urls: urls, types: types }, - this.onHeadersReceived.extra - ); - } - - // https://github.com/gorhill/uBlock/issues/675 - // Experimental: keep polling to be sure our listeners are still installed. - //setTimeout(installListeners, 20000); - }).bind(this); + // Chromium 48 and lower does not support `ping` type. + // Chromium 56 and higher does support `csp_report` stype. + if ( onBeforeSendHeaders ) { + wrApi.onBeforeSendHeaders.addListener( + onBeforeSendHeaders, + { + 'urls': [ '' ], + 'types': [ 'ping' ] + }, + [ 'blocking', 'requestHeaders' ] + ); + } - installListeners(); + if ( onHeadersReceived ) { + urls = this.onHeadersReceived.urls || ['']; + types = onHeadersReceivedTypes; + wrApi.onHeadersReceived.addListener( + onHeadersReceived, + { urls: urls, types: types }, + this.onHeadersReceived.extra + ); + } }; /******************************************************************************/ From 2213b005a0dbb5786d541f96d085f1ac3411748d Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 6 Mar 2017 17:34:46 -0500 Subject: [PATCH 21/23] forgot to add "ws://*/*"/"wss://*/*" to enable support for websocket type" --- platform/chromium/manifest.json | 4 +++- src/js/traffic.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json index 90a216018c51e..180aa84a5374a 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -55,7 +55,9 @@ "webRequest", "webRequestBlocking", "http://*/*", - "https://*/*" + "https://*/*", + "ws://*/*", + "wss://*/*" ], "short_name": "uBlock₀", "storage": { diff --git a/src/js/traffic.js b/src/js/traffic.js index da56f1a0f11f4..0f570429b534e 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -679,7 +679,9 @@ var headerIndexFromName = function(headerName, headers) { vAPI.net.onBeforeRequest = { urls: [ 'http://*/*', - 'https://*/*' + 'https://*/*', + 'ws://*/*', + 'wss://*/*' ], extra: [ 'blocking' ], callback: onBeforeRequest From 7e55ddf16b602dad264bb74e83700a9b353fd26a Mon Sep 17 00:00:00 2001 From: gorhill Date: Mon, 6 Mar 2017 17:53:25 -0500 Subject: [PATCH 22/23] re. websocket: mind backward compatibility --- platform/chromium/vapi-background.js | 12 ++++++++++++ src/js/traffic.js | 4 +--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index c028540bc99ed..2032ba2c1b165 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -1097,6 +1097,18 @@ vAPI.net.registerListeners = function() { if ( onBeforeRequest ) { urls = this.onBeforeRequest.urls || ['']; types = this.onBeforeRequest.types || undefined; + if ( + (validTypes.websocket) && + (types === undefined || types.indexOf('websocket') !== -1) && + (urls.indexOf('') === -1) + ) { + if ( urls.indexOf('ws://*/*') === -1 ) { + urls.push('ws://*/*'); + } + if ( urls.indexOf('wss://*/*') === -1 ) { + urls.push('wss://*/*'); + } + } wrApi.onBeforeRequest.addListener( onBeforeRequest, { urls: urls, types: types }, diff --git a/src/js/traffic.js b/src/js/traffic.js index 0f570429b534e..da56f1a0f11f4 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -679,9 +679,7 @@ var headerIndexFromName = function(headerName, headers) { vAPI.net.onBeforeRequest = { urls: [ 'http://*/*', - 'https://*/*', - 'ws://*/*', - 'wss://*/*' + 'https://*/*' ], extra: [ 'blocking' ], callback: onBeforeRequest From 9f26776c11cf0d22fb52b9b1bb5c373fc06eca7a Mon Sep 17 00:00:00 2001 From: gorhill Date: Tue, 7 Mar 2017 13:51:23 -0500 Subject: [PATCH 23/23] 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 180aa84a5374a..277e007b23804 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "uBlock Origin", - "version": "1.11.3.0", + "version": "1.11.3.1", "default_locale": "en", "description": "__MSG_extShortDesc__",