[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
blundell | 0b2305c | 2015-08-25 15:54:42 | [diff] [blame] | 5 | #ifndef COMPONENTS_VARIATIONS_VARIATIONS_SEED_STORE_H_ |
| 6 | #define COMPONENTS_VARIATIONS_VARIATIONS_SEED_STORE_H_ |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 7 | |
Paul Miller | 49eebb8 | 2018-06-14 04:11:08 | [diff] [blame] | 8 | #include <memory> |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 9 | #include <string> |
| 10 | |
Paul Miller | 33a495e | 2018-09-29 04:35:02 | [diff] [blame] | 11 | #include "base/callback.h" |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 12 | #include "base/compiler_specific.h" |
[email protected] | c69b6c1 | 2014-03-07 20:32:36 | [diff] [blame] | 13 | #include "base/gtest_prod_util.h" |
avi | 5dd91f8 | 2015-12-25 22:30:46 | [diff] [blame] | 14 | #include "base/macros.h" |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 15 | #include "base/time/time.h" |
avi | 5dd91f8 | 2015-12-25 22:30:46 | [diff] [blame] | 16 | #include "build/build_config.h" |
isherman | 5f556b5 | 2017-06-14 16:27:23 | [diff] [blame] | 17 | #include "components/variations/metrics.h" |
Paul Miller | 49eebb8 | 2018-06-14 04:11:08 | [diff] [blame] | 18 | #include "components/variations/seed_response.h" |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 19 | |
| 20 | class PrefService; |
| 21 | class PrefRegistrySimple; |
| 22 | |
[email protected] | 59b6f67 | 2014-07-26 18:35:47 | [diff] [blame] | 23 | namespace variations { |
[email protected] | 59b6f67 | 2014-07-26 18:35:47 | [diff] [blame] | 24 | |
Ilya Sherman | 3231a20 | 2018-01-13 05:15:01 | [diff] [blame] | 25 | struct ClientFilterableState; |
isherman | b1917aabe | 2017-06-13 23:35:14 | [diff] [blame] | 26 | class VariationsSeed; |
[email protected] | 24afce1 | 2014-07-25 21:00:31 | [diff] [blame] | 27 | |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 28 | // VariationsSeedStore is a helper class for reading and writing the variations |
| 29 | // seed from Local State. |
| 30 | class VariationsSeedStore { |
| 31 | public: |
| 32 | explicit VariationsSeedStore(PrefService* local_state); |
Paul Miller | 49eebb8 | 2018-06-14 04:11:08 | [diff] [blame] | 33 | // |initial_seed| may be null. If not null, then it will be stored in this |
| 34 | // seed store. This is used by Android Chrome to supply the first run seed, |
| 35 | // and by Android WebView to supply the seed on every run. |
Paul Miller | 33a495e | 2018-09-29 04:35:02 | [diff] [blame] | 36 | // |on_initial_seed_stored| will be called the first time a seed is stored. |
Paul Miller | 49eebb8 | 2018-06-14 04:11:08 | [diff] [blame] | 37 | VariationsSeedStore(PrefService* local_state, |
Paul Miller | 33a495e | 2018-09-29 04:35:02 | [diff] [blame] | 38 | std::unique_ptr<SeedResponse> initial_seed, |
| 39 | base::OnceCallback<void()> on_initial_seed_stored); |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 40 | virtual ~VariationsSeedStore(); |
| 41 | |
Ilya Sherman | 3231a20 | 2018-01-13 05:15:01 | [diff] [blame] | 42 | // Loads the variations seed data from local state into |seed|, as well as the |
| 43 | // raw pref values into |seed_data| and |base64_signature|. If there is a |
| 44 | // problem with loading, clears the seed pref value and returns false. If |
| 45 | // successful, fills the the outparams with the loaded data and returns true. |
Ilya Sherman | 9534f1d | 2018-01-24 04:02:20 | [diff] [blame] | 46 | // Virtual for testing. |
| 47 | virtual bool LoadSeed(VariationsSeed* seed, |
| 48 | std::string* seed_data, |
| 49 | std::string* base64_seed_signature) WARN_UNUSED_RESULT; |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 50 | |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 51 | // Stores the given seed |data| (serialized protobuf) to local state, along |
[email protected] | 54af732e | 2014-01-23 22:20:39 | [diff] [blame] | 52 | // with a base64-encoded digital signature for seed and the date when it was |
veranika | f6acefe76 | 2015-10-19 16:37:56 | [diff] [blame] | 53 | // fetched. If |is_gzip_compressed| is true, treats |data| as being gzip |
| 54 | // compressed and decompresses it before any other processing. |
| 55 | // If |is_delta_compressed| is true, treats |data| as being delta |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 56 | // compressed and attempts to decode it first using the store's seed data. |
| 57 | // The actual seed data will be base64 encoded for storage. If the string |
| 58 | // is invalid, the existing prefs are untouched and false is returned. |
| 59 | // Additionally, stores the |country_code| that was received with the seed in |
| 60 | // a separate pref. On success and if |parsed_seed| is not NULL, |parsed_seed| |
| 61 | // will be filled with the de-serialized decoded protobuf. |
| 62 | bool StoreSeedData(const std::string& data, |
[email protected] | 54af732e | 2014-01-23 22:20:39 | [diff] [blame] | 63 | const std::string& base64_seed_signature, |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 64 | const std::string& country_code, |
[email protected] | 6839813b | 2014-05-12 22:49:40 | [diff] [blame] | 65 | const base::Time& date_fetched, |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 66 | bool is_delta_compressed, |
veranika | f6acefe76 | 2015-10-19 16:37:56 | [diff] [blame] | 67 | bool is_gzip_compressed, |
Carlos IL | f8472f5f | 2017-12-19 03:23:26 | [diff] [blame] | 68 | bool fetched_insecurely, |
isherman | 5f556b5 | 2017-06-14 16:27:23 | [diff] [blame] | 69 | VariationsSeed* parsed_seed) WARN_UNUSED_RESULT; |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 70 | |
Ilya Sherman | e3b22a6 | 2018-01-22 06:10:21 | [diff] [blame] | 71 | // Loads the safe variations seed data from local state into |seed| and |
Ilya Sherman | 279eff3 | 2018-01-31 04:28:32 | [diff] [blame] | 72 | // updates any relevant fields in |client_state| and stores the |
| 73 | // |seed_fetch_time|. Returns true iff the safe seed was read successfully |
| 74 | // from prefs. If the safe seed could not be loaded, it is guaranteed that no |
| 75 | // fields in |client_state| are modified. |
Ilya Sherman | e3b22a6 | 2018-01-22 06:10:21 | [diff] [blame] | 76 | // Side-effect: Upon any failure to read or validate the safe seed, clears all |
| 77 | // of the safe seed pref values. This occurs iff the method returns false. |
Ilya Sherman | 9534f1d | 2018-01-24 04:02:20 | [diff] [blame] | 78 | // Virtual for testing. |
| 79 | virtual bool LoadSafeSeed(VariationsSeed* seed, |
Ilya Sherman | 279eff3 | 2018-01-31 04:28:32 | [diff] [blame] | 80 | ClientFilterableState* client_state, |
| 81 | base::Time* seed_fetch_time) WARN_UNUSED_RESULT; |
Ilya Sherman | e3b22a6 | 2018-01-22 06:10:21 | [diff] [blame] | 82 | |
Ilya Sherman | 3231a20 | 2018-01-13 05:15:01 | [diff] [blame] | 83 | // Stores the given |seed_data| (a serialized protobuf) to local state as a |
| 84 | // safe seed, along with a base64-encoded digital signature for seed and any |
| 85 | // additional client metadata relevant to the safe seed. Returns true on |
| 86 | // success or false on failure; no prefs are updated in case of failure. |
| 87 | // Virtual for testing. |
| 88 | virtual bool StoreSafeSeed(const std::string& seed_data, |
| 89 | const std::string& base64_seed_signature, |
Ilya Sherman | 279eff3 | 2018-01-31 04:28:32 | [diff] [blame] | 90 | const ClientFilterableState& client_state, |
| 91 | base::Time seed_fetch_time); |
| 92 | |
| 93 | // Loads the last fetch time (for the latest seed) that was persisted to the |
| 94 | // store. |
| 95 | base::Time GetLastFetchTime() const; |
| 96 | |
Robbie McElrath | 27890f1 | 2019-10-16 17:25:59 | [diff] [blame] | 97 | // Records |fetch_time| as the last time at which a seed was fetched |
Ilya Sherman | 279eff3 | 2018-01-31 04:28:32 | [diff] [blame] | 98 | // successfully. Also updates the safe seed's fetch time if the latest and |
| 99 | // safe seeds are identical. |
Robbie McElrath | 27890f1 | 2019-10-16 17:25:59 | [diff] [blame] | 100 | void RecordLastFetchTime(base::Time fetch_time); |
Ilya Sherman | 3231a20 | 2018-01-13 05:15:01 | [diff] [blame] | 101 | |
[email protected] | 344c623a | 2014-03-11 20:29:39 | [diff] [blame] | 102 | // Updates |kVariationsSeedDate| and logs when previous date was from a |
| 103 | // different day. |
| 104 | void UpdateSeedDateAndLogDayChange(const base::Time& server_date_fetched); |
| 105 | |
veranika | f6acefe76 | 2015-10-19 16:37:56 | [diff] [blame] | 106 | // Reports to UMA that the seed format specified by the server is unsupported. |
| 107 | void ReportUnsupportedSeedFormatError(); |
| 108 | |
Ilya Sherman | c70363ec | 2018-01-17 05:51:57 | [diff] [blame] | 109 | // Returns the serial number of the most recently received seed, or an empty |
| 110 | // string if there is no seed (or if it could not be read). |
| 111 | // Side-effect: If there is a failure while attempting to read the latest seed |
| 112 | // from prefs, clears the prefs associated with the seed. |
| 113 | // Efficiency note: If code will eventually need to load the latest seed, it's |
| 114 | // more efficient to call LoadSeed() prior to calling this method. |
| 115 | const std::string& GetLatestSerialNumber(); |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 116 | |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 117 | // Registers Local State prefs used by this class. |
| 118 | static void RegisterPrefs(PrefRegistrySimple* registry); |
| 119 | |
Kyle Milka | 3aababd | 2017-07-20 19:01:32 | [diff] [blame] | 120 | PrefService* local_state() { return local_state_; } |
Kyle Milka | 3aababd | 2017-07-20 19:01:32 | [diff] [blame] | 121 | const PrefService* local_state() const { return local_state_; } |
| 122 | |
[email protected] | c69b6c1 | 2014-03-07 20:32:36 | [diff] [blame] | 123 | protected: |
isherman | 5f556b5 | 2017-06-14 16:27:23 | [diff] [blame] | 124 | // Whether signature verification is enabled. Overridable for tests. |
| 125 | virtual bool SignatureVerificationEnabled(); |
[email protected] | c69b6c1 | 2014-03-07 20:32:36 | [diff] [blame] | 126 | |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 127 | private: |
[email protected] | c69b6c1 | 2014-03-07 20:32:36 | [diff] [blame] | 128 | FRIEND_TEST_ALL_PREFIXES(VariationsSeedStoreTest, VerifySeedSignature); |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 129 | FRIEND_TEST_ALL_PREFIXES(VariationsSeedStoreTest, ApplyDeltaPatch); |
[email protected] | c69b6c1 | 2014-03-07 20:32:36 | [diff] [blame] | 130 | |
Ilya Sherman | 3231a20 | 2018-01-13 05:15:01 | [diff] [blame] | 131 | // The seed store contains two distinct seeds: |
| 132 | // (1) The most recently fetched, or "latest", seed; and |
| 133 | // (2) A "safe" seed, which has been observed to keep Chrome in a basically |
| 134 | // functional state. In particular, a safe seed is one that allows |
| 135 | // Chrome to receive new seed updates from the server. |
| 136 | // Note that it's possible for both seeds to be empty, and it's possible for |
| 137 | // the two seeds to be identical in their contents. |
| 138 | enum class SeedType { |
| 139 | LATEST, |
| 140 | SAFE, |
| 141 | }; |
| 142 | |
Ilya Sherman | e3b22a6 | 2018-01-22 06:10:21 | [diff] [blame] | 143 | // Clears all prefs related to variations seed storage for the specified seed |
| 144 | // type. |
| 145 | void ClearPrefs(SeedType seed_type); |
[email protected] | 54af732e | 2014-01-23 22:20:39 | [diff] [blame] | 146 | |
agulenko | 25d2111a | 2015-11-05 05:16:16 | [diff] [blame] | 147 | #if defined(OS_ANDROID) |
Paul Miller | 49eebb8 | 2018-06-14 04:11:08 | [diff] [blame] | 148 | // Imports the variations seed from the Java side. Logs UMA on failure. |
| 149 | // Android Chrome uses this on first run; WebView uses this on every startup. |
| 150 | // In Chrome's case, it's important to set the first run seed as soon as |
| 151 | // possible, because some clients query the seed store prefs directly rather |
| 152 | // than accessing them via the seed store API: https://crbug.com/829527 |
| 153 | void ImportInitialSeed(std::unique_ptr<SeedResponse> initial_seed); |
agulenko | 25d2111a | 2015-11-05 05:16:16 | [diff] [blame] | 154 | #endif // OS_ANDROID |
| 155 | |
Ilya Sherman | e3b22a6 | 2018-01-22 06:10:21 | [diff] [blame] | 156 | // Loads the variations seed data from local state into |seed|, as well as the |
| 157 | // raw pref values into |seed_data| and |base64_signature|. Loads either the |
| 158 | // safe seed or the latest seed, according to the |seed_type|. Returns whether |
| 159 | // loading the seed was successful. |
| 160 | // Side-effect: Upon any failure to read or validate the safe seed, clears all |
| 161 | // of the pref values for the seed. This occurs iff the method returns false. |
| 162 | LoadSeedResult LoadSeedImpl(SeedType seed_type, |
| 163 | VariationsSeed* seed, |
| 164 | std::string* seed_data, |
| 165 | std::string* base64_seed_signature) |
| 166 | WARN_UNUSED_RESULT; |
| 167 | |
isherman | 5f556b5 | 2017-06-14 16:27:23 | [diff] [blame] | 168 | // Reads the variations seed data from prefs into |seed_data|, and returns the |
| 169 | // result of the load. The value stored into |seed_data| should only be used |
Ilya Sherman | e3b22a6 | 2018-01-22 06:10:21 | [diff] [blame] | 170 | // if the result is SUCCESS. Reads either the latest or the safe seed, |
| 171 | // according to the specified |seed_type|. |
isherman | 5f556b5 | 2017-06-14 16:27:23 | [diff] [blame] | 172 | // Side-effect: If the read fails, clears the prefs associated with the seed. |
Ilya Sherman | e3b22a6 | 2018-01-22 06:10:21 | [diff] [blame] | 173 | LoadSeedResult ReadSeedData(SeedType seed_type, |
| 174 | std::string* seed_data) WARN_UNUSED_RESULT; |
asvitkine | 5ea32c5 | 2015-02-12 01:23:11 | [diff] [blame] | 175 | |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 176 | // Internal version of |StoreSeedData()| that assumes |seed_data| is not delta |
| 177 | // compressed. |
isherman | b1917aabe | 2017-06-13 23:35:14 | [diff] [blame] | 178 | bool StoreSeedDataNoDelta(const std::string& seed_data, |
| 179 | const std::string& base64_seed_signature, |
| 180 | const std::string& country_code, |
| 181 | const base::Time& date_fetched, |
Carlos IL | f8472f5f | 2017-12-19 03:23:26 | [diff] [blame] | 182 | bool fetched_insecurely, |
isherman | 5f556b5 | 2017-06-14 16:27:23 | [diff] [blame] | 183 | VariationsSeed* parsed_seed) WARN_UNUSED_RESULT; |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 184 | |
Ilya Sherman | 3231a20 | 2018-01-13 05:15:01 | [diff] [blame] | 185 | // Validates the |seed_data|, comparing it (if enabled) against the provided |
| 186 | // cryptographic signature. Returns the result of the operation. On success, |
| 187 | // fills |base64_seed_data| with the compressed and base64-encoded seed data; |
| 188 | // and if |parsed_seed| is non-null, fills it with the parsed seed data. |
| 189 | // |fetched_insecurely| indicates whether |seed_data| was just fetched from |
| 190 | // the server over an insecure channel (i.e. over HTTP rathern than HTTPS). |
| 191 | // |seed_type| specifies whether |seed_data| is for the safe seed (vs. the |
| 192 | // regular/normal seed). |
| 193 | StoreSeedResult VerifyAndCompressSeedData( |
| 194 | const std::string& seed_data, |
| 195 | const std::string& base64_seed_signature, |
| 196 | bool fetched_insecurely, |
| 197 | SeedType seed_type, |
| 198 | std::string* base64_seed_data, |
| 199 | VariationsSeed* parsed_seed) WARN_UNUSED_RESULT; |
| 200 | |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 201 | // Applies a delta-compressed |patch| to |existing_data|, producing the result |
| 202 | // in |output|. Returns whether the operation was successful. |
| 203 | static bool ApplyDeltaPatch(const std::string& existing_data, |
| 204 | const std::string& patch, |
isherman | 5f556b5 | 2017-06-14 16:27:23 | [diff] [blame] | 205 | std::string* output) WARN_UNUSED_RESULT; |
asvitkine | b24f4559 | 2015-08-07 02:57:25 | [diff] [blame] | 206 | |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 207 | // The pref service used to persist the variations seed. |
| 208 | PrefService* local_state_; |
| 209 | |
| 210 | // Cached serial number from the most recently fetched variations seed. |
Ilya Sherman | c70363ec | 2018-01-17 05:51:57 | [diff] [blame] | 211 | std::string latest_serial_number_; |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 212 | |
Paul Miller | 33a495e | 2018-09-29 04:35:02 | [diff] [blame] | 213 | base::OnceCallback<void()> on_initial_seed_stored_; |
| 214 | |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 215 | DISALLOW_COPY_AND_ASSIGN(VariationsSeedStore); |
| 216 | }; |
| 217 | |
blundell | 57bcfed | 2015-09-04 08:44:45 | [diff] [blame] | 218 | } // namespace variations |
[email protected] | 1df24d0a | 2014-01-20 21:29:59 | [diff] [blame] | 219 | |
blundell | 0b2305c | 2015-08-25 15:54:42 | [diff] [blame] | 220 | #endif // COMPONENTS_VARIATIONS_VARIATIONS_SEED_STORE_H_ |