1 // Copyright 2015 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.
5 #include "base/prefs/pref_service.h"
6 #include "chrome/browser/browser_process.h"
7 #include "chrome/browser/extensions/api/settings_private/prefs_util.h"
8 #include "chrome/browser/extensions/chrome_extension_function.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/common/pref_names.h"
11 #include "components/proxy_config/proxy_config_pref_names.h"
12 #include "components/url_formatter/url_fixer.h"
14 #if defined(OS_CHROMEOS)
15 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
16 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
17 #include "chrome/browser/chromeos/settings/cros_settings.h"
20 namespace extensions
{
22 namespace settings_private
= api::settings_private
;
24 PrefsUtil::PrefsUtil(Profile
* profile
) : profile_(profile
) {
27 PrefsUtil::~PrefsUtil() {
30 #if defined(OS_CHROMEOS)
31 using CrosSettings
= chromeos::CrosSettings
;
34 const PrefsUtil::TypedPrefMap
& PrefsUtil::GetWhitelistedKeys() {
35 static PrefsUtil::TypedPrefMap
* s_whitelist
= nullptr;
38 s_whitelist
= new PrefsUtil::TypedPrefMap();
39 (*s_whitelist
)["alternate_error_pages.enabled"] =
40 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
41 (*s_whitelist
)["bookmark_bar.show_on_all_tabs"] =
42 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
43 (*s_whitelist
)["browser.show_home_button"] =
44 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
45 (*s_whitelist
)["download.default_directory"] =
46 settings_private::PrefType::PREF_TYPE_STRING
;
47 (*s_whitelist
)["download.prompt_for_download"] =
48 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
49 (*s_whitelist
)["enable_do_not_track"] =
50 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
51 (*s_whitelist
)["homepage"] = settings_private::PrefType::PREF_TYPE_URL
;
52 (*s_whitelist
)["net.network_prediction_options"] =
53 settings_private::PrefType::PREF_TYPE_NUMBER
;
54 (*s_whitelist
)["safebrowsing.enabled"] =
55 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
56 (*s_whitelist
)["safebrowsing.extended_reporting_enabled"] =
57 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
58 (*s_whitelist
)["search.suggest_enabled"] =
59 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
60 (*s_whitelist
)["spellcheck.use_spelling_service"] =
61 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
62 (*s_whitelist
)["session.restore_on_startup"] =
63 settings_private::PrefType::PREF_TYPE_NUMBER
;
64 (*s_whitelist
)["session.startup_urls"] =
65 settings_private::PrefType::PREF_TYPE_LIST
;
67 #if defined(OS_CHROMEOS)
68 (*s_whitelist
)["cros.accounts.allowBWSI"] =
69 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
70 (*s_whitelist
)["cros.accounts.supervisedUsersEnabled"] =
71 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
72 (*s_whitelist
)["cros.accounts.showUserNamesOnSignIn"] =
73 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
74 (*s_whitelist
)["cros.accounts.allowGuest"] =
75 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
76 (*s_whitelist
)["cros.accounts.users"] =
77 settings_private::PrefType::PREF_TYPE_LIST
;
78 (*s_whitelist
)["settings.accessibility"] =
79 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
80 (*s_whitelist
)["settings.a11y.autoclick"] =
81 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
82 (*s_whitelist
)["settings.a11y.autoclick_delay_ms"] =
83 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
84 (*s_whitelist
)["settings.a11y.enable_menu"] =
85 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
86 (*s_whitelist
)["settings.a11y.high_contrast_enabled"] =
87 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
88 (*s_whitelist
)["settings.a11y.large_cursor_enabled"] =
89 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
90 (*s_whitelist
)["settings.a11y.screen_magnifier"] =
91 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
92 (*s_whitelist
)["settings.a11y.sticky_keys_enabled"] =
93 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
94 (*s_whitelist
)["settings.a11y.virtual_keyboard"] =
95 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
96 (*s_whitelist
)["settings.clock.use_24hour_clock"] =
97 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
98 (*s_whitelist
)["settings.touchpad.enable_tap_dragging"] =
99 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
100 (*s_whitelist
)["cros.metrics.reportingEnabled"] =
101 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
102 (*s_whitelist
)["cros.device.attestation_for_content_protection_enabled"] =
103 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
104 (*s_whitelist
)["settings.internet.wake_on_wifi_ssid"] =
105 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
111 api::settings_private::PrefType
PrefsUtil::GetType(const std::string
& name
,
112 base::Value::Type type
) {
114 case base::Value::Type::TYPE_BOOLEAN
:
115 return api::settings_private::PrefType::PREF_TYPE_BOOLEAN
;
116 case base::Value::Type::TYPE_INTEGER
:
117 case base::Value::Type::TYPE_DOUBLE
:
118 return api::settings_private::PrefType::PREF_TYPE_NUMBER
;
119 case base::Value::Type::TYPE_STRING
:
120 return IsPrefTypeURL(name
)
121 ? api::settings_private::PrefType::PREF_TYPE_URL
122 : api::settings_private::PrefType::PREF_TYPE_STRING
;
123 case base::Value::Type::TYPE_LIST
:
124 return api::settings_private::PrefType::PREF_TYPE_LIST
;
126 return api::settings_private::PrefType::PREF_TYPE_NONE
;
130 scoped_ptr
<api::settings_private::PrefObject
> PrefsUtil::GetCrosSettingsPref(
131 const std::string
& name
) {
132 scoped_ptr
<api::settings_private::PrefObject
> pref_object(
133 new api::settings_private::PrefObject());
135 #if defined(OS_CHROMEOS)
136 const base::Value
* value
= CrosSettings::Get()->GetPref(name
);
137 pref_object
->key
= name
;
138 pref_object
->type
= GetType(name
, value
->GetType());
139 pref_object
->value
.reset(value
->DeepCopy());
142 return pref_object
.Pass();
145 scoped_ptr
<api::settings_private::PrefObject
> PrefsUtil::GetPref(
146 const std::string
& name
) {
147 if (IsCrosSetting(name
))
148 return GetCrosSettingsPref(name
);
150 PrefService
* pref_service
= FindServiceForPref(name
);
151 const PrefService::Preference
* pref
= pref_service
->FindPreference(name
);
155 scoped_ptr
<api::settings_private::PrefObject
> pref_object(
156 new api::settings_private::PrefObject());
157 pref_object
->key
= pref
->name();
158 pref_object
->type
= GetType(name
, pref
->GetType());
159 pref_object
->value
.reset(pref
->GetValue()->DeepCopy());
161 if (pref
->IsManaged()) {
162 if (pref
->IsManagedByCustodian()) {
163 pref_object
->policy_source
=
164 api::settings_private::PolicySource::POLICY_SOURCE_DEVICE
;
166 pref_object
->policy_source
=
167 api::settings_private::PolicySource::POLICY_SOURCE_USER
;
169 pref_object
->policy_enforcement
=
170 pref
->IsRecommended() ? api::settings_private::PolicyEnforcement::
171 POLICY_ENFORCEMENT_RECOMMENDED
172 : api::settings_private::PolicyEnforcement::
173 POLICY_ENFORCEMENT_ENFORCED
;
174 } else if (!IsPrefUserModifiable(name
)) {
175 pref_object
->policy_source
=
176 api::settings_private::PolicySource::POLICY_SOURCE_USER
;
177 pref_object
->policy_enforcement
=
178 api::settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED
;
181 return pref_object
.Pass();
184 PrefsUtil::SetPrefResult
PrefsUtil::SetPref(const std::string
& pref_name
,
185 const base::Value
* value
) {
186 if (IsCrosSetting(pref_name
))
187 return SetCrosSettingsPref(pref_name
, value
);
189 PrefService
* pref_service
= FindServiceForPref(pref_name
);
191 if (!IsPrefUserModifiable(pref_name
))
192 return PREF_NOT_MODIFIABLE
;
194 const PrefService::Preference
* pref
=
195 pref_service
->FindPreference(pref_name
);
197 return PREF_NOT_FOUND
;
199 DCHECK_EQ(pref
->GetType(), value
->GetType());
201 switch (pref
->GetType()) {
202 case base::Value::TYPE_BOOLEAN
:
203 case base::Value::TYPE_DOUBLE
:
204 case base::Value::TYPE_LIST
:
205 pref_service
->Set(pref_name
, *value
);
207 case base::Value::TYPE_INTEGER
: {
208 // In JS all numbers are doubles.
210 if (!value
->GetAsDouble(&double_value
))
211 return PREF_TYPE_MISMATCH
;
213 pref_service
->SetInteger(pref_name
, static_cast<int>(double_value
));
216 case base::Value::TYPE_STRING
: {
217 std::string string_value
;
218 if (!value
->GetAsString(&string_value
))
219 return PREF_TYPE_MISMATCH
;
221 if (IsPrefTypeURL(pref_name
)) {
222 GURL fixed
= url_formatter::FixupURL(string_value
, std::string());
223 string_value
= fixed
.spec();
226 pref_service
->SetString(pref_name
, string_value
);
230 return PREF_TYPE_UNSUPPORTED
;
233 // TODO(orenb): Process setting metrics here and in the CrOS setting method
234 // too (like "ProcessUserMetric" in CoreOptionsHandler).
238 PrefsUtil::SetPrefResult
PrefsUtil::SetCrosSettingsPref(
239 const std::string
& pref_name
, const base::Value
* value
) {
240 #if defined(OS_CHROMEOS)
241 chromeos::OwnerSettingsServiceChromeOS
* service
=
242 chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
245 // Check if setting requires owner.
246 if (service
&& service
->HandlesSetting(pref_name
)) {
247 if (service
->Set(pref_name
, *value
))
249 return PREF_NOT_MODIFIABLE
;
252 chromeos::CrosSettings::Get()->Set(pref_name
, *value
);
255 return PREF_NOT_FOUND
;
259 bool PrefsUtil::AppendToListCrosSetting(const std::string
& pref_name
,
260 const base::Value
& value
) {
261 #if defined(OS_CHROMEOS)
262 chromeos::OwnerSettingsServiceChromeOS
* service
=
263 chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
266 // Returns false if not the owner, for settings requiring owner.
267 if (service
&& service
->HandlesSetting(pref_name
)) {
268 return service
->AppendToList(pref_name
, value
);
271 chromeos::CrosSettings::Get()->AppendToList(pref_name
, &value
);
278 bool PrefsUtil::RemoveFromListCrosSetting(const std::string
& pref_name
,
279 const base::Value
& value
) {
280 #if defined(OS_CHROMEOS)
281 chromeos::OwnerSettingsServiceChromeOS
* service
=
282 chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
285 // Returns false if not the owner, for settings requiring owner.
286 if (service
&& service
->HandlesSetting(pref_name
)) {
287 return service
->RemoveFromList(pref_name
, value
);
290 chromeos::CrosSettings::Get()->RemoveFromList(pref_name
, &value
);
297 bool PrefsUtil::IsPrefTypeURL(const std::string
& pref_name
) {
298 settings_private::PrefType pref_type
=
299 settings_private::PrefType::PREF_TYPE_NONE
;
301 const TypedPrefMap keys
= GetWhitelistedKeys();
302 const auto& iter
= keys
.find(pref_name
);
303 if (iter
!= keys
.end())
304 pref_type
= iter
->second
;
306 return pref_type
== settings_private::PrefType::PREF_TYPE_URL
;
309 bool PrefsUtil::IsPrefUserModifiable(const std::string
& pref_name
) {
310 if (pref_name
!= prefs::kBrowserGuestModeEnabled
&&
311 pref_name
!= prefs::kBrowserAddPersonEnabled
) {
315 PrefService
* pref_service
= profile_
->GetPrefs();
316 const PrefService::Preference
* pref
=
317 pref_service
->FindPreference(pref_name
.c_str());
318 if (!pref
|| !pref
->IsUserModifiable() || profile_
->IsSupervised())
324 PrefService
* PrefsUtil::FindServiceForPref(const std::string
& pref_name
) {
325 PrefService
* user_prefs
= profile_
->GetPrefs();
327 // Proxy is a peculiar case: on ChromeOS, settings exist in both user
328 // prefs and local state, but chrome://settings should affect only user prefs.
329 // Elsewhere the proxy settings are stored in local state.
330 // See http://crbug.com/157147
332 if (pref_name
== proxy_config::prefs::kProxy
) {
333 #if defined(OS_CHROMEOS)
336 return g_browser_process
->local_state();
340 // Find which PrefService contains the given pref. Pref names should not
341 // be duplicated across services, however if they are, prefer the user's
343 if (user_prefs
->FindPreference(pref_name
))
346 if (g_browser_process
->local_state()->FindPreference(pref_name
))
347 return g_browser_process
->local_state();
352 bool PrefsUtil::IsCrosSetting(const std::string
& pref_name
) {
353 #if defined(OS_CHROMEOS)
354 return CrosSettings::Get()->IsCrosSettings(pref_name
);
360 } // namespace extensions