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