| 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 |