xref: /aosp_15_r20/external/cronet/net/cookies/cookie_partition_key.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_partition_key.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <ostream>
8*6777b538SAndroid Build Coastguard Worker #include <tuple>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/types/optional_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "net/base/cronet_buildflags.h"
14*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_constants.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/cookies/site_for_cookies.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(CRONET_BUILD)
18*6777b538SAndroid Build Coastguard Worker #include "mojo/public/cpp/bindings/default_construct_tag.h"
19*6777b538SAndroid Build Coastguard Worker #endif
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace net {
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace {
24*6777b538SAndroid Build Coastguard Worker 
WarnAndCreateUnexpected(const std::string & message)25*6777b538SAndroid Build Coastguard Worker base::unexpected<std::string> WarnAndCreateUnexpected(
26*6777b538SAndroid Build Coastguard Worker     const std::string& message) {
27*6777b538SAndroid Build Coastguard Worker   DLOG(WARNING) << message;
28*6777b538SAndroid Build Coastguard Worker   return base::unexpected(message);
29*6777b538SAndroid Build Coastguard Worker }
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker }  // namespace
32*6777b538SAndroid Build Coastguard Worker 
SerializedCookiePartitionKey(const std::string & site,bool has_cross_site_ancestor)33*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::SerializedCookiePartitionKey::SerializedCookiePartitionKey(
34*6777b538SAndroid Build Coastguard Worker     const std::string& site,
35*6777b538SAndroid Build Coastguard Worker     bool has_cross_site_ancestor)
36*6777b538SAndroid Build Coastguard Worker     : top_level_site_(site),
37*6777b538SAndroid Build Coastguard Worker       has_cross_site_ancestor_(has_cross_site_ancestor) {}
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker const std::string&
TopLevelSite() const40*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::SerializedCookiePartitionKey::TopLevelSite() const {
41*6777b538SAndroid Build Coastguard Worker   return top_level_site_;
42*6777b538SAndroid Build Coastguard Worker }
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(CRONET_BUILD)
CookiePartitionKey(mojo::DefaultConstruct::Tag)45*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::CookiePartitionKey(mojo::DefaultConstruct::Tag) {}
46*6777b538SAndroid Build Coastguard Worker #endif
has_cross_site_ancestor() const47*6777b538SAndroid Build Coastguard Worker bool CookiePartitionKey::SerializedCookiePartitionKey::has_cross_site_ancestor()
48*6777b538SAndroid Build Coastguard Worker     const {
49*6777b538SAndroid Build Coastguard Worker   return has_cross_site_ancestor_;
50*6777b538SAndroid Build Coastguard Worker }
51*6777b538SAndroid Build Coastguard Worker 
52*6777b538SAndroid Build Coastguard Worker // static
BoolToAncestorChainBit(bool cross_site)53*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::AncestorChainBit CookiePartitionKey::BoolToAncestorChainBit(
54*6777b538SAndroid Build Coastguard Worker     bool cross_site) {
55*6777b538SAndroid Build Coastguard Worker   return cross_site ? AncestorChainBit::kCrossSite
56*6777b538SAndroid Build Coastguard Worker                     : AncestorChainBit::kSameSite;
57*6777b538SAndroid Build Coastguard Worker }
58*6777b538SAndroid Build Coastguard Worker 
CookiePartitionKey(const SchemefulSite & site,std::optional<base::UnguessableToken> nonce,AncestorChainBit ancestor_chain_bit)59*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::CookiePartitionKey(
60*6777b538SAndroid Build Coastguard Worker     const SchemefulSite& site,
61*6777b538SAndroid Build Coastguard Worker     std::optional<base::UnguessableToken> nonce,
62*6777b538SAndroid Build Coastguard Worker     AncestorChainBit ancestor_chain_bit)
63*6777b538SAndroid Build Coastguard Worker     : site_(site), nonce_(nonce), ancestor_chain_bit_(ancestor_chain_bit) {
64*6777b538SAndroid Build Coastguard Worker   if (nonce.has_value()) {
65*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(ancestor_chain_bit, AncestorChainBit::kCrossSite);
66*6777b538SAndroid Build Coastguard Worker   }
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker 
CookiePartitionKey(bool from_script)69*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::CookiePartitionKey(bool from_script)
70*6777b538SAndroid Build Coastguard Worker     : from_script_(from_script) {}
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::CookiePartitionKey(const CookiePartitionKey& other) =
73*6777b538SAndroid Build Coastguard Worker     default;
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::CookiePartitionKey(CookiePartitionKey&& other) = default;
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker CookiePartitionKey& CookiePartitionKey::operator=(
78*6777b538SAndroid Build Coastguard Worker     const CookiePartitionKey& other) = default;
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker CookiePartitionKey& CookiePartitionKey::operator=(CookiePartitionKey&& other) =
81*6777b538SAndroid Build Coastguard Worker     default;
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::~CookiePartitionKey() = default;
84*6777b538SAndroid Build Coastguard Worker 
operator ==(const CookiePartitionKey & other) const85*6777b538SAndroid Build Coastguard Worker bool CookiePartitionKey::operator==(const CookiePartitionKey& other) const {
86*6777b538SAndroid Build Coastguard Worker   AncestorChainBit this_bit = MaybeAncestorChainBit();
87*6777b538SAndroid Build Coastguard Worker   AncestorChainBit other_bit = other.MaybeAncestorChainBit();
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker   return std::tie(site_, nonce_, this_bit) ==
90*6777b538SAndroid Build Coastguard Worker          std::tie(other.site_, other.nonce_, other_bit);
91*6777b538SAndroid Build Coastguard Worker }
92*6777b538SAndroid Build Coastguard Worker 
operator !=(const CookiePartitionKey & other) const93*6777b538SAndroid Build Coastguard Worker bool CookiePartitionKey::operator!=(const CookiePartitionKey& other) const {
94*6777b538SAndroid Build Coastguard Worker   return !(*this == other);
95*6777b538SAndroid Build Coastguard Worker }
96*6777b538SAndroid Build Coastguard Worker 
operator <(const CookiePartitionKey & other) const97*6777b538SAndroid Build Coastguard Worker bool CookiePartitionKey::operator<(const CookiePartitionKey& other) const {
98*6777b538SAndroid Build Coastguard Worker   AncestorChainBit this_bit = MaybeAncestorChainBit();
99*6777b538SAndroid Build Coastguard Worker   AncestorChainBit other_bit = other.MaybeAncestorChainBit();
100*6777b538SAndroid Build Coastguard Worker   return std::tie(site_, nonce_, this_bit) <
101*6777b538SAndroid Build Coastguard Worker          std::tie(other.site_, other.nonce_, other_bit);
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker // static
105*6777b538SAndroid Build Coastguard Worker base::expected<CookiePartitionKey::SerializedCookiePartitionKey, std::string>
Serialize(const std::optional<CookiePartitionKey> & in)106*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::Serialize(const std::optional<CookiePartitionKey>& in) {
107*6777b538SAndroid Build Coastguard Worker   if (!in) {
108*6777b538SAndroid Build Coastguard Worker     return base::ok(
109*6777b538SAndroid Build Coastguard Worker         SerializedCookiePartitionKey(kEmptyCookiePartitionKey, true));
110*6777b538SAndroid Build Coastguard Worker   }
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   if (!in->IsSerializeable()) {
113*6777b538SAndroid Build Coastguard Worker     return WarnAndCreateUnexpected("CookiePartitionKey is not serializeable");
114*6777b538SAndroid Build Coastguard Worker   }
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   return base::ok(SerializedCookiePartitionKey(
117*6777b538SAndroid Build Coastguard Worker       in->site_.GetURL().SchemeIsFile() ? in->site_.SerializeFileSiteWithHost()
118*6777b538SAndroid Build Coastguard Worker                                         : in->site_.Serialize(),
119*6777b538SAndroid Build Coastguard Worker       in->IsThirdParty()));
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker 
FromNetworkIsolationKey(const NetworkIsolationKey & network_isolation_key,SiteForCookies site_for_cookies,SchemefulSite request_site)122*6777b538SAndroid Build Coastguard Worker std::optional<CookiePartitionKey> CookiePartitionKey::FromNetworkIsolationKey(
123*6777b538SAndroid Build Coastguard Worker     const NetworkIsolationKey& network_isolation_key,
124*6777b538SAndroid Build Coastguard Worker     SiteForCookies site_for_cookies,
125*6777b538SAndroid Build Coastguard Worker     SchemefulSite request_site) {
126*6777b538SAndroid Build Coastguard Worker   const std::optional<base::UnguessableToken>& nonce =
127*6777b538SAndroid Build Coastguard Worker       network_isolation_key.GetNonce();
128*6777b538SAndroid Build Coastguard Worker 
129*6777b538SAndroid Build Coastguard Worker   // Use frame site for nonced partitions. Since the nonce is unique, this
130*6777b538SAndroid Build Coastguard Worker   // still creates a unique partition key. The reason we use the frame site is
131*6777b538SAndroid Build Coastguard Worker   // to align CookiePartitionKey's implementation of nonced partitions with
132*6777b538SAndroid Build Coastguard Worker   // StorageKey's. See https://crbug.com/1440765.
133*6777b538SAndroid Build Coastguard Worker   const std::optional<SchemefulSite>& partition_key_site =
134*6777b538SAndroid Build Coastguard Worker       nonce ? network_isolation_key.GetFrameSiteForCookiePartitionKey(
135*6777b538SAndroid Build Coastguard Worker                   NetworkIsolationKey::CookiePartitionKeyPassKey())
136*6777b538SAndroid Build Coastguard Worker             : network_isolation_key.GetTopFrameSite();
137*6777b538SAndroid Build Coastguard Worker   if (!partition_key_site) {
138*6777b538SAndroid Build Coastguard Worker     return std::nullopt;
139*6777b538SAndroid Build Coastguard Worker   }
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker   const auto ancestor_chain_bit =
142*6777b538SAndroid Build Coastguard Worker       (nonce || site_for_cookies.IsNull())
143*6777b538SAndroid Build Coastguard Worker           ? AncestorChainBit::kCrossSite
144*6777b538SAndroid Build Coastguard Worker           : BoolToAncestorChainBit(
145*6777b538SAndroid Build Coastguard Worker                 !site_for_cookies.IsFirstParty(request_site.GetURL()));
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   return CookiePartitionKey(*partition_key_site, nonce, ancestor_chain_bit);
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker 
150*6777b538SAndroid Build Coastguard Worker // static
FromStorageKeyComponents(const SchemefulSite & site,AncestorChainBit ancestor_chain_bit,const std::optional<base::UnguessableToken> & nonce)151*6777b538SAndroid Build Coastguard Worker std::optional<CookiePartitionKey> CookiePartitionKey::FromStorageKeyComponents(
152*6777b538SAndroid Build Coastguard Worker     const SchemefulSite& site,
153*6777b538SAndroid Build Coastguard Worker     AncestorChainBit ancestor_chain_bit,
154*6777b538SAndroid Build Coastguard Worker     const std::optional<base::UnguessableToken>& nonce) {
155*6777b538SAndroid Build Coastguard Worker   return CookiePartitionKey::FromWire(site, ancestor_chain_bit, nonce);
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker 
158*6777b538SAndroid Build Coastguard Worker // static
159*6777b538SAndroid Build Coastguard Worker base::expected<std::optional<CookiePartitionKey>, std::string>
FromStorage(const std::string & top_level_site,bool has_cross_site_ancestor)160*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::FromStorage(const std::string& top_level_site,
161*6777b538SAndroid Build Coastguard Worker                                 bool has_cross_site_ancestor) {
162*6777b538SAndroid Build Coastguard Worker   if (top_level_site == kEmptyCookiePartitionKey) {
163*6777b538SAndroid Build Coastguard Worker     return base::ok(std::nullopt);
164*6777b538SAndroid Build Coastguard Worker   }
165*6777b538SAndroid Build Coastguard Worker 
166*6777b538SAndroid Build Coastguard Worker   base::expected<CookiePartitionKey, std::string> key = DeserializeInternal(
167*6777b538SAndroid Build Coastguard Worker       top_level_site, BoolToAncestorChainBit(has_cross_site_ancestor));
168*6777b538SAndroid Build Coastguard Worker   if (!key.has_value()) {
169*6777b538SAndroid Build Coastguard Worker     DLOG(WARNING) << key.error();
170*6777b538SAndroid Build Coastguard Worker   }
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker   return key;
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker // static
176*6777b538SAndroid Build Coastguard Worker base::expected<CookiePartitionKey, std::string>
FromUntrustedInput(const std::string & top_level_site,bool has_cross_site_ancestor)177*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::FromUntrustedInput(const std::string& top_level_site,
178*6777b538SAndroid Build Coastguard Worker                                        bool has_cross_site_ancestor) {
179*6777b538SAndroid Build Coastguard Worker   if (top_level_site.empty()) {
180*6777b538SAndroid Build Coastguard Worker     return WarnAndCreateUnexpected("top_level_site is unexpectedly empty");
181*6777b538SAndroid Build Coastguard Worker   }
182*6777b538SAndroid Build Coastguard Worker 
183*6777b538SAndroid Build Coastguard Worker   base::expected<CookiePartitionKey, std::string> key = DeserializeInternal(
184*6777b538SAndroid Build Coastguard Worker       top_level_site, BoolToAncestorChainBit(has_cross_site_ancestor));
185*6777b538SAndroid Build Coastguard Worker   if (!key.has_value()) {
186*6777b538SAndroid Build Coastguard Worker     return WarnAndCreateUnexpected(key.error());
187*6777b538SAndroid Build Coastguard Worker   }
188*6777b538SAndroid Build Coastguard Worker   return key;
189*6777b538SAndroid Build Coastguard Worker }
190*6777b538SAndroid Build Coastguard Worker 
191*6777b538SAndroid Build Coastguard Worker base::expected<CookiePartitionKey, std::string>
DeserializeInternal(const std::string & top_level_site,CookiePartitionKey::AncestorChainBit has_cross_site_ancestor)192*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::DeserializeInternal(
193*6777b538SAndroid Build Coastguard Worker     const std::string& top_level_site,
194*6777b538SAndroid Build Coastguard Worker     CookiePartitionKey::AncestorChainBit has_cross_site_ancestor) {
195*6777b538SAndroid Build Coastguard Worker   auto schemeful_site = SchemefulSite::Deserialize(top_level_site);
196*6777b538SAndroid Build Coastguard Worker   if (schemeful_site.opaque()) {
197*6777b538SAndroid Build Coastguard Worker     return WarnAndCreateUnexpected(
198*6777b538SAndroid Build Coastguard Worker         "Cannot deserialize opaque origin to CookiePartitionKey");
199*6777b538SAndroid Build Coastguard Worker   }
200*6777b538SAndroid Build Coastguard Worker   return base::ok(CookiePartitionKey(schemeful_site, std::nullopt,
201*6777b538SAndroid Build Coastguard Worker                                      has_cross_site_ancestor));
202*6777b538SAndroid Build Coastguard Worker }
203*6777b538SAndroid Build Coastguard Worker 
IsSerializeable() const204*6777b538SAndroid Build Coastguard Worker bool CookiePartitionKey::IsSerializeable() const {
205*6777b538SAndroid Build Coastguard Worker   // We should not try to serialize a partition key created by a renderer.
206*6777b538SAndroid Build Coastguard Worker   DCHECK(!from_script_);
207*6777b538SAndroid Build Coastguard Worker   return !site_.opaque() && !nonce_.has_value();
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker 
MaybeAncestorChainBit() const210*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::AncestorChainBit CookiePartitionKey::MaybeAncestorChainBit()
211*6777b538SAndroid Build Coastguard Worker     const {
212*6777b538SAndroid Build Coastguard Worker   return ancestor_chain_enabled_ ? ancestor_chain_bit_
213*6777b538SAndroid Build Coastguard Worker                                  : AncestorChainBit::kCrossSite;
214*6777b538SAndroid Build Coastguard Worker }
215*6777b538SAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const CookiePartitionKey & cpk)216*6777b538SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const CookiePartitionKey& cpk) {
217*6777b538SAndroid Build Coastguard Worker   os << cpk.site();
218*6777b538SAndroid Build Coastguard Worker   if (cpk.nonce().has_value()) {
219*6777b538SAndroid Build Coastguard Worker     os << ",nonced";
220*6777b538SAndroid Build Coastguard Worker   }
221*6777b538SAndroid Build Coastguard Worker   os << (cpk.IsThirdParty() ? ",cross_site" : ",same_site");
222*6777b538SAndroid Build Coastguard Worker   return os;
223*6777b538SAndroid Build Coastguard Worker }
224*6777b538SAndroid Build Coastguard Worker 
225*6777b538SAndroid Build Coastguard Worker }  // namespace net
226