tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CookieJarSettings.cpp (24497B)


      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 "mozIThirdPartyUtil.h"
      8 #include "mozilla/AntiTrackingUtils.h"
      9 #include "mozilla/BasePrincipal.h"
     10 #include "mozilla/ClearOnShutdown.h"
     11 #include "mozilla/Components.h"
     12 #include "mozilla/ContentBlockingAllowList.h"
     13 #include "mozilla/dom/BrowsingContext.h"
     14 #include "mozilla/net/CookieJarSettings.h"
     15 #include "mozilla/net/NeckoChannelParams.h"
     16 #include "mozilla/Permission.h"
     17 #include "mozilla/PermissionManager.h"
     18 #include "mozilla/SchedulerGroup.h"
     19 #include "mozilla/StaticPrefs_network.h"
     20 #include "mozilla/StoragePrincipalHelper.h"
     21 #include "nsIPrincipal.h"
     22 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
     23 #  include "nsIProtocolHandler.h"
     24 #endif
     25 #include "nsIClassInfoImpl.h"
     26 #include "nsIChannel.h"
     27 #include "nsICookieManager.h"
     28 #include "nsICookieService.h"
     29 #include "nsIObjectInputStream.h"
     30 #include "nsIObjectOutputStream.h"
     31 #include "nsNetUtil.h"
     32 
     33 namespace mozilla {
     34 namespace net {
     35 
     36 NS_IMPL_CLASSINFO(CookieJarSettings, nullptr, nsIClassInfo::THREADSAFE,
     37                  COOKIEJARSETTINGS_CID)
     38 
     39 NS_IMPL_ISUPPORTS_CI(CookieJarSettings, nsICookieJarSettings, nsISerializable)
     40 
     41 static StaticRefPtr<CookieJarSettings> sBlockinAll;
     42 
     43 namespace {
     44 
     45 class PermissionComparator {
     46 public:
     47  static bool Equals(nsIPermission* aA, nsIPermission* aB) {
     48    nsCOMPtr<nsIPrincipal> principalA;
     49    nsresult rv = aA->GetPrincipal(getter_AddRefs(principalA));
     50    if (NS_WARN_IF(NS_FAILED(rv))) {
     51      return false;
     52    }
     53 
     54    nsCOMPtr<nsIPrincipal> principalB;
     55    rv = aB->GetPrincipal(getter_AddRefs(principalB));
     56    if (NS_WARN_IF(NS_FAILED(rv))) {
     57      return false;
     58    }
     59 
     60    bool equals = false;
     61    rv = principalA->Equals(principalB, &equals);
     62    if (NS_WARN_IF(NS_FAILED(rv))) {
     63      return false;
     64    }
     65 
     66    return equals;
     67  }
     68 };
     69 
     70 class ReleaseCookiePermissions final : public Runnable {
     71 public:
     72  explicit ReleaseCookiePermissions(nsTArray<RefPtr<nsIPermission>>&& aArray)
     73      : Runnable("ReleaseCookiePermissions"), mArray(std::move(aArray)) {}
     74 
     75  NS_IMETHOD Run() override {
     76    MOZ_ASSERT(NS_IsMainThread());
     77    mArray.Clear();
     78    return NS_OK;
     79  }
     80 
     81 private:
     82  nsTArray<RefPtr<nsIPermission>> mArray;
     83 };
     84 
     85 }  // namespace
     86 
     87 // static
     88 already_AddRefed<nsICookieJarSettings> CookieJarSettings::GetBlockingAll(
     89    bool aShouldResistFingerprinting) {
     90  MOZ_ASSERT(NS_IsMainThread());
     91 
     92  if (sBlockinAll) {
     93    return do_AddRef(sBlockinAll);
     94  }
     95 
     96  sBlockinAll = new CookieJarSettings(nsICookieService::BEHAVIOR_REJECT,
     97                                      OriginAttributes::IsFirstPartyEnabled(),
     98                                      aShouldResistFingerprinting, eFixed);
     99  ClearOnShutdown(&sBlockinAll);
    100 
    101  return do_AddRef(sBlockinAll);
    102 }
    103 
    104 // static
    105 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
    106    CreateMode aMode, bool aShouldResistFingerprinting) {
    107  MOZ_ASSERT(NS_IsMainThread());
    108 
    109  RefPtr<CookieJarSettings> cookieJarSettings;
    110 
    111  switch (aMode) {
    112    case eRegular:
    113    case ePrivate:
    114      cookieJarSettings = new CookieJarSettings(
    115          nsICookieManager::GetCookieBehavior(aMode == ePrivate),
    116          OriginAttributes::IsFirstPartyEnabled(), aShouldResistFingerprinting,
    117          eProgressive);
    118      break;
    119 
    120    default:
    121      MOZ_CRASH("Unexpected create mode.");
    122  }
    123 
    124  return cookieJarSettings.forget();
    125 }
    126 
    127 // static
    128 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
    129    nsIPrincipal* aPrincipal) {
    130  MOZ_ASSERT(NS_IsMainThread());
    131 
    132  bool shouldResistFingerprinting =
    133      nsContentUtils::ShouldResistFingerprinting_dangerous(
    134          aPrincipal, "We are constructing CookieJarSettings here.",
    135          RFPTarget::IsAlwaysEnabledForPrecompute);
    136 
    137  if (aPrincipal && aPrincipal->OriginAttributesRef().IsPrivateBrowsing()) {
    138    return Create(ePrivate, shouldResistFingerprinting);
    139  }
    140 
    141  return Create(eRegular, shouldResistFingerprinting);
    142 }
    143 
    144 // static
    145 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
    146    uint32_t aCookieBehavior, const nsAString& aPartitionKey,
    147    bool aIsFirstPartyIsolated, bool aIsOnContentBlockingAllowList,
    148    bool aShouldResistFingerprinting) {
    149  MOZ_ASSERT(NS_IsMainThread());
    150 
    151  RefPtr<CookieJarSettings> cookieJarSettings =
    152      new CookieJarSettings(aCookieBehavior, aIsFirstPartyIsolated,
    153                            aShouldResistFingerprinting, eProgressive);
    154  cookieJarSettings->mPartitionKey = aPartitionKey;
    155  cookieJarSettings->mIsOnContentBlockingAllowList =
    156      aIsOnContentBlockingAllowList;
    157 
    158  return cookieJarSettings.forget();
    159 }
    160 
    161 // static
    162 already_AddRefed<nsICookieJarSettings> CookieJarSettings::CreateForXPCOM() {
    163  MOZ_ASSERT(NS_IsMainThread());
    164  return Create(eRegular, /* shouldResistFingerprinting */ false);
    165 }
    166 
    167 CookieJarSettings::CookieJarSettings(uint32_t aCookieBehavior,
    168                                     bool aIsFirstPartyIsolated,
    169                                     bool aShouldResistFingerprinting,
    170                                     State aState)
    171    : mCookieBehavior(aCookieBehavior),
    172      mIsFirstPartyIsolated(aIsFirstPartyIsolated),
    173      mIsOnContentBlockingAllowList(false),
    174      mIsOnContentBlockingAllowListUpdated(false),
    175      mState(aState),
    176      mToBeMerged(false),
    177      mShouldResistFingerprinting(aShouldResistFingerprinting),
    178      mTopLevelWindowContextId(0) {
    179  MOZ_ASSERT_IF(
    180      mIsFirstPartyIsolated,
    181      mCookieBehavior !=
    182          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
    183 }
    184 
    185 CookieJarSettings::~CookieJarSettings() {
    186  if (!NS_IsMainThread() && !mCookiePermissions.IsEmpty()) {
    187    RefPtr<Runnable> r =
    188        new ReleaseCookiePermissions(std::move(mCookiePermissions));
    189    MOZ_ASSERT(mCookiePermissions.IsEmpty());
    190    SchedulerGroup::Dispatch(r.forget());
    191  }
    192 }
    193 
    194 CookieJarSettings::CookiePermissionList&
    195 CookieJarSettings::GetCookiePermissionsListRef() {
    196  MOZ_ASSERT_DEBUG_OR_FUZZING(NS_IsMainThread());
    197 
    198  if (mCookiePermissions.IsEmpty() && !mIPCCookiePermissions.IsEmpty()) {
    199    mCookiePermissions = DeserializeCookiePermissions(mIPCCookiePermissions);
    200  }
    201  return mCookiePermissions;
    202 }
    203 
    204 /* static */
    205 CookieJarSettings::CookiePermissionList
    206 CookieJarSettings::DeserializeCookiePermissions(
    207    const CookiePermissionsArgsData& aPermissionData) {
    208  MOZ_ASSERT_DEBUG_OR_FUZZING(NS_IsMainThread());
    209 
    210  CookiePermissionList list;
    211  for (const CookiePermissionData& data : aPermissionData) {
    212    auto principalOrErr = PrincipalInfoToPrincipal(data.principalInfo());
    213    if (NS_WARN_IF(principalOrErr.isErr())) {
    214      continue;
    215    }
    216 
    217    nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
    218 
    219    nsCOMPtr<nsIPermission> permission = Permission::Create(
    220        principal, "cookie"_ns, data.cookiePermission(), 0, 0, 0);
    221    if (NS_WARN_IF(!permission)) {
    222      continue;
    223    }
    224 
    225    list.AppendElement(permission);
    226  }
    227  return list;
    228 }
    229 
    230 NS_IMETHODIMP
    231 CookieJarSettings::InitWithURI(nsIURI* aURI, bool aIsPrivate) {
    232  NS_ENSURE_ARG(aURI);
    233 
    234  mCookieBehavior = nsICookieManager::GetCookieBehavior(aIsPrivate);
    235 
    236  SetPartitionKey(aURI);
    237  return NS_OK;
    238 }
    239 
    240 NS_IMETHODIMP
    241 CookieJarSettings::GetCookieBehavior(uint32_t* aCookieBehavior) {
    242  *aCookieBehavior = mCookieBehavior;
    243  return NS_OK;
    244 }
    245 
    246 NS_IMETHODIMP
    247 CookieJarSettings::GetIsFirstPartyIsolated(bool* aIsFirstPartyIsolated) {
    248  *aIsFirstPartyIsolated = mIsFirstPartyIsolated;
    249  return NS_OK;
    250 }
    251 
    252 NS_IMETHODIMP
    253 CookieJarSettings::GetShouldResistFingerprinting(
    254    bool* aShouldResistFingerprinting) {
    255  *aShouldResistFingerprinting = mShouldResistFingerprinting;
    256  return NS_OK;
    257 }
    258 
    259 NS_IMETHODIMP
    260 CookieJarSettings::GetRejectThirdPartyContexts(
    261    bool* aRejectThirdPartyContexts) {
    262  *aRejectThirdPartyContexts =
    263      CookieJarSettings::IsRejectThirdPartyContexts(mCookieBehavior);
    264  return NS_OK;
    265 }
    266 
    267 NS_IMETHODIMP
    268 CookieJarSettings::GetLimitForeignContexts(bool* aLimitForeignContexts) {
    269  *aLimitForeignContexts =
    270      mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
    271      (StaticPrefs::privacy_dynamic_firstparty_limitForeign() &&
    272       mCookieBehavior ==
    273           nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
    274  return NS_OK;
    275 }
    276 
    277 NS_IMETHODIMP
    278 CookieJarSettings::GetBlockingAllThirdPartyContexts(
    279    bool* aBlockingAllThirdPartyContexts) {
    280  // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
    281  // simply rejecting the request to use the storage. In the future, if we
    282  // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
    283  // for non-cookie storage types, this may change.
    284  *aBlockingAllThirdPartyContexts =
    285      mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
    286      mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN;
    287  return NS_OK;
    288 }
    289 
    290 NS_IMETHODIMP
    291 CookieJarSettings::GetBlockingAllContexts(bool* aBlockingAllContexts) {
    292  *aBlockingAllContexts = mCookieBehavior == nsICookieService::BEHAVIOR_REJECT;
    293  return NS_OK;
    294 }
    295 
    296 NS_IMETHODIMP
    297 CookieJarSettings::GetPartitionForeign(bool* aPartitionForeign) {
    298  *aPartitionForeign =
    299      mCookieBehavior ==
    300      nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
    301  return NS_OK;
    302 }
    303 
    304 NS_IMETHODIMP
    305 CookieJarSettings::SetPartitionForeign(bool aPartitionForeign) {
    306  if (mIsFirstPartyIsolated) {
    307    return NS_OK;
    308  }
    309 
    310  if (aPartitionForeign) {
    311    mCookieBehavior =
    312        nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
    313  }
    314  return NS_OK;
    315 }
    316 
    317 NS_IMETHODIMP
    318 CookieJarSettings::GetIsOnContentBlockingAllowList(
    319    bool* aIsOnContentBlockingAllowList) {
    320  *aIsOnContentBlockingAllowList = mIsOnContentBlockingAllowList;
    321  return NS_OK;
    322 }
    323 
    324 NS_IMETHODIMP
    325 CookieJarSettings::GetPartitionKey(nsAString& aPartitionKey) {
    326  aPartitionKey = mPartitionKey;
    327  return NS_OK;
    328 }
    329 
    330 NS_IMETHODIMP
    331 CookieJarSettings::GetFingerprintingRandomizationKey(
    332    nsTArray<uint8_t>& aFingerprintingRandomizationKey) {
    333  if (!mFingerprintingRandomKey) {
    334    return NS_ERROR_NOT_AVAILABLE;
    335  }
    336 
    337  aFingerprintingRandomizationKey = mFingerprintingRandomKey->Clone();
    338  return NS_OK;
    339 }
    340 
    341 NS_IMETHODIMP
    342 CookieJarSettings::CookiePermission(nsIPrincipal* aPrincipal,
    343                                    uint32_t* aCookiePermission) {
    344  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    345  NS_ENSURE_ARG_POINTER(aPrincipal);
    346  NS_ENSURE_ARG_POINTER(aCookiePermission);
    347 
    348  *aCookiePermission = nsIPermissionManager::UNKNOWN_ACTION;
    349 
    350  nsresult rv;
    351 
    352  // Let's see if we know this permission.
    353  for (const RefPtr<nsIPermission>& permission :
    354       GetCookiePermissionsListRef()) {
    355    bool match = false;
    356    rv = permission->Matches(aPrincipal, false, &match);
    357    if (NS_WARN_IF(NS_FAILED(rv)) || !match) {
    358      continue;
    359    }
    360 
    361    rv = permission->GetCapability(aCookiePermission);
    362    if (NS_WARN_IF(NS_FAILED(rv))) {
    363      return rv;
    364    }
    365 
    366    return NS_OK;
    367  }
    368 
    369  // Let's ask the permission manager.
    370  RefPtr<PermissionManager> pm = PermissionManager::GetInstance();
    371  if (NS_WARN_IF(!pm)) {
    372    return NS_ERROR_FAILURE;
    373  }
    374 
    375 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
    376  // Check if this protocol doesn't allow cookies.
    377  bool hasFlags;
    378  nsCOMPtr<nsIURI> uri;
    379  BasePrincipal::Cast(aPrincipal)->GetURI(getter_AddRefs(uri));
    380 
    381  rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS,
    382                           &hasFlags);
    383  if (NS_FAILED(rv) || hasFlags) {
    384    *aCookiePermission = PermissionManager::DENY_ACTION;
    385    rv = NS_OK;  // Reset, so it's not caught as a bad status after the `else`.
    386  } else         // Note the tricky `else` which controls the call below.
    387 #endif
    388 
    389    rv = pm->TestPermissionFromPrincipal(aPrincipal, "cookie"_ns,
    390                                         aCookiePermission);
    391  if (NS_WARN_IF(NS_FAILED(rv))) {
    392    return rv;
    393  }
    394 
    395  // Let's store the permission, also if the result is UNKNOWN in order to avoid
    396  // race conditions.
    397 
    398  nsCOMPtr<nsIPermission> permission =
    399      Permission::Create(aPrincipal, "cookie"_ns, *aCookiePermission, 0, 0, 0);
    400  if (permission) {
    401    mCookiePermissions.AppendElement(permission);
    402  }
    403 
    404  mToBeMerged = true;
    405  return NS_OK;
    406 }
    407 
    408 void CookieJarSettings::Serialize(CookieJarSettingsArgs& aData) {
    409  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    410 
    411  aData.isFixed() = mState == eFixed;
    412  aData.cookieBehavior() = mCookieBehavior;
    413  aData.isFirstPartyIsolated() = mIsFirstPartyIsolated;
    414  aData.shouldResistFingerprinting() = mShouldResistFingerprinting;
    415  aData.isOnContentBlockingAllowList() = mIsOnContentBlockingAllowList;
    416  aData.partitionKey() = mPartitionKey;
    417  if (mFingerprintingRandomKey) {
    418    aData.hasFingerprintingRandomizationKey() = true;
    419    aData.fingerprintingRandomizationKey() = mFingerprintingRandomKey->Clone();
    420  } else {
    421    aData.hasFingerprintingRandomizationKey() = false;
    422  }
    423 
    424  for (const RefPtr<nsIPermission>& permission :
    425       GetCookiePermissionsListRef()) {
    426    nsCOMPtr<nsIPrincipal> principal;
    427    nsresult rv = permission->GetPrincipal(getter_AddRefs(principal));
    428    if (NS_WARN_IF(NS_FAILED(rv))) {
    429      continue;
    430    }
    431 
    432    mozilla::ipc::PrincipalInfo principalInfo;
    433    rv = PrincipalToPrincipalInfo(principal, &principalInfo,
    434                                  true /* aSkipBaseDomain */);
    435    if (NS_WARN_IF(NS_FAILED(rv))) {
    436      continue;
    437    }
    438 
    439    uint32_t cookiePermission = 0;
    440    rv = permission->GetCapability(&cookiePermission);
    441    if (NS_WARN_IF(NS_FAILED(rv))) {
    442      continue;
    443    }
    444 
    445    aData.cookiePermissions().AppendElement(
    446        CookiePermissionData(principalInfo, cookiePermission));
    447  }
    448 
    449  aData.topLevelWindowContextId() = mTopLevelWindowContextId;
    450 
    451  mToBeMerged = false;
    452 }
    453 
    454 /* static */ void CookieJarSettings::Deserialize(
    455    const CookieJarSettingsArgs& aData,
    456    nsICookieJarSettings** aCookieJarSettings) {
    457  RefPtr<CookieJarSettings> cookieJarSettings;
    458 
    459  cookieJarSettings = new CookieJarSettings(
    460      aData.cookieBehavior(), aData.isFirstPartyIsolated(),
    461      aData.shouldResistFingerprinting(),
    462      aData.isFixed() ? eFixed : eProgressive);
    463  cookieJarSettings->mIPCCookiePermissions = aData.cookiePermissions().Clone();
    464 
    465  cookieJarSettings->mIsOnContentBlockingAllowList =
    466      aData.isOnContentBlockingAllowList();
    467  cookieJarSettings->mPartitionKey = aData.partitionKey();
    468  cookieJarSettings->mShouldResistFingerprinting =
    469      aData.shouldResistFingerprinting();
    470 
    471  if (aData.hasFingerprintingRandomizationKey()) {
    472    cookieJarSettings->mFingerprintingRandomKey.emplace(
    473        aData.fingerprintingRandomizationKey().Clone());
    474  }
    475 
    476  cookieJarSettings->mTopLevelWindowContextId = aData.topLevelWindowContextId();
    477 
    478  cookieJarSettings.forget(aCookieJarSettings);
    479 }
    480 
    481 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Merge(
    482    const CookieJarSettingsArgs& aData) {
    483  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    484  MOZ_ASSERT(
    485      mCookieBehavior == aData.cookieBehavior() ||
    486      (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
    487       aData.cookieBehavior() ==
    488           nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) ||
    489      (mCookieBehavior ==
    490           nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
    491       aData.cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER));
    492 
    493  if (mState == eFixed) {
    494    return do_AddRef(this);
    495  }
    496 
    497  RefPtr<CookieJarSettings> newCookieJarSettings;
    498  newCookieJarSettings = Clone();
    499 
    500  // Merge cookie behavior pref values
    501  if (newCookieJarSettings->mCookieBehavior ==
    502          nsICookieService::BEHAVIOR_REJECT_TRACKER &&
    503      aData.cookieBehavior() ==
    504          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
    505    // If the other side has decided to partition third-party cookies, update
    506    // our side when first-party isolation is disabled.
    507    if (!newCookieJarSettings->mIsFirstPartyIsolated) {
    508      newCookieJarSettings->mCookieBehavior =
    509          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
    510    }
    511  }
    512  if (newCookieJarSettings->mCookieBehavior ==
    513          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
    514      aData.cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
    515    // If we've decided to partition third-party cookies, the other side may not
    516    // have caught up yet unless it has first-party isolation enabled.
    517    if (aData.isFirstPartyIsolated()) {
    518      newCookieJarSettings->mCookieBehavior =
    519          nsICookieService::BEHAVIOR_REJECT_TRACKER;
    520      newCookieJarSettings->mIsFirstPartyIsolated = true;
    521    }
    522  }
    523  // Ignore all other cases.
    524  MOZ_ASSERT_IF(
    525      newCookieJarSettings->mIsFirstPartyIsolated,
    526      newCookieJarSettings->mCookieBehavior !=
    527          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
    528 
    529  if (aData.shouldResistFingerprinting()) {
    530    newCookieJarSettings->mShouldResistFingerprinting = true;
    531  }
    532 
    533  // Merge partition Key. When a channel is created in the the child process and
    534  // then opened in the parent process, the partition key will be created in the
    535  // parent process, then sending back to the child process. Merging it here to
    536  // ensure the child process has the latest value.
    537  newCookieJarSettings->mPartitionKey = aData.partitionKey();
    538 
    539  PermissionComparator comparator;
    540 
    541  for (const CookiePermissionData& data : aData.cookiePermissions()) {
    542    auto principalOrErr = PrincipalInfoToPrincipal(data.principalInfo());
    543    if (NS_WARN_IF(principalOrErr.isErr())) {
    544      continue;
    545    }
    546 
    547    nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
    548    nsCOMPtr<nsIPermission> permission = Permission::Create(
    549        principal, "cookie"_ns, data.cookiePermission(), 0, 0, 0);
    550    if (NS_WARN_IF(!permission)) {
    551      continue;
    552    }
    553 
    554    if (!newCookieJarSettings->mCookiePermissions.Contains(permission,
    555                                                           comparator)) {
    556      newCookieJarSettings->mCookiePermissions.AppendElement(permission);
    557    }
    558  }
    559 
    560  return newCookieJarSettings.forget();
    561 }
    562 
    563 void CookieJarSettings::SetPartitionKey(nsIURI* aURI) {
    564  MOZ_ASSERT(aURI);
    565 
    566  OriginAttributes attrs;
    567  attrs.SetPartitionKey(aURI, false);
    568  mPartitionKey = std::move(attrs.mPartitionKey);
    569 
    570  mToBeMerged = true;
    571 }
    572 
    573 void CookieJarSettings::UpdatePartitionKeyForDocumentLoadedByChannel(
    574    nsIChannel* aChannel) {
    575  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    576  bool thirdParty = AntiTrackingUtils::IsThirdPartyChannel(aChannel);
    577  bool foreignByAncestorContext =
    578      thirdParty && !loadInfo->GetIsThirdPartyContextToTopWindow();
    579  StoragePrincipalHelper::UpdatePartitionKeyWithForeignAncestorBit(
    580      mPartitionKey, foreignByAncestorContext);
    581 
    582  mToBeMerged = true;
    583 }
    584 
    585 void CookieJarSettings::UpdateIsOnContentBlockingAllowList(
    586    nsIChannel* aChannel) {
    587  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
    588  MOZ_ASSERT(aChannel);
    589 
    590  // Early return if the flag was updated before.
    591  if (mIsOnContentBlockingAllowListUpdated) {
    592    return;
    593  }
    594  mIsOnContentBlockingAllowListUpdated = true;
    595 
    596  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    597 
    598  nsCOMPtr<nsIURI> uri;
    599  nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
    600  if (NS_WARN_IF(NS_FAILED(rv))) {
    601    return;
    602  }
    603 
    604  // We need to recompute the ContentBlockingAllowListPrincipal here for the
    605  // top level channel because we might navigate from the the initial
    606  // about:blank page or the existing page which may have a different origin
    607  // than the URI we are going to load here. Thus, we need to recompute the
    608  // prinicpal in order to get the correct ContentBlockingAllowListPrincipal.
    609  nsCOMPtr<nsIPrincipal> contentBlockingAllowListPrincipal;
    610  OriginAttributes attrs;
    611  loadInfo->GetOriginAttributes(&attrs);
    612  ContentBlockingAllowList::RecomputePrincipal(
    613      uri, attrs, getter_AddRefs(contentBlockingAllowListPrincipal));
    614 
    615  if (!contentBlockingAllowListPrincipal ||
    616      !contentBlockingAllowListPrincipal->GetIsContentPrincipal()) {
    617    return;
    618  }
    619 
    620  (void)ContentBlockingAllowList::Check(contentBlockingAllowListPrincipal,
    621                                        NS_UsePrivateBrowsing(aChannel),
    622                                        mIsOnContentBlockingAllowList);
    623 
    624  mToBeMerged = true;
    625 }
    626 
    627 // static
    628 bool CookieJarSettings::IsRejectThirdPartyContexts(uint32_t aCookieBehavior) {
    629  return aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
    630         aCookieBehavior ==
    631             nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
    632 }
    633 
    634 NS_IMETHODIMP
    635 CookieJarSettings::Read(nsIObjectInputStream* aStream) {
    636  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    637  nsresult rv = aStream->Read32(&mCookieBehavior);
    638  if (NS_WARN_IF(NS_FAILED(rv))) {
    639    return rv;
    640  }
    641 
    642  rv = aStream->ReadBoolean(&mIsFirstPartyIsolated);
    643  if (NS_WARN_IF(NS_FAILED(rv))) {
    644    return rv;
    645  }
    646 
    647  rv = aStream->ReadBoolean(&mShouldResistFingerprinting);
    648  if (NS_WARN_IF(NS_FAILED(rv))) {
    649    return rv;
    650  }
    651 
    652  bool isFixed;
    653  rv = aStream->ReadBoolean(&isFixed);
    654  if (NS_WARN_IF(NS_FAILED(rv))) {
    655    return rv;
    656  }
    657  mState = isFixed ? eFixed : eProgressive;
    658 
    659  rv = aStream->ReadBoolean(&mIsOnContentBlockingAllowList);
    660  if (NS_WARN_IF(NS_FAILED(rv))) {
    661    return rv;
    662  }
    663 
    664  rv = aStream->ReadString(mPartitionKey);
    665  if (NS_WARN_IF(NS_FAILED(rv))) {
    666    return rv;
    667  }
    668 
    669  // Deserializing the cookie permission list.
    670  uint32_t cookiePermissionsLength;
    671  rv = aStream->Read32(&cookiePermissionsLength);
    672  if (NS_WARN_IF(NS_FAILED(rv))) {
    673    return rv;
    674  }
    675 
    676  if (!cookiePermissionsLength) {
    677    // Bailing out early because there is no cookie permission.
    678    return NS_OK;
    679  }
    680 
    681  CookiePermissionList list;
    682  mCookiePermissions.SetCapacity(cookiePermissionsLength);
    683  for (uint32_t i = 0; i < cookiePermissionsLength; ++i) {
    684    nsAutoCString principalJSON;
    685    rv = aStream->ReadCString(principalJSON);
    686    if (NS_WARN_IF(NS_FAILED(rv))) {
    687      return rv;
    688    }
    689 
    690    nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(principalJSON);
    691 
    692    if (NS_WARN_IF(!principal)) {
    693      continue;
    694    }
    695 
    696    uint32_t cookiePermission;
    697    rv = aStream->Read32(&cookiePermission);
    698    if (NS_WARN_IF(NS_FAILED(rv))) {
    699      return rv;
    700    }
    701 
    702    nsCOMPtr<nsIPermission> permission =
    703        Permission::Create(principal, "cookie"_ns, cookiePermission, 0, 0, 0);
    704    if (NS_WARN_IF(!permission)) {
    705      continue;
    706    }
    707 
    708    list.AppendElement(permission);
    709  }
    710 
    711  mCookiePermissions = std::move(list);
    712 
    713  return NS_OK;
    714 }
    715 
    716 NS_IMETHODIMP
    717 CookieJarSettings::Write(nsIObjectOutputStream* aStream) {
    718  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    719  nsresult rv = aStream->Write32(mCookieBehavior);
    720  if (NS_WARN_IF(NS_FAILED(rv))) {
    721    return rv;
    722  }
    723 
    724  rv = aStream->WriteBoolean(mIsFirstPartyIsolated);
    725  if (NS_WARN_IF(NS_FAILED(rv))) {
    726    return rv;
    727  }
    728 
    729  rv = aStream->WriteBoolean(mShouldResistFingerprinting);
    730  if (NS_WARN_IF(NS_FAILED(rv))) {
    731    return rv;
    732  }
    733 
    734  rv = aStream->WriteBoolean(mState == eFixed);
    735  if (NS_WARN_IF(NS_FAILED(rv))) {
    736    return rv;
    737  }
    738 
    739  rv = aStream->WriteBoolean(mIsOnContentBlockingAllowList);
    740  if (NS_WARN_IF(NS_FAILED(rv))) {
    741    return rv;
    742  }
    743 
    744  rv = aStream->WriteWStringZ(mPartitionKey.get());
    745  if (NS_WARN_IF(NS_FAILED(rv))) {
    746    return rv;
    747  }
    748 
    749  // Serializing the cookie permission list. It will first write the length of
    750  // the list, and then, write the cookie permission consecutively.
    751  const auto& cookiePermissions = GetCookiePermissionsListRef();
    752  uint32_t cookiePermissionsLength = cookiePermissions.Length();
    753  rv = aStream->Write32(cookiePermissionsLength);
    754  if (NS_WARN_IF(NS_FAILED(rv))) {
    755    return rv;
    756  }
    757 
    758  for (const RefPtr<nsIPermission>& permission : cookiePermissions) {
    759    nsCOMPtr<nsIPrincipal> principal;
    760    nsresult rv = permission->GetPrincipal(getter_AddRefs(principal));
    761    if (NS_WARN_IF(NS_FAILED(rv))) {
    762      continue;
    763    }
    764 
    765    nsAutoCString principalJSON;
    766    BasePrincipal::Cast(principal)->ToJSON(principalJSON);
    767 
    768    rv = aStream->WriteStringZ(principalJSON.get());
    769    if (NS_WARN_IF(NS_FAILED(rv))) {
    770      return rv;
    771    }
    772 
    773    uint32_t cookiePermission = 0;
    774    rv = permission->GetCapability(&cookiePermission);
    775    if (NS_WARN_IF(NS_FAILED(rv))) {
    776      continue;
    777    }
    778 
    779    rv = aStream->Write32(cookiePermission);
    780    if (NS_WARN_IF(NS_FAILED(rv))) {
    781      return rv;
    782    }
    783  }
    784 
    785  return NS_OK;
    786 }
    787 
    788 }  // namespace net
    789 }  // namespace mozilla