Chromium Code Reviews| 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 |