Skip to content

Commit

Permalink
Bug 1390161 - Show that a WebExtension is managing the tracking prote…
Browse files Browse the repository at this point in the history
…ction setting, r=jaws,mstriemer

This adjusts both the new Tracking Protection UI and the old Tracking Protection UI on
about:preferences to indicate when an extension is controlling Tracking Protection. It
will disable the controls on about:preferences if an extension is in control, and provide
a button to disable the extension.

MozReview-Commit-ID: G04jWrS6Pr9

--HG--
extra : rebase_source : 4cdee73b00b74e25c074e62a872d7b50a984cf8f
  • Loading branch information
Bob Silverberg committed Nov 6, 2017
1 parent dd155c0 commit 31cb7a0
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 43 deletions.
1 change: 0 additions & 1 deletion browser/components/preferences/in-content/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
"browser.download.hide_plugins_without_extensions";

// Strings to identify ExtensionSettingsStore overrides
const PREF_SETTING_TYPE = "prefs";
const CONTAINERS_KEY = "privacy.containers";
const HOMEPAGE_OVERRIDE_KEY = "homepage_override";
const URL_OVERRIDES_TYPE = "url_overrides";
Expand Down
63 changes: 47 additions & 16 deletions browser/components/preferences/in-content/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
XPCOMUtils.defineLazyModuleGetter(this, "formAutofillParent",
"resource://formautofill/FormAutofillParent.jsm");

XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
"privacy.trackingprotection.ui.enabled");

var gLastHash = "";

var gCategoryInits = new Map();
Expand Down Expand Up @@ -418,11 +421,22 @@ function appendSearchKeywords(aId, keywords) {
element.setAttribute("searchkeywords", keywords.join(" "));
}

const PREF_SETTING_TYPE = "prefs";

let extensionControlledContentIds = {
"privacy.containers": "browserContainersExtensionContent",
"homepage_override": "browserHomePageExtensionContent",
"newTabURL": "browserNewTabExtensionContent",
"defaultSearch": "browserDefaultSearchExtensionContent",
get "websites.trackingProtectionMode"() {
return {
button: "trackingProtectionExtensionContentButton",
section:
trackingprotectionUiEnabled ?
"trackingProtectionExtensionContentLabel" :
"trackingProtectionPBMExtensionContentLabel",
};
}
};

let extensionControlledIds = {};
Expand All @@ -435,8 +449,17 @@ async function getControllingExtensionInfo(type, settingName) {
return ExtensionSettingsStore.getSetting(type, settingName);
}

function getControllingExtensionEl(settingName) {
return document.getElementById(extensionControlledContentIds[settingName]);
function getControllingExtensionEls(settingName) {
let idInfo = extensionControlledContentIds[settingName];
let section = document.getElementById(idInfo.section || idInfo);
let button = idInfo.button ?
document.getElementById(idInfo.button) :
section.querySelector("button");
return {
section,
button,
description: section.querySelector("description"),
};
}

async function handleControllingExtension(type, settingName) {
Expand All @@ -453,7 +476,10 @@ async function handleControllingExtension(type, settingName) {
extensionControlledIds[settingName] = info.id;
showControllingExtension(settingName, addon);
} else {
if (extensionControlledIds[settingName] && !document.hidden) {
let elements = getControllingExtensionEls(settingName);
if (extensionControlledIds[settingName]
&& !document.hidden
&& elements.button) {
showEnableExtensionMessage(settingName);
} else {
hideControllingExtension(settingName);
Expand All @@ -466,14 +492,15 @@ async function handleControllingExtension(type, settingName) {

async function showControllingExtension(settingName, addon) {
// Tell the user what extension is controlling the setting.
let extensionControlledContent = getControllingExtensionEl(settingName);
extensionControlledContent.classList.remove("extension-controlled-disabled");
let elements = getControllingExtensionEls(settingName);

elements.section.classList.remove("extension-controlled-disabled");
const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
let stringParts = document
.getElementById("bundlePreferences")
.getString(`extensionControlled.${settingName}`)
.split("%S");
let description = extensionControlledContent.querySelector("description");
let description = elements.description;

// Remove the old content from the description.
while (description.firstChild) {
Expand All @@ -489,38 +516,42 @@ async function showControllingExtension(settingName, addon) {
description.appendChild(document.createTextNode(` ${addon.name}`));
description.appendChild(document.createTextNode(stringParts[1]));

let disableButton = extensionControlledContent.querySelector("button");
if (disableButton) {
disableButton.hidden = false;
if (elements.button) {
elements.button.hidden = false;
}

// Show the controlling extension row and hide the old label.
extensionControlledContent.hidden = false;
elements.section.hidden = false;
}

function hideControllingExtension(settingName) {
getControllingExtensionEl(settingName).hidden = true;
let elements = getControllingExtensionEls(settingName);
elements.section.hidden = true;
if (elements.button) {
elements.button.hidden = true;
}
}

function showEnableExtensionMessage(settingName) {
let extensionControlledContent = getControllingExtensionEl(settingName);
extensionControlledContent.classList.add("extension-controlled-disabled");
let elements = getControllingExtensionEls(settingName);

elements.button.hidden = true;
elements.section.classList.add("extension-controlled-disabled");
let icon = url => `<image src="${url}" class="extension-controlled-icon"/>`;
let addonIcon = icon("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
let toolbarIcon = icon("chrome://browser/skin/menu.svg");
let message = document
.getElementById("bundlePreferences")
.getFormattedString("extensionControlled.enable", [addonIcon, toolbarIcon]);
let description = extensionControlledContent.querySelector("description");
// eslint-disable-next-line no-unsanitized/property
description.innerHTML = message;
elements.description.innerHTML = message;
let dismissButton = document.createElement("image");
dismissButton.setAttribute("class", "extension-controlled-icon close-icon");
dismissButton.addEventListener("click", function dismissHandler() {
hideControllingExtension(settingName);
dismissButton.removeEventListener("click", dismissHandler);
});
description.appendChild(dismissButton);
elements.description.appendChild(dismissButton);
}

function makeDisableControllingExtension(type, settingName) {
Expand Down
79 changes: 77 additions & 2 deletions browser/components/preferences/in-content/privacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
"resource:///modules/SiteDataManager.jsm");

XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
"privacy.trackingprotection.ui.enabled");

Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");

const PREF_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";

const TRACKING_PROTECTION_KEY = "websites.trackingProtectionMode";
const TRACKING_PROTECTION_PREFS = ["privacy.trackingprotection.enabled",
"privacy.trackingprotection.pbmode.enabled"];

XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function() {
try {
let alertsService = Cc["@mozilla.org/alerts-service;1"]
Expand Down Expand Up @@ -133,7 +140,7 @@ var gPrivacyPane = {
* privacy.trackingprotection.ui.enabled pref, and linkify its Learn More link
*/
_initTrackingProtection() {
if (!Services.prefs.getBoolPref("privacy.trackingprotection.ui.enabled")) {
if (!trackingprotectionUiEnabled) {
return;
}

Expand All @@ -153,9 +160,71 @@ var gPrivacyPane = {
* Protection UI.
*/
_initTrackingProtectionPBM() {
let link = document.getElementById("trackingProtectionPBMLearnMore");
if (trackingprotectionUiEnabled) {
return;
}

let link = document.getElementById("trackingProtectionLearnMore");
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "tracking-protection-pbm";
link.setAttribute("href", url);

this._updateTrackingProtectionUI();
},

/**
* Update the tracking protection UI to deal with extension control.
*/
_updateTrackingProtectionUI() {
let isLocked = TRACKING_PROTECTION_PREFS.some(
pref => Services.prefs.prefIsLocked(pref));

function setInputsDisabledState(isControlled) {
let disabled = isLocked || isControlled;
if (trackingprotectionUiEnabled) {
document.querySelectorAll("#trackingProtectionRadioGroup > radio")
.forEach((element) => {
element.disabled = disabled;
});
document.querySelector("#trackingProtectionDesc > label")
.disabled = disabled;
} else {
document.getElementById("trackingProtectionPBM").disabled = disabled;
document.getElementById("trackingProtectionPBMLabel")
.disabled = disabled;
}
}

if (isLocked) {
// An extension can't control this setting if either pref is locked.
hideControllingExtension(TRACKING_PROTECTION_KEY);
setInputsDisabledState(false);
} else {
handleControllingExtension(
PREF_SETTING_TYPE,
TRACKING_PROTECTION_KEY)
.then(setInputsDisabledState);
}
},

/**
* Set up handlers for showing and hiding controlling extension info
* for tracking protection.
*/
_initTrackingProtectionExtensionControl() {
let trackingProtectionObserver = {
observe(subject, topic, data) {
gPrivacyPane._updateTrackingProtectionUI();
},
};

for (let pref of TRACKING_PROTECTION_PREFS) {
Services.prefs.addObserver(pref, trackingProtectionObserver);
}
window.addEventListener("unload", () => {
for (let pref of TRACKING_PROTECTION_PREFS) {
Services.prefs.removeObserver(pref, trackingProtectionObserver);
}
});
},

/**
Expand Down Expand Up @@ -183,6 +252,7 @@ var gPrivacyPane = {
this.initAutoStartPrivateBrowsingReverter();
this._initTrackingProtection();
this._initTrackingProtectionPBM();
this._initTrackingProtectionExtensionControl();
this._initAutocomplete();

Preferences.get("privacy.sanitize.sanitizeOnShutdown").on("change",
Expand Down Expand Up @@ -227,6 +297,9 @@ var gPrivacyPane = {
gPrivacyPane.showCookies);
setEventListener("clearDataSettings", "command",
gPrivacyPane.showClearPrivateDataSettings);
setEventListener("disableTrackingProtectionExtension", "command",
makeDisableControllingExtension(
PREF_SETTING_TYPE, TRACKING_PROTECTION_KEY));
setEventListener("trackingProtectionRadioGroup", "command",
gPrivacyPane.trackingProtectionWritePrefs);
setEventListener("trackingProtectionExceptions", "command",
Expand Down Expand Up @@ -419,6 +492,8 @@ var gPrivacyPane = {
let pbmPref = Preferences.get("privacy.trackingprotection.pbmode.enabled");
let radiogroup = document.getElementById("trackingProtectionRadioGroup");

this._updateTrackingProtectionUI();

// Global enable takes precedence over enabled in Private Browsing.
if (enabledPref.value) {
radiogroup.value = "always";
Expand Down
56 changes: 35 additions & 21 deletions browser/components/preferences/in-content/privacy.xul
Original file line number Diff line number Diff line change
Expand Up @@ -323,41 +323,55 @@
<hbox align="start">
<vbox flex="1">
<description>
&trackingProtection2.description;
&trackingProtection3.description;
<label id="trackingProtectionLearnMore" class="learnMore text-link">&trackingProtectionLearnMore2.label;</label>
</description>
</vbox>
<spacer flex="1"/>
</hbox>
<hbox>
<vbox id="trackingProtectionBox" flex="1" hidden="true">
<description id="trackingProtectionDesc"
control="trackingProtectionRadioGroup">
<label class="tail-with-learn-more">&trackingProtection2.radioGroupLabel;</label>
<label id="trackingProtectionLearnMore" class="learnMore text-link">&trackingProtectionLearnMore.label;</label>
</description>
<radiogroup id="trackingProtectionRadioGroup" aria-labelledby="trackingProtectionDesc">
<radio value="always"
label="&trackingProtectionAlways.label;"
accesskey="&trackingProtectionAlways.accesskey;"/>
<radio value="private"
label="&trackingProtectionPrivate.label;"
accesskey="&trackingProtectionPrivate.accesskey;"/>
<radio value="never"
label="&trackingProtectionNever.label;"
accesskey="&trackingProtectionNever.accesskey;"/>
</radiogroup>
<vbox>
<hbox id="trackingProtectionExtensionContentLabel" align="center" hidden="true">
<description control="disableTrackingProtectionExtension" flex="1"/>
</hbox>
<vbox>
<description id="trackingProtectionDesc"
control="trackingProtectionRadioGroup">
<label>&trackingProtection3.radioGroupLabel;</label>
</description>
<radiogroup id="trackingProtectionRadioGroup" aria-labelledby="trackingProtectionDesc">
<radio value="always"
label="&trackingProtectionAlways.label;"
accesskey="&trackingProtectionAlways.accesskey;"/>
<radio value="private"
label="&trackingProtectionPrivate.label;"
accesskey="&trackingProtectionPrivate.accesskey;"/>
<radio value="never"
label="&trackingProtectionNever.label;"
accesskey="&trackingProtectionNever.accesskey;"/>
</radiogroup>
</vbox>
</vbox>
</vbox>
<vbox id="trackingProtectionPBMBox" flex="1">
<hbox align="center">
<hbox id="trackingProtectionPBMExtensionContentLabel" align="center" hidden="true">
<description control="disableTrackingProtectionExtension" flex="1"/>
</hbox>
<hbox align="start">
<checkbox id="trackingProtectionPBM"
preference="privacy.trackingprotection.pbmode.enabled"
accesskey="&trackingProtectionPBM6.accesskey;"/>
<label flex="1">&trackingProtectionPBM6.label;<spacer class="tail-with-learn-more" /><label id="trackingProtectionPBMLearnMore"
class="learnMore text-link">&trackingProtectionPBMLearnMore.label;</label>
</label>
<label id="trackingProtectionPBMLabel" flex="1">&trackingProtectionPBM6.label;</label>
</hbox>
</vbox>
<vbox id="trackingProtectionAdvancedSettings">
<hbox id="trackingProtectionExtensionContentButton" hidden="true">
<button id="disableTrackingProtectionExtension"
class="extension-controlled-button accessory-button"
flex="1"
label="&disableExtension.label;"/>
</hbox>
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
<hbox>
<button id="trackingProtectionExceptions"
Expand Down
Loading

0 comments on commit 31cb7a0

Please sign in to comment.