#include "chrome/browser/extensions/api/preference/preference_api.h"
#include <stddef.h>
#include <map>
#include <memory>
#include <optional>
#include <utility>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/lazy_instance.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/pref_mapping.h"
#include "chrome/browser/extensions/pref_transformer_interface.h"
#include "chrome/browser/extensions/preference/preference_helpers.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/tracking_protection_prefs.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "extensions/browser/api/content_settings/content_settings_service.h"
#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extension_pref_value_map.h"
#include "extensions/browser/extension_pref_value_map_factory.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extension_prefs_helper.h"
#include "extensions/browser/extension_system_provider.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/pref_names.h"
#include "extensions/common/api/types.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "media/media_buildflags.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom.h"
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/chromeos/extensions/controlled_pref_mapping.h"
#include "chromeos/startup/browser_params_proxy.h"
#endif
APIPermissionID;
namespace extensions {
namespace {
ChromeSettingScope;
constexpr char kConversionErrorMessage[] = …;
constexpr char kPermissionErrorMessage[] = …;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
constexpr char kInvalidPrefPathErrorMessage[] =
"Invalid PrefPath '*' for getting extension pref with control.";
constexpr char kPrimaryProfileOnlyErrorMessage[] =
"You may only access the preference '*' in the primary profile.";
constexpr char kAshDoesNotSupportPreference[] =
"The browser preference is not supported.";
#endif
constexpr char kIncognitoKey[] = …;
constexpr char kScopeKey[] = …;
constexpr char kIncognitoSpecific[] = …;
constexpr char kLevelOfControl[] = …;
constexpr char kValue[] = …;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
bool IsBrowserScopePrefOperation(crosapi::mojom::PrefPath pref_path,
Profile* profile) {
if (pref_path == crosapi::mojom::PrefPath::kUnknown) {
return true;
}
if (pref_path == crosapi::mojom::PrefPath::kProxy) {
if (!profile->IsMainProfile()) {
return true;
}
static constexpr int kMinVersionProxyPref = 4;
const int version = chromeos::LacrosService::Get()
->GetInterfaceVersion<crosapi::mojom::Prefs>();
if (version < kMinVersionProxyPref) {
return true;
}
}
return false;
}
#endif
bool StringToScope(const std::string& s, ChromeSettingScope& scope) { … }
}
PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
: … { … }
PreferenceEventRouter::~PreferenceEventRouter() = default;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void PreferenceEventRouter::OnControlledPrefChanged(
PrefService* pref_service,
const std::string& browser_pref) {
auto* lacros_service = chromeos::LacrosService::Get();
if (!lacros_service ||
!lacros_service->IsAvailable<crosapi::mojom::Prefs>()) {
LOG(ERROR) << ErrorUtils::FormatErrorMessage(
"API unavailable to set pref * in ash.", browser_pref);
return;
}
crosapi::mojom::PrefPath pref_path =
PrefMapping::GetInstance()->GetPrefPathForPrefName(browser_pref);
DCHECK(pref_path != crosapi::mojom::PrefPath::kUnknown);
const PrefService::Preference* pref =
pref_service->FindPreference(browser_pref);
CHECK(pref);
if (pref->IsExtensionControlled()) {
lacros_service->GetRemote<crosapi::mojom::Prefs>()->SetPref(
pref_path, pref->GetValue()->Clone(), base::OnceClosure());
} else {
lacros_service->GetRemote<crosapi::mojom::Prefs>()
->ClearExtensionControlledPref(pref_path, base::OnceClosure());
}
}
void PreferenceEventRouter::OnAshPrefChanged(crosapi::mojom::PrefPath pref_path,
const std::string& extension_pref,
const std::string& browser_pref,
base::Value value) {
auto* lacros_service = chromeos::LacrosService::Get();
DCHECK(lacros_service);
lacros_service->GetRemote<crosapi::mojom::Prefs>()
->GetExtensionPrefWithControl(
pref_path, base::BindOnce(&PreferenceEventRouter::OnAshGetSuccess,
weak_factory_.GetWeakPtr(), browser_pref));
}
void PreferenceEventRouter::OnAshGetSuccess(
const std::string& browser_pref,
std::optional<::base::Value> opt_value,
crosapi::mojom::PrefControlState control_state) {
if (!opt_value.has_value()) {
LOG(ERROR) << ErrorUtils::FormatErrorMessage(kInvalidPrefPathErrorMessage,
browser_pref);
return;
}
bool incognito = false;
std::string event_name;
APIPermissionID permission = APIPermissionID::kInvalid;
bool found_event = PrefMapping::GetInstance()->FindEventForBrowserPref(
browser_pref, &event_name, &permission);
DCHECK(found_event);
base::Value::List args;
PrefTransformerInterface* transformer =
PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
std::optional<base::Value> transformed_value =
transformer->BrowserToExtensionPref(opt_value.value(), incognito);
if (!transformed_value) {
LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
browser_pref);
return;
}
base::Value::Dict dict;
dict.Set(kValue, std::move(*transformed_value));
args.Append(std::move(dict));
events::HistogramValue histogram_value =
events::TYPES_CHROME_SETTING_ON_CHANGE;
extensions::preference_helpers::DispatchEventToExtensionsWithAshControlState(
profile_, histogram_value, event_name, std::move(args), permission,
incognito, browser_pref, control_state);
}
#endif
void PreferenceEventRouter::OnPrefChanged(PrefService* pref_service,
const std::string& browser_pref) { … }
void PreferenceEventRouter::OnOffTheRecordProfileCreated(
Profile* off_the_record) { … }
void PreferenceEventRouter::OnProfileWillBeDestroyed(Profile* profile) { … }
void PreferenceEventRouter::ObserveOffTheRecordPrefs(PrefService* prefs) { … }
PreferenceAPI::PreferenceAPI(content::BrowserContext* context)
: … { … }
PreferenceAPI::~PreferenceAPI() = default;
void PreferenceAPI::Shutdown() { … }
static base::LazyInstance<BrowserContextKeyedAPIFactory<PreferenceAPI>>::
DestructorAtExit g_preference_api_factory = …;
BrowserContextKeyedAPIFactory<PreferenceAPI>*
PreferenceAPI::GetFactoryInstance() { … }
PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) { … }
void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) { … }
void PreferenceAPI::EnsurePreferenceEventRouterCreated() { … }
void PreferenceAPI::OnContentSettingChanged(const ExtensionId& extension_id,
bool incognito) { … }
void PreferenceAPI::ClearIncognitoSessionOnlyContentSettings() { … }
scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() { … }
template <>
void
BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() { … }
PreferenceFunction::~PreferenceFunction() = default;
GetPreferenceFunction::~GetPreferenceFunction() = default;
ExtensionFunction::ResponseAction GetPreferenceFunction::Run() { … }
void GetPreferenceFunction::ProduceGetResult(
base::Value::Dict* result,
const base::Value* pref_value,
const std::string& level_of_control,
const std::string& browser_pref,
bool incognito) { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void GetPreferenceFunction::OnLacrosGetSuccess(
std::optional<::base::Value> opt_value,
crosapi::mojom::PrefControlState control_state) {
if (!browser_context()) {
return;
}
if (!opt_value) {
Respond(Error(kAshDoesNotSupportPreference));
return;
}
Profile* profile = Profile::FromBrowserContext(browser_context());
std::string pref_key = args()[0].GetString();
const base::Value& details = args()[1];
bool incognito = false;
if (std::optional<bool> result = details.GetDict().FindBool(kIncognitoKey)) {
incognito = *result;
}
::base::Value* pref_value = &opt_value.value();
std::string level_of_control;
level_of_control =
extensions::preference_helpers::GetLevelOfControlWithAshControlState(
control_state, profile, extension_id(), cached_browser_pref_,
incognito);
base::Value::Dict result;
ProduceGetResult(&result, pref_value, level_of_control, cached_browser_pref_,
incognito);
Respond(WithArguments(std::move(result)));
}
#endif
SetPreferenceFunction::~SetPreferenceFunction() = default;
ExtensionFunction::ResponseAction SetPreferenceFunction::Run() { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void SetPreferenceFunction::OnLacrosSetSuccess() {
Respond(NoArguments());
}
#endif
ClearPreferenceFunction::~ClearPreferenceFunction() = default;
ExtensionFunction::ResponseAction ClearPreferenceFunction::Run() { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void ClearPreferenceFunction::OnLacrosClearSuccess() {
Respond(NoArguments());
}
#endif
}