Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: components/user_prefs/tracked/pref_hash_store_impl.cc

Issue 2782803002: Move tracked prefs into services/preferences/tracked. (Closed)
Patch Set: rebase Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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
5 #include "components/user_prefs/tracked/pref_hash_store_impl.h"
6
7 #include <stddef.h>
8 #include <utility>
9
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "components/user_prefs/tracked/device_id.h"
14 #include "components/user_prefs/tracked/hash_store_contents.h"
15
16 namespace {
17
18 // Returns a deterministic ID for this machine.
19 std::string GenerateDeviceId() {
20 static std::string cached_device_id;
21 if (!cached_device_id.empty())
22 return cached_device_id;
23
24 std::string device_id;
25 MachineIdStatus status = GetDeterministicMachineSpecificId(&device_id);
26 if (status != MachineIdStatus::NOT_IMPLEMENTED) {
27 // TODO(proberge): Remove this histogram once we validate that machine id
28 // generation is not flaky and consider adding a CHECK or DCHECK.
29 UMA_HISTOGRAM_BOOLEAN("Settings.MachineIdGenerationSuccess",
30 status == MachineIdStatus::SUCCESS);
31 }
32
33 if (status == MachineIdStatus::SUCCESS) {
34 cached_device_id = device_id;
35 return device_id;
36 }
37
38 return std::string();
39 }
40
41 } // namespace
42
43 class PrefHashStoreImpl::PrefHashStoreTransactionImpl
44 : public PrefHashStoreTransaction {
45 public:
46 // Constructs a PrefHashStoreTransactionImpl which can use the private
47 // members of its |outer| PrefHashStoreImpl.
48 PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer,
49 HashStoreContents* storage);
50 ~PrefHashStoreTransactionImpl() override;
51
52 // PrefHashStoreTransaction implementation.
53 base::StringPiece GetStoreUMASuffix() const override;
54 ValueState CheckValue(const std::string& path,
55 const base::Value* value) const override;
56 void StoreHash(const std::string& path, const base::Value* value) override;
57 ValueState CheckSplitValue(
58 const std::string& path,
59 const base::DictionaryValue* initial_split_value,
60 std::vector<std::string>* invalid_keys) const override;
61 void StoreSplitHash(const std::string& path,
62 const base::DictionaryValue* split_value) override;
63 bool HasHash(const std::string& path) const override;
64 void ImportHash(const std::string& path, const base::Value* hash) override;
65 void ClearHash(const std::string& path) override;
66 bool IsSuperMACValid() const override;
67 bool StampSuperMac() override;
68
69 private:
70 PrefHashStoreImpl* outer_;
71 HashStoreContents* contents_;
72
73 bool super_mac_valid_;
74 bool super_mac_dirty_;
75
76 DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl);
77 };
78
79 PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
80 const std::string& legacy_device_id,
81 bool use_super_mac)
82 : pref_hash_calculator_(seed, GenerateDeviceId(), legacy_device_id),
83 use_super_mac_(use_super_mac) {}
84
85 PrefHashStoreImpl::~PrefHashStoreImpl() {
86 }
87
88 std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
89 HashStoreContents* storage) {
90 return std::unique_ptr<PrefHashStoreTransaction>(
91 new PrefHashStoreTransactionImpl(this, std::move(storage)));
92 }
93
94 std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
95 const base::Value* value) {
96 return pref_hash_calculator_.Calculate(path, value);
97 }
98
99 std::unique_ptr<base::DictionaryValue> PrefHashStoreImpl::ComputeSplitMacs(
100 const std::string& path,
101 const base::DictionaryValue* split_values) {
102 DCHECK(split_values);
103
104 std::string keyed_path(path);
105 keyed_path.push_back('.');
106 const size_t common_part_length = keyed_path.length();
107
108 std::unique_ptr<base::DictionaryValue> split_macs(new base::DictionaryValue);
109
110 for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
111 it.Advance()) {
112 // Keep the common part from the old |keyed_path| and replace the key to
113 // get the new |keyed_path|.
114 keyed_path.replace(common_part_length, std::string::npos, it.key());
115
116 split_macs->SetStringWithoutPathExpansion(
117 it.key(), ComputeMac(keyed_path, &it.value()));
118 }
119
120 return split_macs;
121 }
122
123 PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
124 PrefHashStoreImpl* outer,
125 HashStoreContents* storage)
126 : outer_(outer),
127 contents_(std::move(storage)),
128 super_mac_valid_(false),
129 super_mac_dirty_(false) {
130 if (!outer_->use_super_mac_)
131 return;
132
133 // The store must have a valid super MAC to be trusted.
134 std::string super_mac = contents_->GetSuperMac();
135 if (super_mac.empty())
136 return;
137
138 super_mac_valid_ =
139 outer_->pref_hash_calculator_.Validate(
140 "", contents_->GetContents(), super_mac) == PrefHashCalculator::VALID;
141 }
142
143 PrefHashStoreImpl::PrefHashStoreTransactionImpl::
144 ~PrefHashStoreTransactionImpl() {
145 if (super_mac_dirty_ && outer_->use_super_mac_) {
146 // Get the dictionary of hashes (or NULL if it doesn't exist).
147 const base::DictionaryValue* hashes_dict = contents_->GetContents();
148 contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict));
149 }
150 }
151
152 base::StringPiece
153 PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const {
154 return contents_->GetUMASuffix();
155 }
156
157 PrefHashStoreTransaction::ValueState
158 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
159 const std::string& path,
160 const base::Value* initial_value) const {
161 std::string last_hash;
162 contents_->GetMac(path, &last_hash);
163
164 if (last_hash.empty()) {
165 // In the absence of a hash for this pref, always trust a NULL value, but
166 // only trust an existing value if the initial hashes dictionary is trusted.
167 if (!initial_value)
168 return TRUSTED_NULL_VALUE;
169 else if (super_mac_valid_)
170 return TRUSTED_UNKNOWN_VALUE;
171 else
172 return UNTRUSTED_UNKNOWN_VALUE;
173 }
174
175 PrefHashCalculator::ValidationResult validation_result =
176 outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash);
177 switch (validation_result) {
178 case PrefHashCalculator::VALID:
179 return UNCHANGED;
180 case PrefHashCalculator::VALID_SECURE_LEGACY:
181 return SECURE_LEGACY;
182 case PrefHashCalculator::INVALID:
183 return initial_value ? CHANGED : CLEARED;
184 }
185 NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
186 << validation_result;
187 return UNTRUSTED_UNKNOWN_VALUE;
188 }
189
190 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
191 const std::string& path,
192 const base::Value* new_value) {
193 const std::string mac = outer_->ComputeMac(path, new_value);
194 contents_->SetMac(path, mac);
195 super_mac_dirty_ = true;
196 }
197
198 PrefHashStoreTransaction::ValueState
199 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
200 const std::string& path,
201 const base::DictionaryValue* initial_split_value,
202 std::vector<std::string>* invalid_keys) const {
203 DCHECK(invalid_keys && invalid_keys->empty());
204
205 std::map<std::string, std::string> split_macs;
206 const bool has_hashes = contents_->GetSplitMacs(path, &split_macs);
207
208 // Treat NULL and empty the same; otherwise we would need to store a hash for
209 // the entire dictionary (or some other special beacon) to differentiate these
210 // two cases which are really the same for dictionaries.
211 if (!initial_split_value || initial_split_value->empty())
212 return has_hashes ? CLEARED : UNCHANGED;
213
214 if (!has_hashes)
215 return super_mac_valid_ ? TRUSTED_UNKNOWN_VALUE : UNTRUSTED_UNKNOWN_VALUE;
216
217 bool has_secure_legacy_id_hashes = false;
218 std::string keyed_path(path);
219 keyed_path.push_back('.');
220 const size_t common_part_length = keyed_path.length();
221 for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd();
222 it.Advance()) {
223 std::map<std::string, std::string>::iterator entry =
224 split_macs.find(it.key());
225 if (entry == split_macs.end()) {
226 invalid_keys->push_back(it.key());
227 } else {
228 // Keep the common part from the old |keyed_path| and replace the key to
229 // get the new |keyed_path|.
230 keyed_path.replace(common_part_length, std::string::npos, it.key());
231 switch (outer_->pref_hash_calculator_.Validate(keyed_path, &it.value(),
232 entry->second)) {
233 case PrefHashCalculator::VALID:
234 break;
235 case SECURE_LEGACY:
236 // Secure legacy device IDs based hashes are still accepted, but we
237 // should make sure to notify the caller for them to update the legacy
238 // hashes.
239 has_secure_legacy_id_hashes = true;
240 break;
241 case PrefHashCalculator::INVALID:
242 invalid_keys->push_back(it.key());
243 break;
244 }
245 // Remove processed MACs, remaining MACs at the end will also be
246 // considered invalid.
247 split_macs.erase(entry);
248 }
249 }
250
251 // Anything left in the map is missing from the data.
252 for (std::map<std::string, std::string>::const_iterator it =
253 split_macs.begin();
254 it != split_macs.end(); ++it) {
255 invalid_keys->push_back(it->first);
256 }
257
258 return invalid_keys->empty()
259 ? (has_secure_legacy_id_hashes ? SECURE_LEGACY : UNCHANGED)
260 : CHANGED;
261 }
262
263 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
264 const std::string& path,
265 const base::DictionaryValue* split_value) {
266 contents_->RemoveEntry(path);
267
268 if (split_value) {
269 std::unique_ptr<base::DictionaryValue> split_macs =
270 outer_->ComputeSplitMacs(path, split_value);
271
272 for (base::DictionaryValue::Iterator it(*split_macs); !it.IsAtEnd();
273 it.Advance()) {
274 const base::Value* value_as_string;
275 bool is_string = it.value().GetAsString(&value_as_string);
276 DCHECK(is_string);
277
278 contents_->SetSplitMac(path, it.key(), value_as_string->GetString());
279 }
280 }
281 super_mac_dirty_ = true;
282 }
283
284 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash(
285 const std::string& path) const {
286 std::string out_value;
287 std::map<std::string, std::string> out_values;
288 return contents_->GetMac(path, &out_value) ||
289 contents_->GetSplitMacs(path, &out_values);
290 }
291
292 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
293 const std::string& path,
294 const base::Value* hash) {
295 DCHECK(hash);
296
297 contents_->ImportEntry(path, hash);
298
299 if (super_mac_valid_)
300 super_mac_dirty_ = true;
301 }
302
303 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash(
304 const std::string& path) {
305 if (contents_->RemoveEntry(path) && super_mac_valid_) {
306 super_mac_dirty_ = true;
307 }
308 }
309
310 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const {
311 return super_mac_valid_;
312 }
313
314 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() {
315 if (!outer_->use_super_mac_ || super_mac_valid_)
316 return false;
317 super_mac_dirty_ = true;
318 return true;
319 }
OLDNEW
« no previous file with comments | « components/user_prefs/tracked/pref_hash_store_impl.h ('k') | components/user_prefs/tracked/pref_hash_store_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698