Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / settings_private / prefs_util.cc
blobeb0faff9a63e26a54e7349f16fd561e9ee9e5a23
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"
25 #endif
27 namespace {
29 #if defined(OS_CHROMEOS)
30 bool IsPrivilegedCrosSetting(const std::string& pref_name) {
31 if (!chromeos::CrosSettings::IsCrosSettings(pref_name))
32 return false;
33 // kSystemTimezone should be changeable by all users.
34 if (pref_name == chromeos::kSystemTimezone)
35 return false;
36 // All other Cros settings are considered privileged and are either policy
37 // controlled or owner controlled.
38 return true;
40 #endif
42 } // namespace
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;
54 #endif
56 const PrefsUtil::TypedPrefMap& PrefsUtil::GetWhitelistedKeys() {
57 static PrefsUtil::TypedPrefMap* s_whitelist = nullptr;
58 if (s_whitelist)
59 return *s_whitelist;
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;
148 #endif
150 return *s_whitelist;
153 settings_private::PrefType PrefsUtil::GetType(const std::string& name,
154 base::Value::Type type) {
155 switch (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;
166 default:
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);
178 DCHECK(value);
179 pref_object->key = name;
180 pref_object->type = GetType(name, value->GetType());
181 pref_object->value.reset(value->DeepCopy());
182 #endif
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);
193 } else {
194 PrefService* pref_service = FindServiceForPref(name);
195 pref = pref_service->FindPreference(name);
196 if (!pref)
197 return nullptr;
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
214 // prefs in the UI.
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();
221 #endif
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();
252 #endif
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);
285 if (!pref)
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);
295 break;
296 case base::Value::TYPE_INTEGER: {
297 // In JS all numbers are doubles.
298 double double_value;
299 if (!value->GetAsDouble(&double_value))
300 return PREF_TYPE_MISMATCH;
302 pref_service->SetInteger(pref_name, static_cast<int>(double_value));
303 break;
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);
316 break;
318 default:
319 return PREF_TYPE_UNSUPPORTED;
322 // TODO(orenb): Process setting metrics here and in the CrOS setting method
323 // too (like "ProcessUserMetric" in CoreOptionsHandler).
324 return SUCCESS;
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(
332 profile_);
334 // Check if setting requires owner.
335 if (service && service->HandlesSetting(pref_name)) {
336 if (service->Set(pref_name, *value))
337 return SUCCESS;
338 return PREF_NOT_MODIFIABLE;
341 CrosSettings::Get()->Set(pref_name, *value);
342 return SUCCESS;
343 #else
344 return PREF_NOT_FOUND;
345 #endif
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(
353 profile_);
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);
361 return true;
362 #else
363 return false;
364 #endif
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(
372 profile_);
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);
380 return true;
381 #else
382 return false;
383 #endif
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())
404 return true;
406 return false;
409 bool PrefsUtil::IsPrefOwnerControlled(const std::string& pref_name) {
410 if (IsPrivilegedCrosSetting(pref_name)) {
411 if (!chromeos::ProfileHelper::IsOwnerProfile(profile_))
412 return true;
414 return false;
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())
423 return true;
425 return false;
427 #endif
429 bool PrefsUtil::IsPrefSupervisorControlled(const std::string& pref_name) {
430 if (pref_name != prefs::kBrowserGuestModeEnabled &&
431 pref_name != prefs::kBrowserAddPersonEnabled) {
432 return false;
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)
454 return user_prefs;
455 #else
456 return g_browser_process->local_state();
457 #endif
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
462 // prefs.
463 if (user_prefs->FindPreference(pref_name))
464 return user_prefs;
466 if (g_browser_process->local_state()->FindPreference(pref_name))
467 return g_browser_process->local_state();
469 return user_prefs;
472 bool PrefsUtil::IsCrosSetting(const std::string& pref_name) {
473 #if defined(OS_CHROMEOS)
474 return CrosSettings::Get()->IsCrosSettings(pref_name);
475 #else
476 return false;
477 #endif
480 } // namespace extensions