From a51e62a348bedd3abd093b0cddfcf6f7624ff6db Mon Sep 17 00:00:00 2001 From: William Wen Date: Tue, 25 Mar 2025 14:58:20 +0000 Subject: [PATCH] Bug 1950984 - Add consent manager annotation feature. r=timhuang Differential Revision: https://phabricator.services.mozilla.com/D241467 --- modules/libpref/init/StaticPrefList.yaml | 7 + .../url-classifier/UrlClassifierCommon.cpp | 25 +++ netwerk/url-classifier/UrlClassifierCommon.h | 3 + ...ssifierFeatureConsentManagerAnnotation.cpp | 187 ++++++++++++++++++ ...lassifierFeatureConsentManagerAnnotation.h | 49 +++++ .../UrlClassifierFeatureFactory.cpp | 23 +++ netwerk/url-classifier/moz.build | 1 + .../url-classifier/SafeBrowsing.sys.mjs | 18 ++ 8 files changed, 313 insertions(+) create mode 100644 netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.cpp create mode 100644 netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.h diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 2a3f18c21fec..34779227cd4f 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -15544,6 +15544,13 @@ value: false mirror: always +# Annotate channels based on the consent manager list +# Note: consent manager annotations will be disabled if tracking protection is disabled +- name: privacy.trackingprotection.consentmanager.annotate_channels + type: bool + value: true + mirror: always + # Whether to spoof user locale to English (used as part of Resist # Fingerprinting). # 0 - will prompt diff --git a/netwerk/url-classifier/UrlClassifierCommon.cpp b/netwerk/url-classifier/UrlClassifierCommon.cpp index e8f6ac82e806..dc41170f9a2f 100644 --- a/netwerk/url-classifier/UrlClassifierCommon.cpp +++ b/netwerk/url-classifier/UrlClassifierCommon.cpp @@ -515,6 +515,31 @@ void UrlClassifierCommon::AnnotateChannel(nsIChannel* aChannel, } } +// static +void UrlClassifierCommon::AnnotateChannelWithoutNotifying( + nsIChannel* aChannel, uint32_t aClassificationFlags) { + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(aChannel); + + nsCOMPtr chanURI; + nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + RefPtr loadInfo = aChannel->LoadInfo(); + bool isThirdPartyWithTopLevelWinURI = + loadInfo->GetIsThirdPartyContextToTopWindow(); + + SetClassificationFlagsHelper(aChannel, aClassificationFlags, + isThirdPartyWithTopLevelWinURI); + + if (isThirdPartyWithTopLevelWinURI && + StaticPrefs::privacy_trackingprotection_lower_network_priority()) { + LowerPriorityHelper(aChannel); + } +} + // static bool UrlClassifierCommon::IsAllowListed(nsIChannel* aChannel) { nsCOMPtr channel = do_QueryInterface(aChannel); diff --git a/netwerk/url-classifier/UrlClassifierCommon.h b/netwerk/url-classifier/UrlClassifierCommon.h index c1d92ef981c8..2541c49235b4 100644 --- a/netwerk/url-classifier/UrlClassifierCommon.h +++ b/netwerk/url-classifier/UrlClassifierCommon.h @@ -59,6 +59,9 @@ class UrlClassifierCommon final { uint32_t aClassificationFlags, uint32_t aLoadingState); + static void AnnotateChannelWithoutNotifying(nsIChannel* aChannel, + uint32_t aClassificationFlags); + static bool IsAllowListed(nsIChannel* aChannel); static bool IsTrackingClassificationFlag(uint32_t aFlag, bool aIsPrivate); diff --git a/netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.cpp b/netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.cpp new file mode 100644 index 000000000000..d1c8b7807aec --- /dev/null +++ b/netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.cpp @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "UrlClassifierFeatureConsentManagerAnnotation.h" + +#include "Classifier.h" +#include "mozilla/Logging.h" +#include "mozilla/StaticPrefs_privacy.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/net/UrlClassifierCommon.h" +#include "nsIChannel.h" +#include "nsIClassifiedChannel.h" +#include "nsIWebProgressListener.h" +#include "nsContentUtils.h" + +namespace mozilla { +namespace net { + +namespace { + +#define CONSENTMANAGER_ANNOTATION_FEATURE_NAME "consentmanager-annotation" + +#define URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_BLOCKLIST \ + "urlclassifier.features.consentmanager.annotate.blocklistTables" +#define URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_BLOCKLIST_TEST_ENTRIES \ + "urlclassifier.features.consentmanager.annotate.blocklistHosts" +#define URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_ENTITYLIST \ + "urlclassifier.features.consentmanager.annotate.allowlistTables" +#define URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_ENTITYLIST_TEST_ENTRIES \ + "urlclassifier.features.consentmanager.annotate.allowlistHosts" +#define URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_EXCEPTION_URLS \ + "urlclassifier.features.consentmanager.annotate.skipURLs" +#define TABLE_CONSENTMANAGER_ANNOTATION_BLOCKLIST_PREF \ + "consentmanager-annotate-blocklist-pref" +#define TABLE_CONSENTMANAGER_ANNOTATION_ENTITYLIST_PREF \ + "consentmanager-annotate-allowlist-pref" + +static StaticRefPtr + gFeatureConsentManagerAnnotation; + +} // namespace + +UrlClassifierFeatureConsentManagerAnnotation:: + UrlClassifierFeatureConsentManagerAnnotation() + : UrlClassifierFeatureAntiTrackingBase( + nsLiteralCString(CONSENTMANAGER_ANNOTATION_FEATURE_NAME), + nsLiteralCString(URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_BLOCKLIST), + nsLiteralCString(URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_ENTITYLIST), + nsLiteralCString( + URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_BLOCKLIST_TEST_ENTRIES), + nsLiteralCString( + URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_ENTITYLIST_TEST_ENTRIES), + nsLiteralCString(TABLE_CONSENTMANAGER_ANNOTATION_BLOCKLIST_PREF), + nsLiteralCString(TABLE_CONSENTMANAGER_ANNOTATION_ENTITYLIST_PREF), + nsLiteralCString( + URLCLASSIFIER_CONSENTMANAGER_ANNOTATION_EXCEPTION_URLS)) {} + +/* static */ const char* UrlClassifierFeatureConsentManagerAnnotation::Name() { + return CONSENTMANAGER_ANNOTATION_FEATURE_NAME; +} + +/* static */ +void UrlClassifierFeatureConsentManagerAnnotation::MaybeInitialize() { + MOZ_ASSERT(XRE_IsParentProcess()); + UC_LOG_LEAK( + ("UrlClassifierFeatureConsentManagerAnnotation::MaybeInitialize")); + + if (!gFeatureConsentManagerAnnotation) { + gFeatureConsentManagerAnnotation = + new UrlClassifierFeatureConsentManagerAnnotation(); + gFeatureConsentManagerAnnotation->InitializePreferences(); + } +} + +/* static */ +void UrlClassifierFeatureConsentManagerAnnotation::MaybeShutdown() { + UC_LOG_LEAK(("UrlClassifierFeatureConsentManagerAnnotation::MaybeShutdown")); + + if (gFeatureConsentManagerAnnotation) { + gFeatureConsentManagerAnnotation->ShutdownPreferences(); + gFeatureConsentManagerAnnotation = nullptr; + } +} + +/* static */ +already_AddRefed +UrlClassifierFeatureConsentManagerAnnotation::MaybeCreate( + nsIChannel* aChannel) { + MOZ_ASSERT(aChannel); + + UC_LOG_LEAK( + ("UrlClassifierFeatureConsentManagerAnnotation::MaybeCreate - channel %p", + aChannel)); + + if (!StaticPrefs:: + privacy_trackingprotection_consentmanager_annotate_channels()) { + return nullptr; + } + + // We also don't need to annotate the channel if we are not blocking trackers + if (!StaticPrefs::privacy_trackingprotection_enabled() && + !(NS_UsePrivateBrowsing(aChannel) && + StaticPrefs::privacy_trackingprotection_pbmode_enabled())) { + return nullptr; + } + + MaybeInitialize(); + MOZ_ASSERT(gFeatureConsentManagerAnnotation); + + RefPtr self = + gFeatureConsentManagerAnnotation; + return self.forget(); +} + +/* static */ +already_AddRefed +UrlClassifierFeatureConsentManagerAnnotation::GetIfNameMatches( + const nsACString& aName) { + if (!aName.EqualsLiteral(CONSENTMANAGER_ANNOTATION_FEATURE_NAME)) { + return nullptr; + } + + MaybeInitialize(); + MOZ_ASSERT(gFeatureConsentManagerAnnotation); + + RefPtr self = + gFeatureConsentManagerAnnotation; + return self.forget(); +} + +NS_IMETHODIMP +UrlClassifierFeatureConsentManagerAnnotation::ProcessChannel( + nsIChannel* aChannel, const nsTArray& aList, + const nsTArray& aHashes, bool* aShouldContinue) { + NS_ENSURE_ARG_POINTER(aChannel); + NS_ENSURE_ARG_POINTER(aShouldContinue); + + // This is not a blocking feature. + *aShouldContinue = true; + + UC_LOG( + ("UrlClassifierFeatureConsentManagerAnnotation::ProcessChannel - " + "annotating channel %p", + aChannel)); + + static std::vector + sClassificationData = { + {"consent-manager-track-"_ns, + nsIClassifiedChannel::ClassificationFlags:: + CLASSIFIED_CONSENTMANAGER}, + }; + + uint32_t flags = UrlClassifierCommon::TablesToClassificationFlags( + aList, sClassificationData, + nsIClassifiedChannel::ClassificationFlags::CLASSIFIED_CONSENTMANAGER); + + UrlClassifierCommon::SetTrackingInfo(aChannel, aList, aHashes); + + UrlClassifierCommon::AnnotateChannelWithoutNotifying(aChannel, flags); + + return NS_OK; +} + +NS_IMETHODIMP +UrlClassifierFeatureConsentManagerAnnotation::GetURIByListType( + nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType, + nsIUrlClassifierFeature::URIType* aURIType, nsIURI** aURI) { + NS_ENSURE_ARG_POINTER(aChannel); + NS_ENSURE_ARG_POINTER(aURIType); + NS_ENSURE_ARG_POINTER(aURI); + + if (aListType == nsIUrlClassifierFeature::blocklist) { + *aURIType = nsIUrlClassifierFeature::blocklistURI; + return aChannel->GetURI(aURI); + } + + MOZ_ASSERT(aListType == nsIUrlClassifierFeature::entitylist); + + *aURIType = nsIUrlClassifierFeature::pairwiseEntitylistURI; + return UrlClassifierCommon::CreatePairwiseEntityListURI(aChannel, aURI); +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.h b/netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.h new file mode 100644 index 000000000000..52d573e15100 --- /dev/null +++ b/netwerk/url-classifier/UrlClassifierFeatureConsentManagerAnnotation.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_net_UrlClassifierFeatureConsentManagerAnnotation_h +#define mozilla_net_UrlClassifierFeatureConsentManagerAnnotation_h + +#include "UrlClassifierFeatureBase.h" + +class nsIChannel; + +namespace mozilla { +namespace net { + +class UrlClassifierFeatureConsentManagerAnnotation final + : public UrlClassifierFeatureAntiTrackingBase { + public: + static const char* Name(); + + static void MaybeShutdown(); + + static already_AddRefed + MaybeCreate(nsIChannel* aChannel); + + static already_AddRefed GetIfNameMatches( + const nsACString& aName); + + NS_IMETHOD ProcessChannel(nsIChannel* aChannel, + const nsTArray& aList, + const nsTArray& aHashes, + bool* aShouldContinue) override; + + NS_IMETHOD GetURIByListType(nsIChannel* aChannel, + nsIUrlClassifierFeature::listType aListType, + nsIUrlClassifierFeature::URIType* aURIType, + nsIURI** aURI) override; + + private: + UrlClassifierFeatureConsentManagerAnnotation(); + + static void MaybeInitialize(); +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_UrlClassifierFeatureConsentManagerAnnotation_h diff --git a/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp b/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp index 35b3b457eb12..97aacd219fdc 100644 --- a/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp +++ b/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp @@ -9,6 +9,7 @@ // List of Features #include "UrlClassifierFeatureCryptominingAnnotation.h" #include "UrlClassifierFeatureCryptominingProtection.h" +#include "UrlClassifierFeatureConsentManagerAnnotation.h" #include "UrlClassifierFeatureEmailTrackingDataCollection.h" #include "UrlClassifierFeatureEmailTrackingProtection.h" #include "UrlClassifierFeatureFingerprintingAnnotation.h" @@ -35,6 +36,7 @@ void UrlClassifierFeatureFactory::Shutdown() { UrlClassifierFeatureCryptominingAnnotation::MaybeShutdown(); UrlClassifierFeatureCryptominingProtection::MaybeShutdown(); + UrlClassifierFeatureConsentManagerAnnotation::MaybeShutdown(); UrlClassifierFeatureEmailTrackingDataCollection::MaybeShutdown(); UrlClassifierFeatureEmailTrackingProtection::MaybeShutdown(); UrlClassifierFeatureFingerprintingAnnotation::MaybeShutdown(); @@ -70,6 +72,14 @@ void UrlClassifierFeatureFactory::GetFeaturesFromChannel( aFeatures.AppendElement(feature); } + // Consent Manager Annotation + // This must be run before any blocking features because the annotation will + // affect whether the channel should be blocked. + feature = UrlClassifierFeatureConsentManagerAnnotation::MaybeCreate(aChannel); + if (feature) { + aFeatures.AppendElement(feature); + } + // Email Tracking Protection feature = UrlClassifierFeatureEmailTrackingProtection::MaybeCreate(aChannel); if (feature) { @@ -152,6 +162,13 @@ UrlClassifierFeatureFactory::GetFeatureByName(const nsACString& aName) { return feature.forget(); } + // Consent Manager Annotation + feature = + UrlClassifierFeatureConsentManagerAnnotation::GetIfNameMatches(aName); + if (feature) { + return feature.forget(); + } + // Email Tracking Data Collection feature = UrlClassifierFeatureEmailTrackingDataCollection::GetIfNameMatches(aName); @@ -235,6 +252,12 @@ void UrlClassifierFeatureFactory::GetFeatureNames(nsTArray& aArray) { aArray.AppendElement(name); } + // Consent Manager Annotation + name.Assign(UrlClassifierFeatureConsentManagerAnnotation::Name()); + if (!name.IsEmpty()) { + aArray.AppendElement(name); + } + // Email Tracking Data Collection name.Assign(UrlClassifierFeatureEmailTrackingDataCollection::Name()); if (!name.IsEmpty()) { diff --git a/netwerk/url-classifier/moz.build b/netwerk/url-classifier/moz.build index d63206780e50..089693818226 100644 --- a/netwerk/url-classifier/moz.build +++ b/netwerk/url-classifier/moz.build @@ -33,6 +33,7 @@ UNIFIED_SOURCES += [ "nsChannelClassifier.cpp", "UrlClassifierCommon.cpp", "UrlClassifierFeatureBase.cpp", + "UrlClassifierFeatureConsentManagerAnnotation.cpp", "UrlClassifierFeatureCryptominingAnnotation.cpp", "UrlClassifierFeatureCryptominingProtection.cpp", "UrlClassifierFeatureCustomTables.cpp", diff --git a/toolkit/components/url-classifier/SafeBrowsing.sys.mjs b/toolkit/components/url-classifier/SafeBrowsing.sys.mjs index 5f0b5faec8ac..2cb201b1a9bc 100644 --- a/toolkit/components/url-classifier/SafeBrowsing.sys.mjs +++ b/toolkit/components/url-classifier/SafeBrowsing.sys.mjs @@ -278,6 +278,24 @@ const FEATURES = [ ); }, }, + { + name: "consentmanager-annotation", + list: [ + "urlclassifier.features.consentmanager.annotate.blocklistTables", + "urlclassifier.features.consentmanager.annotate.allowlistTables", + ], + enabled() { + return Services.prefs.getBoolPref( + "privacy.trackingprotection.consentmanager.annotate_channels" + ); + }, + update() { + return Services.prefs.getBoolPref( + "browser.safebrowsing.features.consentmanager.annotate.update", + this.enabled() + ); + }, + }, ]; export var SafeBrowsing = {