diff --git a/platform/webext/img/browsericons/icon19-off.png b/platform/webext/img/browsericons/icon19-off.png
deleted file mode 100644
index 79fb3b823..000000000
Binary files a/platform/webext/img/browsericons/icon19-off.png and /dev/null differ
diff --git a/platform/webext/img/browsericons/icon19.png b/platform/webext/img/browsericons/icon19.png
deleted file mode 100644
index e6d57bdda..000000000
Binary files a/platform/webext/img/browsericons/icon19.png and /dev/null differ
diff --git a/platform/webext/img/browsericons/icon38-off.png b/platform/webext/img/browsericons/icon38-off.png
deleted file mode 100644
index a1b5c00bf..000000000
Binary files a/platform/webext/img/browsericons/icon38-off.png and /dev/null differ
diff --git a/platform/webext/img/browsericons/icon38.png b/platform/webext/img/browsericons/icon38.png
deleted file mode 100644
index 09a57d2ff..000000000
Binary files a/platform/webext/img/browsericons/icon38.png and /dev/null differ
diff --git a/platform/webext/is-webrtc-supported.html b/platform/webext/is-webrtc-supported.html
deleted file mode 100644
index 15c155583..000000000
--- a/platform/webext/is-webrtc-supported.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/platform/webext/is-webrtc-supported.js b/platform/webext/is-webrtc-supported.js
deleted file mode 100644
index 5a3eea1e7..000000000
--- a/platform/webext/is-webrtc-supported.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
-
- uBlock Origin - a browser extension to block requests.
- Copyright (C) 2015 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
-*/
-
-// https://github.com/gorhill/uBlock/issues/533#issuecomment-164292868
-// If WebRTC is supported, there won't be an exception if we
-// try to instanciate a peer connection object.
-
-// https://github.com/gorhill/uBlock/issues/533#issuecomment-168097594
-// Because Chromium leaks WebRTC connections after they have been closed
-// and forgotten, we need to test for WebRTC support inside an iframe, this
-// way the closed and forgottetn WebRTC connections are properly garbage
-// collected.
-
-(function() {
- 'use strict';
-
- var pc = null;
- try {
- var PC = self.RTCPeerConnection || self.webkitRTCPeerConnection;
- if ( PC ) {
- pc = new PC(null);
- }
- } catch (ex) {
- console.error(ex);
- }
- if ( pc !== null ) {
- pc.close();
- }
-
- window.top.postMessage(
- pc !== null ? 'webRTCSupported' : 'webRTCNotSupported',
- window.location.origin
- );
-})();
diff --git a/platform/webext/managed_storage.json b/platform/webext/managed_storage.json
deleted file mode 100644
index d3f2c864f..000000000
--- a/platform/webext/managed_storage.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-03/schema#",
- "type": "object",
- "properties": {
- "adminSettings": {
- "title": "A valid JSON string compliant with uBO's backup format.",
- "description": "All entries present will overwrite local settings.",
- "type": "string"
- }
- }
-}
diff --git a/platform/webext/options_ui.html b/platform/webext/options_ui.html
deleted file mode 100644
index d94c001ef..000000000
--- a/platform/webext/options_ui.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-Dashboard
-
-
diff --git a/platform/webext/options_ui.js b/platform/webext/options_ui.js
deleted file mode 100644
index 1e7f552b1..000000000
--- a/platform/webext/options_ui.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
-
- µBlock - a browser extension to block requests.
- Copyright (C) 2015 The µBlock authors
-
- 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
-*/
-
-/******************************************************************************/
-
-(function() {
-
-/******************************************************************************/
-
-'use strict';
-
-vAPI.messaging.send(
- 'default',
- {
- what: 'gotoURL',
- details: {
- url: 'dashboard.html',
- select: true,
- index: -1
- }
- }
-);
-window.close();
-
-/******************************************************************************/
-
-})();
-
-/******************************************************************************/
diff --git a/platform/webext/vapi-background.js b/platform/webext/vapi-background.js
deleted file mode 100644
index 5e95622d6..000000000
--- a/platform/webext/vapi-background.js
+++ /dev/null
@@ -1,1424 +0,0 @@
-/*******************************************************************************
-
- uBlock Origin - a browser extension to block requests.
- Copyright (C) 2014-2016 The uBlock Origin authors
-
- 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
-*/
-
-// For background page
-
-/******************************************************************************/
-
-(function() {
-
-'use strict';
-
-/******************************************************************************/
-
-var vAPI = self.vAPI = self.vAPI || {};
-
-var chrome = self.chrome;
-var manifest = chrome.runtime.getManifest();
-
-vAPI.chrome = true;
-vAPI.cantWebsocket = true;
-
-var noopFunc = function(){};
-
-/******************************************************************************/
-
-vAPI.app = {
- name: manifest.name,
- version: manifest.version
-};
-
-/******************************************************************************/
-
-vAPI.app.restart = function() {
- chrome.runtime.reload();
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-// chrome.storage.local.get(null, function(bin){ console.debug('%o', bin); });
-
-vAPI.storage = chrome.storage.local;
-
-/******************************************************************************/
-/******************************************************************************/
-
-// https://github.com/gorhill/uMatrix/issues/234
-// https://developer.chrome.com/extensions/privacy#property-network
-
-// 2015-08-12: Wrapped Chrome API in try-catch statements. I had a fluke
-// event in which it appeared Chrome 46 decided to restart uBlock (for
-// unknown reasons) and again for unknown reasons the browser acted as if
-// uBlock did not declare the `privacy` permission in its manifest, putting
-// uBlock in a bad, non-functional state -- because call to `chrome.privacy`
-// API threw an exception.
-
-// https://github.com/gorhill/uBlock/issues/2048
-// Do not mess up with existing settings if not assigning them stricter
-// values.
-
-vAPI.browserSettings = {
- webRTCSupported: undefined,
-
- // https://github.com/gorhill/uBlock/issues/875
- // Must not leave `lastError` unchecked.
- noopCallback: function() {
- void chrome.runtime.lastError;
- },
-
- // Calling with `true` means IP address leak is not prevented.
- // https://github.com/gorhill/uBlock/issues/533
- // We must first check wether this Chromium-based browser was compiled
- // with WebRTC support. To do this, we use an iframe, this way the
- // empty RTCPeerConnection object we create to test for support will
- // be properly garbage collected. This prevents issues such as
- // a computer unable to enter into sleep mode, as reported in the
- // Chrome store:
- // https://github.com/gorhill/uBlock/issues/533#issuecomment-167931681
- setWebrtcIPAddress: function(setting) {
- // We don't know yet whether this browser supports WebRTC: find out.
- if ( this.webRTCSupported === undefined ) {
- this.webRTCSupported = { setting: setting };
- var iframe = document.createElement('iframe');
- var me = this;
- var messageHandler = function(ev) {
- if ( ev.origin !== self.location.origin ) {
- return;
- }
- window.removeEventListener('message', messageHandler);
- var setting = me.webRTCSupported.setting;
- me.webRTCSupported = ev.data === 'webRTCSupported';
- me.setWebrtcIPAddress(setting);
- iframe.parentNode.removeChild(iframe);
- iframe = null;
- };
- window.addEventListener('message', messageHandler);
- iframe.src = 'is-webrtc-supported.html';
- document.body.appendChild(iframe);
- return;
- }
-
- // We are waiting for a response from our iframe. This makes the code
- // safe to re-entrancy.
- if ( typeof this.webRTCSupported === 'object' ) {
- this.webRTCSupported.setting = setting;
- return;
- }
-
- // https://github.com/gorhill/uBlock/issues/533
- // WebRTC not supported: `webRTCMultipleRoutesEnabled` can NOT be
- // safely accessed. Accessing the property will cause full browser
- // crash.
- if ( this.webRTCSupported !== true ) {
- return;
- }
-
- var cp = chrome.privacy,
- cpn = cp.network;
-
- // Older version of Chromium do not support this setting, and is
- // marked as "deprecated" since Chromium 48.
- if ( typeof cpn.webRTCMultipleRoutesEnabled === 'object' ) {
- try {
- if ( setting ) {
- cpn.webRTCMultipleRoutesEnabled.clear({
- scope: 'regular'
- }, this.noopCallback);
- } else {
- cpn.webRTCMultipleRoutesEnabled.set({
- value: false,
- scope: 'regular'
- }, this.noopCallback);
- }
- } catch(ex) {
- console.error(ex);
- }
- }
-
- // This setting became available in Chromium 48.
- if ( typeof cpn.webRTCIPHandlingPolicy === 'object' ) {
- try {
- if ( setting ) {
- cpn.webRTCIPHandlingPolicy.clear({
- scope: 'regular'
- }, this.noopCallback);
- } else {
- // Respect current stricter setting if any.
- cpn.webRTCIPHandlingPolicy.get({}, function(details) {
- var value = details.value === 'disable_non_proxied_udp' ?
- 'disable_non_proxied_udp' :
- 'default_public_interface_only';
- cpn.webRTCIPHandlingPolicy.set({
- value: value,
- scope: 'regular'
- }, this.noopCallback);
- }.bind(this));
- }
- } catch(ex) {
- console.error(ex);
- }
- }
- },
-
- set: function(details) {
- for ( var setting in details ) {
- if ( details.hasOwnProperty(setting) === false ) {
- continue;
- }
- switch ( setting ) {
- case 'prefetching':
- try {
- if ( !!details[setting] ) {
- chrome.privacy.network.networkPredictionEnabled.clear({
- scope: 'regular'
- }, this.noopCallback);
- } else {
- chrome.privacy.network.networkPredictionEnabled.set({
- value: false,
- scope: 'regular'
- }, this.noopCallback);
- }
- } catch(ex) {
- console.error(ex);
- }
- break;
-
- case 'hyperlinkAuditing':
- try {
- if ( !!details[setting] ) {
- chrome.privacy.websites.hyperlinkAuditingEnabled.clear({
- scope: 'regular'
- }, this.noopCallback);
- } else {
- chrome.privacy.websites.hyperlinkAuditingEnabled.set({
- value: false,
- scope: 'regular'
- }, this.noopCallback);
- }
- } catch(ex) {
- console.error(ex);
- }
- break;
-
- case 'webrtcIPAddress':
- this.setWebrtcIPAddress(!!details[setting]);
- break;
-
- default:
- break;
- }
- }
- }
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.tabs = {};
-
-/******************************************************************************/
-
-vAPI.isBehindTheSceneTabId = function(tabId) {
- return tabId.toString() === '-1';
-};
-
-vAPI.noTabId = '-1';
-
-/******************************************************************************/
-
-var toChromiumTabId = function(tabId) {
- if ( typeof tabId === 'string' ) {
- tabId = parseInt(tabId, 10);
- }
- if ( typeof tabId !== 'number' || isNaN(tabId) || tabId === -1 ) {
- return 0;
- }
- return tabId;
-};
-
-/******************************************************************************/
-
-vAPI.tabs.registerListeners = function() {
- var onNavigationClient = this.onNavigation || noopFunc;
- var onUpdatedClient = this.onUpdated || noopFunc;
-
- // https://developer.chrome.com/extensions/webNavigation
- // [onCreatedNavigationTarget ->]
- // onBeforeNavigate ->
- // onCommitted ->
- // onDOMContentLoaded ->
- // onCompleted
-
- // The chrome.webRequest.onBeforeRequest() won't be called for everything
- // else than `http`/`https`. Thus, in such case, we will bind the tab as
- // early as possible in order to increase the likelihood of a context
- // properly setup if network requests are fired from within the tab.
- // Example: Chromium + case #6 at
- // http://raymondhill.net/ublock/popup.html
- var reGoodForWebRequestAPI = /^https?:\/\//;
-
- // https://forums.lanik.us/viewtopic.php?f=62&t=32826
- // Chromium-based browsers: sanitize target URL. I've seen data: URI with
- // newline characters in standard fields, possibly as a way of evading
- // filters. As per spec, there should be no whitespaces in a data: URI's
- // standard fields.
- var sanitizeURL = function(url) {
- if ( url.startsWith('data:') === false ) { return url; }
- var pos = url.indexOf(',');
- if ( pos === -1 ) { return url; }
- var s = url.slice(0, pos);
- if ( s.search(/\s/) === -1 ) { return url; }
- return s.replace(/\s+/, '') + url.slice(pos);
- };
-
- var onCreatedNavigationTarget = function(details) {
- //console.debug('onCreatedNavigationTarget: popup candidate tab id %d = "%s"', details.tabId, details.url);
- if ( reGoodForWebRequestAPI.test(details.url) === false ) {
- details.frameId = 0;
- details.url = sanitizeURL(details.url);
- onNavigationClient(details);
- }
- if ( typeof vAPI.tabs.onPopupCreated === 'function' ) {
- vAPI.tabs.onPopupCreated(details.tabId.toString(), details.sourceTabId.toString());
- }
- };
-
- var onBeforeNavigate = function(details) {
- if ( details.frameId !== 0 ) {
- return;
- }
- };
-
- var onCommitted = function(details) {
- if ( details.frameId !== 0 ) {
- return;
- }
- details.url = sanitizeURL(details.url);
- onNavigationClient(details);
- };
-
- var onActivated = function(details) {
- vAPI.contextMenu.onMustUpdate(details.tabId);
- };
-
- var onUpdated = function(tabId, changeInfo, tab) {
- if ( changeInfo.url ) {
- changeInfo.url = sanitizeURL(changeInfo.url);
- }
- onUpdatedClient(tabId, changeInfo, tab);
- };
-
- chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigate);
- chrome.webNavigation.onCommitted.addListener(onCommitted);
- chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
- chrome.tabs.onActivated.addListener(onActivated);
- chrome.tabs.onUpdated.addListener(onUpdated);
-
- if ( typeof this.onClosed === 'function' ) {
- chrome.tabs.onRemoved.addListener(this.onClosed);
- }
-
-};
-
-/******************************************************************************/
-
-vAPI.tabs.get = function(tabId, callback) {
- var onTabReady = function(tab) {
- // https://code.google.com/p/chromium/issues/detail?id=410868#c8
- if ( chrome.runtime.lastError ) {
- /* noop */
- }
- // Caller must be prepared to deal with nil tab value
- callback(tab);
- };
-
- if ( tabId !== null ) {
- tabId = toChromiumTabId(tabId);
- if ( tabId === 0 ) {
- onTabReady(null);
- } else {
- chrome.tabs.get(tabId, onTabReady);
- }
- return;
- }
-
- var onTabReceived = function(tabs) {
- // https://code.google.com/p/chromium/issues/detail?id=410868#c8
- void chrome.runtime.lastError;
- callback(tabs[0]);
- };
- chrome.tabs.query({ active: true, currentWindow: true }, onTabReceived);
-};
-
-/******************************************************************************/
-
-// properties of the details object:
-// url: 'URL', // the address that will be opened
-// tabId: 1, // the tab is used if set, instead of creating a new one
-// index: -1, // undefined: end of the list, -1: following tab, or after index
-// active: false, // opens the tab in background - true and undefined: foreground
-// select: true, // if a tab is already opened with that url, then select it instead of opening a new one
-// popup: true // open in a new window
-
-vAPI.tabs.open = function(details) {
- var targetURL = details.url;
- if ( typeof targetURL !== 'string' || targetURL === '' ) {
- return null;
- }
-
- // extension pages
- if ( /^[\w-]{2,}:/.test(targetURL) !== true ) {
- targetURL = vAPI.getURL(targetURL);
- }
-
- // dealing with Chrome's asynchronous API
- var wrapper = function() {
- if ( details.active === undefined ) {
- details.active = true;
- }
-
- var subWrapper = function() {
- var _details = {
- url: targetURL,
- active: !!details.active
- };
-
- // Opening a tab from incognito window won't focus the window
- // in which the tab was opened
- var focusWindow = function(tab) {
- if ( tab.active ) {
- chrome.windows.update(tab.windowId, { focused: true });
- }
- };
-
- if ( !details.tabId ) {
- if ( details.index !== undefined ) {
- _details.index = details.index;
- }
-
- chrome.tabs.create(_details, focusWindow);
- return;
- }
-
- // update doesn't accept index, must use move
- chrome.tabs.update(toChromiumTabId(details.tabId), _details, function(tab) {
- // if the tab doesn't exist
- if ( vAPI.lastError() ) {
- chrome.tabs.create(_details, focusWindow);
- } else if ( details.index !== undefined ) {
- chrome.tabs.move(tab.id, {index: details.index});
- }
- });
- };
-
- // Open in a standalone window
- if ( details.popup === true ) {
- chrome.windows.create({
- url: details.url,
- focused: details.active,
- type: 'popup'
- });
- return;
- }
-
- if ( details.index !== -1 ) {
- subWrapper();
- return;
- }
-
- vAPI.tabs.get(null, function(tab) {
- if ( tab ) {
- details.index = tab.index + 1;
- } else {
- delete details.index;
- }
-
- subWrapper();
- });
- };
-
- if ( !details.select ) {
- wrapper();
- return;
- }
-
- // https://developer.chrome.com/extensions/tabs#method-query
- // "Note that fragment identifiers are not matched."
- // It's a lie, fragment identifiers ARE matched. So we need to remove the
- // fragment.
- var pos = targetURL.indexOf('#');
- var targetURLWithoutHash = pos === -1 ? targetURL : targetURL.slice(0, pos);
-
- chrome.tabs.query({ url: targetURLWithoutHash }, function(tabs) {
- var tab = tabs[0];
- if ( !tab ) {
- wrapper();
- return;
- }
-
- var _details = {
- active: true,
- url: undefined
- };
- if ( targetURL !== tab.url ) {
- _details.url = targetURL;
- }
- chrome.tabs.update(tab.id, _details, function(tab) {
- chrome.windows.update(tab.windowId, { focused: true });
- });
- });
-};
-
-/******************************************************************************/
-
-// Replace the URL of a tab. Noop if the tab does not exist.
-
-vAPI.tabs.replace = function(tabId, url) {
- tabId = toChromiumTabId(tabId);
- if ( tabId === 0 ) {
- return;
- }
-
- var targetURL = url;
-
- // extension pages
- if ( /^[\w-]{2,}:/.test(targetURL) !== true ) {
- targetURL = vAPI.getURL(targetURL);
- }
-
- chrome.tabs.update(tabId, { url: targetURL }, function() {
- // https://code.google.com/p/chromium/issues/detail?id=410868#c8
- if ( chrome.runtime.lastError ) {
- /* noop */
- }
- });
-};
-
-/******************************************************************************/
-
-vAPI.tabs.remove = function(tabId) {
- tabId = toChromiumTabId(tabId);
- if ( tabId === 0 ) {
- return;
- }
-
- var onTabRemoved = function() {
- // https://code.google.com/p/chromium/issues/detail?id=410868#c8
- if ( chrome.runtime.lastError ) {
- /* noop */
- }
- };
-
- chrome.tabs.remove(tabId, onTabRemoved);
-};
-
-/******************************************************************************/
-
-vAPI.tabs.reload = function(tabId /*, flags*/) {
- tabId = toChromiumTabId(tabId);
- if ( tabId === 0 ) {
- return;
- }
-
- var onReloaded = function() {
- // https://code.google.com/p/chromium/issues/detail?id=410868#c8
- if ( chrome.runtime.lastError ) {
- /* noop */
- }
- };
-
- chrome.tabs.reload(tabId, onReloaded);
-};
-
-/******************************************************************************/
-
-// Select a specific tab.
-
-vAPI.tabs.select = function(tabId) {
- tabId = toChromiumTabId(tabId);
- if ( tabId === 0 ) {
- return;
- }
-
- chrome.tabs.update(tabId, { active: true }, function(tab) {
- if ( chrome.runtime.lastError ) {
- /* noop */
- }
- if ( !tab ) {
- return;
- }
- chrome.windows.update(tab.windowId, { focused: true });
- });
-};
-
-/******************************************************************************/
-
-vAPI.tabs.injectScript = function(tabId, details, callback) {
- var onScriptExecuted = function() {
- // https://code.google.com/p/chromium/issues/detail?id=410868#c8
- if ( chrome.runtime.lastError ) {
- /* noop */
- }
- if ( typeof callback === 'function' ) {
- callback();
- }
- };
- if ( tabId ) {
- chrome.tabs.executeScript(toChromiumTabId(tabId), details, onScriptExecuted);
- } else {
- chrome.tabs.executeScript(details, onScriptExecuted);
- }
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-// Must read: https://code.google.com/p/chromium/issues/detail?id=410868#c8
-
-// https://github.com/chrisaljoudi/uBlock/issues/19
-// https://github.com/chrisaljoudi/uBlock/issues/207
-// Since we may be called asynchronously, the tab id may not exist
-// anymore, so this ensures it does still exist.
-
-vAPI.setIcon = function(tabId, iconStatus, badge) {
- tabId = toChromiumTabId(tabId);
- if ( tabId === 0 ) {
- return;
- }
-
- var onIconReady = function() {
- if ( vAPI.lastError() ) {
- return;
- }
- chrome.browserAction.setBadgeText({ tabId: tabId, text: badge });
- if ( badge !== '' ) {
- chrome.browserAction.setBadgeBackgroundColor({
- tabId: tabId,
- color: '#666'
- });
- }
- };
-
- var iconPaths = iconStatus === 'on' ?
- { '19': 'img/browsericons/icon19.png', '38': 'img/browsericons/icon38.png' } :
- { '19': 'img/browsericons/icon19-off.png', '38': 'img/browsericons/icon38-off.png' };
-
- chrome.browserAction.setIcon({ tabId: tabId, path: iconPaths }, onIconReady);
- vAPI.contextMenu.onMustUpdate(tabId);
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.messaging = {
- ports: {},
- listeners: {},
- defaultHandler: null,
- NOOPFUNC: noopFunc,
- UNHANDLED: 'vAPI.messaging.notHandled'
-};
-
-/******************************************************************************/
-
-vAPI.messaging.listen = function(listenerName, callback) {
- this.listeners[listenerName] = callback;
-};
-
-/******************************************************************************/
-
-vAPI.messaging.onPortMessage = (function() {
- var messaging = vAPI.messaging;
- var toAuxPending = {};
-
- // Use a wrapper to avoid closure and to allow reuse.
- var CallbackWrapper = function(port, request, timeout) {
- this.callback = this.proxy.bind(this); // bind once
- this.init(port, request, timeout);
- };
-
- CallbackWrapper.prototype.init = function(port, request, timeout) {
- this.port = port;
- this.request = request;
- this.timerId = timeout !== undefined ?
- vAPI.setTimeout(this.callback, timeout) :
- null;
- return this;
- };
-
- CallbackWrapper.prototype.proxy = function(response) {
- if ( this.timerId !== null ) {
- clearTimeout(this.timerId);
- delete toAuxPending[this.timerId];
- this.timerId = null;
- }
- // https://github.com/chrisaljoudi/uBlock/issues/383
- if ( messaging.ports.hasOwnProperty(this.port.name) ) {
- this.port.postMessage({
- auxProcessId: this.request.auxProcessId,
- channelName: this.request.channelName,
- msg: response !== undefined ? response : null
- });
- }
- // Mark for reuse
- this.port = this.request = null;
- callbackWrapperJunkyard.push(this);
- };
-
- var callbackWrapperJunkyard = [];
-
- var callbackWrapperFactory = function(port, request, timeout) {
- var wrapper = callbackWrapperJunkyard.pop();
- if ( wrapper ) {
- return wrapper.init(port, request, timeout);
- }
- return new CallbackWrapper(port, request, timeout);
- };
-
- var toAux = function(details, portFrom) {
- var port, portTo;
- var chromiumTabId = toChromiumTabId(details.toTabId);
-
- // TODO: This could be an issue with a lot of tabs: easy to address
- // with a port name to tab id map.
- for ( var portName in messaging.ports ) {
- if ( messaging.ports.hasOwnProperty(portName) === false ) {
- continue;
- }
- // When sending to an auxiliary process, the target is always the
- // port associated with the root frame.
- port = messaging.ports[portName];
- if ( port.sender.frameId === 0 && port.sender.tab.id === chromiumTabId ) {
- portTo = port;
- break;
- }
- }
-
- var wrapper;
- if ( details.auxProcessId !== undefined ) {
- wrapper = callbackWrapperFactory(portFrom, details, 1023);
- }
-
- // Destination not found:
- if ( portTo === undefined ) {
- if ( wrapper !== undefined ) {
- wrapper.callback();
- }
- return;
- }
-
- // As per HTML5, timer id is always an integer, thus suitable to be
- // used as a key, and which value is safe to use across process
- // boundaries.
- if ( wrapper !== undefined ) {
- toAuxPending[wrapper.timerId] = wrapper;
- }
-
- portTo.postMessage({
- mainProcessId: wrapper && wrapper.timerId,
- channelName: details.toChannel,
- msg: details.msg
- });
- };
-
- var toAuxResponse = function(details) {
- var mainProcessId = details.mainProcessId;
- if ( mainProcessId === undefined ) {
- return;
- }
- if ( toAuxPending.hasOwnProperty(mainProcessId) === false ) {
- return;
- }
- var wrapper = toAuxPending[mainProcessId];
- delete toAuxPending[mainProcessId];
- wrapper.callback(details.msg);
- };
-
- return function(request, port) {
- // Auxiliary process to auxiliary process
- if ( request.toTabId !== undefined ) {
- toAux(request, port);
- return;
- }
-
- // Auxiliary process to auxiliary process: response
- if ( request.mainProcessId !== undefined ) {
- toAuxResponse(request);
- return;
- }
-
- // Auxiliary process to main process: prepare response
- var callback = messaging.NOOPFUNC;
- if ( request.auxProcessId !== undefined ) {
- callback = callbackWrapperFactory(port, request).callback;
- }
-
- // Auxiliary process to main process: specific handler
- var r = messaging.UNHANDLED;
- var listener = messaging.listeners[request.channelName];
- if ( typeof listener === 'function' ) {
- r = listener(request.msg, port.sender, callback);
- }
- if ( r !== messaging.UNHANDLED ) {
- return;
- }
-
- // Auxiliary process to main process: default handler
- r = messaging.defaultHandler(request.msg, port.sender, callback);
- if ( r !== messaging.UNHANDLED ) {
- return;
- }
-
- // Auxiliary process to main process: no handler
- console.error('uBlock> messaging > unknown request: %o', request);
-
- // Need to callback anyways in case caller expected an answer, or
- // else there is a memory leak on caller's side
- callback();
- };
-})();
-
-/******************************************************************************/
-
-vAPI.messaging.onPortDisconnect = function(port) {
- port.onDisconnect.removeListener(vAPI.messaging.onPortDisconnect);
- port.onMessage.removeListener(vAPI.messaging.onPortMessage);
- delete vAPI.messaging.ports[port.name];
-};
-
-/******************************************************************************/
-
-vAPI.messaging.onPortConnect = function(port) {
- port.onDisconnect.addListener(vAPI.messaging.onPortDisconnect);
- port.onMessage.addListener(vAPI.messaging.onPortMessage);
- vAPI.messaging.ports[port.name] = port;
-};
-
-/******************************************************************************/
-
-vAPI.messaging.setup = function(defaultHandler) {
- // Already setup?
- if ( this.defaultHandler !== null ) {
- return;
- }
-
- if ( typeof defaultHandler !== 'function' ) {
- defaultHandler = function(){ return vAPI.messaging.UNHANDLED; };
- }
- this.defaultHandler = defaultHandler;
-
- chrome.runtime.onConnect.addListener(this.onPortConnect);
-};
-
-/******************************************************************************/
-
-vAPI.messaging.broadcast = function(message) {
- var messageWrapper = {
- broadcast: true,
- msg: message
- };
-
- for ( var portName in this.ports ) {
- if ( this.ports.hasOwnProperty(portName) === false ) {
- continue;
- }
- this.ports[portName].postMessage(messageWrapper);
- }
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.net = {};
-
-/******************************************************************************/
-
-vAPI.net.registerListeners = function() {
- var µb = µBlock;
- var µburi = µb.URI;
-
- // https://bugs.chromium.org/p/chromium/issues/detail?id=410382
- // Between Chromium 38-48, plug-ins' network requests were reported as
- // type "other" instead of "object".
- var is_v38_48 = /\bChrom[a-z]+\/(?:3[89]|4[0-8])\.[\d.]+\b/.test(navigator.userAgent),
- is_v49_55 = /\bChrom[a-z]+\/(?:49|5[012345])\b/.test(navigator.userAgent);
-
- // Chromium-based browsers understand only these network request types.
- var validTypes = {
- 'main_frame': true,
- 'sub_frame': true,
- 'stylesheet': true,
- 'script': true,
- 'image': true,
- 'object': true,
- 'xmlhttprequest': true,
- 'other': true
- };
-
- var denormalizeTypes = function(aa) {
- if ( aa.length === 0 ) {
- return Object.keys(validTypes);
- }
- var out = [];
- var i = aa.length,
- type,
- needOther = true;
- while ( i-- ) {
- type = aa[i];
- if ( validTypes.hasOwnProperty(type) ) {
- out.push(type);
- }
- if ( type === 'other' ) {
- needOther = false;
- }
- }
- if ( needOther ) {
- out.push('other');
- }
- return out;
- };
-
- var headerValue = function(headers, name) {
- var i = headers.length;
- while ( i-- ) {
- if ( headers[i].name.toLowerCase() === name ) {
- return headers[i].value.trim();
- }
- }
- return '';
- };
-
- var normalizeRequestDetails = function(details) {
- details.tabId = details.tabId.toString();
-
- // https://github.com/gorhill/uBlock/issues/1493
- // Chromium 49+ support a new request type: `ping`, which is fired as
- // a result of using `navigator.sendBeacon`.
- if ( details.type === 'ping' ) {
- details.type = 'beacon';
- return;
- }
-
- // The rest of the function code is to normalize type
- if ( details.type !== 'other' ) {
- return;
- }
-
- var path = µburi.pathFromURI(details.url);
- var pos = path.indexOf('.', path.length - 6);
-
- // https://github.com/chrisaljoudi/uBlock/issues/862
- // If no transposition possible, transpose to `object` as per
- // Chromium bug 410382 (see below)
- if ( pos !== -1 ) {
- var needle = path.slice(pos) + '.';
- if ( '.eot.ttf.otf.svg.woff.woff2.'.indexOf(needle) !== -1 ) {
- details.type = 'font';
- return;
- }
-
- if ( '.mp3.mp4.webm.'.indexOf(needle) !== -1 ) {
- details.type = 'media';
- return;
- }
-
- // Still need this because often behind-the-scene requests are wrongly
- // categorized as 'other'
- if ( '.ico.png.gif.jpg.jpeg.webp.'.indexOf(needle) !== -1 ) {
- details.type = 'image';
- return;
- }
- }
-
- // Try to extract type from response headers if present.
- if ( details.responseHeaders ) {
- var contentType = headerValue(details.responseHeaders, 'content-type');
- if ( contentType.startsWith('font/') ) {
- details.type = 'font';
- return;
- }
- if ( contentType.startsWith('image/') ) {
- details.type = 'image';
- return;
- }
- if ( contentType.startsWith('audio/') || contentType.startsWith('video/') ) {
- details.type = 'media';
- return;
- }
- }
-
- // https://code.google.com/p/chromium/issues/detail?id=410382
- if ( is_v38_48 ) {
- details.type = 'object';
- }
- };
-
- // https://bugs.chromium.org/p/chromium/issues/detail?id=129353
- // https://github.com/gorhill/uBlock/issues/1497
- // Expose websocket-based network requests to uBO's filtering engine,
- // logger, etc.
- // Counterpart of following block of code is found in "vapi-client.js" --
- // search for "https://github.com/gorhill/uBlock/issues/1497".
- var onBeforeWebsocketRequest = function(details) {
- details.type = 'websocket';
- var matches = /url=([^&]+)/.exec(details.url);
- details.url = decodeURIComponent(matches[1]);
- var r = onBeforeRequestClient(details);
- // Blocked?
- if ( r && r.cancel ) {
- return r;
- }
- // Returning a 1x1 transparent pixel means "not blocked".
- return { redirectUrl: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' };
- };
-
- 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);
- }
-
- normalizeRequestDetails(details);
- return onBeforeRequestClient(details);
- };
-
- // This is needed for Chromium 49-55.
- var onBeforeSendHeaders = function(details) {
- if ( details.type !== 'ping' || details.method !== 'POST' ) { return; }
- var type = headerValue(details.requestHeaders, 'content-type');
- if ( type === '' ) { return; }
- if ( type.endsWith('/csp-report') ) {
- details.type = 'csp_report';
- return onBeforeRequestClient(details);
- }
- };
-
- var onHeadersReceivedClient = this.onHeadersReceived.callback,
- onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
- onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
- var onHeadersReceived = function(details) {
- normalizeRequestDetails(details);
- // Hack to work around Chromium API limitations, where requests of
- // type `font` are returned as `other`. For example, our normalization
- // fail at transposing `other` into `font` for URLs which are outside
- // what is expected. At least when headers are received we can check
- // for content type `font/*`. Blocking at onHeadersReceived time is
- // less worse than not blocking at all. Also, due to Chromium bug,
- // `other` always becomes `object` when it can't be normalized into
- // something else. Test case for "unfriendly" font URLs:
- // https://www.google.com/fonts
- if ( details.type === 'font' ) {
- var r = onBeforeRequestClient(details);
- if ( typeof r === 'object' && r.cancel === true ) {
- return { cancel: true };
- }
- }
- if (
- onHeadersReceivedClientTypes.length !== 0 &&
- onHeadersReceivedClientTypes.indexOf(details.type) === -1
- ) {
- return;
- }
- return onHeadersReceivedClient(details);
- };
-
- var installListeners = (function() {
- var crapi = chrome.webRequest;
-
- //listener = function(details) {
- // quickProfiler.start('onBeforeRequest');
- // var r = onBeforeRequest(details);
- // quickProfiler.stop();
- // return r;
- //};
- if ( crapi.onBeforeRequest.hasListener(onBeforeRequest) === false ) {
- crapi.onBeforeRequest.addListener(
- onBeforeRequest,
- {
- 'urls': this.onBeforeRequest.urls || [''],
- 'types': this.onBeforeRequest.types || undefined
- },
- this.onBeforeRequest.extra
- );
- }
-
- // Chromium 48 and lower does not support `ping` type.
- // Chromium 56 and higher does support `csp_report` stype.
- if ( is_v49_55 && crapi.onBeforeSendHeaders.hasListener(onBeforeSendHeaders) === false ) {
- crapi.onBeforeSendHeaders.addListener(
- onBeforeSendHeaders,
- {
- 'urls': [ '' ],
- 'types': [ 'ping' ]
- },
- [ 'blocking', 'requestHeaders' ]
- );
- }
-
- if ( crapi.onHeadersReceived.hasListener(onHeadersReceived) === false ) {
- crapi.onHeadersReceived.addListener(
- onHeadersReceived,
- {
- 'urls': this.onHeadersReceived.urls || [''],
- 'types': onHeadersReceivedTypes
- },
- 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);
-
- installListeners();
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.contextMenu = {
- _callback: null,
- _entries: [],
- _createEntry: function(entry) {
- chrome.contextMenus.create(JSON.parse(JSON.stringify(entry)), function() {
- void chrome.runtime.lastError;
- });
- },
- onMustUpdate: function() {},
- setEntries: function(entries, callback) {
- entries = entries || [];
- var n = Math.max(this._entries.length, entries.length),
- oldEntryId, newEntry;
- for ( var i = 0; i < n; i++ ) {
- oldEntryId = this._entries[i];
- newEntry = entries[i];
- if ( oldEntryId && newEntry ) {
- if ( newEntry.id !== oldEntryId ) {
- chrome.contextMenus.remove(oldEntryId);
- this._createEntry(newEntry);
- this._entries[i] = newEntry.id;
- }
- } else if ( oldEntryId && !newEntry ) {
- chrome.contextMenus.remove(oldEntryId);
- } else if ( !oldEntryId && newEntry ) {
- this._createEntry(newEntry);
- this._entries[i] = newEntry.id;
- }
- }
- n = this._entries.length = entries.length;
- callback = callback || null;
- if ( callback === this._callback ) {
- return;
- }
- if ( n !== 0 && callback !== null ) {
- chrome.contextMenus.onClicked.addListener(callback);
- this._callback = callback;
- } else if ( n === 0 && this._callback !== null ) {
- chrome.contextMenus.onClicked.removeListener(this._callback);
- this._callback = null;
- }
- }
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.lastError = function() {
- return chrome.runtime.lastError;
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-// This is called only once, when everything has been loaded in memory after
-// the extension was launched. It can be used to inject content scripts
-// in already opened web pages, to remove whatever nuisance could make it to
-// the web pages before uBlock was ready.
-
-vAPI.onLoadAllCompleted = function() {
- // http://code.google.com/p/chromium/issues/detail?id=410868#c11
- // Need to be sure to access `vAPI.lastError()` to prevent
- // spurious warnings in the console.
- var scriptDone = function() {
- vAPI.lastError();
- };
- var scriptStart = function(tabId) {
- vAPI.tabs.injectScript(tabId, {
- file: 'js/vapi-client.js',
- allFrames: true,
- runAt: 'document_idle'
- }, function(){ });
- vAPI.tabs.injectScript(tabId, {
- file: 'js/contentscript.js',
- allFrames: true,
- runAt: 'document_idle'
- }, scriptDone);
- };
- var bindToTabs = function(tabs) {
- var µb = µBlock;
- var i = tabs.length, tab;
- while ( i-- ) {
- tab = tabs[i];
- µb.tabContextManager.commit(tab.id, tab.url);
- µb.bindTabToPageStats(tab.id);
- // https://github.com/chrisaljoudi/uBlock/issues/129
- scriptStart(tab.id);
- }
- };
-
- chrome.tabs.query({ url: '' }, bindToTabs);
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.punycodeHostname = function(hostname) {
- return hostname;
-};
-
-vAPI.punycodeURL = function(url) {
- return url;
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-// https://github.com/gorhill/uBlock/issues/531
-// Storage area dedicated to admin settings. Read-only.
-
-// https://github.com/gorhill/uBlock/commit/43a5ed735b95a575a9339b6e71a1fcb27a99663b#commitcomment-13965030
-// Not all Chromium-based browsers support managed storage. Merely testing or
-// exception handling in this case does NOT work: I don't know why. The
-// extension on Opera ends up in a non-sensical state, whereas vAPI become
-// undefined out of nowhere. So only solution left is to test explicitly for
-// Opera.
-// https://github.com/gorhill/uBlock/issues/900
-// Also, UC Browser: http://www.upsieutoc.com/image/WXuH
-
-vAPI.adminStorage = {
- getItem: function(key, callback) {
- var onRead = function(store) {
- var data;
- if (
- !chrome.runtime.lastError &&
- typeof store === 'object' &&
- store !== null
- ) {
- data = store[key];
- }
- callback(data);
- };
- try {
- chrome.storage.managed.get(key, onRead);
- } catch (ex) {
- callback();
- }
- }
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.cloud = (function() {
- var chunkCountPerFetch = 16; // Must be a power of 2
-
- // Mind chrome.storage.sync.MAX_ITEMS (512 at time of writing)
- 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);
-
- // Mind chrome.storage.sync.QUOTA_BYTES (128 kB at time of writing)
- var maxStorageSize = chrome.storage.sync.QUOTA_BYTES;
-
- var options = {
- defaultDeviceName: window.navigator.platform,
- deviceName: window.localStorage.getItem('deviceName') || ''
- };
-
- // This is used to find out a rough count of how many chunks exists:
- // We "poll" at specific index in order to get a rough idea of how
- // large is the stored string.
- // This allows reading a single item with only 2 sync operations -- a
- // good thing given chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_MINUTE
- // and chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_HOUR.
-
- var getCoarseChunkCount = function(dataKey, callback) {
- var bin = {};
- for ( var i = 0; i < maxChunkCountPerItem; i += 16 ) {
- bin[dataKey + i.toString()] = '';
- }
-
- chrome.storage.sync.get(bin, function(bin) {
- if ( chrome.runtime.lastError ) {
- callback(0, chrome.runtime.lastError.message);
- return;
- }
-
- var chunkCount = 0;
- for ( var i = 0; i < maxChunkCountPerItem; i += 16 ) {
- if ( bin[dataKey + i.toString()] === '' ) {
- break;
- }
- chunkCount = i + 16;
- }
-
- callback(chunkCount);
- });
- };
-
- var deleteChunks = function(dataKey, start) {
- var keys = [];
-
- // No point in deleting more than:
- // - The max number of chunks per item
- // - The max number of chunks per storage limit
- var n = Math.min(
- maxChunkCountPerItem,
- Math.ceil(maxStorageSize / maxChunkSize)
- );
- for ( var i = start; i < n; i++ ) {
- keys.push(dataKey + i.toString());
- }
- chrome.storage.sync.remove(keys);
- };
-
- var start = function(/* dataKeys */) {
- };
-
- var push = function(dataKey, data, callback) {
- var bin = {
- 'source': options.deviceName || options.defaultDeviceName,
- 'tstamp': Date.now(),
- 'data': data,
- 'size': 0
- };
- bin.size = JSON.stringify(bin).length;
- var item = JSON.stringify(bin);
-
- // Chunkify taking into account QUOTA_BYTES_PER_ITEM:
- // https://developer.chrome.com/extensions/storage#property-sync
- // "The maximum size (in bytes) of each individual item in sync
- // "storage, as measured by the JSON stringification of its value
- // "plus its key length."
- bin = {};
- var chunkCount = Math.ceil(item.length / maxChunkSize);
- for ( var i = 0; i < chunkCount; i++ ) {
- bin[dataKey + i.toString()] = item.substr(i * maxChunkSize, maxChunkSize);
- }
- bin[dataKey + i.toString()] = ''; // Sentinel
-
- chrome.storage.sync.set(bin, function() {
- var errorStr;
- if ( chrome.runtime.lastError ) {
- errorStr = chrome.runtime.lastError.message;
- }
- callback(errorStr);
-
- // Remove potentially unused trailing chunks
- deleteChunks(dataKey, chunkCount);
- });
- };
-
- var pull = function(dataKey, callback) {
- var assembleChunks = function(bin) {
- if ( chrome.runtime.lastError ) {
- callback(null, chrome.runtime.lastError.message);
- return;
- }
-
- // Assemble chunks into a single string.
- var json = [], jsonSlice;
- var i = 0;
- for (;;) {
- jsonSlice = bin[dataKey + i.toString()];
- if ( jsonSlice === '' ) {
- break;
- }
- json.push(jsonSlice);
- i += 1;
- }
-
- var entry = null;
- try {
- entry = JSON.parse(json.join(''));
- } catch(ex) {
- }
- callback(entry);
- };
-
- var fetchChunks = function(coarseCount, errorStr) {
- if ( coarseCount === 0 || typeof errorStr === 'string' ) {
- callback(null, errorStr);
- return;
- }
-
- var bin = {};
- for ( var i = 0; i < coarseCount; i++ ) {
- bin[dataKey + i.toString()] = '';
- }
-
- chrome.storage.sync.get(bin, assembleChunks);
- };
-
- getCoarseChunkCount(dataKey, fetchChunks);
- };
-
- var getOptions = function(callback) {
- if ( typeof callback !== 'function' ) {
- return;
- }
- callback(options);
- };
-
- var setOptions = function(details, callback) {
- if ( typeof details !== 'object' || details === null ) {
- return;
- }
-
- if ( typeof details.deviceName === 'string' ) {
- window.localStorage.setItem('deviceName', details.deviceName);
- options.deviceName = details.deviceName;
- }
-
- getOptions(callback);
- };
-
- return {
- start: start,
- push: push,
- pull: pull,
- getOptions: getOptions,
- setOptions: setOptions
- };
-})();
-
-/******************************************************************************/
-/******************************************************************************/
-
-})();
-
-/******************************************************************************/
diff --git a/platform/webext/vapi-client.js b/platform/webext/vapi-client.js
deleted file mode 100644
index 0dd976fff..000000000
--- a/platform/webext/vapi-client.js
+++ /dev/null
@@ -1,525 +0,0 @@
-/*******************************************************************************
-
- uBlock Origin - a browser extension to block requests.
- Copyright (C) 2014-2016 The uBlock Origin authors
-
- 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
-*/
-
-/* global HTMLDocument, XMLDocument */
-
-'use strict';
-
-// For non background pages
-
-/******************************************************************************/
-
-(function(self) {
-
-/******************************************************************************/
-/******************************************************************************/
-
-// https://github.com/chrisaljoudi/uBlock/issues/464
-if ( document instanceof HTMLDocument === false ) {
- // https://github.com/chrisaljoudi/uBlock/issues/1528
- // A XMLDocument can be a valid HTML document.
- if (
- document instanceof XMLDocument === false ||
- document.createElement('div') instanceof HTMLDivElement === false
- ) {
- return;
- }
-}
-
-// https://github.com/gorhill/uBlock/issues/1124
-// Looks like `contentType` is on track to be standardized:
-// https://dom.spec.whatwg.org/#concept-document-content-type
-// https://forums.lanik.us/viewtopic.php?f=64&t=31522
-// Skip text/plain documents.
-var contentType = document.contentType || '';
-if ( /^image\/|^text\/plain/.test(contentType) ) {
- return;
-}
-
-/******************************************************************************/
-
-var vAPI = self.vAPI = self.vAPI || {};
-var chrome = self.chrome;
-
-// https://github.com/chrisaljoudi/uBlock/issues/456
-// Already injected?
-if ( vAPI.sessionId ) {
- return;
-}
-
-/******************************************************************************/
-
-// Support minimally working Set() for legacy Chromium.
-
-if ( self.Set instanceof Function ) {
- self.createSet = function() {
- return new Set();
- };
-} else {
- self.createSet = (function() {
- //console.log('Polyfilling for ES6-like Set().');
- var PrimitiveSet = function() {
- this.clear();
- };
- PrimitiveSet.prototype = {
- add: function(k) {
- if ( this._set[k] === undefined ) {
- this._set[k] = true;
- this.size += 1;
- }
- return this;
- },
- clear: function() {
- this._set = Object.create(null);
- this.size = 0;
- this._values = undefined;
- this._i = undefined;
- this.value = undefined;
- this.done = true;
- },
- delete: function(k) {
- if ( this._set[k] === undefined ) { return false; }
- delete this._set[k];
- this.size -= 1;
- return true;
- },
- has: function(k) {
- return this._set[k] !== undefined;
- },
- next: function() {
- if ( this._i < this.size ) {
- this.value = this._values[this._i++];
- } else {
- this._values = undefined;
- this.value = undefined;
- this.done = true;
- }
- return this;
- },
- polyfill: true,
- values: function() {
- this._values = Object.keys(this._set);
- this._i = 0;
- this.value = undefined;
- this.done = false;
- return this;
- }
- };
- var ReferenceSet = function() {
- this.clear();
- };
- ReferenceSet.prototype = {
- add: function(k) {
- if ( this._set.indexOf(k) === -1 ) {
- this._set.push(k);
- }
- },
- clear: function() {
- this._set = [];
- this._i = 0;
- this.value = undefined;
- this.done = true;
- },
- delete: function(k) {
- var pos = this._set.indexOf(k);
- if ( pos === -1 ) { return false; }
- this._set.splice(pos, 1);
- return true;
- },
- has: function(k) {
- return this._set.indexOf(k) !== -1;
- },
- next: function() {
- if ( this._i === this._set.length ) {
- this.value = undefined;
- this.done = true;
- } else {
- this.value = this._set[this._i];
- this._i += 1;
- }
- return this;
- },
- polyfill: true,
- values: function() {
- this._i = 0;
- this.done = false;
- return this;
- }
- };
- Object.defineProperty(ReferenceSet.prototype, 'size', {
- get: function() { return this._set.length; }
- });
- return function(type) {
- return type === 'object' ? new ReferenceSet() : new PrimitiveSet();
- };
- })();
-}
-
-/******************************************************************************/
-
-var referenceCounter = 0;
-
-vAPI.lock = function() {
- referenceCounter += 1;
-};
-
-vAPI.unlock = function() {
- referenceCounter -= 1;
- if ( referenceCounter === 0 ) {
- // Eventually there will be code here to flush the javascript code
- // from this file out of memory when it ends up unused.
-
- }
-};
-
-/******************************************************************************/
-
-vAPI.executionCost = {
- start: function(){},
- stop: function(){}
-};
-/*
-vAPI.executionCost = {
- tcost: 0,
- tstart: 0,
- nstart: 0,
- level: 1,
- start: function() {
- if ( this.nstart === 0 ) {
- this.tstart = window.performance.now();
- }
- this.nstart += 1;
- },
- stop: function(mark) {
- this.nstart -= 1;
- if ( this.nstart !== 0 ) {
- return;
- }
- var tcost = window.performance.now() - this.tstart;
- this.tcost += tcost;
- if ( mark === undefined ) {
- return;
- }
- var top = window === window.top;
- if ( !top && this.level < 2 ) {
- return;
- }
- var context = window === window.top ? ' top' : 'frame';
- var percent = this.tcost / window.performance.now() * 100;
- console.log(
- 'uBO cost (%s): %sms/%s%% (%s: %sms)',
- context,
- this.tcost.toFixed(1),
- percent.toFixed(1),
- mark,
- tcost.toFixed(2)
- );
- }
-};
-*/
-vAPI.executionCost.start();
-
-/******************************************************************************/
-
-vAPI.randomToken = function() {
- return String.fromCharCode(Date.now() % 26 + 97) +
- Math.floor(Math.random() * 982451653 + 982451653).toString(36);
-};
-
-vAPI.sessionId = vAPI.randomToken();
-vAPI.chrome = true;
-vAPI.setTimeout = vAPI.setTimeout || self.setTimeout.bind(self);
-
-/******************************************************************************/
-
-vAPI.shutdown = {
- jobs: [],
- add: function(job) {
- this.jobs.push(job);
- },
- exec: function() {
- var job;
- while ( (job = this.jobs.pop()) ) {
- job();
- }
- },
- remove: function(job) {
- var pos;
- while ( (pos = this.jobs.indexOf(job)) !== -1 ) {
- this.jobs.splice(pos, 1);
- }
- }
-};
-
-/******************************************************************************/
-/******************************************************************************/
-
-vAPI.messaging = {
- port: null,
- portTimer: null,
- portTimerDelay: 10000,
- channels: Object.create(null),
- channelCount: 0,
- pending: Object.create(null),
- pendingCount: 0,
- auxProcessId: 1,
- shuttingDown: false,
-
- shutdown: function() {
- this.shuttingDown = true;
- this.destroyPort();
- },
-
- disconnectListener: function() {
- this.port = null;
- vAPI.shutdown.exec();
- },
- disconnectListenerCallback: null,
-
- messageListener: function(details) {
- if ( !details ) {
- return;
- }
-
- // Sent to all channels
- if ( details.broadcast === true && !details.channelName ) {
- for ( var channelName in this.channels ) {
- this.sendToChannelListeners(channelName, details.msg);
- }
- return;
- }
-
- // Response to specific message previously sent
- if ( details.auxProcessId ) {
- var listener = this.pending[details.auxProcessId];
- delete this.pending[details.auxProcessId];
- delete details.auxProcessId; // TODO: why?
- if ( listener ) {
- this.pendingCount -= 1;
- listener(details.msg);
- return;
- }
- }
-
- // Sent to a specific channel
- var response = this.sendToChannelListeners(details.channelName, details.msg);
-
- // Respond back if required
- if ( details.mainProcessId === undefined ) {
- return;
- }
- var port = this.connect();
- if ( port !== null ) {
- port.postMessage({
- mainProcessId: details.mainProcessId,
- msg: response
- });
- }
- },
- messageListenerCallback: null,
-
- portPoller: function() {
- this.portTimer = null;
- if ( this.port !== null ) {
- if ( this.channelCount !== 0 || this.pendingCount !== 0 ) {
- this.portTimer = vAPI.setTimeout(this.portPollerCallback, this.portTimerDelay);
- this.portTimerDelay = Math.min(this.portTimerDelay * 2, 60 * 60 * 1000);
- return;
- }
- }
- this.destroyPort();
- },
- portPollerCallback: null,
-
- destroyPort: function() {
- if ( this.portTimer !== null ) {
- clearTimeout(this.portTimer);
- this.portTimer = null;
- }
- var port = this.port;
- if ( port !== null ) {
- port.disconnect();
- port.onMessage.removeListener(this.messageListenerCallback);
- port.onDisconnect.removeListener(this.disconnectListenerCallback);
- this.port = null;
- }
- if ( this.channelCount !== 0 ) {
- this.channels = Object.create(null);
- this.channelCount = 0;
- }
- // service pending callbacks
- if ( this.pendingCount !== 0 ) {
- var pending = this.pending, callback;
- this.pending = Object.create(null);
- this.pendingCount = 0;
- for ( var auxId in pending ) {
- callback = pending[auxId];
- if ( typeof callback === 'function' ) {
- callback(null);
- }
- }
- }
- },
-
- createPort: function() {
- if ( this.shuttingDown ) {
- return null;
- }
- if ( this.messageListenerCallback === null ) {
- this.messageListenerCallback = this.messageListener.bind(this);
- this.disconnectListenerCallback = this.disconnectListener.bind(this);
- this.portPollerCallback = this.portPoller.bind(this);
- }
- try {
- this.port = chrome.runtime.connect({name: vAPI.sessionId}) || null;
- } catch (ex) {
- this.port = null;
- }
- if ( this.port !== null ) {
- this.port.onMessage.addListener(this.messageListenerCallback);
- this.port.onDisconnect.addListener(this.disconnectListenerCallback);
- }
- this.portTimerDelay = 10000;
- if ( this.portTimer === null ) {
- this.portTimer = vAPI.setTimeout(this.portPollerCallback, this.portTimerDelay);
- }
- return this.port;
- },
-
- connect: function() {
- return this.port !== null ? this.port : this.createPort();
- },
-
- send: function(channelName, message, callback) {
- this.sendTo(channelName, message, undefined, undefined, callback);
- },
-
- sendTo: function(channelName, message, toTabId, toChannel, callback) {
- // Too large a gap between the last request and the last response means
- // the main process is no longer reachable: memory leaks and bad
- // performance become a risk -- especially for long-lived, dynamic
- // pages. Guard against this.
- if ( this.pendingCount > 25 ) {
- vAPI.shutdown.exec();
- }
- var port = this.connect();
- if ( port === null ) {
- if ( typeof callback === 'function' ) {
- callback();
- }
- return;
- }
- var auxProcessId;
- if ( callback ) {
- auxProcessId = this.auxProcessId++;
- this.pending[auxProcessId] = callback;
- this.pendingCount += 1;
- }
- port.postMessage({
- channelName: channelName,
- auxProcessId: auxProcessId,
- toTabId: toTabId,
- toChannel: toChannel,
- msg: message
- });
- },
-
- addChannelListener: function(channelName, callback) {
- if ( typeof callback !== 'function' ) {
- return;
- }
- var listeners = this.channels[channelName];
- if ( listeners !== undefined && listeners.indexOf(callback) !== -1 ) {
- console.error('Duplicate listener on channel "%s"', channelName);
- return;
- }
- if ( listeners === undefined ) {
- this.channels[channelName] = [callback];
- this.channelCount += 1;
- } else {
- listeners.push(callback);
- }
- this.connect();
- },
-
- removeChannelListener: function(channelName, callback) {
- if ( typeof callback !== 'function' ) {
- return;
- }
- var listeners = this.channels[channelName];
- if ( listeners === undefined ) {
- return;
- }
- var pos = this.listeners.indexOf(callback);
- if ( pos === -1 ) {
- console.error('Listener not found on channel "%s"', channelName);
- return;
- }
- listeners.splice(pos, 1);
- if ( listeners.length === 0 ) {
- delete this.channels[channelName];
- this.channelCount -= 1;
- }
- },
-
- removeAllChannelListeners: function(channelName) {
- var listeners = this.channels[channelName];
- if ( listeners === undefined ) {
- return;
- }
- delete this.channels[channelName];
- this.channelCount -= 1;
- },
-
- sendToChannelListeners: function(channelName, msg) {
- var listeners = this.channels[channelName];
- if ( listeners === undefined ) {
- return;
- }
- var response;
- for ( var i = 0, n = listeners.length; i < n; i++ ) {
- response = listeners[i](msg);
- if ( response !== undefined ) {
- break;
- }
- }
- return response;
- }
-};
-
-/******************************************************************************/
-
-vAPI.shutdown.add(function() {
- vAPI.messaging.shutdown();
- delete window.vAPI;
-});
-
-// https://www.youtube.com/watch?v=rT5zCHn0tsg
-// https://www.youtube.com/watch?v=E-jS4e3zacI
-
-vAPI.executionCost.stop('vapi-client.js');
-
-/******************************************************************************/
-/******************************************************************************/
-
-})(this);
-
-/******************************************************************************/
diff --git a/platform/webext/vapi-common.js b/platform/webext/vapi-common.js
deleted file mode 100644
index 6020d6665..000000000
--- a/platform/webext/vapi-common.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/*******************************************************************************
-
- uBlock Origin - a browser extension to block requests.
- Copyright (C) 2014-2016 The uBlock Origin authors
-
- 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
-*/
-
-// For background page or non-background pages
-
-'use strict';
-
-/******************************************************************************/
-/******************************************************************************/
-
-(function() {
-
-var vAPI = self.vAPI = self.vAPI || {};
-var chrome = self.chrome;
-
-/******************************************************************************/
-
-vAPI.setTimeout = vAPI.setTimeout || self.setTimeout.bind(self);
-
-/******************************************************************************/
-
-// http://www.w3.org/International/questions/qa-scripts#directions
-
-var setScriptDirection = function(language) {
- document.body.setAttribute(
- 'dir',
- ['ar', 'he', 'fa', 'ps', 'ur'].indexOf(language) !== -1 ? 'rtl' : 'ltr'
- );
-};
-
-/******************************************************************************/
-
-vAPI.download = function(details) {
- if ( !details.url ) {
- return;
- }
-
- var a = document.createElement('a');
- a.href = details.url;
- a.setAttribute('download', details.filename || '');
- a.dispatchEvent(new MouseEvent('click'));
-};
-
-/******************************************************************************/
-
-vAPI.insertHTML = function(node, html) {
- node.innerHTML = html;
-};
-
-/******************************************************************************/
-
-vAPI.getURL = chrome.runtime.getURL;
-
-/******************************************************************************/
-
-vAPI.i18n = chrome.i18n.getMessage;
-
-setScriptDirection(vAPI.i18n('@@ui_locale'));
-
-/******************************************************************************/
-
-vAPI.closePopup = function() {
- window.open('','_self').close();
-};
-
-/******************************************************************************/
-
-// A localStorage-like object which should be accessible from the
-// background page or auxiliary pages.
-// This storage is optional, but it is nice to have, for a more polished user
-// experience.
-
-// This can throw in some contexts (like in devtool).
-try {
- vAPI.localStorage = window.localStorage;
-} catch (ex) {
-}
-
-/******************************************************************************/
-
-})();
-
-/******************************************************************************/