| 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 "components/user_prefs/tracked/pref_hash_store_impl.h" | 5 #include "services/preferences/tracked/pref_hash_store_impl.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "components/user_prefs/tracked/device_id.h" | 13 #include "services/preferences/tracked/device_id.h" |
| 14 #include "components/user_prefs/tracked/hash_store_contents.h" | 14 #include "services/preferences/tracked/hash_store_contents.h" |
| 15 | 15 |
| 16 namespace { | 16 namespace { |
| 17 | 17 |
| 18 using ValueState = |
| 19 prefs::mojom::TrackedPreferenceValidationDelegate::ValueState; |
| 20 |
| 18 // Returns a deterministic ID for this machine. | 21 // Returns a deterministic ID for this machine. |
| 19 std::string GenerateDeviceId() { | 22 std::string GenerateDeviceId() { |
| 20 static std::string cached_device_id; | 23 static std::string cached_device_id; |
| 21 if (!cached_device_id.empty()) | 24 if (!cached_device_id.empty()) |
| 22 return cached_device_id; | 25 return cached_device_id; |
| 23 | 26 |
| 24 std::string device_id; | 27 std::string device_id; |
| 25 MachineIdStatus status = GetDeterministicMachineSpecificId(&device_id); | 28 MachineIdStatus status = GetDeterministicMachineSpecificId(&device_id); |
| 26 if (status != MachineIdStatus::NOT_IMPLEMENTED) { | 29 if (status != MachineIdStatus::NOT_IMPLEMENTED) { |
| 27 // TODO(proberge): Remove this histogram once we validate that machine id | 30 // TODO(proberge): Remove this histogram once we validate that machine id |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 | 78 |
| 76 DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl); | 79 DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl); |
| 77 }; | 80 }; |
| 78 | 81 |
| 79 PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed, | 82 PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed, |
| 80 const std::string& legacy_device_id, | 83 const std::string& legacy_device_id, |
| 81 bool use_super_mac) | 84 bool use_super_mac) |
| 82 : pref_hash_calculator_(seed, GenerateDeviceId(), legacy_device_id), | 85 : pref_hash_calculator_(seed, GenerateDeviceId(), legacy_device_id), |
| 83 use_super_mac_(use_super_mac) {} | 86 use_super_mac_(use_super_mac) {} |
| 84 | 87 |
| 85 PrefHashStoreImpl::~PrefHashStoreImpl() { | 88 PrefHashStoreImpl::~PrefHashStoreImpl() {} |
| 86 } | |
| 87 | 89 |
| 88 std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction( | 90 std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction( |
| 89 HashStoreContents* storage) { | 91 HashStoreContents* storage) { |
| 90 return std::unique_ptr<PrefHashStoreTransaction>( | 92 return std::unique_ptr<PrefHashStoreTransaction>( |
| 91 new PrefHashStoreTransactionImpl(this, std::move(storage))); | 93 new PrefHashStoreTransactionImpl(this, std::move(storage))); |
| 92 } | 94 } |
| 93 | 95 |
| 94 std::string PrefHashStoreImpl::ComputeMac(const std::string& path, | 96 std::string PrefHashStoreImpl::ComputeMac(const std::string& path, |
| 95 const base::Value* value) { | 97 const base::Value* value) { |
| 96 return pref_hash_calculator_.Calculate(path, value); | 98 return pref_hash_calculator_.Calculate(path, value); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 const base::DictionaryValue* hashes_dict = contents_->GetContents(); | 149 const base::DictionaryValue* hashes_dict = contents_->GetContents(); |
| 148 contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict)); | 150 contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict)); |
| 149 } | 151 } |
| 150 } | 152 } |
| 151 | 153 |
| 152 base::StringPiece | 154 base::StringPiece |
| 153 PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const { | 155 PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const { |
| 154 return contents_->GetUMASuffix(); | 156 return contents_->GetUMASuffix(); |
| 155 } | 157 } |
| 156 | 158 |
| 157 PrefHashStoreTransaction::ValueState | 159 ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( |
| 158 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( | |
| 159 const std::string& path, | 160 const std::string& path, |
| 160 const base::Value* initial_value) const { | 161 const base::Value* initial_value) const { |
| 161 std::string last_hash; | 162 std::string last_hash; |
| 162 contents_->GetMac(path, &last_hash); | 163 contents_->GetMac(path, &last_hash); |
| 163 | 164 |
| 164 if (last_hash.empty()) { | 165 if (last_hash.empty()) { |
| 165 // In the absence of a hash for this pref, always trust a NULL value, but | 166 // In the absence of a hash for this pref, always trust a NULL value, but |
| 166 // only trust an existing value if the initial hashes dictionary is trusted. | 167 // only trust an existing value if the initial hashes dictionary is trusted. |
| 167 if (!initial_value) | 168 if (!initial_value) |
| 168 return TRUSTED_NULL_VALUE; | 169 return ValueState::TRUSTED_NULL_VALUE; |
| 169 else if (super_mac_valid_) | 170 else if (super_mac_valid_) |
| 170 return TRUSTED_UNKNOWN_VALUE; | 171 return ValueState::TRUSTED_UNKNOWN_VALUE; |
| 171 else | 172 else |
| 172 return UNTRUSTED_UNKNOWN_VALUE; | 173 return ValueState::UNTRUSTED_UNKNOWN_VALUE; |
| 173 } | 174 } |
| 174 | 175 |
| 175 PrefHashCalculator::ValidationResult validation_result = | 176 PrefHashCalculator::ValidationResult validation_result = |
| 176 outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash); | 177 outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash); |
| 177 switch (validation_result) { | 178 switch (validation_result) { |
| 178 case PrefHashCalculator::VALID: | 179 case PrefHashCalculator::VALID: |
| 179 return UNCHANGED; | 180 return ValueState::UNCHANGED; |
| 180 case PrefHashCalculator::VALID_SECURE_LEGACY: | 181 case PrefHashCalculator::VALID_SECURE_LEGACY: |
| 181 return SECURE_LEGACY; | 182 return ValueState::SECURE_LEGACY; |
| 182 case PrefHashCalculator::INVALID: | 183 case PrefHashCalculator::INVALID: |
| 183 return initial_value ? CHANGED : CLEARED; | 184 return initial_value ? ValueState::CHANGED : ValueState::CLEARED; |
| 184 } | 185 } |
| 185 NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: " | 186 NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: " |
| 186 << validation_result; | 187 << validation_result; |
| 187 return UNTRUSTED_UNKNOWN_VALUE; | 188 return ValueState::UNTRUSTED_UNKNOWN_VALUE; |
| 188 } | 189 } |
| 189 | 190 |
| 190 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash( | 191 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash( |
| 191 const std::string& path, | 192 const std::string& path, |
| 192 const base::Value* new_value) { | 193 const base::Value* new_value) { |
| 193 const std::string mac = outer_->ComputeMac(path, new_value); | 194 const std::string mac = outer_->ComputeMac(path, new_value); |
| 194 contents_->SetMac(path, mac); | 195 contents_->SetMac(path, mac); |
| 195 super_mac_dirty_ = true; | 196 super_mac_dirty_ = true; |
| 196 } | 197 } |
| 197 | 198 |
| 198 PrefHashStoreTransaction::ValueState | 199 ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( |
| 199 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( | |
| 200 const std::string& path, | 200 const std::string& path, |
| 201 const base::DictionaryValue* initial_split_value, | 201 const base::DictionaryValue* initial_split_value, |
| 202 std::vector<std::string>* invalid_keys) const { | 202 std::vector<std::string>* invalid_keys) const { |
| 203 DCHECK(invalid_keys && invalid_keys->empty()); | 203 DCHECK(invalid_keys && invalid_keys->empty()); |
| 204 | 204 |
| 205 std::map<std::string, std::string> split_macs; | 205 std::map<std::string, std::string> split_macs; |
| 206 const bool has_hashes = contents_->GetSplitMacs(path, &split_macs); | 206 const bool has_hashes = contents_->GetSplitMacs(path, &split_macs); |
| 207 | 207 |
| 208 // Treat NULL and empty the same; otherwise we would need to store a hash for | 208 // Treat NULL and empty the same; otherwise we would need to store a hash for |
| 209 // the entire dictionary (or some other special beacon) to differentiate these | 209 // the entire dictionary (or some other special beacon) to differentiate these |
| 210 // two cases which are really the same for dictionaries. | 210 // two cases which are really the same for dictionaries. |
| 211 if (!initial_split_value || initial_split_value->empty()) | 211 if (!initial_split_value || initial_split_value->empty()) |
| 212 return has_hashes ? CLEARED : UNCHANGED; | 212 return has_hashes ? ValueState::CLEARED : ValueState::UNCHANGED; |
| 213 | 213 |
| 214 if (!has_hashes) | 214 if (!has_hashes) |
| 215 return super_mac_valid_ ? TRUSTED_UNKNOWN_VALUE : UNTRUSTED_UNKNOWN_VALUE; | 215 return super_mac_valid_ ? ValueState::TRUSTED_UNKNOWN_VALUE |
| 216 : ValueState::UNTRUSTED_UNKNOWN_VALUE; |
| 216 | 217 |
| 217 bool has_secure_legacy_id_hashes = false; | 218 bool has_secure_legacy_id_hashes = false; |
| 218 std::string keyed_path(path); | 219 std::string keyed_path(path); |
| 219 keyed_path.push_back('.'); | 220 keyed_path.push_back('.'); |
| 220 const size_t common_part_length = keyed_path.length(); | 221 const size_t common_part_length = keyed_path.length(); |
| 221 for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd(); | 222 for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd(); |
| 222 it.Advance()) { | 223 it.Advance()) { |
| 223 std::map<std::string, std::string>::iterator entry = | 224 std::map<std::string, std::string>::iterator entry = |
| 224 split_macs.find(it.key()); | 225 split_macs.find(it.key()); |
| 225 if (entry == split_macs.end()) { | 226 if (entry == split_macs.end()) { |
| 226 invalid_keys->push_back(it.key()); | 227 invalid_keys->push_back(it.key()); |
| 227 } else { | 228 } else { |
| 228 // Keep the common part from the old |keyed_path| and replace the key to | 229 // Keep the common part from the old |keyed_path| and replace the key to |
| 229 // get the new |keyed_path|. | 230 // get the new |keyed_path|. |
| 230 keyed_path.replace(common_part_length, std::string::npos, it.key()); | 231 keyed_path.replace(common_part_length, std::string::npos, it.key()); |
| 231 switch (outer_->pref_hash_calculator_.Validate(keyed_path, &it.value(), | 232 switch (outer_->pref_hash_calculator_.Validate(keyed_path, &it.value(), |
| 232 entry->second)) { | 233 entry->second)) { |
| 233 case PrefHashCalculator::VALID: | 234 case PrefHashCalculator::VALID: |
| 234 break; | 235 break; |
| 235 case SECURE_LEGACY: | 236 case PrefHashCalculator::VALID_SECURE_LEGACY: |
| 236 // Secure legacy device IDs based hashes are still accepted, but we | 237 // Secure legacy device IDs based hashes are still accepted, but we |
| 237 // should make sure to notify the caller for them to update the legacy | 238 // should make sure to notify the caller for them to update the legacy |
| 238 // hashes. | 239 // hashes. |
| 239 has_secure_legacy_id_hashes = true; | 240 has_secure_legacy_id_hashes = true; |
| 240 break; | 241 break; |
| 241 case PrefHashCalculator::INVALID: | 242 case PrefHashCalculator::INVALID: |
| 242 invalid_keys->push_back(it.key()); | 243 invalid_keys->push_back(it.key()); |
| 243 break; | 244 break; |
| 244 } | 245 } |
| 245 // Remove processed MACs, remaining MACs at the end will also be | 246 // Remove processed MACs, remaining MACs at the end will also be |
| 246 // considered invalid. | 247 // considered invalid. |
| 247 split_macs.erase(entry); | 248 split_macs.erase(entry); |
| 248 } | 249 } |
| 249 } | 250 } |
| 250 | 251 |
| 251 // Anything left in the map is missing from the data. | 252 // Anything left in the map is missing from the data. |
| 252 for (std::map<std::string, std::string>::const_iterator it = | 253 for (std::map<std::string, std::string>::const_iterator it = |
| 253 split_macs.begin(); | 254 split_macs.begin(); |
| 254 it != split_macs.end(); ++it) { | 255 it != split_macs.end(); ++it) { |
| 255 invalid_keys->push_back(it->first); | 256 invalid_keys->push_back(it->first); |
| 256 } | 257 } |
| 257 | 258 |
| 258 return invalid_keys->empty() | 259 return invalid_keys->empty() |
| 259 ? (has_secure_legacy_id_hashes ? SECURE_LEGACY : UNCHANGED) | 260 ? (has_secure_legacy_id_hashes ? ValueState::SECURE_LEGACY |
| 260 : CHANGED; | 261 : ValueState::UNCHANGED) |
| 262 : ValueState::CHANGED; |
| 261 } | 263 } |
| 262 | 264 |
| 263 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash( | 265 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash( |
| 264 const std::string& path, | 266 const std::string& path, |
| 265 const base::DictionaryValue* split_value) { | 267 const base::DictionaryValue* split_value) { |
| 266 contents_->RemoveEntry(path); | 268 contents_->RemoveEntry(path); |
| 267 | 269 |
| 268 if (split_value) { | 270 if (split_value) { |
| 269 std::unique_ptr<base::DictionaryValue> split_macs = | 271 std::unique_ptr<base::DictionaryValue> split_macs = |
| 270 outer_->ComputeSplitMacs(path, split_value); | 272 outer_->ComputeSplitMacs(path, split_value); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const { | 312 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const { |
| 311 return super_mac_valid_; | 313 return super_mac_valid_; |
| 312 } | 314 } |
| 313 | 315 |
| 314 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() { | 316 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() { |
| 315 if (!outer_->use_super_mac_ || super_mac_valid_) | 317 if (!outer_->use_super_mac_ || super_mac_valid_) |
| 316 return false; | 318 return false; |
| 317 super_mac_dirty_ = true; | 319 super_mac_dirty_ = true; |
| 318 return true; | 320 return true; |
| 319 } | 321 } |
| OLD | NEW |