UrlClassifierFeatureEmailTrackingProtection.cpp (7899B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "UrlClassifierFeatureEmailTrackingProtection.h" 8 9 #include "ChannelClassifierService.h" 10 #include "mozilla/AntiTrackingUtils.h" 11 #include "mozilla/net/UrlClassifierCommon.h" 12 #include "mozilla/StaticPrefs_privacy.h" 13 #include "mozilla/StaticPtr.h" 14 #include "nsIChannel.h" 15 #include "nsILoadContext.h" 16 #include "nsIHttpChannelInternal.h" 17 #include "nsIWebProgressListener.h" 18 #include "nsNetUtil.h" 19 20 namespace mozilla::net { 21 22 namespace { 23 24 #define EMAIL_TRACKING_PROTECTION_FEATURE_NAME "emailtracking-protection" 25 26 #define URLCLASSIFIER_EMAIL_TRACKING_BLOCKLIST \ 27 "urlclassifier.features.emailtracking.blocklistTables" 28 #define URLCLASSIFIER_EMAIL_TRACKING_BLOCKLIST_TEST_ENTRIES \ 29 "urlclassifier.features.emailtracking.blocklistHosts" 30 #define URLCLASSIFIER_EMAIL_TRACKING_ENTITYLIST \ 31 "urlclassifier.features.emailtracking.allowlistTables" 32 #define URLCLASSIFIER_EMAIL_TRACKING_ENTITYLIST_TEST_ENTRIES \ 33 "urlclassifier.features.emailtracking.allowlistHosts" 34 #define URLCLASSIFIER_EMAIL_TRACKING_PROTECTION_EXCEPTION_URLS \ 35 "urlclassifier.features.emailtracking.skipURLs" 36 #define TABLE_EMAIL_TRACKING_BLOCKLIST_PREF "emailtracking-blocklist-pref" 37 #define TABLE_EMAIL_TRACKING_ENTITYLIST_PREF "emailtracking-allowlist-pref" 38 39 StaticRefPtr<UrlClassifierFeatureEmailTrackingProtection> 40 gFeatureEmailTrackingProtection; 41 42 } // namespace 43 44 UrlClassifierFeatureEmailTrackingProtection:: 45 UrlClassifierFeatureEmailTrackingProtection() 46 : UrlClassifierFeatureAntiTrackingBase( 47 nsLiteralCString(EMAIL_TRACKING_PROTECTION_FEATURE_NAME), 48 nsLiteralCString(URLCLASSIFIER_EMAIL_TRACKING_BLOCKLIST), 49 nsLiteralCString(URLCLASSIFIER_EMAIL_TRACKING_ENTITYLIST), 50 nsLiteralCString(URLCLASSIFIER_EMAIL_TRACKING_BLOCKLIST_TEST_ENTRIES), 51 nsLiteralCString( 52 URLCLASSIFIER_EMAIL_TRACKING_ENTITYLIST_TEST_ENTRIES), 53 nsLiteralCString(TABLE_EMAIL_TRACKING_BLOCKLIST_PREF), 54 nsLiteralCString(TABLE_EMAIL_TRACKING_ENTITYLIST_PREF), 55 nsLiteralCString( 56 URLCLASSIFIER_EMAIL_TRACKING_PROTECTION_EXCEPTION_URLS)) {} 57 58 /* static */ 59 const char* UrlClassifierFeatureEmailTrackingProtection::Name() { 60 return EMAIL_TRACKING_PROTECTION_FEATURE_NAME; 61 } 62 63 /* static */ 64 void UrlClassifierFeatureEmailTrackingProtection::MaybeInitialize() { 65 MOZ_ASSERT(XRE_IsParentProcess()); 66 UC_LOG_LEAK(("UrlClassifierFeatureEmailTrackingProtection::MaybeInitialize")); 67 68 if (!gFeatureEmailTrackingProtection) { 69 gFeatureEmailTrackingProtection = 70 new UrlClassifierFeatureEmailTrackingProtection(); 71 gFeatureEmailTrackingProtection->InitializePreferences(); 72 } 73 } 74 75 /* static */ 76 void UrlClassifierFeatureEmailTrackingProtection::MaybeShutdown() { 77 UC_LOG_LEAK(("UrlClassifierFeatureEmailTrackingProtection::MaybeShutdown")); 78 79 if (gFeatureEmailTrackingProtection) { 80 gFeatureEmailTrackingProtection->ShutdownPreferences(); 81 gFeatureEmailTrackingProtection = nullptr; 82 } 83 } 84 85 /* static */ 86 already_AddRefed<UrlClassifierFeatureEmailTrackingProtection> 87 UrlClassifierFeatureEmailTrackingProtection::MaybeCreate(nsIChannel* aChannel) { 88 MOZ_ASSERT(aChannel); 89 90 UC_LOG_LEAK( 91 ("UrlClassifierFeatureEmailTrackingProtection::MaybeCreate - channel %p", 92 aChannel)); 93 94 // Check if the email tracking protection is enabled. 95 if (!StaticPrefs::privacy_trackingprotection_emailtracking_enabled() && 96 !(NS_UsePrivateBrowsing(aChannel) && 97 StaticPrefs:: 98 privacy_trackingprotection_emailtracking_pbmode_enabled())) { 99 return nullptr; 100 } 101 102 RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 103 bool isThirdParty = loadInfo->GetIsThirdPartyContextToTopWindow(); 104 if (!isThirdParty) { 105 UC_LOG( 106 ("UrlClassifierFeatureEmailTrackingProtection::MaybeCreate - " 107 "skipping first party or top-level load for channel %p", 108 aChannel)); 109 return nullptr; 110 } 111 112 if (!UrlClassifierCommon::ShouldEnableProtectionForChannel(aChannel)) { 113 return nullptr; 114 } 115 116 MaybeInitialize(); 117 MOZ_ASSERT(gFeatureEmailTrackingProtection); 118 119 RefPtr<UrlClassifierFeatureEmailTrackingProtection> self = 120 gFeatureEmailTrackingProtection; 121 return self.forget(); 122 } 123 124 /* static */ 125 already_AddRefed<nsIUrlClassifierFeature> 126 UrlClassifierFeatureEmailTrackingProtection::GetIfNameMatches( 127 const nsACString& aName) { 128 if (!aName.EqualsLiteral(EMAIL_TRACKING_PROTECTION_FEATURE_NAME)) { 129 return nullptr; 130 } 131 132 MaybeInitialize(); 133 MOZ_ASSERT(gFeatureEmailTrackingProtection); 134 135 RefPtr<UrlClassifierFeatureEmailTrackingProtection> self = 136 gFeatureEmailTrackingProtection; 137 return self.forget(); 138 } 139 140 NS_IMETHODIMP 141 UrlClassifierFeatureEmailTrackingProtection::ProcessChannel( 142 nsIChannel* aChannel, const nsTArray<nsCString>& aList, 143 const nsTArray<nsCString>& aHashes, bool* aShouldContinue) { 144 NS_ENSURE_ARG_POINTER(aChannel); 145 NS_ENSURE_ARG_POINTER(aShouldContinue); 146 147 bool isAllowListed = UrlClassifierCommon::IsAllowListed(aChannel); 148 149 // This is a blocking feature. 150 *aShouldContinue = isAllowListed; 151 152 if (isAllowListed) { 153 return NS_OK; 154 } 155 156 bool ShouldProcessByProtectionFeature = 157 UrlClassifierCommon::ShouldProcessWithProtectionFeature(aChannel); 158 159 *aShouldContinue = !ShouldProcessByProtectionFeature; 160 161 if (!ShouldProcessByProtectionFeature) { 162 return NS_OK; 163 } 164 165 nsAutoCString list; 166 UrlClassifierCommon::TablesToString(aList, list); 167 168 ChannelBlockDecision decision = 169 ChannelClassifierService::OnBeforeBlockChannel(aChannel, mName, list); 170 if (decision != ChannelBlockDecision::Blocked) { 171 uint32_t event = 172 decision == ChannelBlockDecision::Replaced 173 ? nsIWebProgressListener::STATE_REPLACED_TRACKING_CONTENT 174 : nsIWebProgressListener::STATE_ALLOWED_TRACKING_CONTENT; 175 176 // Need to set aBlocked to True if we replace the Email Tracker with a shim, 177 // since the shim is treated as a blocked event 178 // Note: If we need to account for which kind of tracker was replaced, 179 // we need to create a new event type in nsIWebProgressListener 180 if (event == nsIWebProgressListener::STATE_REPLACED_TRACKING_CONTENT) { 181 ContentBlockingNotifier::OnEvent(aChannel, event, true); 182 } else { 183 ContentBlockingNotifier::OnEvent(aChannel, event, false); 184 } 185 186 *aShouldContinue = true; 187 return NS_OK; 188 } 189 190 UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_EMAILTRACKING_URI, 191 list, ""_ns, ""_ns); 192 193 UC_LOG( 194 ("UrlClassifierFeatureEmailTrackingProtection::ProcessChannel - " 195 "cancelling channel %p", 196 aChannel)); 197 198 nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel); 199 if (httpChannel) { 200 (void)httpChannel->CancelByURLClassifier(NS_ERROR_EMAILTRACKING_URI); 201 } else { 202 (void)aChannel->Cancel(NS_ERROR_EMAILTRACKING_URI); 203 } 204 205 return NS_OK; 206 } 207 208 NS_IMETHODIMP 209 UrlClassifierFeatureEmailTrackingProtection::GetURIByListType( 210 nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType, 211 nsIUrlClassifierFeature::URIType* aURIType, nsIURI** aURI) { 212 NS_ENSURE_ARG_POINTER(aChannel); 213 NS_ENSURE_ARG_POINTER(aURIType); 214 NS_ENSURE_ARG_POINTER(aURI); 215 216 if (aListType == nsIUrlClassifierFeature::blocklist) { 217 *aURIType = nsIUrlClassifierFeature::blocklistURI; 218 return aChannel->GetURI(aURI); 219 } 220 221 MOZ_ASSERT(aListType == nsIUrlClassifierFeature::entitylist); 222 223 *aURIType = nsIUrlClassifierFeature::pairwiseEntitylistURI; 224 return UrlClassifierCommon::CreatePairwiseEntityListURI(aChannel, aURI); 225 } 226 227 } // namespace mozilla::net