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 "mozilla/net/UrlClassifierCommon.h"
8 
9 #include "ClassifierDummyChannel.h"
10 #include "mozilla/AntiTrackingUtils.h"
11 #include "mozilla/BasePrincipal.h"
12 #include "mozilla/Components.h"
13 #include "mozilla/ContentBlockingAllowList.h"
14 #include "mozilla/ContentBlockingNotifier.h"
15 #include "mozilla/dom/WindowGlobalParent.h"
16 #include "mozilla/net/HttpBaseChannel.h"
17 #include "mozilla/net/UrlClassifierFeatureFactory.h"
18 #include "mozilla/StaticPrefs_network.h"
19 #include "mozilla/StaticPrefs_privacy.h"
20 #include "mozilla/StaticPrefs_channelclassifier.h"
21 #include "mozilla/StaticPrefs_security.h"
22 #include "mozIThirdPartyUtil.h"
23 #include "nsContentUtils.h"
24 #include "nsIChannel.h"
25 #include "nsIClassifiedChannel.h"
26 #include "mozilla/dom/Document.h"
27 #include "nsIDocShell.h"
28 #include "nsIHttpChannel.h"
29 #include "nsIHttpChannelInternal.h"
30 #include "nsIParentChannel.h"
31 #include "nsIScriptError.h"
32 #include "nsIWebProgressListener.h"
33 #include "nsNetUtil.h"
34 #include "nsQueryObject.h"
35 #include "nsReadableUtils.h"
36 
37 namespace mozilla {
38 namespace net {
39 
40 const nsCString::size_type UrlClassifierCommon::sMaxSpecLength = 128;
41 
42 // MOZ_LOG=nsChannelClassifier:5
43 LazyLogModule UrlClassifierCommon::sLog("nsChannelClassifier");
44 LazyLogModule UrlClassifierCommon::sLogLeak("nsChannelClassifierLeak");
45 
46 /* static */
AddonMayLoad(nsIChannel * aChannel,nsIURI * aURI)47 bool UrlClassifierCommon::AddonMayLoad(nsIChannel* aChannel, nsIURI* aURI) {
48   nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->LoadInfo();
49   // loadingPrincipal is used here to ensure we are loading into an
50   // addon principal.  This allows an addon, with explicit permission, to
51   // call out to API endpoints that may otherwise get blocked.
52   nsIPrincipal* loadingPrincipal = channelLoadInfo->GetLoadingPrincipal();
53   if (!loadingPrincipal) {
54     return false;
55   }
56 
57   return BasePrincipal::Cast(loadingPrincipal)->AddonAllowsLoad(aURI, true);
58 }
59 
60 /* static */
ShouldEnableProtectionForChannel(nsIChannel * aChannel)61 bool UrlClassifierCommon::ShouldEnableProtectionForChannel(
62     nsIChannel* aChannel) {
63   MOZ_ASSERT(aChannel);
64 
65   nsCOMPtr<nsIURI> chanURI;
66   nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
67   if (NS_WARN_IF(NS_FAILED(rv))) {
68     return false;
69   }
70 
71   if (UrlClassifierCommon::AddonMayLoad(aChannel, chanURI)) {
72     return false;
73   }
74 
75   nsCOMPtr<nsIURI> topWinURI;
76   nsCOMPtr<nsIHttpChannelInternal> channel = do_QueryInterface(aChannel);
77   if (NS_WARN_IF(!channel)) {
78     return false;
79   }
80 
81   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
82   MOZ_ASSERT(loadInfo);
83 
84   auto policyType = loadInfo->GetExternalContentPolicyType();
85   if (policyType == ExtContentPolicy::TYPE_DOCUMENT) {
86     UC_LOG(
87         ("UrlClassifierCommon::ShouldEnableProtectionForChannel - "
88          "skipping top-level load for channel %p",
89          aChannel));
90     return false;
91   }
92 
93   // Tracking protection will be enabled so return without updating
94   // the security state. If any channels are subsequently cancelled
95   // (page elements blocked) the state will be then updated.
96 
97   return true;
98 }
99 
100 /* static */
SetTrackingInfo(nsIChannel * aChannel,const nsTArray<nsCString> & aLists,const nsTArray<nsCString> & aFullHashes)101 nsresult UrlClassifierCommon::SetTrackingInfo(
102     nsIChannel* aChannel, const nsTArray<nsCString>& aLists,
103     const nsTArray<nsCString>& aFullHashes) {
104   NS_ENSURE_ARG(!aLists.IsEmpty());
105 
106   // Can be called in EITHER the parent or child process.
107   nsresult rv;
108   nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
109       do_QueryInterface(aChannel, &rv);
110   NS_ENSURE_SUCCESS(rv, rv);
111 
112   if (classifiedChannel) {
113     classifiedChannel->SetMatchedTrackingInfo(aLists, aFullHashes);
114   }
115 
116   nsCOMPtr<nsIParentChannel> parentChannel;
117   NS_QueryNotificationCallbacks(aChannel, parentChannel);
118   if (parentChannel) {
119     // This channel is a parent-process proxy for a child process request.
120     // Tell the child process channel to do this as well.
121     // TODO: We can remove the code sending the IPC to content to update
122     //       tracking info once we move the ContentBlockingLog into the parent.
123     //       This would be done in Bug 1599046.
124     nsAutoCString strLists, strHashes;
125     TablesToString(aLists, strLists);
126     TablesToString(aFullHashes, strHashes);
127 
128     parentChannel->SetClassifierMatchedTrackingInfo(strLists, strHashes);
129   }
130 
131   return NS_OK;
132 }
133 
134 /* static */
SetBlockedContent(nsIChannel * channel,nsresult aErrorCode,const nsACString & aList,const nsACString & aProvider,const nsACString & aFullHash)135 nsresult UrlClassifierCommon::SetBlockedContent(nsIChannel* channel,
136                                                 nsresult aErrorCode,
137                                                 const nsACString& aList,
138                                                 const nsACString& aProvider,
139                                                 const nsACString& aFullHash) {
140   NS_ENSURE_ARG(!aList.IsEmpty());
141 
142   switch (aErrorCode) {
143     case NS_ERROR_MALWARE_URI:
144       NS_SetRequestBlockingReason(
145           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_MALWARE_URI);
146       break;
147     case NS_ERROR_PHISHING_URI:
148       NS_SetRequestBlockingReason(
149           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_PHISHING_URI);
150       break;
151     case NS_ERROR_UNWANTED_URI:
152       NS_SetRequestBlockingReason(
153           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_UNWANTED_URI);
154       break;
155     case NS_ERROR_TRACKING_URI:
156       NS_SetRequestBlockingReason(
157           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_TRACKING_URI);
158       break;
159     case NS_ERROR_BLOCKED_URI:
160       NS_SetRequestBlockingReason(
161           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_BLOCKED_URI);
162       break;
163     case NS_ERROR_HARMFUL_URI:
164       NS_SetRequestBlockingReason(
165           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_HARMFUL_URI);
166       break;
167     case NS_ERROR_CRYPTOMINING_URI:
168       NS_SetRequestBlockingReason(
169           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_CRYPTOMINING_URI);
170       break;
171     case NS_ERROR_FINGERPRINTING_URI:
172       NS_SetRequestBlockingReason(
173           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_FINGERPRINTING_URI);
174       break;
175     case NS_ERROR_SOCIALTRACKING_URI:
176       NS_SetRequestBlockingReason(
177           channel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_SOCIALTRACKING_URI);
178       break;
179     default:
180       MOZ_CRASH(
181           "Missing nsILoadInfo::BLOCKING_REASON* for the classification error");
182       break;
183   }
184 
185   // Can be called in EITHER the parent or child process.
186   nsresult rv;
187   nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
188       do_QueryInterface(channel, &rv);
189   NS_ENSURE_SUCCESS(rv, rv);
190 
191   if (classifiedChannel) {
192     classifiedChannel->SetMatchedInfo(aList, aProvider, aFullHash);
193   }
194 
195   if (XRE_IsParentProcess()) {
196     nsCOMPtr<nsIParentChannel> parentChannel;
197     NS_QueryNotificationCallbacks(channel, parentChannel);
198     if (parentChannel) {
199       // This channel is a parent-process proxy for a child process request.
200       // Tell the child process channel to do this as well.
201       // TODO: We can remove the code sending the IPC to content to update
202       //       matched info once we move the ContentBlockingLog into the parent.
203       //       This would be done in Bug 1601063.
204       parentChannel->SetClassifierMatchedInfo(aList, aProvider, aFullHash);
205     }
206 
207     unsigned state =
208         UrlClassifierFeatureFactory::GetClassifierBlockingEventCode(aErrorCode);
209     if (!state) {
210       state = nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
211     }
212     ContentBlockingNotifier::OnEvent(channel, state);
213 
214     return NS_OK;
215   }
216 
217   // TODO: ReportToConsole is called in the child process,
218   // If nsContentUtils::ReportToConsole is not fission compatiable(cannot report
219   // to correct top-level window), we need to do this in the parent process
220   // instead (find the top-level window in the parent and send an IPC to child
221   // processes to report console).
222   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
223       components::ThirdPartyUtil::Service();
224   if (NS_WARN_IF(!thirdPartyUtil)) {
225     return NS_OK;
226   }
227 
228   nsCOMPtr<nsIURI> uriBeingLoaded =
229       AntiTrackingUtils::MaybeGetDocumentURIBeingLoaded(channel);
230   nsCOMPtr<mozIDOMWindowProxy> win;
231   rv = thirdPartyUtil->GetTopWindowForChannel(channel, uriBeingLoaded,
232                                               getter_AddRefs(win));
233   NS_ENSURE_SUCCESS(rv, NS_OK);
234   auto* pwin = nsPIDOMWindowOuter::From(win);
235   nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
236   if (!docShell) {
237     return NS_OK;
238   }
239   RefPtr<dom::Document> doc = docShell->GetDocument();
240   NS_ENSURE_TRUE(doc, NS_OK);
241 
242   // Log a warning to the web console.
243   nsCOMPtr<nsIURI> uri;
244   channel->GetURI(getter_AddRefs(uri));
245   AutoTArray<nsString, 1> params;
246   CopyUTF8toUTF16(uri->GetSpecOrDefault(), *params.AppendElement());
247   const char* message;
248   nsCString category;
249 
250   if (UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aErrorCode)) {
251     message = UrlClassifierFeatureFactory::
252         ClassifierBlockingErrorCodeToConsoleMessage(aErrorCode, category);
253   } else {
254     message = "UnsafeUriBlocked";
255     category = "Safe Browsing"_ns;
256   }
257 
258   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, category, doc,
259                                   nsContentUtils::eNECKO_PROPERTIES, message,
260                                   params);
261 
262   return NS_OK;
263 }
264 
265 /* static */
GetTopWindowURI(nsIChannel * aChannel,nsIURI ** aURI)266 nsresult UrlClassifierCommon::GetTopWindowURI(nsIChannel* aChannel,
267                                               nsIURI** aURI) {
268   MOZ_ASSERT(XRE_IsParentProcess());
269   MOZ_ASSERT(aChannel);
270 
271   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
272   MOZ_ASSERT(loadInfo);
273 
274   RefPtr<dom::BrowsingContext> browsingContext;
275   nsresult rv =
276       loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
277   if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
278     return NS_ERROR_FAILURE;
279   }
280 
281   dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top();
282   dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal();
283   if (!wgp) {
284     return NS_ERROR_FAILURE;
285   }
286 
287   RefPtr<nsIURI> uri = wgp->GetDocumentURI();
288   if (!uri) {
289     return NS_ERROR_FAILURE;
290   }
291 
292   uri.forget(aURI);
293   return NS_OK;
294 }
295 
296 /* static */
CreatePairwiseEntityListURI(nsIChannel * aChannel,nsIURI ** aURI)297 nsresult UrlClassifierCommon::CreatePairwiseEntityListURI(nsIChannel* aChannel,
298                                                           nsIURI** aURI) {
299   MOZ_ASSERT(aChannel);
300   MOZ_ASSERT(aURI);
301 
302   nsresult rv;
303   nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(aChannel, &rv);
304   NS_ENSURE_SUCCESS(rv, rv);
305   if (!chan) {
306     return NS_ERROR_FAILURE;
307   }
308 
309   nsCOMPtr<nsIURI> topWinURI;
310   rv =
311       UrlClassifierCommon::GetTopWindowURI(aChannel, getter_AddRefs(topWinURI));
312   if (NS_FAILED(rv) || !topWinURI) {
313     // SharedWorker and ServiceWorker don't have an associated window, use
314     // client's URI instead.
315     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
316     MOZ_ASSERT(loadInfo);
317 
318     Maybe<dom::ClientInfo> clientInfo = loadInfo->GetClientInfo();
319     if (clientInfo.isSome()) {
320       if ((clientInfo->Type() == dom::ClientType::Sharedworker) ||
321           (clientInfo->Type() == dom::ClientType::Serviceworker)) {
322         UC_LOG(
323             ("UrlClassifierCommon::CreatePairwiseEntityListURI - "
324              "channel %p initiated by worker, get uri from client",
325              aChannel));
326 
327         auto clientPrincipalOrErr = clientInfo->GetPrincipal();
328         if (clientPrincipalOrErr.isOk()) {
329           nsCOMPtr<nsIPrincipal> principal = clientPrincipalOrErr.unwrap();
330           if (principal) {
331             auto* basePrin = BasePrincipal::Cast(principal);
332             rv = basePrin->GetURI(getter_AddRefs(topWinURI));
333             Unused << NS_WARN_IF(NS_FAILED(rv));
334           }
335         }
336       }
337     }
338 
339     if (!topWinURI) {
340       UC_LOG(
341           ("UrlClassifierCommon::CreatePairwiseEntityListURI - "
342            "no top-level window associated with channel %p, "
343            "get uri from loading principal",
344            aChannel));
345 
346       nsCOMPtr<nsIPrincipal> principal = loadInfo->GetLoadingPrincipal();
347       if (principal) {
348         auto* basePrin = BasePrincipal::Cast(principal);
349         rv = basePrin->GetURI(getter_AddRefs(topWinURI));
350         Unused << NS_WARN_IF(NS_FAILED(rv));
351       }
352     }
353   }
354 
355   if (!topWinURI) {
356     UC_LOG(
357         ("UrlClassifierCommon::CreatePairwiseEntityListURI - "
358          "fail to get top-level window uri for channel %p",
359          aChannel));
360 
361     // Return success because we want to continue to look up even without
362     // whitelist.
363     return NS_OK;
364   }
365 
366   nsCOMPtr<nsIScriptSecurityManager> securityManager =
367       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
368   NS_ENSURE_SUCCESS(rv, rv);
369   nsCOMPtr<nsIPrincipal> chanPrincipal;
370   rv = securityManager->GetChannelURIPrincipal(aChannel,
371                                                getter_AddRefs(chanPrincipal));
372   NS_ENSURE_SUCCESS(rv, rv);
373 
374   // Craft a entitylist URL like "toplevel.page/?resource=third.party.domain"
375   nsAutoCString pageHostname, resourceDomain;
376   rv = topWinURI->GetHost(pageHostname);
377   if (NS_FAILED(rv)) {
378     // When the top-level page doesn't support GetHost, for example, about:home,
379     // we don't return an error here; instead, we return success to make sure
380     // that the lookup process calling this API continues to run.
381     if (UC_LOG_ENABLED()) {
382       nsCString topWinSpec =
383           topWinURI ? topWinURI->GetSpecOrDefault() : "(null)"_ns;
384       topWinSpec.Truncate(
385           std::min(topWinSpec.Length(), UrlClassifierCommon::sMaxSpecLength));
386       UC_LOG(
387           ("UrlClassifierCommon::CreatePairwiseEntityListURI - "
388            "cannot get host from the top-level uri %s of channel %p",
389            topWinSpec.get(), aChannel));
390     }
391     return NS_OK;
392   }
393 
394   rv = chanPrincipal->GetBaseDomain(resourceDomain);
395   NS_ENSURE_SUCCESS(rv, rv);
396   nsAutoCString entitylistEntry =
397       "http://"_ns + pageHostname + "/?resource="_ns + resourceDomain;
398   UC_LOG(
399       ("UrlClassifierCommon::CreatePairwiseEntityListURI - looking for %s in "
400        "the entitylist on channel %p",
401        entitylistEntry.get(), aChannel));
402 
403   nsCOMPtr<nsIURI> entitylistURI;
404   rv = NS_NewURI(getter_AddRefs(entitylistURI), entitylistEntry);
405   NS_ENSURE_SUCCESS(rv, rv);
406 
407   entitylistURI.forget(aURI);
408   return NS_OK;
409 }
410 
411 namespace {
412 
LowerPriorityHelper(nsIChannel * aChannel)413 void LowerPriorityHelper(nsIChannel* aChannel) {
414   MOZ_ASSERT(aChannel);
415 
416   bool isBlockingResource = false;
417 
418   nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
419   if (cos) {
420     if (StaticPrefs::network_http_tailing_enabled()) {
421       uint32_t cosFlags = 0;
422       cos->GetClassFlags(&cosFlags);
423       isBlockingResource =
424           cosFlags & (nsIClassOfService::UrgentStart |
425                       nsIClassOfService::Leader | nsIClassOfService::Unblocked);
426 
427       // Requests not allowed to be tailed are usually those with higher
428       // prioritization.  That overweights being a tracker: don't throttle
429       // them when not in background.
430       if (!(cosFlags & nsIClassOfService::TailForbidden)) {
431         cos->AddClassFlags(nsIClassOfService::Throttleable);
432       }
433     } else {
434       // Yes, we even don't want to evaluate the isBlockingResource when tailing
435       // is off see bug 1395525.
436 
437       cos->AddClassFlags(nsIClassOfService::Throttleable);
438     }
439   }
440 
441   if (!isBlockingResource) {
442     nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aChannel);
443     if (p) {
444       UC_LOG(
445           ("UrlClassifierCommon::LowerPriorityHelper - "
446            "setting PRIORITY_LOWEST for channel %p",
447            aChannel));
448       p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
449     }
450   }
451 }
452 
453 }  // namespace
454 
455 // static
SetClassificationFlagsHelper(nsIChannel * aChannel,uint32_t aClassificationFlags,bool aIsThirdParty)456 void UrlClassifierCommon::SetClassificationFlagsHelper(
457     nsIChannel* aChannel, uint32_t aClassificationFlags, bool aIsThirdParty) {
458   MOZ_ASSERT(aChannel);
459 
460   nsCOMPtr<nsIParentChannel> parentChannel;
461   NS_QueryNotificationCallbacks(aChannel, parentChannel);
462   if (parentChannel) {
463     // This channel is a parent-process proxy for a child process
464     // request. We should notify the child process as well.
465     parentChannel->NotifyClassificationFlags(aClassificationFlags,
466                                              aIsThirdParty);
467   }
468 
469   RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
470   if (httpChannel) {
471     httpChannel->AddClassificationFlags(aClassificationFlags, aIsThirdParty);
472   }
473 
474   RefPtr<ClassifierDummyChannel> dummyChannel = do_QueryObject(aChannel);
475   if (dummyChannel) {
476     dummyChannel->AddClassificationFlags(aClassificationFlags, aIsThirdParty);
477   }
478 }
479 
480 // static
AnnotateChannel(nsIChannel * aChannel,uint32_t aClassificationFlags,uint32_t aLoadingState)481 void UrlClassifierCommon::AnnotateChannel(nsIChannel* aChannel,
482                                           uint32_t aClassificationFlags,
483                                           uint32_t aLoadingState) {
484   MOZ_ASSERT(XRE_IsParentProcess());
485   MOZ_ASSERT(aChannel);
486 
487   nsCOMPtr<nsIURI> chanURI;
488   nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
489   if (NS_WARN_IF(NS_FAILED(rv))) {
490     return;
491   }
492 
493   bool isThirdPartyWithTopLevelWinURI =
494       AntiTrackingUtils::IsThirdPartyChannel(aChannel);
495 
496   SetClassificationFlagsHelper(aChannel, aClassificationFlags,
497                                isThirdPartyWithTopLevelWinURI);
498 
499   // We consider valid tracking flags (based on the current strict vs basic list
500   // prefs) and cryptomining (which is not considered as tracking).
501   bool validClassificationFlags =
502       IsTrackingClassificationFlag(aClassificationFlags) ||
503       IsCryptominingClassificationFlag(aClassificationFlags);
504 
505   if (validClassificationFlags && isThirdPartyWithTopLevelWinURI) {
506     ContentBlockingNotifier::OnEvent(aChannel, aLoadingState);
507   }
508 
509   if (isThirdPartyWithTopLevelWinURI &&
510       StaticPrefs::privacy_trackingprotection_lower_network_priority()) {
511     LowerPriorityHelper(aChannel);
512   }
513 }
514 
515 // static
IsAllowListed(nsIChannel * aChannel)516 bool UrlClassifierCommon::IsAllowListed(nsIChannel* aChannel) {
517   nsCOMPtr<nsIHttpChannelInternal> channel = do_QueryInterface(aChannel);
518   if (NS_WARN_IF(!channel)) {
519     return false;
520   }
521 
522   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
523 
524   bool isAllowListed = false;
525   if (StaticPrefs::channelclassifier_allowlist_example()) {
526     UC_LOG(
527         ("UrlClassifierCommon::IsAllowListed - "
528          "check allowlisting test domain on channel %p",
529          aChannel));
530 
531     nsCOMPtr<nsIIOService> ios = components::IO::Service();
532     if (NS_WARN_IF(!ios)) {
533       return false;
534     }
535 
536     nsCOMPtr<nsIURI> uri;
537     nsresult rv = ios->NewURI("http://allowlisted.example.com"_ns, nullptr,
538                               nullptr, getter_AddRefs(uri));
539     if (NS_WARN_IF(NS_FAILED(rv))) {
540       return false;
541     }
542     nsCOMPtr<nsIPrincipal> cbAllowListPrincipal =
543         BasePrincipal::CreateContentPrincipal(uri,
544                                               loadInfo->GetOriginAttributes());
545 
546     rv = ContentBlockingAllowList::Check(
547         cbAllowListPrincipal, NS_UsePrivateBrowsing(aChannel), isAllowListed);
548     if (NS_WARN_IF(NS_FAILED(rv))) {
549       return false;
550     }
551   } else {
552     nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
553     MOZ_ALWAYS_SUCCEEDS(
554         loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings)));
555     isAllowListed = cookieJarSettings->GetIsOnContentBlockingAllowList();
556   }
557 
558   if (isAllowListed) {
559     UC_LOG(("UrlClassifierCommon::IsAllowListed - user override on channel %p",
560             aChannel));
561   }
562 
563   return isAllowListed;
564 }
565 
566 // static
IsTrackingClassificationFlag(uint32_t aFlag)567 bool UrlClassifierCommon::IsTrackingClassificationFlag(uint32_t aFlag) {
568   if (StaticPrefs::privacy_annotate_channels_strict_list_enabled() &&
569       (aFlag & nsIClassifiedChannel::ClassificationFlags::
570                    CLASSIFIED_ANY_STRICT_TRACKING)) {
571     return true;
572   }
573 
574   if (StaticPrefs::privacy_socialtracking_block_cookies_enabled() &&
575       IsSocialTrackingClassificationFlag(aFlag)) {
576     return true;
577   }
578 
579   return (
580       aFlag &
581       nsIClassifiedChannel::ClassificationFlags::CLASSIFIED_ANY_BASIC_TRACKING);
582 }
583 
584 // static
IsSocialTrackingClassificationFlag(uint32_t aFlag)585 bool UrlClassifierCommon::IsSocialTrackingClassificationFlag(uint32_t aFlag) {
586   return (aFlag & nsIClassifiedChannel::ClassificationFlags::
587                       CLASSIFIED_ANY_SOCIAL_TRACKING) != 0;
588 }
589 
590 // static
IsCryptominingClassificationFlag(uint32_t aFlag)591 bool UrlClassifierCommon::IsCryptominingClassificationFlag(uint32_t aFlag) {
592   if (aFlag &
593       nsIClassifiedChannel::ClassificationFlags::CLASSIFIED_CRYPTOMINING) {
594     return true;
595   }
596 
597   if (StaticPrefs::privacy_annotate_channels_strict_list_enabled() &&
598       (aFlag & nsIClassifiedChannel::ClassificationFlags::
599                    CLASSIFIED_CRYPTOMINING_CONTENT)) {
600     return true;
601   }
602 
603   return false;
604 }
605 
TablesToString(const nsTArray<nsCString> & aList,nsACString & aString)606 void UrlClassifierCommon::TablesToString(const nsTArray<nsCString>& aList,
607                                          nsACString& aString) {
608   // Truncate and append rather than assigning because that's more efficient if
609   // aString is an nsAutoCString.
610   aString.Truncate();
611   StringJoinAppend(aString, ","_ns, aList);
612 }
613 
TablesToClassificationFlags(const nsTArray<nsCString> & aList,const std::vector<ClassificationData> & aData,uint32_t aDefaultFlag)614 uint32_t UrlClassifierCommon::TablesToClassificationFlags(
615     const nsTArray<nsCString>& aList,
616     const std::vector<ClassificationData>& aData, uint32_t aDefaultFlag) {
617   uint32_t flags = 0;
618   for (const nsCString& table : aList) {
619     flags |= TableToClassificationFlag(table, aData);
620   }
621 
622   if (flags == 0) {
623     flags |= aDefaultFlag;
624   }
625 
626   return flags;
627 }
628 
TableToClassificationFlag(const nsACString & aTable,const std::vector<ClassificationData> & aData)629 uint32_t UrlClassifierCommon::TableToClassificationFlag(
630     const nsACString& aTable, const std::vector<ClassificationData>& aData) {
631   for (const ClassificationData& data : aData) {
632     if (StringBeginsWith(aTable, data.mPrefix)) {
633       return data.mFlag;
634     }
635   }
636 
637   return 0;
638 }
639 
640 /* static */
IsPassiveContent(nsIChannel * aChannel)641 bool UrlClassifierCommon::IsPassiveContent(nsIChannel* aChannel) {
642   MOZ_ASSERT(aChannel);
643 
644   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
645   ExtContentPolicyType contentType = loadInfo->GetExternalContentPolicyType();
646 
647   // Return true if aChannel is loading passive display content, as
648   // defined by the mixed content blocker.
649   // https://searchfox.org/mozilla-central/rev/c80fa7258c935223fe319c5345b58eae85d4c6ae/dom/security/nsMixedContentBlocker.cpp#532
650   return contentType == ExtContentPolicy::TYPE_IMAGE ||
651          contentType == ExtContentPolicy::TYPE_MEDIA ||
652          (contentType == ExtContentPolicy::TYPE_OBJECT_SUBREQUEST &&
653           !StaticPrefs::security_mixed_content_block_object_subrequest());
654 }
655 
656 }  // namespace net
657 }  // namespace mozilla
658