diff --git a/src/js/background.js b/src/js/background.js index 9f4861e4f3..392f0924ce 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -50,6 +50,7 @@ function Badger() { self.heuristicBlocking = new HeuristicBlocking.HeuristicBlocker(thisStorage); self.updateTabList(); self.initializeDefaultSettings(); + self.registerContentScripts(); try { self.runMigrations(); } finally { @@ -700,6 +701,7 @@ Badger.prototype = { if (disabledSites.indexOf(origin) < 0) { disabledSites.push(origin); settings.setItem("disabledSites", disabledSites); + this.registerContentScripts(); } }, @@ -722,6 +724,118 @@ Badger.prototype = { if (idx >= 0) { utils.removeElementFromArray(disabledSites, idx); settings.setItem("disabledSites", disabledSites); + this.registerContentScripts(); + } + }, + + /** + * Registers content scripts using the contentScripts API; currently only + * available in FF59+. + * TODO Figure out how to pass configuration with these scripts. + */ + registerContentScripts: function() { + // If 'browser' is undefined, we are running in Chrome. + if (typeof browser === "undefined" || !browser.contentScripts) { + return; + } + + if (badger.activeContentScripts) { + badger.activeContentScripts.unregister(); + } + + if (badger.idleContentScripts) { + badger.idleContentScripts.unregister(); + } + + // Convert the domains in disabledSites into URLs that can be matched against. + const whitelistedURLs = badger.getSettings().getItem('disabledSites') + .map((site) => '*://' + site + '/*'); + + const activeScripts = { + 'js': [ + {file: '/js/contentscripts/fingerprinting.js'}, + {file: '/js/contentscripts/clobbercookie.js'}, + {file: '/js/contentscripts/clobberlocalstorage.js'}], + 'matches': ["http://*/*", "https://*/*"], + 'allFrames': true, + 'runAt': 'document_start' + }; + + const idleScripts = { + 'js': [{file: '/js/contentscripts/supercookie.js'}], + 'matches': ["http://*/*", "https://*/*"], + 'allFrames': true, + 'runAt': 'document_idle' + }; + + if (whitelistedURLs.length > 0) { + activeScripts.excludeMatches = whitelistedURLs; + idleScripts.excludeMatches = whitelistedURLs; + } + + if (badger.isSocialWidgetReplacementEnabled()) { + idleScripts.js.push({file: '/js/contentscripts/socialwidgets.js'}); + } + + const registerActive = browser.contentScripts.register(activeScripts); + const registerIdle = browser.contentScripts.register(idleScripts); + + registerActive.then((res) => {badger.activeContentScripts = res;}); + registerIdle.then((res) => {badger.idleContentScripts = res;}); + }, + + /** + * Insert into the tab the required content scripts based on whitelisting status. + * + * @param {int} tab_id The ID of the tab + * @param {String} url The URL of the specified tab + * @param {int} frame_id The ID from the current frame + * @param {Boolean} is_internal Whether this tab is an internal browser tab + */ + insertContentScripts(tab_id, url, frame_id, is_internal) { + if (!this.isPrivacyBadgerEnabled(url) || is_internal) { + return; + } + // In FF 59+, content scripts are injected with registerContentScripts(). + if (typeof browser !== "undefined" && browser.contentScripts) { + return; + } + + var noop = function() { + if (chrome.runtime.lastError) { + // // Do nothing + } + }; + + // Insert all scripts + // TODO Put this in a loop? + chrome.tabs.executeScript(tab_id, { + 'file': '/js/contentscripts/fingerprinting.js', + 'frameId': frame_id, + 'runAt': 'document_start' + }, noop); + chrome.tabs.executeScript(tab_id, { + 'file': '/js/contentscripts/clobbercookie.js', + 'frameId': frame_id, + 'runAt': 'document_start' + }, noop); + chrome.tabs.executeScript(tab_id, { + 'file': '/js/contentscripts/clobberlocalstorage.js', + 'frameId': frame_id, + 'runAt': 'document_start' + }, noop); + chrome.tabs.executeScript(tab_id, { + 'file': '/js/contentscripts/supercookie.js', + 'frameId': frame_id, + 'runAt': 'document_idle' + }, noop); + + if (this.isSocialWidgetReplacementEnabled()) { + chrome.tabs.executeScript(tab_id, { + 'file': '/js/contentscripts/socialwidgets.js', + 'frameId': frame_id, + 'runAt': 'document_start' + }, noop); } }, diff --git a/src/js/contentscripts/fingerprinting.js b/src/js/contentscripts/fingerprinting.js index 61ca56b588..7578949822 100644 --- a/src/js/contentscripts/fingerprinting.js +++ b/src/js/contentscripts/fingerprinting.js @@ -19,7 +19,6 @@ */ function getFpPageScript() { - // code below is not a content script: no chrome.* APIs ///////////////////// // return a string @@ -320,27 +319,20 @@ function insertFpScript(text, data) { parent.removeChild(script); } -// TODO race condition; fix waiting on https://crbug.com/478183 -chrome.runtime.sendMessage({checkEnabled: true}, - function (enabled) { - if (!enabled) { - return; - } - /** - * Communicating to webrequest.js - */ - var event_id = Math.random(); - - // listen for messages from the script we are about to insert - document.addEventListener(event_id, function (e) { - // pass these on to the background page - chrome.runtime.sendMessage({ - 'fpReport': e.detail - }); - }); +/** + * Communicating to webrequest.js + */ +var event_id = Math.random(); + +// listen for messages from the script we are about to insert +document.addEventListener(event_id, function (e) { + // pass these on to the background page + chrome.runtime.sendMessage({ + 'fpReport': e.detail + }); +}); + +insertFpScript(getFpPageScript(), { + event_id: event_id +}); - insertFpScript(getFpPageScript(), { - event_id: event_id - }); - } -); diff --git a/src/js/contentscripts/socialwidgets.js b/src/js/contentscripts/socialwidgets.js index acf097fd51..803a556c32 100644 --- a/src/js/contentscripts/socialwidgets.js +++ b/src/js/contentscripts/socialwidgets.js @@ -327,11 +327,4 @@ function unblockTracker(buttonUrls, callback) { chrome.runtime.sendMessage(request, callback); } -chrome.runtime.sendMessage({ - checkSocialWidgetReplacementEnabled: true -}, function (checkSocialWidgetReplacementEnabled) { - if (!checkSocialWidgetReplacementEnabled) { - return; - } - initialize(); -}); +initialize(); diff --git a/src/js/options.js b/src/js/options.js index 3dc4a30dc5..91f58ed56f 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -295,6 +295,7 @@ function updateShowCounter() { function updateSocialWidgetReplacement() { var replaceSocialWidgets = $("#replace_social_widgets_checkbox").prop("checked"); settings.setItem("socialWidgetReplacementEnabled", replaceSocialWidgets); + badger.registerContentScripts(); } function updateCheckingDNTPolicy() { diff --git a/src/js/webrequest.js b/src/js/webrequest.js index de047b7ef7..426210fdd8 100644 --- a/src/js/webrequest.js +++ b/src/js/webrequest.js @@ -40,6 +40,16 @@ var temporarySocialWidgetUnblock = {}; /***************** Blocking Listener Functions **************/ +function injectScripts(details) { + var frame_id = details.frameId, + tab_id = details.tabId, + url = details.url; + + if (!_isTabChromeInternal(tab_id)) { + badger.insertContentScripts(tab_id, url, frame_id); + } +} + /** * Event handling of http requests, main logic to collect data what to block * @@ -52,6 +62,8 @@ function onBeforeRequest(details) { type = details.type, url = details.url; + var is_internal = _isTabChromeInternal(tab_id); + if (type == "main_frame") { forgetTab(tab_id); @@ -77,7 +89,8 @@ function onBeforeRequest(details) { return {cancel: true}; } - if (_isTabChromeInternal(tab_id)) { + // TODO Any danger in moving this above `main_frame` check? + if (is_internal) { return {}; } @@ -703,6 +716,7 @@ function startListeners() { chrome.webRequest.onBeforeRequest.addListener(onBeforeRequest, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {urls: ["http://*/*", "https://*/*"]}, ["requestHeaders", "blocking"]); chrome.webRequest.onHeadersReceived.addListener(onHeadersReceived, {urls: [""]}, ["responseHeaders", "blocking"]); + chrome.webNavigation.onCommitted.addListener(injectScripts); chrome.tabs.onRemoved.addListener(onTabRemoved); chrome.tabs.onReplaced.addListener(onTabReplaced); chrome.runtime.onMessage.addListener(dispatcher); diff --git a/src/manifest.json b/src/manifest.json index d3a584aaff..c30aa347e5 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -53,29 +53,6 @@ "http://twitter.com/*" ], "run_at": "document_idle" - }, - { - "js": [ - "js/contentscripts/clobbercookie.js", - "js/contentscripts/clobberlocalstorage.js", - "js/contentscripts/fingerprinting.js" - ], - "matches": [ - "" - ], - "all_frames": true, - "run_at": "document_start" - }, - { - "js": [ - "js/contentscripts/socialwidgets.js", - "js/contentscripts/supercookie.js" - ], - "matches": [ - "" - ], - "all_frames": true, - "run_at": "document_idle" } ], "default_locale": "en_US",