diff --git a/dist/firefox/updates.json b/dist/firefox/updates.json
index d23a8da59..63a7f9422 100644
--- a/dist/firefox/updates.json
+++ b/dist/firefox/updates.json
@@ -3,9 +3,9 @@
"uBlock0@raymondhill.net": {
"updates": [
{
- "version": "1.37.1.1",
+ "version": "1.37.1.2",
"browser_specific_settings": { "gecko": { "strict_min_version": "57" } },
- "update_link": "https://github.com/gorhill/uBlock/releases/download/1.37.1b1/uBlock0_1.37.1b1.firefox.signed.xpi"
+ "update_link": "https://github.com/gorhill/uBlock/releases/download/1.37.1b2/uBlock0_1.37.1b2.firefox.signed.xpi"
}
]
}
diff --git a/dist/version b/dist/version
index 29ae45efb..e56539b5d 100644
--- a/dist/version
+++ b/dist/version
@@ -1 +1 @@
-1.37.1.1
+1.37.1.2
diff --git a/platform/browser/main.js b/platform/browser/main.js
new file mode 100644
index 000000000..aaacfe9a2
--- /dev/null
+++ b/platform/browser/main.js
@@ -0,0 +1,125 @@
+/*******************************************************************************
+
+ uBlock Origin - a browser extension to block requests.
+ Copyright (C) 2014-present 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
+
+ Home: https://github.com/gorhill/uBlock
+*/
+
+'use strict';
+
+/******************************************************************************/
+
+import './lib/publicsuffixlist/publicsuffixlist.js';
+import './lib/punycode.js';
+
+import globals from './js/globals.js';
+import { FilteringContext } from './js/filtering-context.js';
+import { LineIterator } from './js/text-iterators.js';
+import { StaticFilteringParser } from './js/static-filtering-parser.js';
+import { staticNetFilteringEngine } from './js/static-net-filtering.js';
+
+import {
+ CompiledListReader,
+ CompiledListWriter
+} from './js/static-filtering-io.js';
+
+/******************************************************************************/
+
+function compileList(rawText, writer) {
+ const lineIter = new LineIterator(rawText);
+ const parser = new StaticFilteringParser(true);
+
+ parser.setMaxTokenLength(staticNetFilteringEngine.MAX_TOKEN_LENGTH);
+
+ while ( lineIter.eot() === false ) {
+ let line = lineIter.next();
+
+ while ( line.endsWith(' \\') ) {
+ if ( lineIter.peek(4) !== ' ' ) { break; }
+ line = line.slice(0, -2).trim() + lineIter.next().trim();
+ }
+ parser.analyze(line);
+
+ if ( parser.shouldIgnore() ) { continue; }
+ if ( parser.category !== parser.CATStaticNetFilter ) { continue; }
+ if ( parser.patternHasUnicode() && parser.toASCII() === false ) {
+ continue;
+ }
+ if ( staticNetFilteringEngine.compile(parser, writer) ) { continue; }
+ if ( staticNetFilteringEngine.error !== undefined ) {
+ console.info(JSON.stringify({
+ realm: 'message',
+ type: 'error',
+ text: staticNetFilteringEngine.error
+ }));
+ }
+ }
+
+ return writer.toString();
+}
+
+function applyList(name, raw) {
+ const writer = new CompiledListWriter();
+ writer.properties.set('name', name);
+ const compiled = compileList(raw, writer);
+ const reader = new CompiledListReader(compiled);
+ staticNetFilteringEngine.fromCompiled(reader);
+}
+
+function enableWASM(path) {
+ return Promise.all([
+ globals.publicSuffixList.enableWASM(`${path}/lib/publicsuffixlist`),
+ staticNetFilteringEngine.enableWASM(`${path}/js`),
+ ]);
+}
+
+function pslInit(raw) {
+ if ( typeof raw !== 'string' || raw.trim() === '' ) {
+ console.info('Unable to populate public suffix list');
+ return;
+ }
+ globals.publicSuffixList.parse(raw, globals.punycode.toASCII);
+ console.info('Public suffix list populated');
+}
+
+function restart(lists) {
+ // Remove all filters
+ reset();
+
+ if ( Array.isArray(lists) && lists.length !== 0 ) {
+ // Populate filtering engine with filter lists
+ for ( const { name, raw } of lists ) {
+ applyList(name, raw);
+ }
+ // Commit changes
+ staticNetFilteringEngine.freeze();
+ staticNetFilteringEngine.optimize();
+ }
+
+ return staticNetFilteringEngine;
+}
+
+function reset() {
+ staticNetFilteringEngine.reset();
+}
+
+export {
+ FilteringContext,
+ enableWASM,
+ pslInit,
+ restart,
+};
diff --git a/platform/browser/test.html b/platform/browser/test.html
new file mode 100644
index 000000000..32b1aba8e
--- /dev/null
+++ b/platform/browser/test.html
@@ -0,0 +1,71 @@
+
+
+
+
+uBO Static Network Filtering Engine
+
+
+
+
+
diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json
index 9a515985a..f9ab901be 100644
--- a/platform/chromium/manifest.json
+++ b/platform/chromium/manifest.json
@@ -70,7 +70,7 @@
},
"incognito": "split",
"manifest_version": 2,
- "minimum_chrome_version": "55.0",
+ "minimum_chrome_version": "61.0",
"name": "uBlock Origin",
"options_ui": {
"page": "dashboard.html",
diff --git a/platform/common/vapi-background.js b/platform/common/vapi-background.js
index 489f231fe..b9f7e2721 100644
--- a/platform/common/vapi-background.js
+++ b/platform/common/vapi-background.js
@@ -26,12 +26,6 @@
/******************************************************************************/
-{
-// >>>>> start of local scope
-
-/******************************************************************************/
-/******************************************************************************/
-
const browser = self.browser;
const manifest = browser.runtime.getManifest();
@@ -1719,9 +1713,3 @@ vAPI.cloud = (( ) => {
})();
/******************************************************************************/
-/******************************************************************************/
-
-// <<<<< end of local scope
-}
-
-/******************************************************************************/
diff --git a/platform/common/vapi-common.js b/platform/common/vapi-common.js
index e8de131d2..184260681 100644
--- a/platform/common/vapi-common.js
+++ b/platform/common/vapi-common.js
@@ -100,59 +100,6 @@ vAPI.webextFlavor = {
/******************************************************************************/
-{
- const punycode = self.punycode;
- const reCommonHostnameFromURL = /^https?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])\//;
- const reAuthorityFromURI = /^(?:[^:\/?#]+:)?(\/\/[^\/?#]+)/;
- const reHostFromNakedAuthority = /^[0-9a-z._-]+[0-9a-z]$/i;
- const reHostFromAuthority = /^(?:[^@]*@)?([^:]+)(?::\d*)?$/;
- const reIPv6FromAuthority = /^(?:[^@]*@)?(\[[0-9a-f:]+\])(?::\d*)?$/i;
- const reMustNormalizeHostname = /[^0-9a-z._-]/;
-
- vAPI.hostnameFromURI = function(uri) {
- let matches = reCommonHostnameFromURL.exec(uri);
- if ( matches !== null ) { return matches[1]; }
- matches = reAuthorityFromURI.exec(uri);
- if ( matches === null ) { return ''; }
- const authority = matches[1].slice(2);
- if ( reHostFromNakedAuthority.test(authority) ) {
- return authority.toLowerCase();
- }
- matches = reHostFromAuthority.exec(authority);
- if ( matches === null ) {
- matches = reIPv6FromAuthority.exec(authority);
- if ( matches === null ) { return ''; }
- }
- let hostname = matches[1];
- while ( hostname.endsWith('.') ) {
- hostname = hostname.slice(0, -1);
- }
- if ( reMustNormalizeHostname.test(hostname) ) {
- hostname = punycode.toASCII(hostname.toLowerCase());
- }
- return hostname;
- };
-
- const reHostnameFromNetworkURL =
- /^(?:http|ws|ftp)s?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])(?::\d+)?\//;
-
- vAPI.hostnameFromNetworkURL = function(url) {
- const matches = reHostnameFromNetworkURL.exec(url);
- return matches !== null ? matches[1] : '';
- };
-
- const psl = self.publicSuffixList;
- const reIPAddressNaive = /^\d+\.\d+\.\d+\.\d+$|^\[[\da-zA-Z:]+\]$/;
-
- vAPI.domainFromHostname = function(hostname) {
- return reIPAddressNaive.test(hostname)
- ? hostname
- : psl.getDomain(hostname);
- };
-}
-
-/******************************************************************************/
-
vAPI.download = function(details) {
if ( !details.url ) { return; }
const a = document.createElement('a');
diff --git a/platform/firefox/vapi-background-ext.js b/platform/firefox/vapi-background-ext.js
index c083cabfe..69609f216 100644
--- a/platform/firefox/vapi-background-ext.js
+++ b/platform/firefox/vapi-background-ext.js
@@ -25,30 +25,17 @@
/******************************************************************************/
+import {
+ domainFromHostname,
+ hostnameFromNetworkURL,
+} from './uri-utils.js';
+
+/******************************************************************************/
+
(( ) => {
// https://github.com/uBlockOrigin/uBlock-issues/issues/407
if ( vAPI.webextFlavor.soup.has('firefox') === false ) { return; }
- // https://github.com/gorhill/uBlock/issues/2950
- // Firefox 56 does not normalize URLs to ASCII, uBO must do this itself.
- // https://bugzilla.mozilla.org/show_bug.cgi?id=945240
- const evalMustPunycode = ( ) => {
- return vAPI.webextFlavor.soup.has('firefox') &&
- vAPI.webextFlavor.major < 57;
- };
-
- let mustPunycode = evalMustPunycode();
-
- // The real actual webextFlavor value may not be set in stone, so listen
- // for possible future changes.
- window.addEventListener('webextFlavor', ( ) => {
- mustPunycode = evalMustPunycode();
- }, { once: true });
-
- const punycode = self.punycode;
- const reAsciiHostname = /^https?:\/\/[0-9a-z_.:@-]+[/?#]/;
- const parsedURL = new URL('about:blank');
-
// Canonical name-uncloaking feature.
let cnameUncloakEnabled = browser.dns instanceof Object;
let cnameUncloakProxied = false;
@@ -144,14 +131,6 @@
}
}
normalizeDetails(details) {
- if ( mustPunycode && !reAsciiHostname.test(details.url) ) {
- parsedURL.href = details.url;
- details.url = details.url.replace(
- parsedURL.hostname,
- punycode.toASCII(parsedURL.hostname)
- );
- }
-
const type = details.type;
if ( type === 'imageset' ) {
@@ -231,7 +210,7 @@
if (
cname !== '' &&
this.cnameIgnore1stParty &&
- vAPI.domainFromHostname(cname) === vAPI.domainFromHostname(hn)
+ domainFromHostname(cname) === domainFromHostname(hn)
) {
cname = '';
}
@@ -284,7 +263,7 @@
) {
return;
}
- const hn = vAPI.hostnameFromNetworkURL(details.url);
+ const hn = hostnameFromNetworkURL(details.url);
const cname = this.cnames.get(hn);
if ( cname === '' ) { return; }
if ( cname !== undefined ) {
diff --git a/platform/nodejs/main.js b/platform/nodejs/main.js
new file mode 100644
index 000000000..a104fae84
--- /dev/null
+++ b/platform/nodejs/main.js
@@ -0,0 +1,127 @@
+/*******************************************************************************
+
+ uBlock Origin - a browser extension to block requests.
+ Copyright (C) 2014-present 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
+
+ Home: https://github.com/gorhill/uBlock
+*/
+
+'use strict';
+
+/******************************************************************************/
+
+import './lib/punycode.js';
+import './lib/publicsuffixlist/publicsuffixlist.js';
+
+import globals from './js/globals.js';
+import { FilteringContext } from './js/filtering-context.js';
+import { LineIterator } from './js/text-iterators.js';
+import { StaticFilteringParser } from './js/static-filtering-parser.js';
+import { staticNetFilteringEngine } from './js/static-net-filtering.js';
+
+import {
+ CompiledListReader,
+ CompiledListWriter,
+} from './js/static-filtering-io.js';
+
+/******************************************************************************/
+
+function compileList(rawText, writer) {
+ const lineIter = new LineIterator(rawText);
+ const parser = new StaticFilteringParser(true);
+
+ parser.setMaxTokenLength(staticNetFilteringEngine.MAX_TOKEN_LENGTH);
+
+ while ( lineIter.eot() === false ) {
+ let line = lineIter.next();
+
+ while ( line.endsWith(' \\') ) {
+ if ( lineIter.peek(4) !== ' ' ) { break; }
+ line = line.slice(0, -2).trim() + lineIter.next().trim();
+ }
+ parser.analyze(line);
+
+ if ( parser.shouldIgnore() ) { continue; }
+ if ( parser.category !== parser.CATStaticNetFilter ) { continue; }
+ if ( parser.patternHasUnicode() && parser.toASCII() === false ) {
+ continue;
+ }
+ if ( staticNetFilteringEngine.compile(parser, writer) ) { continue; }
+ if ( staticNetFilteringEngine.error !== undefined ) {
+ console.info(JSON.stringify({
+ realm: 'message',
+ type: 'error',
+ text: staticNetFilteringEngine.error
+ }));
+ }
+ }
+
+ return writer.toString();
+}
+
+function applyList(name, raw) {
+ const writer = new CompiledListWriter();
+ writer.properties.set('name', name);
+ const compiled = compileList(raw, writer);
+ const reader = new CompiledListReader(compiled);
+ staticNetFilteringEngine.fromCompiled(reader);
+}
+
+function enableWASM(path) {
+ return Promise.all([
+ globals.publicSuffixList.enableWASM(`${path}/lib/publicsuffixlist`),
+ staticNetFilteringEngine.enableWASM(`${path}/js`),
+ ]);
+}
+
+function pslInit(raw) {
+ if ( typeof raw !== 'string' || raw.trim() === '' ) {
+ console.info('Unable to populate public suffix list');
+ return;
+ }
+ globals.publicSuffixList.parse(raw, globals.punycode.toASCII);
+ console.info('Public suffix list populated');
+}
+
+function restart(lists) {
+ // Remove all filters
+ reset();
+
+ if ( Array.isArray(lists) && lists.length !== 0 ) {
+ // Populate filtering engine with filter lists
+ for ( const { name, raw } of lists ) {
+ applyList(name, raw);
+ }
+ // Commit changes
+ staticNetFilteringEngine.freeze();
+ staticNetFilteringEngine.optimize();
+ }
+
+ console.info('Static network filtering engine populated');
+
+ return staticNetFilteringEngine;
+}
+
+function reset() {
+ staticNetFilteringEngine.reset();
+}
+
+export {
+ FilteringContext,
+ enableWASM,
+ pslInit,
+ restart,
+};
diff --git a/platform/nodejs/package.json b/platform/nodejs/package.json
new file mode 100644
index 000000000..37dbc7755
--- /dev/null
+++ b/platform/nodejs/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "uBO-snfe",
+ "version": "0.1.0",
+ "description": "To create a working instance of uBlock's static network filtering engine",
+ "type": "module",
+ "main": "main.js",
+ "scripts": {
+ "test": "node test.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/gorhill/uBlock.git"
+ },
+ "keywords": [
+ "uBlock",
+ "uBO",
+ "adblock"
+ ],
+ "author": "Raymond Hill",
+ "license": "GPL-3.0-or-later",
+ "bugs": {
+ "url": "https://github.com/gorhill/uBlock/issues"
+ },
+ "homepage": "https://github.com/gorhill/uBlock#readme"
+}
diff --git a/platform/nodejs/test.js b/platform/nodejs/test.js
new file mode 100644
index 000000000..0d544e9d1
--- /dev/null
+++ b/platform/nodejs/test.js
@@ -0,0 +1,107 @@
+/*******************************************************************************
+
+ uBlock Origin - a browser extension to block requests.
+ Copyright (C) 2014-present 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
+
+ Home: https://github.com/gorhill/uBlock
+*/
+
+/* globals process */
+
+'use strict';
+
+/******************************************************************************/
+
+import { readFile } from 'fs';
+
+import {
+ FilteringContext,
+ pslInit,
+ restart,
+} from './main.js';
+
+/******************************************************************************/
+
+function fetch(path) {
+ return new Promise((resolve, reject) => {
+ readFile(path, 'utf8', (err, data) => {
+ if ( err ) {
+ reject(err);
+ } else {
+ resolve(data);
+ }
+ });
+ });
+}
+
+(async ( ) => {
+ /*
+ * WASM require fetch(), not present in Node
+ try {
+ await enableWASM('//ublock/dist/build/uBlock0.nodejs');
+ } catch(ex) {
+ }
+ */
+
+ await fetch('./data/effective_tld_names.dat').then(pslRaw => {
+ pslInit(pslRaw);
+ });
+
+ const snfe = await Promise.all([
+ fetch('./data/easylist.txt'),
+ fetch('./data/easyprivacy.txt'),
+ ]).then(rawLists => {
+ return restart([
+ { name: 'easylist', raw: rawLists[0] },
+ { name: 'easyprivacy', raw: rawLists[1] },
+ ]);
+ });
+
+ // Reuse filtering context: it's what uBO does
+ const fctxt = new FilteringContext();
+
+ // Tests
+ // Not blocked
+ fctxt.setDocOriginFromURL('https://www.bloomberg.com/');
+ fctxt.setURL('https://www.bloomberg.com/tophat/assets/v2.6.1/that.css');
+ fctxt.setType('stylesheet');
+ if ( snfe.matchRequest(fctxt) !== 0 ) {
+ console.log(snfe.toLogData());
+ }
+
+ // Blocked
+ fctxt.setDocOriginFromURL('https://www.bloomberg.com/');
+ fctxt.setURL('https://securepubads.g.doubleclick.net/tag/js/gpt.js');
+ fctxt.setType('script');
+ if ( snfe.matchRequest(fctxt) !== 0 ) {
+ console.log(snfe.toLogData());
+ }
+
+ // Unblocked
+ fctxt.setDocOriginFromURL('https://www.bloomberg.com/');
+ fctxt.setURL('https://sourcepointcmp.bloomberg.com/ccpa.js');
+ fctxt.setType('script');
+ if ( snfe.matchRequest(fctxt) !== 0 ) {
+ console.log(snfe.toLogData());
+ }
+
+ // Remove all filters
+ restart();
+
+ process.exit();
+})();
+
+/******************************************************************************/
diff --git a/platform/opera/manifest.json b/platform/opera/manifest.json
index 69af37e96..2545566ee 100644
--- a/platform/opera/manifest.json
+++ b/platform/opera/manifest.json
@@ -69,7 +69,7 @@
},
"incognito": "split",
"manifest_version": 2,
- "minimum_opera_version": "42.0",
+ "minimum_opera_version": "48.0",
"name": "uBlock Origin",
"options_page": "dashboard.html",
"permissions": [
diff --git a/platform/thunderbird/manifest.json b/platform/thunderbird/manifest.json
index a0762a129..3f909edbe 100644
--- a/platform/thunderbird/manifest.json
+++ b/platform/thunderbird/manifest.json
@@ -2,7 +2,7 @@
"applications": {
"gecko": {
"id": "uBlock0@raymondhill.net",
- "strict_min_version": "65.0"
+ "strict_min_version": "78.0"
}
},
"author": "Raymond Hill & contributors",
diff --git a/src/1p-filters.html b/src/1p-filters.html
index 26fce7f6e..29d615501 100644
--- a/src/1p-filters.html
+++ b/src/1p-filters.html
@@ -50,11 +50,9 @@
-
-
@@ -65,8 +63,7 @@
-
-
+