| Index: chrome/browser/prefs/pref_hash_store_impl.cc
|
| diff --git a/chrome/browser/prefs/pref_hash_store_impl.cc b/chrome/browser/prefs/pref_hash_store_impl.cc
|
| index ef698fc75fcef3ca1726764ae3cfe8e2f25fbe3e..2b62bac61fc473a789fbf5239a362afb384f4ec7 100644
|
| --- a/chrome/browser/prefs/pref_hash_store_impl.cc
|
| +++ b/chrome/browser/prefs/pref_hash_store_impl.cc
|
| @@ -5,6 +5,7 @@
|
| #include "chrome/browser/prefs/pref_hash_store_impl.h"
|
|
|
| #include "base/logging.h"
|
| +#include "base/metrics/histogram.h"
|
| #include "base/prefs/pref_registry_simple.h"
|
| #include "base/prefs/pref_service.h"
|
| #include "base/prefs/scoped_user_pref_update.h"
|
| @@ -17,7 +18,11 @@ PrefHashStoreImpl::PrefHashStoreImpl(const std::string& hash_store_id,
|
| PrefService* local_state)
|
| : hash_store_id_(hash_store_id),
|
| pref_hash_calculator_(seed, device_id),
|
| - local_state_(local_state) {}
|
| + local_state_(local_state),
|
| + initial_hashes_dictionary_trusted_(IsHashDictionaryTrusted()) {
|
| + UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted",
|
| + initial_hashes_dictionary_trusted_);
|
| +}
|
|
|
| // static
|
| void PrefHashStoreImpl::RegisterPrefs(PrefRegistrySimple* registry) {
|
| @@ -35,42 +40,82 @@ PrefHashStore::ValueState PrefHashStoreImpl::CheckValue(
|
| &hashed_prefs);
|
|
|
| std::string last_hash;
|
| - if (!hashed_prefs || !hashed_prefs->GetString(path, &last_hash))
|
| - return PrefHashStore::UNKNOWN_VALUE;
|
| + if (!hashed_prefs || !hashed_prefs->GetString(path, &last_hash)) {
|
| + // In the absence of a hash for this pref, always trust a NULL value, but
|
| + // only trust an existing value if the initial hashes dictionary is trusted.
|
| + return (!initial_value || initial_hashes_dictionary_trusted_) ?
|
| + TRUSTED_UNKNOWN_VALUE : UNTRUSTED_UNKNOWN_VALUE;
|
| + }
|
|
|
| PrefHashCalculator::ValidationResult validation_result =
|
| pref_hash_calculator_.Validate(path, initial_value, last_hash);
|
| switch (validation_result) {
|
| case PrefHashCalculator::VALID:
|
| - return PrefHashStore::UNCHANGED;
|
| + return UNCHANGED;
|
| case PrefHashCalculator::VALID_LEGACY:
|
| - return PrefHashStore::MIGRATED;
|
| + return MIGRATED;
|
| case PrefHashCalculator::INVALID:
|
| - return initial_value ? PrefHashStore::CHANGED : PrefHashStore::CLEARED;
|
| + return initial_value ? CHANGED : CLEARED;
|
| }
|
| NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
|
| << validation_result;
|
| - return PrefHashStore::UNKNOWN_VALUE;
|
| + return UNTRUSTED_UNKNOWN_VALUE;
|
| }
|
|
|
| void PrefHashStoreImpl::StoreHash(
|
| const std::string& path, const base::Value* new_value) {
|
| {
|
| DictionaryPrefUpdate update(local_state_, prefs::kProfilePreferenceHashes);
|
| - base::DictionaryValue* child_dictionary = NULL;
|
|
|
| // Get the dictionary corresponding to the profile name, which may have a
|
| // '.'
|
| + base::DictionaryValue* hashes_dict = NULL;
|
| if (!update->GetDictionaryWithoutPathExpansion(hash_store_id_,
|
| - &child_dictionary)) {
|
| - child_dictionary = new base::DictionaryValue;
|
| - update->SetWithoutPathExpansion(hash_store_id_, child_dictionary);
|
| + &hashes_dict)) {
|
| + hashes_dict = new base::DictionaryValue;
|
| + update->SetWithoutPathExpansion(hash_store_id_, hashes_dict);
|
| }
|
|
|
| - child_dictionary->SetString(
|
| + hashes_dict->SetString(
|
| path, pref_hash_calculator_.Calculate(path, new_value));
|
| +
|
| + // Get the dictionary where the hash of hashes are stored.
|
| + base::DictionaryValue* hash_of_hashes_dict = NULL;
|
| + if (!update->GetDictionaryWithoutPathExpansion(internals::kHashOfHashesPref,
|
| + &hash_of_hashes_dict)) {
|
| + hash_of_hashes_dict = new base::DictionaryValue;
|
| + update->SetWithoutPathExpansion(internals::kHashOfHashesPref,
|
| + hash_of_hashes_dict);
|
| + }
|
| + // Use the |hash_store_id_| as the hashed path to avoid having the hash
|
| + // depend on kProfilePreferenceHashes.
|
| + std::string hash_of_hashes(pref_hash_calculator_.Calculate(hash_store_id_,
|
| + hashes_dict));
|
| + hash_of_hashes_dict->SetStringWithoutPathExpansion(hash_store_id_,
|
| + hash_of_hashes);
|
| }
|
| // TODO(erikwright): During tests, pending writes were still waiting when the
|
| // IO thread is already gone. Consider other solutions.
|
| local_state_->CommitPendingWrite();
|
| }
|
| +
|
| +bool PrefHashStoreImpl::IsHashDictionaryTrusted() const {
|
| + const base::DictionaryValue* pref_hash_dicts =
|
| + local_state_->GetDictionary(prefs::kProfilePreferenceHashes);
|
| + const base::DictionaryValue* hashes_dict = NULL;
|
| + const base::DictionaryValue* hash_of_hashes_dict = NULL;
|
| + std::string hash_of_hashes;
|
| + // The absence of the hashes dictionary isn't trusted. Nor is the absence of
|
| + // the hash of hashes for this |hash_store_id_|.
|
| + if (!pref_hash_dicts->GetDictionaryWithoutPathExpansion(
|
| + hash_store_id_, &hashes_dict) ||
|
| + !pref_hash_dicts->GetDictionaryWithoutPathExpansion(
|
| + internals::kHashOfHashesPref, &hash_of_hashes_dict) ||
|
| + !hash_of_hashes_dict->GetStringWithoutPathExpansion(
|
| + hash_store_id_, &hash_of_hashes)) {
|
| + return false;
|
| + }
|
| +
|
| + return pref_hash_calculator_.Validate(
|
| + hash_store_id_, hashes_dict, hash_of_hashes) == PrefHashCalculator::VALID;
|
| +}
|
|
|