// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/unguessable_token.h" #include "base/values.h" #include "net/base/features.h" #include "net/base/network_isolation_key.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "schemeful_site.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" #include "url/origin.h" #include "url/url_constants.h" namespace net { namespace { std::string GetSiteDebugString(const absl::optional& site) { return site ? site->GetDebugString() : "null"; } } // namespace NetworkIsolationKey::NetworkIsolationKey(const SchemefulSite& top_frame_site, const SchemefulSite& frame_site, const base::UnguessableToken* nonce) : NetworkIsolationKey(SchemefulSite(top_frame_site), SchemefulSite(frame_site), nonce) {} NetworkIsolationKey::NetworkIsolationKey(SchemefulSite&& top_frame_site, SchemefulSite&& frame_site, const base::UnguessableToken* nonce) : top_frame_site_(std::move(top_frame_site)), frame_site_(IsFrameSiteEnabled() ? absl::make_optional(std::move(frame_site)) : absl::nullopt), nonce_(nonce ? absl::make_optional(*nonce) : absl::nullopt) { DCHECK(!nonce || !nonce->is_empty()); } NetworkIsolationKey::NetworkIsolationKey(const url::Origin& top_frame_origin, const url::Origin& frame_origin) : NetworkIsolationKey(SchemefulSite(top_frame_origin), SchemefulSite(frame_origin)) {} NetworkIsolationKey::NetworkIsolationKey() = default; NetworkIsolationKey::NetworkIsolationKey( const NetworkIsolationKey& network_isolation_key) = default; NetworkIsolationKey::NetworkIsolationKey( NetworkIsolationKey&& network_isolation_key) = default; NetworkIsolationKey::~NetworkIsolationKey() = default; NetworkIsolationKey& NetworkIsolationKey::operator=( const NetworkIsolationKey& network_isolation_key) = default; NetworkIsolationKey& NetworkIsolationKey::operator=( NetworkIsolationKey&& network_isolation_key) = default; NetworkIsolationKey NetworkIsolationKey::CreateTransient() { SchemefulSite site_with_opaque_origin; return NetworkIsolationKey(site_with_opaque_origin, site_with_opaque_origin); } NetworkIsolationKey NetworkIsolationKey::CreateWithNewFrameSite( const SchemefulSite& new_frame_site) const { if (!top_frame_site_) return NetworkIsolationKey(); NetworkIsolationKey key(top_frame_site_.value(), new_frame_site); key.nonce_ = nonce_; return key; } absl::optional NetworkIsolationKey::ToCacheKeyString() const { if (IsTransient()) return absl::nullopt; std::string frame_site_str = " " + (IsFrameSiteEnabled() ? frame_site_->Serialize() : top_frame_site_->Serialize()); return top_frame_site_->Serialize() + frame_site_str; } std::string NetworkIsolationKey::ToDebugString() const { // The space-separated serialization of |top_frame_site_| and // |frame_site_|. std::string return_string = GetSiteDebugString(top_frame_site_); return_string += " " + GetSiteDebugString(frame_site_); if (nonce_.has_value()) { return_string += " (with nonce " + nonce_->ToString() + ")"; } return return_string; } bool NetworkIsolationKey::IsFullyPopulated() const { return top_frame_site_.has_value() && (!IsFrameSiteEnabled() || frame_site_.has_value()); } bool NetworkIsolationKey::IsTransient() const { if (!IsFullyPopulated()) return true; return IsOpaque(); } bool NetworkIsolationKey::ToValue(base::Value* out_value) const { if (IsEmpty()) { *out_value = base::Value(base::Value::Type::LIST); return true; } if (IsTransient()) return false; // NetworkIsolationKeys with nonces are now always transient, so serializing // with nonces isn't strictly needed, but it's used for backwards // compatibility, Origin::Deserialize() is not compatible with // SerializeWithNonce(). absl::optional top_frame_value = SerializeSiteWithNonce(*top_frame_site_); if (!top_frame_value) return false; base::Value::List list; list.Append(std::move(top_frame_value).value()); absl::optional frame_value = IsFrameSiteEnabled() ? SerializeSiteWithNonce(*frame_site_) : absl::nullopt; if (frame_value.has_value()) { // If there is a frame value, append it. list.Append(std::move(frame_value).value()); } else if (IsFrameSiteEnabled()) { // If there is supposed to be a frame value but there isn't return false. return false; } // List will have size 1 when frame site is disabled. *out_value = base::Value(std::move(list)); return true; } bool NetworkIsolationKey::FromValue( const base::Value& value, NetworkIsolationKey* network_isolation_key) { if (!value.is_list()) return false; const base::Value::List& list = value.GetList(); if (list.empty()) { *network_isolation_key = NetworkIsolationKey(); return true; } // When frame site is enabled list must be of size 2 and both values must be // strings. // When frame site is disabled for double key `list` can be either be of size // 2 or of size 1. For backwards compatibility, frame site is allowed to be of // size 2 when frame site is disabled because a previous expirement set frame // site equal to a copy of top frame site rather than setting it empty. if (IsFrameSiteEnabled()) { if (list.size() != 2 || !list[0].is_string() || !list[1].is_string()) { return false; } } else { if (list.size() < 0 || list.size() > 2 || !list[0].is_string()) { return false; } } absl::optional top_frame_site = SchemefulSite::DeserializeWithNonce(list[0].GetString()); // Opaque origins are currently never serialized to disk, but they used to be. if (!top_frame_site || top_frame_site->opaque()) return false; if (list.size() == 1) { // The value of the frame_site parameter doesn't matter because the // constructor will default it to nullopt. *network_isolation_key = NetworkIsolationKey(std::move(*top_frame_site), net::SchemefulSite()); return true; } absl::optional frame_site = SchemefulSite::DeserializeWithNonce(list[1].GetString()); // Opaque origins are currently never serialized to disk, but they used to be. if (!frame_site || frame_site->opaque()) return false; *network_isolation_key = NetworkIsolationKey(std::move(*top_frame_site), std::move(*frame_site)); return true; } const absl::optional& NetworkIsolationKey::GetFrameSite() const { // TODO: @brgoldstein, add CHECK that // `kForceIsolationInfoFrameOriginToTopLevelFrame` is not enabled. return frame_site_; } bool NetworkIsolationKey::IsEmpty() const { return !top_frame_site_.has_value() && !frame_site_.has_value(); } bool NetworkIsolationKey::IsFrameSiteEnabled() { return !base::FeatureList::IsEnabled( net::features::kForceIsolationInfoFrameOriginToTopLevelFrame); } bool NetworkIsolationKey::IsOpaque() const { return top_frame_site_->opaque() || (IsFrameSiteEnabled() && frame_site_->opaque()) || nonce_.has_value(); } absl::optional NetworkIsolationKey::SerializeSiteWithNonce( const SchemefulSite& site) { return *(const_cast(site).SerializeWithNonce()); } } // namespace net