Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Using contentScripts API for conditional content script injection #1876

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function Badger() {
self.heuristicBlocking = new HeuristicBlocking.HeuristicBlocker(thisStorage);
self.updateTabList();
self.initializeDefaultSettings();
self.registerContentScripts();
try {
self.runMigrations();
} finally {
Expand Down Expand Up @@ -700,6 +701,7 @@ Badger.prototype = {
if (disabledSites.indexOf(origin) < 0) {
disabledSites.push(origin);
settings.setItem("disabledSites", disabledSites);
this.registerContentScripts();
}
},

Expand All @@ -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);
}
},

Expand Down
40 changes: 16 additions & 24 deletions src/js/contentscripts/fingerprinting.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/

function getFpPageScript() {

// code below is not a content script: no chrome.* APIs /////////////////////

// return a string
Expand Down Expand Up @@ -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
});
}
);
9 changes: 1 addition & 8 deletions src/js/contentscripts/socialwidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
1 change: 1 addition & 0 deletions src/js/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ function updateShowCounter() {
function updateSocialWidgetReplacement() {
var replaceSocialWidgets = $("#replace_social_widgets_checkbox").prop("checked");
settings.setItem("socialWidgetReplacementEnabled", replaceSocialWidgets);
badger.registerContentScripts();
}

function updateCheckingDNTPolicy() {
Expand Down
16 changes: 15 additions & 1 deletion src/js/webrequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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);

Expand All @@ -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 {};
}

Expand Down Expand Up @@ -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: ["<all_urls>"]}, ["responseHeaders", "blocking"]);
chrome.webNavigation.onCommitted.addListener(injectScripts);
chrome.tabs.onRemoved.addListener(onTabRemoved);
chrome.tabs.onReplaced.addListener(onTabReplaced);
chrome.runtime.onMessage.addListener(dispatcher);
Expand Down
23 changes: 0 additions & 23 deletions src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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_urls>"
],
"all_frames": true,
"run_at": "document_start"
},
{
"js": [
"js/contentscripts/socialwidgets.js",
"js/contentscripts/supercookie.js"
],
"matches": [
"<all_urls>"
],
"all_frames": true,
"run_at": "document_idle"
}
],
"default_locale": "en_US",
Expand Down