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 <cstddef>
6 #include <string>
7
8 #include "base/unguessable_token.h"
9 #include "net/base/features.h"
10 #include "net/base/network_isolation_key.h"
11 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
12 #include "schemeful_site.h"
13 #include "third_party/abseil-cpp/absl/types/optional.h"
14 #include "url/gurl.h"
15 #include "url/origin.h"
16 #include "url/url_constants.h"
17
18 namespace net {
19
20 namespace {
21
GetSiteDebugString(const absl::optional<SchemefulSite> & site)22 std::string GetSiteDebugString(const absl::optional<SchemefulSite>& site) {
23 return site ? site->GetDebugString() : "null";
24 }
25
26 } // namespace
27
NetworkIsolationKey(SerializationPasskey,SchemefulSite top_frame_site,SchemefulSite frame_site,bool is_cross_site,absl::optional<base::UnguessableToken> nonce)28 NetworkIsolationKey::NetworkIsolationKey(
29 SerializationPasskey,
30 SchemefulSite top_frame_site,
31 SchemefulSite frame_site,
32 bool is_cross_site,
33 absl::optional<base::UnguessableToken> nonce)
34 : top_frame_site_(std::move(top_frame_site)),
35 frame_site_(std::move(frame_site)),
36 is_cross_site_(is_cross_site),
37 nonce_(std::move(nonce)) {
38 CHECK_EQ(GetMode(), Mode::kCrossSiteFlagEnabled);
39 }
40
NetworkIsolationKey(const SchemefulSite & top_frame_site,const SchemefulSite & frame_site,const absl::optional<base::UnguessableToken> & nonce)41 NetworkIsolationKey::NetworkIsolationKey(
42 const SchemefulSite& top_frame_site,
43 const SchemefulSite& frame_site,
44 const absl::optional<base::UnguessableToken>& nonce)
45 : NetworkIsolationKey(SchemefulSite(top_frame_site),
46 SchemefulSite(frame_site),
47 absl::optional<base::UnguessableToken>(nonce)) {}
48
NetworkIsolationKey(SchemefulSite && top_frame_site,SchemefulSite && frame_site,absl::optional<base::UnguessableToken> && nonce)49 NetworkIsolationKey::NetworkIsolationKey(
50 SchemefulSite&& top_frame_site,
51 SchemefulSite&& frame_site,
52 absl::optional<base::UnguessableToken>&& nonce)
53 : top_frame_site_(std::move(top_frame_site)),
54 frame_site_(absl::make_optional(std::move(frame_site))),
55 is_cross_site_((GetMode() == Mode::kCrossSiteFlagEnabled)
56 ? absl::make_optional(*top_frame_site_ != *frame_site_)
57 : absl::nullopt),
58 nonce_(std::move(nonce)) {
59 DCHECK(!nonce_ || !nonce_->is_empty());
60 }
61
NetworkIsolationKey(const url::Origin & top_frame_origin,const url::Origin & frame_origin)62 NetworkIsolationKey::NetworkIsolationKey(const url::Origin& top_frame_origin,
63 const url::Origin& frame_origin)
64 : NetworkIsolationKey(SchemefulSite(top_frame_origin),
65 SchemefulSite(frame_origin)) {}
66
67 NetworkIsolationKey::NetworkIsolationKey() = default;
68
69 NetworkIsolationKey::NetworkIsolationKey(
70 const NetworkIsolationKey& network_isolation_key) = default;
71
72 NetworkIsolationKey::NetworkIsolationKey(
73 NetworkIsolationKey&& network_isolation_key) = default;
74
75 NetworkIsolationKey::~NetworkIsolationKey() = default;
76
77 NetworkIsolationKey& NetworkIsolationKey::operator=(
78 const NetworkIsolationKey& network_isolation_key) = default;
79
80 NetworkIsolationKey& NetworkIsolationKey::operator=(
81 NetworkIsolationKey&& network_isolation_key) = default;
82
CreateTransient()83 NetworkIsolationKey NetworkIsolationKey::CreateTransient() {
84 SchemefulSite site_with_opaque_origin;
85 return NetworkIsolationKey(site_with_opaque_origin, site_with_opaque_origin);
86 }
87
CreateWithNewFrameSite(const SchemefulSite & new_frame_site) const88 NetworkIsolationKey NetworkIsolationKey::CreateWithNewFrameSite(
89 const SchemefulSite& new_frame_site) const {
90 if (!top_frame_site_)
91 return NetworkIsolationKey();
92 NetworkIsolationKey key(top_frame_site_.value(), new_frame_site);
93 key.nonce_ = nonce_;
94 return key;
95 }
96
ToCacheKeyString() const97 absl::optional<std::string> NetworkIsolationKey::ToCacheKeyString() const {
98 if (IsTransient())
99 return absl::nullopt;
100
101 std::string variable_key_piece;
102 switch (GetMode()) {
103 case Mode::kFrameSiteEnabled:
104 variable_key_piece = frame_site_->Serialize();
105 break;
106 case Mode::kCrossSiteFlagEnabled:
107 variable_key_piece = (*is_cross_site_ ? "_1" : "_0");
108 break;
109 }
110 return top_frame_site_->Serialize() + " " + variable_key_piece;
111 }
112
ToDebugString() const113 std::string NetworkIsolationKey::ToDebugString() const {
114 // The space-separated serialization of |top_frame_site_| and
115 // |frame_site_|.
116 std::string return_string = GetSiteDebugString(top_frame_site_);
117 switch (GetMode()) {
118 case Mode::kFrameSiteEnabled:
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 return Mode::kCrossSiteFlagEnabled;
156 } else {
157 return Mode::kFrameSiteEnabled;
158 }
159 }
160
GetFrameSite() const161 const absl::optional<SchemefulSite>& NetworkIsolationKey::GetFrameSite() const {
162 // Frame site will be empty if double-keying is enabled.
163 CHECK(GetMode() == Mode::kFrameSiteEnabled);
164 return frame_site_;
165 }
166
GetIsCrossSite() const167 absl::optional<bool> NetworkIsolationKey::GetIsCrossSite() const {
168 CHECK(GetMode() == Mode::kCrossSiteFlagEnabled);
169 return is_cross_site_;
170 }
171
IsEmpty() const172 bool NetworkIsolationKey::IsEmpty() const {
173 return !top_frame_site_.has_value() && !frame_site_.has_value();
174 }
175
IsOpaque() const176 bool NetworkIsolationKey::IsOpaque() const {
177 if (top_frame_site_->opaque()) {
178 return true;
179 }
180 if (GetMode() == Mode::kFrameSiteEnabled && frame_site_->opaque()) {
181 return true;
182 }
183 if (nonce_.has_value()) {
184 return true;
185 }
186 return false;
187 }
188
189 } // namespace net
190