201 lines
6.3 KiB
JavaScript
201 lines
6.3 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/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
EveryWindow: "resource:///modules/EveryWindow.sys.mjs",
|
|
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
|
});
|
|
|
|
const NOTIFICATION_VALUE = "reduced-protection-reload";
|
|
|
|
const PREF = "privacy.reducePageProtection.infobar.enabled.pbmode";
|
|
|
|
export const ReducedProtectionNotification = {
|
|
_initialized: false,
|
|
_prefObserved: false,
|
|
// Store per browsingContext whether we encountered blocked resources to only show the
|
|
// ReducedProtectionNotification when a reload really would unblock resources
|
|
_blockedTrackers: new WeakSet(),
|
|
// Track browsers where the user triggered a reload that should show the notification.
|
|
_pendingNotification: new WeakSet(),
|
|
// Per tab we only want to show the infobar at maximum once per host to not annoy users.
|
|
// Keep track of hosts, where this infobar already appeared per tab.
|
|
_shownHosts: new WeakMap(),
|
|
|
|
observePref() {
|
|
if (this._prefObserved) {
|
|
return;
|
|
}
|
|
this._prefObserved = true;
|
|
Services.prefs.addObserver(PREF, () => {
|
|
if (Services.prefs.getBoolPref(PREF, false)) {
|
|
this.init();
|
|
} else {
|
|
this.uninit();
|
|
}
|
|
});
|
|
if (Services.prefs.getBoolPref(PREF, false)) {
|
|
this.init();
|
|
}
|
|
},
|
|
|
|
init() {
|
|
if (this._initialized) {
|
|
return;
|
|
}
|
|
lazy.EveryWindow.registerCallback(
|
|
"reduced-protection-notification",
|
|
win => {
|
|
if (
|
|
lazy.PrivateBrowsingUtils.isWindowPrivate(win) &&
|
|
!lazy.PrivateBrowsingUtils.permanentPrivateBrowsing
|
|
) {
|
|
win.gBrowser?.addTabsProgressListener(this);
|
|
}
|
|
},
|
|
win => {
|
|
if (
|
|
lazy.PrivateBrowsingUtils.isWindowPrivate(win) &&
|
|
!lazy.PrivateBrowsingUtils.permanentPrivateBrowsing
|
|
) {
|
|
win.gBrowser?.removeTabsProgressListener(this);
|
|
}
|
|
}
|
|
);
|
|
this._initialized = true;
|
|
},
|
|
|
|
uninit() {
|
|
if (!this._initialized) {
|
|
return;
|
|
}
|
|
lazy.EveryWindow.unregisterCallback("reduced-protection-notification");
|
|
this._initialized = false;
|
|
this._blockedTrackers = new WeakSet();
|
|
this._pendingNotification = new WeakSet();
|
|
this._shownHosts = new WeakMap();
|
|
},
|
|
|
|
markUserReload(aBrowser) {
|
|
if (this._blockedTrackers.has(aBrowser)) {
|
|
const host = aBrowser.currentURI?.host;
|
|
if (host && !this._shownHosts.get(aBrowser)?.has(host)) {
|
|
this._pendingNotification.add(aBrowser);
|
|
}
|
|
}
|
|
},
|
|
|
|
onContentBlockingEvent(aBrowser, aWebProgress, aRequest, aEvent) {
|
|
if (!aWebProgress.isTopLevel) {
|
|
return;
|
|
}
|
|
if (aEvent & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) {
|
|
this._blockedTrackers.add(aBrowser);
|
|
}
|
|
},
|
|
|
|
onLocationChange(aBrowser, aWebProgress, aRequest, aLocation, aFlags) {
|
|
if (!aWebProgress.isTopLevel) {
|
|
return;
|
|
}
|
|
// Don't do anything when staying on the same page (e.g. clicking an an anchor link)
|
|
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
|
|
return;
|
|
}
|
|
|
|
// We only want to show the notification if we blocked trackers and
|
|
// user initiated reload through browser UI
|
|
const blockedTrackers = this._blockedTrackers.delete(aBrowser);
|
|
const isPending = this._pendingNotification.delete(aBrowser);
|
|
if (
|
|
aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_RELOAD &&
|
|
isPending &&
|
|
blockedTrackers
|
|
) {
|
|
this.showNotification(aBrowser).catch(e => console.error(e));
|
|
}
|
|
},
|
|
|
|
async showNotification(aBrowser) {
|
|
const tabbrowser = aBrowser.getTabBrowser();
|
|
if (!tabbrowser) {
|
|
return;
|
|
}
|
|
|
|
const currentURI = aBrowser.currentURI;
|
|
if (!currentURI) {
|
|
return;
|
|
}
|
|
|
|
const host = currentURI.host;
|
|
if (this._shownHosts.get(aBrowser)?.has(host)) {
|
|
return;
|
|
}
|
|
|
|
const notificationBox = tabbrowser.getNotificationBox(aBrowser);
|
|
if (notificationBox.getNotificationWithValue(NOTIFICATION_VALUE)) {
|
|
return;
|
|
}
|
|
|
|
await notificationBox.appendNotification(
|
|
NOTIFICATION_VALUE,
|
|
{
|
|
label: { "l10n-id": "reduced-protection-infobar-message" },
|
|
priority: notificationBox.PRIORITY_INFO_LOW,
|
|
},
|
|
[
|
|
{
|
|
"l10n-id": "reduced-protection-infobar-never-show-button",
|
|
callback: () => {
|
|
Glean.privacyReducedPageProtection.disableClicked.add(1);
|
|
Services.prefs.setBoolPref(PREF, false);
|
|
},
|
|
},
|
|
{
|
|
"l10n-id": "reduced-protection-infobar-reload-button",
|
|
callback: () => {
|
|
Glean.privacyReducedPageProtection.reloadClicked.add(1);
|
|
const scopedPrefs = aBrowser.browsingContext.scopedPrefs;
|
|
if (scopedPrefs) {
|
|
const bc = aBrowser.browsingContext;
|
|
for (const pref of [
|
|
Ci.nsIScopedPrefs.PRIVACY_TRACKINGPROTECTION_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_CRYPTOMINING_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_FINGERPRINTING_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_SOCIALTRACKING_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_EMAILTRACKING_ENABLED,
|
|
Ci.nsIScopedPrefs.PRIVACY_TRACKINGPROTECTION_CONTENT_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_CONTENT_CRYPTOMINING_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_CONTENT_FINGERPRINTING_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_CONTENT_SOCIALTRACKING_ENABLED,
|
|
Ci.nsIScopedPrefs
|
|
.PRIVACY_TRACKINGPROTECTION_CONTENT_EMAILTRACKING_ENABLED,
|
|
]) {
|
|
scopedPrefs.setBoolPrefScoped(pref, bc, false);
|
|
}
|
|
}
|
|
aBrowser.reload();
|
|
},
|
|
},
|
|
]
|
|
);
|
|
|
|
Glean.privacyReducedPageProtection.bannerShown.add(1);
|
|
|
|
if (!this._shownHosts.has(aBrowser)) {
|
|
this._shownHosts.set(aBrowser, new Set());
|
|
}
|
|
this._shownHosts.get(aBrowser).add(host);
|
|
},
|
|
};
|