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