Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(762)

Side by Side Diff: chrome/browser/prefs/pref_hash_calculator.cc

Issue 90563003: Fix a race condition in preference metric reporting. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/prefs/pref_hash_calculator.h"
6
7 #include <vector>
8
9 #include "base/json/json_string_value_serializer.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "crypto/hmac.h"
16
17 #if defined (OS_WIN) && defined(ENABLE_RLZ)
18 #include "rlz/lib/machine_id.h"
19 #endif
20 namespace {
gab 2013/11/27 23:43:27 nit: +empty line above
21
22 // Renders |value| as a string. |value| may be NULL, in which case the result
23 // is an empty string.
24 std::string ValueAsString(const base::Value* value) {
25 // Dictionary values may contain empty lists and sub-dictionaries. Make a
26 // deep copy with those removed to make the hash more stable.
27 const base::DictionaryValue* dict_value;
28 scoped_ptr<DictionaryValue> canonical_dict_value;
29 if (value && value->GetAsDictionary(&dict_value)) {
30 canonical_dict_value.reset(dict_value->DeepCopyWithoutEmptyChildren());
31 value = canonical_dict_value.get();
32 }
33
34 std::string value_as_string;
35 if (value) {
36 JSONStringValueSerializer serializer(&value_as_string);
37 serializer.Serialize(*value);
38 }
39
40 return value_as_string;
41 }
42
43 // Common helper for all hash algorithms.
44 std::string CalculateFromValueAndComponents(
45 const std::string& seed,
46 const base::Value* value,
47 const std::vector<std::string>& extra_components) {
48 static const size_t kSHA256DigestSize = 32;
49
50 std::string message = JoinString(extra_components, "") + ValueAsString(value);
51
52 crypto::HMAC hmac(crypto::HMAC::SHA256);
53 unsigned char digest[kSHA256DigestSize];
54 if (!hmac.Init(seed) || !hmac.Sign(message, digest, arraysize(digest))) {
55 NOTREACHED();
56 return std::string();
57 }
58
59 return base::HexEncode(digest, arraysize(digest));
60 }
61
62
63 // Common signature for current and legacy hash algorithms.
64 typedef std::string (CalculateFunctor)(const std::string& seed,
65 const std::string& path,
66 const base::Value* value);
67
68 #if defined(OS_WIN) && defined(ENABLE_RLZ)
69 // Current algorithm on Windows.
70 std::string CalculateWithDeviceId(const std::string& seed,
71 const std::string& path,
72 const base::Value* value) {
73 std::vector<std::string> components;
74
75 // This is used by
76 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc
77 // but that API is private and other platforms are not available
78 // synchronously.
79 // As part of improving pref metrics on other platforms we may want to find
80 // ways to defer preference loading until the device ID can be used.
81 components.resize(2);
82 rlz_lib::GetMachineId(&components[0]);
83 components[1] = path;
84 return CalculateFromValueAndComponents(seed, value, components);
85 }
86 #else
87 // Current algorithm when device ID is not available synchronously.
88 std::string CalculateWithPath(const std::string& seed,
89 const std::string& path,
90 const base::Value* value) {
91 std::vector<std::string> components;
92 components.insert(components.begin(), path);
gab 2013/11/27 23:43:27 components.push_back(path); would be simpler here.
93 return CalculateFromValueAndComponents(seed, value, components);
94 }
95 #endif
96
97 // Legacy algorithm.
98 std::string CalculateWithValueOnly(const std::string& seed,
99 const std::string& path,
100 const base::Value* value) {
101 return CalculateFromValueAndComponents(seed,
102 value,
103 std::vector<std::string>());
104 }
105
106 // Put the "modern" calculator followed by all deprecated calculators from which
107 // migration is supported.
108 static CalculateFunctor* const kCalculators[] = {
109 #if defined(OS_WIN) && defined(ENABLE_RLZ)
110 CalculateWithDeviceId,
111 #else
112 CalculateWithPath,
113 #endif
114 CalculateWithValueOnly
115 };
116
117 } // namespace
118
119 PrefHashCalculator::PrefHashCalculator(const std::string& seed) : seed_(seed) {}
120
121 PrefHashCalculator::ValidationResult PrefHashCalculator::Validate(
122 const std::string& path,
123 const base::Value* value,
124 const std::string& hash) {
125 // Attempt validation with each of the supported algorithms.
126 for (size_t i = 0; i < arraysize(kCalculators); ++i) {
127 if (hash == kCalculators[i](seed_, path, value))
128 return i == 0 ? VALID : VALID_LEGACY;
gab 2013/11/27 23:43:27 I love the CalculateFunctor approach, but it seems
erikwright (departed) 2013/11/28 17:48:07 Actually already refactored this in the patchset t
129 }
130 return INVALID;
131 }
132
133 std::string PrefHashCalculator::Calculate(const std::string& path,
134 const base::Value* value) {
135 // Use the current (first listed) algorithm to calculate the hash.
136 return kCalculators[0](seed_, path, value);
137 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698