blob: 2d828ee1ee64a4ce307bd64891bd88c8bb6e7215 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ssl/generated_https_first_mode_pref.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "chrome/browser/extensions/api/settings_private/prefs_util_enums.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
#include "chrome/browser/ssl/https_first_mode_settings_tracker.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/extensions/api/settings_private.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
namespace settings_api = extensions::api::settings_private;
const char kGeneratedHttpsFirstModePref[] =
"generated.https_first_mode_enabled";
GeneratedHttpsFirstModePref::GeneratedHttpsFirstModePref(Profile* profile)
: profile_(profile) {
user_prefs_registrar_.Init(profile->GetPrefs());
user_prefs_registrar_.Add(
prefs::kHttpsOnlyModeEnabled,
base::BindRepeating(
&GeneratedHttpsFirstModePref::OnSourcePreferencesChanged,
base::Unretained(this)));
user_prefs_registrar_.Add(
prefs::kHttpsFirstModeIncognito,
base::BindRepeating(
&GeneratedHttpsFirstModePref::OnSourcePreferencesChanged,
base::Unretained(this)));
// Track Advanced Protection status.
if (base::FeatureList::IsEnabled(
features::kHttpsFirstModeForAdvancedProtectionUsers)) {
obs_.Observe(
safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile(
profile_));
// On startup, AdvancedProtectionStatusManager runs before this class so we
// don't get called back. Run the callback to get the AP setting.
OnAdvancedProtectionStatusChanged(
safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile(
profile_)
->IsUnderAdvancedProtection());
}
}
GeneratedHttpsFirstModePref::~GeneratedHttpsFirstModePref() = default;
void GeneratedHttpsFirstModePref::OnSourcePreferencesChanged() {
NotifyObservers(kGeneratedHttpsFirstModePref);
}
void GeneratedHttpsFirstModePref::OnAdvancedProtectionStatusChanged(
bool enabled) {
DCHECK(base::FeatureList::IsEnabled(
features::kHttpsFirstModeForAdvancedProtectionUsers));
NotifyObservers(kGeneratedHttpsFirstModePref);
}
// Convert the setting selection into values for the two underlying boolean
// prefs.
extensions::settings_private::SetPrefResult
GeneratedHttpsFirstModePref::SetPref(const base::Value* value) {
if (!value->is_int()) {
return extensions::settings_private::SetPrefResult::PREF_TYPE_MISMATCH;
}
auto selection = static_cast<HttpsFirstModeSetting>(value->GetInt());
if (selection != HttpsFirstModeSetting::kDisabled &&
selection != HttpsFirstModeSetting::kEnabledIncognito &&
selection != HttpsFirstModeSetting::kEnabledFull) {
return extensions::settings_private::SetPrefResult::PREF_TYPE_MISMATCH;
}
if (!base::FeatureList::IsEnabled(features::kHttpsFirstModeIncognito) &&
selection == HttpsFirstModeSetting::kEnabledIncognito) {
return extensions::settings_private::SetPrefResult::PREF_TYPE_UNSUPPORTED;
}
// kHttpsOnlyModeEnabled is considered the canonical source for HFM
// management. Policy enforcement turns it fully on or fully off.
const PrefService::Preference* enabled_pref =
profile_->GetPrefs()->FindPreference(prefs::kHttpsOnlyModeEnabled);
if (!enabled_pref->IsUserModifiable()) {
return extensions::settings_private::SetPrefResult::PREF_NOT_MODIFIABLE;
}
// Update both HTTPS-First Mode preferences to match the selection.
//
// Note that the HttpsFirstModeSetting::kEnabledIncognito is not available by
// default. If the feature flag is disabled, then the kEnabledFull and
// kDisabled settings will only be mapped to the kHttpsOnlyModeEnabled pref.
if (base::FeatureList::IsEnabled(features::kHttpsFirstModeIncognito)) {
profile_->GetPrefs()->SetBoolean(
prefs::kHttpsFirstModeIncognito,
selection != HttpsFirstModeSetting::kDisabled);
}
profile_->GetPrefs()->SetBoolean(
prefs::kHttpsOnlyModeEnabled,
selection == HttpsFirstModeSetting::kEnabledFull);
return extensions::settings_private::SetPrefResult::SUCCESS;
}
// Convert the underlying boolean prefs into the setting selection.
settings_api::PrefObject GeneratedHttpsFirstModePref::GetPrefObject() const {
bool is_advanced_protection_enabled =
safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile(
profile_)
->IsUnderAdvancedProtection();
// prefs::kHttpsOnlyModeEnabled is the backing pref that can be controlled by
// enterprise policy.
auto* hfm_fully_enabled_pref =
profile_->GetPrefs()->FindPreference(prefs::kHttpsOnlyModeEnabled);
// The HttpsFirstModeSetting::kEnabledIncognito setting is not available by
// default -- if the feature flag is disabled, then the kEnabledFull and
// kDisabled settings will be mapped to the kHttpsOnlyModeEnabled pref on its
// own.
bool hfm_incognito_enabled =
base::FeatureList::IsEnabled(features::kHttpsFirstModeIncognito) &&
profile_->GetPrefs()->GetBoolean(prefs::kHttpsFirstModeIncognito);
bool fully_enabled = hfm_fully_enabled_pref->GetValue()->GetBool() ||
is_advanced_protection_enabled;
settings_api::PrefObject pref_object;
pref_object.key = kGeneratedHttpsFirstModePref;
pref_object.type = settings_api::PrefType::kNumber;
// Map the two boolean prefs to the enum setting states.
if (fully_enabled) {
pref_object.value =
base::Value(static_cast<int>(HttpsFirstModeSetting::kEnabledFull));
} else if (hfm_incognito_enabled) {
pref_object.value =
base::Value(static_cast<int>(HttpsFirstModeSetting::kEnabledIncognito));
} else {
pref_object.value =
base::Value(static_cast<int>(HttpsFirstModeSetting::kDisabled));
}
pref_object.user_control_disabled = is_advanced_protection_enabled;
if (!hfm_fully_enabled_pref->IsUserModifiable()) {
// The pref was controlled by the enterprise policy.
pref_object.enforcement = settings_api::Enforcement::kEnforced;
extensions::settings_private::GeneratedPref::ApplyControlledByFromPref(
&pref_object, hfm_fully_enabled_pref);
} else if (hfm_fully_enabled_pref->GetRecommendedValue()) {
// Policy can set a recommended setting of fully enabled or fully disabled.
// Map those to the enum values.
pref_object.enforcement = settings_api::Enforcement::kRecommended;
if (hfm_fully_enabled_pref->GetRecommendedValue()->GetBool()) {
pref_object.recommended_value =
base::Value(static_cast<int>(HttpsFirstModeSetting::kEnabledFull));
} else {
// TODO(crbug.com/1494186): Consider supporting a recommended value of
// kEnabledIncognito after the enterprise policy support is updated.
pref_object.recommended_value =
base::Value(static_cast<int>(HttpsFirstModeSetting::kDisabled));
}
}
return pref_object;
}