Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/components/antitracking/AntiTrackingCommon.cpp
Line
Count
Source (jump to first uncovered line)
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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "AntiTrackingCommon.h"
8
9
#include "mozilla/dom/ContentChild.h"
10
#include "mozilla/ipc/MessageChannel.h"
11
#include "mozilla/AbstractThread.h"
12
#include "mozilla/IntegerPrintfMacros.h"
13
#include "mozilla/Logging.h"
14
#include "mozilla/StaticPrefs.h"
15
#include "mozIThirdPartyUtil.h"
16
#include "nsContentUtils.h"
17
#include "nsGlobalWindowInner.h"
18
#include "nsCookiePermission.h"
19
#include "nsICookieService.h"
20
#include "nsIDocShell.h"
21
#include "nsIHttpChannelInternal.h"
22
#include "nsIIOService.h"
23
#include "nsIParentChannel.h"
24
#include "nsIPermission.h"
25
#include "nsIPermissionManager.h"
26
#include "nsIPrincipal.h"
27
#include "nsIScriptError.h"
28
#include "nsIURI.h"
29
#include "nsIURL.h"
30
#include "nsIWebProgressListener.h"
31
#include "nsNetUtil.h"
32
#include "nsPIDOMWindow.h"
33
#include "nsScriptSecurityManager.h"
34
#include "nsSandboxFlags.h"
35
#include "prtime.h"
36
37
0
#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
38
0
#define USER_INTERACTION_PERM "storageAccessAPI"
39
40
using namespace mozilla;
41
using mozilla::dom::ContentChild;
42
43
static LazyLogModule gAntiTrackingLog("AntiTracking");
44
static const nsCString::size_type sMaxSpecLength = 128;
45
46
0
#define LOG(format) MOZ_LOG(gAntiTrackingLog, mozilla::LogLevel::Debug, format)
47
48
#define LOG_SPEC(format, uri)                                                 \
49
0
  PR_BEGIN_MACRO                                                              \
50
0
    if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug)) {           \
51
0
      nsAutoCString _specStr(NS_LITERAL_CSTRING("(null)"));                   \
52
0
      _specStr.Truncate(std::min(_specStr.Length(), sMaxSpecLength));         \
53
0
      if (uri) {                                                              \
54
0
        _specStr = uri->GetSpecOrDefault();                                   \
55
0
      }                                                                       \
56
0
      const char* _spec = _specStr.get();                                     \
57
0
      LOG(format);                                                            \
58
0
    }                                                                         \
59
0
  PR_END_MACRO
60
61
namespace {
62
63
bool
64
GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner* a3rdPartyTrackingWindow,
65
                                    nsIPrincipal** aTopLevelStoragePrincipal,
66
                                    nsACString& aTrackingOrigin)
67
0
{
68
0
  if (!nsContentUtils::IsTrackingResourceWindow(a3rdPartyTrackingWindow)) {
69
0
    return false;
70
0
  }
71
0
72
0
  nsIDocument* doc = a3rdPartyTrackingWindow->GetDocument();
73
0
  // Make sure storage access isn't disabled
74
0
  if (doc && ((doc->GetSandboxFlags() & SANDBOXED_STORAGE_ACCESS) != 0 ||
75
0
              nsContentUtils::IsInPrivateBrowsing(doc))) {
76
0
    return false;
77
0
  }
78
0
79
0
  // Now we need the principal and the origin of the parent window.
80
0
  nsCOMPtr<nsIPrincipal> topLevelStoragePrincipal =
81
0
    a3rdPartyTrackingWindow->GetTopLevelStorageAreaPrincipal();
82
0
  if (NS_WARN_IF(!topLevelStoragePrincipal)) {
83
0
    return false;
84
0
  }
85
0
86
0
  // Let's take the principal and the origin of the tracker.
87
0
  nsIPrincipal* trackingPrincipal = a3rdPartyTrackingWindow->GetPrincipal();
88
0
  if (NS_WARN_IF(!trackingPrincipal)) {
89
0
    return false;
90
0
  }
91
0
92
0
  nsresult rv = trackingPrincipal->GetOriginNoSuffix(aTrackingOrigin);
93
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
94
0
    return false;
95
0
  }
96
0
97
0
  topLevelStoragePrincipal.forget(aTopLevelStoragePrincipal);
98
0
  return true;
99
0
};
100
101
void
102
CreatePermissionKey(const nsCString& aTrackingOrigin,
103
                    const nsCString& aGrantedOrigin,
104
                    nsACString& aPermissionKey)
105
0
{
106
0
  if (aTrackingOrigin == aGrantedOrigin) {
107
0
    aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s",
108
0
                                     aTrackingOrigin.get());
109
0
    return;
110
0
  }
111
0
112
0
  aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s",
113
0
                                   aTrackingOrigin.get(),
114
0
                                   aGrantedOrigin.get());
115
0
}
116
117
// This internal method returns ACCESS_DENY if the access is denied,
118
// ACCESS_DEFAULT if unknown, some other access code if granted.
119
nsCookieAccess
120
CheckCookiePermissionForPrincipal(nsIPrincipal* aPrincipal)
121
0
{
122
0
  nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT;
123
0
  if (!aPrincipal->GetIsCodebasePrincipal()) {
124
0
    return access;
125
0
  }
126
0
127
0
  nsCOMPtr<nsICookiePermission> cps = nsCookiePermission::GetOrCreate();
128
0
129
0
  nsresult rv = cps->CanAccess(aPrincipal, &access);
130
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
131
0
    return access;
132
0
  }
133
0
134
0
  // If we have a custom cookie permission, let's use it.
135
0
  return access;
136
0
}
137
138
int32_t
139
CookiesBehavior(nsIPrincipal* aPrincipal)
140
0
{
141
0
  // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
142
0
  // (See Bug 1406675 for rationale).
143
0
  if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
144
0
    return nsICookieService::BEHAVIOR_ACCEPT;
145
0
  }
146
0
147
0
  return StaticPrefs::network_cookie_cookieBehavior();
148
0
}
149
150
bool
151
CheckContentBlockingAllowList(nsIURI* aTopWinURI)
152
0
{
153
0
  bool isAllowed = false;
154
0
  nsresult rv =
155
0
    AntiTrackingCommon::IsOnContentBlockingAllowList(aTopWinURI,
156
0
                                                     AntiTrackingCommon::eStorageChecks,
157
0
                                                     isAllowed);
158
0
  if (NS_SUCCEEDED(rv) && isAllowed) {
159
0
    LOG_SPEC(("The top-level window (%s) is on the content blocking allow list, "
160
0
              "bail out early", _spec), aTopWinURI);
161
0
    return true;
162
0
  }
163
0
  if (NS_FAILED(rv)) {
164
0
    LOG_SPEC(("Checking the content blocking allow list for %s failed with %" PRIx32,
165
0
              _spec, static_cast<uint32_t>(rv)), aTopWinURI);
166
0
  }
167
0
  return false;
168
0
}
169
170
bool
171
CheckContentBlockingAllowList(nsPIDOMWindowInner* aWindow)
172
0
{
173
0
  nsPIDOMWindowOuter* top = aWindow->GetScriptableTop();
174
0
  if (top) {
175
0
    nsIURI* topWinURI = top->GetDocumentURI();
176
0
    return CheckContentBlockingAllowList(topWinURI);
177
0
  }
178
0
179
0
  LOG(("Could not check the content blocking allow list because the top "
180
0
       "window wasn't accessible"));
181
0
  return false;
182
0
}
183
184
bool
185
CheckContentBlockingAllowList(nsIHttpChannel* aChannel)
186
0
{
187
0
  nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(aChannel);
188
0
  if (chan) {
189
0
    nsCOMPtr<nsIURI> topWinURI;
190
0
    nsresult rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
191
0
    if (NS_SUCCEEDED(rv)) {
192
0
      return CheckContentBlockingAllowList(topWinURI);
193
0
    }
194
0
  }
195
0
196
0
  LOG(("Could not check the content blocking allow list because the top "
197
0
       "window wasn't accessible"));
198
0
  return false;
199
0
}
200
201
void
202
ReportBlockingToConsole(nsPIDOMWindowOuter* aWindow, nsIHttpChannel* aChannel,
203
                        uint32_t aRejectedReason)
204
0
{
205
0
  MOZ_ASSERT(aWindow && aChannel);
206
0
  MOZ_ASSERT(aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION ||
207
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER ||
208
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL ||
209
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN ||
210
0
             aRejectedReason == nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT);
211
0
212
0
  if (!AntiTrackingCommon::ShouldHonorContentBlockingCookieRestrictions()) {
213
0
    return;
214
0
  }
215
0
216
0
  nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
217
0
  if (NS_WARN_IF(!docShell)) {
218
0
    return;
219
0
  }
220
0
221
0
  nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
222
0
  if (NS_WARN_IF(!doc)) {
223
0
    return;
224
0
  }
225
0
226
0
  const char* message = nullptr;
227
0
  switch (aRejectedReason) {
228
0
    case nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION:
229
0
      message = "CookieBlockedByPermission";
230
0
      break;
231
0
232
0
    case nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER:
233
0
      message = "CookieBlockedTracker";
234
0
      break;
235
0
236
0
    case nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL:
237
0
      message = "CookieBlockedAll";
238
0
      break;
239
0
240
0
    case nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN:
241
0
      message = "CookieBlockedForeign";
242
0
      break;
243
0
244
0
    case nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT:
245
0
      message = "CookieBlockedSlowTrackingContent";
246
0
      break;
247
0
248
0
    default:
249
0
      return;
250
0
  }
251
0
252
0
  MOZ_ASSERT(message);
253
0
254
0
  nsCOMPtr<nsIURI> uri;
255
0
  aChannel->GetURI(getter_AddRefs(uri));
256
0
  NS_ConvertUTF8toUTF16 spec(uri->GetSpecOrDefault());
257
0
  const char16_t* params[] = { spec.get() };
258
0
259
0
  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
260
0
                                  NS_LITERAL_CSTRING("Content Blocking"),
261
0
                                  doc,
262
0
                                  nsContentUtils::eNECKO_PROPERTIES,
263
0
                                  message,
264
0
                                  params, ArrayLength(params));
265
0
}
266
267
void
268
ReportUnblockingConsole(nsPIDOMWindowInner* aWindow,
269
                        const nsAString& aTrackingOrigin,
270
                        const nsAString& aGrantedOrigin,
271
                        AntiTrackingCommon::StorageAccessGrantedReason aReason)
272
0
{
273
0
  nsCOMPtr<nsIPrincipal> principal =
274
0
    nsGlobalWindowInner::Cast(aWindow)->GetPrincipal();
275
0
  if (NS_WARN_IF(!principal)) {
276
0
    return;
277
0
  }
278
0
279
0
  nsAutoString origin;
280
0
  nsresult rv = nsContentUtils::GetUTFOrigin(principal, origin);
281
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
282
0
    return;
283
0
  }
284
0
285
0
  nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
286
0
  if (NS_WARN_IF(!docShell)) {
287
0
    return;
288
0
  }
289
0
290
0
  nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
291
0
  if (NS_WARN_IF(!doc)) {
292
0
    return;
293
0
  }
294
0
295
0
  const char16_t* params[] = { origin.BeginReading(),
296
0
                               aTrackingOrigin.BeginReading(),
297
0
                               aGrantedOrigin.BeginReading() };
298
0
  const char* messageWithDifferentOrigin = nullptr;
299
0
  const char *messageWithSameOrigin = nullptr;
300
0
301
0
  switch (aReason) {
302
0
    case AntiTrackingCommon::eStorageAccessAPI:
303
0
      messageWithDifferentOrigin = "CookieAllowedForOriginOnTrackerByStorageAccessAPI";
304
0
      messageWithSameOrigin = "CookieAllowedForTrackerByStorageAccessAPI";
305
0
      break;
306
0
307
0
    case AntiTrackingCommon::eHeuristic:
308
0
      messageWithDifferentOrigin = "CookieAllowedForOriginOnTrackerByHeuristic";
309
0
      messageWithSameOrigin = "CookieAllowedForTrackerByHeuristic";
310
0
      break;
311
0
  }
312
0
313
0
  if (aTrackingOrigin == aGrantedOrigin) {
314
0
    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
315
0
                                    NS_LITERAL_CSTRING("Content Blocking"),
316
0
                                    doc,
317
0
                                    nsContentUtils::eNECKO_PROPERTIES,
318
0
                                    messageWithSameOrigin,
319
0
                                    params, 2);
320
0
  } else {
321
0
    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
322
0
                                    NS_LITERAL_CSTRING("Content Blocking"),
323
0
                                    doc,
324
0
                                    nsContentUtils::eNECKO_PROPERTIES,
325
0
                                    messageWithDifferentOrigin,
326
0
                                    params, 3);
327
0
  }
328
0
}
329
330
} // anonymous
331
332
/* static */ bool
333
AntiTrackingCommon::ShouldHonorContentBlockingCookieRestrictions()
334
0
{
335
0
  return StaticPrefs::browser_contentblocking_enabled() &&
336
0
         StaticPrefs::browser_contentblocking_ui_enabled();
337
0
}
338
339
/* static */ RefPtr<AntiTrackingCommon::StorageAccessGrantPromise>
340
AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin,
341
                                                         nsPIDOMWindowInner* aParentWindow,
342
                                                         StorageAccessGrantedReason aReason)
343
0
{
344
0
  MOZ_ASSERT(aParentWindow);
345
0
346
0
  LOG(("Adding a first-party storage exception for %s...",
347
0
       NS_ConvertUTF16toUTF8(aOrigin).get()));
348
0
349
0
  if (StaticPrefs::network_cookie_cookieBehavior() !=
350
0
        nsICookieService::BEHAVIOR_REJECT_TRACKER) {
351
0
    LOG(("Disabled by network.cookie.cookieBehavior pref (%d), bailing out early",
352
0
         StaticPrefs::network_cookie_cookieBehavior()));
353
0
    return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
354
0
  }
355
0
356
0
  if (!ShouldHonorContentBlockingCookieRestrictions()) {
357
0
    LOG(("The content blocking pref has been disabled, bail out early"));
358
0
    return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
359
0
  }
360
0
361
0
  if (CheckContentBlockingAllowList(aParentWindow)) {
362
0
    return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
363
0
  }
364
0
365
0
  nsCOMPtr<nsIPrincipal> topLevelStoragePrincipal;
366
0
  nsAutoCString trackingOrigin;
367
0
368
0
  nsGlobalWindowInner* parentWindow = nsGlobalWindowInner::Cast(aParentWindow);
369
0
  nsGlobalWindowOuter* outerParentWindow =
370
0
    nsGlobalWindowOuter::Cast(parentWindow->GetOuterWindow());
371
0
  if (NS_WARN_IF(!outerParentWindow)) {
372
0
    LOG(("No outer window found for our parent window, bailing out early"));
373
0
    return StorageAccessGrantPromise::CreateAndReject(false, __func__);
374
0
  }
375
0
376
0
  LOG(("The current resource is %s-party",
377
0
       outerParentWindow->IsTopLevelWindow() ? "first" : "third"));
378
0
379
0
  // We are a first party resource.
380
0
  if (outerParentWindow->IsTopLevelWindow()) {
381
0
    CopyUTF16toUTF8(aOrigin, trackingOrigin);
382
0
    topLevelStoragePrincipal = parentWindow->GetPrincipal();
383
0
    if (NS_WARN_IF(!topLevelStoragePrincipal)) {
384
0
      LOG(("Top-level storage area principal not found, bailing out early"));
385
0
      return StorageAccessGrantPromise::CreateAndReject(false, __func__);
386
0
    }
387
0
388
0
  // We are a 3rd party source.
389
0
  } else if (!GetParentPrincipalAndTrackingOrigin(parentWindow,
390
0
                                                  getter_AddRefs(topLevelStoragePrincipal),
391
0
                                                  trackingOrigin)) {
392
0
    LOG(("Error while computing the parent principal and tracking origin, bailing out early"));
393
0
    return StorageAccessGrantPromise::CreateAndReject(false, __func__);
394
0
  }
395
0
396
0
  NS_ConvertUTF16toUTF8 grantedOrigin(aOrigin);
397
0
398
0
  ReportUnblockingConsole(aParentWindow, NS_ConvertUTF8toUTF16(trackingOrigin),
399
0
                          aOrigin, aReason);
400
0
401
0
  if (XRE_IsParentProcess()) {
402
0
    LOG(("Saving the permission: trackingOrigin=%s, grantedOrigin=%s",
403
0
         trackingOrigin.get(), grantedOrigin.get()));
404
0
405
0
    RefPtr<StorageAccessGrantPromise::Private> p = new StorageAccessGrantPromise::Private(__func__);
406
0
    SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(topLevelStoragePrincipal,
407
0
                                                               trackingOrigin,
408
0
                                                               grantedOrigin,
409
0
                                                               [p] (bool success) {
410
0
                                                                 p->Resolve(success, __func__);
411
0
                                                               });
412
0
    return p;
413
0
  }
414
0
415
0
  ContentChild* cc = ContentChild::GetSingleton();
416
0
  MOZ_ASSERT(cc);
417
0
418
0
  LOG(("Asking the parent process to save the permission for us: trackingOrigin=%s, grantedOrigin=%s",
419
0
       trackingOrigin.get(), grantedOrigin.get()));
420
0
421
0
  // This is not really secure, because here we have the content process sending
422
0
  // the request of storing a permission.
423
0
  RefPtr<StorageAccessGrantPromise::Private> p = new StorageAccessGrantPromise::Private(__func__);
424
0
  cc->SendFirstPartyStorageAccessGrantedForOrigin(IPC::Principal(topLevelStoragePrincipal),
425
0
                                                  trackingOrigin,
426
0
                                                  grantedOrigin)
427
0
    ->Then(GetCurrentThreadSerialEventTarget(), __func__,
428
0
           [p] (bool success) {
429
0
             p->Resolve(success, __func__);
430
0
           }, [p] (ipc::ResponseRejectReason aReason) {
431
0
             p->Reject(false, __func__);
432
0
           });
433
0
  return p;
434
0
}
435
436
/* static */ void
437
AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aParentPrincipal,
438
                                                                               const nsCString& aTrackingOrigin,
439
                                                                               const nsCString& aGrantedOrigin,
440
                                                                               FirstPartyStorageAccessGrantedForOriginResolver&& aResolver)
441
0
{
442
0
  MOZ_ASSERT(XRE_IsParentProcess());
443
0
444
0
  nsCOMPtr<nsIURI> parentPrincipalURI;
445
0
  Unused << aParentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
446
0
  LOG_SPEC(("Saving a first-party storage permission on %s for trackingOrigin=%s grantedOrigin=%s",
447
0
            _spec, aTrackingOrigin.get(), aGrantedOrigin.get()), parentPrincipalURI);
448
0
449
0
  if (NS_WARN_IF(!aParentPrincipal)) {
450
0
    // The child process is sending something wrong. Let's ignore it.
451
0
    LOG(("aParentPrincipal is null, bailing out early"));
452
0
    aResolver(false);
453
0
    return;
454
0
  }
455
0
456
0
  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
457
0
  if (NS_WARN_IF(!pm)) {
458
0
    LOG(("Permission manager is null, bailing out early"));
459
0
    aResolver(false);
460
0
    return;
461
0
  }
462
0
463
0
  // Remember that this pref is stored in seconds!
464
0
  uint32_t expirationType = nsIPermissionManager::EXPIRE_TIME;
465
0
  uint32_t expirationTime =
466
0
    StaticPrefs::privacy_restrict3rdpartystorage_expiration() * 1000;
467
0
  int64_t when = (PR_Now() / PR_USEC_PER_MSEC) + expirationTime;
468
0
469
0
  uint32_t privateBrowsingId = 0;
470
0
  nsresult rv = aParentPrincipal->GetPrivateBrowsingId(&privateBrowsingId);
471
0
  if (!NS_WARN_IF(NS_FAILED(rv)) && privateBrowsingId > 0) {
472
0
    // If we are coming from a private window, make sure to store a session-only
473
0
    // permission which won't get persisted to disk.
474
0
    expirationType = nsIPermissionManager::EXPIRE_SESSION;
475
0
    when = 0;
476
0
  }
477
0
478
0
  nsAutoCString type;
479
0
  CreatePermissionKey(aTrackingOrigin, aGrantedOrigin, type);
480
0
481
0
  LOG(("Computed permission key: %s, expiry: %d, proceeding to save in the permission manager",
482
0
       type.get(), expirationTime));
483
0
484
0
  rv = pm->AddFromPrincipal(aParentPrincipal, type.get(),
485
0
                            nsIPermissionManager::ALLOW_ACTION,
486
0
                            expirationType, when);
487
0
  Unused << NS_WARN_IF(NS_FAILED(rv));
488
0
  aResolver(NS_SUCCEEDED(rv));
489
0
490
0
  LOG(("Result: %s", NS_SUCCEEDED(rv) ? "success" : "failure"));
491
0
}
492
493
bool
494
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aWindow,
495
                                                        nsIURI* aURI,
496
                                                        uint32_t* aRejectedReason)
497
0
{
498
0
  MOZ_ASSERT(aWindow);
499
0
  MOZ_ASSERT(aURI);
500
0
501
0
  // Let's avoid a null check on aRejectedReason everywhere else.
502
0
  uint32_t rejectedReason = 0;
503
0
  if (!aRejectedReason) {
504
0
    aRejectedReason = &rejectedReason;
505
0
  }
506
0
507
0
  LOG_SPEC(("Computing whether window %p has access to URI %s", aWindow, _spec), aURI);
508
0
509
0
  nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
510
0
  nsIPrincipal* toplevelPrincipal = innerWindow->GetTopLevelPrincipal();
511
0
  if (!toplevelPrincipal) {
512
0
    // We are already the top-level principal. Let's use the window's principal.
513
0
    LOG(("Our inner window lacks a top-level principal, use the window's principal instead"));
514
0
    toplevelPrincipal = innerWindow->GetPrincipal();
515
0
  }
516
0
517
0
  if (!toplevelPrincipal) {
518
0
    // This should not be possible, right?
519
0
    LOG(("No top-level principal, this shouldn't be happening! Bail out early"));
520
0
    return false;
521
0
  }
522
0
523
0
  nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal);
524
0
  if (access != nsICookiePermission::ACCESS_DEFAULT) {
525
0
    LOG(("CheckCookiePermissionForPrincipal() returned a non-default access code (%d), returning %s",
526
0
         int(access), access != nsICookiePermission::ACCESS_DENY ?
527
0
                        "success" : "failure"));
528
0
    if (access != nsICookiePermission::ACCESS_DENY) {
529
0
      return true;
530
0
    }
531
0
532
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
533
0
    return false;
534
0
  }
535
0
536
0
  int32_t behavior = CookiesBehavior(toplevelPrincipal);
537
0
  if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
538
0
    LOG(("The cookie behavior pref mandates accepting all cookies!"));
539
0
    return true;
540
0
  }
541
0
542
0
  if (behavior == nsICookieService::BEHAVIOR_REJECT) {
543
0
    LOG(("The cookie behavior pref mandates rejecting all cookies!"));
544
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
545
0
    return false;
546
0
  }
547
0
548
0
  // Let's check if this is a 3rd party context.
549
0
  if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, nullptr, aURI)) {
550
0
    LOG(("Our window isn't a third-party window"));
551
0
    return true;
552
0
  }
553
0
554
0
  if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
555
0
    // Now, we have to also honour the Content Blocking pref.
556
0
    if (!ShouldHonorContentBlockingCookieRestrictions()) {
557
0
      LOG(("The content blocking pref has been disabled, bail out early by "
558
0
           "by pretending our window isn't a third-party window"));
559
0
      return true;
560
0
    }
561
0
562
0
    if (CheckContentBlockingAllowList(aWindow)) {
563
0
      LOG(("Allowing access even though our behavior is reject foreign"));
564
0
      return true;
565
0
    }
566
0
  }
567
0
568
0
  if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
569
0
      behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
570
0
    // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
571
0
    // simply rejecting the request to use the storage. In the future, if we
572
0
    // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
573
0
    // for non-cookie storage types, this may change.
574
0
    LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
575
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
576
0
    return false;
577
0
  }
578
0
579
0
  MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
580
0
581
0
  // Now, we have to also honour the Content Blocking pref.
582
0
  if (!ShouldHonorContentBlockingCookieRestrictions()) {
583
0
    LOG(("The content blocking pref has been disabled, bail out early by "
584
0
         "by pretending our window isn't a tracking window"));
585
0
    return true;
586
0
  }
587
0
588
0
  if (CheckContentBlockingAllowList(aWindow)) {
589
0
    return true;
590
0
  }
591
0
592
0
  if (!nsContentUtils::IsTrackingResourceWindow(aWindow)) {
593
0
    LOG(("Our window isn't a tracking window"));
594
0
    return true;
595
0
  }
596
0
597
0
  nsCOMPtr<nsIPrincipal> parentPrincipal;
598
0
  nsAutoCString trackingOrigin;
599
0
  if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(aWindow),
600
0
                                           getter_AddRefs(parentPrincipal),
601
0
                                           trackingOrigin)) {
602
0
    LOG(("Failed to obtain the parent principal and the tracking origin"));
603
0
    return false;
604
0
  }
605
0
606
0
  nsAutoString origin;
607
0
  nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
608
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
609
0
    LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
610
0
    return false;
611
0
  }
612
0
613
0
  nsAutoCString type;
614
0
  CreatePermissionKey(trackingOrigin, NS_ConvertUTF16toUTF8(origin), type);
615
0
616
0
  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
617
0
  if (NS_WARN_IF(!pm)) {
618
0
    LOG(("Failed to obtain the permission manager"));
619
0
    return false;
620
0
  }
621
0
622
0
  uint32_t result = 0;
623
0
  rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result);
624
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
625
0
    LOG(("Failed to test the permission"));
626
0
    return false;
627
0
  }
628
0
629
0
  nsCOMPtr<nsIURI> parentPrincipalURI;
630
0
  Unused << parentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
631
0
  LOG_SPEC(("Testing permission type %s for %s resulted in %d (%s)",
632
0
            type.get(), _spec, int(result),
633
0
            result == nsIPermissionManager::ALLOW_ACTION ?
634
0
              "success" : "failure"), parentPrincipalURI);
635
0
636
0
  if (result != nsIPermissionManager::ALLOW_ACTION) {
637
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
638
0
    return false;
639
0
  }
640
0
641
0
  return true;
642
0
}
643
644
bool
645
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel,
646
                                                        nsIURI* aURI,
647
                                                        uint32_t* aRejectedReason)
648
0
{
649
0
  MOZ_ASSERT(aURI);
650
0
  MOZ_ASSERT(aChannel);
651
0
652
0
  // Let's avoid a null check on aRejectedReason everywhere else.
653
0
  uint32_t rejectedReason = 0;
654
0
  if (!aRejectedReason) {
655
0
    aRejectedReason = &rejectedReason;
656
0
  }
657
0
658
0
  nsCOMPtr<nsIURI> channelURI;
659
0
  Unused << aChannel->GetURI(getter_AddRefs(channelURI));
660
0
  LOG_SPEC(("Computing whether channel %p has access to URI %s", aChannel, _spec),
661
0
           channelURI);
662
0
663
0
  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
664
0
  if (!loadInfo) {
665
0
    LOG(("No loadInfo, bail out early"));
666
0
    return true;
667
0
  }
668
0
669
0
  // We need to find the correct principal to check the cookie permission. For
670
0
  // third-party contexts, we want to check if the top-level window has a custom
671
0
  // cookie permission.
672
0
  nsIPrincipal* toplevelPrincipal = loadInfo->TopLevelPrincipal();
673
0
674
0
  // If this is already the top-level window, we should use the loading
675
0
  // principal.
676
0
  if (!toplevelPrincipal) {
677
0
    LOG(("Our loadInfo lacks a top-level principal, use the loadInfo's loading principal instead"));
678
0
    toplevelPrincipal = loadInfo->LoadingPrincipal();
679
0
  }
680
0
681
0
  nsCOMPtr<nsIPrincipal> channelPrincipal;
682
0
  nsIScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager();
683
0
  nsresult rv = ssm->GetChannelResultPrincipal(aChannel,
684
0
                                               getter_AddRefs(channelPrincipal));
685
0
686
0
  // If we don't have a loading principal and this is a document channel, we are
687
0
  // a top-level window!
688
0
  if (!toplevelPrincipal) {
689
0
    LOG(("We don't have a loading principal, let's see if this is a document channel"
690
0
         " that belongs to a top-level window"));
691
0
    bool isDocument = false;
692
0
    nsresult rv2 = aChannel->GetIsMainDocumentChannel(&isDocument);
693
0
    if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && isDocument) {
694
0
      toplevelPrincipal = channelPrincipal;
695
0
      LOG(("Yes, we guessed right!"));
696
0
    } else {
697
0
      LOG(("No, we guessed wrong!"));
698
0
    }
699
0
  }
700
0
701
0
  // Let's use the triggering principal then.
702
0
  if (!toplevelPrincipal) {
703
0
    LOG(("Our loadInfo lacks a top-level principal, use the loadInfo's triggering principal instead"));
704
0
    toplevelPrincipal = loadInfo->TriggeringPrincipal();
705
0
  }
706
0
707
0
  if (NS_WARN_IF(!toplevelPrincipal)) {
708
0
    LOG(("No top-level principal! Bail out early"));
709
0
    return false;
710
0
  }
711
0
712
0
  nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal);
713
0
  if (access != nsICookiePermission::ACCESS_DEFAULT) {
714
0
    LOG(("CheckCookiePermissionForPrincipal() returned a non-default access code (%d), returning %s",
715
0
         int(access), access != nsICookiePermission::ACCESS_DENY ?
716
0
                        "success" : "failure"));
717
0
    if (access != nsICookiePermission::ACCESS_DENY) {
718
0
      return true;
719
0
    }
720
0
721
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
722
0
    return false;
723
0
  }
724
0
725
0
  if (NS_WARN_IF(NS_FAILED(rv) || !channelPrincipal)) {
726
0
    LOG(("No channel principal, bail out early"));
727
0
    return false;
728
0
  }
729
0
730
0
  int32_t behavior = CookiesBehavior(toplevelPrincipal);
731
0
  if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
732
0
    LOG(("The cookie behavior pref mandates accepting all cookies!"));
733
0
    return true;
734
0
  }
735
0
736
0
  if (behavior == nsICookieService::BEHAVIOR_REJECT) {
737
0
    LOG(("The cookie behavior pref mandates rejecting all cookies!"));
738
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
739
0
    return false;
740
0
  }
741
0
742
0
  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
743
0
  if (!thirdPartyUtil) {
744
0
    LOG(("No thirdPartyUtil, bail out early"));
745
0
    return true;
746
0
  }
747
0
748
0
  bool thirdParty = false;
749
0
  rv = thirdPartyUtil->IsThirdPartyChannel(aChannel,
750
0
                                           aURI,
751
0
                                           &thirdParty);
752
0
  // Grant if it's not a 3rd party.
753
0
  // Be careful to check the return value of IsThirdPartyChannel, since
754
0
  // IsThirdPartyChannel() will fail if the channel's loading principal is the
755
0
  // system principal...
756
0
  if (NS_SUCCEEDED(rv) && !thirdParty) {
757
0
    LOG(("Our channel isn't a third-party channel"));
758
0
    return true;
759
0
  }
760
0
761
0
  if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
762
0
    // Now, we have to also honour the Content Blocking pref.
763
0
    if (!ShouldHonorContentBlockingCookieRestrictions()) {
764
0
      LOG(("The content blocking pref has been disabled, bail out early by "
765
0
           "by pretending our window isn't a third-party window"));
766
0
      return true;
767
0
    }
768
0
769
0
    if (CheckContentBlockingAllowList(aChannel)) {
770
0
      LOG(("Allowing access even though our behavior is reject foreign"));
771
0
      return true;
772
0
    }
773
0
  }
774
0
775
0
  if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
776
0
      behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
777
0
    // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
778
0
    // simply rejecting the request to use the storage. In the future, if we
779
0
    // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
780
0
    // for non-cookie storage types, this may change.
781
0
    LOG(("Nothing more to do due to the behavior code %d", int(behavior)));
782
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
783
0
    return false;
784
0
  }
785
0
786
0
  MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
787
0
788
0
  // Now, we have to also honour the Content Blocking pref.
789
0
  if (!ShouldHonorContentBlockingCookieRestrictions()) {
790
0
    LOG(("The content blocking pref has been disabled, bail out early by "
791
0
         "pretending our channel isn't a tracking channel"));
792
0
    return true;
793
0
  }
794
0
795
0
  if (CheckContentBlockingAllowList(aChannel)) {
796
0
    return true;
797
0
  }
798
0
799
0
  nsIPrincipal* parentPrincipal = loadInfo->TopLevelStorageAreaPrincipal();
800
0
  if (!parentPrincipal) {
801
0
    LOG(("No top-level storage area principal at hand"));
802
0
803
0
    // parentPrincipal can be null if the parent window is not the top-level
804
0
    // window.
805
0
    if (loadInfo->TopLevelPrincipal()) {
806
0
      LOG(("Parent window is the top-level window, bail out early"));
807
0
      return false;
808
0
    }
809
0
810
0
    parentPrincipal = toplevelPrincipal;
811
0
    if (NS_WARN_IF(!parentPrincipal)) {
812
0
      LOG(("No triggering principal, this shouldn't be happening! Bail out early"));
813
0
      // Why we are here?!?
814
0
      return true;
815
0
    }
816
0
  }
817
0
818
0
  // Not a tracker.
819
0
  if (!aChannel->GetIsTrackingResource()) {
820
0
    LOG(("Our channel isn't a tracking channel"));
821
0
    return true;
822
0
  }
823
0
824
0
  // Let's see if we have to grant the access for this particular channel.
825
0
826
0
  nsCOMPtr<nsIURI> trackingURI;
827
0
  rv = aChannel->GetURI(getter_AddRefs(trackingURI));
828
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
829
0
    LOG(("Failed to get the channel URI"));
830
0
    return true;
831
0
  }
832
0
833
0
  nsAutoString trackingOrigin;
834
0
  rv = nsContentUtils::GetUTFOrigin(trackingURI, trackingOrigin);
835
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
836
0
    LOG_SPEC(("Failed to compute the origin from %s", _spec), trackingURI);
837
0
    return false;
838
0
  }
839
0
840
0
  nsAutoString origin;
841
0
  rv = nsContentUtils::GetUTFOrigin(aURI, origin);
842
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
843
0
    LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
844
0
    return false;
845
0
  }
846
0
847
0
  nsAutoCString type;
848
0
  CreatePermissionKey(NS_ConvertUTF16toUTF8(trackingOrigin),
849
0
                      NS_ConvertUTF16toUTF8(origin), type);
850
0
851
0
  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
852
0
  if (NS_WARN_IF(!pm)) {
853
0
    LOG(("Failed to obtain the permission manager"));
854
0
    return false;
855
0
  }
856
0
857
0
  uint32_t result = 0;
858
0
  rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result);
859
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
860
0
    LOG(("Failed to test the permission"));
861
0
    return false;
862
0
  }
863
0
864
0
  nsCOMPtr<nsIURI> parentPrincipalURI;
865
0
  Unused << parentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
866
0
  LOG_SPEC(("Testing permission type %s for %s resulted in %d (%s)",
867
0
            type.get(), _spec, int(result),
868
0
            result == nsIPermissionManager::ALLOW_ACTION ?
869
0
              "success" : "failure"), parentPrincipalURI);
870
0
871
0
  if (result != nsIPermissionManager::ALLOW_ACTION) {
872
0
    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
873
0
    return false;
874
0
  }
875
0
876
0
  return true;
877
0
}
878
879
bool
880
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal)
881
0
{
882
0
  MOZ_ASSERT(aPrincipal);
883
0
884
0
  nsCookieAccess access = CheckCookiePermissionForPrincipal(aPrincipal);
885
0
  if (access != nsICookiePermission::ACCESS_DEFAULT) {
886
0
    return access != nsICookiePermission::ACCESS_DENY;
887
0
  }
888
0
889
0
  int32_t behavior = CookiesBehavior(aPrincipal);
890
0
  return behavior != nsICookieService::BEHAVIOR_REJECT;
891
0
}
892
893
/* static */ bool
894
AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow,
895
                                                             nsIURI* aURI)
896
0
{
897
0
  MOZ_ASSERT(aFirstPartyWindow);
898
0
  MOZ_ASSERT(aURI);
899
0
900
0
  LOG_SPEC(("Computing a best guess as to whether window %p has access to URI %s",
901
0
            aFirstPartyWindow, _spec), aURI);
902
0
903
0
  if (StaticPrefs::network_cookie_cookieBehavior() !=
904
0
        nsICookieService::BEHAVIOR_REJECT_TRACKER) {
905
0
    LOG(("Disabled by the pref (%d), bail out early",
906
0
         StaticPrefs::network_cookie_cookieBehavior()));
907
0
    return true;
908
0
  }
909
0
910
0
  // Now, we have to also honour the Content Blocking pref.
911
0
  if (!ShouldHonorContentBlockingCookieRestrictions()) {
912
0
    LOG(("The content blocking pref has been disabled, bail out early"));
913
0
    return true;
914
0
  }
915
0
916
0
  if (CheckContentBlockingAllowList(aFirstPartyWindow)) {
917
0
    return true;
918
0
  }
919
0
920
0
  if (!nsContentUtils::IsThirdPartyWindowOrChannel(aFirstPartyWindow,
921
0
                                                   nullptr, aURI)) {
922
0
    LOG(("Our window isn't a third-party window"));
923
0
    return true;
924
0
  }
925
0
926
0
  nsCOMPtr<nsIPrincipal> parentPrincipal =
927
0
    nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetPrincipal();
928
0
  if (NS_WARN_IF(!parentPrincipal)) {
929
0
    LOG(("Failed to get the first party window's principal"));
930
0
    return false;
931
0
  }
932
0
933
0
  nsCookieAccess access = CheckCookiePermissionForPrincipal(parentPrincipal);
934
0
  if (access != nsICookiePermission::ACCESS_DEFAULT) {
935
0
    LOG(("CheckCookiePermissionForPrincipal() returned a non-default access code (%d), returning %s",
936
0
         int(access), access != nsICookiePermission::ACCESS_DENY ?
937
0
                        "success" : "failure"));
938
0
    return access != nsICookiePermission::ACCESS_DENY;
939
0
  }
940
0
941
0
  nsAutoString origin;
942
0
  nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
943
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
944
0
    LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
945
0
    return false;
946
0
  }
947
0
948
0
  NS_ConvertUTF16toUTF8 utf8Origin(origin);
949
0
950
0
  nsAutoCString type;
951
0
  CreatePermissionKey(utf8Origin, utf8Origin, type);
952
0
953
0
  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
954
0
  if (NS_WARN_IF(!pm)) {
955
0
    LOG(("Failed to obtain the permission manager"));
956
0
    return false;
957
0
  }
958
0
959
0
  uint32_t result = 0;
960
0
  rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result);
961
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
962
0
    LOG(("Failed to test the permission"));
963
0
    return false;
964
0
  }
965
0
966
0
  nsCOMPtr<nsIURI> parentPrincipalURI;
967
0
  Unused << parentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
968
0
  LOG_SPEC(("Testing permission type %s for %s resulted in %d (%s)",
969
0
            type.get(), _spec, int(result),
970
0
            result == nsIPermissionManager::ALLOW_ACTION ?
971
0
              "success" : "failure"), parentPrincipalURI);
972
0
973
0
  return result == nsIPermissionManager::ALLOW_ACTION;
974
0
}
975
976
nsresult
977
AntiTrackingCommon::IsOnContentBlockingAllowList(nsIURI* aTopWinURI,
978
  AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose,
979
  bool& aIsAllowListed)
980
0
{
981
0
  aIsAllowListed = false;
982
0
983
0
  // For storage checks, check the storage pref, and for annotations checks,
984
0
  // check the corresponding pref as well.  This allows each set of checks to
985
0
  // be disabled individually if needed.
986
0
  if ((aPurpose == eStorageChecks &&
987
0
       !StaticPrefs::browser_contentblocking_allowlist_storage_enabled()) ||
988
0
      (aPurpose == eTrackingAnnotations &&
989
0
       !StaticPrefs::browser_contentblocking_allowlist_annotations_enabled())) {
990
0
    LOG(("Attempting to check the content blocking allow list aborted because "
991
0
         "the third-party cookies UI has been disabled."));
992
0
    return NS_OK;
993
0
  }
994
0
995
0
  LOG_SPEC(("Deciding whether the user has overridden content blocking for %s",
996
0
            _spec), aTopWinURI);
997
0
998
0
  nsCOMPtr<nsIIOService> ios = services::GetIOService();
999
0
  NS_ENSURE_TRUE(ios, NS_ERROR_FAILURE);
1000
0
1001
0
  // Take the host/port portion so we can allowlist by site. Also ignore the
1002
0
  // scheme, since users who put sites on the allowlist probably don't expect
1003
0
  // allowlisting to depend on scheme.
1004
0
  nsresult rv = NS_ERROR_FAILURE;
1005
0
  nsCOMPtr<nsIURL> url = do_QueryInterface(aTopWinURI, &rv);
1006
0
  if (NS_FAILED(rv)) {
1007
0
    return rv; // normal for some loads, no need to print a warning
1008
0
  }
1009
0
1010
0
  nsCString escaped(NS_LITERAL_CSTRING("https://"));
1011
0
  nsAutoCString temp;
1012
0
  rv = url->GetHostPort(temp);
1013
0
  NS_ENSURE_SUCCESS(rv, rv);
1014
0
  escaped.Append(temp);
1015
0
1016
0
  // Stuff the whole thing back into a URI for the permission manager.
1017
0
  nsCOMPtr<nsIURI> topWinURI;
1018
0
  rv = ios->NewURI(escaped, nullptr, nullptr, getter_AddRefs(topWinURI));
1019
0
  NS_ENSURE_SUCCESS(rv, rv);
1020
0
1021
0
  nsCOMPtr<nsIPermissionManager> permMgr =
1022
0
    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
1023
0
  NS_ENSURE_SUCCESS(rv, rv);
1024
0
1025
0
  // Check both the normal mode and private browsing mode user override permissions.
1026
0
  const char* types[] = {
1027
0
    "trackingprotection",
1028
0
    "trackingprotection-pb"
1029
0
  };
1030
0
1031
0
  for (size_t i = 0; i < ArrayLength(types); ++i) {
1032
0
    uint32_t permissions = nsIPermissionManager::UNKNOWN_ACTION;
1033
0
    rv = permMgr->TestPermission(topWinURI, types[i], &permissions);
1034
0
    NS_ENSURE_SUCCESS(rv, rv);
1035
0
1036
0
    if (permissions == nsIPermissionManager::ALLOW_ACTION) {
1037
0
      aIsAllowListed = true;
1038
0
      LOG_SPEC(("Found user override type %s for %s", types[i], _spec),
1039
0
               topWinURI);
1040
0
      // Stop checking the next permisson type if we decided to override.
1041
0
      break;
1042
0
    }
1043
0
  }
1044
0
1045
0
  if (!aIsAllowListed) {
1046
0
    LOG(("No user override found"));
1047
0
  }
1048
0
1049
0
  return NS_OK;
1050
0
}
1051
1052
/* static */ void
1053
AntiTrackingCommon::NotifyRejection(nsIChannel* aChannel,
1054
                                    uint32_t aRejectedReason)
1055
0
{
1056
0
  MOZ_ASSERT(aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION ||
1057
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER ||
1058
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL ||
1059
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN ||
1060
0
             aRejectedReason == nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT);
1061
0
1062
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
1063
0
  if (!httpChannel) {
1064
0
    return;
1065
0
  }
1066
0
1067
0
  // Can be called in EITHER the parent or child process.
1068
0
  nsCOMPtr<nsIParentChannel> parentChannel;
1069
0
  NS_QueryNotificationCallbacks(aChannel, parentChannel);
1070
0
  if (parentChannel) {
1071
0
    // This channel is a parent-process proxy for a child process request.
1072
0
    // Tell the child process channel to do this instead.
1073
0
    parentChannel->NotifyTrackingCookieBlocked(aRejectedReason);
1074
0
    return;
1075
0
  }
1076
0
1077
0
  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
1078
0
  if (!thirdPartyUtil) {
1079
0
    return;
1080
0
  }
1081
0
1082
0
  nsCOMPtr<mozIDOMWindowProxy> win;
1083
0
  nsresult rv = thirdPartyUtil->GetTopWindowForChannel(httpChannel,
1084
0
                                                       getter_AddRefs(win));
1085
0
  NS_ENSURE_SUCCESS_VOID(rv);
1086
0
1087
0
  nsCOMPtr<nsPIDOMWindowOuter> pwin = nsPIDOMWindowOuter::From(win);
1088
0
  if (!pwin) {
1089
0
    return;
1090
0
  }
1091
0
1092
0
  pwin->NotifyContentBlockingState(aRejectedReason, aChannel);
1093
0
1094
0
  ReportBlockingToConsole(pwin, httpChannel, aRejectedReason);
1095
0
}
1096
1097
/* static */ void
1098
AntiTrackingCommon::NotifyRejection(nsPIDOMWindowInner* aWindow,
1099
                                    uint32_t aRejectedReason)
1100
0
{
1101
0
  MOZ_ASSERT(aWindow);
1102
0
  MOZ_ASSERT(aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION ||
1103
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER ||
1104
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL ||
1105
0
             aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN ||
1106
0
             aRejectedReason == nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT);
1107
0
1108
0
  nsIDocument* document = aWindow->GetExtantDoc();
1109
0
  if (!document) {
1110
0
    return;
1111
0
  }
1112
0
1113
0
  nsCOMPtr<nsIHttpChannel> httpChannel =
1114
0
    do_QueryInterface(document->GetChannel());
1115
0
  if (!httpChannel) {
1116
0
    return;
1117
0
  }
1118
0
1119
0
  nsCOMPtr<nsPIDOMWindowOuter> pwin;
1120
0
  auto* outer = nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow());
1121
0
  if (outer) {
1122
0
    pwin = outer->GetTopOuter();
1123
0
  }
1124
0
1125
0
  if (!pwin) {
1126
0
    return;
1127
0
  }
1128
0
1129
0
  pwin->NotifyContentBlockingState(aRejectedReason, httpChannel);
1130
0
1131
0
  ReportBlockingToConsole(pwin, httpChannel, aRejectedReason);
1132
0
}
1133
1134
/* static */ void
1135
AntiTrackingCommon::StoreUserInteractionFor(nsIPrincipal* aPrincipal)
1136
0
{
1137
0
  if (XRE_IsParentProcess()) {
1138
0
    nsCOMPtr<nsIURI> uri;
1139
0
    Unused << aPrincipal->GetURI(getter_AddRefs(uri));
1140
0
    LOG_SPEC(("Saving the userInteraction for %s", _spec), uri);
1141
0
1142
0
    nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
1143
0
    if (NS_WARN_IF(!pm)) {
1144
0
      LOG(("Permission manager is null, bailing out early"));
1145
0
      return;
1146
0
    }
1147
0
1148
0
    // Remember that this pref is stored in seconds!
1149
0
    uint32_t expirationType = nsIPermissionManager::EXPIRE_TIME;
1150
0
    uint32_t expirationTime =
1151
0
      StaticPrefs::privacy_userInteraction_expiration() * 1000;
1152
0
    int64_t when = (PR_Now() / PR_USEC_PER_MSEC) + expirationTime;
1153
0
1154
0
    uint32_t privateBrowsingId = 0;
1155
0
    nsresult rv = aPrincipal->GetPrivateBrowsingId(&privateBrowsingId);
1156
0
    if (!NS_WARN_IF(NS_FAILED(rv)) && privateBrowsingId > 0) {
1157
0
      // If we are coming from a private window, make sure to store a session-only
1158
0
      // permission which won't get persisted to disk.
1159
0
      expirationType = nsIPermissionManager::EXPIRE_SESSION;
1160
0
      when = 0;
1161
0
    }
1162
0
1163
0
    rv = pm->AddFromPrincipal(aPrincipal,
1164
0
                              USER_INTERACTION_PERM,
1165
0
                              nsIPermissionManager::ALLOW_ACTION,
1166
0
                              expirationType, when);
1167
0
    Unused << NS_WARN_IF(NS_FAILED(rv));
1168
0
    return;
1169
0
  }
1170
0
1171
0
  ContentChild* cc = ContentChild::GetSingleton();
1172
0
  MOZ_ASSERT(cc);
1173
0
1174
0
  nsCOMPtr<nsIURI> uri;
1175
0
  Unused << aPrincipal->GetURI(getter_AddRefs(uri));
1176
0
  LOG_SPEC(("Asking the parent process to save the user-interaction for us: %s",
1177
0
            _spec), uri);
1178
0
  cc->SendStoreUserInteractionAsPermission(IPC::Principal(aPrincipal));
1179
0
}