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 "chrome/browser/extensions/api/settings_private/prefs_util.h"
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/extensions/chrome_extension_function.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/common/pref_names.h"
12 #include "components/proxy_config/proxy_config_pref_names.h"
13 #include "components/url_formatter/url_fixer.h"
14 #include "extensions/browser/extension_pref_value_map.h"
15 #include "extensions/browser/extension_pref_value_map_factory.h"
16 #include "extensions/browser/extension_registry.h"
18 #if defined(OS_CHROMEOS)
19 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
20 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
21 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
22 #include "chrome/browser/chromeos/profiles/profile_helper.h"
23 #include "chrome/browser/chromeos/settings/cros_settings.h"
24 #include "chromeos/settings/cros_settings_names.h"
29 #if defined(OS_CHROMEOS)
30 bool IsPrivilegedCrosSetting(const std::string
& pref_name
) {
31 if (!chromeos::CrosSettings::IsCrosSettings(pref_name
))
33 // kSystemTimezone should be changeable by all users.
34 if (pref_name
== chromeos::kSystemTimezone
)
36 // All other Cros settings are considered privileged and are either policy
37 // controlled or owner controlled.
44 namespace extensions
{
46 namespace settings_private
= api::settings_private
;
48 PrefsUtil::PrefsUtil(Profile
* profile
) : profile_(profile
) {}
50 PrefsUtil::~PrefsUtil() {}
52 #if defined(OS_CHROMEOS)
53 using CrosSettings
= chromeos::CrosSettings
;
56 const PrefsUtil::TypedPrefMap
& PrefsUtil::GetWhitelistedKeys() {
57 static PrefsUtil::TypedPrefMap
* s_whitelist
= nullptr;
60 s_whitelist
= new PrefsUtil::TypedPrefMap();
61 (*s_whitelist
)["alternate_error_pages.enabled"] =
62 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
63 (*s_whitelist
)["bookmark_bar.show_on_all_tabs"] =
64 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
65 (*s_whitelist
)["browser.show_home_button"] =
66 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
67 (*s_whitelist
)["download.default_directory"] =
68 settings_private::PrefType::PREF_TYPE_STRING
;
69 (*s_whitelist
)["download.prompt_for_download"] =
70 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
71 (*s_whitelist
)["enable_do_not_track"] =
72 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
73 (*s_whitelist
)["homepage"] = settings_private::PrefType::PREF_TYPE_URL
;
74 (*s_whitelist
)["homepage_is_newtabpage"] =
75 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
76 (*s_whitelist
)["net.network_prediction_options"] =
77 settings_private::PrefType::PREF_TYPE_NUMBER
;
78 (*s_whitelist
)["safebrowsing.enabled"] =
79 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
80 (*s_whitelist
)["safebrowsing.extended_reporting_enabled"] =
81 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
82 (*s_whitelist
)["search.suggest_enabled"] =
83 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
84 (*s_whitelist
)["spellcheck.use_spelling_service"] =
85 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
86 (*s_whitelist
)["session.restore_on_startup"] =
87 settings_private::PrefType::PREF_TYPE_NUMBER
;
88 (*s_whitelist
)["session.startup_urls"] =
89 settings_private::PrefType::PREF_TYPE_LIST
;
90 (*s_whitelist
)["browser.clear_data.browsing_history"] =
91 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
92 (*s_whitelist
)["browser.clear_data.download_history"] =
93 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
94 (*s_whitelist
)["browser.clear_data.cache"] =
95 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
96 (*s_whitelist
)["browser.clear_data.cookies"] =
97 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
98 (*s_whitelist
)["browser.clear_data.passwords"] =
99 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
100 (*s_whitelist
)["browser.clear_data.form_data"] =
101 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
102 (*s_whitelist
)["browser.clear_data.hosted_apps_data"] =
103 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
104 (*s_whitelist
)["browser.clear_data.content_licenses"] =
105 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
106 (*s_whitelist
)["browser.clear_data.time_period"] =
107 settings_private::PrefType::PREF_TYPE_NUMBER
;
109 #if defined(OS_CHROMEOS)
110 (*s_whitelist
)["cros.accounts.allowBWSI"] =
111 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
112 (*s_whitelist
)["cros.accounts.supervisedUsersEnabled"] =
113 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
114 (*s_whitelist
)["cros.accounts.showUserNamesOnSignIn"] =
115 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
116 (*s_whitelist
)["cros.accounts.allowGuest"] =
117 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
118 (*s_whitelist
)["cros.accounts.users"] =
119 settings_private::PrefType::PREF_TYPE_LIST
;
120 (*s_whitelist
)["settings.accessibility"] =
121 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
122 (*s_whitelist
)["settings.a11y.autoclick"] =
123 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
124 (*s_whitelist
)["settings.a11y.autoclick_delay_ms"] =
125 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
126 (*s_whitelist
)["settings.a11y.enable_menu"] =
127 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
128 (*s_whitelist
)["settings.a11y.high_contrast_enabled"] =
129 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
130 (*s_whitelist
)["settings.a11y.large_cursor_enabled"] =
131 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
132 (*s_whitelist
)["settings.a11y.screen_magnifier"] =
133 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
134 (*s_whitelist
)["settings.a11y.sticky_keys_enabled"] =
135 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
136 (*s_whitelist
)["settings.a11y.virtual_keyboard"] =
137 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
138 (*s_whitelist
)["settings.clock.use_24hour_clock"] =
139 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
140 (*s_whitelist
)["settings.touchpad.enable_tap_dragging"] =
141 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
142 (*s_whitelist
)["cros.metrics.reportingEnabled"] =
143 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
144 (*s_whitelist
)["cros.device.attestation_for_content_protection_enabled"] =
145 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
146 (*s_whitelist
)["settings.internet.wake_on_wifi_ssid"] =
147 settings_private::PrefType::PREF_TYPE_BOOLEAN
;
153 settings_private::PrefType
PrefsUtil::GetType(const std::string
& name
,
154 base::Value::Type type
) {
156 case base::Value::Type::TYPE_BOOLEAN
:
157 return settings_private::PrefType::PREF_TYPE_BOOLEAN
;
158 case base::Value::Type::TYPE_INTEGER
:
159 case base::Value::Type::TYPE_DOUBLE
:
160 return settings_private::PrefType::PREF_TYPE_NUMBER
;
161 case base::Value::Type::TYPE_STRING
:
162 return IsPrefTypeURL(name
) ? settings_private::PrefType::PREF_TYPE_URL
163 : settings_private::PrefType::PREF_TYPE_STRING
;
164 case base::Value::Type::TYPE_LIST
:
165 return settings_private::PrefType::PREF_TYPE_LIST
;
167 return settings_private::PrefType::PREF_TYPE_NONE
;
171 scoped_ptr
<settings_private::PrefObject
> PrefsUtil::GetCrosSettingsPref(
172 const std::string
& name
) {
173 scoped_ptr
<settings_private::PrefObject
> pref_object(
174 new settings_private::PrefObject());
176 #if defined(OS_CHROMEOS)
177 const base::Value
* value
= CrosSettings::Get()->GetPref(name
);
179 pref_object
->key
= name
;
180 pref_object
->type
= GetType(name
, value
->GetType());
181 pref_object
->value
.reset(value
->DeepCopy());
184 return pref_object
.Pass();
187 scoped_ptr
<settings_private::PrefObject
> PrefsUtil::GetPref(
188 const std::string
& name
) {
189 const PrefService::Preference
* pref
= nullptr;
190 scoped_ptr
<settings_private::PrefObject
> pref_object
;
191 if (IsCrosSetting(name
)) {
192 pref_object
= GetCrosSettingsPref(name
);
194 PrefService
* pref_service
= FindServiceForPref(name
);
195 pref
= pref_service
->FindPreference(name
);
198 pref_object
.reset(new settings_private::PrefObject());
199 pref_object
->key
= pref
->name();
200 pref_object
->type
= GetType(name
, pref
->GetType());
201 pref_object
->value
.reset(pref
->GetValue()->DeepCopy());
204 #if defined(OS_CHROMEOS)
205 if (IsPrefPrimaryUserControlled(name
)) {
206 pref_object
->policy_source
=
207 settings_private::PolicySource::POLICY_SOURCE_PRIMARY_USER
;
208 pref_object
->policy_enforcement
=
209 settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED
;
210 return pref_object
.Pass();
212 if (IsPrefEnterpriseManaged(name
)) {
213 // Enterprise managed prefs are treated the same as device policy restricted
215 pref_object
->policy_source
=
216 settings_private::PolicySource::POLICY_SOURCE_DEVICE_POLICY
;
217 pref_object
->policy_enforcement
=
218 settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED
;
219 return pref_object
.Pass();
223 if (pref
&& pref
->IsManaged()) {
224 pref_object
->policy_source
=
225 settings_private::PolicySource::POLICY_SOURCE_USER_POLICY
;
226 pref_object
->policy_enforcement
=
227 settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED
;
228 return pref_object
.Pass();
230 if (pref
&& pref
->IsRecommended()) {
231 pref_object
->policy_source
=
232 settings_private::PolicySource::POLICY_SOURCE_USER_POLICY
;
233 pref_object
->policy_enforcement
=
234 settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_RECOMMENDED
;
235 pref_object
->recommended_value
.reset(
236 pref
->GetRecommendedValue()->DeepCopy());
237 return pref_object
.Pass();
240 #if defined(OS_CHROMEOS)
241 if (IsPrefOwnerControlled(name
)) {
242 // Check for owner controlled after managed checks because if there is a
243 // device policy there is no "owner". (In the unlikely case that both
244 // situations apply, either badge is potentially relevant, so the order
245 // is somewhat arbitrary).
246 pref_object
->policy_source
=
247 settings_private::PolicySource::POLICY_SOURCE_OWNER
;
248 pref_object
->policy_enforcement
=
249 settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED
;
250 return pref_object
.Pass();
254 if (pref
&& pref
->IsExtensionControlled()) {
255 pref_object
->policy_source
=
256 settings_private::PolicySource::POLICY_SOURCE_EXTENSION
;
257 pref_object
->policy_enforcement
=
258 settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED
;
259 std::string extension_id
=
260 ExtensionPrefValueMapFactory::GetForBrowserContext(profile_
)
261 ->GetExtensionControllingPref(pref
->name());
262 pref_object
->extension_id
.reset(new std::string(extension_id
));
263 return pref_object
.Pass();
265 if (pref
&& (!pref
->IsUserModifiable() || IsPrefSupervisorControlled(name
))) {
266 // TODO(stevenjb): Investigate whether either of these should be badged.
267 pref_object
->read_only
.reset(new bool(true));
268 return pref_object
.Pass();
271 return pref_object
.Pass();
274 PrefsUtil::SetPrefResult
PrefsUtil::SetPref(const std::string
& pref_name
,
275 const base::Value
* value
) {
276 if (IsCrosSetting(pref_name
))
277 return SetCrosSettingsPref(pref_name
, value
);
279 PrefService
* pref_service
= FindServiceForPref(pref_name
);
281 if (!IsPrefUserModifiable(pref_name
))
282 return PREF_NOT_MODIFIABLE
;
284 const PrefService::Preference
* pref
= pref_service
->FindPreference(pref_name
);
286 return PREF_NOT_FOUND
;
288 DCHECK_EQ(pref
->GetType(), value
->GetType());
290 switch (pref
->GetType()) {
291 case base::Value::TYPE_BOOLEAN
:
292 case base::Value::TYPE_DOUBLE
:
293 case base::Value::TYPE_LIST
:
294 pref_service
->Set(pref_name
, *value
);
296 case base::Value::TYPE_INTEGER
: {
297 // In JS all numbers are doubles.
299 if (!value
->GetAsDouble(&double_value
))
300 return PREF_TYPE_MISMATCH
;
302 pref_service
->SetInteger(pref_name
, static_cast<int>(double_value
));
305 case base::Value::TYPE_STRING
: {
306 std::string string_value
;
307 if (!value
->GetAsString(&string_value
))
308 return PREF_TYPE_MISMATCH
;
310 if (IsPrefTypeURL(pref_name
)) {
311 GURL fixed
= url_formatter::FixupURL(string_value
, std::string());
312 string_value
= fixed
.spec();
315 pref_service
->SetString(pref_name
, string_value
);
319 return PREF_TYPE_UNSUPPORTED
;
322 // TODO(orenb): Process setting metrics here and in the CrOS setting method
323 // too (like "ProcessUserMetric" in CoreOptionsHandler).
327 PrefsUtil::SetPrefResult
PrefsUtil::SetCrosSettingsPref(
328 const std::string
& pref_name
, const base::Value
* value
) {
329 #if defined(OS_CHROMEOS)
330 chromeos::OwnerSettingsServiceChromeOS
* service
=
331 chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
334 // Check if setting requires owner.
335 if (service
&& service
->HandlesSetting(pref_name
)) {
336 if (service
->Set(pref_name
, *value
))
338 return PREF_NOT_MODIFIABLE
;
341 CrosSettings::Get()->Set(pref_name
, *value
);
344 return PREF_NOT_FOUND
;
348 bool PrefsUtil::AppendToListCrosSetting(const std::string
& pref_name
,
349 const base::Value
& value
) {
350 #if defined(OS_CHROMEOS)
351 chromeos::OwnerSettingsServiceChromeOS
* service
=
352 chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
355 // Returns false if not the owner, for settings requiring owner.
356 if (service
&& service
->HandlesSetting(pref_name
)) {
357 return service
->AppendToList(pref_name
, value
);
360 CrosSettings::Get()->AppendToList(pref_name
, &value
);
367 bool PrefsUtil::RemoveFromListCrosSetting(const std::string
& pref_name
,
368 const base::Value
& value
) {
369 #if defined(OS_CHROMEOS)
370 chromeos::OwnerSettingsServiceChromeOS
* service
=
371 chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
374 // Returns false if not the owner, for settings requiring owner.
375 if (service
&& service
->HandlesSetting(pref_name
)) {
376 return service
->RemoveFromList(pref_name
, value
);
379 CrosSettings::Get()->RemoveFromList(pref_name
, &value
);
386 bool PrefsUtil::IsPrefTypeURL(const std::string
& pref_name
) {
387 settings_private::PrefType pref_type
=
388 settings_private::PrefType::PREF_TYPE_NONE
;
390 const TypedPrefMap keys
= GetWhitelistedKeys();
391 const auto& iter
= keys
.find(pref_name
);
392 if (iter
!= keys
.end())
393 pref_type
= iter
->second
;
395 return pref_type
== settings_private::PrefType::PREF_TYPE_URL
;
398 #if defined(OS_CHROMEOS)
399 bool PrefsUtil::IsPrefEnterpriseManaged(const std::string
& pref_name
) {
400 if (IsPrivilegedCrosSetting(pref_name
)) {
401 policy::BrowserPolicyConnectorChromeOS
* connector
=
402 g_browser_process
->platform_part()->browser_policy_connector_chromeos();
403 if (connector
->IsEnterpriseManaged())
409 bool PrefsUtil::IsPrefOwnerControlled(const std::string
& pref_name
) {
410 if (IsPrivilegedCrosSetting(pref_name
)) {
411 if (!chromeos::ProfileHelper::IsOwnerProfile(profile_
))
417 bool PrefsUtil::IsPrefPrimaryUserControlled(const std::string
& pref_name
) {
418 if (pref_name
== prefs::kWakeOnWifiSsid
) {
419 user_manager::UserManager
* user_manager
= user_manager::UserManager::Get();
420 const user_manager::User
* user
=
421 chromeos::ProfileHelper::Get()->GetUserByProfile(profile_
);
422 if (user
&& user
->email() != user_manager
->GetPrimaryUser()->email())
429 bool PrefsUtil::IsPrefSupervisorControlled(const std::string
& pref_name
) {
430 if (pref_name
!= prefs::kBrowserGuestModeEnabled
&&
431 pref_name
!= prefs::kBrowserAddPersonEnabled
) {
434 return profile_
->IsSupervised();
437 bool PrefsUtil::IsPrefUserModifiable(const std::string
& pref_name
) {
438 PrefService
* pref_service
= profile_
->GetPrefs();
439 const PrefService::Preference
* pref
=
440 pref_service
->FindPreference(pref_name
.c_str());
441 return pref
&& pref
->IsUserModifiable();
444 PrefService
* PrefsUtil::FindServiceForPref(const std::string
& pref_name
) {
445 PrefService
* user_prefs
= profile_
->GetPrefs();
447 // Proxy is a peculiar case: on ChromeOS, settings exist in both user
448 // prefs and local state, but chrome://settings should affect only user prefs.
449 // Elsewhere the proxy settings are stored in local state.
450 // See http://crbug.com/157147
452 if (pref_name
== proxy_config::prefs::kProxy
) {
453 #if defined(OS_CHROMEOS)
456 return g_browser_process
->local_state();
460 // Find which PrefService contains the given pref. Pref names should not
461 // be duplicated across services, however if they are, prefer the user's
463 if (user_prefs
->FindPreference(pref_name
))
466 if (g_browser_process
->local_state()->FindPreference(pref_name
))
467 return g_browser_process
->local_state();
472 bool PrefsUtil::IsCrosSetting(const std::string
& pref_name
) {
473 #if defined(OS_CHROMEOS)
474 return CrosSettings::Get()->IsCrosSettings(pref_name
);
480 } // namespace extensions