ChannelClassifierService.cpp (8137B)
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 "ChannelClassifierService.h" 8 9 #include "mozilla/ClearOnShutdown.h" 10 #include "mozilla/dom/BrowserParent.h" 11 #include "mozilla/dom/BrowsingContext.h" 12 #include "mozilla/dom/CanonicalBrowsingContext.h" 13 #include "mozilla/dom/WindowGlobalParent.h" 14 #include "mozilla/net/UrlClassifierCommon.h" 15 16 #include "UrlClassifierFeatureCryptominingProtection.h" 17 #include "UrlClassifierFeatureFingerprintingProtection.h" 18 #include "UrlClassifierFeatureSocialTrackingProtection.h" 19 #include "UrlClassifierFeatureTrackingProtection.h" 20 21 #include "mozilla/StaticPtr.h" 22 #include "nsIChannel.h" 23 24 namespace mozilla { 25 namespace net { 26 27 static StaticRefPtr<ChannelClassifierService> gChannelClassifierService; 28 29 NS_IMPL_ISUPPORTS(UrlClassifierBlockedChannel, nsIUrlClassifierBlockedChannel) 30 31 UrlClassifierBlockedChannel::UrlClassifierBlockedChannel(nsIChannel* aChannel) 32 : mChannel(aChannel), 33 mDecision(ChannelBlockDecision::Blocked), 34 mReason(TRACKING_PROTECTION) { 35 MOZ_ASSERT(aChannel); 36 } 37 38 NS_IMETHODIMP 39 UrlClassifierBlockedChannel::GetReason(uint8_t* aReason) { 40 NS_ENSURE_ARG_POINTER(aReason); 41 42 *aReason = mReason; 43 return NS_OK; 44 } 45 46 NS_IMETHODIMP 47 UrlClassifierBlockedChannel::GetUrl(nsAString& aUrl) { 48 nsCOMPtr<nsIURI> uri; 49 mChannel->GetURI(getter_AddRefs(uri)); 50 if (uri) { 51 CopyUTF8toUTF16(uri->GetSpecOrDefault(), aUrl); 52 } 53 return NS_OK; 54 } 55 56 NS_IMETHODIMP 57 UrlClassifierBlockedChannel::GetTabId(uint64_t* aTabId) { 58 NS_ENSURE_ARG_POINTER(aTabId); 59 60 *aTabId = 0; 61 62 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo(); 63 MOZ_ASSERT(loadInfo); 64 65 RefPtr<dom::BrowsingContext> browsingContext; 66 nsresult rv = 67 loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext)); 68 if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) { 69 return NS_ERROR_FAILURE; 70 } 71 72 // Get top-level browsing context to ensure window global parent is ready 73 // to use, tabId is the same anyway. 74 dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top(); 75 dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal(); 76 if (!wgp) { 77 return NS_ERROR_FAILURE; 78 } 79 80 RefPtr<dom::BrowserParent> browserParent = wgp->GetBrowserParent(); 81 if (!browserParent) { 82 return NS_ERROR_FAILURE; 83 } 84 85 *aTabId = browserParent->GetTabId(); 86 return NS_OK; 87 } 88 89 NS_IMETHODIMP 90 UrlClassifierBlockedChannel::GetChannelId(uint64_t* aChannelId) { 91 NS_ENSURE_ARG_POINTER(aChannelId); 92 93 nsCOMPtr<nsIIdentChannel> channel(do_QueryInterface(mChannel)); 94 *aChannelId = channel ? channel->ChannelId() : 0; 95 96 return NS_OK; 97 } 98 99 NS_IMETHODIMP 100 UrlClassifierBlockedChannel::GetTopLevelUrl(nsAString& aTopLevelUrl) { 101 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo(); 102 MOZ_ASSERT(loadInfo); 103 104 RefPtr<dom::BrowsingContext> browsingContext; 105 nsresult rv = 106 loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext)); 107 if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) { 108 return NS_ERROR_FAILURE; 109 } 110 111 // Get top-level browsing context to ensure window global parent is ready 112 // to use, tabId is the same anyway. 113 dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top(); 114 dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal(); 115 if (!wgp) { 116 return NS_ERROR_FAILURE; 117 } 118 119 RefPtr<nsIURI> uri = wgp->GetDocumentURI(); 120 if (!uri) { 121 return NS_ERROR_FAILURE; 122 } 123 124 CopyUTF8toUTF16(uri->GetSpecOrDefault(), aTopLevelUrl); 125 return NS_OK; 126 } 127 128 NS_IMETHODIMP 129 UrlClassifierBlockedChannel::GetTables(nsACString& aTables) { 130 aTables.Assign(mTables); 131 return NS_OK; 132 } 133 134 NS_IMETHODIMP 135 UrlClassifierBlockedChannel::GetBrowserId(uint64_t* aBrowserId) { 136 NS_ENSURE_ARG_POINTER(aBrowserId); 137 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo(); 138 MOZ_ASSERT(loadInfo); 139 140 RefPtr<dom::BrowsingContext> browsingContext; 141 nsresult rv = 142 loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext)); 143 if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) { 144 return NS_ERROR_FAILURE; 145 } 146 *aBrowserId = browsingContext->BrowserId(); 147 148 return NS_OK; 149 } 150 151 NS_IMETHODIMP 152 UrlClassifierBlockedChannel::GetIsPrivateBrowsing(bool* aIsPrivateBrowsing) { 153 NS_ENSURE_ARG_POINTER(aIsPrivateBrowsing); 154 155 *aIsPrivateBrowsing = NS_UsePrivateBrowsing(mChannel); 156 return NS_OK; 157 } 158 159 NS_IMETHODIMP 160 UrlClassifierBlockedChannel::Allow() { 161 UC_LOG(("ChannelClassifierService: allow loading the channel %p", 162 mChannel.get())); 163 164 mDecision = ChannelBlockDecision::Allowed; 165 return NS_OK; 166 } 167 168 NS_IMETHODIMP 169 UrlClassifierBlockedChannel::Replace() { 170 UC_LOG(("ChannelClassifierService: replace channel %p", mChannel.get())); 171 172 mDecision = ChannelBlockDecision::Replaced; 173 return NS_OK; 174 } 175 176 void UrlClassifierBlockedChannel::SetReason(const nsACString& aFeatureName, 177 const nsACString& aTableName) { 178 mTables = aTableName; 179 180 nsCOMPtr<nsIUrlClassifierFeature> feature; 181 feature = 182 UrlClassifierFeatureTrackingProtection::GetIfNameMatches(aFeatureName); 183 if (feature) { 184 mReason = TRACKING_PROTECTION; 185 return; 186 } 187 188 feature = UrlClassifierFeatureSocialTrackingProtection::GetIfNameMatches( 189 aFeatureName); 190 if (feature) { 191 mReason = SOCIAL_TRACKING_PROTECTION; 192 return; 193 } 194 195 feature = UrlClassifierFeatureFingerprintingProtection::GetIfNameMatches( 196 aFeatureName); 197 if (feature) { 198 mReason = FINGERPRINTING_PROTECTION; 199 return; 200 } 201 202 feature = UrlClassifierFeatureCryptominingProtection::GetIfNameMatches( 203 aFeatureName); 204 if (feature) { 205 mReason = CRYPTOMINING_PROTECTION; 206 return; 207 } 208 } 209 210 NS_IMPL_ISUPPORTS(ChannelClassifierService, nsIChannelClassifierService) 211 212 // static 213 already_AddRefed<nsIChannelClassifierService> 214 ChannelClassifierService::GetSingleton() { 215 if (gChannelClassifierService) { 216 return do_AddRef(gChannelClassifierService); 217 } 218 219 gChannelClassifierService = new ChannelClassifierService(); 220 ClearOnShutdown(&gChannelClassifierService); 221 return do_AddRef(gChannelClassifierService); 222 } 223 224 ChannelClassifierService::ChannelClassifierService() { mListeners.Clear(); } 225 226 NS_IMETHODIMP 227 ChannelClassifierService::AddListener(nsIObserver* aObserver) { 228 MOZ_ASSERT(aObserver); 229 MOZ_ASSERT(!mListeners.Contains(aObserver)); 230 231 mListeners.AppendElement(aObserver); 232 return NS_OK; 233 } 234 235 NS_IMETHODIMP 236 ChannelClassifierService::RemoveListener(nsIObserver* aObserver) { 237 MOZ_ASSERT(aObserver); 238 MOZ_ASSERT(mListeners.Contains(aObserver)); 239 240 mListeners.RemoveElement(aObserver); 241 return NS_OK; 242 } 243 244 /* static */ 245 ChannelBlockDecision ChannelClassifierService::OnBeforeBlockChannel( 246 nsIChannel* aChannel, const nsACString& aFeatureName, 247 const nsACString& aTableName) { 248 MOZ_ASSERT(aChannel); 249 250 // Don't bother continuing if no one has ever registered listener 251 if (!gChannelClassifierService || !gChannelClassifierService->HasListener()) { 252 return ChannelBlockDecision::Blocked; 253 } 254 255 ChannelBlockDecision decision; 256 nsresult rv = gChannelClassifierService->OnBeforeBlockChannel( 257 aChannel, aFeatureName, aTableName, decision); 258 if (NS_WARN_IF(NS_FAILED(rv))) { 259 return ChannelBlockDecision::Blocked; 260 } 261 262 return decision; 263 } 264 265 nsresult ChannelClassifierService::OnBeforeBlockChannel( 266 nsIChannel* aChannel, const nsACString& aFeatureName, 267 const nsACString& aTableName, ChannelBlockDecision& aDecision) { 268 MOZ_ASSERT(aChannel); 269 270 aDecision = ChannelBlockDecision::Blocked; 271 272 RefPtr<UrlClassifierBlockedChannel> channel = 273 new UrlClassifierBlockedChannel(aChannel); 274 channel->SetReason(aFeatureName, aTableName); 275 276 for (const auto& listener : mListeners) { 277 listener->Observe( 278 NS_ISUPPORTS_CAST(nsIUrlClassifierBlockedChannel*, channel), 279 "urlclassifier-before-block-channel", nullptr); 280 281 aDecision = channel->GetDecision(); 282 } 283 284 return NS_OK; 285 } 286 287 } // namespace net 288 } // namespace mozilla