|
@@ -0,0 +1,2359 @@
|
|
|
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
+From: Keeley Hammond <[email protected]>
|
|
|
+Date: Thu, 21 Sep 2023 16:21:29 -0700
|
|
|
+Subject: fix: revert samesite cookie removal
|
|
|
+
|
|
|
+SameSite cookie is currently being removed upstream by Chrome, but is still
|
|
|
+depended on by some Electron consumers. This patch is meant to restore the
|
|
|
+removed SameSite cookie functionality and supported methods while the
|
|
|
+Chrome team finishes the Storage Access API, which we can then use in
|
|
|
+place of SameSite cookies.
|
|
|
+
|
|
|
+This patch can be removed when Storage Access API cookie support is
|
|
|
+completed upstream.
|
|
|
+
|
|
|
+diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
|
|
|
+index 128e46bff2164d437b75cdb2ea9eb0c9967f3509..72a0667ea16c42ab6aa35c5e9e33aa912b5a26e3 100644
|
|
|
+--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
|
|
|
++++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
|
|
|
+@@ -116,6 +116,7 @@ void FirstPartySetsPolicyService::Init() {
|
|
|
+ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+ if (!is_enabled()) {
|
|
|
+@@ -127,17 +128,18 @@ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadata(
|
|
|
+ on_ready_callbacks_.push_back(base::BindOnce(
|
|
|
+ &FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal,
|
|
|
+ weak_factory_.GetWeakPtr(), site, base::OptionalFromPtr(top_frame_site),
|
|
|
+- std::move(callback)));
|
|
|
++ party_context, std::move(callback)));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ content::FirstPartySetsHandler::GetInstance()->ComputeFirstPartySetMetadata(
|
|
|
+- site, top_frame_site, *config_, std::move(callback));
|
|
|
++ site, top_frame_site, party_context, *config_, std::move(callback));
|
|
|
+ }
|
|
|
+
|
|
|
+ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+ CHECK(config_.has_value());
|
|
|
+@@ -148,7 +150,8 @@ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal(
|
|
|
+ }
|
|
|
+
|
|
|
+ content::FirstPartySetsHandler::GetInstance()->ComputeFirstPartySetMetadata(
|
|
|
+- site, base::OptionalToPtr(top_frame_site), *config_, std::move(callback));
|
|
|
++ site, base::OptionalToPtr(top_frame_site), party_context, *config_,
|
|
|
++ std::move(callback));
|
|
|
+ }
|
|
|
+
|
|
|
+ void FirstPartySetsPolicyService::AddRemoteAccessDelegate(
|
|
|
+diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.h b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
|
|
|
+index 1e0a49b7d2ec489f1be24a4bbcdd2741b789b85d..246d521b71d88c0e8a838a9711b7265fa59bf1ed 100644
|
|
|
+--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.h
|
|
|
++++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
|
|
|
+@@ -49,6 +49,7 @@ class FirstPartySetsPolicyService : public KeyedService {
|
|
|
+ void ComputeFirstPartySetMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
|
|
|
+
|
|
|
+ // Stores `access_delegate` in a RemoteSet for later IPC calls on it when this
|
|
|
+@@ -152,6 +153,7 @@ class FirstPartySetsPolicyService : public KeyedService {
|
|
|
+ void ComputeFirstPartySetMetadataInternal(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
|
|
|
+
|
|
|
+ // Clears the content settings associated with `profile` that were
|
|
|
+diff --git a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
|
|
|
+index b0167e5b1c77f66809a47526a2c0dcfe9ea2928b..55705bf4286f6307c05da20f5e10a96dab43bf70 100644
|
|
|
+--- a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
|
|
|
++++ b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
|
|
|
+@@ -9,6 +9,7 @@
|
|
|
+ #include "base/feature_list.h"
|
|
|
+ #include "base/functional/callback.h"
|
|
|
+ #include "base/task/sequenced_task_runner.h"
|
|
|
++#include "base/types/optional_util.h"
|
|
|
+ #include "content/public/browser/first_party_sets_handler.h"
|
|
|
+ #include "content/public/common/content_features.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_metadata.h"
|
|
|
+@@ -75,10 +76,11 @@ void ScopedMockFirstPartySetsHandler::ClearSiteDataOnChangedSetsForContext(
|
|
|
+ void ScopedMockFirstPartySetsHandler::ComputeFirstPartySetMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
|
+ net::FirstPartySetMetadata metadata =
|
|
|
+- global_sets_.ComputeMetadata(site, top_frame_site, config);
|
|
|
++ global_sets_.ComputeMetadata(site, top_frame_site, party_context, config);
|
|
|
+ if (invoke_callbacks_asynchronously_) {
|
|
|
+ base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
|
|
|
+ FROM_HERE, base::BindOnce(std::move(callback), std::move(metadata)));
|
|
|
+diff --git a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
|
|
|
+index a93e67a33f5ca5c845fa48606c8255ef51c4f5c8..817785f539deaa30621b76690de0db367565e922 100644
|
|
|
+--- a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
|
|
|
++++ b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
|
|
|
+@@ -61,6 +61,7 @@ class ScopedMockFirstPartySetsHandler : public content::FirstPartySetsHandler {
|
|
|
+ void ComputeFirstPartySetMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) override;
|
|
|
+
|
|
|
+diff --git a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
|
|
|
+index 16e2af1a1f5a6c7209ebc8adbfaf5fcc3c7185cd..6ea0787b47e7e7c36dc178d89faf92bc6b51534b 100644
|
|
|
+--- a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
|
|
|
++++ b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
|
|
|
+@@ -286,6 +286,7 @@ void StorageAccessGrantPermissionContext::DecidePermission(
|
|
|
+ browser_context())
|
|
|
+ ->ComputeFirstPartySetMetadata(
|
|
|
+ requesting_site, &embedding_site,
|
|
|
++ /*party_context=*/{},
|
|
|
+ base::BindOnce(&StorageAccessGrantPermissionContext::
|
|
|
+ CheckForAutoGrantOrAutoDenial,
|
|
|
+ weak_factory_.GetWeakPtr(), std::move(request_data),
|
|
|
+diff --git a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
|
|
|
+index 900e17bcf2d379facf8a6efd3b4e03fce8f00bab..994269dbab5b6afa6d548676b70128208575d039 100644
|
|
|
+--- a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
|
|
|
++++ b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
|
|
|
+@@ -96,6 +96,7 @@ void TopLevelStorageAccessPermissionContext::DecidePermission(
|
|
|
+ browser_context())
|
|
|
+ ->ComputeFirstPartySetMetadata(
|
|
|
+ requesting_site, &embedding_site,
|
|
|
++ /*party_context=*/{},
|
|
|
+ base::BindOnce(&TopLevelStorageAccessPermissionContext::
|
|
|
+ CheckForAutoGrantOrAutoDenial,
|
|
|
+ weak_factory_.GetWeakPtr(), std::move(request_data),
|
|
|
+diff --git a/content/browser/cookie_store/cookie_change_subscription.cc b/content/browser/cookie_store/cookie_change_subscription.cc
|
|
|
+index dbe3c5b8a6c83c5e8d26b109f24e77b4ab2e604e..fd51ab0f749b63fda2a7848594bb616fe6a48730 100644
|
|
|
+--- a/content/browser/cookie_store/cookie_change_subscription.cc
|
|
|
++++ b/content/browser/cookie_store/cookie_change_subscription.cc
|
|
|
+@@ -9,8 +9,10 @@
|
|
|
+ #include "content/browser/cookie_store/cookie_change_subscriptions.pb.h"
|
|
|
+ #include "content/public/browser/content_browser_client.h"
|
|
|
+ #include "content/public/common/content_client.h"
|
|
|
++#include "net/base/features.h"
|
|
|
+ #include "net/cookies/cookie_constants.h"
|
|
|
+ #include "net/cookies/cookie_util.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "services/network/public/cpp/is_potentially_trustworthy.h"
|
|
|
+
|
|
|
+ namespace content {
|
|
|
+@@ -169,17 +171,26 @@ bool CookieChangeSubscription::ShouldObserveChangeTo(
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+- // We assume that this is a same-site context.
|
|
|
++ // We assume that this is a same-site, same-party context.
|
|
|
+ net::CookieOptions net_options;
|
|
|
+ net_options.set_same_site_cookie_context(
|
|
|
+ net::CookieOptions::SameSiteCookieContext::MakeInclusive());
|
|
|
++ net_options.set_same_party_context(net::SamePartyContext::MakeInclusive());
|
|
|
++ // It doesn't matter which we choose here, since both SameParty and SameSite
|
|
|
++ // semantics should allow this access. But we make a choice to be explicit.
|
|
|
++ net_options.set_is_in_nontrivial_first_party_set(true);
|
|
|
+
|
|
|
+ return cookie
|
|
|
+- .IncludeForRequestURL(url_, net_options,
|
|
|
+- net::CookieAccessParams{
|
|
|
+- access_semantics,
|
|
|
+- network::IsUrlPotentiallyTrustworthy(url_),
|
|
|
+- })
|
|
|
++ .IncludeForRequestURL(
|
|
|
++ url_, net_options,
|
|
|
++ net::CookieAccessParams{
|
|
|
++ access_semantics,
|
|
|
++ network::IsUrlPotentiallyTrustworthy(url_),
|
|
|
++ net::cookie_util::GetSamePartyStatus(
|
|
|
++ cookie, net_options,
|
|
|
++ base::FeatureList::IsEnabled(
|
|
|
++ net::features::kSamePartyAttributeEnabled)),
|
|
|
++ })
|
|
|
+ .status.IsInclude();
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
|
|
|
+index 74737944f75cdc45b07ae110551ec4b2f250abc7..26a051883a10964168122f9b4ce8ac37f4efa006 100644
|
|
|
+--- a/content/browser/devtools/protocol/network_handler.cc
|
|
|
++++ b/content/browser/devtools/protocol/network_handler.cc
|
|
|
+@@ -783,6 +783,11 @@ GetProtocolBlockedSetCookieReason(net::CookieInclusionStatus status) {
|
|
|
+ blockedReasons->push_back(
|
|
|
+ Network::SetCookieBlockedReasonEnum::ThirdPartyBlockedInFirstPartySet);
|
|
|
+ }
|
|
|
++ if (status.HasExclusionReason(
|
|
|
++ net::CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT)) {
|
|
|
++ blockedReasons->push_back(
|
|
|
++ Network::SetCookieBlockedReasonEnum::SamePartyFromCrossPartyContext);
|
|
|
++ }
|
|
|
+ if (status.HasExclusionReason(
|
|
|
+ net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE)) {
|
|
|
+ blockedReasons->push_back(Network::SetCookieBlockedReasonEnum::SyntaxError);
|
|
|
+@@ -807,6 +812,11 @@ GetProtocolBlockedSetCookieReason(net::CookieInclusionStatus status) {
|
|
|
+ blockedReasons->push_back(
|
|
|
+ Network::SetCookieBlockedReasonEnum::InvalidPrefix);
|
|
|
+ }
|
|
|
++ if (status.HasExclusionReason(
|
|
|
++ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY)) {
|
|
|
++ blockedReasons->push_back(Network::SetCookieBlockedReasonEnum::
|
|
|
++ SamePartyConflictsWithOtherAttributes);
|
|
|
++ }
|
|
|
+ if (status.HasExclusionReason(net::CookieInclusionStatus::
|
|
|
+ EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE)) {
|
|
|
+ blockedReasons->push_back(
|
|
|
+@@ -889,6 +899,11 @@ GetProtocolBlockedCookieReason(net::CookieInclusionStatus status) {
|
|
|
+ blockedReasons->push_back(
|
|
|
+ Network::CookieBlockedReasonEnum::ThirdPartyBlockedInFirstPartySet);
|
|
|
+ }
|
|
|
++ if (status.HasExclusionReason(
|
|
|
++ net::CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT)) {
|
|
|
++ blockedReasons->push_back(
|
|
|
++ Network::CookieBlockedReasonEnum::SamePartyFromCrossPartyContext);
|
|
|
++ }
|
|
|
+ if (status.HasExclusionReason(net::CookieInclusionStatus::
|
|
|
+ EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE)) {
|
|
|
+ blockedReasons->push_back(
|
|
|
+diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.cc b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
|
|
|
+index cefd0827b70fb092012d37357ad20444655db9a2..fef5f9ee7c9e3d005d1e366a332e408a1b4cab22 100644
|
|
|
+--- a/content/browser/first_party_sets/first_party_sets_handler_impl.cc
|
|
|
++++ b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
|
|
|
+@@ -443,6 +443,7 @@ void FirstPartySetsHandlerImpl::DidClearSiteDataOnChangedSetsForContext(
|
|
|
+ void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+@@ -450,17 +451,19 @@ void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadata(
|
|
|
+ EnqueuePendingTask(base::BindOnce(
|
|
|
+ &FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal,
|
|
|
+ base::Unretained(this), site, base::OptionalFromPtr(top_frame_site),
|
|
|
+- config.Clone(), base::ElapsedTimer(), std::move(callback)));
|
|
|
++ party_context, config.Clone(), base::ElapsedTimer(),
|
|
|
++ std::move(callback)));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+- std::move(callback).Run(
|
|
|
+- global_sets_->ComputeMetadata(site, top_frame_site, config));
|
|
|
++ std::move(callback).Run(global_sets_->ComputeMetadata(site, top_frame_site,
|
|
|
++ party_context, config));
|
|
|
+ }
|
|
|
+
|
|
|
+ void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& config,
|
|
|
+ const base::ElapsedTimer& timer,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
|
+@@ -472,7 +475,7 @@ void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal(
|
|
|
+ timer.Elapsed());
|
|
|
+
|
|
|
+ std::move(callback).Run(global_sets_->ComputeMetadata(
|
|
|
+- site, base::OptionalToPtr(top_frame_site), config));
|
|
|
++ site, base::OptionalToPtr(top_frame_site), party_context, config));
|
|
|
+ }
|
|
|
+
|
|
|
+ net::FirstPartySetsContextConfig
|
|
|
+diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.h b/content/browser/first_party_sets/first_party_sets_handler_impl.h
|
|
|
+index 877f713c77542d0aab7d9bcd309c9346f97467f5..61e0cc95484e8fb1396d6734f73745b7c7ae16b5 100644
|
|
|
+--- a/content/browser/first_party_sets/first_party_sets_handler_impl.h
|
|
|
++++ b/content/browser/first_party_sets/first_party_sets_handler_impl.h
|
|
|
+@@ -110,6 +110,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
|
|
|
+ void ComputeFirstPartySetMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) override;
|
|
|
+
|
|
|
+@@ -174,6 +175,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
|
|
|
+ void ComputeFirstPartySetMetadataInternal(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& config,
|
|
|
+ const base::ElapsedTimer& timer,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
|
|
|
+diff --git a/content/browser/renderer_host/cookie_utils.cc b/content/browser/renderer_host/cookie_utils.cc
|
|
|
+index 47707316874d2c23948c804321abea17a5300bf5..71d3ac287ef911589391c6fa6f1cdf9b2c1f5234 100644
|
|
|
+--- a/content/browser/renderer_host/cookie_utils.cc
|
|
|
++++ b/content/browser/renderer_host/cookie_utils.cc
|
|
|
+@@ -104,6 +104,8 @@ void RecordSchemefulContextDowngradeUKM(
|
|
|
+ bool ShouldReportDevToolsIssueForStatus(
|
|
|
+ const net::CookieInclusionStatus& status) {
|
|
|
+ return status.ShouldWarn() ||
|
|
|
++ status.HasExclusionReason(
|
|
|
++ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY) ||
|
|
|
+ status.HasExclusionReason(
|
|
|
+ net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII) ||
|
|
|
+ status.HasExclusionReason(
|
|
|
+@@ -173,6 +175,10 @@ void EmitCookieWarningsAndMetrics(
|
|
|
+ bool breaking_context_downgrade = false;
|
|
|
+ bool lax_allow_unsafe_cookies = false;
|
|
|
+
|
|
|
++ bool same_party = false;
|
|
|
++ bool same_party_exclusion_overruled_samesite = false;
|
|
|
++ bool same_party_inclusion_overruled_samesite = false;
|
|
|
++
|
|
|
+ bool samesite_cookie_inclusion_changed_by_cross_site_redirect = false;
|
|
|
+
|
|
|
+ bool partitioned_cookies_exist = false;
|
|
|
+@@ -217,6 +223,22 @@ void EmitCookieWarningsAndMetrics(
|
|
|
+ net::CookieInclusionStatus::
|
|
|
+ WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
|
|
|
+
|
|
|
++ same_party = same_party ||
|
|
|
++ status.HasWarningReason(
|
|
|
++ net::CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
|
|
|
++
|
|
|
++ same_party_exclusion_overruled_samesite =
|
|
|
++ same_party_exclusion_overruled_samesite ||
|
|
|
++ status.HasWarningReason(
|
|
|
++ net::CookieInclusionStatus::
|
|
|
++ WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
|
|
|
++
|
|
|
++ same_party_inclusion_overruled_samesite =
|
|
|
++ same_party_inclusion_overruled_samesite ||
|
|
|
++ status.HasWarningReason(
|
|
|
++ net::CookieInclusionStatus::
|
|
|
++ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
|
|
|
++
|
|
|
+ samesite_cookie_inclusion_changed_by_cross_site_redirect =
|
|
|
+ samesite_cookie_inclusion_changed_by_cross_site_redirect ||
|
|
|
+ status.HasWarningReason(
|
|
|
+@@ -304,6 +326,23 @@ void EmitCookieWarningsAndMetrics(
|
|
|
+ rfh, blink::mojom::WebFeature::kLaxAllowingUnsafeCookies);
|
|
|
+ }
|
|
|
+
|
|
|
++ if (same_party) {
|
|
|
++ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
|
++ rfh, blink::mojom::WebFeature::kSamePartyCookieAttribute);
|
|
|
++ }
|
|
|
++
|
|
|
++ if (same_party_exclusion_overruled_samesite) {
|
|
|
++ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
|
++ rfh,
|
|
|
++ blink::mojom::WebFeature::kSamePartyCookieExclusionOverruledSameSite);
|
|
|
++ }
|
|
|
++
|
|
|
++ if (same_party_inclusion_overruled_samesite) {
|
|
|
++ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
|
++ rfh,
|
|
|
++ blink::mojom::WebFeature::kSamePartyCookieInclusionOverruledSameSite);
|
|
|
++ }
|
|
|
++
|
|
|
+ if (samesite_cookie_inclusion_changed_by_cross_site_redirect) {
|
|
|
+ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
|
+ rfh, blink::mojom::WebFeature::
|
|
|
+diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h
|
|
|
+index 6d829bf3aec1abd6747492d1bf9b82e8081946af..6814bcf8f4d7549cb026743b94c93f0f9d8a5e6f 100644
|
|
|
+--- a/content/public/browser/first_party_sets_handler.h
|
|
|
++++ b/content/public/browser/first_party_sets_handler.h
|
|
|
+@@ -195,6 +195,7 @@ class CONTENT_EXPORT FirstPartySetsHandler {
|
|
|
+ virtual void ComputeFirstPartySetMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) = 0;
|
|
|
+ };
|
|
|
+diff --git a/net/BUILD.gn b/net/BUILD.gn
|
|
|
+index f0493cfd8456000f88f1536e908fdc8ace227a28..68a30283eda63918f14efcc4cb40971180dc6ea8 100644
|
|
|
+--- a/net/BUILD.gn
|
|
|
++++ b/net/BUILD.gn
|
|
|
+@@ -584,6 +584,8 @@ component("net") {
|
|
|
+ "first_party_sets/first_party_sets_context_config.h",
|
|
|
+ "first_party_sets/global_first_party_sets.cc",
|
|
|
+ "first_party_sets/global_first_party_sets.h",
|
|
|
++ "first_party_sets/same_party_context.cc",
|
|
|
++ "first_party_sets/same_party_context.h",
|
|
|
+ "http/alternative_service.cc",
|
|
|
+ "http/alternative_service.h",
|
|
|
+ "http/bidirectional_stream.cc",
|
|
|
+diff --git a/net/base/features.cc b/net/base/features.cc
|
|
|
+index 0f675cc7951ec2bd45a810e740a4d0981136a60b..3d892468de1e0231855c84e4f46cf94b1cfdd8ae 100644
|
|
|
+--- a/net/base/features.cc
|
|
|
++++ b/net/base/features.cc
|
|
|
+@@ -247,6 +247,10 @@ BASE_FEATURE(kCookieSameSiteConsidersRedirectChain,
|
|
|
+ "CookieSameSiteConsidersRedirectChain",
|
|
|
+ base::FEATURE_DISABLED_BY_DEFAULT);
|
|
|
+
|
|
|
++BASE_FEATURE(kSamePartyAttributeEnabled,
|
|
|
++ "SamePartyAttributeEnabled",
|
|
|
++ base::FEATURE_DISABLED_BY_DEFAULT);
|
|
|
++
|
|
|
+ BASE_FEATURE(kWaitForFirstPartySetsInit,
|
|
|
+ "WaitForFirstPartySetsInit",
|
|
|
+ base::FEATURE_ENABLED_BY_DEFAULT);
|
|
|
+diff --git a/net/base/features.h b/net/base/features.h
|
|
|
+index 46a132caade78e1f4f3ea87cf2bee43d2aaf9bca..966a3a18173212fecbd05ac9d0e11ba787195615 100644
|
|
|
+--- a/net/base/features.h
|
|
|
++++ b/net/base/features.h
|
|
|
+@@ -297,6 +297,12 @@ NET_EXPORT BASE_DECLARE_FEATURE(kUdpSocketPosixAlwaysUpdateBytesReceived);
|
|
|
+ // See spec changes in https://github.com/httpwg/http-extensions/pull/1348
|
|
|
+ NET_EXPORT BASE_DECLARE_FEATURE(kCookieSameSiteConsidersRedirectChain);
|
|
|
+
|
|
|
++// When this feature is enabled, the SameParty attribute is enabled. (Note that
|
|
|
++// when this feature is disabled, the SameParty attribute is still parsed and
|
|
|
++// saved for cookie-sets, but it has no associated semantics (when setting or
|
|
|
++// reading cookies).)
|
|
|
++NET_EXPORT BASE_DECLARE_FEATURE(kSamePartyAttributeEnabled);
|
|
|
++
|
|
|
+ // When this feature is enabled, the network service will wait until First-Party
|
|
|
+ // Sets are initialized before issuing requests that use the HTTP cache or
|
|
|
+ // cookies.
|
|
|
+diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
|
|
|
+index 089443aab299000b7a10b42b90f3367318aa7730..cc2742ff7d3b04e42988b5e0e927d91af5c12389 100644
|
|
|
+--- a/net/cookies/canonical_cookie.cc
|
|
|
++++ b/net/cookies/canonical_cookie.cc
|
|
|
+@@ -339,9 +339,11 @@ bool HasValidHostPrefixAttributes(const GURL& url,
|
|
|
+ } // namespace
|
|
|
+
|
|
|
+ CookieAccessParams::CookieAccessParams(CookieAccessSemantics access_semantics,
|
|
|
+- bool delegate_treats_url_as_trustworthy)
|
|
|
++ bool delegate_treats_url_as_trustworthy,
|
|
|
++ CookieSamePartyStatus same_party_status)
|
|
|
+ : access_semantics(access_semantics),
|
|
|
+- delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy) {}
|
|
|
++ delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy),
|
|
|
++ same_party_status(same_party_status) {}
|
|
|
+
|
|
|
+ CanonicalCookie::CanonicalCookie() = default;
|
|
|
+
|
|
|
+@@ -614,6 +616,12 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
|
|
|
+ status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
|
|
|
+ }
|
|
|
+
|
|
|
++ bool is_same_party_valid = IsCookieSamePartyValid(parsed_cookie);
|
|
|
++ if (!is_same_party_valid) {
|
|
|
++ status->AddExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
|
|
|
++ }
|
|
|
++
|
|
|
+ bool partition_has_nonce = CookiePartitionKey::HasNonce(cookie_partition_key);
|
|
|
+ bool is_partitioned_valid =
|
|
|
+ IsCookiePartitionedValid(url, parsed_cookie, partition_has_nonce);
|
|
|
+@@ -879,6 +887,10 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
|
|
|
+ net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
|
|
|
+ }
|
|
|
+
|
|
|
++ if (!IsCookieSamePartyValid(same_party, secure, same_site)) {
|
|
|
++ status->AddExclusionReason(
|
|
|
++ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
|
|
|
++ }
|
|
|
+ if (!IsCookiePartitionedValid(url, secure,
|
|
|
+ /*is_partitioned=*/partition_key.has_value(),
|
|
|
+ /*partition_has_nonce=*/
|
|
|
+@@ -1180,11 +1192,56 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL(
|
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
|
|
|
+ }
|
|
|
+
|
|
|
+- // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
|
+- ApplySameSiteCookieWarningToStatus(SameSite(), effective_same_site,
|
|
|
+- IsSecure(),
|
|
|
+- options.same_site_cookie_context(),
|
|
|
+- &status, false /* is_cookie_being_set */);
|
|
|
++ switch (params.same_party_status) {
|
|
|
++ case CookieSamePartyStatus::kEnforceSamePartyExclude:
|
|
|
++ DCHECK(IsSameParty());
|
|
|
++ status.AddExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
|
|
|
++ [[fallthrough]];
|
|
|
++ case CookieSamePartyStatus::kEnforceSamePartyInclude: {
|
|
|
++ status.AddWarningReason(CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
|
|
|
++ // Remove any SameSite exclusion reasons, since SameParty overrides
|
|
|
++ // SameSite.
|
|
|
++ DCHECK(!status.HasExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
|
|
|
++ DCHECK_NE(effective_same_site, CookieEffectiveSameSite::STRICT_MODE);
|
|
|
++ bool included_by_samesite =
|
|
|
++ !status.HasExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
|
|
|
++ !status.HasExclusionReason(
|
|
|
++ CookieInclusionStatus::
|
|
|
++ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
|
|
|
++ if (!included_by_samesite) {
|
|
|
++ status.RemoveExclusionReasons({
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
|
|
++ });
|
|
|
++ }
|
|
|
++
|
|
|
++ // Update metrics.
|
|
|
++ if (status.HasOnlyExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
|
|
|
++ included_by_samesite) {
|
|
|
++ status.AddWarningReason(
|
|
|
++ CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
|
|
|
++ }
|
|
|
++ if (status.IsInclude()) {
|
|
|
++ if (!included_by_samesite) {
|
|
|
++ status.AddWarningReason(
|
|
|
++ CookieInclusionStatus::
|
|
|
++ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
|
|
|
++ }
|
|
|
++ }
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ case CookieSamePartyStatus::kNoSamePartyEnforcement:
|
|
|
++ // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
|
++ ApplySameSiteCookieWarningToStatus(
|
|
|
++ SameSite(), effective_same_site, IsSecure(),
|
|
|
++ options.same_site_cookie_context(), &status,
|
|
|
++ false /* is_cookie_being_set */);
|
|
|
++ break;
|
|
|
++ }
|
|
|
+
|
|
|
+ if (status.IsInclude()) {
|
|
|
+ UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedRequestEffectiveSameSite",
|
|
|
+@@ -1354,11 +1411,59 @@ CookieAccessResult CanonicalCookie::IsSetPermittedInContext(
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+- // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
|
+- ApplySameSiteCookieWarningToStatus(
|
|
|
+- SameSite(), access_result.effective_same_site, IsSecure(),
|
|
|
+- options.same_site_cookie_context(), &access_result.status,
|
|
|
+- true /* is_cookie_being_set */);
|
|
|
++ switch (params.same_party_status) {
|
|
|
++ case CookieSamePartyStatus::kEnforceSamePartyExclude:
|
|
|
++ DCHECK(IsSameParty());
|
|
|
++ access_result.status.AddExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
|
|
|
++ [[fallthrough]];
|
|
|
++ case CookieSamePartyStatus::kEnforceSamePartyInclude: {
|
|
|
++ DCHECK(IsSameParty());
|
|
|
++ access_result.status.AddWarningReason(
|
|
|
++ CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
|
|
|
++ // Remove any SameSite exclusion reasons, since SameParty overrides
|
|
|
++ // SameSite.
|
|
|
++ DCHECK(!access_result.status.HasExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
|
|
|
++ DCHECK_NE(access_result.effective_same_site,
|
|
|
++ CookieEffectiveSameSite::STRICT_MODE);
|
|
|
++ bool included_by_samesite =
|
|
|
++ !access_result.status.HasExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
|
|
|
++ !access_result.status.HasExclusionReason(
|
|
|
++ CookieInclusionStatus::
|
|
|
++ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
|
|
|
++ if (!included_by_samesite) {
|
|
|
++ access_result.status.RemoveExclusionReasons({
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
|
|
++ });
|
|
|
++ }
|
|
|
++
|
|
|
++ // Update metrics.
|
|
|
++ if (access_result.status.HasOnlyExclusionReason(
|
|
|
++ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
|
|
|
++ included_by_samesite) {
|
|
|
++ access_result.status.AddWarningReason(
|
|
|
++ CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
|
|
|
++ }
|
|
|
++ if (access_result.status.IsInclude()) {
|
|
|
++ if (!included_by_samesite) {
|
|
|
++ access_result.status.AddWarningReason(
|
|
|
++ CookieInclusionStatus::
|
|
|
++ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
|
|
|
++ }
|
|
|
++ }
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ case CookieSamePartyStatus::kNoSamePartyEnforcement:
|
|
|
++ // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
|
++ ApplySameSiteCookieWarningToStatus(
|
|
|
++ SameSite(), access_result.effective_same_site, IsSecure(),
|
|
|
++ options.same_site_cookie_context(), &access_result.status,
|
|
|
++ true /* is_cookie_being_set */);
|
|
|
++ break;
|
|
|
++ }
|
|
|
+
|
|
|
+ if (access_result.status.IsInclude()) {
|
|
|
+ UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedResponseEffectiveSameSite",
|
|
|
+@@ -1465,6 +1570,9 @@ bool CanonicalCookie::IsCanonicalForFromStorage() const {
|
|
|
+ if (name_ == "" && HasHiddenPrefixName(value_))
|
|
|
+ return false;
|
|
|
+
|
|
|
++ if (!IsCookieSamePartyValid(same_party_, secure_, same_site_))
|
|
|
++ return false;
|
|
|
++
|
|
|
+ if (IsPartitioned()) {
|
|
|
+ if (CookiePartitionKey::HasNonce(partition_key_))
|
|
|
+ return true;
|
|
|
+@@ -1711,6 +1819,23 @@ bool CanonicalCookie::IsRecentlyCreated(base::TimeDelta age_threshold) const {
|
|
|
+ return (base::Time::Now() - creation_date_) <= age_threshold;
|
|
|
+ }
|
|
|
+
|
|
|
++// static
|
|
|
++bool CanonicalCookie::IsCookieSamePartyValid(
|
|
|
++ const ParsedCookie& parsed_cookie) {
|
|
|
++ return IsCookieSamePartyValid(parsed_cookie.IsSameParty(),
|
|
|
++ parsed_cookie.IsSecure(),
|
|
|
++ parsed_cookie.SameSite());
|
|
|
++}
|
|
|
++
|
|
|
++// static
|
|
|
++bool CanonicalCookie::IsCookieSamePartyValid(bool is_same_party,
|
|
|
++ bool is_secure,
|
|
|
++ CookieSameSite same_site) {
|
|
|
++ if (!is_same_party)
|
|
|
++ return true;
|
|
|
++ return is_secure && (same_site != CookieSameSite::STRICT_MODE);
|
|
|
++}
|
|
|
++
|
|
|
+ // static
|
|
|
+ bool CanonicalCookie::IsCookiePartitionedValid(
|
|
|
+ const GURL& url,
|
|
|
+diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
|
|
|
+index 6a86240fd610b1c1148e5df39c2243f715d10975..5744b3644a615ba256573887047e2f3917123b96 100644
|
|
|
+--- a/net/cookies/canonical_cookie.h
|
|
|
++++ b/net/cookies/canonical_cookie.h
|
|
|
+@@ -43,7 +43,8 @@ using CookieAccessResultList = std::vector<CookieWithAccessResult>;
|
|
|
+ struct NET_EXPORT CookieAccessParams {
|
|
|
+ CookieAccessParams() = delete;
|
|
|
+ CookieAccessParams(CookieAccessSemantics access_semantics,
|
|
|
+- bool delegate_treats_url_as_trustworthy);
|
|
|
++ bool delegate_treats_url_as_trustworthy,
|
|
|
++ CookieSamePartyStatus same_party_status);
|
|
|
+
|
|
|
+ // |access_semantics| is the access mode of the cookie access check.
|
|
|
+ CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN;
|
|
|
+@@ -51,6 +52,10 @@ struct NET_EXPORT CookieAccessParams {
|
|
|
+ // CookieAccessDelegate has authorized access to secure cookies from URLs
|
|
|
+ // which might not otherwise be able to do so.
|
|
|
+ bool delegate_treats_url_as_trustworthy = false;
|
|
|
++ // |same_party_status| indicates whether, and how, SameParty restrictions
|
|
|
++ // should be enforced.
|
|
|
++ CookieSamePartyStatus same_party_status =
|
|
|
++ CookieSamePartyStatus::kNoSamePartyEnforcement;
|
|
|
+ };
|
|
|
+
|
|
|
+ class NET_EXPORT CanonicalCookie {
|
|
|
+@@ -537,6 +542,14 @@ class NET_EXPORT CanonicalCookie {
|
|
|
+ // Returns whether the cookie was created at most |age_threshold| ago.
|
|
|
+ bool IsRecentlyCreated(base::TimeDelta age_threshold) const;
|
|
|
+
|
|
|
++ // Returns true iff the cookie does not violate any rules associated with
|
|
|
++ // creating a cookie with the SameParty attribute. In particular, if a cookie
|
|
|
++ // has SameParty, then it must be Secure and must not be SameSite=Strict.
|
|
|
++ static bool IsCookieSamePartyValid(const ParsedCookie& parsed_cookie);
|
|
|
++ static bool IsCookieSamePartyValid(bool is_same_party,
|
|
|
++ bool is_secure,
|
|
|
++ CookieSameSite same_site);
|
|
|
++
|
|
|
+ // Returns true iff the cookie is a partitioned cookie with a nonce or that
|
|
|
+ // does not violate the semantics of the Partitioned attribute:
|
|
|
+ // - Must have the Secure attribute OR the cookie partition contains a nonce.
|
|
|
+diff --git a/net/cookies/cookie_access_delegate.cc b/net/cookies/cookie_access_delegate.cc
|
|
|
+index 256dd856cce9fb482926f7a0c8bb80676a37e0e7..9811f944fff0a20a1a7b431e214f3578ed30785b 100644
|
|
|
+--- a/net/cookies/cookie_access_delegate.cc
|
|
|
++++ b/net/cookies/cookie_access_delegate.cc
|
|
|
+@@ -4,7 +4,13 @@
|
|
|
+
|
|
|
+ #include "net/cookies/cookie_access_delegate.h"
|
|
|
+
|
|
|
+-class GURL;
|
|
|
++#include <set>
|
|
|
++
|
|
|
++#include "base/functional/callback.h"
|
|
|
++#include "net/base/schemeful_site.h"
|
|
|
++#include "net/cookies/cookie_partition_key.h"
|
|
|
++#include "net/first_party_sets/first_party_set_entry.h"
|
|
|
++#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
+
|
|
|
+ namespace net {
|
|
|
+
|
|
|
+diff --git a/net/cookies/cookie_access_delegate.h b/net/cookies/cookie_access_delegate.h
|
|
|
+index 203434ee5d078284e396c5711617ec0dd7f2e174..ee8e3d0fab27ef7f087194ad8fcfb6f17b042592 100644
|
|
|
+--- a/net/cookies/cookie_access_delegate.h
|
|
|
++++ b/net/cookies/cookie_access_delegate.h
|
|
|
+@@ -5,6 +5,8 @@
|
|
|
+ #ifndef NET_COOKIES_COOKIE_ACCESS_DELEGATE_H_
|
|
|
+ #define NET_COOKIES_COOKIE_ACCESS_DELEGATE_H_
|
|
|
+
|
|
|
++#include <set>
|
|
|
++
|
|
|
+ #include "base/containers/flat_map.h"
|
|
|
+ #include "base/containers/flat_set.h"
|
|
|
+ #include "base/functional/callback_forward.h"
|
|
|
+@@ -15,6 +17,7 @@
|
|
|
+ #include "net/cookies/cookie_partition_key.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_entry.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_metadata.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
+ #include "url/gurl.h"
|
|
|
+
|
|
|
+@@ -49,8 +52,10 @@ class NET_EXPORT CookieAccessDelegate {
|
|
|
+ const GURL& url,
|
|
|
+ const SiteForCookies& site_for_cookies) const = 0;
|
|
|
+
|
|
|
+- // Calls `callback` with First-Party Sets metadata about `site` and
|
|
|
+- // `top_frame_site`.
|
|
|
++ // Calls `callback` with metadata indicating whether `site` is same-party with
|
|
|
++ // `party_context` and `top_frame_site`; and `site`'s owner, if applicable..
|
|
|
++ // If `top_frame_site` is nullptr, then `site` will be checked only against
|
|
|
++ // `party_context`.
|
|
|
+ //
|
|
|
+ // This may return a result synchronously, or asynchronously invoke `callback`
|
|
|
+ // with the result. The callback will be invoked iff the return value is
|
|
|
+@@ -60,6 +65,7 @@ class NET_EXPORT CookieAccessDelegate {
|
|
|
+ ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(FirstPartySetMetadata)> callback) const = 0;
|
|
|
+
|
|
|
+ // Returns the entries of a set of sites if the sites are in non-trivial sets.
|
|
|
+diff --git a/net/cookies/cookie_constants.h b/net/cookies/cookie_constants.h
|
|
|
+index 725517694b1eda27181e683be3b631ebecb63486..5a7913ca669eabafb9fef59267a1b40632e11165 100644
|
|
|
+--- a/net/cookies/cookie_constants.h
|
|
|
++++ b/net/cookies/cookie_constants.h
|
|
|
+@@ -118,6 +118,16 @@ enum class CookieAccessSemantics {
|
|
|
+ LEGACY,
|
|
|
+ };
|
|
|
+
|
|
|
++enum class CookieSamePartyStatus {
|
|
|
++ // Used when there should be no SameParty enforcement (either because the
|
|
|
++ // cookie is not marked SameParty, or the enforcement is irrelevant).
|
|
|
++ kNoSamePartyEnforcement = 0,
|
|
|
++ // Used when SameParty enforcement says to exclude the cookie.
|
|
|
++ kEnforceSamePartyExclude = 1,
|
|
|
++ // Used when SameParty enforcement says to include the cookie.
|
|
|
++ kEnforceSamePartyInclude = 2,
|
|
|
++};
|
|
|
++
|
|
|
+ // What scheme was used in the setting of a cookie.
|
|
|
+ // Do not renumber.
|
|
|
+ enum class CookieSourceScheme {
|
|
|
+diff --git a/net/cookies/cookie_inclusion_status.cc b/net/cookies/cookie_inclusion_status.cc
|
|
|
+index 117fca1e81b6a77bd787368151ed984648e20175..d23a2ac82762667e332abc414fe0c25c4d47f09e 100644
|
|
|
+--- a/net/cookies/cookie_inclusion_status.cc
|
|
|
++++ b/net/cookies/cookie_inclusion_status.cc
|
|
|
+@@ -231,6 +231,9 @@ std::string CookieInclusionStatus::GetDebugString() const {
|
|
|
+ {EXCLUDE_SHADOWING_DOMAIN, "EXCLUDE_SHADOWING_DOMAIN"},
|
|
|
+ {EXCLUDE_DISALLOWED_CHARACTER, "EXCLUDE_DISALLOWED_CHARACTER"},
|
|
|
+ {EXCLUDE_THIRD_PARTY_PHASEOUT, "EXCLUDE_THIRD_PARTY_PHASEOUT"},
|
|
|
++ {EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT,
|
|
|
++ "EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT"},
|
|
|
++ {EXCLUDE_INVALID_SAMEPARTY, "EXCLUDE_INVALID_SAMEPARTY"},
|
|
|
+ };
|
|
|
+ static_assert(
|
|
|
+ std::size(exclusion_reasons) == ExclusionReason::NUM_EXCLUSION_REASONS,
|
|
|
+@@ -280,6 +283,11 @@ std::string CookieInclusionStatus::GetDebugString() const {
|
|
|
+ "WARN_TENTATIVELY_ALLOWING_SECURE_SOURCE_SCHEME"},
|
|
|
+ {WARN_SHADOWING_DOMAIN, "WARN_SHADOWING_DOMAIN"},
|
|
|
+ {WARN_THIRD_PARTY_PHASEOUT, "WARN_THIRD_PARTY_PHASEOUT"},
|
|
|
++ {WARN_TREATED_AS_SAMEPARTY, "WARN_TREATED_AS_SAMEPARTY"},
|
|
|
++ {WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE,
|
|
|
++ "WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE"},
|
|
|
++ {WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE,
|
|
|
++ "WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE"},
|
|
|
+ };
|
|
|
+ static_assert(
|
|
|
+ std::size(warning_reasons) == WarningReason::NUM_WARNING_REASONS,
|
|
|
+diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h
|
|
|
+index e197c984d721171f5a131a1a7a8913cc9292719b..566e94489cbac6f0fa3d325a636ea1b71fb5615e 100644
|
|
|
+--- a/net/cookies/cookie_inclusion_status.h
|
|
|
++++ b/net/cookies/cookie_inclusion_status.h
|
|
|
+@@ -107,6 +107,12 @@ class NET_EXPORT CookieInclusionStatus {
|
|
|
+ EXCLUDE_DISALLOWED_CHARACTER = 24,
|
|
|
+ // Cookie is blocked for third-party cookie phaseout.
|
|
|
+ EXCLUDE_THIRD_PARTY_PHASEOUT = 25,
|
|
|
++ // The cookie specified SameParty, but was used in a cross-party context.
|
|
|
++ EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT = 26,
|
|
|
++ // Cookie was set with an invalid SameParty attribute in combination with
|
|
|
++ // other attributes. (SameParty is invalid if Secure is not present, or if
|
|
|
++ // SameSite=Strict is present.)
|
|
|
++ EXCLUDE_INVALID_SAMEPARTY = 27,
|
|
|
+
|
|
|
+ // This should be kept last.
|
|
|
+ NUM_EXCLUSION_REASONS
|
|
|
+@@ -226,6 +232,24 @@ class NET_EXPORT CookieInclusionStatus {
|
|
|
+ // This cookie will be blocked for third-party cookie phaseout.
|
|
|
+ WARN_THIRD_PARTY_PHASEOUT = 16,
|
|
|
+
|
|
|
++ // The cookie was treated as SameParty. This is different from looking at
|
|
|
++ // whether the cookie has the SameParty attribute, since we may choose to
|
|
|
++ // ignore that attribute for one reason or another. E.g., we ignore the
|
|
|
++ // SameParty attribute if the site is not a member of a nontrivial
|
|
|
++ // First-Party Set.
|
|
|
++ WARN_TREATED_AS_SAMEPARTY = 17,
|
|
|
++
|
|
|
++ // The cookie was excluded solely for SameParty reasons (i.e. it was in
|
|
|
++ // cross-party context), but would have been included by SameSite. (This can
|
|
|
++ // only occur in cross-party, cross-site contexts, for cookies that are
|
|
|
++ // 'SameParty; SameSite=None'.)
|
|
|
++ WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE = 18,
|
|
|
++
|
|
|
++ // The cookie was included due to SameParty, even though it would have been
|
|
|
++ // excluded by SameSite. (This can only occur in same-party, cross-site
|
|
|
++ // contexts, for cookies that are 'SameParty; SameSite=Lax'.)
|
|
|
++ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE = 19,
|
|
|
++
|
|
|
+ // This should be kept last.
|
|
|
+ NUM_WARNING_REASONS
|
|
|
+ };
|
|
|
+diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
|
|
|
+index 0c3ce2e289b5944d38315790cca829e851c31e19..5c4352bb9fc1fd85373ee413b59a12967bd02710 100644
|
|
|
+--- a/net/cookies/cookie_monster.cc
|
|
|
++++ b/net/cookies/cookie_monster.cc
|
|
|
+@@ -377,7 +377,9 @@ CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
|
|
|
+ CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
|
|
|
+ base::TimeDelta last_access_threshold,
|
|
|
+ NetLog* net_log)
|
|
|
+- : change_dispatcher_(this),
|
|
|
++ : same_party_attribute_enabled_(base::FeatureList::IsEnabled(
|
|
|
++ net::features::kSamePartyAttributeEnabled)),
|
|
|
++ change_dispatcher_(this, same_party_attribute_enabled_),
|
|
|
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
|
|
|
+ store_(std::move(store)),
|
|
|
+ last_access_threshold_(last_access_threshold),
|
|
|
+@@ -739,9 +741,13 @@ bool CookieMonster::MatchCookieDeletionInfo(
|
|
|
+ delete_info.url.value());
|
|
|
+ }
|
|
|
+
|
|
|
++ // Deletion uses all inclusive options, so it's ok to get the
|
|
|
++ // `CookieSamePartyStatus` wrong here.
|
|
|
+ return delete_info.Matches(
|
|
|
+- cookie, CookieAccessParams{GetAccessSemanticsForCookie(cookie),
|
|
|
+- delegate_treats_url_as_trustworthy});
|
|
|
++ cookie,
|
|
|
++ CookieAccessParams{GetAccessSemanticsForCookie(cookie),
|
|
|
++ delegate_treats_url_as_trustworthy,
|
|
|
++ CookieSamePartyStatus::kNoSamePartyEnforcement});
|
|
|
+ }
|
|
|
+
|
|
|
+ void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
|
|
|
+@@ -1205,8 +1211,11 @@ void CookieMonster::FilterCookiesWithOptions(
|
|
|
+ // cookie |options|.
|
|
|
+ CookieAccessResult access_result = cookie_ptr->IncludeForRequestURL(
|
|
|
+ url, options,
|
|
|
+- CookieAccessParams{GetAccessSemanticsForCookie(*cookie_ptr),
|
|
|
+- delegate_treats_url_as_trustworthy});
|
|
|
++ CookieAccessParams{
|
|
|
++ GetAccessSemanticsForCookie(*cookie_ptr),
|
|
|
++ delegate_treats_url_as_trustworthy,
|
|
|
++ cookie_util::GetSamePartyStatus(*cookie_ptr, options,
|
|
|
++ same_party_attribute_enabled_)});
|
|
|
+ cookies_and_access_results.emplace_back(cookie_ptr, access_result);
|
|
|
+
|
|
|
+ // Record the names of all origin cookies that would be included if both
|
|
|
+@@ -1549,7 +1558,9 @@ void CookieMonster::SetCanonicalCookie(
|
|
|
+ CookieAccessResult access_result = cc->IsSetPermittedInContext(
|
|
|
+ source_url, options,
|
|
|
+ CookieAccessParams(GetAccessSemanticsForCookie(*cc),
|
|
|
+- delegate_treats_url_as_trustworthy),
|
|
|
++ delegate_treats_url_as_trustworthy,
|
|
|
++ cookie_util::GetSamePartyStatus(
|
|
|
++ *cc, options, same_party_attribute_enabled_)),
|
|
|
+ cookieable_schemes_, cookie_access_result);
|
|
|
+
|
|
|
+ const std::string key(GetKey(cc->Domain()));
|
|
|
+diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
|
|
|
+index 3ca2c691cfd00acf34f7648dfc6c9f6692be470a..6086953c99f55bd8a1034f0fa33ea77e4af9ec0d 100644
|
|
|
+--- a/net/cookies/cookie_monster.h
|
|
|
++++ b/net/cookies/cookie_monster.h
|
|
|
+@@ -734,6 +734,8 @@ class NET_EXPORT CookieMonster : public CookieStore {
|
|
|
+ // nonce.
|
|
|
+ size_t num_nonced_partitioned_cookie_bytes_ = 0u;
|
|
|
+
|
|
|
++ bool same_party_attribute_enabled_ = false;
|
|
|
++
|
|
|
+ CookieMonsterChangeDispatcher change_dispatcher_;
|
|
|
+
|
|
|
+ // Indicates whether the cookie store has been initialized.
|
|
|
+diff --git a/net/cookies/cookie_monster_change_dispatcher.cc b/net/cookies/cookie_monster_change_dispatcher.cc
|
|
|
+index 61bd41e5a273e9d8d467deb587794600257feae6..34448cfee892b93558016c4fba22123c9522f6c4 100644
|
|
|
+--- a/net/cookies/cookie_monster_change_dispatcher.cc
|
|
|
++++ b/net/cookies/cookie_monster_change_dispatcher.cc
|
|
|
+@@ -37,6 +37,7 @@ CookieMonsterChangeDispatcher::Subscription::Subscription(
|
|
|
+ std::string name_key,
|
|
|
+ GURL url,
|
|
|
+ CookiePartitionKeyCollection cookie_partition_key_collection,
|
|
|
++ bool same_party_attribute_enabled,
|
|
|
+ net::CookieChangeCallback callback)
|
|
|
+ : change_dispatcher_(std::move(change_dispatcher)),
|
|
|
+ domain_key_(std::move(domain_key)),
|
|
|
+@@ -45,6 +46,7 @@ CookieMonsterChangeDispatcher::Subscription::Subscription(
|
|
|
+ cookie_partition_key_collection_(
|
|
|
+ std::move(cookie_partition_key_collection)),
|
|
|
+ callback_(std::move(callback)),
|
|
|
++ same_party_attribute_enabled_(same_party_attribute_enabled),
|
|
|
+ task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
|
|
|
+ DCHECK(url_.is_valid() || url_.is_empty());
|
|
|
+ DCHECK_EQ(url_.is_empty(), domain_key_ == kGlobalDomainKey);
|
|
|
+@@ -73,11 +75,14 @@ void CookieMonsterChangeDispatcher::Subscription::DispatchChange(
|
|
|
+ cookie_access_delegate &&
|
|
|
+ cookie_access_delegate->ShouldTreatUrlAsTrustworthy(url_);
|
|
|
+ CookieOptions options = CookieOptions::MakeAllInclusive();
|
|
|
++ CookieSamePartyStatus same_party_status = cookie_util::GetSamePartyStatus(
|
|
|
++ cookie, options, same_party_attribute_enabled_);
|
|
|
+ if (!cookie
|
|
|
+ .IncludeForRequestURL(
|
|
|
+ url_, options,
|
|
|
+ CookieAccessParams{change.access_result.access_semantics,
|
|
|
+- delegate_treats_url_as_trustworthy})
|
|
|
++ delegate_treats_url_as_trustworthy,
|
|
|
++ same_party_status})
|
|
|
+ .status.IsInclude()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+@@ -111,8 +116,10 @@ void CookieMonsterChangeDispatcher::Subscription::DoDispatchChange(
|
|
|
+ }
|
|
|
+
|
|
|
+ CookieMonsterChangeDispatcher::CookieMonsterChangeDispatcher(
|
|
|
+- const CookieMonster* cookie_monster)
|
|
|
+- : cookie_monster_(cookie_monster) {}
|
|
|
++ const CookieMonster* cookie_monster,
|
|
|
++ bool same_party_attribute_enabled)
|
|
|
++ : cookie_monster_(cookie_monster),
|
|
|
++ same_party_attribute_enabled_(same_party_attribute_enabled) {}
|
|
|
+
|
|
|
+ CookieMonsterChangeDispatcher::~CookieMonsterChangeDispatcher() {
|
|
|
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
|
|
+@@ -154,7 +161,7 @@ CookieMonsterChangeDispatcher::AddCallbackForCookie(
|
|
|
+ std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
|
|
|
+ weak_ptr_factory_.GetWeakPtr(), DomainKey(url), NameKey(name), url,
|
|
|
+ CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
|
|
|
+- std::move(callback));
|
|
|
++ same_party_attribute_enabled_, std::move(callback));
|
|
|
+
|
|
|
+ LinkSubscription(subscription.get());
|
|
|
+ return subscription;
|
|
|
+@@ -171,7 +178,7 @@ CookieMonsterChangeDispatcher::AddCallbackForUrl(
|
|
|
+ weak_ptr_factory_.GetWeakPtr(), DomainKey(url),
|
|
|
+ std::string(kGlobalNameKey), url,
|
|
|
+ CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
|
|
|
+- std::move(callback));
|
|
|
++ same_party_attribute_enabled_, std::move(callback));
|
|
|
+
|
|
|
+ LinkSubscription(subscription.get());
|
|
|
+ return subscription;
|
|
|
+@@ -185,7 +192,8 @@ CookieMonsterChangeDispatcher::AddCallbackForAllChanges(
|
|
|
+ std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
|
|
|
+ weak_ptr_factory_.GetWeakPtr(), std::string(kGlobalDomainKey),
|
|
|
+ std::string(kGlobalNameKey), GURL(""),
|
|
|
+- CookiePartitionKeyCollection::ContainsAll(), std::move(callback));
|
|
|
++ CookiePartitionKeyCollection::ContainsAll(),
|
|
|
++ same_party_attribute_enabled_, std::move(callback));
|
|
|
+
|
|
|
+ LinkSubscription(subscription.get());
|
|
|
+ return subscription;
|
|
|
+diff --git a/net/cookies/cookie_monster_change_dispatcher.h b/net/cookies/cookie_monster_change_dispatcher.h
|
|
|
+index d6f449140b0244263b0c248e9163eb9940407541..31ca1e979ce1133dd6a78a7d8d09a6aba8f0ee44 100644
|
|
|
+--- a/net/cookies/cookie_monster_change_dispatcher.h
|
|
|
++++ b/net/cookies/cookie_monster_change_dispatcher.h
|
|
|
+@@ -33,7 +33,8 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
|
+ base::RepeatingCallbackList<void(const CookieChangeInfo&)>;
|
|
|
+
|
|
|
+ // Expects |cookie_monster| to outlive this.
|
|
|
+- explicit CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster);
|
|
|
++ CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster,
|
|
|
++ bool same_party_attribute_enabled);
|
|
|
+
|
|
|
+ CookieMonsterChangeDispatcher(const CookieMonsterChangeDispatcher&) = delete;
|
|
|
+ CookieMonsterChangeDispatcher& operator=(
|
|
|
+@@ -78,6 +79,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
|
+ std::string name_key,
|
|
|
+ GURL url,
|
|
|
+ CookiePartitionKeyCollection cookie_partition_key_collection,
|
|
|
++ bool same_party_attribute_enabled,
|
|
|
+ net::CookieChangeCallback callback);
|
|
|
+
|
|
|
+ Subscription(const Subscription&) = delete;
|
|
|
+@@ -105,6 +107,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
|
+ const GURL url_; // empty() means no URL-based filtering.
|
|
|
+ const CookiePartitionKeyCollection cookie_partition_key_collection_;
|
|
|
+ const net::CookieChangeCallback callback_;
|
|
|
++ bool same_party_attribute_enabled_;
|
|
|
+
|
|
|
+ void DoDispatchChange(const CookieChangeInfo& change) const;
|
|
|
+
|
|
|
+@@ -154,6 +157,8 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
|
+
|
|
|
+ CookieDomainMap cookie_domain_map_;
|
|
|
+
|
|
|
++ const bool same_party_attribute_enabled_;
|
|
|
++
|
|
|
+ THREAD_CHECKER(thread_checker_);
|
|
|
+
|
|
|
+ // Vends weak pointers to subscriptions.
|
|
|
+diff --git a/net/cookies/cookie_options.cc b/net/cookies/cookie_options.cc
|
|
|
+index d3e96410b39057e3a8d20078d69cbd728f7c8bde..42eb151094e5b26671ea576bf402f8a877e862a3 100644
|
|
|
+--- a/net/cookies/cookie_options.cc
|
|
|
++++ b/net/cookies/cookie_options.cc
|
|
|
+@@ -8,7 +8,9 @@
|
|
|
+
|
|
|
+ #include <tuple>
|
|
|
+
|
|
|
++#include "base/metrics/histogram_functions.h"
|
|
|
+ #include "net/cookies/cookie_util.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+
|
|
|
+ namespace net {
|
|
|
+
|
|
|
+@@ -99,6 +101,8 @@ CookieOptions CookieOptions::MakeAllInclusive() {
|
|
|
+ options.set_include_httponly();
|
|
|
+ options.set_same_site_cookie_context(SameSiteCookieContext::MakeInclusive());
|
|
|
+ options.set_do_not_update_access_time();
|
|
|
++ options.set_same_party_context(SamePartyContext::MakeInclusive());
|
|
|
++ options.set_is_in_nontrivial_first_party_set(true);
|
|
|
+ return options;
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/net/cookies/cookie_options.h b/net/cookies/cookie_options.h
|
|
|
+index 183c1f61c1fbe94c8c85dd4f9a27695a04aad816..fc7cddad43a74945d5af6c2100893720f3895734 100644
|
|
|
+--- a/net/cookies/cookie_options.h
|
|
|
++++ b/net/cookies/cookie_options.h
|
|
|
+@@ -10,8 +10,11 @@
|
|
|
+ #include <ostream>
|
|
|
+ #include <string>
|
|
|
+
|
|
|
+-#include "base/check_op.h"
|
|
|
+ #include "net/base/net_export.h"
|
|
|
++#include "net/cookies/cookie_constants.h"
|
|
|
++#include "net/cookies/cookie_inclusion_status.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
++#include "url/gurl.h"
|
|
|
+
|
|
|
+ namespace net {
|
|
|
+
|
|
|
+@@ -266,6 +269,26 @@ class NET_EXPORT CookieOptions {
|
|
|
+ void unset_return_excluded_cookies() { return_excluded_cookies_ = false; }
|
|
|
+ bool return_excluded_cookies() const { return return_excluded_cookies_; }
|
|
|
+
|
|
|
++ void set_same_party_context(const SamePartyContext& context) {
|
|
|
++ same_party_context_ = context;
|
|
|
++ }
|
|
|
++ const SamePartyContext& same_party_context() const {
|
|
|
++ return same_party_context_;
|
|
|
++ }
|
|
|
++
|
|
|
++ // Getter/setter of |full_party_context_size_| for logging purposes.
|
|
|
++ void set_full_party_context_size(uint32_t len) {
|
|
|
++ full_party_context_size_ = len;
|
|
|
++ }
|
|
|
++ uint32_t full_party_context_size() const { return full_party_context_size_; }
|
|
|
++
|
|
|
++ void set_is_in_nontrivial_first_party_set(bool is_member) {
|
|
|
++ is_in_nontrivial_first_party_set_ = is_member;
|
|
|
++ }
|
|
|
++ bool is_in_nontrivial_first_party_set() const {
|
|
|
++ return is_in_nontrivial_first_party_set_;
|
|
|
++ }
|
|
|
++
|
|
|
+ // Convenience method for where you need a CookieOptions that will
|
|
|
+ // work for getting/setting all types of cookies, including HttpOnly and
|
|
|
+ // SameSite cookies. Also specifies not to update the access time, because
|
|
|
+@@ -281,6 +304,19 @@ class NET_EXPORT CookieOptions {
|
|
|
+ SameSiteCookieContext same_site_cookie_context_;
|
|
|
+ bool update_access_time_ = true;
|
|
|
+ bool return_excluded_cookies_ = false;
|
|
|
++
|
|
|
++ SamePartyContext same_party_context_;
|
|
|
++
|
|
|
++ // The size of the isolation_info.party_context plus the top-frame site.
|
|
|
++ // Stored for logging purposes.
|
|
|
++ uint32_t full_party_context_size_ = 0;
|
|
|
++ // Whether the site requesting cookie access (as opposed to e.g. the
|
|
|
++ // `site_for_cookies`) is a member (or owner) of a nontrivial First-Party
|
|
|
++ // Set.
|
|
|
++ // This is included here temporarily, for the purpose of ignoring SameParty
|
|
|
++ // for sites that are not participating in the Origin Trial.
|
|
|
++ // TODO(https://crbug.com/1163990): remove this field.
|
|
|
++ bool is_in_nontrivial_first_party_set_ = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ NET_EXPORT bool operator==(
|
|
|
+diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
|
|
|
+index 5e4748bf6fc8d06a8207642e1e2a9b3122b3b75e..e2670576d72bfcc2267d8cc9b1865210d8162a4f 100644
|
|
|
+--- a/net/cookies/cookie_util.cc
|
|
|
++++ b/net/cookies/cookie_util.cc
|
|
|
+@@ -32,6 +32,7 @@
|
|
|
+ #include "net/cookies/cookie_monster.h"
|
|
|
+ #include "net/cookies/cookie_options.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_metadata.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "net/http/http_util.h"
|
|
|
+ #include "url/gurl.h"
|
|
|
+ #include "url/url_constants.h"
|
|
|
+@@ -897,13 +898,16 @@ absl::optional<FirstPartySetMetadata> ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ const SchemefulSite& request_site,
|
|
|
+ const IsolationInfo& isolation_info,
|
|
|
+ const CookieAccessDelegate* cookie_access_delegate,
|
|
|
++ bool force_ignore_top_frame_party,
|
|
|
+ base::OnceCallback<void(FirstPartySetMetadata)> callback) {
|
|
|
+ if (isolation_info.party_context().has_value() && cookie_access_delegate) {
|
|
|
+ return cookie_access_delegate->ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ request_site,
|
|
|
+- base::OptionalToPtr(
|
|
|
+- isolation_info.network_isolation_key().GetTopFrameSite()),
|
|
|
+- std::move(callback));
|
|
|
++ force_ignore_top_frame_party
|
|
|
++ ? nullptr
|
|
|
++ : base::OptionalToPtr(
|
|
|
++ isolation_info.network_isolation_key().GetTopFrameSite()),
|
|
|
++ isolation_info.party_context().value(), std::move(callback));
|
|
|
+ }
|
|
|
+
|
|
|
+ return FirstPartySetMetadata();
|
|
|
+@@ -935,6 +939,23 @@ HttpMethodStringToEnum(const std::string& in) {
|
|
|
+ return HttpMethod::kUnknown;
|
|
|
+ }
|
|
|
+
|
|
|
++CookieSamePartyStatus GetSamePartyStatus(
|
|
|
++ const CanonicalCookie& cookie,
|
|
|
++ const CookieOptions& options,
|
|
|
++ const bool same_party_attribute_enabled) {
|
|
|
++ if (!same_party_attribute_enabled || !cookie.IsSameParty() ||
|
|
|
++ !options.is_in_nontrivial_first_party_set()) {
|
|
|
++ return CookieSamePartyStatus::kNoSamePartyEnforcement;
|
|
|
++ }
|
|
|
++
|
|
|
++ switch (options.same_party_context().context_type()) {
|
|
|
++ case SamePartyContext::Type::kCrossParty:
|
|
|
++ return CookieSamePartyStatus::kEnforceSamePartyExclude;
|
|
|
++ case SamePartyContext::Type::kSameParty:
|
|
|
++ return CookieSamePartyStatus::kEnforceSamePartyInclude;
|
|
|
++ };
|
|
|
++}
|
|
|
++
|
|
|
+ bool IsCookieAccessResultInclude(CookieAccessResult cookie_access_result) {
|
|
|
+ return cookie_access_result.status.IsInclude();
|
|
|
+ }
|
|
|
+diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
|
|
|
+index 1ea066648012400453f56dcd437c891439199c2d..1a424e940524830fa396032bc567e0eb4db9d99a 100644
|
|
|
+--- a/net/cookies/cookie_util.h
|
|
|
++++ b/net/cookies/cookie_util.h
|
|
|
+@@ -295,6 +295,7 @@ ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ const SchemefulSite& request_site,
|
|
|
+ const IsolationInfo& isolation_info,
|
|
|
+ const CookieAccessDelegate* cookie_access_delegate,
|
|
|
++ bool force_ignore_top_frame_party,
|
|
|
+ base::OnceCallback<void(FirstPartySetMetadata)> callback);
|
|
|
+
|
|
|
+ // Converts a string representing the http request method to its enum
|
|
|
+@@ -302,6 +303,14 @@ ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ NET_EXPORT CookieOptions::SameSiteCookieContext::ContextMetadata::HttpMethod
|
|
|
+ HttpMethodStringToEnum(const std::string& in);
|
|
|
+
|
|
|
++// Get the SameParty inclusion status. If the cookie is not SameParty, returns
|
|
|
++// kNoSamePartyEnforcement; if the cookie is SameParty but does not have a
|
|
|
++// valid context, returns kEnforceSamePartyExclude.
|
|
|
++NET_EXPORT CookieSamePartyStatus
|
|
|
++GetSamePartyStatus(const CanonicalCookie& cookie,
|
|
|
++ const CookieOptions& options,
|
|
|
++ bool same_party_attribute_enabled);
|
|
|
++
|
|
|
+ // Takes a CookieAccessResult and returns a bool, returning true if the
|
|
|
+ // CookieInclusionStatus in CookieAccessResult was set to "include", else
|
|
|
+ // returning false.
|
|
|
+diff --git a/net/cookies/test_cookie_access_delegate.cc b/net/cookies/test_cookie_access_delegate.cc
|
|
|
+index 1e90c180f9ca510b273a9d35ce4d427423506d33..988a25e98959f7ee65abcdfa59c9064f3966d68e 100644
|
|
|
+--- a/net/cookies/test_cookie_access_delegate.cc
|
|
|
++++ b/net/cookies/test_cookie_access_delegate.cc
|
|
|
+@@ -21,6 +21,7 @@
|
|
|
+ #include "net/cookies/cookie_util.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_entry.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_metadata.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+
|
|
|
+ namespace net {
|
|
|
+
|
|
|
+@@ -62,11 +63,13 @@ absl::optional<FirstPartySetMetadata>
|
|
|
+ TestCookieAccessDelegate::ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ const SchemefulSite& site,
|
|
|
+ const SchemefulSite* top_frame_site,
|
|
|
++ const std::set<SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(FirstPartySetMetadata)> callback) const {
|
|
|
+ absl::optional<FirstPartySetEntry> top_frame_owner =
|
|
|
+ top_frame_site ? FindFirstPartySetEntry(*top_frame_site) : absl::nullopt;
|
|
|
+ return RunMaybeAsync(
|
|
|
+- FirstPartySetMetadata(base::OptionalToPtr(FindFirstPartySetEntry(site)),
|
|
|
++ FirstPartySetMetadata(SamePartyContext(),
|
|
|
++ base::OptionalToPtr(FindFirstPartySetEntry(site)),
|
|
|
+ base::OptionalToPtr(top_frame_owner)),
|
|
|
+ std::move(callback));
|
|
|
+ }
|
|
|
+diff --git a/net/cookies/test_cookie_access_delegate.h b/net/cookies/test_cookie_access_delegate.h
|
|
|
+index 35957aafe9ad0867ab1500cfb49bdbf95eaec4d8..a2324fdf7746b2ef967fd7cbb8ef2704902ad2e9 100644
|
|
|
+--- a/net/cookies/test_cookie_access_delegate.h
|
|
|
++++ b/net/cookies/test_cookie_access_delegate.h
|
|
|
+@@ -43,6 +43,7 @@ class TestCookieAccessDelegate : public CookieAccessDelegate {
|
|
|
+ absl::optional<FirstPartySetMetadata> ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ const SchemefulSite& site,
|
|
|
+ const SchemefulSite* top_frame_site,
|
|
|
++ const std::set<SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(FirstPartySetMetadata)> callback) const override;
|
|
|
+ absl::optional<base::flat_map<SchemefulSite, FirstPartySetEntry>>
|
|
|
+ FindFirstPartySetEntries(
|
|
|
+diff --git a/net/first_party_sets/first_party_set_metadata.cc b/net/first_party_sets/first_party_set_metadata.cc
|
|
|
+index 75f41ad79ac067f806d4bea8b687a4781778e37a..26521fa5f9b4a93f892212cbd45e77ce41fc0f29 100644
|
|
|
+--- a/net/first_party_sets/first_party_set_metadata.cc
|
|
|
++++ b/net/first_party_sets/first_party_set_metadata.cc
|
|
|
+@@ -13,9 +13,11 @@ namespace net {
|
|
|
+
|
|
|
+ FirstPartySetMetadata::FirstPartySetMetadata() = default;
|
|
|
+ FirstPartySetMetadata::FirstPartySetMetadata(
|
|
|
++ const SamePartyContext& context,
|
|
|
+ const FirstPartySetEntry* frame_entry,
|
|
|
+ const FirstPartySetEntry* top_frame_entry)
|
|
|
+- : frame_entry_(base::OptionalFromPtr(frame_entry)),
|
|
|
++ : context_(context),
|
|
|
++ frame_entry_(base::OptionalFromPtr(frame_entry)),
|
|
|
+ top_frame_entry_(base::OptionalFromPtr(top_frame_entry)) {}
|
|
|
+
|
|
|
+ FirstPartySetMetadata::FirstPartySetMetadata(FirstPartySetMetadata&&) = default;
|
|
|
+@@ -26,8 +28,8 @@ FirstPartySetMetadata::~FirstPartySetMetadata() = default;
|
|
|
+
|
|
|
+ bool FirstPartySetMetadata::operator==(
|
|
|
+ const FirstPartySetMetadata& other) const {
|
|
|
+- return std::tie(frame_entry_, top_frame_entry_) ==
|
|
|
+- std::tie(other.frame_entry_, other.top_frame_entry_);
|
|
|
++ return std::tie(context_, frame_entry_, top_frame_entry_) ==
|
|
|
++ std::tie(other.context_, other.frame_entry_, other.top_frame_entry_);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool FirstPartySetMetadata::operator!=(
|
|
|
+@@ -37,7 +39,8 @@ bool FirstPartySetMetadata::operator!=(
|
|
|
+
|
|
|
+ std::ostream& operator<<(std::ostream& os,
|
|
|
+ const FirstPartySetMetadata& metadata) {
|
|
|
+- os << "{" << base::OptionalToPtr(metadata.frame_entry()) << ", "
|
|
|
++ os << "{" << metadata.context() << ", "
|
|
|
++ << base::OptionalToPtr(metadata.frame_entry()) << ", "
|
|
|
+ << base::OptionalToPtr(metadata.top_frame_entry()) << "}";
|
|
|
+ return os;
|
|
|
+ }
|
|
|
+diff --git a/net/first_party_sets/first_party_set_metadata.h b/net/first_party_sets/first_party_set_metadata.h
|
|
|
+index b23e52575bc2ae0634075890782eb46716116217..77cf13c75599522be3efda658b8685b21532c41c 100644
|
|
|
+--- a/net/first_party_sets/first_party_set_metadata.h
|
|
|
++++ b/net/first_party_sets/first_party_set_metadata.h
|
|
|
+@@ -7,6 +7,7 @@
|
|
|
+
|
|
|
+ #include "net/base/net_export.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_entry.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
+
|
|
|
+ namespace net {
|
|
|
+@@ -20,7 +21,8 @@ class NET_EXPORT FirstPartySetMetadata {
|
|
|
+ // `frame_entry` and `top_frame_entry` must live for the duration of the ctor;
|
|
|
+ // nullptr indicates that there's no First-Party Set that's associated with
|
|
|
+ // the current frame or the top frame, respectively, in the given context.
|
|
|
+- FirstPartySetMetadata(const FirstPartySetEntry* frame_entry,
|
|
|
++ FirstPartySetMetadata(const SamePartyContext& context,
|
|
|
++ const FirstPartySetEntry* frame_entry,
|
|
|
+ const FirstPartySetEntry* top_frame_entry);
|
|
|
+
|
|
|
+ FirstPartySetMetadata(FirstPartySetMetadata&&);
|
|
|
+@@ -31,6 +33,10 @@ class NET_EXPORT FirstPartySetMetadata {
|
|
|
+ bool operator==(const FirstPartySetMetadata& other) const;
|
|
|
+ bool operator!=(const FirstPartySetMetadata& other) const;
|
|
|
+
|
|
|
++ const SamePartyContext& context() const { return context_; }
|
|
|
++
|
|
|
++ // Returns a optional<T>& instead of a T* so that operator== can be defined
|
|
|
++ // more easily.
|
|
|
+ const absl::optional<FirstPartySetEntry>& frame_entry() const {
|
|
|
+ return frame_entry_;
|
|
|
+ }
|
|
|
+@@ -43,6 +49,7 @@ class NET_EXPORT FirstPartySetMetadata {
|
|
|
+ bool AreSitesInSameFirstPartySet() const;
|
|
|
+
|
|
|
+ private:
|
|
|
++ SamePartyContext context_ = SamePartyContext();
|
|
|
+ absl::optional<FirstPartySetEntry> frame_entry_ = absl::nullopt;
|
|
|
+ absl::optional<FirstPartySetEntry> top_frame_entry_ = absl::nullopt;
|
|
|
+ };
|
|
|
+diff --git a/net/first_party_sets/global_first_party_sets.cc b/net/first_party_sets/global_first_party_sets.cc
|
|
|
+index 29d34cd442ae19006d399b09b766c19dd5b12c76..ae2845f897ee9eb23f4888871b07edf28b62234c 100644
|
|
|
+--- a/net/first_party_sets/global_first_party_sets.cc
|
|
|
++++ b/net/first_party_sets/global_first_party_sets.cc
|
|
|
+@@ -28,6 +28,13 @@ namespace {
|
|
|
+ using FlattenedSets = base::flat_map<SchemefulSite, FirstPartySetEntry>;
|
|
|
+ using SingleSet = base::flat_map<SchemefulSite, FirstPartySetEntry>;
|
|
|
+
|
|
|
++// Converts WS to HTTP, and WSS to HTTPS.
|
|
|
++SchemefulSite NormalizeScheme(const SchemefulSite& site) {
|
|
|
++ SchemefulSite normalized_site = site;
|
|
|
++ normalized_site.ConvertWebSocketToHttp();
|
|
|
++ return normalized_site;
|
|
|
++}
|
|
|
++
|
|
|
+ // Converts a list of First-Party Sets from a SingleSet to a FlattenedSet
|
|
|
+ // representation.
|
|
|
+ FlattenedSets SetListToFlattenedSets(const std::vector<SingleSet>& set_list) {
|
|
|
+@@ -59,6 +66,11 @@ const SchemefulSite& ProjectKey(
|
|
|
+ return p.first;
|
|
|
+ }
|
|
|
+
|
|
|
++SamePartyContext::Type ContextTypeFromBool(bool is_same_party) {
|
|
|
++ return is_same_party ? SamePartyContext::Type::kSameParty
|
|
|
++ : SamePartyContext::Type::kCrossParty;
|
|
|
++}
|
|
|
++
|
|
|
+ } // namespace
|
|
|
+
|
|
|
+ GlobalFirstPartySets::GlobalFirstPartySets() = default;
|
|
|
+@@ -126,9 +138,11 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
|
+ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
|
+ const SchemefulSite& site,
|
|
|
+ const FirstPartySetsContextConfig* config) const {
|
|
|
+- // Check if `site` can be found in the customizations first.
|
|
|
++ const SchemefulSite normalized_site = NormalizeScheme(site);
|
|
|
++
|
|
|
++ // Check if `normalized_site` can be found in the customizations first.
|
|
|
+ if (config) {
|
|
|
+- if (const auto override = config->FindOverride(site);
|
|
|
++ if (const auto override = config->FindOverride(normalized_site);
|
|
|
+ override.has_value()) {
|
|
|
+ return override->IsDeletion() ? absl::nullopt
|
|
|
+ : absl::make_optional(override->GetEntry());
|
|
|
+@@ -136,7 +150,7 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now see if it's in the manual config (with or without a manual alias).
|
|
|
+- if (const auto manual_override = manual_config_.FindOverride(site);
|
|
|
++ if (const auto manual_override = manual_config_.FindOverride(normalized_site);
|
|
|
+ manual_override.has_value()) {
|
|
|
+ return manual_override->IsDeletion()
|
|
|
+ ? absl::nullopt
|
|
|
+@@ -144,9 +158,9 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
|
+ }
|
|
|
+
|
|
|
+ // Finally, look up in `entries_`, applying an alias if applicable.
|
|
|
+- const auto canonical_it = aliases_.find(site);
|
|
|
++ const auto canonical_it = aliases_.find(normalized_site);
|
|
|
+ const SchemefulSite& canonical_site =
|
|
|
+- canonical_it == aliases_.end() ? site : canonical_it->second;
|
|
|
++ canonical_it == aliases_.end() ? normalized_site : canonical_it->second;
|
|
|
+ if (const auto entry_it = entries_.find(canonical_site);
|
|
|
+ entry_it != entries_.end()) {
|
|
|
+ return entry_it->second;
|
|
|
+@@ -172,16 +186,50 @@ GlobalFirstPartySets::FindEntries(
|
|
|
+ FirstPartySetMetadata GlobalFirstPartySets::ComputeMetadata(
|
|
|
+ const SchemefulSite& site,
|
|
|
+ const SchemefulSite* top_frame_site,
|
|
|
++ const std::set<SchemefulSite>& party_context,
|
|
|
+ const FirstPartySetsContextConfig& fps_context_config) const {
|
|
|
++ const base::ElapsedTimer timer;
|
|
|
++
|
|
|
++ SamePartyContext::Type context_type =
|
|
|
++ ContextTypeFromBool(IsContextSamePartyWithSite(
|
|
|
++ site, top_frame_site, party_context, fps_context_config));
|
|
|
++
|
|
|
++ SamePartyContext context(context_type);
|
|
|
++
|
|
|
+ absl::optional<FirstPartySetEntry> top_frame_entry =
|
|
|
+ top_frame_site ? FindEntry(*top_frame_site, fps_context_config)
|
|
|
+ : absl::nullopt;
|
|
|
+
|
|
|
+ return FirstPartySetMetadata(
|
|
|
+- base::OptionalToPtr(FindEntry(site, fps_context_config)),
|
|
|
++ context, base::OptionalToPtr(FindEntry(site, fps_context_config)),
|
|
|
+ base::OptionalToPtr(top_frame_entry));
|
|
|
+ }
|
|
|
+
|
|
|
++bool GlobalFirstPartySets::IsContextSamePartyWithSite(
|
|
|
++ const SchemefulSite& site,
|
|
|
++ const SchemefulSite* top_frame_site,
|
|
|
++ const std::set<SchemefulSite>& party_context,
|
|
|
++ const FirstPartySetsContextConfig& fps_context_config) const {
|
|
|
++ const absl::optional<FirstPartySetEntry> site_entry =
|
|
|
++ FindEntry(site, fps_context_config);
|
|
|
++ if (!site_entry.has_value())
|
|
|
++ return false;
|
|
|
++
|
|
|
++ const auto is_in_same_set_as_frame_site =
|
|
|
++ [this, &site_entry,
|
|
|
++ &fps_context_config](const SchemefulSite& context_site) -> bool {
|
|
|
++ const absl::optional<FirstPartySetEntry> context_entry =
|
|
|
++ FindEntry(context_site, fps_context_config);
|
|
|
++ return context_entry.has_value() &&
|
|
|
++ context_entry->primary() == site_entry->primary();
|
|
|
++ };
|
|
|
++
|
|
|
++ if (top_frame_site && !is_in_same_set_as_frame_site(*top_frame_site))
|
|
|
++ return false;
|
|
|
++
|
|
|
++ return base::ranges::all_of(party_context, is_in_same_set_as_frame_site);
|
|
|
++}
|
|
|
++
|
|
|
+ void GlobalFirstPartySets::ApplyManuallySpecifiedSet(
|
|
|
+ const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries) {
|
|
|
+ CHECK(manual_config_.empty());
|
|
|
+diff --git a/net/first_party_sets/global_first_party_sets.h b/net/first_party_sets/global_first_party_sets.h
|
|
|
+index f4f4e99189e0f3b8accfa884e136a127d0128bab..dc12d5fc440cecf291931cef98256b5f7ac58886 100644
|
|
|
+--- a/net/first_party_sets/global_first_party_sets.h
|
|
|
++++ b/net/first_party_sets/global_first_party_sets.h
|
|
|
+@@ -10,6 +10,8 @@
|
|
|
+ #include "base/containers/flat_map.h"
|
|
|
+ #include "base/containers/flat_set.h"
|
|
|
+ #include "base/functional/function_ref.h"
|
|
|
++#include "base/time/time.h"
|
|
|
++#include "base/timer/elapsed_timer.h"
|
|
|
+ #include "base/version.h"
|
|
|
+ #include "net/base/net_export.h"
|
|
|
+ #include "net/base/schemeful_site.h"
|
|
|
+@@ -83,6 +85,7 @@ class NET_EXPORT GlobalFirstPartySets {
|
|
|
+ FirstPartySetMetadata ComputeMetadata(
|
|
|
+ const SchemefulSite& site,
|
|
|
+ const SchemefulSite* top_frame_site,
|
|
|
++ const std::set<SchemefulSite>& party_context,
|
|
|
+ const FirstPartySetsContextConfig& fps_context_config) const;
|
|
|
+
|
|
|
+ // Modifies this instance such that it will respect the given
|
|
|
+@@ -166,6 +169,12 @@ class NET_EXPORT GlobalFirstPartySets {
|
|
|
+ const std::vector<base::flat_map<SchemefulSite, FirstPartySetEntry>>&
|
|
|
+ addition_sets) const;
|
|
|
+
|
|
|
++ bool IsContextSamePartyWithSite(
|
|
|
++ const SchemefulSite& site,
|
|
|
++ const SchemefulSite* top_frame_site,
|
|
|
++ const std::set<SchemefulSite>& party_context,
|
|
|
++ const FirstPartySetsContextConfig& fps_context_config) const;
|
|
|
++
|
|
|
+ // Same as the public version of ForEachEffectiveSetEntry, but is allowed to
|
|
|
+ // omit the `config` argument (i.e. pass nullptr instead of a reference).
|
|
|
+ bool ForEachEffectiveSetEntry(
|
|
|
+diff --git a/net/first_party_sets/same_party_context.cc b/net/first_party_sets/same_party_context.cc
|
|
|
+new file mode 100644
|
|
|
+index 0000000000000000000000000000000000000000..afa9ddf645cc8776d7c9303da9d93725b945a5d7
|
|
|
+--- /dev/null
|
|
|
++++ b/net/first_party_sets/same_party_context.cc
|
|
|
+@@ -0,0 +1,28 @@
|
|
|
++// Copyright 2021 The Chromium Authors
|
|
|
++// Use of this source code is governed by a BSD-style license that can be
|
|
|
++// found in the LICENSE file.
|
|
|
++
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
++
|
|
|
++#include <ostream>
|
|
|
++
|
|
|
++namespace net {
|
|
|
++
|
|
|
++SamePartyContext::SamePartyContext(Type context_type)
|
|
|
++ : context_type_(context_type) {}
|
|
|
++
|
|
|
++bool SamePartyContext::operator==(const SamePartyContext& other) const {
|
|
|
++ return context_type_ == other.context_type_;
|
|
|
++}
|
|
|
++
|
|
|
++std::ostream& operator<<(std::ostream& os, const SamePartyContext& spc) {
|
|
|
++ os << "{" << static_cast<int>(spc.context_type()) << "}";
|
|
|
++ return os;
|
|
|
++}
|
|
|
++
|
|
|
++// static
|
|
|
++SamePartyContext SamePartyContext::MakeInclusive() {
|
|
|
++ return SamePartyContext(Type::kSameParty);
|
|
|
++}
|
|
|
++
|
|
|
++} // namespace net
|
|
|
+diff --git a/net/first_party_sets/same_party_context.h b/net/first_party_sets/same_party_context.h
|
|
|
+new file mode 100644
|
|
|
+index 0000000000000000000000000000000000000000..448f000d8ab368f071d73da887e0e857c33e8973
|
|
|
+--- /dev/null
|
|
|
++++ b/net/first_party_sets/same_party_context.h
|
|
|
+@@ -0,0 +1,51 @@
|
|
|
++// Copyright 2021 The Chromium Authors
|
|
|
++// Use of this source code is governed by a BSD-style license that can be
|
|
|
++// found in the LICENSE file.
|
|
|
++
|
|
|
++#ifndef NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
|
|
|
++#define NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
|
|
|
++
|
|
|
++#include <ostream>
|
|
|
++
|
|
|
++#include "net/base/net_export.h"
|
|
|
++
|
|
|
++namespace net {
|
|
|
++
|
|
|
++// This struct bundles together a few different notions of same-party-ness.
|
|
|
++// `context_type()` gives the notion of same-party-ness that Chromium should use
|
|
|
++// in all cases except metrics; other accessors are just for metrics purposes,
|
|
|
++// to explore the impact of different definitions of "same-party".
|
|
|
++class NET_EXPORT SamePartyContext {
|
|
|
++ public:
|
|
|
++ // Computed for every cookie access attempt but is only relevant for SameParty
|
|
|
++ // cookies.
|
|
|
++ enum class Type {
|
|
|
++ // The opposite to kSameParty. Should be the default value.
|
|
|
++ kCrossParty = 0,
|
|
|
++ // If the request URL is in the same First-Party Sets as the top-frame site
|
|
|
++ // and each member of the isolation_info.party_context.
|
|
|
++ kSameParty = 1,
|
|
|
++ };
|
|
|
++
|
|
|
++ SamePartyContext() = default;
|
|
|
++ explicit SamePartyContext(Type context_type);
|
|
|
++
|
|
|
++ bool operator==(const SamePartyContext& other) const;
|
|
|
++
|
|
|
++ // How trusted is the current browser environment when it comes to accessing
|
|
|
++ // SameParty cookies. Default is not trusted, e.g. kCrossParty.
|
|
|
++ Type context_type() const { return context_type_; }
|
|
|
++
|
|
|
++ // Creates a SamePartyContext that is as permissive as possible.
|
|
|
++ static SamePartyContext MakeInclusive();
|
|
|
++
|
|
|
++ private:
|
|
|
++ Type context_type_ = Type::kCrossParty;
|
|
|
++};
|
|
|
++
|
|
|
++NET_EXPORT std::ostream& operator<<(std::ostream& os,
|
|
|
++ const SamePartyContext& spc);
|
|
|
++
|
|
|
++} // namespace net
|
|
|
++
|
|
|
++#endif // NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
|
|
|
+diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
|
|
|
+index 3c9516b7d80c09d97ce014859f15a0b4a2c634cc..88838c902460eec1aa45e558c8c04f5b9e6059cf 100644
|
|
|
+--- a/net/url_request/url_request.h
|
|
|
++++ b/net/url_request/url_request.h
|
|
|
+@@ -315,6 +315,16 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
|
|
|
+ force_ignore_site_for_cookies_ = attach;
|
|
|
+ }
|
|
|
+
|
|
|
++ // Indicates whether the top frame party will be considered same-party to the
|
|
|
++ // request URL (regardless of what it is), for the purpose of SameParty
|
|
|
++ // cookies.
|
|
|
++ bool force_ignore_top_frame_party_for_cookies() const {
|
|
|
++ return force_ignore_top_frame_party_for_cookies_;
|
|
|
++ }
|
|
|
++ void set_force_ignore_top_frame_party_for_cookies(bool force) {
|
|
|
++ force_ignore_top_frame_party_for_cookies_ = force;
|
|
|
++ }
|
|
|
++
|
|
|
+ // Indicates if the request should be treated as a main frame navigation for
|
|
|
+ // SameSite cookie computations. This flag overrides the IsolationInfo
|
|
|
+ // request type associated with fetches from a service worker context.
|
|
|
+@@ -961,6 +971,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
|
|
|
+ absl::optional<CookiePartitionKey> cookie_partition_key_ = absl::nullopt;
|
|
|
+
|
|
|
+ bool force_ignore_site_for_cookies_ = false;
|
|
|
++ bool force_ignore_top_frame_party_for_cookies_ = false;
|
|
|
+ bool force_main_frame_for_same_site_cookies_ = false;
|
|
|
+ CookieSettingOverrides cookie_setting_overrides_;
|
|
|
+
|
|
|
+diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
|
|
|
+index eac944172789c28deda9e86e880d31d7e0dae1cf..f25f62a4ab8f826d5d1a4b25d8593f0a18428073 100644
|
|
|
+--- a/net/url_request/url_request_http_job.cc
|
|
|
++++ b/net/url_request/url_request_http_job.cc
|
|
|
+@@ -63,6 +63,7 @@
|
|
|
+ #include "net/filter/zstd_source_stream.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_entry.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_metadata.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "net/http/http_content_disposition.h"
|
|
|
+ #include "net/http/http_log_util.h"
|
|
|
+ #include "net/http/http_network_session.h"
|
|
|
+@@ -165,11 +166,22 @@ void LogTrustAnchor(const net::HashValueVector& spki_hashes) {
|
|
|
+ }
|
|
|
+
|
|
|
+ net::CookieOptions CreateCookieOptions(
|
|
|
+- net::CookieOptions::SameSiteCookieContext same_site_context) {
|
|
|
++ net::CookieOptions::SameSiteCookieContext same_site_context,
|
|
|
++ const net::SamePartyContext& same_party_context,
|
|
|
++ const net::IsolationInfo& isolation_info,
|
|
|
++ bool is_in_nontrivial_first_party_set) {
|
|
|
+ net::CookieOptions options;
|
|
|
+ options.set_return_excluded_cookies();
|
|
|
+ options.set_include_httponly();
|
|
|
+ options.set_same_site_cookie_context(same_site_context);
|
|
|
++ options.set_same_party_context(same_party_context);
|
|
|
++ if (isolation_info.party_context().has_value()) {
|
|
|
++ // Count the top-frame site since it's not in the party_context.
|
|
|
++ options.set_full_party_context_size(isolation_info.party_context()->size() +
|
|
|
++ 1);
|
|
|
++ }
|
|
|
++ options.set_is_in_nontrivial_first_party_set(
|
|
|
++ is_in_nontrivial_first_party_set);
|
|
|
+ return options;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -322,6 +334,7 @@ void URLRequestHttpJob::Start() {
|
|
|
+ cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ SchemefulSite(request()->url()), request()->isolation_info(),
|
|
|
+ request()->context()->cookie_store()->cookie_access_delegate(),
|
|
|
++ request()->force_ignore_top_frame_party_for_cookies(),
|
|
|
+ base::BindOnce(&URLRequestHttpJob::OnGotFirstPartySetMetadata,
|
|
|
+ weak_factory_.GetWeakPtr()));
|
|
|
+
|
|
|
+@@ -684,7 +697,11 @@ void URLRequestHttpJob::AddCookieHeaderAndStart() {
|
|
|
+ request_->site_for_cookies(), request_->initiator(),
|
|
|
+ is_main_frame_navigation, force_ignore_site_for_cookies);
|
|
|
+
|
|
|
+- CookieOptions options = CreateCookieOptions(same_site_context);
|
|
|
++ bool is_in_nontrivial_first_party_set =
|
|
|
++ first_party_set_metadata_.frame_entry().has_value();
|
|
|
++ CookieOptions options = CreateCookieOptions(
|
|
|
++ same_site_context, first_party_set_metadata_.context(),
|
|
|
++ request_->isolation_info(), is_in_nontrivial_first_party_set);
|
|
|
+
|
|
|
+ cookie_store->GetCookieListWithOptionsAsync(
|
|
|
+ request_->url(), options,
|
|
|
+@@ -937,7 +954,11 @@ void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
|
|
|
+ request_->initiator(), is_main_frame_navigation,
|
|
|
+ force_ignore_site_for_cookies);
|
|
|
+
|
|
|
+- CookieOptions options = CreateCookieOptions(same_site_context);
|
|
|
++ bool is_in_nontrivial_first_party_set =
|
|
|
++ first_party_set_metadata_.frame_entry().has_value();
|
|
|
++ CookieOptions options = CreateCookieOptions(
|
|
|
++ same_site_context, first_party_set_metadata_.context(),
|
|
|
++ request_->isolation_info(), is_in_nontrivial_first_party_set);
|
|
|
+
|
|
|
+ // Set all cookies, without waiting for them to be set. Any subsequent
|
|
|
+ // read will see the combined result of all cookie operation.
|
|
|
+diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc
|
|
|
+index cd44f7ecda273880f148577648dee0380381beb9..ab310b74a255834f558828d1ba4a830f09ccebcf 100644
|
|
|
+--- a/services/network/cookie_access_delegate_impl.cc
|
|
|
++++ b/services/network/cookie_access_delegate_impl.cc
|
|
|
+@@ -64,11 +64,12 @@ absl::optional<net::FirstPartySetMetadata>
|
|
|
+ CookieAccessDelegateImpl::ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
|
+ if (!first_party_sets_access_delegate_)
|
|
|
+ return {net::FirstPartySetMetadata()};
|
|
|
+ return first_party_sets_access_delegate_->ComputeMetadata(
|
|
|
+- site, top_frame_site, std::move(callback));
|
|
|
++ site, top_frame_site, party_context, std::move(callback));
|
|
|
+ }
|
|
|
+
|
|
|
+ absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
|
|
|
+diff --git a/services/network/cookie_access_delegate_impl.h b/services/network/cookie_access_delegate_impl.h
|
|
|
+index 4ef1746b383cfbf7ad007cb6ae7e331408ab75fe..50c3a309db86e5f044e2bfc429ca82fc6586d084 100644
|
|
|
+--- a/services/network/cookie_access_delegate_impl.h
|
|
|
++++ b/services/network/cookie_access_delegate_impl.h
|
|
|
+@@ -5,7 +5,10 @@
|
|
|
+ #ifndef SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
|
|
|
+ #define SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
|
|
|
+
|
|
|
++#include <set>
|
|
|
++
|
|
|
+ #include "base/component_export.h"
|
|
|
++#include "base/containers/flat_map.h"
|
|
|
+ #include "base/containers/flat_set.h"
|
|
|
+ #include "base/functional/callback_forward.h"
|
|
|
+ #include "base/memory/raw_ptr.h"
|
|
|
+@@ -56,6 +59,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CookieAccessDelegateImpl
|
|
|
+ ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback)
|
|
|
+ const override;
|
|
|
+ [[nodiscard]] absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
|
|
|
+diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.cc b/services/network/first_party_sets/first_party_sets_access_delegate.cc
|
|
|
+index 08120524ead3ca40a8a167bf8d9991af871426df..9f2e736f056bf2d2b8c04264be6052fabc769d26 100644
|
|
|
+--- a/services/network/first_party_sets/first_party_sets_access_delegate.cc
|
|
|
++++ b/services/network/first_party_sets/first_party_sets_access_delegate.cc
|
|
|
+@@ -69,6 +69,7 @@ absl::optional<net::FirstPartySetMetadata>
|
|
|
+ FirstPartySetsAccessDelegate::ComputeMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+
|
|
|
+@@ -85,12 +86,12 @@ FirstPartySetsAccessDelegate::ComputeMetadata(
|
|
|
+ EnqueuePendingQuery(base::BindOnce(
|
|
|
+ &FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke,
|
|
|
+ base::Unretained(this), site, base::OptionalFromPtr(top_frame_site),
|
|
|
+- std::move(callback)));
|
|
|
++ party_context, std::move(callback)));
|
|
|
+ return absl::nullopt;
|
|
|
+ }
|
|
|
+
|
|
|
+- return manager_->ComputeMetadata(site, top_frame_site, *context_config(),
|
|
|
+- std::move(callback));
|
|
|
++ return manager_->ComputeMetadata(site, top_frame_site, party_context,
|
|
|
++ *context_config(), std::move(callback));
|
|
|
+ }
|
|
|
+
|
|
|
+ absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
|
|
|
+@@ -148,6 +149,7 @@ FirstPartySetsAccessDelegate::GetCacheFilterMatchInfo(
|
|
|
+ void FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite> top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+ CHECK(context_config());
|
|
|
+@@ -162,7 +164,8 @@ void FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke(
|
|
|
+
|
|
|
+ absl::optional<net::FirstPartySetMetadata> sync_result =
|
|
|
+ manager_->ComputeMetadata(site, base::OptionalToPtr(top_frame_site),
|
|
|
+- *context_config(), std::move(callbacks.first));
|
|
|
++ party_context, *context_config(),
|
|
|
++ std::move(callbacks.first));
|
|
|
+
|
|
|
+ if (sync_result.has_value())
|
|
|
+ std::move(callbacks.second).Run(std::move(sync_result.value()));
|
|
|
+diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.h b/services/network/first_party_sets/first_party_sets_access_delegate.h
|
|
|
+index cb2399650853758378306ffe34ae14688ca06f72..67df37ef7dfc344bff9bb569fdc58c29967aeb22 100644
|
|
|
+--- a/services/network/first_party_sets/first_party_sets_access_delegate.h
|
|
|
++++ b/services/network/first_party_sets/first_party_sets_access_delegate.h
|
|
|
+@@ -62,6 +62,7 @@ class FirstPartySetsAccessDelegate
|
|
|
+ [[nodiscard]] absl::optional<net::FirstPartySetMetadata> ComputeMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
|
|
|
+
|
|
|
+ // Calls FirstPartySetsManager::FindEntries either asynchronously or
|
|
|
+@@ -91,6 +92,7 @@ class FirstPartySetsAccessDelegate
|
|
|
+ void ComputeMetadataAndInvoke(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite> top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
|
|
|
+
|
|
|
+ // Same as `FindEntries`, but plumbs the result into the callback. Must only
|
|
|
+diff --git a/services/network/first_party_sets/first_party_sets_manager.cc b/services/network/first_party_sets/first_party_sets_manager.cc
|
|
|
+index 68306f7e32db4455366be68e8dd6434797bc6e3e..d89cd3f6fd38a17f9aa7d09d168496518b1e716a 100644
|
|
|
+--- a/services/network/first_party_sets/first_party_sets_manager.cc
|
|
|
++++ b/services/network/first_party_sets/first_party_sets_manager.cc
|
|
|
+@@ -15,6 +15,7 @@
|
|
|
+ #include "base/feature_list.h"
|
|
|
+ #include "base/metrics/histogram_functions.h"
|
|
|
+ #include "base/metrics/histogram_macros.h"
|
|
|
++#include "base/ranges/algorithm.h"
|
|
|
+ #include "base/sequence_checker.h"
|
|
|
+ #include "base/time/time.h"
|
|
|
+ #include "base/timer/elapsed_timer.h"
|
|
|
+@@ -24,6 +25,7 @@
|
|
|
+ #include "net/first_party_sets/first_party_set_entry.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_metadata.h"
|
|
|
+ #include "net/first_party_sets/global_first_party_sets.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
+
|
|
|
+ namespace network {
|
|
|
+@@ -48,6 +50,7 @@ absl::optional<net::FirstPartySetMetadata>
|
|
|
+ FirstPartySetsManager::ComputeMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& fps_context_config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+@@ -59,16 +62,19 @@ FirstPartySetsManager::ComputeMetadata(
|
|
|
+ EnqueuePendingQuery(base::BindOnce(
|
|
|
+ &FirstPartySetsManager::ComputeMetadataAndInvoke,
|
|
|
+ weak_factory_.GetWeakPtr(), site, base::OptionalFromPtr(top_frame_site),
|
|
|
+- fps_context_config.Clone(), std::move(callback), base::ElapsedTimer()));
|
|
|
++ party_context, fps_context_config.Clone(), std::move(callback),
|
|
|
++ base::ElapsedTimer()));
|
|
|
+ return absl::nullopt;
|
|
|
+ }
|
|
|
+
|
|
|
+- return ComputeMetadataInternal(site, top_frame_site, fps_context_config);
|
|
|
++ return ComputeMetadataInternal(site, top_frame_site, party_context,
|
|
|
++ fps_context_config);
|
|
|
+ }
|
|
|
+
|
|
|
+ void FirstPartySetsManager::ComputeMetadataAndInvoke(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite> top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& fps_context_config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback,
|
|
|
+ base::ElapsedTimer timer) const {
|
|
|
+@@ -78,18 +84,21 @@ void FirstPartySetsManager::ComputeMetadataAndInvoke(
|
|
|
+ UMA_HISTOGRAM_TIMES("Cookie.FirstPartySets.EnqueueingDelay.ComputeMetadata2",
|
|
|
+ timer.Elapsed());
|
|
|
+
|
|
|
+- std::move(callback).Run(ComputeMetadataInternal(
|
|
|
+- site, base::OptionalToPtr(top_frame_site), fps_context_config));
|
|
|
++ std::move(callback).Run(
|
|
|
++ ComputeMetadataInternal(site, base::OptionalToPtr(top_frame_site),
|
|
|
++ party_context, fps_context_config));
|
|
|
+ }
|
|
|
+
|
|
|
+ net::FirstPartySetMetadata FirstPartySetsManager::ComputeMetadataInternal(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& fps_context_config) const {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+ CHECK(sets_.has_value());
|
|
|
+
|
|
|
+- return sets_->ComputeMetadata(site, top_frame_site, fps_context_config);
|
|
|
++ return sets_->ComputeMetadata(site, top_frame_site, party_context,
|
|
|
++ fps_context_config);
|
|
|
+ }
|
|
|
+
|
|
|
+ absl::optional<net::FirstPartySetEntry> FirstPartySetsManager::FindEntry(
|
|
|
+diff --git a/services/network/first_party_sets/first_party_sets_manager.h b/services/network/first_party_sets/first_party_sets_manager.h
|
|
|
+index 9754dd5f6b0087c6630285b1f592e43cda4ba8d6..b04a98f42fc96a5f2e85cd1bc8ea841fb170e4f2 100644
|
|
|
+--- a/services/network/first_party_sets/first_party_sets_manager.h
|
|
|
++++ b/services/network/first_party_sets/first_party_sets_manager.h
|
|
|
+@@ -15,6 +15,7 @@
|
|
|
+ #include "base/functional/callback.h"
|
|
|
+ #include "base/sequence_checker.h"
|
|
|
+ #include "base/thread_annotations.h"
|
|
|
++#include "base/time/time.h"
|
|
|
+ #include "base/timer/elapsed_timer.h"
|
|
|
+ #include "net/base/schemeful_site.h"
|
|
|
+ #include "net/first_party_sets/first_party_set_entry.h"
|
|
|
+@@ -52,6 +53,7 @@ class FirstPartySetsManager {
|
|
|
+ [[nodiscard]] absl::optional<net::FirstPartySetMetadata> ComputeMetadata(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& fps_context_config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
|
|
|
+
|
|
|
+@@ -84,6 +86,7 @@ class FirstPartySetsManager {
|
|
|
+ void ComputeMetadataAndInvoke(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const absl::optional<net::SchemefulSite> top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& fps_context_config,
|
|
|
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback,
|
|
|
+ base::ElapsedTimer timer) const;
|
|
|
+@@ -93,6 +96,7 @@ class FirstPartySetsManager {
|
|
|
+ net::FirstPartySetMetadata ComputeMetadataInternal(
|
|
|
+ const net::SchemefulSite& site,
|
|
|
+ const net::SchemefulSite* top_frame_site,
|
|
|
++ const std::set<net::SchemefulSite>& party_context,
|
|
|
+ const net::FirstPartySetsContextConfig& fps_context_config) const;
|
|
|
+
|
|
|
+ // Returns `site`'s entry, or `nullopt` if `site` has no entry.
|
|
|
+diff --git a/services/network/network_service_network_delegate.cc b/services/network/network_service_network_delegate.cc
|
|
|
+index d8133af94ca8dc20974e8e6600933ce115106530..80acabb2b079a48cab2a76f8e1faad1db7e7710e 100644
|
|
|
+--- a/services/network/network_service_network_delegate.cc
|
|
|
++++ b/services/network/network_service_network_delegate.cc
|
|
|
+@@ -18,6 +18,7 @@
|
|
|
+ #include "net/base/load_flags.h"
|
|
|
+ #include "net/base/net_errors.h"
|
|
|
+ #include "net/cookies/cookie_setting_override.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "net/url_request/clear_site_data.h"
|
|
|
+ #include "net/url_request/referrer_policy.h"
|
|
|
+ #include "net/url_request/url_request.h"
|
|
|
+diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.cc b/services/network/public/cpp/cookie_manager_mojom_traits.cc
|
|
|
+index 5269c91580bc8d9cf93c3323f7b96ac748cd5972..2505b01a13c62f49ce73a539d5d452ea6ae340bd 100644
|
|
|
+--- a/services/network/public/cpp/cookie_manager_mojom_traits.cc
|
|
|
++++ b/services/network/public/cpp/cookie_manager_mojom_traits.cc
|
|
|
+@@ -586,6 +586,17 @@ bool StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions>::
|
|
|
+ else
|
|
|
+ cookie_options->unset_return_excluded_cookies();
|
|
|
+
|
|
|
++ net::SamePartyContext same_party_context;
|
|
|
++ if (!mojo_options.ReadSamePartyContext(&same_party_context))
|
|
|
++ return false;
|
|
|
++ cookie_options->set_same_party_context(same_party_context);
|
|
|
++
|
|
|
++ cookie_options->set_full_party_context_size(
|
|
|
++ mojo_options.full_party_context_size());
|
|
|
++
|
|
|
++ cookie_options->set_is_in_nontrivial_first_party_set(
|
|
|
++ mojo_options.is_in_nontrivial_first_party_set());
|
|
|
++
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.h b/services/network/public/cpp/cookie_manager_mojom_traits.h
|
|
|
+index 5531222e359de032cb45b28e3451b5622a731069..d562b702b0f5a87017268e80d5941585609ccc3b 100644
|
|
|
+--- a/services/network/public/cpp/cookie_manager_mojom_traits.h
|
|
|
++++ b/services/network/public/cpp/cookie_manager_mojom_traits.h
|
|
|
+@@ -16,6 +16,8 @@
|
|
|
+ #include "net/cookies/cookie_inclusion_status.h"
|
|
|
+ #include "net/cookies/cookie_options.h"
|
|
|
+ #include "net/cookies/cookie_partition_key_collection.h"
|
|
|
++#include "net/first_party_sets/first_party_set_entry.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "services/network/public/cpp/cookie_manager_shared_mojom_traits.h"
|
|
|
+ #include "services/network/public/mojom/cookie_manager.mojom-forward.h"
|
|
|
+ #include "services/network/public/mojom/cookie_manager.mojom.h"
|
|
|
+@@ -194,6 +196,18 @@ struct StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions> {
|
|
|
+ return o.return_excluded_cookies();
|
|
|
+ }
|
|
|
+
|
|
|
++ static net::SamePartyContext same_party_context(const net::CookieOptions& o) {
|
|
|
++ return o.same_party_context();
|
|
|
++ }
|
|
|
++
|
|
|
++ static uint32_t full_party_context_size(const net::CookieOptions& o) {
|
|
|
++ return o.full_party_context_size();
|
|
|
++ }
|
|
|
++
|
|
|
++ static bool is_in_nontrivial_first_party_set(const net::CookieOptions& o) {
|
|
|
++ return o.is_in_nontrivial_first_party_set();
|
|
|
++ }
|
|
|
++
|
|
|
+ static bool Read(network::mojom::CookieOptionsDataView mojo_options,
|
|
|
+ net::CookieOptions* cookie_options);
|
|
|
+ };
|
|
|
+diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.cc b/services/network/public/cpp/first_party_sets_mojom_traits.cc
|
|
|
+index 0c20fd9b054b6bdf989adde7d9c03f4f784215d9..4d1e584278722eb449012ef4f2f8f2162223711f 100644
|
|
|
+--- a/services/network/public/cpp/first_party_sets_mojom_traits.cc
|
|
|
++++ b/services/network/public/cpp/first_party_sets_mojom_traits.cc
|
|
|
+@@ -18,6 +18,7 @@
|
|
|
+ #include "net/first_party_sets/first_party_sets_cache_filter.h"
|
|
|
+ #include "net/first_party_sets/first_party_sets_context_config.h"
|
|
|
+ #include "net/first_party_sets/global_first_party_sets.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "services/network/public/cpp/schemeful_site_mojom_traits.h"
|
|
|
+ #include "services/network/public/mojom/first_party_sets.mojom-shared.h"
|
|
|
+
|
|
|
+@@ -83,10 +84,55 @@ bool StructTraits<network::mojom::FirstPartySetEntryDataView,
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
++bool EnumTraits<network::mojom::SamePartyCookieContextType,
|
|
|
++ net::SamePartyContext::Type>::
|
|
|
++ FromMojom(network::mojom::SamePartyCookieContextType context_type,
|
|
|
++ net::SamePartyContext::Type* out) {
|
|
|
++ switch (context_type) {
|
|
|
++ case network::mojom::SamePartyCookieContextType::kCrossParty:
|
|
|
++ *out = net::SamePartyContext::Type::kCrossParty;
|
|
|
++ return true;
|
|
|
++ case network::mojom::SamePartyCookieContextType::kSameParty:
|
|
|
++ *out = net::SamePartyContext::Type::kSameParty;
|
|
|
++ return true;
|
|
|
++ }
|
|
|
++ return false;
|
|
|
++}
|
|
|
++
|
|
|
++network::mojom::SamePartyCookieContextType
|
|
|
++EnumTraits<network::mojom::SamePartyCookieContextType,
|
|
|
++ net::SamePartyContext::Type>::ToMojom(net::SamePartyContext::Type
|
|
|
++ context_type) {
|
|
|
++ switch (context_type) {
|
|
|
++ case net::SamePartyContext::Type::kCrossParty:
|
|
|
++ return network::mojom::SamePartyCookieContextType::kCrossParty;
|
|
|
++ case net::SamePartyContext::Type::kSameParty:
|
|
|
++ return network::mojom::SamePartyCookieContextType::kSameParty;
|
|
|
++ }
|
|
|
++ NOTREACHED();
|
|
|
++ return network::mojom::SamePartyCookieContextType::kCrossParty;
|
|
|
++}
|
|
|
++
|
|
|
++bool StructTraits<network::mojom::SamePartyContextDataView,
|
|
|
++ net::SamePartyContext>::
|
|
|
++ Read(network::mojom::SamePartyContextDataView context,
|
|
|
++ net::SamePartyContext* out) {
|
|
|
++ net::SamePartyContext::Type context_type;
|
|
|
++ if (!context.ReadContextType(&context_type))
|
|
|
++ return false;
|
|
|
++
|
|
|
++ *out = net::SamePartyContext(context_type);
|
|
|
++ return true;
|
|
|
++}
|
|
|
++
|
|
|
+ bool StructTraits<network::mojom::FirstPartySetMetadataDataView,
|
|
|
+ net::FirstPartySetMetadata>::
|
|
|
+ Read(network::mojom::FirstPartySetMetadataDataView metadata,
|
|
|
+ net::FirstPartySetMetadata* out_metadata) {
|
|
|
++ net::SamePartyContext context;
|
|
|
++ if (!metadata.ReadContext(&context))
|
|
|
++ return false;
|
|
|
++
|
|
|
+ absl::optional<net::FirstPartySetEntry> frame_entry;
|
|
|
+ if (!metadata.ReadFrameEntry(&frame_entry))
|
|
|
+ return false;
|
|
|
+@@ -95,8 +141,9 @@ bool StructTraits<network::mojom::FirstPartySetMetadataDataView,
|
|
|
+ if (!metadata.ReadTopFrameEntry(&top_frame_entry))
|
|
|
+ return false;
|
|
|
+
|
|
|
+- *out_metadata = net::FirstPartySetMetadata(
|
|
|
+- base::OptionalToPtr(frame_entry), base::OptionalToPtr(top_frame_entry));
|
|
|
++ *out_metadata =
|
|
|
++ net::FirstPartySetMetadata(context, base::OptionalToPtr(frame_entry),
|
|
|
++ base::OptionalToPtr(top_frame_entry));
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.h b/services/network/public/cpp/first_party_sets_mojom_traits.h
|
|
|
+index b255f56ead022bb237296e7560c73f692a7d7ee3..644aab23aef7fb37c573add9e4180b743c755a12 100644
|
|
|
+--- a/services/network/public/cpp/first_party_sets_mojom_traits.h
|
|
|
++++ b/services/network/public/cpp/first_party_sets_mojom_traits.h
|
|
|
+@@ -16,6 +16,7 @@
|
|
|
+ #include "net/first_party_sets/first_party_sets_cache_filter.h"
|
|
|
+ #include "net/first_party_sets/first_party_sets_context_config.h"
|
|
|
+ #include "net/first_party_sets/global_first_party_sets.h"
|
|
|
++#include "net/first_party_sets/same_party_context.h"
|
|
|
+ #include "services/network/public/mojom/first_party_sets.mojom-shared.h"
|
|
|
+
|
|
|
+ namespace mojo {
|
|
|
+@@ -61,10 +62,38 @@ struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
|
+ net::FirstPartySetEntry* out);
|
|
|
+ };
|
|
|
+
|
|
|
++template <>
|
|
|
++struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
|
++ EnumTraits<network::mojom::SamePartyCookieContextType,
|
|
|
++ net::SamePartyContext::Type> {
|
|
|
++ static network::mojom::SamePartyCookieContextType ToMojom(
|
|
|
++ net::SamePartyContext::Type context_type);
|
|
|
++
|
|
|
++ static bool FromMojom(network::mojom::SamePartyCookieContextType context_type,
|
|
|
++ net::SamePartyContext::Type* out);
|
|
|
++};
|
|
|
++
|
|
|
++template <>
|
|
|
++struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
|
++ StructTraits<network::mojom::SamePartyContextDataView,
|
|
|
++ net::SamePartyContext> {
|
|
|
++ static net::SamePartyContext::Type context_type(
|
|
|
++ const net::SamePartyContext& s) {
|
|
|
++ return s.context_type();
|
|
|
++ }
|
|
|
++
|
|
|
++ static bool Read(network::mojom::SamePartyContextDataView bundle,
|
|
|
++ net::SamePartyContext* out);
|
|
|
++};
|
|
|
++
|
|
|
+ template <>
|
|
|
+ struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
|
+ StructTraits<network::mojom::FirstPartySetMetadataDataView,
|
|
|
+ net::FirstPartySetMetadata> {
|
|
|
++ static net::SamePartyContext context(const net::FirstPartySetMetadata& m) {
|
|
|
++ return m.context();
|
|
|
++ }
|
|
|
++
|
|
|
+ static absl::optional<net::FirstPartySetEntry> frame_entry(
|
|
|
+ const net::FirstPartySetMetadata& m) {
|
|
|
+ return m.frame_entry();
|
|
|
+diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
|
|
|
+index 311985f787a8577715609fcd389c3de04f25e310..32dd3b3924964d087121b5d4256c83951160baf1 100644
|
|
|
+--- a/services/network/public/mojom/BUILD.gn
|
|
|
++++ b/services/network/public/mojom/BUILD.gn
|
|
|
+@@ -1019,6 +1019,14 @@ mojom("mojom_first_party_sets") {
|
|
|
+ mojom = "network.mojom.FirstPartySetEntry"
|
|
|
+ cpp = "::net::FirstPartySetEntry"
|
|
|
+ },
|
|
|
++ {
|
|
|
++ mojom = "network.mojom.SamePartyCookieContextType"
|
|
|
++ cpp = "::net::SamePartyContext::Type"
|
|
|
++ },
|
|
|
++ {
|
|
|
++ mojom = "network.mojom.SamePartyContext"
|
|
|
++ cpp = "::net::SamePartyContext"
|
|
|
++ },
|
|
|
+ {
|
|
|
+ mojom = "network.mojom.FirstPartySetMetadata"
|
|
|
+ cpp = "::net::FirstPartySetMetadata"
|
|
|
+diff --git a/services/network/public/mojom/cookie_manager.mojom b/services/network/public/mojom/cookie_manager.mojom
|
|
|
+index 3e2e95956b691efe49b99a1509daea55d96fb8b9..563394f5d34f3314ca2208e46913bfd69bef6c58 100644
|
|
|
+--- a/services/network/public/mojom/cookie_manager.mojom
|
|
|
++++ b/services/network/public/mojom/cookie_manager.mojom
|
|
|
+@@ -183,6 +183,12 @@ struct CookieOptions {
|
|
|
+ CookieSameSiteContext same_site_cookie_context;
|
|
|
+ bool update_access_time = true;
|
|
|
+ bool return_excluded_cookies = false;
|
|
|
++ SamePartyContext same_party_context;
|
|
|
++ // The size of the isolation_info.party_context plus the top-frame site for
|
|
|
++ // logging purposes.
|
|
|
++ uint32 full_party_context_size = 0;
|
|
|
++ // Whether the site is a member of a nontrivial First-Party Set.
|
|
|
++ bool is_in_nontrivial_first_party_set = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ // See net/cookies/canonical_cookie.{h,cc} for documentation.
|
|
|
+diff --git a/services/network/public/mojom/first_party_sets.mojom b/services/network/public/mojom/first_party_sets.mojom
|
|
|
+index 0ea745cd2450c2d92002c3a0113295b0d4bbd40e..150fed986ded1c82ca3b965c0218193dc938d7a1 100644
|
|
|
+--- a/services/network/public/mojom/first_party_sets.mojom
|
|
|
++++ b/services/network/public/mojom/first_party_sets.mojom
|
|
|
+@@ -27,9 +27,25 @@ struct FirstPartySetEntry {
|
|
|
+ SiteIndex? site_index;
|
|
|
+ };
|
|
|
+
|
|
|
++// Computed for every cookie access attempt but is only relevant for SameParty
|
|
|
++// cookies.
|
|
|
++enum SamePartyCookieContextType {
|
|
|
++ // The opposite to kSameParty. Should be the default value.
|
|
|
++ kCrossParty,
|
|
|
++ // If the request URL is in the same First-Party Sets as the top-frame site
|
|
|
++ // and each member of the isolation_info.party_context.
|
|
|
++ kSameParty,
|
|
|
++};
|
|
|
++
|
|
|
++// Keep defaults in here in sync with net/cookies/same_party_context.cc.
|
|
|
++struct SamePartyContext {
|
|
|
++ SamePartyCookieContextType context_type = kCrossParty;
|
|
|
++};
|
|
|
++
|
|
|
+ // This struct must match the class fields defined in
|
|
|
+ // //net/first_party_sets/first_party_set_metadata.h.
|
|
|
+ struct FirstPartySetMetadata {
|
|
|
++ SamePartyContext context;
|
|
|
+ // absl::nullopt indicates that the frame's site is not associated with any
|
|
|
+ // First-Party Set.
|
|
|
+ FirstPartySetEntry? frame_entry;
|
|
|
+diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
|
|
|
+index cc22ed62613a567e44708758a75de2cac18ee284..1a1eca338ff8cd7e1b1b247cfadaee16f37e5628 100644
|
|
|
+--- a/services/network/restricted_cookie_manager.cc
|
|
|
++++ b/services/network/restricted_cookie_manager.cc
|
|
|
+@@ -56,11 +56,17 @@ BASE_FEATURE(kIncreaseCoookieAccesCacheSize,
|
|
|
+ // adding a user-perceptible delay.
|
|
|
+ constexpr base::TimeDelta kCookiesAccessedTimeout = base::Milliseconds(100);
|
|
|
+
|
|
|
++// The `force_ignore_top_frame_party` param being false prevents `document.cookie`
|
|
|
++// access for same-party scripts embedded in an extension frame.
|
|
|
++const bool kForceIgnoreTopFrameParty = false;
|
|
|
++
|
|
|
+ net::CookieOptions MakeOptionsForSet(
|
|
|
+ mojom::RestrictedCookieManagerRole role,
|
|
|
+ const GURL& url,
|
|
|
+ const net::SiteForCookies& site_for_cookies,
|
|
|
+- const CookieSettings& cookie_settings) {
|
|
|
++ const net::IsolationInfo& isolation_info,
|
|
|
++ const CookieSettings& cookie_settings,
|
|
|
++ const net::FirstPartySetMetadata& first_party_set_metadata) {
|
|
|
+ net::CookieOptions options;
|
|
|
+ bool force_ignore_site_for_cookies =
|
|
|
+ cookie_settings.ShouldIgnoreSameSiteRestrictions(url, site_for_cookies);
|
|
|
+@@ -76,6 +82,14 @@ net::CookieOptions MakeOptionsForSet(
|
|
|
+ net::cookie_util::ComputeSameSiteContextForSubresource(
|
|
|
+ url, site_for_cookies, force_ignore_site_for_cookies));
|
|
|
+ }
|
|
|
++ options.set_same_party_context(first_party_set_metadata.context());
|
|
|
++ if (isolation_info.party_context().has_value()) {
|
|
|
++ // Count the top-frame site since it's not in the party_context.
|
|
|
++ options.set_full_party_context_size(isolation_info.party_context()->size() +
|
|
|
++ 1);
|
|
|
++ }
|
|
|
++ options.set_is_in_nontrivial_first_party_set(
|
|
|
++ first_party_set_metadata.frame_entry().has_value());
|
|
|
+
|
|
|
+ return options;
|
|
|
+ }
|
|
|
+@@ -84,7 +98,9 @@ net::CookieOptions MakeOptionsForGet(
|
|
|
+ mojom::RestrictedCookieManagerRole role,
|
|
|
+ const GURL& url,
|
|
|
+ const net::SiteForCookies& site_for_cookies,
|
|
|
+- const CookieSettings& cookie_settings) {
|
|
|
++ const net::IsolationInfo& isolation_info,
|
|
|
++ const CookieSettings& cookie_settings,
|
|
|
++ const net::FirstPartySetMetadata& first_party_set_metadata) {
|
|
|
+ // TODO(https://crbug.com/925311): Wire initiator here.
|
|
|
+ net::CookieOptions options;
|
|
|
+ bool force_ignore_site_for_cookies =
|
|
|
+@@ -102,6 +118,14 @@ net::CookieOptions MakeOptionsForGet(
|
|
|
+ net::cookie_util::ComputeSameSiteContextForSubresource(
|
|
|
+ url, site_for_cookies, force_ignore_site_for_cookies));
|
|
|
+ }
|
|
|
++ options.set_same_party_context(first_party_set_metadata.context());
|
|
|
++ if (isolation_info.party_context().has_value()) {
|
|
|
++ // Count the top-frame site since it's not in the party_context.
|
|
|
++ options.set_full_party_context_size(isolation_info.party_context()->size() +
|
|
|
++ 1);
|
|
|
++ }
|
|
|
++ options.set_is_in_nontrivial_first_party_set(
|
|
|
++ first_party_set_metadata.frame_entry().has_value());
|
|
|
+
|
|
|
+ return options;
|
|
|
+ }
|
|
|
+@@ -123,7 +147,8 @@ void RestrictedCookieManager::ComputeFirstPartySetMetadata(
|
|
|
+ absl::optional<net::FirstPartySetMetadata> metadata =
|
|
|
+ net::cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
|
|
|
+ /*request_site=*/net::SchemefulSite(origin), isolation_info,
|
|
|
+- cookie_store->cookie_access_delegate(), std::move(callbacks.first));
|
|
|
++ cookie_store->cookie_access_delegate(), kForceIgnoreTopFrameParty,
|
|
|
++ std::move(callbacks.first));
|
|
|
+ if (metadata.has_value())
|
|
|
+ std::move(callbacks.second).Run(std::move(metadata.value()));
|
|
|
+ }
|
|
|
+@@ -216,7 +241,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
|
+ bool has_storage_access,
|
|
|
+ const absl::optional<net::CookiePartitionKey>& cookie_partition_key,
|
|
|
+ net::CookieOptions options,
|
|
|
+- mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener)
|
|
|
++ mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener,
|
|
|
++ bool same_party_attribute_enabled)
|
|
|
+ : cookie_store_(cookie_store),
|
|
|
+ restricted_cookie_manager_(restricted_cookie_manager),
|
|
|
+ url_(url),
|
|
|
+@@ -224,7 +250,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
|
+ top_frame_origin_(top_frame_origin),
|
|
|
+ has_storage_access_(has_storage_access),
|
|
|
+ options_(options),
|
|
|
+- mojo_listener_(std::move(mojo_listener)) {
|
|
|
++ mojo_listener_(std::move(mojo_listener)),
|
|
|
++ same_party_attribute_enabled_(same_party_attribute_enabled) {
|
|
|
+ // TODO(pwnall): add a constructor w/options to net::CookieChangeDispatcher.
|
|
|
+ cookie_store_subscription_ =
|
|
|
+ cookie_store->GetChangeDispatcher().AddCallbackForUrl(
|
|
|
+@@ -260,11 +287,16 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
|
+
|
|
|
+ // CookieChangeDispatcher doesn't check for inclusion against `options_`, so
|
|
|
+ // we need to double-check that.
|
|
|
++ net::CookieSamePartyStatus same_party_status =
|
|
|
++ net::cookie_util::GetSamePartyStatus(change.cookie, options_,
|
|
|
++ same_party_attribute_enabled_);
|
|
|
++
|
|
|
+ if (!change.cookie
|
|
|
+ .IncludeForRequestURL(
|
|
|
+ url_, options_,
|
|
|
+ net::CookieAccessParams{change.access_result.access_semantics,
|
|
|
+- delegate_treats_url_as_trustworthy})
|
|
|
++ delegate_treats_url_as_trustworthy,
|
|
|
++ same_party_status})
|
|
|
+ .status.IsInclude()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+@@ -315,6 +347,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
|
+
|
|
|
+ mojo::Remote<mojom::CookieChangeListener> mojo_listener_;
|
|
|
+
|
|
|
++ bool same_party_attribute_enabled_;
|
|
|
++
|
|
|
+ SEQUENCE_CHECKER(sequence_checker_);
|
|
|
+ };
|
|
|
+
|
|
|
+@@ -341,6 +375,8 @@ RestrictedCookieManager::RestrictedCookieManager(
|
|
|
+ cookie_partition_key_collection_(
|
|
|
+ net::CookiePartitionKeyCollection::FromOptional(
|
|
|
+ cookie_partition_key_)),
|
|
|
++ same_party_attribute_enabled_(base::FeatureList::IsEnabled(
|
|
|
++ net::features::kSamePartyAttributeEnabled)),
|
|
|
+ receiver_(this),
|
|
|
+ metrics_updater_(metrics_updater),
|
|
|
+ cookies_access_timer_(
|
|
|
+@@ -451,7 +487,8 @@ void RestrictedCookieManager::GetAllForUrl(
|
|
|
+ // TODO(morlovich): Try to validate site_for_cookies as well.
|
|
|
+
|
|
|
+ net::CookieOptions net_options =
|
|
|
+- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
|
|
|
++ MakeOptionsForGet(role_, url, site_for_cookies, isolation_info_,
|
|
|
++ cookie_settings(), first_party_set_metadata_);
|
|
|
+ // TODO(https://crbug.com/977040): remove set_return_excluded_cookies() once
|
|
|
+ // removing deprecation warnings.
|
|
|
+ net_options.set_return_excluded_cookies();
|
|
|
+@@ -705,7 +742,8 @@ void RestrictedCookieManager::SetCanonicalCookie(
|
|
|
+
|
|
|
+ net::CanonicalCookie cookie_copy = *sanitized_cookie;
|
|
|
+ net::CookieOptions options =
|
|
|
+- MakeOptionsForSet(role_, url, site_for_cookies, cookie_settings());
|
|
|
++ MakeOptionsForSet(role_, url, site_for_cookies, isolation_info_,
|
|
|
++ cookie_settings(), first_party_set_metadata_);
|
|
|
+
|
|
|
+ net::CookieAccessResult cookie_access_result(status);
|
|
|
+ cookie_store_->SetCanonicalCookieAsync(
|
|
|
+@@ -757,11 +795,12 @@ void RestrictedCookieManager::AddChangeListener(
|
|
|
+ }
|
|
|
+
|
|
|
+ net::CookieOptions net_options =
|
|
|
+- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
|
|
|
++ MakeOptionsForGet(role_, url, site_for_cookies, isolation_info_,
|
|
|
++ cookie_settings(), first_party_set_metadata_);
|
|
|
+ auto listener = std::make_unique<Listener>(
|
|
|
+ cookie_store_, this, url, site_for_cookies, top_frame_origin,
|
|
|
+ has_storage_access, cookie_partition_key_, net_options,
|
|
|
+- std::move(mojo_listener));
|
|
|
++ std::move(mojo_listener), same_party_attribute_enabled_);
|
|
|
+
|
|
|
+ listener->mojo_listener().set_disconnect_handler(
|
|
|
+ base::BindOnce(&RestrictedCookieManager::RemoveChangeListener,
|
|
|
+diff --git a/services/network/restricted_cookie_manager.h b/services/network/restricted_cookie_manager.h
|
|
|
+index be2749818c7af32f48da819b378c9afaa4933933..8086076904844fe208c4f3f72569e85fb485dec0 100644
|
|
|
+--- a/services/network/restricted_cookie_manager.h
|
|
|
++++ b/services/network/restricted_cookie_manager.h
|
|
|
+@@ -314,6 +314,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) RestrictedCookieManager
|
|
|
+ // update filtering.
|
|
|
+ CookieAccessesByURLAndSite recent_cookie_accesses_;
|
|
|
+
|
|
|
++ bool same_party_attribute_enabled_;
|
|
|
++
|
|
|
+ // This class can optionally bind its Receiver. If that's the case it's stored
|
|
|
+ // done with this variable.
|
|
|
+ mojo::Receiver<mojom::RestrictedCookieManager> receiver_;
|
|
|
+diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
|
|
|
+index 4ad8c5476cbf00a4246ec524e5d95037b06a7151..2cb705fcd442334074edcf2265ae0ccbb26db183 100644
|
|
|
+--- a/services/network/url_loader.cc
|
|
|
++++ b/services/network/url_loader.cc
|
|
|
+@@ -287,6 +287,8 @@ bool ShouldNotifyAboutCookie(net::CookieInclusionStatus status) {
|
|
|
+ return status.IsInclude() || status.ShouldWarn() ||
|
|
|
+ status.HasExclusionReason(
|
|
|
+ net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES) ||
|
|
|
++ status.HasExclusionReason(
|
|
|
++ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY) ||
|
|
|
+ status.HasExclusionReason(
|
|
|
+ net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII);
|
|
|
+ }
|
|
|
+@@ -586,6 +588,9 @@ URLLoader::URLLoader(
|
|
|
+ DCHECK(!url_request_->isolation_info().IsEmpty());
|
|
|
+ }
|
|
|
+
|
|
|
++ if (ShouldForceIgnoreTopFramePartyForCookies())
|
|
|
++ url_request_->set_force_ignore_top_frame_party_for_cookies(true);
|
|
|
++
|
|
|
+ // When a service worker forwards a navigation request it uses the
|
|
|
+ // service worker's IsolationInfo. This causes the cookie code to fail
|
|
|
+ // to send SameSite=Lax cookies for main-frame navigations passed through
|
|
|
+@@ -2689,6 +2694,36 @@ bool URLLoader::ShouldForceIgnoreSiteForCookies(
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
++bool URLLoader::ShouldForceIgnoreTopFramePartyForCookies() const {
|
|
|
++ const net::IsolationInfo& isolation_info = url_request_->isolation_info();
|
|
|
++ const absl::optional<url::Origin>& top_frame_origin =
|
|
|
++ isolation_info.top_frame_origin();
|
|
|
++
|
|
|
++ if (!top_frame_origin || top_frame_origin->opaque())
|
|
|
++ return false;
|
|
|
++
|
|
|
++ const absl::optional<std::set<net::SchemefulSite>>& party_context =
|
|
|
++ isolation_info.party_context();
|
|
|
++ if (!party_context)
|
|
|
++ return false;
|
|
|
++
|
|
|
++ // The top frame origin must have access to the request URL.
|
|
|
++ if (cors::OriginAccessList::AccessState::kAllowed !=
|
|
|
++ origin_access_list_->CheckAccessState(*top_frame_origin,
|
|
|
++ url_request_->url())) {
|
|
|
++ return false;
|
|
|
++ }
|
|
|
++
|
|
|
++ // The top frame origin must have access to each site in the party_context.
|
|
|
++ return base::ranges::all_of(
|
|
|
++ *party_context,
|
|
|
++ [this, &top_frame_origin](const net::SchemefulSite& site) {
|
|
|
++ return origin_access_list_->CheckAccessState(*top_frame_origin,
|
|
|
++ site.GetURL()) ==
|
|
|
++ cors::OriginAccessList::AccessState::kAllowed;
|
|
|
++ });
|
|
|
++}
|
|
|
++
|
|
|
+ void URLLoader::SetRequestCredentials(const GURL& url) {
|
|
|
+ bool coep_allow_credentials = CoepAllowCredentials(url);
|
|
|
+
|
|
|
+diff --git a/services/network/url_loader.h b/services/network/url_loader.h
|
|
|
+index 6970066e65c6e61a6fed1248127abd6550ddfec6..96d224b1634aff0791ac6b3799725e61ab11afca 100644
|
|
|
+--- a/services/network/url_loader.h
|
|
|
++++ b/services/network/url_loader.h
|
|
|
+@@ -548,6 +548,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
|
|
|
+ // Whether `force_ignore_site_for_cookies` should be set on net::URLRequest.
|
|
|
+ bool ShouldForceIgnoreSiteForCookies(const ResourceRequest& request);
|
|
|
+
|
|
|
++ // Whether `force_ignore_top_frame_party_for_cookies` should be set on
|
|
|
++ // net::URLRequest.
|
|
|
++ bool ShouldForceIgnoreTopFramePartyForCookies() const;
|
|
|
++
|
|
|
+ // Applies Private Network Access checks to the current request.
|
|
|
+ //
|
|
|
+ // Helper for `OnConnected()`.
|