Roll src/third_party/WebKit 3aea697:d9c6159 (svn 201973:201974)
[chromium-blink-merge.git] / components / user_prefs / tracked / pref_hash_store_impl.cc
blobdd862221d57e5683ac88ddd3428d7e241769940c
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
3 // found in the LICENSE file.
5 #include "components/user_prefs/tracked/pref_hash_store_impl.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/values.h"
10 #include "components/user_prefs/tracked/hash_store_contents.h"
11 #include "components/user_prefs/tracked/pref_hash_store_transaction.h"
13 class PrefHashStoreImpl::PrefHashStoreTransactionImpl
14 : public PrefHashStoreTransaction {
15 public:
16 // Constructs a PrefHashStoreTransactionImpl which can use the private
17 // members of its |outer| PrefHashStoreImpl.
18 PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer,
19 scoped_ptr<HashStoreContents> storage);
20 ~PrefHashStoreTransactionImpl() override;
22 // PrefHashStoreTransaction implementation.
23 ValueState CheckValue(const std::string& path,
24 const base::Value* value) const override;
25 void StoreHash(const std::string& path, const base::Value* value) override;
26 ValueState CheckSplitValue(
27 const std::string& path,
28 const base::DictionaryValue* initial_split_value,
29 std::vector<std::string>* invalid_keys) const override;
30 void StoreSplitHash(const std::string& path,
31 const base::DictionaryValue* split_value) override;
32 bool HasHash(const std::string& path) const override;
33 void ImportHash(const std::string& path, const base::Value* hash) override;
34 void ClearHash(const std::string& path) override;
35 bool IsSuperMACValid() const override;
36 bool StampSuperMac() override;
38 private:
39 bool GetSplitMacs(const std::string& path,
40 std::map<std::string, std::string>* split_macs) const;
42 HashStoreContents* contents() {
43 return outer_->legacy_hash_store_contents_
44 ? outer_->legacy_hash_store_contents_.get()
45 : contents_.get();
48 const HashStoreContents* contents() const {
49 return outer_->legacy_hash_store_contents_
50 ? outer_->legacy_hash_store_contents_.get()
51 : contents_.get();
54 PrefHashStoreImpl* outer_;
55 scoped_ptr<HashStoreContents> contents_;
57 bool super_mac_valid_;
58 bool super_mac_dirty_;
60 DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl);
63 PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
64 const std::string& device_id,
65 bool use_super_mac)
66 : pref_hash_calculator_(seed, device_id), use_super_mac_(use_super_mac) {
69 PrefHashStoreImpl::~PrefHashStoreImpl() {
72 void PrefHashStoreImpl::set_legacy_hash_store_contents(
73 scoped_ptr<HashStoreContents> legacy_hash_store_contents) {
74 legacy_hash_store_contents_ = legacy_hash_store_contents.Pass();
77 scoped_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
78 scoped_ptr<HashStoreContents> storage) {
79 return scoped_ptr<PrefHashStoreTransaction>(
80 new PrefHashStoreTransactionImpl(this, storage.Pass()));
83 PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
84 PrefHashStoreImpl* outer,
85 scoped_ptr<HashStoreContents> storage)
86 : outer_(outer),
87 contents_(storage.Pass()),
88 super_mac_valid_(false),
89 super_mac_dirty_(false) {
90 if (!outer_->use_super_mac_)
91 return;
93 // The store must be initialized and have a valid super MAC to be trusted.
95 const base::DictionaryValue* store_contents = contents()->GetContents();
96 if (!store_contents)
97 return;
99 std::string super_mac = contents()->GetSuperMac();
100 if (super_mac.empty())
101 return;
103 super_mac_valid_ = outer_->pref_hash_calculator_.Validate(
104 contents()->hash_store_id(), store_contents,
105 super_mac) == PrefHashCalculator::VALID;
108 PrefHashStoreImpl::PrefHashStoreTransactionImpl::
109 ~PrefHashStoreTransactionImpl() {
110 if (super_mac_dirty_ && outer_->use_super_mac_) {
111 // Get the dictionary of hashes (or NULL if it doesn't exist).
112 const base::DictionaryValue* hashes_dict = contents()->GetContents();
113 contents()->SetSuperMac(outer_->pref_hash_calculator_.Calculate(
114 contents()->hash_store_id(), hashes_dict));
118 PrefHashStoreTransaction::ValueState
119 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
120 const std::string& path,
121 const base::Value* initial_value) const {
122 const base::DictionaryValue* hashes_dict = contents()->GetContents();
124 std::string last_hash;
125 if (hashes_dict)
126 hashes_dict->GetString(path, &last_hash);
128 if (last_hash.empty()) {
129 // In the absence of a hash for this pref, always trust a NULL value, but
130 // only trust an existing value if the initial hashes dictionary is trusted.
131 if (!initial_value)
132 return TRUSTED_NULL_VALUE;
133 else if (super_mac_valid_)
134 return TRUSTED_UNKNOWN_VALUE;
135 else
136 return UNTRUSTED_UNKNOWN_VALUE;
139 PrefHashCalculator::ValidationResult validation_result =
140 outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash);
141 switch (validation_result) {
142 case PrefHashCalculator::VALID:
143 return UNCHANGED;
144 case PrefHashCalculator::VALID_SECURE_LEGACY:
145 return SECURE_LEGACY;
146 case PrefHashCalculator::INVALID:
147 return initial_value ? CHANGED : CLEARED;
149 NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
150 << validation_result;
151 return UNTRUSTED_UNKNOWN_VALUE;
154 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
155 const std::string& path,
156 const base::Value* new_value) {
157 const std::string mac =
158 outer_->pref_hash_calculator_.Calculate(path, new_value);
159 (*contents()->GetMutableContents())->SetString(path, mac);
160 super_mac_dirty_ = true;
163 PrefHashStoreTransaction::ValueState
164 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
165 const std::string& path,
166 const base::DictionaryValue* initial_split_value,
167 std::vector<std::string>* invalid_keys) const {
168 DCHECK(invalid_keys && invalid_keys->empty());
170 std::map<std::string, std::string> split_macs;
171 const bool has_hashes = GetSplitMacs(path, &split_macs);
173 // Treat NULL and empty the same; otherwise we would need to store a hash for
174 // the entire dictionary (or some other special beacon) to differentiate these
175 // two cases which are really the same for dictionaries.
176 if (!initial_split_value || initial_split_value->empty())
177 return has_hashes ? CLEARED : UNCHANGED;
179 if (!has_hashes)
180 return super_mac_valid_ ? TRUSTED_UNKNOWN_VALUE : UNTRUSTED_UNKNOWN_VALUE;
182 bool has_secure_legacy_id_hashes = false;
183 std::string keyed_path(path);
184 keyed_path.push_back('.');
185 const size_t common_part_length = keyed_path.length();
186 for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd();
187 it.Advance()) {
188 std::map<std::string, std::string>::iterator entry =
189 split_macs.find(it.key());
190 if (entry == split_macs.end()) {
191 invalid_keys->push_back(it.key());
192 } else {
193 // Keep the common part from the old |keyed_path| and replace the key to
194 // get the new |keyed_path|.
195 keyed_path.replace(common_part_length, std::string::npos, it.key());
196 switch (outer_->pref_hash_calculator_.Validate(keyed_path, &it.value(),
197 entry->second)) {
198 case PrefHashCalculator::VALID:
199 break;
200 case SECURE_LEGACY:
201 // Secure legacy device IDs based hashes are still accepted, but we
202 // should make sure to notify the caller for him to update the legacy
203 // hashes.
204 has_secure_legacy_id_hashes = true;
205 break;
206 case PrefHashCalculator::INVALID:
207 invalid_keys->push_back(it.key());
208 break;
210 // Remove processed MACs, remaining MACs at the end will also be
211 // considered invalid.
212 split_macs.erase(entry);
216 // Anything left in the map is missing from the data.
217 for (std::map<std::string, std::string>::const_iterator it =
218 split_macs.begin();
219 it != split_macs.end(); ++it) {
220 invalid_keys->push_back(it->first);
223 return invalid_keys->empty()
224 ? (has_secure_legacy_id_hashes ? SECURE_LEGACY : UNCHANGED)
225 : CHANGED;
228 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
229 const std::string& path,
230 const base::DictionaryValue* split_value) {
231 scoped_ptr<HashStoreContents::MutableDictionary> mutable_dictionary =
232 contents()->GetMutableContents();
233 (*mutable_dictionary)->Remove(path, NULL);
235 if (split_value) {
236 std::string keyed_path(path);
237 keyed_path.push_back('.');
238 const size_t common_part_length = keyed_path.length();
239 for (base::DictionaryValue::Iterator it(*split_value); !it.IsAtEnd();
240 it.Advance()) {
241 // Keep the common part from the old |keyed_path| and replace the key to
242 // get the new |keyed_path|.
243 keyed_path.replace(common_part_length, std::string::npos, it.key());
244 (*mutable_dictionary)
245 ->SetString(keyed_path, outer_->pref_hash_calculator_.Calculate(
246 keyed_path, &it.value()));
249 super_mac_dirty_ = true;
252 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs(
253 const std::string& key,
254 std::map<std::string, std::string>* split_macs) const {
255 DCHECK(split_macs);
256 DCHECK(split_macs->empty());
258 const base::DictionaryValue* hashes_dict = contents()->GetContents();
259 const base::DictionaryValue* split_mac_dictionary = NULL;
260 if (!hashes_dict || !hashes_dict->GetDictionary(key, &split_mac_dictionary))
261 return false;
262 for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd();
263 it.Advance()) {
264 std::string mac_string;
265 if (!it.value().GetAsString(&mac_string)) {
266 NOTREACHED();
267 continue;
269 split_macs->insert(make_pair(it.key(), mac_string));
271 return true;
274 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash(
275 const std::string& path) const {
276 const base::DictionaryValue* hashes_dict = contents()->GetContents();
277 return hashes_dict && hashes_dict->Get(path, NULL);
280 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
281 const std::string& path,
282 const base::Value* hash) {
283 DCHECK(hash);
285 (*contents()->GetMutableContents())->Set(path, hash->DeepCopy());
287 if (super_mac_valid_)
288 super_mac_dirty_ = true;
291 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash(
292 const std::string& path) {
293 if ((*contents()->GetMutableContents())->RemovePath(path, NULL) &&
294 super_mac_valid_) {
295 super_mac_dirty_ = true;
299 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const {
300 return super_mac_valid_;
303 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() {
304 if (!outer_->use_super_mac_ || super_mac_valid_)
305 return false;
306 super_mac_dirty_ = true;
307 return true;