OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/prefs/pref_hash_store_impl.h" | 5 #include "chrome/browser/prefs/pref_hash_store_impl.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/values.h" | 9 #include "base/values.h" |
10 #include "chrome/browser/prefs/pref_hash_store_transaction.h" | 10 #include "chrome/browser/prefs/pref_hash_store_transaction.h" |
11 #include "chrome/browser/prefs/tracked/hash_store_contents.h" | 11 #include "chrome/browser/prefs/tracked/hash_store_contents.h" |
12 | 12 |
13 namespace { | |
14 | |
15 // Returns true if the dictionary of hashes stored in |contents| is trusted | |
16 // (which implies unknown values can be trusted as newly tracked values). | |
17 bool IsHashDictionaryTrusted(const PrefHashCalculator& calculator, | |
18 const HashStoreContents& contents) { | |
19 const base::DictionaryValue* store_contents = contents.GetContents(); | |
20 std::string super_mac = contents.GetSuperMac(); | |
21 // The store must be initialized and have a valid super MAC to be trusted. | |
22 return store_contents && !super_mac.empty() && | |
23 calculator.Validate(contents.hash_store_id(), | |
24 store_contents, | |
25 super_mac) == PrefHashCalculator::VALID; | |
26 } | |
27 | |
28 } // namespace | |
29 | |
30 class PrefHashStoreImpl::PrefHashStoreTransactionImpl | 13 class PrefHashStoreImpl::PrefHashStoreTransactionImpl |
31 : public PrefHashStoreTransaction { | 14 : public PrefHashStoreTransaction { |
32 public: | 15 public: |
33 // Constructs a PrefHashStoreTransactionImpl which can use the private | 16 // Constructs a PrefHashStoreTransactionImpl which can use the private |
34 // members of its |outer| PrefHashStoreImpl. | 17 // members of its |outer| PrefHashStoreImpl. |
35 explicit PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer); | 18 explicit PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer); |
36 virtual ~PrefHashStoreTransactionImpl(); | 19 virtual ~PrefHashStoreTransactionImpl(); |
37 | 20 |
38 // PrefHashStoreTransaction implementation. | 21 // PrefHashStoreTransaction implementation. |
39 virtual ValueState CheckValue(const std::string& path, | 22 virtual ValueState CheckValue(const std::string& path, |
40 const base::Value* value) const OVERRIDE; | 23 const base::Value* value) const OVERRIDE; |
41 virtual void StoreHash(const std::string& path, | 24 virtual void StoreHash(const std::string& path, |
42 const base::Value* value) OVERRIDE; | 25 const base::Value* value) OVERRIDE; |
26 virtual const base::Value* GetHash(const std::string& path) const OVERRIDE; | |
27 virtual void ImportHash(const std::string& path, | |
28 const base::Value* hash) OVERRIDE; | |
29 virtual void ClearHash(const std::string& path) OVERRIDE; | |
30 virtual bool StampSuperMac() OVERRIDE; | |
31 | |
43 virtual ValueState CheckSplitValue( | 32 virtual ValueState CheckSplitValue( |
44 const std::string& path, | 33 const std::string& path, |
45 const base::DictionaryValue* initial_split_value, | 34 const base::DictionaryValue* initial_split_value, |
46 std::vector<std::string>* invalid_keys) const OVERRIDE; | 35 std::vector<std::string>* invalid_keys) const OVERRIDE; |
47 virtual void StoreSplitHash( | 36 virtual void StoreSplitHash( |
48 const std::string& path, | 37 const std::string& path, |
49 const base::DictionaryValue* split_value) OVERRIDE; | 38 const base::DictionaryValue* split_value) OVERRIDE; |
50 | 39 |
51 private: | 40 private: |
52 bool GetSplitMacs(const std::string& path, | 41 bool GetSplitMacs(const std::string& path, |
53 std::map<std::string, std::string>* split_macs) const; | 42 std::map<std::string, std::string>* split_macs) const; |
54 PrefHashStoreImpl* outer_; | 43 PrefHashStoreImpl* outer_; |
55 bool has_changed_; | 44 bool has_changed_; |
45 bool super_mac_dirty_; | |
56 | 46 |
57 DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl); | 47 DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl); |
58 }; | 48 }; |
59 | 49 |
60 PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed, | 50 PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed, |
61 const std::string& device_id, | 51 const std::string& device_id) |
62 scoped_ptr<HashStoreContents> contents) | |
63 : pref_hash_calculator_(seed, device_id), | 52 : pref_hash_calculator_(seed, device_id), |
64 contents_(contents.Pass()), | 53 initial_hashes_dictionary_trusted_(false), |
65 initial_hashes_dictionary_trusted_( | |
66 IsHashDictionaryTrusted(pref_hash_calculator_, *contents_)), | |
67 has_pending_write_(false) { | 54 has_pending_write_(false) { |
68 DCHECK(contents_); | |
69 UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted", | 55 UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted", |
70 initial_hashes_dictionary_trusted_); | 56 initial_hashes_dictionary_trusted_); |
gab
2014/06/06 21:54:59
This histogram should also move.
erikwright (departed)
2014/06/10 20:27:47
Done.
| |
71 } | 57 } |
72 | 58 |
73 PrefHashStoreImpl::~PrefHashStoreImpl() {} | 59 PrefHashStoreImpl::~PrefHashStoreImpl() {} |
74 | 60 |
61 void PrefHashStoreImpl::SetHashStoreContents( | |
gab
2014/06/06 21:54:59
Call this method Init()? And explicitly state that
| |
62 scoped_ptr<HashStoreContents> contents) { | |
63 contents_ = contents.Pass(); | |
64 | |
65 const base::DictionaryValue* store_contents = contents_->GetContents(); | |
66 std::string super_mac = contents_->GetSuperMac(); | |
67 | |
68 // The store must be initialized and have a valid super MAC to be trusted. | |
69 initial_hashes_dictionary_trusted_ = | |
70 store_contents && !super_mac.empty() && | |
71 pref_hash_calculator_.Validate(contents_->hash_store_id(), | |
72 store_contents, | |
73 super_mac) == PrefHashCalculator::VALID; | |
74 } | |
75 | |
76 bool PrefHashStoreImpl::IsInitialized() const { | |
77 return contents_->IsInitialized(); | |
78 } | |
79 | |
75 void PrefHashStoreImpl::Reset() { | 80 void PrefHashStoreImpl::Reset() { |
76 contents_->Reset(); | 81 contents_->Reset(); |
77 } | 82 } |
78 | 83 |
79 scoped_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction() { | 84 scoped_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction() { |
80 return scoped_ptr<PrefHashStoreTransaction>( | 85 return scoped_ptr<PrefHashStoreTransaction>( |
81 new PrefHashStoreTransactionImpl(this)); | 86 new PrefHashStoreTransactionImpl(this)); |
82 } | 87 } |
83 | 88 |
84 PrefHashStoreImpl::StoreVersion PrefHashStoreImpl::GetCurrentVersion() const { | |
85 if (!contents_->IsInitialized()) | |
86 return VERSION_UNINITIALIZED; | |
87 | |
88 int current_version; | |
89 if (!contents_->GetVersion(¤t_version)) { | |
90 return VERSION_PRE_MIGRATION; | |
91 } | |
92 | |
93 DCHECK_GT(current_version, VERSION_PRE_MIGRATION); | |
94 return static_cast<StoreVersion>(current_version); | |
95 } | |
96 | |
97 void PrefHashStoreImpl::CommitPendingWrite() { | 89 void PrefHashStoreImpl::CommitPendingWrite() { |
98 if (has_pending_write_) { | 90 if (has_pending_write_) { |
99 contents_->CommitPendingWrite(); | 91 contents_->CommitPendingWrite(); |
100 has_pending_write_ = false; | 92 has_pending_write_ = false; |
101 } | 93 } |
102 } | 94 } |
103 | 95 |
104 PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl( | 96 PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl( |
105 PrefHashStoreImpl* outer) : outer_(outer), has_changed_(false) { | 97 PrefHashStoreImpl* outer) |
98 : outer_(outer), has_changed_(false), super_mac_dirty_(false) { | |
106 } | 99 } |
107 | 100 |
108 PrefHashStoreImpl::PrefHashStoreTransactionImpl:: | 101 PrefHashStoreImpl::PrefHashStoreTransactionImpl:: |
109 ~PrefHashStoreTransactionImpl() { | 102 ~PrefHashStoreTransactionImpl() { |
110 // Update the super MAC if and only if the hashes dictionary has been | |
111 // modified in this transaction. | |
112 if (has_changed_) { | 103 if (has_changed_) { |
113 // Get the dictionary of hashes (or NULL if it doesn't exist). | 104 // Update the super MAC if and only if the hashes dictionary has been |
114 const base::DictionaryValue* hashes_dict = outer_->contents_->GetContents(); | 105 // modified in this transaction. Imports do not necessarily affect the super |
115 outer_->contents_->SetSuperMac(outer_->pref_hash_calculator_.Calculate( | 106 // MAC (will not transition it from invalid to valid). |
116 outer_->contents_->hash_store_id(), hashes_dict)); | 107 if (super_mac_dirty_) { |
108 // Get the dictionary of hashes (or NULL if it doesn't exist). | |
109 const base::DictionaryValue* hashes_dict = | |
110 outer_->contents_->GetContents(); | |
111 outer_->contents_->SetSuperMac(outer_->pref_hash_calculator_.Calculate( | |
112 outer_->contents_->hash_store_id(), hashes_dict)); | |
113 } | |
117 | 114 |
118 outer_->has_pending_write_ = true; | 115 outer_->has_pending_write_ = true; |
119 } | 116 } |
120 | |
121 // Mark this hash store has having been updated to the latest version (in | |
122 // practice only initialization transactions will actually do this, but | |
123 // since they always occur before minor update transaction it's okay | |
124 // to unconditionally do this here). Only do this if this store's version | |
125 // isn't already at VERSION_LATEST (to avoid scheduling a write when | |
126 // unecessary). Note, this is outside of |if (has_changed)| to also seed | |
127 // version number of otherwise unchanged profiles. | |
128 int current_version; | |
129 if (!outer_->contents_->GetVersion(¤t_version) || | |
130 current_version != VERSION_LATEST) { | |
131 outer_->contents_->SetVersion(VERSION_LATEST); | |
132 outer_->has_pending_write_ = true; | |
133 } | |
134 } | 117 } |
135 | 118 |
119 const base::Value* PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetHash( | |
120 const std::string& path) const { | |
121 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); | |
122 | |
123 const base::Value* last_hash = NULL; | |
124 if (hashed_prefs) | |
125 hashed_prefs->Get(path, &last_hash); | |
126 return last_hash; | |
127 } | |
128 | |
136 PrefHashStoreTransaction::ValueState | 129 PrefHashStoreTransaction::ValueState |
137 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( | 130 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( |
138 const std::string& path, const base::Value* initial_value) const { | 131 const std::string& path, const base::Value* initial_value) const { |
139 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); | 132 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); |
140 | 133 |
141 std::string last_hash; | 134 std::string last_hash; |
142 if (hashed_prefs) | 135 if (hashed_prefs) |
143 hashed_prefs->GetString(path, &last_hash); | 136 hashed_prefs->GetString(path, &last_hash); |
144 | 137 |
145 if (last_hash.empty()) { | 138 if (last_hash.empty()) { |
(...skipping 19 matching lines...) Expand all Loading... | |
165 << validation_result; | 158 << validation_result; |
166 return UNTRUSTED_UNKNOWN_VALUE; | 159 return UNTRUSTED_UNKNOWN_VALUE; |
167 } | 160 } |
168 | 161 |
169 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash( | 162 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash( |
170 const std::string& path, const base::Value* new_value) { | 163 const std::string& path, const base::Value* new_value) { |
171 const std::string mac = | 164 const std::string mac = |
172 outer_->pref_hash_calculator_.Calculate(path, new_value); | 165 outer_->pref_hash_calculator_.Calculate(path, new_value); |
173 (*outer_->contents_->GetMutableContents())->SetString(path, mac); | 166 (*outer_->contents_->GetMutableContents())->SetString(path, mac); |
174 has_changed_ = true; | 167 has_changed_ = true; |
168 super_mac_dirty_ = true; | |
169 } | |
170 | |
171 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash( | |
172 const std::string& path, | |
173 const base::Value* hash) { | |
gab
2014/06/06 21:54:59
I think |hash| should be passed as a std::string.
erikwright (departed)
2014/06/09 18:34:50
That requires separate pairs of methods for atomic
gab
2014/06/09 20:24:33
Duh, of course, passing it via a Value object is f
erikwright (departed)
2014/06/10 20:27:47
I thought about that, but it's consistent with Sto
| |
174 if (!hash) | |
175 (*outer_->contents_->GetMutableContents())->RemovePath(path, NULL); | |
176 else | |
177 (*outer_->contents_->GetMutableContents())->Set(path, hash->DeepCopy()); | |
178 has_changed_ = true; | |
179 super_mac_dirty_ = | |
180 super_mac_dirty_ || outer_->initial_hashes_dictionary_trusted_; | |
gab
2014/06/06 21:54:59
It's incorrect to re-write the super MAC here if t
erikwright (departed)
2014/06/09 18:34:50
We talked about this offline. It's correct to keep
| |
181 } | |
182 | |
183 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash( | |
184 const std::string& path) { | |
185 (*outer_->contents_->GetMutableContents())->RemovePath(path, NULL); | |
186 has_changed_ = true; | |
187 super_mac_dirty_ = | |
188 super_mac_dirty_ || outer_->initial_hashes_dictionary_trusted_; | |
189 } | |
190 | |
191 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() { | |
192 if (outer_->initial_hashes_dictionary_trusted_) | |
193 return false; | |
194 has_changed_ = true; | |
195 super_mac_dirty_ = true; | |
196 return true; | |
175 } | 197 } |
176 | 198 |
177 PrefHashStoreTransaction::ValueState | 199 PrefHashStoreTransaction::ValueState |
178 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( | 200 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( |
179 const std::string& path, | 201 const std::string& path, |
180 const base::DictionaryValue* initial_split_value, | 202 const base::DictionaryValue* initial_split_value, |
181 std::vector<std::string>* invalid_keys) const { | 203 std::vector<std::string>* invalid_keys) const { |
182 DCHECK(invalid_keys && invalid_keys->empty()); | 204 DCHECK(invalid_keys && invalid_keys->empty()); |
183 | 205 |
184 std::map<std::string, std::string> split_macs; | 206 std::map<std::string, std::string> split_macs; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
265 it.Advance()) { | 287 it.Advance()) { |
266 // Keep the common part from the old |keyed_path| and replace the key to | 288 // Keep the common part from the old |keyed_path| and replace the key to |
267 // get the new |keyed_path|. | 289 // get the new |keyed_path|. |
268 keyed_path.replace(common_part_length, std::string::npos, it.key()); | 290 keyed_path.replace(common_part_length, std::string::npos, it.key()); |
269 (*mutable_dictionary)->SetString( | 291 (*mutable_dictionary)->SetString( |
270 keyed_path, | 292 keyed_path, |
271 outer_->pref_hash_calculator_.Calculate(keyed_path, &it.value())); | 293 outer_->pref_hash_calculator_.Calculate(keyed_path, &it.value())); |
272 } | 294 } |
273 } | 295 } |
274 has_changed_ = true; | 296 has_changed_ = true; |
297 super_mac_dirty_ = true; | |
275 } | 298 } |
276 | 299 |
277 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs( | 300 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs( |
278 const std::string& key, | 301 const std::string& key, |
279 std::map<std::string, std::string>* split_macs) const { | 302 std::map<std::string, std::string>* split_macs) const { |
280 DCHECK(split_macs); | 303 DCHECK(split_macs); |
281 DCHECK(split_macs->empty()); | 304 DCHECK(split_macs->empty()); |
282 | 305 |
283 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); | 306 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); |
284 const base::DictionaryValue* split_mac_dictionary = NULL; | 307 const base::DictionaryValue* split_mac_dictionary = NULL; |
285 if (!hashed_prefs || !hashed_prefs->GetDictionary(key, &split_mac_dictionary)) | 308 if (!hashed_prefs || !hashed_prefs->GetDictionary(key, &split_mac_dictionary)) |
286 return false; | 309 return false; |
287 for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd(); | 310 for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd(); |
288 it.Advance()) { | 311 it.Advance()) { |
289 std::string mac_string; | 312 std::string mac_string; |
290 if (!it.value().GetAsString(&mac_string)) { | 313 if (!it.value().GetAsString(&mac_string)) { |
291 NOTREACHED(); | 314 NOTREACHED(); |
292 continue; | 315 continue; |
293 } | 316 } |
294 split_macs->insert(make_pair(it.key(), mac_string)); | 317 split_macs->insert(make_pair(it.key(), mac_string)); |
295 } | 318 } |
296 return true; | 319 return true; |
297 } | 320 } |
OLD | NEW |