fune/browser/base/content/browser-trackingprotection.js
Johann Hofmann e4580d39d9 Bug 1476317 - Fix identity popup display for pages with exceptions that have blocked content. r=nhnt11
The identity popup will now show that there's an exception on the site instead of being confused.

We previously didn't handle this state because I assumed it wouldn't be possible to enter.
Turns out if you open the same (tracking) site in two tabs and then add an exception in one tab,
the other tab will be in this state until reload.

MozReview-Commit-ID: GVVdNpsAm6h

--HG--
extra : rebase_source : 3ace3cd4f99094edf3c678c56a39adebdc37d1f3
2018-07-18 16:33:06 +02:00

362 lines
13 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var TrackingProtection = {
// If the user ignores the doorhanger, we stop showing it after some time.
MAX_INTROS: 20,
PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
PREF_APP_MENU_TOGGLE: "privacy.trackingprotection.appMenuToggle.enabled",
PREF_ANIMATIONS_ENABLED: "toolkit.cosmeticAnimations.enabled",
enabledGlobally: false,
enabledInPrivateWindows: false,
container: null,
content: null,
icon: null,
activeTooltipText: null,
disabledTooltipText: null,
get _baseURIForChannelClassifier() {
// Convert document URI into the format used by
// nsChannelClassifier::ShouldEnableTrackingProtection.
// Any scheme turned into https is correct.
try {
return Services.io.newURI("https://" + gBrowser.selectedBrowser.currentURI.hostPort);
} catch (e) {
// Getting the hostPort for about: and file: URIs fails, but TP doesn't work with
// these URIs anyway, so just return null here.
return null;
}
},
init() {
let $ = selector => document.querySelector(selector);
this.container = $("#tracking-protection-container");
this.content = $("#tracking-protection-content");
this.icon = $("#tracking-protection-icon");
this.appMenuContainer = $("#appMenu-tp-container");
this.appMenuSeparator = $("#appMenu-tp-separator");
this.iconBox = $("#tracking-protection-icon-box");
this.animatedIcon = $("#tracking-protection-icon-animatable-image");
this.animatedIcon.addEventListener("animationend", () => this.iconBox.removeAttribute("animate"));
this.appMenuButton = $("#appMenu-tp-toggle");
this.enableTooltip =
gNavigatorBundle.getString("trackingProtection.toggle.enable.tooltip");
this.disableTooltip =
gNavigatorBundle.getString("trackingProtection.toggle.disable.tooltip");
this.enableTooltipPB =
gNavigatorBundle.getString("trackingProtection.toggle.enable.pbmode.tooltip");
this.disableTooltipPB =
gNavigatorBundle.getString("trackingProtection.toggle.disable.pbmode.tooltip");
this.updateAnimationsEnabled = () => {
this.iconBox.toggleAttribute("animationsenabled",
Services.prefs.getBoolPref(this.PREF_ANIMATIONS_ENABLED, false));
};
this.updateAnimationsEnabled();
Services.prefs.addObserver(this.PREF_ANIMATIONS_ENABLED, this.updateAnimationsEnabled);
this.updateEnabled();
this.updateAppMenuToggle = () => {
if (Services.prefs.getBoolPref(this.PREF_APP_MENU_TOGGLE, false)) {
this.appMenuContainer.removeAttribute("hidden");
this.appMenuSeparator.removeAttribute("hidden");
} else {
this.appMenuContainer.setAttribute("hidden", "true");
this.appMenuSeparator.setAttribute("hidden", "true");
}
};
Services.prefs.addObserver(this.PREF_ENABLED_GLOBALLY, this);
Services.prefs.addObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this);
Services.prefs.addObserver(this.PREF_APP_MENU_TOGGLE, this.updateAppMenuToggle);
this.updateAppMenuToggle();
this.activeTooltipText =
gNavigatorBundle.getString("trackingProtection.icon.activeTooltip");
this.disabledTooltipText =
gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip");
this.enabledHistogramAdd(this.enabledGlobally);
this.disabledPBMHistogramAdd(!this.enabledInPrivateWindows);
},
uninit() {
Services.prefs.removeObserver(this.PREF_ENABLED_GLOBALLY, this);
Services.prefs.removeObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this);
Services.prefs.removeObserver(this.PREF_APP_MENU_TOGGLE, this.updateAppMenuToggle);
Services.prefs.removeObserver(this.PREF_ANIMATIONS_ENABLED, this.updateAnimationsEnabled);
},
observe() {
this.updateEnabled();
},
get enabled() {
return this.enabledGlobally ||
(this.enabledInPrivateWindows &&
PrivateBrowsingUtils.isWindowPrivate(window));
},
onGlobalToggleCommand() {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
Services.prefs.setBoolPref(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, !this.enabledInPrivateWindows);
} else {
Services.prefs.setBoolPref(this.PREF_ENABLED_GLOBALLY, !this.enabledGlobally);
}
},
hideIdentityPopupAndReload() {
document.getElementById("identity-popup").hidePopup();
BrowserReload();
},
openPreferences(origin) {
openPreferences("privacy-trackingprotection", { origin });
},
updateEnabled() {
this.enabledGlobally =
Services.prefs.getBoolPref(this.PREF_ENABLED_GLOBALLY);
this.enabledInPrivateWindows =
Services.prefs.getBoolPref(this.PREF_ENABLED_IN_PRIVATE_WINDOWS);
this.content.setAttribute("enabled", this.enabled);
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
this.appMenuButton.setAttribute("enabled", this.enabledInPrivateWindows);
this.appMenuButton.setAttribute("aria-pressed", this.enabledInPrivateWindows);
this.appMenuButton.setAttribute("tooltiptext", this.enabledInPrivateWindows ?
this.disableTooltipPB : this.enableTooltipPB);
} else {
this.appMenuButton.setAttribute("enabled", this.enabledGlobally);
this.appMenuButton.setAttribute("aria-pressed", this.enabledGlobally);
this.appMenuButton.setAttribute("tooltiptext", this.enabledGlobally ?
this.disableTooltip : this.enableTooltip);
}
},
enabledHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").add(value);
},
disabledPBMHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
Services.telemetry.getHistogramById("TRACKING_PROTECTION_PBM_DISABLED").add(value);
},
eventsHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS").add(value);
},
shieldHistogramAdd(value) {
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD").add(value);
},
cancelAnimation() {
let iconAnimation = this.animatedIcon.getAnimations()[0];
if (iconAnimation && iconAnimation.currentTime) {
iconAnimation.cancel();
}
this.iconBox.removeAttribute("animate");
},
onSecurityChange(state, webProgress, isSimulated) {
let baseURI = this._baseURIForChannelClassifier;
// Don't deal with about:, file: etc.
if (!baseURI) {
this.cancelAnimation();
this.iconBox.removeAttribute("state");
return;
}
// The user might have navigated before the shield animation
// finished. In this case, reset the animation to be able to
// play it in full again and avoid choppiness.
if (webProgress.isTopLevel) {
this.cancelAnimation();
}
let isBlocking = state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT;
let isAllowing = state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT;
// Check whether the user has added an exception for this site.
let hasException = false;
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
hasException = PrivateBrowsingUtils.existsInTrackingAllowlist(baseURI);
} else {
hasException = Services.perms.testExactPermission(baseURI,
"trackingprotection") == Services.perms.ALLOW_ACTION;
}
if (hasException) {
this.iconBox.setAttribute("hasException", "true");
this.content.setAttribute("hasException", "true");
} else {
this.iconBox.removeAttribute("hasException");
this.content.removeAttribute("hasException");
}
if (isBlocking && this.enabled) {
if (isSimulated) {
this.cancelAnimation();
} else if (webProgress.isTopLevel) {
this.iconBox.setAttribute("animate", "true");
}
this.iconBox.setAttribute("tooltiptext", this.activeTooltipText);
this.iconBox.setAttribute("state", "blocked-tracking-content");
this.content.setAttribute("state", "blocked-tracking-content");
// Open the tracking protection introduction panel, if applicable.
if (this.enabledGlobally) {
let introCount = Services.prefs.getIntPref("privacy.trackingprotection.introCount");
if (introCount < TrackingProtection.MAX_INTROS) {
Services.prefs.setIntPref("privacy.trackingprotection.introCount", ++introCount);
Services.prefs.savePrefFile(null);
this.showIntroPanel();
}
}
this.shieldHistogramAdd(2);
} else if (isAllowing) {
if (isSimulated) {
this.cancelAnimation();
} else if (webProgress.isTopLevel) {
this.iconBox.setAttribute("animate", "true");
}
// Only show the shield when TP is enabled for now.
if (this.enabled) {
this.iconBox.setAttribute("tooltiptext", this.disabledTooltipText);
this.iconBox.setAttribute("state", "loaded-tracking-content");
this.shieldHistogramAdd(1);
} else {
this.iconBox.removeAttribute("tooltiptext");
this.iconBox.removeAttribute("state");
this.shieldHistogramAdd(0);
}
// Warn in the control center even with TP disabled.
this.content.setAttribute("state", "loaded-tracking-content");
} else {
this.iconBox.removeAttribute("tooltiptext");
this.iconBox.removeAttribute("state");
this.content.removeAttribute("state");
// We didn't show the shield
this.shieldHistogramAdd(0);
}
// Telemetry for state change.
this.eventsHistogramAdd(0);
},
disableForCurrentPage() {
let baseURI = this._baseURIForChannelClassifier;
// Add the current host in the 'trackingprotection' consumer of
// the permission manager using a normalized URI. This effectively
// places this host on the tracking protection allowlist.
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
PrivateBrowsingUtils.addToTrackingAllowlist(baseURI);
} else {
Services.perms.add(baseURI,
"trackingprotection", Services.perms.ALLOW_ACTION);
}
// Telemetry for disable protection.
this.eventsHistogramAdd(1);
this.hideIdentityPopupAndReload();
},
enableForCurrentPage() {
// Remove the current host from the 'trackingprotection' consumer
// of the permission manager. This effectively removes this host
// from the tracking protection allowlist.
let baseURI = this._baseURIForChannelClassifier;
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
PrivateBrowsingUtils.removeFromTrackingAllowlist(baseURI);
} else {
Services.perms.remove(baseURI, "trackingprotection");
}
// Telemetry for enable protection.
this.eventsHistogramAdd(2);
this.hideIdentityPopupAndReload();
},
dontShowIntroPanelAgain() {
// This function may be called in private windows, but it does not change
// any preference unless Tracking Protection is enabled globally.
if (this.enabledGlobally) {
Services.prefs.setIntPref("privacy.trackingprotection.introCount",
this.MAX_INTROS);
Services.prefs.savePrefFile(null);
}
},
async showIntroPanel() {
let brandBundle = document.getElementById("bundle_brand");
let brandShortName = brandBundle.getString("brandShortName");
let openStep2 = () => {
// When the user proceeds in the tour, adjust the counter to indicate that
// the user doesn't need to see the intro anymore.
this.dontShowIntroPanelAgain();
let nextURL = Services.urlFormatter.formatURLPref("privacy.trackingprotection.introURL") +
"?step=2&newtab=true";
switchToTabHavingURI(nextURL, true, {
// Ignore the fragment in case the intro is shown on the tour page
// (e.g. if the user manually visited the tour or clicked the link from
// about:privatebrowsing) so we can avoid a reload.
ignoreFragment: "whenComparingAndReplace",
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
};
let buttons = [
{
label: gNavigatorBundle.getString("trackingProtection.intro.step1of3"),
style: "text",
},
{
callback: openStep2,
label: gNavigatorBundle.getString("trackingProtection.intro.nextButton.label"),
style: "primary",
},
];
let panelTarget = await UITour.getTarget(window, "trackingProtection");
UITour.initForBrowser(gBrowser.selectedBrowser, window);
UITour.showInfo(window, panelTarget,
gNavigatorBundle.getString("trackingProtection.intro.title"),
gNavigatorBundle.getFormattedString("trackingProtection.intro.description2",
[brandShortName]),
undefined, buttons,
{ closeButtonCallback: () => this.dontShowIntroPanelAgain() });
},
};