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

Side by Side Diff: chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc

Issue 2614773008: Add a config class for the settings reset prompt. (Closed)
Patch Set: Rebase and fixed constructor call in unittest. Created 3 years, 11 months 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
OLDNEW
(Empty)
1 // Copyright 2017 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/safe_browsing/settings_reset_prompt/settings_reset_prom pt_config.h"
6
7 #include <utility>
8
9 #include "base/json/json_reader.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/string_util.h"
15 #include "base/values.h"
16 #include "components/url_formatter/url_fixer.h"
17 #include "components/variations/variations_associated_data.h"
18 #include "crypto/sha2.h"
19 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
20 #include "url/gurl.h"
21
22 namespace safe_browsing {
23
24 namespace {
25
26 const char kSettingsResetPromptFeatureName[] = "SettingsResetPrompt";
27 const char kDomainHashesParamName[] = "domain_hashes";
28 const char kConfigErrorMetric[] = "SettingsResetPrompt.ConfigError";
29
30 } // namespace.
31
32 const base::Feature kSettingsResetPrompt{kSettingsResetPromptFeatureName,
33 base::FEATURE_DISABLED_BY_DEFAULT};
34
35 // static
36 bool SettingsResetPromptConfig::IsPromptEnabled() {
37 // TODO(alito): Add prefs to local state to track when the user was
38 // last prompted and ensure that we only prompt once per reset prompt
39 // wave.
40 return base::FeatureList::IsEnabled(kSettingsResetPrompt);
41 }
42
43 // static
44 std::unique_ptr<SettingsResetPromptConfig> SettingsResetPromptConfig::Create() {
45 if (!IsPromptEnabled())
46 return nullptr;
47
48 auto prompt_config = base::WrapUnique(new SettingsResetPromptConfig());
49 if (!prompt_config->Init())
50 return nullptr;
51
52 return prompt_config;
53 }
54
55 SettingsResetPromptConfig::SettingsResetPromptConfig() {}
56
57 SettingsResetPromptConfig::~SettingsResetPromptConfig() {}
58
59 int SettingsResetPromptConfig::UrlToResetDomainId(const GURL& url) const {
60 DCHECK(IsPromptEnabled());
61
62 // Do a best-effort to fix the URL before testing if it is valid.
63 GURL fixed_url =
64 url_formatter::FixupURL(url.possibly_invalid_spec(), std::string());
65 if (!fixed_url.is_valid())
66 return -1;
67
68 // Get the length of the top level domain or registry of the URL. Used
69 // to guard against trying to match the (effective) TLDs themselves.
70 size_t registry_length = net::registry_controlled_domains::GetRegistryLength(
71 fixed_url, net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
72 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
73 // Do not proceed, if |fixed_url| does not have a host or consists entirely of
74 // a registry or top domain.
75 if (registry_length == 0 || registry_length == std::string::npos)
76 return -1;
77
78 // The hashes in the prompt config are generally TLD+1 and identify
79 // only the topmost levels of URLs that we wish to prompt for. Try to
80 // match each sensible suffix of the URL host with the hashes in the
81 // prompt config. For example, if the host is
82 // "www.sub.domain.com", try hashes for:
83 // "www.sub.domain.com"
84 // "sub.domain.com"
85 // "domain.com"
86 // We Do not check top level or registry domains to guard against bad
87 // configuration data.
88 SHA256Hash hash(crypto::kSHA256Length, '\0');
89 base::StringPiece host = fixed_url.host_piece();
90 while (host.size() > registry_length) {
91 crypto::SHA256HashString(host, hash.data(), crypto::kSHA256Length);
92 auto iter = domain_hashes_.find(hash);
93 if (iter != domain_hashes_.end())
94 return iter->second;
95
96 size_t next_start_pos = host.find('.');
97 next_start_pos = next_start_pos == base::StringPiece::npos
98 ? base::StringPiece::npos
99 : next_start_pos + 1;
100 host = host.substr(next_start_pos);
101 }
102
103 return -1;
104 }
105
106 // Implements the hash function for SHA256Hash objects. Simply uses the
107 // first bytes of the SHA256 hash as its own hash.
108 size_t SettingsResetPromptConfig::SHA256HashHasher::operator()(
109 const SHA256Hash& key) const {
110 DCHECK_EQ(crypto::kSHA256Length, key.size());
111 // This is safe because |key| contains 32 bytes while a size_t is
112 // either 4 or 8 bytes.
113 return *reinterpret_cast<const size_t*>(key.data());
114 }
115
116 // These values are written to logs. New enum values can be added, but
117 // existing enums must never be renumbered or deleted and reused. If you
118 // do add values, also update the corresponding enum definition in the
119 // histograms.xml file.
120 enum SettingsResetPromptConfig::ConfigError : int {
121 CONFIG_ERROR_OK = 1,
122 CONFIG_ERROR_MISSING_DOMAIN_HASHES_PARAM = 2,
123 CONFIG_ERROR_BAD_DOMAIN_HASHES_PARAM = 3,
124 CONFIG_ERROR_BAD_DOMAIN_HASH = 4,
125 CONFIG_ERROR_BAD_DOMAIN_ID = 5,
126 CONFIG_ERROR_DUPLICATE_DOMAIN_HASH = 6,
127 CONFIG_ERROR_MAX
128 };
129
130 bool SettingsResetPromptConfig::Init() {
131 if (!IsPromptEnabled())
132 return false;
133
134 std::string domain_hashes_json = variations::GetVariationParamValueByFeature(
135 kSettingsResetPrompt, kDomainHashesParamName);
136 ConfigError error = ParseDomainHashes(domain_hashes_json);
137 UMA_HISTOGRAM_ENUMERATION(kConfigErrorMetric, error, CONFIG_ERROR_MAX);
rkaplow 2017/01/12 18:42:33 generally people inline the metric name
alito 2017/01/12 18:55:36 Done.
138 return error == CONFIG_ERROR_OK;
139 }
140
141 SettingsResetPromptConfig::ConfigError
142 SettingsResetPromptConfig::ParseDomainHashes(
143 const std::string& domain_hashes_json) {
144 if (domain_hashes_json.empty())
145 return CONFIG_ERROR_MISSING_DOMAIN_HASHES_PARAM;
146
147 // Is the input parseable JSON?
148 std::unique_ptr<base::DictionaryValue> domains_dict =
149 base::DictionaryValue::From(base::JSONReader::Read(domain_hashes_json));
150 if (!domains_dict || domains_dict->empty())
151 return CONFIG_ERROR_BAD_DOMAIN_HASHES_PARAM;
152
153 // The input JSON should be a hash object with hex-encoded 32-byte
154 // hashes as keys and integer IDs as values. For example,
155 //
156 // {"2714..D7": "1", "2821..CB": "2", ...}
157 //
158 // Each key in the hash should be a 64-byte long string and each
159 // integer ID should fit in an int.
160 domain_hashes_.clear();
161 for (base::DictionaryValue::Iterator iter(*domains_dict); !iter.IsAtEnd();
162 iter.Advance()) {
163 const std::string& hash_string = iter.key();
164 if (hash_string.size() != crypto::kSHA256Length * 2)
165 return CONFIG_ERROR_BAD_DOMAIN_HASH;
166
167 // Convert hex-encoded hash string to its numeric value as bytes.
168 SHA256Hash hash;
169 hash.reserve(crypto::kSHA256Length);
170 if (!base::HexStringToBytes(hash_string, &hash))
171 return CONFIG_ERROR_BAD_DOMAIN_HASH;
172
173 // Convert the ID string to an integer.
174 std::string domain_id_string;
175 int domain_id = -1;
176 if (!iter.value().GetAsString(&domain_id_string) ||
177 !base::StringToInt(domain_id_string, &domain_id) || domain_id < 0) {
178 return CONFIG_ERROR_BAD_DOMAIN_ID;
179 }
180
181 if (!domain_hashes_.insert(std::make_pair(std::move(hash), domain_id))
182 .second)
183 return CONFIG_ERROR_DUPLICATE_DOMAIN_HASH;
184 }
185
186 return CONFIG_ERROR_OK;
187 }
188
189 } // namespace safe_browsing.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698