xref: /aosp_15_r20/external/cronet/net/cookies/cookie_partition_key.h (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 #ifndef NET_COOKIES_COOKIE_PARTITION_KEY_H_
6*6777b538SAndroid Build Coastguard Worker #define NET_COOKIES_COOKIE_PARTITION_KEY_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <optional>
9*6777b538SAndroid Build Coastguard Worker #include <string>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/types/expected.h"
12*6777b538SAndroid Build Coastguard Worker #include "net/base/cronet_buildflags.h"
13*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
14*6777b538SAndroid Build Coastguard Worker #include "net/base/net_export.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/base/network_isolation_key.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/base/schemeful_site.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/cookies/site_for_cookies.h"
18*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(CRONET_BUILD)
21*6777b538SAndroid Build Coastguard Worker #include "mojo/public/cpp/bindings/default_construct_tag.h"
22*6777b538SAndroid Build Coastguard Worker #endif
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker namespace net {
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker class NET_EXPORT CookiePartitionKey {
27*6777b538SAndroid Build Coastguard Worker  public:
28*6777b538SAndroid Build Coastguard Worker   class NET_EXPORT SerializedCookiePartitionKey {
29*6777b538SAndroid Build Coastguard Worker    public:
30*6777b538SAndroid Build Coastguard Worker     const std::string& TopLevelSite() const;
31*6777b538SAndroid Build Coastguard Worker     bool has_cross_site_ancestor() const;
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker    private:
34*6777b538SAndroid Build Coastguard Worker     friend class CookiePartitionKey;
35*6777b538SAndroid Build Coastguard Worker     // This constructor does not check if the values being serialized are valid.
36*6777b538SAndroid Build Coastguard Worker     // The caller of this function must ensure that only valid values are passed
37*6777b538SAndroid Build Coastguard Worker     // to this method.
38*6777b538SAndroid Build Coastguard Worker     explicit SerializedCookiePartitionKey(const std::string& site,
39*6777b538SAndroid Build Coastguard Worker                                           bool has_cross_site_ancestor);
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker     std::string top_level_site_;
42*6777b538SAndroid Build Coastguard Worker     bool has_cross_site_ancestor_;
43*6777b538SAndroid Build Coastguard Worker   };
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker   // An enumerated value representing whether any frame in the PartitionKey's
46*6777b538SAndroid Build Coastguard Worker   // ancestor chain (including the top-level document's site) is cross-site with
47*6777b538SAndroid Build Coastguard Worker   // the current frame. These values are persisted to disk. Entries should not
48*6777b538SAndroid Build Coastguard Worker   // be renumbered and numeric values should never be reused.
49*6777b538SAndroid Build Coastguard Worker   enum class AncestorChainBit {
50*6777b538SAndroid Build Coastguard Worker     // All frames in the ancestor chain are pairwise same-site.
51*6777b538SAndroid Build Coastguard Worker     kSameSite = 0,
52*6777b538SAndroid Build Coastguard Worker     // At least one frame in the ancestor chain is cross-site with
53*6777b538SAndroid Build Coastguard Worker     // the current frame.
54*6777b538SAndroid Build Coastguard Worker     kCrossSite = 1,
55*6777b538SAndroid Build Coastguard Worker   };
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker   static AncestorChainBit BoolToAncestorChainBit(bool val);
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker   CookiePartitionKey() = delete;
60*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(CRONET_BUILD)
61*6777b538SAndroid Build Coastguard Worker   explicit CookiePartitionKey(mojo::DefaultConstruct::Tag);
62*6777b538SAndroid Build Coastguard Worker #endif
63*6777b538SAndroid Build Coastguard Worker   CookiePartitionKey(const CookiePartitionKey& other);
64*6777b538SAndroid Build Coastguard Worker   CookiePartitionKey(CookiePartitionKey&& other);
65*6777b538SAndroid Build Coastguard Worker   CookiePartitionKey& operator=(const CookiePartitionKey& other);
66*6777b538SAndroid Build Coastguard Worker   CookiePartitionKey& operator=(CookiePartitionKey&& other);
67*6777b538SAndroid Build Coastguard Worker   ~CookiePartitionKey();
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker   bool operator==(const CookiePartitionKey& other) const;
70*6777b538SAndroid Build Coastguard Worker   bool operator!=(const CookiePartitionKey& other) const;
71*6777b538SAndroid Build Coastguard Worker   bool operator<(const CookiePartitionKey& other) const;
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker   // Methods for serializing and deserializing a partition key to/from a string.
74*6777b538SAndroid Build Coastguard Worker   // This is currently used for:
75*6777b538SAndroid Build Coastguard Worker   // -  Storing persistent partitioned cookies
76*6777b538SAndroid Build Coastguard Worker   // -  Loading partitioned cookies into Java code
77*6777b538SAndroid Build Coastguard Worker   // -  Sending cookie partition keys as strings in the DevTools protocol
78*6777b538SAndroid Build Coastguard Worker   //
79*6777b538SAndroid Build Coastguard Worker   // This function returns true if the partition key is not opaque and if nonce_
80*6777b538SAndroid Build Coastguard Worker   // is not present. We do not want to serialize cookies with opaque origins or
81*6777b538SAndroid Build Coastguard Worker   // nonce in their partition key to disk, because if the browser session ends
82*6777b538SAndroid Build Coastguard Worker   // we will not be able to attach the saved cookie to any future requests. This
83*6777b538SAndroid Build Coastguard Worker   // is because opaque origins' nonces are only stored in volatile memory.
84*6777b538SAndroid Build Coastguard Worker   //
85*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1225444) Investigate ways to persist partition keys with
86*6777b538SAndroid Build Coastguard Worker   // opaque origins if a browser session is restored.
87*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] static base::expected<SerializedCookiePartitionKey, std::string>
88*6777b538SAndroid Build Coastguard Worker   Serialize(const std::optional<CookiePartitionKey>& in);
89*6777b538SAndroid Build Coastguard Worker 
90*6777b538SAndroid Build Coastguard Worker   static CookiePartitionKey FromURLForTesting(
91*6777b538SAndroid Build Coastguard Worker       const GURL& url,
92*6777b538SAndroid Build Coastguard Worker       AncestorChainBit ancestor_chain_bit = AncestorChainBit::kCrossSite,
93*6777b538SAndroid Build Coastguard Worker       std::optional<base::UnguessableToken> nonce = std::nullopt) {
94*6777b538SAndroid Build Coastguard Worker     return CookiePartitionKey(SchemefulSite(url), nonce, ancestor_chain_bit);
95*6777b538SAndroid Build Coastguard Worker   }
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker   // Create a partition key from a network isolation key. Partition key is
98*6777b538SAndroid Build Coastguard Worker   // derived from the key's top-frame site. For scripts, the request_site
99*6777b538SAndroid Build Coastguard Worker   // is the url of the context running the code.
100*6777b538SAndroid Build Coastguard Worker   static std::optional<CookiePartitionKey> FromNetworkIsolationKey(
101*6777b538SAndroid Build Coastguard Worker       const NetworkIsolationKey& network_isolation_key,
102*6777b538SAndroid Build Coastguard Worker       SiteForCookies site_for_cookies,
103*6777b538SAndroid Build Coastguard Worker       SchemefulSite request_site);
104*6777b538SAndroid Build Coastguard Worker 
105*6777b538SAndroid Build Coastguard Worker   // Create a new CookiePartitionKey from the site of an existing
106*6777b538SAndroid Build Coastguard Worker   // CookiePartitionKey. This should only be used for sites of partition keys
107*6777b538SAndroid Build Coastguard Worker   // which were already created using Deserialize or FromNetworkIsolationKey.
108*6777b538SAndroid Build Coastguard Worker   static CookiePartitionKey FromWire(
109*6777b538SAndroid Build Coastguard Worker       const SchemefulSite& site,
110*6777b538SAndroid Build Coastguard Worker       AncestorChainBit ancestor_chain_bit,
111*6777b538SAndroid Build Coastguard Worker       std::optional<base::UnguessableToken> nonce = std::nullopt) {
112*6777b538SAndroid Build Coastguard Worker     return CookiePartitionKey(site, nonce, ancestor_chain_bit);
113*6777b538SAndroid Build Coastguard Worker   }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker   // Create a new CookiePartitionKey in a script running in a renderer. We do
116*6777b538SAndroid Build Coastguard Worker   // not trust the renderer to provide us with a cookie partition key, so we let
117*6777b538SAndroid Build Coastguard Worker   // the renderer use this method to indicate the cookie is partitioned but the
118*6777b538SAndroid Build Coastguard Worker   // key still needs to be determined.
119*6777b538SAndroid Build Coastguard Worker   //
120*6777b538SAndroid Build Coastguard Worker   // When the browser is ingesting cookie partition keys from the renderer,
121*6777b538SAndroid Build Coastguard Worker   // either the `from_script_` flag should be set or the cookie partition key
122*6777b538SAndroid Build Coastguard Worker   // should match the browser's. Otherwise the renderer may be compromised.
123*6777b538SAndroid Build Coastguard Worker   //
124*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1225444) Consider removing this factory method and
125*6777b538SAndroid Build Coastguard Worker   // `from_script_` flag when BlinkStorageKey is available in
126*6777b538SAndroid Build Coastguard Worker   // ServiceWorkerGlobalScope.
FromScript()127*6777b538SAndroid Build Coastguard Worker   static std::optional<CookiePartitionKey> FromScript() {
128*6777b538SAndroid Build Coastguard Worker     return std::make_optional(CookiePartitionKey(true));
129*6777b538SAndroid Build Coastguard Worker   }
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker   // Create a new CookiePartitionKey from the components of a StorageKey.
132*6777b538SAndroid Build Coastguard Worker   // Forwards to FromWire, but unlike that method in this one the optional nonce
133*6777b538SAndroid Build Coastguard Worker   // argument has no default. It also checks that cookie partitioning is enabled
134*6777b538SAndroid Build Coastguard Worker   // before returning a valid key, which FromWire does not check.
135*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] static std::optional<CookiePartitionKey>
136*6777b538SAndroid Build Coastguard Worker   FromStorageKeyComponents(const SchemefulSite& top_level_site,
137*6777b538SAndroid Build Coastguard Worker                            AncestorChainBit ancestor_chain_bit,
138*6777b538SAndroid Build Coastguard Worker                            const std::optional<base::UnguessableToken>& nonce);
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker   // FromStorage is a factory method which is meant for creating a new
141*6777b538SAndroid Build Coastguard Worker   // CookiePartitionKey using properties of a previously existing
142*6777b538SAndroid Build Coastguard Worker   // CookiePartitionKey that was already ingested into storage. This should NOT
143*6777b538SAndroid Build Coastguard Worker   // be used to create a new CookiePartitionKey that was not previously saved in
144*6777b538SAndroid Build Coastguard Worker   // storage.
145*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] static base::expected<std::optional<CookiePartitionKey>,
146*6777b538SAndroid Build Coastguard Worker                                       std::string>
147*6777b538SAndroid Build Coastguard Worker   FromStorage(const std::string& top_level_site, bool has_cross_site_ancestor);
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker   // This method should be used when the data provided is expected to be
150*6777b538SAndroid Build Coastguard Worker   // non-null but might be invalid or comes from a potentially untrustworthy
151*6777b538SAndroid Build Coastguard Worker   // source (such as user-supplied data).
152*6777b538SAndroid Build Coastguard Worker   //
153*6777b538SAndroid Build Coastguard Worker   // This reserves FromStorage to handle cases that can result in a null key
154*6777b538SAndroid Build Coastguard Worker   // (and perfectly validly, like in the case when the top_level_site is empty).
155*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] static base::expected<CookiePartitionKey, std::string>
156*6777b538SAndroid Build Coastguard Worker   FromUntrustedInput(const std::string& top_level_site,
157*6777b538SAndroid Build Coastguard Worker                      bool has_cross_site_ancestor);
158*6777b538SAndroid Build Coastguard Worker 
site()159*6777b538SAndroid Build Coastguard Worker   const SchemefulSite& site() const { return site_; }
160*6777b538SAndroid Build Coastguard Worker 
from_script()161*6777b538SAndroid Build Coastguard Worker   bool from_script() const { return from_script_; }
162*6777b538SAndroid Build Coastguard Worker 
163*6777b538SAndroid Build Coastguard Worker   // Returns true if the current partition key can be serialized to a string.
164*6777b538SAndroid Build Coastguard Worker   // Cookie partition keys whose internal site is opaque cannot be serialized.
165*6777b538SAndroid Build Coastguard Worker   bool IsSerializeable() const;
166*6777b538SAndroid Build Coastguard Worker 
nonce()167*6777b538SAndroid Build Coastguard Worker   const std::optional<base::UnguessableToken>& nonce() const { return nonce_; }
168*6777b538SAndroid Build Coastguard Worker 
HasNonce(const std::optional<CookiePartitionKey> & key)169*6777b538SAndroid Build Coastguard Worker   static bool HasNonce(const std::optional<CookiePartitionKey>& key) {
170*6777b538SAndroid Build Coastguard Worker     return key && key->nonce();
171*6777b538SAndroid Build Coastguard Worker   }
172*6777b538SAndroid Build Coastguard Worker 
IsThirdParty()173*6777b538SAndroid Build Coastguard Worker   bool IsThirdParty() const {
174*6777b538SAndroid Build Coastguard Worker     return ancestor_chain_bit_ == AncestorChainBit::kCrossSite;
175*6777b538SAndroid Build Coastguard Worker   }
176*6777b538SAndroid Build Coastguard Worker 
177*6777b538SAndroid Build Coastguard Worker  private:
178*6777b538SAndroid Build Coastguard Worker   explicit CookiePartitionKey(const SchemefulSite& site,
179*6777b538SAndroid Build Coastguard Worker                               std::optional<base::UnguessableToken> nonce,
180*6777b538SAndroid Build Coastguard Worker                               AncestorChainBit ancestor_chain_bit);
181*6777b538SAndroid Build Coastguard Worker   explicit CookiePartitionKey(bool from_script);
182*6777b538SAndroid Build Coastguard Worker 
183*6777b538SAndroid Build Coastguard Worker   // This method holds the deserialization logic for validating input from
184*6777b538SAndroid Build Coastguard Worker   // DeserializeForTesting and FromUntrustedInput which can be used to pass
185*6777b538SAndroid Build Coastguard Worker   // unserializable top_level_site values.
186*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] static base::expected<CookiePartitionKey, std::string>
187*6777b538SAndroid Build Coastguard Worker   DeserializeInternal(
188*6777b538SAndroid Build Coastguard Worker       const std::string& top_level_site,
189*6777b538SAndroid Build Coastguard Worker       CookiePartitionKey::AncestorChainBit has_cross_site_ancestor);
190*6777b538SAndroid Build Coastguard Worker 
191*6777b538SAndroid Build Coastguard Worker   AncestorChainBit MaybeAncestorChainBit() const;
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker   SchemefulSite site_;
194*6777b538SAndroid Build Coastguard Worker   bool from_script_ = false;
195*6777b538SAndroid Build Coastguard Worker   // crbug.com/328043119 remove code associated with
196*6777b538SAndroid Build Coastguard Worker   // kAncestorChainBitEnabledInPartitionedCookies
197*6777b538SAndroid Build Coastguard Worker   //  when feature is no longer needed.
198*6777b538SAndroid Build Coastguard Worker   bool ancestor_chain_enabled_ = base::FeatureList::IsEnabled(
199*6777b538SAndroid Build Coastguard Worker       features::kAncestorChainBitEnabledInPartitionedCookies);
200*6777b538SAndroid Build Coastguard Worker 
201*6777b538SAndroid Build Coastguard Worker   // Having a nonce is a way to force a transient opaque `CookiePartitionKey`
202*6777b538SAndroid Build Coastguard Worker   // for non-opaque origins.
203*6777b538SAndroid Build Coastguard Worker   std::optional<base::UnguessableToken> nonce_;
204*6777b538SAndroid Build Coastguard Worker   AncestorChainBit ancestor_chain_bit_ = AncestorChainBit::kCrossSite;
205*6777b538SAndroid Build Coastguard Worker };
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker // Used so that CookiePartitionKeys can be the arguments of DCHECK_EQ.
208*6777b538SAndroid Build Coastguard Worker NET_EXPORT std::ostream& operator<<(std::ostream& os,
209*6777b538SAndroid Build Coastguard Worker                                     const CookiePartitionKey& cpk);
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker }  // namespace net
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker #endif  // NET_COOKIES_COOKIE_PARTITION_KEY_H_
214