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

Unified 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: Address rkaplow@'s comments 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
new file mode 100644
index 0000000000000000000000000000000000000000..17601d090ed4c073667cec528fe69667314652a7
--- /dev/null
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
@@ -0,0 +1,189 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h"
+
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "components/url_formatter/url_fixer.h"
+#include "components/variations/variations_associated_data.h"
+#include "crypto/sha2.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/gurl.h"
+
+namespace safe_browsing {
+
+namespace {
+
+const char kSettingsResetPromptFeatureName[] = "SettingsResetPrompt";
+const char kDomainHashesParamName[] = "domain_hashes";
+
+} // namespace.
+
+const base::Feature kSettingsResetPrompt{kSettingsResetPromptFeatureName,
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// static
+bool SettingsResetPromptConfig::IsPromptEnabled() {
+ // TODO(alito): Add prefs to local state to track when the user was
+ // last prompted and ensure that we only prompt once per reset prompt
+ // wave.
+ return base::FeatureList::IsEnabled(kSettingsResetPrompt);
+}
+
+// static
+std::unique_ptr<SettingsResetPromptConfig> SettingsResetPromptConfig::Create() {
+ if (!IsPromptEnabled())
+ return nullptr;
+
+ auto prompt_config = base::WrapUnique(new SettingsResetPromptConfig());
+ if (!prompt_config->Init())
+ return nullptr;
+
+ return prompt_config;
+}
+
+SettingsResetPromptConfig::SettingsResetPromptConfig() {}
+
+SettingsResetPromptConfig::~SettingsResetPromptConfig() {}
+
+int SettingsResetPromptConfig::UrlToResetDomainId(const GURL& url) const {
+ DCHECK(IsPromptEnabled());
+
+ // Do a best-effort to fix the URL before testing if it is valid.
+ GURL fixed_url =
+ url_formatter::FixupURL(url.possibly_invalid_spec(), std::string());
+ if (!fixed_url.is_valid())
+ return -1;
+
+ // Get the length of the top level domain or registry of the URL. Used
+ // to guard against trying to match the (effective) TLDs themselves.
+ size_t registry_length = net::registry_controlled_domains::GetRegistryLength(
+ fixed_url, net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+ // Do not proceed, if |fixed_url| does not have a host or consists entirely of
+ // a registry or top domain.
+ if (registry_length == 0 || registry_length == std::string::npos)
+ return -1;
+
+ // The hashes in the prompt config are generally TLD+1 and identify
+ // only the topmost levels of URLs that we wish to prompt for. Try to
+ // match each sensible suffix of the URL host with the hashes in the
+ // prompt config. For example, if the host is
+ // "www.sub.domain.com", try hashes for:
+ // "www.sub.domain.com"
+ // "sub.domain.com"
+ // "domain.com"
+ // We Do not check top level or registry domains to guard against bad
+ // configuration data.
+ SHA256Hash hash(crypto::kSHA256Length, '\0');
+ base::StringPiece host = fixed_url.host_piece();
+ while (host.size() > registry_length) {
+ crypto::SHA256HashString(host, hash.data(), crypto::kSHA256Length);
+ auto iter = domain_hashes_.find(hash);
+ if (iter != domain_hashes_.end())
+ return iter->second;
+
+ size_t next_start_pos = host.find('.');
+ next_start_pos = next_start_pos == base::StringPiece::npos
+ ? base::StringPiece::npos
+ : next_start_pos + 1;
+ host = host.substr(next_start_pos);
+ }
+
+ return -1;
+}
+
+// Implements the hash function for SHA256Hash objects. Simply uses the
+// first bytes of the SHA256 hash as its own hash.
+size_t SettingsResetPromptConfig::SHA256HashHasher::operator()(
+ const SHA256Hash& key) const {
+ DCHECK_EQ(crypto::kSHA256Length, key.size());
+ // This is safe because |key| contains 32 bytes while a size_t is
+ // either 4 or 8 bytes.
+ return *reinterpret_cast<const size_t*>(key.data());
+}
+
+// These values are written to logs. New enum values can be added, but
+// existing enums must never be renumbered or deleted and reused. If you
+// do add values, also update the corresponding enum definition in the
+// histograms.xml file.
+enum SettingsResetPromptConfig::ConfigError : int {
+ CONFIG_ERROR_OK = 1,
+ CONFIG_ERROR_MISSING_DOMAIN_HASHES_PARAM = 2,
+ CONFIG_ERROR_BAD_DOMAIN_HASHES_PARAM = 3,
+ CONFIG_ERROR_BAD_DOMAIN_HASH = 4,
+ CONFIG_ERROR_BAD_DOMAIN_ID = 5,
+ CONFIG_ERROR_DUPLICATE_DOMAIN_HASH = 6,
+ CONFIG_ERROR_MAX
+};
+
+bool SettingsResetPromptConfig::Init() {
+ if (!IsPromptEnabled())
+ return false;
+
+ std::string domain_hashes_json = variations::GetVariationParamValueByFeature(
+ kSettingsResetPrompt, kDomainHashesParamName);
+ ConfigError error = ParseDomainHashes(domain_hashes_json);
+ UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ConfigError", error,
+ CONFIG_ERROR_MAX);
+ return error == CONFIG_ERROR_OK;
+}
+
+SettingsResetPromptConfig::ConfigError
+SettingsResetPromptConfig::ParseDomainHashes(
+ const std::string& domain_hashes_json) {
+ if (domain_hashes_json.empty())
+ return CONFIG_ERROR_MISSING_DOMAIN_HASHES_PARAM;
+
+ // Is the input parseable JSON?
+ std::unique_ptr<base::DictionaryValue> domains_dict =
+ base::DictionaryValue::From(base::JSONReader::Read(domain_hashes_json));
+ if (!domains_dict || domains_dict->empty())
+ return CONFIG_ERROR_BAD_DOMAIN_HASHES_PARAM;
+
+ // The input JSON should be a hash object with hex-encoded 32-byte
+ // hashes as keys and integer IDs as values. For example,
+ //
+ // {"2714..D7": "1", "2821..CB": "2", ...}
+ //
+ // Each key in the hash should be a 64-byte long string and each
+ // integer ID should fit in an int.
+ domain_hashes_.clear();
+ for (base::DictionaryValue::Iterator iter(*domains_dict); !iter.IsAtEnd();
+ iter.Advance()) {
+ const std::string& hash_string = iter.key();
+ if (hash_string.size() != crypto::kSHA256Length * 2)
+ return CONFIG_ERROR_BAD_DOMAIN_HASH;
+
+ // Convert hex-encoded hash string to its numeric value as bytes.
+ SHA256Hash hash;
+ hash.reserve(crypto::kSHA256Length);
+ if (!base::HexStringToBytes(hash_string, &hash))
+ return CONFIG_ERROR_BAD_DOMAIN_HASH;
+
+ // Convert the ID string to an integer.
+ std::string domain_id_string;
+ int domain_id = -1;
+ if (!iter.value().GetAsString(&domain_id_string) ||
+ !base::StringToInt(domain_id_string, &domain_id) || domain_id < 0) {
+ return CONFIG_ERROR_BAD_DOMAIN_ID;
+ }
+
+ if (!domain_hashes_.insert(std::make_pair(std::move(hash), domain_id))
+ .second)
+ return CONFIG_ERROR_DUPLICATE_DOMAIN_HASH;
+ }
+
+ return CONFIG_ERROR_OK;
+}
+
+} // namespace safe_browsing.

Powered by Google App Engine
This is Rietveld 408576698