blob: 5eae4fe7fbadb77332bfb055d6c8b0f811c681b0 [file] [log] [blame]
// Copyright 2019 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/net/secure_dns_util.h"
#include <algorithm>
#include <string>
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_split.h"
#include "chrome/common/chrome_features.h"
#include "components/country_codes/country_codes.h"
#include "components/embedder_support/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "net/dns/public/dns_config_overrides.h"
#include "net/dns/public/doh_provider_entry.h"
#include "net/dns/public/util.h"
#include "net/third_party/uri_template/uri_template.h"
#include "url/gurl.h"
namespace chrome_browser_net {
namespace secure_dns {
namespace {
const char kAlternateErrorPagesBackup[] = "alternate_error_pages.backup";
void IncrementDropdownHistogram(net::DohProviderIdForHistogram id,
const std::string& doh_template,
base::StringPiece old_template,
base::StringPiece new_template) {
if (doh_template == old_template) {
UMA_HISTOGRAM_ENUMERATION("Net.DNS.UI.DropdownSelectionEvent.Unselected",
id);
} else if (doh_template == new_template) {
UMA_HISTOGRAM_ENUMERATION("Net.DNS.UI.DropdownSelectionEvent.Selected", id);
} else {
UMA_HISTOGRAM_ENUMERATION("Net.DNS.UI.DropdownSelectionEvent.Ignored", id);
}
}
bool EntryIsForCountry(const net::DohProviderEntry* entry, int country_id) {
if (entry->display_globally) {
return true;
}
const auto& countries = entry->display_countries;
bool matches = std::any_of(countries.begin(), countries.end(),
[country_id](const std::string& country_code) {
return country_codes::CountryStringToCountryID(
country_code) == country_id;
});
if (matches) {
DCHECK(!entry->ui_name.empty());
DCHECK(!entry->privacy_policy.empty());
}
return matches;
}
} // namespace
void RegisterProbesSettingBackupPref(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kAlternateErrorPagesBackup, true);
}
void MigrateProbesSettingToOrFromBackup(PrefService* prefs) {
// If the privacy settings redesign is enabled and the user value of the
// preference hasn't been backed up yet, back it up, and clear it. That way,
// the preference will revert to using the hardcoded default value (unless
// it's managed by a policy or an extension). This is necessary, as the
// privacy settings redesign removed the user-facing toggle, and so the
// user value of the preference is no longer modifiable.
if (base::FeatureList::IsEnabled(features::kPrivacySettingsRedesign) &&
!prefs->HasPrefPath(kAlternateErrorPagesBackup)) {
// If the user never changed the value of the preference and still uses the
// hardcoded default value, we'll consider it to be the user value for
// the purposes of this migration.
const base::Value* user_value =
prefs->FindPreference(embedder_support::kAlternateErrorPagesEnabled)
->HasUserSetting()
? prefs->GetUserPrefValue(
embedder_support::kAlternateErrorPagesEnabled)
: prefs->GetDefaultPrefValue(
embedder_support::kAlternateErrorPagesEnabled);
DCHECK(user_value->is_bool());
prefs->SetBoolean(kAlternateErrorPagesBackup, user_value->GetBool());
prefs->ClearPref(embedder_support::kAlternateErrorPagesEnabled);
}
// If the privacy settings redesign is rolled back and there is a backed up
// value of the preference, restore it to the original preference, and clear
// the backup.
if (!base::FeatureList::IsEnabled(features::kPrivacySettingsRedesign) &&
prefs->HasPrefPath(kAlternateErrorPagesBackup)) {
prefs->SetBoolean(embedder_support::kAlternateErrorPagesEnabled,
prefs->GetBoolean(kAlternateErrorPagesBackup));
prefs->ClearPref(kAlternateErrorPagesBackup);
}
}
net::DohProviderEntry::List ProvidersForCountry(
const net::DohProviderEntry::List& providers,
int country_id) {
net::DohProviderEntry::List local_providers;
std::copy_if(providers.begin(), providers.end(),
std::back_inserter(local_providers),
[country_id](const auto* entry) {
return EntryIsForCountry(entry, country_id);
});
return local_providers;
}
std::vector<std::string> GetDisabledProviders() {
return SplitString(features::kDnsOverHttpsDisabledProvidersParam.Get(), ",",
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
}
net::DohProviderEntry::List RemoveDisabledProviders(
const net::DohProviderEntry::List& providers,
const std::vector<string>& disabled_providers) {
net::DohProviderEntry::List filtered_providers;
std::copy_if(providers.begin(), providers.end(),
std::back_inserter(filtered_providers),
[&disabled_providers](const auto* entry) {
return !base::Contains(disabled_providers, entry->provider);
});
return filtered_providers;
}
std::vector<base::StringPiece> SplitGroup(base::StringPiece group) {
// Templates in a group are whitespace-separated.
return SplitStringPiece(group, " ", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
}
bool IsValidGroup(base::StringPiece group) {
// All templates must be valid for the group to be considered valid.
std::vector<base::StringPiece> templates = SplitGroup(group);
return std::all_of(templates.begin(), templates.end(), [](auto t) {
std::string method;
return net::dns_util::IsValidDohTemplate(t, &method);
});
}
void UpdateDropdownHistograms(
const std::vector<const net::DohProviderEntry*>& providers,
base::StringPiece old_template,
base::StringPiece new_template) {
for (const auto* entry : providers) {
IncrementDropdownHistogram(entry->provider_id_for_histogram.value(),
entry->dns_over_https_template, old_template,
new_template);
}
// An empty template indicates a custom provider.
IncrementDropdownHistogram(net::DohProviderIdForHistogram::kCustom,
std::string(), old_template, new_template);
}
void UpdateValidationHistogram(bool valid) {
UMA_HISTOGRAM_BOOLEAN("Net.DNS.UI.ValidationAttemptSuccess", valid);
}
void UpdateProbeHistogram(bool success) {
UMA_HISTOGRAM_BOOLEAN("Net.DNS.UI.ProbeAttemptSuccess", success);
}
void ApplyTemplate(net::DnsConfigOverrides* overrides,
base::StringPiece server_template) {
std::string server_method;
// We only allow use of templates that have already passed a format
// validation check.
CHECK(net::dns_util::IsValidDohTemplate(server_template, &server_method));
overrides->dns_over_https_servers.emplace({net::DnsOverHttpsServerConfig(
std::string(server_template), server_method == "POST")});
}
} // namespace secure_dns
} // namespace chrome_browser_net