1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/network_isolation_key.h"
6
7 #include <cstddef>
8 #include <optional>
9 #include <string>
10
11 #include "base/unguessable_token.h"
12 #include "net/base/features.h"
13 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
14 #include "schemeful_site.h"
15 #include "url/gurl.h"
16 #include "url/origin.h"
17 #include "url/url_constants.h"
18
19 namespace net {
20
21 namespace {
22
GetSiteDebugString(const std::optional<SchemefulSite> & site)23 std::string GetSiteDebugString(const std::optional<SchemefulSite>& site) {
24 return site ? site->GetDebugString() : "null";
25 }
26
27 } // namespace
28
NetworkIsolationKey(const SchemefulSite & top_frame_site,const SchemefulSite & frame_site,const std::optional<base::UnguessableToken> & nonce)29 NetworkIsolationKey::NetworkIsolationKey(
30 const SchemefulSite& top_frame_site,
31 const SchemefulSite& frame_site,
32 const std::optional<base::UnguessableToken>& nonce)
33 : NetworkIsolationKey(SchemefulSite(top_frame_site),
34 SchemefulSite(frame_site),
35 std::optional<base::UnguessableToken>(nonce)) {}
36
NetworkIsolationKey(SchemefulSite && top_frame_site,SchemefulSite && frame_site,std::optional<base::UnguessableToken> && nonce)37 NetworkIsolationKey::NetworkIsolationKey(
38 SchemefulSite&& top_frame_site,
39 SchemefulSite&& frame_site,
40 std::optional<base::UnguessableToken>&& nonce)
41 : top_frame_site_(std::move(top_frame_site)),
42 frame_site_(std::make_optional(std::move(frame_site))),
43 is_cross_site_((GetMode() == Mode::kCrossSiteFlagEnabled)
44 ? std::make_optional(*top_frame_site_ != *frame_site_)
45 : std::nullopt),
46 nonce_(std::move(nonce)) {
47 DCHECK(!nonce_ || !nonce_->is_empty());
48 }
49
NetworkIsolationKey(const url::Origin & top_frame_origin,const url::Origin & frame_origin)50 NetworkIsolationKey::NetworkIsolationKey(const url::Origin& top_frame_origin,
51 const url::Origin& frame_origin)
52 : NetworkIsolationKey(SchemefulSite(top_frame_origin),
53 SchemefulSite(frame_origin)) {}
54
55 NetworkIsolationKey::NetworkIsolationKey() = default;
56
57 NetworkIsolationKey::NetworkIsolationKey(
58 const NetworkIsolationKey& network_isolation_key) = default;
59
60 NetworkIsolationKey::NetworkIsolationKey(
61 NetworkIsolationKey&& network_isolation_key) = default;
62
63 NetworkIsolationKey::~NetworkIsolationKey() = default;
64
65 NetworkIsolationKey& NetworkIsolationKey::operator=(
66 const NetworkIsolationKey& network_isolation_key) = default;
67
68 NetworkIsolationKey& NetworkIsolationKey::operator=(
69 NetworkIsolationKey&& network_isolation_key) = default;
70
CreateTransientForTesting()71 NetworkIsolationKey NetworkIsolationKey::CreateTransientForTesting() {
72 SchemefulSite site_with_opaque_origin;
73 return NetworkIsolationKey(site_with_opaque_origin, site_with_opaque_origin);
74 }
75
CreateWithNewFrameSite(const SchemefulSite & new_frame_site) const76 NetworkIsolationKey NetworkIsolationKey::CreateWithNewFrameSite(
77 const SchemefulSite& new_frame_site) const {
78 if (!top_frame_site_)
79 return NetworkIsolationKey();
80 return NetworkIsolationKey(top_frame_site_.value(), new_frame_site, nonce_);
81 }
82
ToCacheKeyString() const83 std::optional<std::string> NetworkIsolationKey::ToCacheKeyString() const {
84 if (IsTransient())
85 return std::nullopt;
86
87 std::string variable_key_piece;
88 switch (GetMode()) {
89 case Mode::kFrameSiteEnabled:
90 variable_key_piece = frame_site_->Serialize();
91 break;
92 case Mode::kFrameSiteWithSharedOpaqueEnabled:
93 if (frame_site_->opaque()) {
94 variable_key_piece = "_opaque";
95 break;
96 }
97 variable_key_piece = frame_site_->Serialize();
98 break;
99 case Mode::kCrossSiteFlagEnabled:
100 variable_key_piece = (*is_cross_site_ ? "_1" : "_0");
101 break;
102 }
103 return top_frame_site_->Serialize() + " " + variable_key_piece;
104 }
105
ToDebugString() const106 std::string NetworkIsolationKey::ToDebugString() const {
107 // The space-separated serialization of |top_frame_site_| and
108 // |frame_site_|.
109 std::string return_string = GetSiteDebugString(top_frame_site_);
110 switch (GetMode()) {
111 case Mode::kFrameSiteEnabled:
112 return_string += " " + GetSiteDebugString(frame_site_);
113 break;
114 case Mode::kFrameSiteWithSharedOpaqueEnabled:
115 if (frame_site_ && frame_site_->opaque()) {
116 return_string += " opaque-origin";
117 break;
118 }
119 return_string += " " + GetSiteDebugString(frame_site_);
120 break;
121 case Mode::kCrossSiteFlagEnabled:
122 if (is_cross_site_.has_value()) {
123 return_string += (*is_cross_site_ ? " cross-site" : " same-site");
124 }
125 break;
126 }
127
128 if (nonce_.has_value()) {
129 return_string += " (with nonce " + nonce_->ToString() + ")";
130 }
131
132 return return_string;
133 }
134
IsFullyPopulated() const135 bool NetworkIsolationKey::IsFullyPopulated() const {
136 if (!top_frame_site_.has_value()) {
137 return false;
138 }
139 if (GetMode() == Mode::kFrameSiteEnabled && !frame_site_.has_value()) {
140 return false;
141 }
142 return true;
143 }
144
IsTransient() const145 bool NetworkIsolationKey::IsTransient() const {
146 if (!IsFullyPopulated())
147 return true;
148 return IsOpaque();
149 }
150
151 // static
GetMode()152 NetworkIsolationKey::Mode NetworkIsolationKey::GetMode() {
153 if (base::FeatureList::IsEnabled(
154 net::features::kEnableCrossSiteFlagNetworkIsolationKey)) {
155 DCHECK(!base::FeatureList::IsEnabled(
156 net::features::kEnableFrameSiteSharedOpaqueNetworkIsolationKey));
157 return Mode::kCrossSiteFlagEnabled;
158 } else if (base::FeatureList::IsEnabled(
159 net::features::
160 kEnableFrameSiteSharedOpaqueNetworkIsolationKey)) {
161 return Mode::kFrameSiteWithSharedOpaqueEnabled;
162 } else {
163 return Mode::kFrameSiteEnabled;
164 }
165 }
166
IsEmpty() const167 bool NetworkIsolationKey::IsEmpty() const {
168 return !top_frame_site_.has_value() && !frame_site_.has_value();
169 }
170
IsOpaque() const171 bool NetworkIsolationKey::IsOpaque() const {
172 if (top_frame_site_->opaque()) {
173 return true;
174 }
175 // For Mode::kCrossSiteFlagEnabled and Mode::kFrameSiteWithSharedOpaqueEnabled
176 // we don't want to treat NIKs for opaque origin frames as opaque.
177 if (GetMode() == Mode::kFrameSiteEnabled && frame_site_->opaque()) {
178 return true;
179 }
180 if (nonce_.has_value()) {
181 return true;
182 }
183 return false;
184 }
185
186 } // namespace net
187