mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-18 23:05:40 -04:00
1497 lines
45 KiB
JavaScript
1497 lines
45 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 Fingerprinting = {
|
|
PREF_ENABLED: "privacy.trackingprotection.fingerprinting.enabled",
|
|
reportBreakageLabel: "fingerprinting",
|
|
telemetryIdentifier: "fp",
|
|
|
|
strings: {
|
|
get subViewBlocked() {
|
|
delete this.subViewBlocked;
|
|
return (this.subViewBlocked = gNavigatorBundle.getString(
|
|
"contentBlocking.fingerprintersView.blocked.label"
|
|
));
|
|
},
|
|
},
|
|
|
|
init() {
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"enabled",
|
|
this.PREF_ENABLED,
|
|
false,
|
|
() => this.updateCategoryLabel()
|
|
);
|
|
this.updateCategoryLabel();
|
|
},
|
|
|
|
get categoryItem() {
|
|
delete this.categoryItem;
|
|
return (this.categoryItem = document.getElementById(
|
|
"identity-popup-content-blocking-category-fingerprinters"
|
|
));
|
|
},
|
|
|
|
get categoryLabel() {
|
|
delete this.categoryLabel;
|
|
return (this.categoryLabel = document.getElementById(
|
|
"identity-popup-content-blocking-fingerprinters-state-label"
|
|
));
|
|
},
|
|
|
|
get subViewList() {
|
|
delete this.subViewList;
|
|
return (this.subViewList = document.getElementById(
|
|
"identity-popup-fingerprintersView-list"
|
|
));
|
|
},
|
|
|
|
updateCategoryLabel() {
|
|
let label;
|
|
if (this.enabled) {
|
|
label = ContentBlocking.showBlockedLabels
|
|
? "contentBlocking.fingerprinters.blocking.label"
|
|
: null;
|
|
} else {
|
|
label = ContentBlocking.showAllowedLabels
|
|
? "contentBlocking.fingerprinters.allowed.label"
|
|
: null;
|
|
}
|
|
this.categoryLabel.textContent = label
|
|
? gNavigatorBundle.getString(label)
|
|
: "";
|
|
},
|
|
|
|
isBlocking(state) {
|
|
return (
|
|
(state &
|
|
Ci.nsIWebProgressListener.STATE_BLOCKED_FINGERPRINTING_CONTENT) !=
|
|
0
|
|
);
|
|
},
|
|
|
|
isAllowing(state) {
|
|
return (
|
|
this.enabled &&
|
|
(state & Ci.nsIWebProgressListener.STATE_LOADED_FINGERPRINTING_CONTENT) !=
|
|
0
|
|
);
|
|
},
|
|
|
|
isDetected(state) {
|
|
return this.isBlocking(state) || this.isAllowing(state);
|
|
},
|
|
|
|
async updateSubView() {
|
|
let contentBlockingLog = await gBrowser.selectedBrowser.getContentBlockingLog();
|
|
contentBlockingLog = JSON.parse(contentBlockingLog);
|
|
|
|
let fragment = document.createDocumentFragment();
|
|
for (let [origin, actions] of Object.entries(contentBlockingLog)) {
|
|
let listItem = this._createListItem(origin, actions);
|
|
if (listItem) {
|
|
fragment.appendChild(listItem);
|
|
}
|
|
}
|
|
|
|
this.subViewList.textContent = "";
|
|
this.subViewList.append(fragment);
|
|
},
|
|
|
|
_createListItem(origin, actions) {
|
|
let isAllowed = actions.some(([state]) => this.isAllowing(state));
|
|
let isDetected =
|
|
isAllowed || actions.some(([state]) => this.isBlocking(state));
|
|
|
|
if (!isDetected) {
|
|
return null;
|
|
}
|
|
|
|
let uri = Services.io.newURI(origin);
|
|
|
|
let listItem = document.createXULElement("hbox");
|
|
listItem.className = "identity-popup-content-blocking-list-item";
|
|
listItem.classList.toggle("allowed", isAllowed);
|
|
// Repeat the host in the tooltip in case it's too long
|
|
// and overflows in our panel.
|
|
listItem.tooltipText = uri.host;
|
|
|
|
let image = document.createXULElement("image");
|
|
image.className = "identity-popup-fingerprintersView-icon";
|
|
image.classList.toggle("allowed", isAllowed);
|
|
listItem.append(image);
|
|
|
|
let label = document.createXULElement("label");
|
|
label.value = uri.host;
|
|
label.className = "identity-popup-content-blocking-list-host-label";
|
|
label.setAttribute("crop", "end");
|
|
listItem.append(label);
|
|
|
|
if (!isAllowed) {
|
|
let stateLabel = document.createXULElement("label");
|
|
stateLabel.value = this.strings.subViewBlocked;
|
|
stateLabel.className = "identity-popup-content-blocking-list-state-label";
|
|
listItem.append(stateLabel);
|
|
}
|
|
|
|
return listItem;
|
|
},
|
|
};
|
|
|
|
var Cryptomining = {
|
|
PREF_ENABLED: "privacy.trackingprotection.cryptomining.enabled",
|
|
reportBreakageLabel: "cryptomining",
|
|
telemetryIdentifier: "cm",
|
|
|
|
strings: {
|
|
get subViewBlocked() {
|
|
delete this.subViewBlocked;
|
|
return (this.subViewBlocked = gNavigatorBundle.getString(
|
|
"contentBlocking.cryptominersView.blocked.label"
|
|
));
|
|
},
|
|
},
|
|
|
|
init() {
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"enabled",
|
|
this.PREF_ENABLED,
|
|
false,
|
|
() => this.updateCategoryLabel()
|
|
);
|
|
this.updateCategoryLabel();
|
|
},
|
|
|
|
get categoryItem() {
|
|
delete this.categoryItem;
|
|
return (this.categoryItem = document.getElementById(
|
|
"identity-popup-content-blocking-category-cryptominers"
|
|
));
|
|
},
|
|
|
|
get categoryLabel() {
|
|
delete this.categoryLabel;
|
|
return (this.categoryLabel = document.getElementById(
|
|
"identity-popup-content-blocking-cryptominers-state-label"
|
|
));
|
|
},
|
|
|
|
get subViewList() {
|
|
delete this.subViewList;
|
|
return (this.subViewList = document.getElementById(
|
|
"identity-popup-cryptominersView-list"
|
|
));
|
|
},
|
|
|
|
updateCategoryLabel() {
|
|
let label;
|
|
if (this.enabled) {
|
|
label = ContentBlocking.showBlockedLabels
|
|
? "contentBlocking.cryptominers.blocking.label"
|
|
: null;
|
|
} else {
|
|
label = ContentBlocking.showAllowedLabels
|
|
? "contentBlocking.cryptominers.allowed.label"
|
|
: null;
|
|
}
|
|
this.categoryLabel.textContent = label
|
|
? gNavigatorBundle.getString(label)
|
|
: "";
|
|
},
|
|
|
|
isBlocking(state) {
|
|
return (
|
|
(state & Ci.nsIWebProgressListener.STATE_BLOCKED_CRYPTOMINING_CONTENT) !=
|
|
0
|
|
);
|
|
},
|
|
|
|
isAllowing(state) {
|
|
return (
|
|
this.enabled &&
|
|
(state & Ci.nsIWebProgressListener.STATE_LOADED_CRYPTOMINING_CONTENT) != 0
|
|
);
|
|
},
|
|
|
|
isDetected(state) {
|
|
return this.isBlocking(state) || this.isAllowing(state);
|
|
},
|
|
|
|
async updateSubView() {
|
|
let contentBlockingLog = await gBrowser.selectedBrowser.getContentBlockingLog();
|
|
contentBlockingLog = JSON.parse(contentBlockingLog);
|
|
|
|
let fragment = document.createDocumentFragment();
|
|
for (let [origin, actions] of Object.entries(contentBlockingLog)) {
|
|
let listItem = this._createListItem(origin, actions);
|
|
if (listItem) {
|
|
fragment.appendChild(listItem);
|
|
}
|
|
}
|
|
|
|
this.subViewList.textContent = "";
|
|
this.subViewList.append(fragment);
|
|
},
|
|
|
|
_createListItem(origin, actions) {
|
|
let isAllowed = actions.some(([state]) => this.isAllowing(state));
|
|
let isDetected =
|
|
isAllowed || actions.some(([state]) => this.isBlocking(state));
|
|
|
|
if (!isDetected) {
|
|
return null;
|
|
}
|
|
|
|
let uri = Services.io.newURI(origin);
|
|
|
|
let listItem = document.createXULElement("hbox");
|
|
listItem.className = "identity-popup-content-blocking-list-item";
|
|
listItem.classList.toggle("allowed", isAllowed);
|
|
// Repeat the host in the tooltip in case it's too long
|
|
// and overflows in our panel.
|
|
listItem.tooltipText = uri.host;
|
|
|
|
let image = document.createXULElement("image");
|
|
image.className = "identity-popup-cryptominersView-icon";
|
|
image.classList.toggle("allowed", isAllowed);
|
|
listItem.append(image);
|
|
|
|
let label = document.createXULElement("label");
|
|
label.value = uri.host;
|
|
label.className = "identity-popup-content-blocking-list-host-label";
|
|
label.setAttribute("crop", "end");
|
|
listItem.append(label);
|
|
|
|
if (!isAllowed) {
|
|
let stateLabel = document.createXULElement("label");
|
|
stateLabel.value = this.strings.subViewBlocked;
|
|
stateLabel.className = "identity-popup-content-blocking-list-state-label";
|
|
listItem.append(stateLabel);
|
|
}
|
|
|
|
return listItem;
|
|
},
|
|
};
|
|
|
|
var TrackingProtection = {
|
|
reportBreakageLabel: "trackingprotection",
|
|
telemetryIdentifier: "tp",
|
|
PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
|
|
PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
|
|
PREF_TRACKING_TABLE: "urlclassifier.trackingTable",
|
|
PREF_TRACKING_ANNOTATION_TABLE: "urlclassifier.trackingAnnotationTable",
|
|
enabledGlobally: false,
|
|
enabledInPrivateWindows: false,
|
|
|
|
get categoryItem() {
|
|
delete this.categoryItem;
|
|
return (this.categoryItem = document.getElementById(
|
|
"identity-popup-content-blocking-category-tracking-protection"
|
|
));
|
|
},
|
|
|
|
get categoryLabel() {
|
|
delete this.categoryLabel;
|
|
return (this.categoryLabel = document.getElementById(
|
|
"identity-popup-content-blocking-tracking-protection-state-label"
|
|
));
|
|
},
|
|
|
|
get subViewList() {
|
|
delete this.subViewList;
|
|
return (this.subViewList = document.getElementById(
|
|
"identity-popup-trackersView-list"
|
|
));
|
|
},
|
|
|
|
get strictInfo() {
|
|
delete this.strictInfo;
|
|
return (this.strictInfo = document.getElementById(
|
|
"identity-popup-trackersView-strict-info"
|
|
));
|
|
},
|
|
|
|
strings: {
|
|
get subViewBlocked() {
|
|
delete this.subViewBlocked;
|
|
return (this.subViewBlocked = gNavigatorBundle.getString(
|
|
"contentBlocking.trackersView.blocked.label"
|
|
));
|
|
},
|
|
},
|
|
|
|
init() {
|
|
this.updateEnabled();
|
|
|
|
Services.prefs.addObserver(this.PREF_ENABLED_GLOBALLY, this);
|
|
Services.prefs.addObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this);
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"trackingTable",
|
|
this.PREF_TRACKING_TABLE,
|
|
false
|
|
);
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"trackingAnnotationTable",
|
|
this.PREF_TRACKING_ANNOTATION_TABLE,
|
|
false
|
|
);
|
|
},
|
|
|
|
uninit() {
|
|
Services.prefs.removeObserver(this.PREF_ENABLED_GLOBALLY, this);
|
|
Services.prefs.removeObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this);
|
|
},
|
|
|
|
observe() {
|
|
this.updateEnabled();
|
|
},
|
|
|
|
get enabled() {
|
|
return (
|
|
this.enabledGlobally ||
|
|
(this.enabledInPrivateWindows &&
|
|
PrivateBrowsingUtils.isWindowPrivate(window))
|
|
);
|
|
},
|
|
|
|
updateEnabled() {
|
|
this.enabledGlobally = Services.prefs.getBoolPref(
|
|
this.PREF_ENABLED_GLOBALLY
|
|
);
|
|
this.enabledInPrivateWindows = Services.prefs.getBoolPref(
|
|
this.PREF_ENABLED_IN_PRIVATE_WINDOWS
|
|
);
|
|
this.updateCategoryLabel();
|
|
},
|
|
|
|
updateCategoryLabel() {
|
|
let label;
|
|
if (this.enabled) {
|
|
label = ContentBlocking.showBlockedLabels
|
|
? "contentBlocking.trackers.blocking.label"
|
|
: null;
|
|
} else {
|
|
label = ContentBlocking.showAllowedLabels
|
|
? "contentBlocking.trackers.allowed.label"
|
|
: null;
|
|
}
|
|
this.categoryLabel.textContent = label
|
|
? gNavigatorBundle.getString(label)
|
|
: "";
|
|
},
|
|
|
|
isBlocking(state) {
|
|
return (
|
|
(state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) != 0
|
|
);
|
|
},
|
|
|
|
isAllowing(state) {
|
|
return (
|
|
(state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) != 0
|
|
);
|
|
},
|
|
|
|
isDetected(state) {
|
|
return this.isBlocking(state) || this.isAllowing(state);
|
|
},
|
|
|
|
async updateSubView() {
|
|
let previousURI = gBrowser.currentURI.spec;
|
|
let previousWindow = gBrowser.selectedBrowser.innerWindowID;
|
|
|
|
let contentBlockingLog = await gBrowser.selectedBrowser.getContentBlockingLog();
|
|
contentBlockingLog = JSON.parse(contentBlockingLog);
|
|
|
|
// Don't tell the user to turn on TP if they are already blocking trackers.
|
|
this.strictInfo.hidden = this.enabled;
|
|
|
|
let fragment = document.createDocumentFragment();
|
|
for (let [origin, actions] of Object.entries(contentBlockingLog)) {
|
|
let listItem = await this._createListItem(origin, actions);
|
|
if (listItem) {
|
|
fragment.appendChild(listItem);
|
|
}
|
|
}
|
|
|
|
// If we don't have trackers we would usually not show the menu item
|
|
// allowing the user to show the sub-panel. However, in the edge case
|
|
// that we annotated trackers on the page using the strict list but did
|
|
// not detect trackers on the page using the basic list, we currently
|
|
// still show the panel. To reduce the confusion, tell the user that we have
|
|
// not detected any tracker.
|
|
if (fragment.childNodes.length == 0) {
|
|
let emptyBox = document.createXULElement("vbox");
|
|
let emptyImage = document.createXULElement("image");
|
|
emptyImage.classList.add(
|
|
"identity-popup-content-blocking-trackersView-empty-image"
|
|
);
|
|
emptyImage.classList.add("tracking-protection-icon");
|
|
|
|
let emptyLabel = document.createXULElement("label");
|
|
emptyLabel.classList.add("identity-popup-content-blocking-empty-label");
|
|
emptyLabel.textContent = gNavigatorBundle.getString(
|
|
"contentBlocking.trackersView.empty.label"
|
|
);
|
|
|
|
emptyBox.appendChild(emptyImage);
|
|
emptyBox.appendChild(emptyLabel);
|
|
fragment.appendChild(emptyBox);
|
|
|
|
this.subViewList.classList.add("empty");
|
|
} else {
|
|
this.subViewList.classList.remove("empty");
|
|
}
|
|
|
|
// This might have taken a while. Only update the list if we're still on the same page.
|
|
if (
|
|
previousURI == gBrowser.currentURI.spec &&
|
|
previousWindow == gBrowser.selectedBrowser.innerWindowID
|
|
) {
|
|
this.subViewList.textContent = "";
|
|
this.subViewList.append(fragment);
|
|
}
|
|
},
|
|
|
|
// Given a URI from a source that was tracking-annotated, figure out
|
|
// if it's really on the tracking table or just on the annotation table.
|
|
_isOnTrackingTable(uri) {
|
|
if (this.trackingTable == this.trackingAnnotationTable) {
|
|
return true;
|
|
}
|
|
|
|
let feature = classifierService.getFeatureByName("tracking-protection");
|
|
if (!feature) {
|
|
return false;
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
classifierService.asyncClassifyLocalWithFeatures(
|
|
uri,
|
|
[feature],
|
|
Ci.nsIUrlClassifierFeature.blacklist,
|
|
list => resolve(!!list.length)
|
|
);
|
|
});
|
|
},
|
|
|
|
async _createListItem(origin, actions) {
|
|
// Figure out if this list entry was actually detected by TP or something else.
|
|
let isAllowed = actions.some(([state]) => this.isAllowing(state));
|
|
let isDetected =
|
|
isAllowed || actions.some(([state]) => this.isBlocking(state));
|
|
|
|
if (!isDetected) {
|
|
return null;
|
|
}
|
|
|
|
let uri = Services.io.newURI(origin);
|
|
|
|
// Because we might use different lists for annotation vs. blocking, we
|
|
// need to make sure that this is a tracker that we would actually have blocked
|
|
// before showing it to the user.
|
|
let isTracker = await this._isOnTrackingTable(uri);
|
|
if (!isTracker) {
|
|
return null;
|
|
}
|
|
|
|
let listItem = document.createXULElement("hbox");
|
|
listItem.className = "identity-popup-content-blocking-list-item";
|
|
listItem.classList.toggle("allowed", isAllowed);
|
|
// Repeat the host in the tooltip in case it's too long
|
|
// and overflows in our panel.
|
|
listItem.tooltipText = uri.host;
|
|
|
|
let image = document.createXULElement("image");
|
|
image.className = "identity-popup-trackersView-icon";
|
|
image.classList.toggle("allowed", isAllowed);
|
|
listItem.append(image);
|
|
|
|
let label = document.createXULElement("label");
|
|
label.value = uri.host;
|
|
label.className = "identity-popup-content-blocking-list-host-label";
|
|
label.setAttribute("crop", "end");
|
|
listItem.append(label);
|
|
|
|
if (!isAllowed) {
|
|
let stateLabel = document.createXULElement("label");
|
|
stateLabel.value = this.strings.subViewBlocked;
|
|
stateLabel.className = "identity-popup-content-blocking-list-state-label";
|
|
listItem.append(stateLabel);
|
|
}
|
|
|
|
return listItem;
|
|
},
|
|
};
|
|
|
|
var ThirdPartyCookies = {
|
|
telemetryIdentifier: "cr",
|
|
PREF_ENABLED: "network.cookie.cookieBehavior",
|
|
PREF_REPORT_BREAKAGE_ENABLED:
|
|
"browser.contentblocking.rejecttrackers.reportBreakage.enabled",
|
|
PREF_ENABLED_VALUES: [
|
|
// These values match the ones exposed under the Content Blocking section
|
|
// of the Preferences UI.
|
|
Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN, // Block all third-party cookies
|
|
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER, // Block third-party cookies from trackers
|
|
],
|
|
|
|
get categoryItem() {
|
|
delete this.categoryItem;
|
|
return (this.categoryItem = document.getElementById(
|
|
"identity-popup-content-blocking-category-cookies"
|
|
));
|
|
},
|
|
|
|
get categoryLabel() {
|
|
delete this.categoryLabel;
|
|
return (this.categoryLabel = document.getElementById(
|
|
"identity-popup-content-blocking-cookies-state-label"
|
|
));
|
|
},
|
|
|
|
get subViewList() {
|
|
delete this.subViewList;
|
|
return (this.subViewList = document.getElementById(
|
|
"identity-popup-cookiesView-list"
|
|
));
|
|
},
|
|
|
|
strings: {
|
|
get subViewAllowed() {
|
|
delete this.subViewAllowed;
|
|
return (this.subViewAllowed = gNavigatorBundle.getString(
|
|
"contentBlocking.cookiesView.allowed.label"
|
|
));
|
|
},
|
|
|
|
get subViewBlocked() {
|
|
delete this.subViewBlocked;
|
|
return (this.subViewBlocked = gNavigatorBundle.getString(
|
|
"contentBlocking.cookiesView.blocked.label"
|
|
));
|
|
},
|
|
},
|
|
|
|
get reportBreakageLabel() {
|
|
switch (this.behaviorPref) {
|
|
case Ci.nsICookieService.BEHAVIOR_ACCEPT:
|
|
return "nocookiesblocked";
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
|
|
return "allthirdpartycookiesblocked";
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT:
|
|
return "allcookiesblocked";
|
|
case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
|
|
return "cookiesfromunvisitedsitesblocked";
|
|
default:
|
|
Cu.reportError(
|
|
`Error: Unknown cookieBehavior pref observed: ${this.behaviorPref}`
|
|
);
|
|
// fall through
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
|
|
return "cookierestrictions";
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN:
|
|
return "cookierestrictionsforeignpartitioned";
|
|
}
|
|
},
|
|
|
|
updateCategoryLabel() {
|
|
let label;
|
|
switch (this.behaviorPref) {
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
|
|
label = ContentBlocking.showBlockedLabels
|
|
? "contentBlocking.cookies.blocking3rdParty.label"
|
|
: null;
|
|
break;
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT:
|
|
label = ContentBlocking.showBlockedLabels
|
|
? "contentBlocking.cookies.blockingAll.label"
|
|
: null;
|
|
break;
|
|
case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
|
|
label = ContentBlocking.showBlockedLabels
|
|
? "contentBlocking.cookies.blockingUnvisited.label"
|
|
: null;
|
|
break;
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
|
|
label = ContentBlocking.showBlockedLabels
|
|
? "contentBlocking.cookies.blockingTrackers.label"
|
|
: null;
|
|
break;
|
|
default:
|
|
Cu.reportError(
|
|
`Error: Unknown cookieBehavior pref observed: ${this.behaviorPref}`
|
|
);
|
|
// fall through
|
|
case Ci.nsICookieService.BEHAVIOR_ACCEPT:
|
|
label = ContentBlocking.showAllowedLabels
|
|
? "contentBlocking.cookies.allowed.label"
|
|
: null;
|
|
break;
|
|
}
|
|
this.categoryLabel.textContent = label
|
|
? gNavigatorBundle.getString(label)
|
|
: "";
|
|
},
|
|
|
|
init() {
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"behaviorPref",
|
|
this.PREF_ENABLED,
|
|
Ci.nsICookieService.BEHAVIOR_ACCEPT,
|
|
this.updateCategoryLabel.bind(this)
|
|
);
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"reportBreakageEnabled",
|
|
this.PREF_REPORT_BREAKAGE_ENABLED,
|
|
false
|
|
);
|
|
this.updateCategoryLabel();
|
|
},
|
|
|
|
get enabled() {
|
|
return this.PREF_ENABLED_VALUES.includes(this.behaviorPref);
|
|
},
|
|
|
|
isBlocking(state) {
|
|
return (
|
|
(state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_TRACKER) != 0 ||
|
|
(state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_ALL) != 0 ||
|
|
(state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_BY_PERMISSION) !=
|
|
0 ||
|
|
(state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_FOREIGN) != 0
|
|
);
|
|
},
|
|
|
|
isDetected(state) {
|
|
return (state & Ci.nsIWebProgressListener.STATE_COOKIES_LOADED) != 0;
|
|
},
|
|
|
|
async updateSubView() {
|
|
let contentBlockingLog = await gBrowser.selectedBrowser.getContentBlockingLog();
|
|
contentBlockingLog = JSON.parse(contentBlockingLog);
|
|
|
|
let categories = this._processContentBlockingLog(contentBlockingLog);
|
|
|
|
this.subViewList.textContent = "";
|
|
|
|
for (let category of ["firstParty", "trackers", "thirdParty"]) {
|
|
let box = document.createXULElement("vbox");
|
|
let label = document.createXULElement("label");
|
|
label.className = "identity-popup-cookiesView-list-header";
|
|
label.textContent = gNavigatorBundle.getString(
|
|
`contentBlocking.cookiesView.${category}.label`
|
|
);
|
|
box.appendChild(label);
|
|
|
|
for (let info of categories[category]) {
|
|
box.appendChild(this._createListItem(info));
|
|
}
|
|
|
|
// If the category is empty, add a label noting that to the user.
|
|
if (categories[category].length == 0) {
|
|
let emptyLabel = document.createXULElement("label");
|
|
emptyLabel.classList.add("identity-popup-content-blocking-empty-label");
|
|
emptyLabel.textContent = gNavigatorBundle.getString(
|
|
`contentBlocking.cookiesView.${category}.empty.label`
|
|
);
|
|
box.appendChild(emptyLabel);
|
|
}
|
|
|
|
this.subViewList.appendChild(box);
|
|
}
|
|
},
|
|
|
|
_hasException(origin) {
|
|
for (let perm of Services.perms.getAllForPrincipal(
|
|
gBrowser.contentPrincipal
|
|
)) {
|
|
if (
|
|
perm.type == "3rdPartyStorage^" + origin ||
|
|
perm.type.startsWith("3rdPartyStorage^" + origin + "^")
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(
|
|
origin
|
|
);
|
|
// Cookie exceptions get "inherited" from parent- to sub-domain, so we need to
|
|
// make sure to include parent domains in the permission check for "cookies".
|
|
return (
|
|
Services.perms.testPermissionFromPrincipal(principal, "cookie") !=
|
|
Services.perms.UNKNOWN_ACTION
|
|
);
|
|
},
|
|
|
|
_clearException(origin) {
|
|
for (let perm of Services.perms.getAllForPrincipal(
|
|
gBrowser.contentPrincipal
|
|
)) {
|
|
if (
|
|
perm.type == "3rdPartyStorage^" + origin ||
|
|
perm.type.startsWith("3rdPartyStorage^" + origin + "^")
|
|
) {
|
|
Services.perms.removePermission(perm);
|
|
}
|
|
}
|
|
|
|
// OAs don't matter here, so we can just use the hostname.
|
|
let host = Services.io.newURI(origin).host;
|
|
|
|
// Cookie exceptions get "inherited" from parent- to sub-domain, so we need to
|
|
// clear any cookie permissions from parent domains as well.
|
|
for (let perm of Services.perms.enumerator) {
|
|
if (
|
|
perm.type == "cookie" &&
|
|
Services.eTLD.hasRootDomain(host, perm.principal.URI.host)
|
|
) {
|
|
Services.perms.removePermission(perm);
|
|
}
|
|
}
|
|
},
|
|
|
|
// Transforms and filters cookie entries in the content blocking log
|
|
// so that we can categorize and display them in the UI.
|
|
_processContentBlockingLog(log) {
|
|
let newLog = {
|
|
firstParty: [],
|
|
trackers: [],
|
|
thirdParty: [],
|
|
};
|
|
|
|
let firstPartyDomain = null;
|
|
try {
|
|
firstPartyDomain = Services.eTLD.getBaseDomain(gBrowser.currentURI);
|
|
} catch (e) {
|
|
// There are nasty edge cases here where someone is trying to set a cookie
|
|
// on a public suffix or an IP address. Just categorize those as third party...
|
|
if (
|
|
e.result != Cr.NS_ERROR_HOST_IS_IP_ADDRESS &&
|
|
e.result != Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
|
|
) {
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
for (let [origin, actions] of Object.entries(log)) {
|
|
if (!origin.startsWith("http")) {
|
|
continue;
|
|
}
|
|
|
|
let info = {
|
|
origin,
|
|
isAllowed: true,
|
|
hasException: this._hasException(origin),
|
|
};
|
|
let hasCookie = false;
|
|
let isTracker = false;
|
|
|
|
// Extract information from the states entries in the content blocking log.
|
|
// Each state will contain a single state flag from nsIWebProgressListener.
|
|
// Note that we are using the same helper functions that are applied to the
|
|
// bit map passed to onSecurityChange (which contains multiple states), thus
|
|
// not checking exact equality, just presence of bits.
|
|
for (let [state, blocked] of actions) {
|
|
if (this.isDetected(state)) {
|
|
hasCookie = true;
|
|
}
|
|
if (TrackingProtection.isAllowing(state)) {
|
|
isTracker = true;
|
|
}
|
|
// blocked tells us whether the resource was actually blocked
|
|
// (which it may not be in case of an exception).
|
|
if (this.isBlocking(state)) {
|
|
info.isAllowed = !blocked;
|
|
}
|
|
}
|
|
|
|
if (!hasCookie) {
|
|
continue;
|
|
}
|
|
|
|
let isFirstParty = false;
|
|
try {
|
|
let uri = Services.io.newURI(origin);
|
|
isFirstParty = Services.eTLD.getBaseDomain(uri) == firstPartyDomain;
|
|
} catch (e) {
|
|
if (
|
|
e.result != Cr.NS_ERROR_HOST_IS_IP_ADDRESS &&
|
|
e.result != Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
|
|
) {
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
if (isFirstParty) {
|
|
newLog.firstParty.push(info);
|
|
} else if (isTracker) {
|
|
newLog.trackers.push(info);
|
|
} else {
|
|
newLog.thirdParty.push(info);
|
|
}
|
|
}
|
|
|
|
return newLog;
|
|
},
|
|
|
|
_createListItem({ origin, isAllowed, hasException }) {
|
|
let listItem = document.createXULElement("hbox");
|
|
listItem.className = "identity-popup-content-blocking-list-item";
|
|
listItem.classList.toggle("allowed", isAllowed);
|
|
// Repeat the origin in the tooltip in case it's too long
|
|
// and overflows in our panel.
|
|
listItem.tooltipText = origin;
|
|
|
|
let image = document.createXULElement("image");
|
|
image.className = "identity-popup-cookiesView-icon";
|
|
image.classList.toggle("allowed", isAllowed);
|
|
listItem.append(image);
|
|
|
|
let label = document.createXULElement("label");
|
|
label.value = origin;
|
|
label.className = "identity-popup-content-blocking-list-host-label";
|
|
label.setAttribute("crop", "end");
|
|
listItem.append(label);
|
|
|
|
let stateLabel;
|
|
if (isAllowed && hasException) {
|
|
stateLabel = document.createXULElement("label");
|
|
stateLabel.value = this.strings.subViewAllowed;
|
|
stateLabel.className = "identity-popup-content-blocking-list-state-label";
|
|
listItem.append(stateLabel);
|
|
} else if (!isAllowed) {
|
|
stateLabel = document.createXULElement("label");
|
|
stateLabel.value = this.strings.subViewBlocked;
|
|
stateLabel.className = "identity-popup-content-blocking-list-state-label";
|
|
listItem.append(stateLabel);
|
|
}
|
|
|
|
if (hasException) {
|
|
let removeException = document.createXULElement("button");
|
|
removeException.className = "identity-popup-permission-remove-button";
|
|
removeException.tooltipText = gNavigatorBundle.getFormattedString(
|
|
"contentBlocking.cookiesView.removeButton.tooltip",
|
|
[origin]
|
|
);
|
|
removeException.addEventListener("click", () => {
|
|
this._clearException(origin);
|
|
// Just flip the display based on what state we had previously.
|
|
stateLabel.value = isAllowed
|
|
? this.strings.subViewBlocked
|
|
: this.strings.subViewAllowed;
|
|
listItem.classList.toggle("allowed", !isAllowed);
|
|
image.classList.toggle("allowed", !isAllowed);
|
|
removeException.hidden = true;
|
|
});
|
|
listItem.append(removeException);
|
|
}
|
|
|
|
return listItem;
|
|
},
|
|
};
|
|
|
|
var ContentBlocking = {
|
|
PREF_ANIMATIONS_ENABLED: "toolkit.cosmeticAnimations.enabled",
|
|
PREF_REPORT_BREAKAGE_ENABLED:
|
|
"browser.contentblocking.reportBreakage.enabled",
|
|
PREF_REPORT_BREAKAGE_URL: "browser.contentblocking.reportBreakage.url",
|
|
PREF_CB_CATEGORY: "browser.contentblocking.category",
|
|
PREF_SHOW_ALLOWED_LABELS:
|
|
"browser.contentblocking.control-center.ui.showAllowedLabels",
|
|
PREF_SHOW_BLOCKED_LABELS:
|
|
"browser.contentblocking.control-center.ui.showBlockedLabels",
|
|
|
|
get content() {
|
|
delete this.content;
|
|
return (this.content = document.getElementById(
|
|
"identity-popup-content-blocking-content"
|
|
));
|
|
},
|
|
|
|
get icon() {
|
|
delete this.icon;
|
|
return (this.icon = document.getElementById("tracking-protection-icon"));
|
|
},
|
|
|
|
get iconBox() {
|
|
delete this.iconBox;
|
|
return (this.iconBox = document.getElementById(
|
|
"tracking-protection-icon-box"
|
|
));
|
|
},
|
|
|
|
get animatedIcon() {
|
|
delete this.animatedIcon;
|
|
return (this.animatedIcon = document.getElementById(
|
|
"tracking-protection-icon-animatable-image"
|
|
));
|
|
},
|
|
|
|
get identityPopupMultiView() {
|
|
delete this.identityPopupMultiView;
|
|
return (this.identityPopupMultiView = document.getElementById(
|
|
"identity-popup-multiView"
|
|
));
|
|
},
|
|
|
|
get reportBreakageButton() {
|
|
delete this.reportBreakageButton;
|
|
return (this.reportBreakageButton = document.getElementById(
|
|
"identity-popup-content-blocking-report-breakage"
|
|
));
|
|
},
|
|
|
|
get reportBreakageURL() {
|
|
delete this.reportBreakageURL;
|
|
return (this.reportBreakageURL = document.getElementById(
|
|
"identity-popup-breakageReportView-collection-url"
|
|
));
|
|
},
|
|
|
|
get reportBreakageLearnMore() {
|
|
delete this.reportBreakageLearnMore;
|
|
return (this.reportBreakageLearnMore = document.getElementById(
|
|
"identity-popup-breakageReportView-learn-more"
|
|
));
|
|
},
|
|
|
|
get appMenuLabel() {
|
|
delete this.appMenuLabel;
|
|
return (this.appMenuLabel = document.getElementById("appMenu-tp-label"));
|
|
},
|
|
|
|
get identityPopup() {
|
|
delete this.identityPopup;
|
|
return (this.identityPopup = document.getElementById("identity-popup"));
|
|
},
|
|
|
|
strings: {
|
|
get appMenuTitle() {
|
|
delete this.appMenuTitle;
|
|
return (this.appMenuTitle = gNavigatorBundle.getString(
|
|
"contentBlocking.title"
|
|
));
|
|
},
|
|
|
|
get appMenuTooltip() {
|
|
delete this.appMenuTooltip;
|
|
if (AppConstants.platform == "win") {
|
|
return (this.appMenuTooltip = gNavigatorBundle.getString(
|
|
"contentBlocking.tooltipWin"
|
|
));
|
|
}
|
|
return (this.appMenuTooltip = gNavigatorBundle.getString(
|
|
"contentBlocking.tooltipOther"
|
|
));
|
|
},
|
|
|
|
get activeTooltipText() {
|
|
delete this.activeTooltipText;
|
|
return (this.activeTooltipText = gNavigatorBundle.getString(
|
|
"trackingProtection.icon.activeTooltip"
|
|
));
|
|
},
|
|
|
|
get disabledTooltipText() {
|
|
delete this.disabledTooltipText;
|
|
return (this.disabledTooltipText = gNavigatorBundle.getString(
|
|
"trackingProtection.icon.disabledTooltip"
|
|
));
|
|
},
|
|
},
|
|
|
|
// A list of blockers that will be displayed in the categories list
|
|
// when blockable content is detected. A blocker must be an object
|
|
// with at least the following two properties:
|
|
// - enabled: Whether the blocker is currently turned on.
|
|
// - isDetected(state): Given a content blocking state, whether the blocker has
|
|
// either allowed or blocked elements.
|
|
// - categoryItem: The DOM item that represents the entry in the category list.
|
|
//
|
|
// It may also contain an init() and uninit() function, which will be called
|
|
// on ContentBlocking.init() and ContentBlocking.uninit().
|
|
blockers: [
|
|
TrackingProtection,
|
|
ThirdPartyCookies,
|
|
Fingerprinting,
|
|
Cryptomining,
|
|
],
|
|
|
|
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() {
|
|
this.animatedIcon.addEventListener("animationend", () =>
|
|
this.iconBox.removeAttribute("animate")
|
|
);
|
|
|
|
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
|
|
this.reportBreakageLearnMore.href = baseURL + "blocking-breakage";
|
|
|
|
this.updateAnimationsEnabled = () => {
|
|
this.iconBox.toggleAttribute(
|
|
"animationsenabled",
|
|
Services.prefs.getBoolPref(this.PREF_ANIMATIONS_ENABLED, false)
|
|
);
|
|
};
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"showBlockedLabels",
|
|
this.PREF_SHOW_BLOCKED_LABELS,
|
|
false,
|
|
() => {
|
|
for (let blocker of this.blockers) {
|
|
blocker.updateCategoryLabel();
|
|
}
|
|
}
|
|
);
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"showAllowedLabels",
|
|
this.PREF_SHOW_ALLOWED_LABELS,
|
|
false,
|
|
() => {
|
|
for (let blocker of this.blockers) {
|
|
blocker.updateCategoryLabel();
|
|
}
|
|
}
|
|
);
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"reportBreakageEnabled",
|
|
this.PREF_REPORT_BREAKAGE_ENABLED,
|
|
false
|
|
);
|
|
|
|
for (let blocker of this.blockers) {
|
|
if (blocker.init) {
|
|
blocker.init();
|
|
}
|
|
}
|
|
|
|
this.updateAnimationsEnabled();
|
|
|
|
Services.prefs.addObserver(
|
|
this.PREF_ANIMATIONS_ENABLED,
|
|
this.updateAnimationsEnabled
|
|
);
|
|
|
|
this.appMenuLabel.setAttribute("value", this.strings.appMenuTitle);
|
|
this.appMenuLabel.setAttribute("tooltiptext", this.strings.appMenuTooltip);
|
|
|
|
this.updateCBCategoryLabel = this.updateCBCategoryLabel.bind(this);
|
|
this.updateCBCategoryLabel();
|
|
Services.prefs.addObserver(
|
|
this.PREF_CB_CATEGORY,
|
|
this.updateCBCategoryLabel
|
|
);
|
|
},
|
|
|
|
uninit() {
|
|
for (let blocker of this.blockers) {
|
|
if (blocker.uninit) {
|
|
blocker.uninit();
|
|
}
|
|
}
|
|
|
|
Services.prefs.removeObserver(
|
|
this.PREF_ANIMATIONS_ENABLED,
|
|
this.updateAnimationsEnabled
|
|
);
|
|
Services.prefs.removeObserver(
|
|
this.PREF_CB_CATEGORY,
|
|
this.updateCBCategoryLabel
|
|
);
|
|
},
|
|
|
|
updateCBCategoryLabel() {
|
|
if (!Services.prefs.prefHasUserValue(this.PREF_CB_CATEGORY)) {
|
|
// Fallback to not setting a label, it's preferable to not set a label than to set an incorrect one.
|
|
return;
|
|
}
|
|
let button = document.getElementById(
|
|
"tracking-protection-preferences-button"
|
|
);
|
|
let appMenuCategoryLabel = document.getElementById("appMenu-tp-category");
|
|
let label;
|
|
let category = Services.prefs.getStringPref(this.PREF_CB_CATEGORY);
|
|
switch (category) {
|
|
case "standard":
|
|
label = gNavigatorBundle.getString("contentBlocking.category.standard");
|
|
break;
|
|
case "strict":
|
|
label = gNavigatorBundle.getString("contentBlocking.category.strict");
|
|
break;
|
|
case "custom":
|
|
label = gNavigatorBundle.getString("contentBlocking.category.custom");
|
|
break;
|
|
}
|
|
appMenuCategoryLabel.value = label;
|
|
button.label = label;
|
|
},
|
|
|
|
hideIdentityPopupAndReload() {
|
|
this.identityPopup.hidePopup();
|
|
BrowserReload();
|
|
},
|
|
|
|
openPreferences(origin) {
|
|
openPreferences("privacy-trackingprotection", { origin });
|
|
},
|
|
|
|
backToMainView() {
|
|
this.identityPopupMultiView.goBack();
|
|
},
|
|
|
|
submitBreakageReport() {
|
|
this.identityPopup.hidePopup();
|
|
|
|
let reportEndpoint = Services.prefs.getStringPref(
|
|
this.PREF_REPORT_BREAKAGE_URL
|
|
);
|
|
if (!reportEndpoint) {
|
|
return;
|
|
}
|
|
|
|
let formData = new FormData();
|
|
formData.set("title", this.reportURI.host);
|
|
|
|
// Leave the ? at the end of the URL to signify that this URL had its query stripped.
|
|
let urlWithoutQuery = this.reportURI.asciiSpec.replace(
|
|
this.reportURI.query,
|
|
""
|
|
);
|
|
let body = `Full URL: ${urlWithoutQuery}\n`;
|
|
body += `userAgent: ${navigator.userAgent}\n`;
|
|
|
|
body += "\n**Preferences**\n";
|
|
body += `${
|
|
TrackingProtection.PREF_ENABLED_GLOBALLY
|
|
}: ${Services.prefs.getBoolPref(
|
|
TrackingProtection.PREF_ENABLED_GLOBALLY
|
|
)}\n`;
|
|
body += `${
|
|
TrackingProtection.PREF_ENABLED_IN_PRIVATE_WINDOWS
|
|
}: ${Services.prefs.getBoolPref(
|
|
TrackingProtection.PREF_ENABLED_IN_PRIVATE_WINDOWS
|
|
)}\n`;
|
|
body += `urlclassifier.trackingTable: ${Services.prefs.getStringPref(
|
|
"urlclassifier.trackingTable"
|
|
)}\n`;
|
|
body += `network.http.referer.defaultPolicy: ${Services.prefs.getIntPref(
|
|
"network.http.referer.defaultPolicy"
|
|
)}\n`;
|
|
body += `network.http.referer.defaultPolicy.pbmode: ${Services.prefs.getIntPref(
|
|
"network.http.referer.defaultPolicy.pbmode"
|
|
)}\n`;
|
|
body += `${ThirdPartyCookies.PREF_ENABLED}: ${Services.prefs.getIntPref(
|
|
ThirdPartyCookies.PREF_ENABLED
|
|
)}\n`;
|
|
body += `network.cookie.lifetimePolicy: ${Services.prefs.getIntPref(
|
|
"network.cookie.lifetimePolicy"
|
|
)}\n`;
|
|
body += `privacy.restrict3rdpartystorage.expiration: ${Services.prefs.getIntPref(
|
|
"privacy.restrict3rdpartystorage.expiration"
|
|
)}\n`;
|
|
body += `${Fingerprinting.PREF_ENABLED}: ${Services.prefs.getBoolPref(
|
|
Fingerprinting.PREF_ENABLED
|
|
)}\n`;
|
|
body += `${Cryptomining.PREF_ENABLED}: ${Services.prefs.getBoolPref(
|
|
Cryptomining.PREF_ENABLED
|
|
)}\n`;
|
|
|
|
let comments = document.getElementById(
|
|
"identity-popup-breakageReportView-collection-comments"
|
|
);
|
|
body += "\n**Comments**\n" + comments.value;
|
|
|
|
formData.set("body", body);
|
|
|
|
let activatedBlockers = [];
|
|
for (let blocker of this.blockers) {
|
|
if (blocker.activated) {
|
|
activatedBlockers.push(blocker.reportBreakageLabel);
|
|
}
|
|
}
|
|
|
|
if (activatedBlockers.length) {
|
|
formData.set("labels", activatedBlockers.join(","));
|
|
}
|
|
|
|
fetch(reportEndpoint, {
|
|
method: "POST",
|
|
credentials: "omit",
|
|
body: formData,
|
|
})
|
|
.then(function(response) {
|
|
if (!response.ok) {
|
|
Cu.reportError(
|
|
`Content Blocking report to ${reportEndpoint} failed with status ${
|
|
response.status
|
|
}`
|
|
);
|
|
} else {
|
|
// Clear the textarea value when the report is submitted
|
|
comments.value = "";
|
|
}
|
|
})
|
|
.catch(Cu.reportError);
|
|
},
|
|
|
|
toggleReportBreakageButton() {
|
|
// For release (due to the large volume) we only want to receive reports
|
|
// for breakage that is directly related to third party cookie blocking.
|
|
if (
|
|
this.reportBreakageEnabled ||
|
|
(ThirdPartyCookies.reportBreakageEnabled &&
|
|
ThirdPartyCookies.activated &&
|
|
!TrackingProtection.activated)
|
|
) {
|
|
this.reportBreakageButton.removeAttribute("hidden");
|
|
} else {
|
|
this.reportBreakageButton.setAttribute("hidden", "true");
|
|
}
|
|
},
|
|
|
|
showReportBreakageSubview() {
|
|
// Save this URI to make sure that the user really only submits the location
|
|
// they see in the report breakage dialog.
|
|
this.reportURI = gBrowser.currentURI;
|
|
let urlWithoutQuery = this.reportURI.asciiSpec.replace(
|
|
"?" + this.reportURI.query,
|
|
""
|
|
);
|
|
this.reportBreakageURL.value = urlWithoutQuery;
|
|
this.identityPopupMultiView.showSubView(
|
|
"identity-popup-breakageReportView"
|
|
);
|
|
},
|
|
|
|
async showTrackersSubview() {
|
|
await TrackingProtection.updateSubView();
|
|
this.identityPopupMultiView.showSubView("identity-popup-trackersView");
|
|
},
|
|
|
|
async showCookiesSubview() {
|
|
await ThirdPartyCookies.updateSubView();
|
|
this.identityPopupMultiView.showSubView("identity-popup-cookiesView");
|
|
},
|
|
|
|
async showFingerprintersSubview() {
|
|
await Fingerprinting.updateSubView();
|
|
this.identityPopupMultiView.showSubView(
|
|
"identity-popup-fingerprintersView"
|
|
);
|
|
},
|
|
|
|
async showCryptominersSubview() {
|
|
await Cryptomining.updateSubView();
|
|
this.identityPopupMultiView.showSubView("identity-popup-cryptominersView");
|
|
},
|
|
|
|
shieldHistogramAdd(value) {
|
|
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
|
|
return;
|
|
}
|
|
Services.telemetry
|
|
.getHistogramById("TRACKING_PROTECTION_SHIELD")
|
|
.add(value);
|
|
},
|
|
|
|
cryptominersHistogramAdd(value) {
|
|
Services.telemetry
|
|
.getHistogramById("CRYPTOMINERS_BLOCKED_COUNT")
|
|
.add(value);
|
|
},
|
|
|
|
fingerprintersHistogramAdd(value) {
|
|
Services.telemetry
|
|
.getHistogramById("FINGERPRINTERS_BLOCKED_COUNT")
|
|
.add(value);
|
|
},
|
|
|
|
// This triggers from top level location changes.
|
|
onLocationChange() {
|
|
// Reset blocking and exception status so that we can send telemetry
|
|
this.hadShieldState = false;
|
|
let baseURI = this._baseURIForChannelClassifier;
|
|
|
|
// Don't deal with about:, file: etc.
|
|
if (!baseURI) {
|
|
return;
|
|
}
|
|
// Add to telemetry per page load as a baseline measurement.
|
|
this.fingerprintersHistogramAdd("pageLoad");
|
|
this.cryptominersHistogramAdd("pageLoad");
|
|
this.shieldHistogramAdd(0);
|
|
},
|
|
|
|
onContentBlockingEvent(event, webProgress, isSimulated) {
|
|
let previousState = gBrowser.securityUI.contentBlockingEvent;
|
|
let baseURI = this._baseURIForChannelClassifier;
|
|
|
|
// Don't deal with about:, file: etc.
|
|
if (!baseURI) {
|
|
this.iconBox.removeAttribute("animate");
|
|
this.iconBox.removeAttribute("active");
|
|
this.iconBox.removeAttribute("hasException");
|
|
return;
|
|
}
|
|
|
|
let anyDetected = false;
|
|
let anyBlocking = false;
|
|
|
|
for (let blocker of this.blockers) {
|
|
// Store data on whether the blocker is activated in the current document for
|
|
// reporting it using the "report breakage" dialog. Under normal circumstances this
|
|
// dialog should only be able to open in the currently selected tab and onSecurityChange
|
|
// runs on tab switch, so we can avoid associating the data with the document directly.
|
|
blocker.activated = blocker.isBlocking(event);
|
|
blocker.categoryItem.classList.toggle("blocked", blocker.enabled);
|
|
let detected = blocker.isDetected(event);
|
|
blocker.categoryItem.hidden = !detected;
|
|
anyDetected = anyDetected || detected;
|
|
anyBlocking = anyBlocking || blocker.activated;
|
|
}
|
|
|
|
let isBrowserPrivate = PrivateBrowsingUtils.isBrowserPrivate(
|
|
gBrowser.selectedBrowser
|
|
);
|
|
|
|
// Check whether the user has added an exception for this site.
|
|
let principal = Services.scriptSecurityManager.createCodebasePrincipal(
|
|
baseURI,
|
|
{}
|
|
);
|
|
let type = isBrowserPrivate
|
|
? "trackingprotection-pb"
|
|
: "trackingprotection";
|
|
let hasException =
|
|
Services.perms.testExactPermissionFromPrincipal(principal, type) ==
|
|
Services.perms.ALLOW_ACTION;
|
|
|
|
// Reset the animation in case the user is switching tabs or if no blockers were detected
|
|
// (this is most likely happening because the user navigated on to a different site). This
|
|
// allows us to play it from the start without choppiness next time.
|
|
if (isSimulated || !anyBlocking) {
|
|
this.iconBox.removeAttribute("animate");
|
|
// Only play the animation when the shield is not already shown on the page (the visibility
|
|
// of the shield based on this onSecurityChange be determined afterwards).
|
|
} else if (anyBlocking && !this.iconBox.hasAttribute("active")) {
|
|
this.iconBox.setAttribute("animate", "true");
|
|
}
|
|
|
|
// We consider the shield state "active" when some kind of blocking activity
|
|
// occurs on the page. Note that merely allowing the loading of content that
|
|
// we could have blocked does not trigger the appearance of the shield.
|
|
// This state will be overriden later if there's an exception set for this site.
|
|
this.content.toggleAttribute("detected", anyDetected);
|
|
this.content.toggleAttribute("blocking", anyBlocking);
|
|
this.content.toggleAttribute("hasException", hasException);
|
|
|
|
this.iconBox.toggleAttribute("active", anyBlocking);
|
|
this.iconBox.toggleAttribute("hasException", hasException);
|
|
|
|
if (hasException) {
|
|
this.iconBox.setAttribute(
|
|
"tooltiptext",
|
|
this.strings.disabledTooltipText
|
|
);
|
|
if (!this.hadShieldState && !isSimulated) {
|
|
this.hadShieldState = true;
|
|
this.shieldHistogramAdd(1);
|
|
}
|
|
} else if (anyBlocking) {
|
|
this.iconBox.setAttribute("tooltiptext", this.strings.activeTooltipText);
|
|
if (!this.hadShieldState && !isSimulated) {
|
|
this.hadShieldState = true;
|
|
this.shieldHistogramAdd(2);
|
|
}
|
|
} else {
|
|
this.iconBox.removeAttribute("tooltiptext");
|
|
}
|
|
|
|
// We report up to one instance of fingerprinting and cryptomining
|
|
// blocking and/or allowing per page load.
|
|
let fingerprintingBlocking =
|
|
Fingerprinting.isBlocking(event) &&
|
|
!Fingerprinting.isBlocking(previousState);
|
|
let fingerprintingAllowing =
|
|
Fingerprinting.isAllowing(event) &&
|
|
!Fingerprinting.isAllowing(previousState);
|
|
let cryptominingBlocking =
|
|
Cryptomining.isBlocking(event) && !Cryptomining.isBlocking(previousState);
|
|
let cryptominingAllowing =
|
|
Cryptomining.isAllowing(event) && !Cryptomining.isAllowing(previousState);
|
|
|
|
if (fingerprintingBlocking) {
|
|
this.fingerprintersHistogramAdd("blocked");
|
|
} else if (fingerprintingAllowing) {
|
|
this.fingerprintersHistogramAdd("allowed");
|
|
}
|
|
|
|
if (cryptominingBlocking) {
|
|
this.cryptominersHistogramAdd("blocked");
|
|
} else if (cryptominingAllowing) {
|
|
this.cryptominersHistogramAdd("allowed");
|
|
}
|
|
},
|
|
|
|
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
|
|
);
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
this.hideIdentityPopupAndReload();
|
|
},
|
|
};
|