CookieService.cpp (65399B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 ts=8 et 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 "CookieCommons.h" 8 #include "CookieLogging.h" 9 #include "CookieParser.h" 10 #include "CookieService.h" 11 #include "CookieValidation.h" 12 #include "mozilla/AppShutdown.h" 13 #include "mozilla/ClearOnShutdown.h" 14 #include "mozilla/Components.h" 15 #include "mozilla/ConsoleReportCollector.h" 16 #include "mozilla/ContentBlockingNotifier.h" 17 #include "mozilla/RefPtr.h" 18 #include "mozilla/dom/Document.h" 19 #include "mozilla/dom/nsMixedContentBlocker.h" 20 #include "mozilla/dom/Promise.h" 21 #include "mozilla/dom/Promise-inl.h" 22 #include "mozilla/net/CookieJarSettings.h" 23 #include "mozilla/net/CookiePersistentStorage.h" 24 #include "mozilla/net/CookiePrivateStorage.h" 25 #include "mozilla/net/CookieService.h" 26 #include "mozilla/net/CookieServiceChild.h" 27 #include "mozilla/net/HttpBaseChannel.h" 28 #include "mozilla/net/NeckoCommon.h" 29 #include "mozilla/StaticPrefs_network.h" 30 #include "mozilla/StoragePrincipalHelper.h" 31 #include "mozIThirdPartyUtil.h" 32 #include "nsICookiePermission.h" 33 #include "nsIConsoleReportCollector.h" 34 #include "nsIEffectiveTLDService.h" 35 #include "nsIScriptError.h" 36 #include "nsIScriptSecurityManager.h" 37 #include "nsIURI.h" 38 #include "nsIWebProgressListener.h" 39 #include "nsNetUtil.h" 40 #include "ThirdPartyUtil.h" 41 42 using namespace mozilla::dom; 43 44 namespace { 45 46 uint32_t MakeCookieBehavior(uint32_t aCookieBehavior) { 47 bool isFirstPartyIsolated = OriginAttributes::IsFirstPartyEnabled(); 48 49 if (isFirstPartyIsolated && 50 aCookieBehavior == 51 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) { 52 return nsICookieService::BEHAVIOR_REJECT_TRACKER; 53 } 54 return aCookieBehavior; 55 } 56 57 /* 58 Enables sanitizeOnShutdown cleaning prefs and disables the 59 network.cookie.lifetimePolicy 60 */ 61 void MigrateCookieLifetimePrefs() { 62 // Former network.cookie.lifetimePolicy values ACCEPT_SESSION/ACCEPT_NORMALLY 63 // are not available anymore 2 = ACCEPT_SESSION 64 if (mozilla::Preferences::GetInt("network.cookie.lifetimePolicy") != 2) { 65 return; 66 } 67 if (!mozilla::Preferences::GetBool("privacy.sanitize.sanitizeOnShutdown")) { 68 mozilla::Preferences::SetBool("privacy.sanitize.sanitizeOnShutdown", true); 69 // To avoid clearing categories that the user did not intend to clear 70 mozilla::Preferences::SetBool("privacy.clearOnShutdown.history", false); 71 mozilla::Preferences::SetBool("privacy.clearOnShutdown.formdata", false); 72 mozilla::Preferences::SetBool("privacy.clearOnShutdown.downloads", false); 73 mozilla::Preferences::SetBool("privacy.clearOnShutdown.sessions", false); 74 mozilla::Preferences::SetBool("privacy.clearOnShutdown.siteSettings", 75 false); 76 77 // We will migrate the new clear on shutdown prefs to align both sets of 78 // prefs incase the user has not migrated yet. We don't have a new sessions 79 // prefs, as it was merged into cookiesAndStorage as part of the effort for 80 // the clear data revamp Bug 1853996 81 mozilla::Preferences::SetBool( 82 "privacy.clearOnShutdown_v2.browsingHistoryAndDownloads", false); 83 mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.siteSettings", 84 false); 85 } 86 mozilla::Preferences::SetBool("privacy.clearOnShutdown.cookies", true); 87 mozilla::Preferences::SetBool("privacy.clearOnShutdown.cache", true); 88 mozilla::Preferences::SetBool("privacy.clearOnShutdown.offlineApps", true); 89 90 // Migrate the new clear on shutdown prefs 91 mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.cookiesAndStorage", 92 true); 93 mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.cache", true); 94 mozilla::Preferences::ClearUser("network.cookie.lifetimePolicy"); 95 } 96 97 } // anonymous namespace 98 99 // static 100 uint32_t nsICookieManager::GetCookieBehavior(bool aIsPrivate) { 101 if (aIsPrivate) { 102 // To sync the cookieBehavior pref between regular and private mode in ETP 103 // custom mode, we will return the regular cookieBehavior pref for private 104 // mode when 105 // 1. The regular cookieBehavior pref has a non-default value. 106 // 2. And the private cookieBehavior pref has a default value. 107 // Also, this can cover the migration case where the user has a non-default 108 // cookieBehavior before the private cookieBehavior was introduced. The 109 // getter here will directly return the regular cookieBehavior, so that the 110 // cookieBehavior for private mode is consistent. 111 if (mozilla::Preferences::HasUserValue( 112 "network.cookie.cookieBehavior.pbmode")) { 113 return MakeCookieBehavior( 114 mozilla::StaticPrefs::network_cookie_cookieBehavior_pbmode()); 115 } 116 117 if (mozilla::Preferences::HasUserValue("network.cookie.cookieBehavior")) { 118 return MakeCookieBehavior( 119 mozilla::StaticPrefs::network_cookie_cookieBehavior()); 120 } 121 122 return MakeCookieBehavior( 123 mozilla::StaticPrefs::network_cookie_cookieBehavior_pbmode()); 124 } 125 return MakeCookieBehavior( 126 mozilla::StaticPrefs::network_cookie_cookieBehavior()); 127 } 128 129 namespace mozilla { 130 namespace net { 131 132 /****************************************************************************** 133 * CookieService impl: 134 * useful types & constants 135 ******************************************************************************/ 136 137 static StaticRefPtr<CookieService> gCookieService; 138 139 namespace { 140 141 // Return false if the cookie should be ignored for the current channel. 142 bool ProcessSameSiteCookieForForeignRequest(nsIChannel* aChannel, 143 Cookie* aCookie, 144 bool aIsSafeTopLevelNav, 145 bool aHadCrossSiteRedirects, 146 bool aLaxByDefault) { 147 // If it's a cross-site request and the cookie is same site only (strict) 148 // don't send it. 149 if (aCookie->SameSite() == nsICookie::SAMESITE_STRICT) { 150 return false; 151 } 152 153 // Explicit SameSite=None cookies are always processed. When laxByDefault 154 // is OFF then so are default cookies. 155 if (aCookie->SameSite() == nsICookie::SAMESITE_NONE || 156 (!aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET)) { 157 return true; 158 } 159 160 // Lax-by-default cookies are processed even with an intermediate 161 // cross-site redirect (they are treated like aIsSameSiteForeign = false). 162 if (aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET && 163 aHadCrossSiteRedirects && 164 StaticPrefs:: 165 network_cookie_sameSite_laxByDefault_allowBoomerangRedirect()) { 166 return true; 167 } 168 169 int64_t currentTimeInUsec = PR_Now(); 170 171 // 2 minutes of tolerance for 'SameSite=Lax by default' for cookies set 172 // without a SameSite value when used for unsafe http methods. 173 if (aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET && 174 StaticPrefs::network_cookie_sameSite_laxPlusPOST_timeout() > 0 && 175 currentTimeInUsec - aCookie->UpdateTimeInUSec() <= 176 (StaticPrefs::network_cookie_sameSite_laxPlusPOST_timeout() * 177 PR_USEC_PER_SEC) && 178 !NS_IsSafeMethodNav(aChannel)) { 179 return true; 180 } 181 182 MOZ_ASSERT( 183 (aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET) || 184 aCookie->SameSite() == nsICookie::SAMESITE_LAX); 185 // We only have SameSite=Lax or lax-by-default cookies at this point. These 186 // are processed only if it's a top-level navigation 187 return aIsSafeTopLevelNav; 188 } 189 190 } // namespace 191 192 /****************************************************************************** 193 * CookieService impl: 194 * singleton instance ctor/dtor methods 195 ******************************************************************************/ 196 197 already_AddRefed<nsICookieService> CookieService::GetXPCOMSingleton() { 198 if (IsNeckoChild()) { 199 return CookieServiceChild::GetSingleton(); 200 } 201 202 return GetSingleton(); 203 } 204 205 already_AddRefed<CookieService> CookieService::GetSingleton() { 206 NS_ASSERTION(!IsNeckoChild(), "not a parent process"); 207 208 if (gCookieService) { 209 return do_AddRef(gCookieService); 210 } 211 212 // Create a new singleton CookieService. 213 // We AddRef only once since XPCOM has rules about the ordering of module 214 // teardowns - by the time our module destructor is called, it's too late to 215 // Release our members (e.g. nsIObserverService and nsIPrefBranch), since GC 216 // cycles have already been completed and would result in serious leaks. 217 // See bug 209571. 218 // TODO: Verify what is the earliest point in time during shutdown where 219 // we can deny the creation of the CookieService as a whole. 220 gCookieService = new CookieService(); 221 if (gCookieService) { 222 if (NS_SUCCEEDED(gCookieService->Init())) { 223 ClearOnShutdown(&gCookieService); 224 } else { 225 gCookieService = nullptr; 226 } 227 } 228 229 return do_AddRef(gCookieService); 230 } 231 232 /****************************************************************************** 233 * CookieService impl: 234 * public methods 235 ******************************************************************************/ 236 237 NS_IMPL_ISUPPORTS(CookieService, nsICookieService, nsICookieManager, 238 nsIObserver, nsISupportsWeakReference, nsIMemoryReporter) 239 240 CookieService::CookieService() = default; 241 242 nsresult CookieService::Init() { 243 nsresult rv; 244 mTLDService = mozilla::components::EffectiveTLD::Service(&rv); 245 NS_ENSURE_SUCCESS(rv, rv); 246 247 mThirdPartyUtil = mozilla::components::ThirdPartyUtil::Service(); 248 NS_ENSURE_SUCCESS(rv, rv); 249 250 // Init our default, and possibly private CookieStorages. 251 InitCookieStorages(); 252 253 // Migrate network.cookie.lifetimePolicy pref to sanitizeOnShutdown prefs 254 MigrateCookieLifetimePrefs(); 255 256 RegisterWeakMemoryReporter(this); 257 258 nsCOMPtr<nsIObserverService> os = services::GetObserverService(); 259 NS_ENSURE_STATE(os); 260 os->AddObserver(this, "profile-before-change", true); 261 os->AddObserver(this, "profile-do-change", true); 262 os->AddObserver(this, "last-pb-context-exited", true); 263 os->AddObserver(this, "browser-delayed-startup-finished", true); 264 265 return NS_OK; 266 } 267 268 void CookieService::InitCookieStorages() { 269 NS_ASSERTION(!mPersistentStorage, "already have a default CookieStorage"); 270 NS_ASSERTION(!mPrivateStorage, "already have a private CookieStorage"); 271 272 // Create two new CookieStorages. If we are in or beyond our observed 273 // shutdown phase, just be non-persistent. 274 if (MOZ_UNLIKELY(StaticPrefs::network_cookie_noPersistentStorage() || 275 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown))) { 276 mPersistentStorage = CookiePrivateStorage::Create(); 277 } else { 278 mPersistentStorage = CookiePersistentStorage::Create(); 279 } 280 281 mPrivateStorage = CookiePrivateStorage::Create(); 282 } 283 284 void CookieService::CloseCookieStorages() { 285 // return if we already closed 286 if (!mPersistentStorage) { 287 return; 288 } 289 290 // Let's nullify both storages before calling Close(). 291 RefPtr<CookieStorage> privateStorage; 292 privateStorage.swap(mPrivateStorage); 293 294 RefPtr<CookieStorage> persistentStorage; 295 persistentStorage.swap(mPersistentStorage); 296 297 privateStorage->Close(); 298 persistentStorage->Close(); 299 } 300 301 CookieService::~CookieService() { 302 CloseCookieStorages(); 303 304 UnregisterWeakMemoryReporter(this); 305 306 gCookieService = nullptr; 307 } 308 309 NS_IMETHODIMP 310 CookieService::Observe(nsISupports* /*aSubject*/, const char* aTopic, 311 const char16_t* /*aData*/) { 312 // check the topic 313 if (!strcmp(aTopic, "profile-before-change")) { 314 // The profile is about to change, 315 // or is going away because the application is shutting down. 316 317 // Close the default DB connection and null out our CookieStorages before 318 // changing. 319 CloseCookieStorages(); 320 321 } else if (!strcmp(aTopic, "profile-do-change")) { 322 NS_ASSERTION(!mPersistentStorage, "shouldn't have a default CookieStorage"); 323 NS_ASSERTION(!mPrivateStorage, "shouldn't have a private CookieStorage"); 324 325 // the profile has already changed; init the db from the new location. 326 // if we are in the private browsing state, however, we do not want to read 327 // data into it - we should instead put it into the default state, so it's 328 // ready for us if and when we switch back to it. 329 InitCookieStorages(); 330 331 } else if (!strcmp(aTopic, "browser-delayed-startup-finished")) { 332 mThirdPartyCookieBlockingExceptions.Initialize(); 333 334 RunOnShutdown([self = RefPtr{this}] { 335 self->mThirdPartyCookieBlockingExceptions.Shutdown(); 336 }); 337 } else if (!strcmp(aTopic, "last-pb-context-exited")) { 338 // Flush all the cookies stored by private browsing contexts 339 OriginAttributesPattern pattern; 340 pattern.mPrivateBrowsingId.Construct(1); 341 RemoveCookiesWithOriginAttributes(pattern, ""_ns); 342 mPrivateStorage = CookiePrivateStorage::Create(); 343 } 344 345 return NS_OK; 346 } 347 348 NS_IMETHODIMP 349 CookieService::GetCookieBehavior(bool aIsPrivate, uint32_t* aCookieBehavior) { 350 NS_ENSURE_ARG_POINTER(aCookieBehavior); 351 *aCookieBehavior = nsICookieManager::GetCookieBehavior(aIsPrivate); 352 return NS_OK; 353 } 354 355 NS_IMETHODIMP 356 CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel, 357 nsACString& aCookieString) { 358 NS_ENSURE_ARG(aHostURI); 359 NS_ENSURE_ARG(aChannel); 360 361 aCookieString.Truncate(); 362 363 if (!CookieCommons::IsSchemeSupported(aHostURI)) { 364 return NS_OK; 365 } 366 367 uint32_t rejectedReason = 0; 368 ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel( 369 aChannel, false, aHostURI, nullptr, &rejectedReason); 370 371 bool isSafeTopLevelNav = CookieCommons::IsSafeTopLevelNav(aChannel); 372 bool hadCrossSiteRedirects = false; 373 bool isSameSiteForeign = CookieCommons::IsSameSiteForeign( 374 aChannel, aHostURI, &hadCrossSiteRedirects); 375 376 OriginAttributes storageOriginAttributes; 377 StoragePrincipalHelper::GetOriginAttributes( 378 aChannel, storageOriginAttributes, 379 StoragePrincipalHelper::eStorageAccessPrincipal); 380 381 nsTArray<OriginAttributes> originAttributesList; 382 originAttributesList.AppendElement(storageOriginAttributes); 383 384 // CHIPS - If CHIPS is enabled the partitioned cookie jar is always available 385 // (and therefore the partitioned OriginAttributes), the unpartitioned cookie 386 // jar is only available in first-party or third-party with storageAccess 387 // contexts. 388 nsCOMPtr<nsICookieJarSettings> cookieJarSettings = 389 CookieCommons::GetCookieJarSettings(aChannel); 390 bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() && 391 !cookieJarSettings->GetBlockingAllContexts(); 392 bool isUnpartitioned = 393 !result.contains(ThirdPartyAnalysis::IsForeign) || 394 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted); 395 if (isCHIPS && isUnpartitioned) { 396 // Assert that the storage originAttributes is empty. In other words, 397 // it's unpartitioned. 398 MOZ_ASSERT(storageOriginAttributes.mPartitionKey.IsEmpty()); 399 // Add the partitioned principal to principals 400 OriginAttributes partitionedOriginAttributes; 401 StoragePrincipalHelper::GetOriginAttributes( 402 aChannel, partitionedOriginAttributes, 403 StoragePrincipalHelper::ePartitionedPrincipal); 404 // Only append the partitioned originAttributes if the partitionKey is set. 405 // The partitionKey could be empty for partitionKey in partitioned 406 // originAttributes if the channel is for privilege request, such as 407 // extension's requests. 408 if (!partitionedOriginAttributes.mPartitionKey.IsEmpty()) { 409 originAttributesList.AppendElement(partitionedOriginAttributes); 410 } 411 } 412 413 AutoTArray<RefPtr<Cookie>, 8> foundCookieList; 414 GetCookiesForURI( 415 aHostURI, aChannel, result.contains(ThirdPartyAnalysis::IsForeign), 416 result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource), 417 result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource), 418 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted), 419 rejectedReason, isSafeTopLevelNav, isSameSiteForeign, 420 hadCrossSiteRedirects, true, false, originAttributesList, 421 foundCookieList); 422 423 CookieCommons::ComposeCookieString(foundCookieList, aCookieString); 424 425 if (!aCookieString.IsEmpty()) { 426 COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, aCookieString, nullptr, false); 427 } 428 return NS_OK; 429 } 430 431 NS_IMETHODIMP 432 CookieService::SetCookieStringFromHttp(nsIURI* aHostURI, 433 const nsACString& aCookieHeader, 434 nsIChannel* aChannel) { 435 NS_ENSURE_ARG(aHostURI); 436 NS_ENSURE_ARG(aChannel); 437 438 if (!IsInitialized()) { 439 return NS_OK; 440 } 441 442 if (!CookieCommons::IsSchemeSupported(aHostURI)) { 443 return NS_OK; 444 } 445 446 uint32_t rejectedReason = 0; 447 ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel( 448 aChannel, false, aHostURI, nullptr, &rejectedReason); 449 450 OriginAttributes storagePrincipalOriginAttributes; 451 StoragePrincipalHelper::GetOriginAttributes( 452 aChannel, storagePrincipalOriginAttributes, 453 StoragePrincipalHelper::eStorageAccessPrincipal); 454 455 // get the base domain for the host URI. 456 // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk". 457 // file:// URI's (i.e. with an empty host) are allowed, but any other 458 // scheme must have a non-empty host. A trailing dot in the host 459 // is acceptable. 460 bool requireHostMatch; 461 nsAutoCString baseDomain; 462 nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI, baseDomain, 463 requireHostMatch); 464 if (NS_FAILED(rv)) { 465 COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, 466 "couldn't get base domain from URI"); 467 return NS_OK; 468 } 469 470 nsCOMPtr<nsICookieJarSettings> cookieJarSettings = 471 CookieCommons::GetCookieJarSettings(aChannel); 472 473 nsAutoCString hostFromURI; 474 nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI); 475 476 nsAutoCString baseDomainFromURI; 477 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, hostFromURI, 478 baseDomainFromURI); 479 NS_ENSURE_SUCCESS(rv, NS_OK); 480 481 CookieStorage* storage = PickStorage(storagePrincipalOriginAttributes); 482 483 // check default prefs 484 uint32_t priorCookieCount = storage->CountCookiesFromHost( 485 baseDomainFromURI, storagePrincipalOriginAttributes.mPrivateBrowsingId); 486 487 nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel); 488 489 CookieStatus cookieStatus = CheckPrefs( 490 crc, cookieJarSettings, aHostURI, 491 result.contains(ThirdPartyAnalysis::IsForeign), 492 result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource), 493 result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource), 494 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted), 495 aCookieHeader, priorCookieCount, storagePrincipalOriginAttributes, 496 &rejectedReason); 497 498 MOZ_ASSERT_IF( 499 rejectedReason && 500 rejectedReason != 501 nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER, 502 cookieStatus == STATUS_REJECTED); 503 504 // fire a notification if third party or if cookie was rejected 505 // (but not if there was an error) 506 switch (cookieStatus) { 507 case STATUS_REJECTED: 508 CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason, 509 OPERATION_WRITE); 510 return NS_OK; // Stop here 511 case STATUS_REJECTED_WITH_ERROR: 512 CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason, 513 OPERATION_WRITE); 514 return NS_OK; 515 case STATUS_ACCEPTED: // Fallthrough 516 case STATUS_ACCEPT_SESSION: 517 NotifyAccepted(aChannel); 518 519 // Notify the content blocking event if tracker cookies are partitioned. 520 if (rejectedReason == 521 nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER) { 522 ContentBlockingNotifier::OnDecision( 523 aChannel, ContentBlockingNotifier::BlockingDecision::eBlock, 524 rejectedReason); 525 } 526 break; 527 default: 528 break; 529 } 530 531 bool addonAllowsLoad = false; 532 nsCOMPtr<nsIURI> channelURI; 533 NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); 534 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 535 addonAllowsLoad = BasePrincipal::Cast(loadInfo->TriggeringPrincipal()) 536 ->AddonAllowsLoad(channelURI); 537 538 bool isForeignAndNotAddon = false; 539 if (!addonAllowsLoad) { 540 mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, 541 &isForeignAndNotAddon); 542 543 // include sub-document navigations from cross-site to same-site 544 // wrt top-level in our check for thirdparty-ness 545 if (StaticPrefs::network_cookie_sameSite_crossSiteIframeSetCheck() && 546 !isForeignAndNotAddon && 547 loadInfo->GetExternalContentPolicyType() == 548 ExtContentPolicy::TYPE_SUBDOCUMENT) { 549 bool triggeringPrincipalIsThirdParty = false; 550 BasePrincipal::Cast(loadInfo->TriggeringPrincipal()) 551 ->IsThirdPartyURI(channelURI, &triggeringPrincipalIsThirdParty); 552 isForeignAndNotAddon |= triggeringPrincipalIsThirdParty; 553 } 554 } 555 556 bool mustBePartitioned = 557 isForeignAndNotAddon && 558 cookieJarSettings->GetCookieBehavior() == 559 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN && 560 !result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted); 561 562 nsCString cookieHeader(aCookieHeader); 563 564 // CHIPS - The partitioned cookie jar is always available and it is always 565 // possible to store cookies in it using the "Partitioned" attribute. 566 // Prepare the partitioned principals OAs to enable possible partitioned 567 // cookie storing from first-party or with StorageAccess. 568 // Similar behavior to CookieServiceChild::SetCookieStringFromHttp(). 569 OriginAttributes partitionedPrincipalOriginAttributes; 570 bool isPartitionedPrincipal = 571 !storagePrincipalOriginAttributes.mPartitionKey.IsEmpty(); 572 bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() && 573 !cookieJarSettings->GetBlockingAllContexts(); 574 // Only need to get OAs if we don't already use the partitioned principal. 575 if (isCHIPS && !isPartitionedPrincipal) { 576 StoragePrincipalHelper::GetOriginAttributes( 577 aChannel, partitionedPrincipalOriginAttributes, 578 StoragePrincipalHelper::ePartitionedPrincipal); 579 } 580 581 nsAutoCString dateHeader; 582 CookieCommons::GetServerDateHeader(aChannel, dateHeader); 583 584 // process each cookie in the header 585 CookieParser cookieParser(crc, aHostURI); 586 587 cookieParser.Parse(baseDomain, requireHostMatch, cookieStatus, cookieHeader, 588 dateHeader, true, isForeignAndNotAddon, mustBePartitioned, 589 storagePrincipalOriginAttributes.IsPrivateBrowsing(), 590 loadInfo->GetIsOn3PCBExceptionList(), 591 CookieCommons::GetCurrentTimeInUSecFromChannel(aChannel)); 592 593 if (!cookieParser.ContainsCookie()) { 594 return NS_OK; 595 } 596 597 // check permissions from site permission list. 598 if (!CookieCommons::CheckCookiePermission(aChannel, 599 cookieParser.CookieData())) { 600 COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, 601 "cookie rejected by permission manager"); 602 CookieCommons::NotifyRejected( 603 aHostURI, aChannel, 604 nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION, 605 OPERATION_WRITE); 606 cookieParser.RejectCookie(CookieParser::RejectedByPermissionManager); 607 return NS_OK; 608 } 609 610 // CHIPS - If the partitioned attribute is set, store cookie in partitioned 611 // cookie jar independent of context. If the cookies are stored in the 612 // partitioned cookie jar anyway no special treatment of CHIPS cookies 613 // necessary. 614 bool needPartitioned = isCHIPS && cookieParser.CookieData().isPartitioned() && 615 !isPartitionedPrincipal; 616 OriginAttributes& cookieOriginAttributes = 617 needPartitioned ? partitionedPrincipalOriginAttributes 618 : storagePrincipalOriginAttributes; 619 // Assert that partitionedPrincipalOriginAttributes are initialized if used. 620 MOZ_ASSERT_IF(needPartitioned, 621 !partitionedPrincipalOriginAttributes.mPartitionKey.IsEmpty()); 622 623 // create a new Cookie 624 RefPtr<Cookie> cookie = 625 Cookie::Create(cookieParser.CookieData(), cookieOriginAttributes); 626 MOZ_ASSERT(cookie); 627 628 int64_t currentTimeInUsec = PR_Now(); 629 cookie->SetLastAccessedInUSec(currentTimeInUsec); 630 cookie->SetCreationTimeInUSec( 631 Cookie::GenerateUniqueCreationTimeInUSec(currentTimeInUsec)); 632 cookie->SetUpdateTimeInUSec(cookie->CreationTimeInUSec()); 633 634 // Use TargetBrowsingContext to also take frame loads into account. 635 RefPtr<BrowsingContext> bc = loadInfo->GetTargetBrowsingContext(); 636 637 // add the cookie to the list. AddCookie() takes care of logging. 638 storage->AddCookie(&cookieParser, baseDomain, cookieOriginAttributes, cookie, 639 currentTimeInUsec, aHostURI, aCookieHeader, true, 640 isForeignAndNotAddon, bc); 641 642 return NS_OK; 643 } 644 645 void CookieService::NotifyAccepted(nsIChannel* aChannel) { 646 ContentBlockingNotifier::OnDecision( 647 aChannel, ContentBlockingNotifier::BlockingDecision::eAllow, 0); 648 } 649 650 /****************************************************************************** 651 * CookieService: 652 * public transaction helper impl 653 ******************************************************************************/ 654 655 NS_IMETHODIMP 656 CookieService::RunInTransaction(nsICookieTransactionCallback* aCallback) { 657 NS_ENSURE_ARG(aCallback); 658 659 if (!IsInitialized()) { 660 return NS_ERROR_NOT_AVAILABLE; 661 } 662 663 mPersistentStorage->EnsureInitialized(); 664 return mPersistentStorage->RunInTransaction(aCallback); 665 } 666 667 /****************************************************************************** 668 * nsICookieManager impl: 669 * nsICookieManager 670 ******************************************************************************/ 671 672 NS_IMETHODIMP 673 CookieService::RemoveAll() { 674 if (!IsInitialized()) { 675 return NS_ERROR_NOT_AVAILABLE; 676 } 677 678 mPersistentStorage->EnsureInitialized(); 679 mPersistentStorage->RemoveAll(); 680 return NS_OK; 681 } 682 683 NS_IMETHODIMP 684 CookieService::GetCookies(nsTArray<RefPtr<nsICookie>>& aCookies) { 685 if (!IsInitialized()) { 686 return NS_ERROR_NOT_AVAILABLE; 687 } 688 689 mPersistentStorage->EnsureInitialized(); 690 691 // We expose only non-private cookies. 692 mPersistentStorage->GetCookies(aCookies); 693 694 return NS_OK; 695 } 696 697 NS_IMETHODIMP 698 CookieService::GetSessionCookies(nsTArray<RefPtr<nsICookie>>& aCookies) { 699 if (!IsInitialized()) { 700 return NS_ERROR_NOT_AVAILABLE; 701 } 702 703 mPersistentStorage->EnsureInitialized(); 704 705 // We expose only non-private cookies. 706 mPersistentStorage->GetSessionCookies(aCookies); 707 708 return NS_OK; 709 } 710 711 NS_IMETHODIMP 712 CookieService::Add(const nsACString& aHost, const nsACString& aPath, 713 const nsACString& aName, const nsACString& aValue, 714 bool aIsSecure, bool aIsHttpOnly, bool aIsSession, 715 int64_t aExpiry, JS::Handle<JS::Value> aOriginAttributes, 716 int32_t aSameSite, nsICookie::schemeType aSchemeMap, 717 bool aIsPartitioned, JSContext* aCx, 718 nsICookieValidation** aValidation) { 719 NS_ENSURE_ARG_POINTER(aCx); 720 NS_ENSURE_ARG_POINTER(aValidation); 721 722 OriginAttributes attrs; 723 724 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 725 return NS_ERROR_INVALID_ARG; 726 } 727 728 nsCOMPtr<nsICookieValidation> validation; 729 nsresult rv = AddInternal(nullptr, aHost, aPath, aName, aValue, aIsSecure, 730 aIsHttpOnly, aIsSession, aExpiry, &attrs, aSameSite, 731 aSchemeMap, aIsPartitioned, /* from-http: */ true, 732 nullptr, getter_AddRefs(validation)); 733 if (rv != NS_ERROR_ILLEGAL_VALUE || !validation || 734 CookieValidation::Cast(validation)->Result() == 735 nsICookieValidation::eOK) { 736 validation.forget(aValidation); 737 return rv; 738 } 739 740 validation.forget(aValidation); 741 return NS_OK; 742 } 743 744 NS_IMETHODIMP_(nsresult) 745 CookieService::AddNative(nsIURI* aCookieURI, const nsACString& aHost, 746 const nsACString& aPath, const nsACString& aName, 747 const nsACString& aValue, bool aIsSecure, 748 bool aIsHttpOnly, bool aIsSession, int64_t aExpiry, 749 OriginAttributes* aOriginAttributes, int32_t aSameSite, 750 nsICookie::schemeType aSchemeMap, bool aIsPartitioned, 751 bool aFromHttp, const nsID* aOperationID, 752 nsICookieValidation** aValidation) { 753 return AddInternal(aCookieURI, aHost, aPath, aName, aValue, aIsSecure, 754 aIsHttpOnly, aIsSession, aExpiry, aOriginAttributes, 755 aSameSite, aSchemeMap, aIsPartitioned, aFromHttp, 756 aOperationID, aValidation); 757 } 758 759 nsresult CookieService::AddInternal( 760 nsIURI* aCookieURI, const nsACString& aHost, const nsACString& aPath, 761 const nsACString& aName, const nsACString& aValue, bool aIsSecure, 762 bool aIsHttpOnly, bool aIsSession, int64_t aExpiry, 763 OriginAttributes* aOriginAttributes, int32_t aSameSite, 764 nsICookie::schemeType aSchemeMap, bool aIsPartitioned, bool aFromHttp, 765 const nsID* aOperationID, nsICookieValidation** aValidation) { 766 NS_ENSURE_ARG_POINTER(aValidation); 767 768 if (NS_WARN_IF(!aOriginAttributes)) { 769 return NS_ERROR_FAILURE; 770 } 771 772 if (!IsInitialized()) { 773 return NS_ERROR_NOT_AVAILABLE; 774 } 775 776 // first, normalize the hostname, and fail if it contains illegal characters. 777 nsAutoCString host(aHost); 778 nsresult rv = NormalizeHost(host); 779 NS_ENSURE_SUCCESS(rv, rv); 780 781 // get the base domain for the host URI. 782 // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk". 783 nsAutoCString baseDomain; 784 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain); 785 NS_ENSURE_SUCCESS(rv, rv); 786 787 int64_t currentTimeInUsec = PR_Now(); 788 int64_t uniqueCreationTimeInUSec = 789 Cookie::GenerateUniqueCreationTimeInUSec(currentTimeInUsec); 790 791 CookieStruct cookieData(nsCString(aName), nsCString(aValue), host, 792 nsCString(aPath), aExpiry, currentTimeInUsec, 793 uniqueCreationTimeInUSec, uniqueCreationTimeInUSec, 794 aIsHttpOnly, aIsSession, aIsSecure, aIsPartitioned, 795 aSameSite, aSchemeMap); 796 797 RefPtr<CookieValidation> cv = CookieValidation::Validate(cookieData); 798 799 if (cv->Result() != nsICookieValidation::eOK) { 800 cv.forget(aValidation); 801 return NS_ERROR_ILLEGAL_VALUE; 802 } 803 804 RefPtr<Cookie> cookie = Cookie::Create(cookieData, *aOriginAttributes); 805 MOZ_ASSERT(cookie); 806 807 CookieStorage* storage = PickStorage(*aOriginAttributes); 808 storage->AddCookie(nullptr, baseDomain, *aOriginAttributes, cookie, 809 currentTimeInUsec, aCookieURI, VoidCString(), aFromHttp, 810 !aOriginAttributes->mPartitionKey.IsEmpty(), nullptr, 811 aOperationID); 812 813 cv.forget(aValidation); 814 return NS_OK; 815 } 816 817 nsresult CookieService::Remove(const nsACString& aHost, 818 const OriginAttributes& aAttrs, 819 const nsACString& aName, const nsACString& aPath, 820 bool aFromHttp, const nsID* aOperationID) { 821 // first, normalize the hostname, and fail if it contains illegal characters. 822 nsAutoCString host(aHost); 823 nsresult rv = NormalizeHost(host); 824 NS_ENSURE_SUCCESS(rv, rv); 825 826 nsAutoCString baseDomain; 827 if (!host.IsEmpty()) { 828 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain); 829 NS_ENSURE_SUCCESS(rv, rv); 830 } 831 832 if (!IsInitialized()) { 833 return NS_ERROR_NOT_AVAILABLE; 834 } 835 836 CookieStorage* storage = PickStorage(aAttrs); 837 storage->RemoveCookie(baseDomain, aAttrs, host, PromiseFlatCString(aName), 838 PromiseFlatCString(aPath), aFromHttp, aOperationID); 839 840 return NS_OK; 841 } 842 843 NS_IMETHODIMP 844 CookieService::Remove(const nsACString& aHost, const nsACString& aName, 845 const nsACString& aPath, 846 JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx) { 847 OriginAttributes attrs; 848 849 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 850 return NS_ERROR_INVALID_ARG; 851 } 852 853 return RemoveNative(aHost, aName, aPath, &attrs, /* from http: */ true, 854 nullptr); 855 } 856 857 NS_IMETHODIMP_(nsresult) 858 CookieService::RemoveNative(const nsACString& aHost, const nsACString& aName, 859 const nsACString& aPath, 860 OriginAttributes* aOriginAttributes, bool aFromHttp, 861 const nsID* aOperationID) { 862 if (NS_WARN_IF(!aOriginAttributes)) { 863 return NS_ERROR_FAILURE; 864 } 865 866 nsresult rv = 867 Remove(aHost, *aOriginAttributes, aName, aPath, aFromHttp, aOperationID); 868 if (NS_WARN_IF(NS_FAILED(rv))) { 869 return rv; 870 } 871 872 return NS_OK; 873 } 874 875 void CookieService::GetCookiesForURI( 876 nsIURI* aHostURI, nsIChannel* aChannel, bool aIsForeign, 877 bool aIsThirdPartyTrackingResource, 878 bool aIsThirdPartySocialTrackingResource, 879 bool aStorageAccessPermissionGranted, uint32_t aRejectedReason, 880 bool aIsSafeTopLevelNav, bool aIsSameSiteForeign, 881 bool aHadCrossSiteRedirects, bool aHttpBound, 882 bool aAllowSecureCookiesToInsecureOrigin, 883 const nsTArray<OriginAttributes>& aOriginAttrsList, 884 nsTArray<RefPtr<Cookie>>& aCookieList) { 885 NS_ASSERTION(aHostURI, "null host!"); 886 887 if (!CookieCommons::IsSchemeSupported(aHostURI)) { 888 return; 889 } 890 891 if (!IsInitialized()) { 892 return; 893 } 894 895 nsCOMPtr<nsICookieJarSettings> cookieJarSettings = 896 CookieCommons::GetCookieJarSettings(aChannel); 897 898 nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel); 899 900 nsCOMPtr<nsILoadInfo> loadInfo = aChannel ? aChannel->LoadInfo() : nullptr; 901 const bool on3pcdException = loadInfo && loadInfo->GetIsOn3PCBExceptionList(); 902 903 for (const auto& attrs : aOriginAttrsList) { 904 CookieStorage* storage = PickStorage(attrs); 905 906 // get the base domain, host, and path from the URI. 907 // e.g. for "www.bbc.co.uk", the base domain would be "bbc.co.uk". 908 // file:// URI's (i.e. with an empty host) are allowed, but any other 909 // scheme must have a non-empty host. A trailing dot in the host 910 // is acceptable. 911 bool requireHostMatch; 912 nsAutoCString baseDomain; 913 nsAutoCString hostFromURI; 914 nsAutoCString pathFromURI; 915 nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI, 916 baseDomain, requireHostMatch); 917 if (NS_SUCCEEDED(rv)) { 918 rv = nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI); 919 } 920 if (NS_SUCCEEDED(rv)) { 921 rv = aHostURI->GetFilePath(pathFromURI); 922 } 923 if (NS_FAILED(rv)) { 924 COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, VoidCString(), 925 "invalid host/path from URI"); 926 return; 927 } 928 929 nsAutoCString normalizedHostFromURI(hostFromURI); 930 rv = NormalizeHost(normalizedHostFromURI); 931 NS_ENSURE_SUCCESS_VOID(rv); 932 933 nsAutoCString baseDomainFromURI; 934 rv = CookieCommons::GetBaseDomainFromHost( 935 mTLDService, normalizedHostFromURI, baseDomainFromURI); 936 NS_ENSURE_SUCCESS_VOID(rv); 937 938 // check default prefs 939 uint32_t rejectedReason = aRejectedReason; 940 uint32_t priorCookieCount = storage->CountCookiesFromHost( 941 baseDomainFromURI, attrs.mPrivateBrowsingId); 942 943 CookieStatus cookieStatus = CheckPrefs( 944 crc, cookieJarSettings, aHostURI, aIsForeign, 945 aIsThirdPartyTrackingResource, aIsThirdPartySocialTrackingResource, 946 aStorageAccessPermissionGranted, VoidCString(), priorCookieCount, attrs, 947 &rejectedReason); 948 949 MOZ_ASSERT_IF( 950 rejectedReason && 951 rejectedReason != 952 nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER, 953 cookieStatus == STATUS_REJECTED); 954 955 // for GetCookie(), we only fire acceptance/rejection notifications 956 // (but not if there was an error) 957 switch (cookieStatus) { 958 case STATUS_REJECTED: 959 // If we don't have any cookies from this host, fail silently. 960 if (priorCookieCount) { 961 CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason, 962 OPERATION_READ); 963 } 964 return; 965 default: 966 break; 967 } 968 969 // Note: The following permissions logic is mirrored in 970 // extensions::MatchPattern::MatchesCookie. 971 // If it changes, please update that function, or file a bug for someone 972 // else to do so. 973 974 // check if aHostURI is using an https secure protocol. 975 // if it isn't, then we can't send a secure cookie over the connection. 976 // if SchemeIs fails, assume an insecure connection, to be on the safe side 977 bool potentiallyTrustworthy = 978 nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI); 979 980 int64_t currentTimeInUsec = PR_Now(); 981 int64_t currentTimeInMSec = currentTimeInUsec / PR_USEC_PER_MSEC; 982 bool stale = false; 983 984 nsTArray<RefPtr<Cookie>> cookies; 985 storage->GetCookiesFromHost(baseDomain, attrs, cookies); 986 if (cookies.IsEmpty()) { 987 continue; 988 } 989 990 bool laxByDefault = 991 StaticPrefs::network_cookie_sameSite_laxByDefault() && 992 !nsContentUtils::IsURIInPrefList( 993 aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts"); 994 995 // iterate the cookies! 996 for (Cookie* cookie : cookies) { 997 // check the host, since the base domain lookup is conservative. 998 if (!CookieCommons::DomainMatches(cookie, hostFromURI)) { 999 continue; 1000 } 1001 1002 // if the cookie is secure and the host scheme isn't, we avoid sending 1003 // cookie if possible. But for process synchronization purposes, we may 1004 // want the content process to know about the cookie (without it's value). 1005 // In which case we will wipe the value before sending 1006 if (cookie->IsSecure() && !potentiallyTrustworthy && 1007 !aAllowSecureCookiesToInsecureOrigin) { 1008 continue; 1009 } 1010 1011 // if the cookie is httpOnly and it's not going directly to the HTTP 1012 // connection, don't send it 1013 if (cookie->IsHttpOnly() && !aHttpBound) { 1014 continue; 1015 } 1016 1017 // if the nsIURI path doesn't match the cookie path, don't send it back 1018 if (!CookieCommons::PathMatches(cookie, pathFromURI)) { 1019 continue; 1020 } 1021 1022 // check if the cookie has expired 1023 if (cookie->ExpiryInMSec() <= currentTimeInMSec) { 1024 continue; 1025 } 1026 1027 // Check if we need to block the cookie because of opt-in partitioning. 1028 // We will only allow partitioned cookies with "partitioned" attribution 1029 // if opt-in partitioning is enabled. 1030 // 1031 // Note: If the cookie is on the 3pcd exception list, we will include 1032 // the cookie. 1033 if (aIsForeign && cookieJarSettings->GetPartitionForeign() && 1034 (StaticPrefs::network_cookie_cookieBehavior_optInPartitioning() || 1035 (attrs.IsPrivateBrowsing() && 1036 StaticPrefs:: 1037 network_cookie_cookieBehavior_optInPartitioning_pbmode())) && 1038 !(cookie->IsPartitioned() && cookie->RawIsPartitioned()) && 1039 !aStorageAccessPermissionGranted && !on3pcdException) { 1040 continue; 1041 } 1042 1043 if (aHttpBound && aIsSameSiteForeign) { 1044 bool blockCookie = !ProcessSameSiteCookieForForeignRequest( 1045 aChannel, cookie, aIsSafeTopLevelNav, aHadCrossSiteRedirects, 1046 laxByDefault); 1047 1048 if (blockCookie) { 1049 if (aHadCrossSiteRedirects) { 1050 CookieLogging::LogMessageToConsole( 1051 crc, aHostURI, nsIScriptError::warningFlag, 1052 CONSOLE_REJECTION_CATEGORY, "CookieBlockedCrossSiteRedirect"_ns, 1053 AutoTArray<nsString, 1>{ 1054 NS_ConvertUTF8toUTF16(cookie->Name()), 1055 }); 1056 } 1057 continue; 1058 } 1059 } 1060 1061 // all checks passed - add to list and check if lastAccessedInUSec stamp 1062 // needs updating 1063 aCookieList.AppendElement(cookie); 1064 if (cookie->IsStale()) { 1065 stale = true; 1066 } 1067 } 1068 1069 if (aCookieList.IsEmpty()) { 1070 continue; 1071 } 1072 1073 // update lastAccessedInUSec timestamps. we only do this if the timestamp is 1074 // stale by a certain amount, to avoid thrashing the db during pageload. 1075 if (stale) { 1076 storage->StaleCookies(aCookieList, currentTimeInUsec); 1077 } 1078 } 1079 1080 if (aCookieList.IsEmpty()) { 1081 return; 1082 } 1083 1084 // Send a notification about the acceptance of the cookies now that we found 1085 // some. 1086 NotifyAccepted(aChannel); 1087 1088 // return cookies in order of path length; longest to shortest. 1089 // this is required per RFC2109. if cookies match in length, 1090 // then sort by creation time (see bug 236772). 1091 aCookieList.Sort(CompareCookiesForSending()); 1092 } 1093 1094 /****************************************************************************** 1095 * CookieService impl: 1096 * private domain & permission compliance enforcement functions 1097 ******************************************************************************/ 1098 1099 nsresult CookieService::NormalizeHost(nsCString& aHost) { 1100 nsAutoCString host; 1101 if (!CookieCommons::IsIPv6BaseDomain(aHost)) { 1102 nsresult rv = NS_DomainToASCII(aHost, host); 1103 if (NS_FAILED(rv)) { 1104 return rv; 1105 } 1106 aHost = host; 1107 } 1108 1109 return NS_OK; 1110 } 1111 1112 CookieStatus CookieService::CheckPrefs( 1113 nsIConsoleReportCollector* aCRC, nsICookieJarSettings* aCookieJarSettings, 1114 nsIURI* aHostURI, bool aIsForeign, bool aIsThirdPartyTrackingResource, 1115 bool aIsThirdPartySocialTrackingResource, 1116 bool aStorageAccessPermissionGranted, const nsACString& aCookieHeader, 1117 const int aNumOfCookies, const OriginAttributes& aOriginAttrs, 1118 uint32_t* aRejectedReason) { 1119 nsresult rv; 1120 1121 MOZ_ASSERT(aRejectedReason); 1122 1123 *aRejectedReason = 0; 1124 1125 // don't let unsupported scheme sites get/set cookies (could be a security 1126 // issue) 1127 if (!CookieCommons::IsSchemeSupported(aHostURI)) { 1128 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader, 1129 "non http/https sites cannot read cookies"); 1130 return STATUS_REJECTED_WITH_ERROR; 1131 } 1132 1133 nsCOMPtr<nsIPrincipal> principal = 1134 BasePrincipal::CreateContentPrincipal(aHostURI, aOriginAttrs); 1135 1136 if (!principal) { 1137 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader, 1138 "non-content principals cannot get/set cookies"); 1139 return STATUS_REJECTED_WITH_ERROR; 1140 } 1141 1142 // check the permission list first; if we find an entry, it overrides 1143 // default prefs. see bug 184059. 1144 uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT; 1145 rv = aCookieJarSettings->CookiePermission(principal, &cookiePermission); 1146 if (NS_SUCCEEDED(rv)) { 1147 switch (cookiePermission) { 1148 case nsICookiePermission::ACCESS_DENY: 1149 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader, 1150 "cookies are blocked for this site"); 1151 CookieLogging::LogMessageToConsole( 1152 aCRC, aHostURI, nsIScriptError::warningFlag, 1153 CONSOLE_REJECTION_CATEGORY, "CookieRejectedByPermissionManager"_ns, 1154 AutoTArray<nsString, 1>{ 1155 NS_ConvertUTF8toUTF16(aCookieHeader), 1156 }); 1157 1158 *aRejectedReason = 1159 nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION; 1160 return STATUS_REJECTED; 1161 1162 case nsICookiePermission::ACCESS_ALLOW: 1163 return STATUS_ACCEPTED; 1164 default: 1165 break; 1166 } 1167 } 1168 1169 // No cookies allowed if this request comes from a resource in a 3rd party 1170 // context, when anti-tracking protection is enabled and when we don't have 1171 // access to the first-party cookie jar. 1172 if (aIsForeign && aIsThirdPartyTrackingResource && 1173 !aStorageAccessPermissionGranted && 1174 aCookieJarSettings->GetRejectThirdPartyContexts()) { 1175 // Set the reject reason to partitioned tracker if we are not blocking 1176 // tracker cookie. 1177 uint32_t rejectReason = 1178 aCookieJarSettings->GetPartitionForeign() && 1179 !StaticPrefs:: 1180 network_cookie_cookieBehavior_trackerCookieBlocking() 1181 ? nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN 1182 : nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER; 1183 if (StoragePartitioningEnabled(rejectReason, aCookieJarSettings)) { 1184 MOZ_ASSERT(!aOriginAttrs.mPartitionKey.IsEmpty(), 1185 "We must have a StoragePrincipal here!"); 1186 // Set the reject reason to partitioned tracker if the resource to reflect 1187 // that we are partitioning tracker cookies. 1188 *aRejectedReason = 1189 nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER; 1190 return STATUS_ACCEPTED; 1191 } 1192 1193 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader, 1194 "cookies are disabled in trackers"); 1195 if (aIsThirdPartySocialTrackingResource) { 1196 *aRejectedReason = 1197 nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER; 1198 } else { 1199 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER; 1200 } 1201 return STATUS_REJECTED; 1202 } 1203 1204 // check default prefs. 1205 // Check aStorageAccessPermissionGranted when checking aCookieBehavior 1206 // so that we take things such as the content blocking allow list into 1207 // account. 1208 if (aCookieJarSettings->GetCookieBehavior() == 1209 nsICookieService::BEHAVIOR_REJECT && 1210 !aStorageAccessPermissionGranted) { 1211 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader, 1212 "cookies are disabled"); 1213 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL; 1214 return STATUS_REJECTED; 1215 } 1216 1217 // check if cookie is foreign 1218 if (aIsForeign) { 1219 if (aCookieJarSettings->GetCookieBehavior() == 1220 nsICookieService::BEHAVIOR_REJECT_FOREIGN && 1221 !aStorageAccessPermissionGranted) { 1222 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader, 1223 "context is third party"); 1224 CookieLogging::LogMessageToConsole( 1225 aCRC, aHostURI, nsIScriptError::warningFlag, 1226 CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns, 1227 AutoTArray<nsString, 1>{ 1228 NS_ConvertUTF8toUTF16(aCookieHeader), 1229 }); 1230 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN; 1231 return STATUS_REJECTED; 1232 } 1233 1234 if (aCookieJarSettings->GetLimitForeignContexts() && 1235 !aStorageAccessPermissionGranted && aNumOfCookies == 0) { 1236 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader, 1237 "context is third party"); 1238 CookieLogging::LogMessageToConsole( 1239 aCRC, aHostURI, nsIScriptError::warningFlag, 1240 CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns, 1241 AutoTArray<nsString, 1>{ 1242 NS_ConvertUTF8toUTF16(aCookieHeader), 1243 }); 1244 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN; 1245 return STATUS_REJECTED; 1246 } 1247 } 1248 1249 // if nothing has complained, accept cookie 1250 return STATUS_ACCEPTED; 1251 } 1252 1253 /****************************************************************************** 1254 * CookieService impl: 1255 * private cookielist management functions 1256 ******************************************************************************/ 1257 1258 // find whether a given cookie has been previously set. this is provided by the 1259 // nsICookieManager interface. 1260 NS_IMETHODIMP 1261 CookieService::CookieExists(const nsACString& aHost, const nsACString& aPath, 1262 const nsACString& aName, 1263 JS::Handle<JS::Value> aOriginAttributes, 1264 JSContext* aCx, bool* aFoundCookie) { 1265 NS_ENSURE_ARG_POINTER(aCx); 1266 NS_ENSURE_ARG_POINTER(aFoundCookie); 1267 1268 OriginAttributes attrs; 1269 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 1270 return NS_ERROR_INVALID_ARG; 1271 } 1272 return CookieExistsNative(aHost, aPath, aName, &attrs, aFoundCookie); 1273 } 1274 1275 NS_IMETHODIMP_(nsresult) 1276 CookieService::CookieExistsNative(const nsACString& aHost, 1277 const nsACString& aPath, 1278 const nsACString& aName, 1279 OriginAttributes* aOriginAttributes, 1280 bool* aFoundCookie) { 1281 nsCOMPtr<nsICookie> cookie; 1282 nsresult rv = GetCookieNative(aHost, aPath, aName, aOriginAttributes, 1283 getter_AddRefs(cookie)); 1284 NS_ENSURE_SUCCESS(rv, rv); 1285 1286 *aFoundCookie = cookie != nullptr; 1287 1288 return NS_OK; 1289 } 1290 1291 NS_IMETHODIMP_(nsresult) 1292 CookieService::GetCookieNative(const nsACString& aHost, const nsACString& aPath, 1293 const nsACString& aName, 1294 OriginAttributes* aOriginAttributes, 1295 nsICookie** aCookie) { 1296 NS_ENSURE_ARG_POINTER(aOriginAttributes); 1297 NS_ENSURE_ARG_POINTER(aCookie); 1298 1299 if (!IsInitialized()) { 1300 return NS_ERROR_NOT_AVAILABLE; 1301 } 1302 1303 nsAutoCString baseDomain; 1304 nsresult rv = 1305 CookieCommons::GetBaseDomainFromHost(mTLDService, aHost, baseDomain); 1306 NS_ENSURE_SUCCESS(rv, rv); 1307 1308 CookieStorage* storage = PickStorage(*aOriginAttributes); 1309 1310 RefPtr<Cookie> cookie = 1311 storage->FindCookie(baseDomain, *aOriginAttributes, aHost, aName, aPath); 1312 cookie.forget(aCookie); 1313 1314 return NS_OK; 1315 } 1316 1317 // count the number of cookies stored by a particular host. this is provided by 1318 // the nsICookieManager interface. 1319 NS_IMETHODIMP 1320 CookieService::CountCookiesFromHost(const nsACString& aHost, 1321 uint32_t* aCountFromHost) { 1322 // first, normalize the hostname, and fail if it contains illegal characters. 1323 nsAutoCString host(aHost); 1324 nsresult rv = NormalizeHost(host); 1325 NS_ENSURE_SUCCESS(rv, rv); 1326 1327 nsAutoCString baseDomain; 1328 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain); 1329 NS_ENSURE_SUCCESS(rv, rv); 1330 1331 if (!IsInitialized()) { 1332 return NS_ERROR_NOT_AVAILABLE; 1333 } 1334 1335 mPersistentStorage->EnsureInitialized(); 1336 1337 *aCountFromHost = mPersistentStorage->CountCookiesFromHost(baseDomain, 0); 1338 1339 return NS_OK; 1340 } 1341 1342 // get an enumerator of cookies stored by a particular host. this is provided by 1343 // the nsICookieManager interface. 1344 NS_IMETHODIMP 1345 CookieService::GetCookiesFromHost(const nsACString& aHost, 1346 JS::Handle<JS::Value> aOriginAttributes, 1347 bool aSorted, JSContext* aCx, 1348 nsTArray<RefPtr<nsICookie>>& aResult) { 1349 OriginAttributes attrs; 1350 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 1351 return NS_ERROR_INVALID_ARG; 1352 } 1353 1354 return GetCookiesFromHostNative(aHost, &attrs, aSorted, aResult); 1355 } 1356 1357 NS_IMETHODIMP 1358 CookieService::GetCookiesFromHostNative(const nsACString& aHost, 1359 OriginAttributes* aAttrs, bool aSorted, 1360 nsTArray<RefPtr<nsICookie>>& aResult) { 1361 // first, normalize the hostname, and fail if it contains illegal characters. 1362 nsAutoCString host(aHost); 1363 nsresult rv = NormalizeHost(host); 1364 NS_ENSURE_SUCCESS(rv, rv); 1365 1366 nsAutoCString baseDomain; 1367 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain); 1368 NS_ENSURE_SUCCESS(rv, rv); 1369 1370 if (!IsInitialized()) { 1371 return NS_ERROR_NOT_AVAILABLE; 1372 } 1373 1374 CookieStorage* storage = PickStorage(*aAttrs); 1375 1376 nsTArray<RefPtr<Cookie>> cookies; 1377 storage->GetCookiesFromHost(baseDomain, *aAttrs, cookies); 1378 1379 if (cookies.IsEmpty()) { 1380 return NS_OK; 1381 } 1382 1383 aResult.SetCapacity(cookies.Length()); 1384 for (Cookie* cookie : cookies) { 1385 aResult.AppendElement(cookie); 1386 } 1387 1388 if (aSorted) { 1389 aResult.Sort(CompareCookiesForSending()); 1390 } 1391 1392 return NS_OK; 1393 } 1394 1395 NS_IMETHODIMP 1396 CookieService::GetCookiesWithOriginAttributes( 1397 const nsAString& aPattern, const nsACString& aHost, const bool aSorted, 1398 nsTArray<RefPtr<nsICookie>>& aResult) { 1399 OriginAttributesPattern pattern; 1400 if (!pattern.Init(aPattern)) { 1401 return NS_ERROR_INVALID_ARG; 1402 } 1403 1404 nsAutoCString host(aHost); 1405 nsresult rv = NormalizeHost(host); 1406 NS_ENSURE_SUCCESS(rv, rv); 1407 1408 nsAutoCString baseDomain; 1409 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain); 1410 NS_ENSURE_SUCCESS(rv, rv); 1411 1412 return GetCookiesWithOriginAttributes(pattern, baseDomain, aSorted, aResult); 1413 } 1414 1415 nsresult CookieService::GetCookiesWithOriginAttributes( 1416 const OriginAttributesPattern& aPattern, const nsCString& aBaseDomain, 1417 bool aSorted, nsTArray<RefPtr<nsICookie>>& aResult) { 1418 CookieStorage* storage = PickStorage(aPattern); 1419 storage->GetCookiesWithOriginAttributes(aPattern, aBaseDomain, aSorted, 1420 aResult); 1421 1422 return NS_OK; 1423 } 1424 1425 NS_IMETHODIMP 1426 CookieService::RemoveCookiesWithOriginAttributes(const nsAString& aPattern, 1427 const nsACString& aHost) { 1428 MOZ_ASSERT(XRE_IsParentProcess()); 1429 1430 OriginAttributesPattern pattern; 1431 if (!pattern.Init(aPattern)) { 1432 return NS_ERROR_INVALID_ARG; 1433 } 1434 1435 nsAutoCString host(aHost); 1436 nsresult rv = NormalizeHost(host); 1437 NS_ENSURE_SUCCESS(rv, rv); 1438 1439 nsAutoCString baseDomain; 1440 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain); 1441 NS_ENSURE_SUCCESS(rv, rv); 1442 1443 return RemoveCookiesWithOriginAttributes(pattern, baseDomain); 1444 } 1445 1446 nsresult CookieService::RemoveCookiesWithOriginAttributes( 1447 const OriginAttributesPattern& aPattern, const nsCString& aBaseDomain) { 1448 if (!IsInitialized()) { 1449 return NS_ERROR_NOT_AVAILABLE; 1450 } 1451 1452 CookieStorage* storage = PickStorage(aPattern); 1453 storage->RemoveCookiesWithOriginAttributes(aPattern, aBaseDomain); 1454 1455 return NS_OK; 1456 } 1457 1458 NS_IMETHODIMP 1459 CookieService::RemoveCookiesFromExactHost(const nsACString& aHost, 1460 const nsAString& aPattern) { 1461 MOZ_ASSERT(XRE_IsParentProcess()); 1462 1463 OriginAttributesPattern pattern; 1464 if (!pattern.Init(aPattern)) { 1465 return NS_ERROR_INVALID_ARG; 1466 } 1467 1468 return RemoveCookiesFromExactHost(aHost, pattern); 1469 } 1470 1471 nsresult CookieService::RemoveCookiesFromExactHost( 1472 const nsACString& aHost, const OriginAttributesPattern& aPattern) { 1473 nsAutoCString host(aHost); 1474 nsresult rv = NormalizeHost(host); 1475 NS_ENSURE_SUCCESS(rv, rv); 1476 1477 nsAutoCString baseDomain; 1478 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain); 1479 NS_ENSURE_SUCCESS(rv, rv); 1480 1481 if (!IsInitialized()) { 1482 return NS_ERROR_NOT_AVAILABLE; 1483 } 1484 1485 CookieStorage* storage = PickStorage(aPattern); 1486 storage->RemoveCookiesFromExactHost(aHost, baseDomain, aPattern); 1487 1488 return NS_OK; 1489 } 1490 1491 namespace { 1492 1493 class RemoveAllSinceRunnable : public Runnable { 1494 public: 1495 using CookieArray = nsTArray<RefPtr<nsICookie>>; 1496 RemoveAllSinceRunnable(Promise* aPromise, CookieService* aSelf, 1497 CookieArray&& aCookieArray, int64_t aSinceWhen) 1498 : Runnable("RemoveAllSinceRunnable"), 1499 mPromise(aPromise), 1500 mSelf(aSelf), 1501 mList(std::move(aCookieArray)), 1502 mIndex(0), 1503 mSinceWhen(aSinceWhen) {} 1504 1505 NS_IMETHODIMP Run() override { 1506 RemoveSome(); 1507 1508 if (mIndex < mList.Length()) { 1509 return NS_DispatchToCurrentThread(this); 1510 } 1511 mPromise->MaybeResolveWithUndefined(); 1512 1513 return NS_OK; 1514 } 1515 1516 private: 1517 void RemoveSome() { 1518 for (CookieArray::size_type iter = 0; 1519 iter < kYieldPeriod && mIndex < mList.Length(); ++mIndex, ++iter) { 1520 auto* cookie = static_cast<Cookie*>(mList[mIndex].get()); 1521 if (cookie->CreationTimeInUSec() > mSinceWhen && 1522 NS_FAILED(mSelf->Remove(cookie->Host(), cookie->OriginAttributesRef(), 1523 cookie->Name(), cookie->Path(), 1524 /* from http: */ true, nullptr))) { 1525 continue; 1526 } 1527 } 1528 } 1529 1530 private: 1531 RefPtr<Promise> mPromise; 1532 RefPtr<CookieService> mSelf; 1533 CookieArray mList; 1534 CookieArray::size_type mIndex; 1535 int64_t mSinceWhen; 1536 static const CookieArray::size_type kYieldPeriod = 10; 1537 }; 1538 1539 } // namespace 1540 1541 NS_IMETHODIMP 1542 CookieService::RemoveAllSince(int64_t aSinceWhen, JSContext* aCx, 1543 Promise** aRetVal) { 1544 nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx); 1545 if (NS_WARN_IF(!globalObject)) { 1546 return NS_ERROR_UNEXPECTED; 1547 } 1548 1549 ErrorResult result; 1550 RefPtr<Promise> promise = Promise::Create(globalObject, result); 1551 if (NS_WARN_IF(result.Failed())) { 1552 return result.StealNSResult(); 1553 } 1554 1555 mPersistentStorage->EnsureInitialized(); 1556 1557 nsTArray<RefPtr<nsICookie>> cookieList; 1558 1559 // We delete only non-private cookies. 1560 mPersistentStorage->GetAll(cookieList); 1561 1562 RefPtr<RemoveAllSinceRunnable> runMe = new RemoveAllSinceRunnable( 1563 promise, this, std::move(cookieList), aSinceWhen); 1564 1565 promise.forget(aRetVal); 1566 1567 return runMe->Run(); 1568 } 1569 1570 namespace { 1571 1572 class CompareCookiesCreationTime { 1573 public: 1574 static bool Equals(const nsICookie* aCookie1, const nsICookie* aCookie2) { 1575 return static_cast<const Cookie*>(aCookie1)->CreationTimeInUSec() == 1576 static_cast<const Cookie*>(aCookie2)->CreationTimeInUSec(); 1577 } 1578 1579 static bool LessThan(const nsICookie* aCookie1, const nsICookie* aCookie2) { 1580 return static_cast<const Cookie*>(aCookie1)->CreationTimeInUSec() < 1581 static_cast<const Cookie*>(aCookie2)->CreationTimeInUSec(); 1582 } 1583 }; 1584 1585 } // namespace 1586 1587 NS_IMETHODIMP 1588 CookieService::GetCookiesSince(int64_t aSinceWhen, 1589 nsTArray<RefPtr<nsICookie>>& aResult) { 1590 if (!IsInitialized()) { 1591 return NS_OK; 1592 } 1593 1594 mPersistentStorage->EnsureInitialized(); 1595 1596 // We expose only non-private cookies. 1597 nsTArray<RefPtr<nsICookie>> cookieList; 1598 mPersistentStorage->GetAll(cookieList); 1599 1600 for (RefPtr<nsICookie>& cookie : cookieList) { 1601 if (static_cast<Cookie*>(cookie.get())->CreationTimeInUSec() >= 1602 aSinceWhen) { 1603 aResult.AppendElement(cookie); 1604 } 1605 } 1606 1607 aResult.Sort(CompareCookiesCreationTime()); 1608 return NS_OK; 1609 } 1610 1611 size_t CookieService::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { 1612 size_t n = aMallocSizeOf(this); 1613 1614 if (mPersistentStorage) { 1615 n += mPersistentStorage->SizeOfIncludingThis(aMallocSizeOf); 1616 } 1617 if (mPrivateStorage) { 1618 n += mPrivateStorage->SizeOfIncludingThis(aMallocSizeOf); 1619 } 1620 1621 return n; 1622 } 1623 1624 MOZ_DEFINE_MALLOC_SIZE_OF(CookieServiceMallocSizeOf) 1625 1626 NS_IMETHODIMP 1627 CookieService::CollectReports(nsIHandleReportCallback* aHandleReport, 1628 nsISupports* aData, bool /*aAnonymize*/) { 1629 MOZ_COLLECT_REPORT("explicit/cookie-service", KIND_HEAP, UNITS_BYTES, 1630 SizeOfIncludingThis(CookieServiceMallocSizeOf), 1631 "Memory used by the cookie service."); 1632 1633 return NS_OK; 1634 } 1635 1636 bool CookieService::IsInitialized() const { 1637 if (!mPersistentStorage) { 1638 NS_WARNING("No CookieStorage! Profile already close?"); 1639 return false; 1640 } 1641 1642 MOZ_ASSERT(mPrivateStorage); 1643 return true; 1644 } 1645 1646 CookieStorage* CookieService::PickStorage(const OriginAttributes& aAttrs) { 1647 MOZ_ASSERT(IsInitialized()); 1648 1649 if (aAttrs.IsPrivateBrowsing()) { 1650 return mPrivateStorage; 1651 } 1652 1653 mPersistentStorage->EnsureInitialized(); 1654 return mPersistentStorage; 1655 } 1656 1657 CookieStorage* CookieService::PickStorage( 1658 const OriginAttributesPattern& aAttrs) { 1659 MOZ_ASSERT(IsInitialized()); 1660 1661 if (aAttrs.mPrivateBrowsingId.WasPassed() && 1662 aAttrs.mPrivateBrowsingId.Value() > 0) { 1663 return mPrivateStorage; 1664 } 1665 1666 mPersistentStorage->EnsureInitialized(); 1667 return mPersistentStorage; 1668 } 1669 1670 nsICookieValidation::ValidationError CookieService::SetCookiesFromIPC( 1671 const nsACString& aBaseDomain, const OriginAttributes& aAttrs, 1672 nsIURI* aHostURI, bool aFromHttp, bool aIsThirdParty, 1673 const nsTArray<CookieStruct>& aCookies, BrowsingContext* aBrowsingContext) { 1674 if (!IsInitialized()) { 1675 // If we are probably shutting down, we can ignore this cookie. 1676 return nsICookieValidation::eOK; 1677 } 1678 1679 CookieStorage* storage = PickStorage(aAttrs); 1680 int64_t currentTimeInUsec = PR_Now(); 1681 1682 for (const CookieStruct& cookieData : aCookies) { 1683 RefPtr<CookieValidation> validation = CookieValidation::ValidateForHost( 1684 cookieData, aHostURI, aBaseDomain, false, aFromHttp); 1685 MOZ_ASSERT(validation); 1686 1687 if (validation->Result() != nsICookieValidation::eOK) { 1688 return validation->Result(); 1689 } 1690 1691 // create a new Cookie and copy attributes 1692 RefPtr<Cookie> cookie = Cookie::Create(cookieData, aAttrs); 1693 if (!cookie) { 1694 continue; 1695 } 1696 1697 cookie->SetLastAccessedInUSec(currentTimeInUsec); 1698 cookie->SetCreationTimeInUSec( 1699 Cookie::GenerateUniqueCreationTimeInUSec(currentTimeInUsec)); 1700 cookie->SetUpdateTimeInUSec(cookie->CreationTimeInUSec()); 1701 1702 storage->AddCookie(nullptr, aBaseDomain, aAttrs, cookie, currentTimeInUsec, 1703 aHostURI, ""_ns, aFromHttp, aIsThirdParty, 1704 aBrowsingContext); 1705 } 1706 1707 return nsICookieValidation::eOK; 1708 } 1709 1710 void CookieService::GetCookiesFromHost( 1711 const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes, 1712 nsTArray<RefPtr<Cookie>>& aCookies) { 1713 if (!IsInitialized()) { 1714 return; 1715 } 1716 1717 CookieStorage* storage = PickStorage(aOriginAttributes); 1718 storage->GetCookiesFromHost(aBaseDomain, aOriginAttributes, aCookies); 1719 } 1720 1721 void CookieService::StaleCookies(const nsTArray<RefPtr<Cookie>>& aCookies, 1722 int64_t aCurrentTimeInUsec) { 1723 if (!IsInitialized()) { 1724 return; 1725 } 1726 1727 if (aCookies.IsEmpty()) { 1728 return; 1729 } 1730 1731 OriginAttributes originAttributes = aCookies[0]->OriginAttributesRef(); 1732 #ifdef MOZ_DEBUG 1733 for (Cookie* cookie : aCookies) { 1734 MOZ_ASSERT(originAttributes == cookie->OriginAttributesRef()); 1735 } 1736 #endif 1737 1738 CookieStorage* storage = PickStorage(originAttributes); 1739 storage->StaleCookies(aCookies, aCurrentTimeInUsec); 1740 } 1741 1742 bool CookieService::HasExistingCookies( 1743 const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes) { 1744 if (!IsInitialized()) { 1745 return false; 1746 } 1747 1748 CookieStorage* storage = PickStorage(aOriginAttributes); 1749 return !!storage->CountCookiesFromHost(aBaseDomain, 1750 aOriginAttributes.mPrivateBrowsingId); 1751 } 1752 1753 void CookieService::AddCookieFromDocument( 1754 CookieParser& aCookieParser, const nsACString& aBaseDomain, 1755 const OriginAttributes& aOriginAttributes, Cookie& aCookie, 1756 int64_t aCurrentTimeInUsec, nsIURI* aDocumentURI, bool aThirdParty, 1757 Document* aDocument) { 1758 MOZ_ASSERT(aDocumentURI); 1759 MOZ_ASSERT(aDocument); 1760 1761 if (!IsInitialized()) { 1762 return; 1763 } 1764 1765 nsAutoCString cookieString; 1766 aCookieParser.GetCookieString(cookieString); 1767 1768 PickStorage(aOriginAttributes) 1769 ->AddCookie(&aCookieParser, aBaseDomain, aOriginAttributes, &aCookie, 1770 aCurrentTimeInUsec, aDocumentURI, cookieString, false, 1771 aThirdParty, aDocument->GetBrowsingContext()); 1772 } 1773 1774 /* static */ 1775 void CookieService::Update3PCBExceptionInfo(nsIChannel* aChannel) { 1776 MOZ_ASSERT(aChannel); 1777 MOZ_ASSERT(XRE_IsParentProcess()); 1778 1779 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 1780 RefPtr<CookieService> csSingleton = CookieService::GetSingleton(); 1781 1782 // Bail out if the channel is a top-level loading. The exception is only 1783 // applicable to third-party loading. 1784 if (loadInfo->GetExternalContentPolicyType() == 1785 ExtContentPolicy::TYPE_DOCUMENT) { 1786 return; 1787 } 1788 1789 // Bail out earlier if the 3PCB exception service is not initialized. 1790 if (!csSingleton->mThirdPartyCookieBlockingExceptions.IsInitialized()) { 1791 return; 1792 } 1793 1794 // If the channel is triggered by a system principal, we don't need to do 1795 // anything because the channel is for loading system resources. 1796 if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) { 1797 return; 1798 } 1799 1800 bool isInExceptionList = 1801 csSingleton->mThirdPartyCookieBlockingExceptions.CheckExceptionForChannel( 1802 aChannel); 1803 1804 (void)loadInfo->SetIsOn3PCBExceptionList(isInExceptionList); 1805 } 1806 1807 NS_IMETHODIMP 1808 CookieService::AddThirdPartyCookieBlockingExceptions( 1809 const nsTArray<RefPtr<nsIThirdPartyCookieExceptionEntry>>& aExceptions) { 1810 for (const auto& ex : aExceptions) { 1811 nsAutoCString exception; 1812 MOZ_ALWAYS_SUCCEEDS(ex->Serialize(exception)); 1813 mThirdPartyCookieBlockingExceptions.Insert(exception); 1814 } 1815 1816 return NS_OK; 1817 } 1818 1819 NS_IMETHODIMP 1820 CookieService::RemoveThirdPartyCookieBlockingExceptions( 1821 const nsTArray<RefPtr<nsIThirdPartyCookieExceptionEntry>>& aExceptions) { 1822 for (const auto& ex : aExceptions) { 1823 nsAutoCString exception; 1824 MOZ_ALWAYS_SUCCEEDS(ex->Serialize(exception)); 1825 mThirdPartyCookieBlockingExceptions.Remove(exception); 1826 } 1827 1828 return NS_OK; 1829 } 1830 1831 NS_IMETHODIMP 1832 CookieService::TestGet3PCBExceptions(nsTArray<nsCString>& aExceptions) { 1833 aExceptions.Clear(); 1834 1835 mThirdPartyCookieBlockingExceptions.GetExceptions(aExceptions); 1836 1837 return NS_OK; 1838 } 1839 1840 NS_IMETHODIMP 1841 CookieService::MaybeCapExpiry(int64_t aExpiryInMSec, int64_t* aResult) { 1842 NS_ENSURE_ARG_POINTER(aResult); 1843 *aResult = 1844 CookieCommons::MaybeCapExpiry(PR_Now() / PR_USEC_PER_MSEC, aExpiryInMSec); 1845 return NS_OK; 1846 } 1847 1848 } // namespace net 1849 } // namespace mozilla