diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index ce470b54f141..f570c89ca920 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -710,6 +710,7 @@ @RESPATH@/components/nsUrlClassifierHashCompleter.js @RESPATH@/components/nsUrlClassifierListManager.js @RESPATH@/components/nsUrlClassifierLib.js +@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js @RESPATH@/components/url-classifier.xpt ; GNOME hooks diff --git a/browser/base/content/browser-trackingprotection.js b/browser/base/content/browser-trackingprotection.js index 2d97dc858869..29f72bcf703f 100644 --- a/browser/base/content/browser-trackingprotection.js +++ b/browser/base/content/browser-trackingprotection.js @@ -116,8 +116,12 @@ let TrackingProtection = { // 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. - Services.perms.add(normalizedUrl, - "trackingprotection", Services.perms.ALLOW_ACTION); + if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) { + PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl); + } else { + Services.perms.add(normalizedUrl, + "trackingprotection", Services.perms.ALLOW_ACTION); + } // Telemetry for disable protection. this.eventsHistogram.add(1); @@ -133,8 +137,11 @@ let TrackingProtection = { "https://" + gBrowser.selectedBrowser.currentURI.hostPort, null, null); - Services.perms.remove(normalizedUrl, - "trackingprotection"); + if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) { + PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl); + } else { + Services.perms.remove(normalizedUrl, "trackingprotection"); + } // Telemetry for enable protection. this.eventsHistogram.add(2); diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 48e5d17b7485..3e3f86fabf10 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -637,6 +637,7 @@ @RESPATH@/components/nsUrlClassifierHashCompleter.js @RESPATH@/components/nsUrlClassifierListManager.js @RESPATH@/components/nsUrlClassifierLib.js +@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js @RESPATH@/components/url-classifier.xpt #endif diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 234d05aedb35..72a80fbbc6e9 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1759,13 +1759,21 @@ var BrowserApp = { // 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 white list. - Services.perms.add(normalizedUrl, "trackingprotection", Services.perms.ALLOW_ACTION); + if (PrivateBrowsingUtils.isBrowserPrivate(browser)) { + PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl); + } else { + Services.perms.add(normalizedUrl, "trackingprotection", Services.perms.ALLOW_ACTION); + } Telemetry.addData("TRACKING_PROTECTION_EVENTS", 1); } else { // Remove the current host from the 'trackingprotection' consumer // of the permission manager. This effectively removes this host // from the tracking protection white list (any list actually). - Services.perms.remove(normalizedUrl, "trackingprotection"); + if (PrivateBrowsingUtils.isBrowserPrivate(browser)) { + PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl); + } else { + Services.perms.remove(normalizedUrl, "trackingprotection"); + } Telemetry.addData("TRACKING_PROTECTION_EVENTS", 2); } } diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index e7afddef9195..bc9271cac366 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -480,6 +480,7 @@ @BINPATH@/components/nsUrlClassifierHashCompleter.js @BINPATH@/components/nsUrlClassifierListManager.js @BINPATH@/components/nsUrlClassifierLib.js +@BINPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js @BINPATH@/components/url-classifier.xpt #endif diff --git a/netwerk/base/nsChannelClassifier.cpp b/netwerk/base/nsChannelClassifier.cpp index bdc8a004ac51..b217b0444b58 100644 --- a/netwerk/base/nsChannelClassifier.cpp +++ b/netwerk/base/nsChannelClassifier.cpp @@ -19,6 +19,7 @@ #include "nsIIOService.h" #include "nsIParentChannel.h" #include "nsIPermissionManager.h" +#include "nsIPrivateBrowsingTrackingProtectionWhitelist.h" #include "nsIProtocolHandler.h" #include "nsIScriptError.h" #include "nsIScriptSecurityManager.h" @@ -163,6 +164,25 @@ nsChannelClassifier::ShouldEnableTrackingProtection(nsIChannel *aChannel, *result = true; } + // In Private Browsing Mode we also check against an in-memory list. + if (NS_UsePrivateBrowsing(aChannel)) { + nsCOMPtr pbmtpWhitelist = + do_GetService(NS_PBTRACKINGPROTECTIONWHITELIST_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + bool exists = false; + rv = pbmtpWhitelist->ExistsInAllowList(topWinURI, &exists); + NS_ENSURE_SUCCESS(rv, rv); + + if (exists) { + mIsAllowListed = true; + LOG(("nsChannelClassifier[%p]: Allowlisting channel[%p] in PBM for %s", + this, aChannel, escaped.get())); + } + + *result = !exists; + } + // Tracking protection will be enabled so return without updating // the security state. If any channels are subsequently cancelled // (page elements blocked) the state will be then updated. diff --git a/toolkit/components/url-classifier/PrivateBrowsingTrackingProtectionWhitelist.js b/toolkit/components/url-classifier/PrivateBrowsingTrackingProtectionWhitelist.js new file mode 100644 index 000000000000..5c1c27874d41 --- /dev/null +++ b/toolkit/components/url-classifier/PrivateBrowsingTrackingProtectionWhitelist.js @@ -0,0 +1,68 @@ +/* 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 Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +function PrivateBrowsingTrackingProtectionWhitelist() { + // The list of URIs explicitly excluded from tracking protection. + this._allowlist = []; + + Services.obs.addObserver(this, "last-pb-context-exited", true); +} + +PrivateBrowsingTrackingProtectionWhitelist.prototype = { + classID: Components.ID("{a319b616-c45d-4037-8d86-01c592b5a9af}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrivateBrowsingTrackingProtectionWhitelist, + Ci.nsIObserver, + Ci.nsISupportsWeakReference, + Ci.nsISupports]), + _xpcom_factory: XPCOMUtils.generateSingletonFactory(PrivateBrowsingTrackingProtectionWhitelist), + + /** + * Add the provided URI to the list of allowed tracking sites. + * + * @param uri nsIURI + * The URI to add to the list. + */ + addToAllowList(uri) { + if (this._allowlist.indexOf(uri.spec) === -1) { + this._allowlist.push(uri.spec); + } + }, + + /** + * Remove the provided URI from the list of allowed tracking sites. + * + * @param uri nsIURI + * The URI to add to the list. + */ + removeFromAllowList(uri) { + let index = this._allowlist.indexOf(uri.spec); + if (index !== -1) { + this._allowlist.splice(index, 1); + } + }, + + /** + * Check if the provided URI exists in the list of allowed tracking sites. + * + * @param uri nsIURI + * The URI to add to the list. + */ + existsInAllowList(uri) { + return this._allowlist.indexOf(uri.spec) !== -1; + }, + + observe: function (subject, topic, data) { + if (topic == "last-pb-context-exited") { + this._allowlist = []; + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PrivateBrowsingTrackingProtectionWhitelist]); diff --git a/toolkit/components/url-classifier/moz.build b/toolkit/components/url-classifier/moz.build index 169de362426d..22a48caea393 100644 --- a/toolkit/components/url-classifier/moz.build +++ b/toolkit/components/url-classifier/moz.build @@ -7,6 +7,7 @@ TEST_DIRS += ['tests'] XPIDL_SOURCES += [ + 'nsIPrivateBrowsingTrackingProtectionWhitelist.idl', 'nsIUrlClassifierDBService.idl', 'nsIUrlClassifierHashCompleter.idl', 'nsIUrlClassifierPrefixSet.idl', @@ -42,6 +43,7 @@ SOURCES += [ EXTRA_COMPONENTS += [ 'nsURLClassifier.manifest', 'nsUrlClassifierHashCompleter.js', + 'PrivateBrowsingTrackingProtectionWhitelist.js', ] # Same as JS components that are run through the pre-processor. diff --git a/toolkit/components/url-classifier/nsIPrivateBrowsingTrackingProtectionWhitelist.idl b/toolkit/components/url-classifier/nsIPrivateBrowsingTrackingProtectionWhitelist.idl new file mode 100644 index 000000000000..c3621ce233f9 --- /dev/null +++ b/toolkit/components/url-classifier/nsIPrivateBrowsingTrackingProtectionWhitelist.idl @@ -0,0 +1,46 @@ +/* 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/. */ + +#include "nsISupports.idl" + +interface nsIURI; + +/** + * The Private Browsing Tracking Protection service checks a URI against an + * in-memory list of tracking sites. + */ +[scriptable, uuid(c77ddfac-6cd6-43a9-84e8-91682a1a7b18)] +interface nsIPrivateBrowsingTrackingProtectionWhitelist : nsISupports +{ + /** + * Add a URI to the list of allowed tracking sites in Private Browsing mode + * (essentially a tracking whitelist). This operation will cause the URI to + * be registered if it does not currently exist. If it already exists, then + * the operation is essentially a no-op. + * + * @param uri the uri to add to the list + */ + void addToAllowList(in nsIURI uri); + + /** + * Remove a URI from the list of allowed tracking sites in Private Browsing + * mode (the tracking whitelist). If the URI is not already in the list, + * then the operation is essentially a no-op. + * + * @param uri the uri to remove from the list + */ + void removeFromAllowList(in nsIURI uri); + + /** + * Check if a URI exists in the list of allowed tracking sites in Private + * Browsing mode (the tracking whitelist). + * + * @param uri the uri to look for in the list + */ + bool existsInAllowList(in nsIURI uri); +}; + +%{ C++ +#define NS_PBTRACKINGPROTECTIONWHITELIST_CONTRACTID "@mozilla.org/url-classifier/pbm-tp-whitelist;1" +%} diff --git a/toolkit/components/url-classifier/nsURLClassifier.manifest b/toolkit/components/url-classifier/nsURLClassifier.manifest index f035dea80953..fa5e41d45548 100644 --- a/toolkit/components/url-classifier/nsURLClassifier.manifest +++ b/toolkit/components/url-classifier/nsURLClassifier.manifest @@ -4,3 +4,5 @@ component {ca168834-cc00-48f9-b83c-fd018e58cae3} nsUrlClassifierListManager.js contract @mozilla.org/url-classifier/listmanager;1 {ca168834-cc00-48f9-b83c-fd018e58cae3} component {9111de73-9322-4bfc-8b65-2b727f3e6ec8} nsUrlClassifierHashCompleter.js contract @mozilla.org/url-classifier/hashcompleter;1 {9111de73-9322-4bfc-8b65-2b727f3e6ec8} +component {a319b616-c45d-4037-8d86-01c592b5a9af} PrivateBrowsingTrackingProtectionWhitelist.js +contract @mozilla.org/url-classifier/pbm-tp-whitelist;1 {a319b616-c45d-4037-8d86-01c592b5a9af} diff --git a/toolkit/modules/PrivateBrowsingUtils.jsm b/toolkit/modules/PrivateBrowsingUtils.jsm index f322347fa380..8eec35dd7808 100644 --- a/toolkit/modules/PrivateBrowsingUtils.jsm +++ b/toolkit/modules/PrivateBrowsingUtils.jsm @@ -51,6 +51,18 @@ this.PrivateBrowsingUtils = { .QueryInterface(Ci.nsILoadContext); }, + addToTrackingAllowlist(aURI) { + let pbmtpWhitelist = Cc["@mozilla.org/url-classifier/pbm-tp-whitelist;1"] + .getService(Ci.nsIPrivateBrowsingTrackingProtectionWhitelist); + pbmtpWhitelist.addToAllowList(aURI); + }, + + removeFromTrackingAllowlist(aURI) { + let pbmtpWhitelist = Cc["@mozilla.org/url-classifier/pbm-tp-whitelist;1"] + .getService(Ci.nsIPrivateBrowsingTrackingProtectionWhitelist); + pbmtpWhitelist.removeFromAllowList(aURI); + }, + get permanentPrivateBrowsing() { try { return gTemporaryAutoStartMode ||