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) | 52 bool use_super_mac) |
63 : pref_hash_calculator_(seed, device_id), | 53 : pref_hash_calculator_(seed, device_id), |
64 contents_(contents.Pass()), | 54 use_super_mac_(use_super_mac), |
65 initial_hashes_dictionary_trusted_( | 55 checked_super_mac_(false), |
66 IsHashDictionaryTrusted(pref_hash_calculator_, *contents_)), | 56 initial_hashes_dictionary_trusted_(false), |
67 has_pending_write_(false) { | 57 has_pending_write_(false) { |
68 DCHECK(contents_); | |
69 UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted", | |
70 initial_hashes_dictionary_trusted_); | |
71 } | 58 } |
72 | 59 |
73 PrefHashStoreImpl::~PrefHashStoreImpl() {} | 60 PrefHashStoreImpl::~PrefHashStoreImpl() {} |
74 | 61 |
| 62 void PrefHashStoreImpl::SetHashStoreContents( |
| 63 scoped_ptr<HashStoreContents> contents) { |
| 64 contents_ = contents.Pass(); |
| 65 |
| 66 } |
| 67 |
| 68 bool PrefHashStoreImpl::IsInitialized() const { |
| 69 return contents_->IsInitialized(); |
| 70 } |
| 71 |
75 void PrefHashStoreImpl::Reset() { | 72 void PrefHashStoreImpl::Reset() { |
76 contents_->Reset(); | 73 contents_->Reset(); |
77 } | 74 } |
78 | 75 |
79 scoped_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction() { | 76 scoped_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction() { |
| 77 CheckSuperMac(); |
80 return scoped_ptr<PrefHashStoreTransaction>( | 78 return scoped_ptr<PrefHashStoreTransaction>( |
81 new PrefHashStoreTransactionImpl(this)); | 79 new PrefHashStoreTransactionImpl(this)); |
82 } | 80 } |
83 | 81 |
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() { | 82 void PrefHashStoreImpl::CommitPendingWrite() { |
98 if (has_pending_write_) { | 83 if (has_pending_write_) { |
99 contents_->CommitPendingWrite(); | 84 contents_->CommitPendingWrite(); |
100 has_pending_write_ = false; | 85 has_pending_write_ = false; |
101 } | 86 } |
102 } | 87 } |
103 | 88 |
| 89 bool PrefHashStoreImpl::CheckSuperMac() { |
| 90 if (checked_super_mac_ || !use_super_mac_) |
| 91 return initial_hashes_dictionary_trusted_; |
| 92 |
| 93 const base::DictionaryValue* store_contents = contents_->GetContents(); |
| 94 std::string super_mac = contents_->GetSuperMac(); |
| 95 // The store must be initialized and have a valid super MAC to be trusted. |
| 96 initial_hashes_dictionary_trusted_ = |
| 97 store_contents && !super_mac.empty() && |
| 98 pref_hash_calculator_.Validate(contents_->hash_store_id(), |
| 99 store_contents, |
| 100 super_mac) == PrefHashCalculator::VALID; |
| 101 |
| 102 checked_super_mac_ = true; |
| 103 |
| 104 UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted", |
| 105 initial_hashes_dictionary_trusted_); |
| 106 |
| 107 return initial_hashes_dictionary_trusted_; |
| 108 } |
| 109 |
104 PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl( | 110 PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl( |
105 PrefHashStoreImpl* outer) : outer_(outer), has_changed_(false) { | 111 PrefHashStoreImpl* outer) |
| 112 : outer_(outer), has_changed_(false), super_mac_dirty_(false) { |
106 } | 113 } |
107 | 114 |
108 PrefHashStoreImpl::PrefHashStoreTransactionImpl:: | 115 PrefHashStoreImpl::PrefHashStoreTransactionImpl:: |
109 ~PrefHashStoreTransactionImpl() { | 116 ~PrefHashStoreTransactionImpl() { |
110 // Update the super MAC if and only if the hashes dictionary has been | |
111 // modified in this transaction. | |
112 if (has_changed_) { | 117 if (has_changed_) { |
113 // Get the dictionary of hashes (or NULL if it doesn't exist). | 118 // Update the super MAC if and only if the hashes dictionary has been |
114 const base::DictionaryValue* hashes_dict = outer_->contents_->GetContents(); | 119 // modified in this transaction. Imports do not necessarily affect the super |
115 outer_->contents_->SetSuperMac(outer_->pref_hash_calculator_.Calculate( | 120 // MAC (will not transition it from invalid to valid). |
116 outer_->contents_->hash_store_id(), hashes_dict)); | 121 if (outer_->use_super_mac_ && super_mac_dirty_) { |
| 122 // Get the dictionary of hashes (or NULL if it doesn't exist). |
| 123 const base::DictionaryValue* hashes_dict = |
| 124 outer_->contents_->GetContents(); |
| 125 outer_->contents_->SetSuperMac(outer_->pref_hash_calculator_.Calculate( |
| 126 outer_->contents_->hash_store_id(), hashes_dict)); |
| 127 } |
117 | 128 |
118 outer_->has_pending_write_ = true; | 129 outer_->has_pending_write_ = true; |
119 } | 130 } |
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 } | 131 } |
135 | 132 |
| 133 const base::Value* PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetHash( |
| 134 const std::string& path) const { |
| 135 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); |
| 136 |
| 137 const base::Value* last_hash = NULL; |
| 138 if (hashed_prefs) |
| 139 hashed_prefs->Get(path, &last_hash); |
| 140 return last_hash; |
| 141 } |
| 142 |
136 PrefHashStoreTransaction::ValueState | 143 PrefHashStoreTransaction::ValueState |
137 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( | 144 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( |
138 const std::string& path, const base::Value* initial_value) const { | 145 const std::string& path, const base::Value* initial_value) const { |
139 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); | 146 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); |
140 | 147 |
141 std::string last_hash; | 148 std::string last_hash; |
142 if (hashed_prefs) | 149 if (hashed_prefs) |
143 hashed_prefs->GetString(path, &last_hash); | 150 hashed_prefs->GetString(path, &last_hash); |
144 | 151 |
145 if (last_hash.empty()) { | 152 if (last_hash.empty()) { |
(...skipping 19 matching lines...) Expand all Loading... |
165 << validation_result; | 172 << validation_result; |
166 return UNTRUSTED_UNKNOWN_VALUE; | 173 return UNTRUSTED_UNKNOWN_VALUE; |
167 } | 174 } |
168 | 175 |
169 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash( | 176 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash( |
170 const std::string& path, const base::Value* new_value) { | 177 const std::string& path, const base::Value* new_value) { |
171 const std::string mac = | 178 const std::string mac = |
172 outer_->pref_hash_calculator_.Calculate(path, new_value); | 179 outer_->pref_hash_calculator_.Calculate(path, new_value); |
173 (*outer_->contents_->GetMutableContents())->SetString(path, mac); | 180 (*outer_->contents_->GetMutableContents())->SetString(path, mac); |
174 has_changed_ = true; | 181 has_changed_ = true; |
| 182 super_mac_dirty_ = true; |
| 183 } |
| 184 |
| 185 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash( |
| 186 const std::string& path, |
| 187 const base::Value* hash) { |
| 188 if (!hash) |
| 189 (*outer_->contents_->GetMutableContents())->RemovePath(path, NULL); |
| 190 else |
| 191 (*outer_->contents_->GetMutableContents())->Set(path, hash->DeepCopy()); |
| 192 has_changed_ = true; |
| 193 super_mac_dirty_ = |
| 194 super_mac_dirty_ || outer_->initial_hashes_dictionary_trusted_; |
| 195 } |
| 196 |
| 197 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash( |
| 198 const std::string& path) { |
| 199 (*outer_->contents_->GetMutableContents())->RemovePath(path, NULL); |
| 200 has_changed_ = true; |
| 201 super_mac_dirty_ = |
| 202 super_mac_dirty_ || outer_->initial_hashes_dictionary_trusted_; |
| 203 } |
| 204 |
| 205 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() { |
| 206 if (!outer_->use_super_mac_ || outer_->initial_hashes_dictionary_trusted_) |
| 207 return false; |
| 208 has_changed_ = true; |
| 209 super_mac_dirty_ = true; |
| 210 return true; |
175 } | 211 } |
176 | 212 |
177 PrefHashStoreTransaction::ValueState | 213 PrefHashStoreTransaction::ValueState |
178 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( | 214 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( |
179 const std::string& path, | 215 const std::string& path, |
180 const base::DictionaryValue* initial_split_value, | 216 const base::DictionaryValue* initial_split_value, |
181 std::vector<std::string>* invalid_keys) const { | 217 std::vector<std::string>* invalid_keys) const { |
182 DCHECK(invalid_keys && invalid_keys->empty()); | 218 DCHECK(invalid_keys && invalid_keys->empty()); |
183 | 219 |
184 std::map<std::string, std::string> split_macs; | 220 std::map<std::string, std::string> split_macs; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 it.Advance()) { | 301 it.Advance()) { |
266 // Keep the common part from the old |keyed_path| and replace the key to | 302 // Keep the common part from the old |keyed_path| and replace the key to |
267 // get the new |keyed_path|. | 303 // get the new |keyed_path|. |
268 keyed_path.replace(common_part_length, std::string::npos, it.key()); | 304 keyed_path.replace(common_part_length, std::string::npos, it.key()); |
269 (*mutable_dictionary)->SetString( | 305 (*mutable_dictionary)->SetString( |
270 keyed_path, | 306 keyed_path, |
271 outer_->pref_hash_calculator_.Calculate(keyed_path, &it.value())); | 307 outer_->pref_hash_calculator_.Calculate(keyed_path, &it.value())); |
272 } | 308 } |
273 } | 309 } |
274 has_changed_ = true; | 310 has_changed_ = true; |
| 311 super_mac_dirty_ = true; |
275 } | 312 } |
276 | 313 |
277 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs( | 314 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs( |
278 const std::string& key, | 315 const std::string& key, |
279 std::map<std::string, std::string>* split_macs) const { | 316 std::map<std::string, std::string>* split_macs) const { |
280 DCHECK(split_macs); | 317 DCHECK(split_macs); |
281 DCHECK(split_macs->empty()); | 318 DCHECK(split_macs->empty()); |
282 | 319 |
283 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); | 320 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents(); |
284 const base::DictionaryValue* split_mac_dictionary = NULL; | 321 const base::DictionaryValue* split_mac_dictionary = NULL; |
285 if (!hashed_prefs || !hashed_prefs->GetDictionary(key, &split_mac_dictionary)) | 322 if (!hashed_prefs || !hashed_prefs->GetDictionary(key, &split_mac_dictionary)) |
286 return false; | 323 return false; |
287 for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd(); | 324 for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd(); |
288 it.Advance()) { | 325 it.Advance()) { |
289 std::string mac_string; | 326 std::string mac_string; |
290 if (!it.value().GetAsString(&mac_string)) { | 327 if (!it.value().GetAsString(&mac_string)) { |
291 NOTREACHED(); | 328 NOTREACHED(); |
292 continue; | 329 continue; |
293 } | 330 } |
294 split_macs->insert(make_pair(it.key(), mac_string)); | 331 split_macs->insert(make_pair(it.key(), mac_string)); |
295 } | 332 } |
296 return true; | 333 return true; |
297 } | 334 } |
OLD | NEW |