Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / preference / preference_api.cc
blobac80eb49dc6e367e9c629ccf8f2cc342deb12a10
1 // Copyright (c) 2012 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/preference/preference_api.h"
7 #include <map>
8 #include <utility>
10 #include "base/lazy_instance.h"
11 #include "base/memory/singleton.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/stl_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/extensions/api/content_settings/content_settings_service.h"
18 #include "chrome/browser/extensions/api/preference/preference_api_constants.h"
19 #include "chrome/browser/extensions/api/preference/preference_helpers.h"
20 #include "chrome/browser/extensions/api/proxy/proxy_api.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/net/prediction_options.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/common/pref_names.h"
25 #include "components/content_settings/core/common/pref_names.h"
26 #include "components/translate/core/common/translate_pref_names.h"
27 #include "content/public/browser/notification_details.h"
28 #include "content/public/browser/notification_source.h"
29 #include "extensions/browser/extension_pref_value_map.h"
30 #include "extensions/browser/extension_pref_value_map_factory.h"
31 #include "extensions/browser/extension_prefs.h"
32 #include "extensions/browser/extension_prefs_factory.h"
33 #include "extensions/browser/extension_system_provider.h"
34 #include "extensions/browser/extensions_browser_client.h"
35 #include "extensions/browser/pref_names.h"
36 #include "extensions/common/error_utils.h"
37 #include "extensions/common/permissions/api_permission.h"
38 #include "extensions/common/permissions/permissions_data.h"
40 namespace keys = extensions::preference_api_constants;
41 namespace helpers = extensions::preference_helpers;
43 using base::DictionaryValue;
45 namespace extensions {
47 namespace {
49 struct PrefMappingEntry {
50 // Name of the preference referenced by the extension API JSON.
51 const char* extension_pref;
53 // Name of the preference in the PrefStores.
54 const char* browser_pref;
56 // Permission required to read and observe this preference.
57 // Use APIPermission::kInvalid for |read_permission| to express that the read
58 // permission should not be granted.
59 APIPermission::ID read_permission;
61 // Permission required to write this preference.
62 // Use APIPermission::kInvalid for |write_permission| to express that the
63 // write permission should not be granted.
64 APIPermission::ID write_permission;
67 const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange";
68 const char kConversionErrorMessage[] =
69 "Internal error: Stored value for preference '*' cannot be converted "
70 "properly.";
72 PrefMappingEntry kPrefMapping[] = {
73 {"spdy_proxy.enabled",
74 data_reduction_proxy::prefs::kDataReductionProxyEnabled,
75 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
76 {"data_reduction.daily_original_length",
77 data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
78 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
79 {"data_reduction.daily_received_length",
80 data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
81 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
82 {"alternateErrorPagesEnabled", prefs::kAlternateErrorPagesEnabled,
83 APIPermission::kPrivacy, APIPermission::kPrivacy},
84 {"autofillEnabled", autofill::prefs::kAutofillEnabled,
85 APIPermission::kPrivacy, APIPermission::kPrivacy},
86 {"hyperlinkAuditingEnabled", prefs::kEnableHyperlinkAuditing,
87 APIPermission::kPrivacy, APIPermission::kPrivacy},
88 {"hotwordSearchEnabled", prefs::kHotwordSearchEnabled,
89 APIPermission::kPrivacy, APIPermission::kPrivacy},
90 {"networkPredictionEnabled", prefs::kNetworkPredictionOptions,
91 APIPermission::kPrivacy, APIPermission::kPrivacy},
92 {"passwordSavingEnabled",
93 password_manager::prefs::kPasswordManagerSavingEnabled,
94 APIPermission::kPrivacy, APIPermission::kPrivacy},
95 {"protectedContentEnabled", prefs::kEnableDRM, APIPermission::kPrivacy,
96 APIPermission::kPrivacy},
97 {"proxy", prefs::kProxy, APIPermission::kProxy, APIPermission::kProxy},
98 {"referrersEnabled", prefs::kEnableReferrers, APIPermission::kPrivacy,
99 APIPermission::kPrivacy},
100 {"safeBrowsingEnabled", prefs::kSafeBrowsingEnabled,
101 APIPermission::kPrivacy, APIPermission::kPrivacy},
102 {"safeBrowsingExtendedReportingEnabled",
103 prefs::kSafeBrowsingExtendedReportingEnabled, APIPermission::kPrivacy,
104 APIPermission::kPrivacy},
105 {"searchSuggestEnabled", prefs::kSearchSuggestEnabled,
106 APIPermission::kPrivacy, APIPermission::kPrivacy},
107 {"spellingServiceEnabled", prefs::kSpellCheckUseSpellingService,
108 APIPermission::kPrivacy, APIPermission::kPrivacy},
109 {"thirdPartyCookiesAllowed", prefs::kBlockThirdPartyCookies,
110 APIPermission::kPrivacy, APIPermission::kPrivacy},
111 {"translationServiceEnabled", prefs::kEnableTranslate,
112 APIPermission::kPrivacy, APIPermission::kPrivacy},
113 #if defined(ENABLE_WEBRTC)
114 {"webRTCMultipleRoutesEnabled", prefs::kWebRTCMultipleRoutesEnabled,
115 APIPermission::kPrivacy, APIPermission::kPrivacy},
116 #endif
117 // accessibilityFeatures.animationPolicy is available for
118 // all platforms but the others from accessibilityFeatures
119 // is only available for OS_CHROMEOS.
120 {"animationPolicy", prefs::kAnimationPolicy,
121 APIPermission::kAccessibilityFeaturesRead,
122 APIPermission::kAccessibilityFeaturesModify},
123 #if defined(OS_CHROMEOS)
124 {"autoclick", prefs::kAccessibilityAutoclickEnabled,
125 APIPermission::kAccessibilityFeaturesRead,
126 APIPermission::kAccessibilityFeaturesModify},
127 {"highContrast", prefs::kAccessibilityHighContrastEnabled,
128 APIPermission::kAccessibilityFeaturesRead,
129 APIPermission::kAccessibilityFeaturesModify},
130 {"largeCursor", prefs::kAccessibilityLargeCursorEnabled,
131 APIPermission::kAccessibilityFeaturesRead,
132 APIPermission::kAccessibilityFeaturesModify},
133 {"screenMagnifier", prefs::kAccessibilityScreenMagnifierEnabled,
134 APIPermission::kAccessibilityFeaturesRead,
135 APIPermission::kAccessibilityFeaturesModify},
136 {"spokenFeedback", prefs::kAccessibilitySpokenFeedbackEnabled,
137 APIPermission::kAccessibilityFeaturesRead,
138 APIPermission::kAccessibilityFeaturesModify},
139 {"stickyKeys", prefs::kAccessibilityStickyKeysEnabled,
140 APIPermission::kAccessibilityFeaturesRead,
141 APIPermission::kAccessibilityFeaturesModify},
142 {"virtualKeyboard", prefs::kAccessibilityVirtualKeyboardEnabled,
143 APIPermission::kAccessibilityFeaturesRead,
144 APIPermission::kAccessibilityFeaturesModify},
145 #endif
148 class IdentityPrefTransformer : public PrefTransformerInterface {
149 public:
150 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
151 std::string* error,
152 bool* bad_message) override {
153 return extension_pref->DeepCopy();
156 base::Value* BrowserToExtensionPref(
157 const base::Value* browser_pref) override {
158 return browser_pref->DeepCopy();
162 class InvertBooleanTransformer : public PrefTransformerInterface {
163 public:
164 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
165 std::string* error,
166 bool* bad_message) override {
167 return InvertBooleanValue(extension_pref);
170 base::Value* BrowserToExtensionPref(
171 const base::Value* browser_pref) override {
172 return InvertBooleanValue(browser_pref);
175 private:
176 static base::Value* InvertBooleanValue(const base::Value* value) {
177 bool bool_value = false;
178 bool result = value->GetAsBoolean(&bool_value);
179 DCHECK(result);
180 return new base::FundamentalValue(!bool_value);
184 class NetworkPredictionTransformer : public PrefTransformerInterface {
185 public:
186 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
187 std::string* error,
188 bool* bad_message) override {
189 bool bool_value = false;
190 const bool pref_found = extension_pref->GetAsBoolean(&bool_value);
191 DCHECK(pref_found) << "Preference not found.";
192 if (bool_value) {
193 return new base::FundamentalValue(
194 chrome_browser_net::NETWORK_PREDICTION_DEFAULT);
195 } else {
196 return new base::FundamentalValue(
197 chrome_browser_net::NETWORK_PREDICTION_NEVER);
201 base::Value* BrowserToExtensionPref(
202 const base::Value* browser_pref) override {
203 int int_value = chrome_browser_net::NETWORK_PREDICTION_DEFAULT;
204 const bool pref_found = browser_pref->GetAsInteger(&int_value);
205 DCHECK(pref_found) << "Preference not found.";
206 return new base::FundamentalValue(
207 int_value != chrome_browser_net::NETWORK_PREDICTION_NEVER);
211 class PrefMapping {
212 public:
213 static PrefMapping* GetInstance() {
214 return Singleton<PrefMapping>::get();
217 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
218 std::string* browser_pref,
219 APIPermission::ID* read_permission,
220 APIPermission::ID* write_permission) {
221 PrefMap::iterator it = mapping_.find(extension_pref);
222 if (it != mapping_.end()) {
223 *browser_pref = it->second.pref_name;
224 *read_permission = it->second.read_permission;
225 *write_permission = it->second.write_permission;
226 return true;
228 return false;
231 bool FindEventForBrowserPref(const std::string& browser_pref,
232 std::string* event_name,
233 APIPermission::ID* permission) {
234 PrefMap::iterator it = event_mapping_.find(browser_pref);
235 if (it != event_mapping_.end()) {
236 *event_name = it->second.pref_name;
237 *permission = it->second.read_permission;
238 return true;
240 return false;
243 PrefTransformerInterface* FindTransformerForBrowserPref(
244 const std::string& browser_pref) {
245 std::map<std::string, PrefTransformerInterface*>::iterator it =
246 transformers_.find(browser_pref);
247 if (it != transformers_.end())
248 return it->second;
249 else
250 return identity_transformer_.get();
253 private:
254 friend struct DefaultSingletonTraits<PrefMapping>;
256 PrefMapping() {
257 identity_transformer_.reset(new IdentityPrefTransformer());
258 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
259 mapping_[kPrefMapping[i].extension_pref] =
260 PrefMapData(kPrefMapping[i].browser_pref,
261 kPrefMapping[i].read_permission,
262 kPrefMapping[i].write_permission);
263 std::string event_name =
264 base::StringPrintf(kOnPrefChangeFormat,
265 kPrefMapping[i].extension_pref);
266 event_mapping_[kPrefMapping[i].browser_pref] =
267 PrefMapData(event_name,
268 kPrefMapping[i].read_permission,
269 kPrefMapping[i].write_permission);
271 DCHECK_EQ(arraysize(kPrefMapping), mapping_.size());
272 DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size());
273 RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer());
274 RegisterPrefTransformer(prefs::kBlockThirdPartyCookies,
275 new InvertBooleanTransformer());
276 RegisterPrefTransformer(prefs::kNetworkPredictionOptions,
277 new NetworkPredictionTransformer());
280 ~PrefMapping() {
281 STLDeleteContainerPairSecondPointers(transformers_.begin(),
282 transformers_.end());
285 void RegisterPrefTransformer(const std::string& browser_pref,
286 PrefTransformerInterface* transformer) {
287 DCHECK_EQ(0u, transformers_.count(browser_pref)) <<
288 "Trying to register pref transformer for " << browser_pref << " twice";
289 transformers_[browser_pref] = transformer;
292 struct PrefMapData {
293 PrefMapData()
294 : read_permission(APIPermission::kInvalid),
295 write_permission(APIPermission::kInvalid) {}
297 PrefMapData(const std::string& pref_name,
298 APIPermission::ID read,
299 APIPermission::ID write)
300 : pref_name(pref_name),
301 read_permission(read),
302 write_permission(write) {}
304 // Browser or extension preference to which the data maps.
305 std::string pref_name;
307 // Permission needed to read the preference.
308 APIPermission::ID read_permission;
310 // Permission needed to write the preference.
311 APIPermission::ID write_permission;
314 typedef std::map<std::string, PrefMapData> PrefMap;
316 // Mapping from extension pref keys to browser pref keys and permissions.
317 PrefMap mapping_;
319 // Mapping from browser pref keys to extension event names and permissions.
320 PrefMap event_mapping_;
322 // Mapping from browser pref keys to transformers.
323 std::map<std::string, PrefTransformerInterface*> transformers_;
325 scoped_ptr<PrefTransformerInterface> identity_transformer_;
327 DISALLOW_COPY_AND_ASSIGN(PrefMapping);
330 } // namespace
332 PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
333 : profile_(profile) {
334 registrar_.Init(profile_->GetPrefs());
335 incognito_registrar_.Init(profile_->GetOffTheRecordPrefs());
336 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
337 registrar_.Add(kPrefMapping[i].browser_pref,
338 base::Bind(&PreferenceEventRouter::OnPrefChanged,
339 base::Unretained(this),
340 registrar_.prefs()));
341 incognito_registrar_.Add(kPrefMapping[i].browser_pref,
342 base::Bind(&PreferenceEventRouter::OnPrefChanged,
343 base::Unretained(this),
344 incognito_registrar_.prefs()));
348 PreferenceEventRouter::~PreferenceEventRouter() { }
350 void PreferenceEventRouter::OnPrefChanged(PrefService* pref_service,
351 const std::string& browser_pref) {
352 bool incognito = (pref_service != profile_->GetPrefs());
354 std::string event_name;
355 APIPermission::ID permission = APIPermission::kInvalid;
356 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
357 browser_pref, &event_name, &permission);
358 DCHECK(rv);
360 base::ListValue args;
361 base::DictionaryValue* dict = new base::DictionaryValue();
362 args.Append(dict);
363 const PrefService::Preference* pref =
364 pref_service->FindPreference(browser_pref.c_str());
365 CHECK(pref);
366 PrefTransformerInterface* transformer =
367 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
368 base::Value* transformed_value =
369 transformer->BrowserToExtensionPref(pref->GetValue());
370 if (!transformed_value) {
371 LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
372 pref->name());
373 return;
376 dict->Set(keys::kValue, transformed_value);
377 if (incognito) {
378 ExtensionPrefs* ep = ExtensionPrefs::Get(profile_);
379 dict->SetBoolean(keys::kIncognitoSpecific,
380 ep->HasIncognitoPrefValue(browser_pref));
383 // TODO(kalman): Have a histogram value for each pref type.
384 // This isn't so important for the current use case of these
385 // histograms, which is to track which event types are waking up event
386 // pages, or which are delivered to persistent background pages. Simply
387 // "a setting changed" is enough detail for that. However if we try to
388 // use these histograms for any fine-grained logic (like removing the
389 // string event name altogether), or if we discover this event is
390 // firing a lot and want to understand that better, then this will need
391 // to change.
392 events::HistogramValue histogram_value =
393 events::TYPES_CHROME_SETTING_ON_CHANGE;
394 helpers::DispatchEventToExtensions(profile_, histogram_value, event_name,
395 &args, permission, incognito,
396 browser_pref);
399 void PreferenceAPIBase::SetExtensionControlledPref(
400 const std::string& extension_id,
401 const std::string& pref_key,
402 ExtensionPrefsScope scope,
403 base::Value* value) {
404 #ifndef NDEBUG
405 const PrefService::Preference* pref =
406 extension_prefs()->pref_service()->FindPreference(pref_key.c_str());
407 DCHECK(pref) << "Extension controlled preference key " << pref_key
408 << " not registered.";
409 DCHECK_EQ(pref->GetType(), value->GetType())
410 << "Extension controlled preference " << pref_key << " has wrong type.";
411 #endif
413 std::string scope_string;
414 // ScopeToPrefName() returns false if the scope is not persisted.
415 if (pref_names::ScopeToPrefName(scope, &scope_string)) {
416 // Also store in persisted Preferences file to recover after a
417 // browser restart.
418 ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
419 extension_id,
420 scope_string);
421 base::DictionaryValue* preference = update.Get();
422 if (!preference)
423 preference = update.Create();
424 preference->SetWithoutPathExpansion(pref_key, value->DeepCopy());
426 extension_pref_value_map()->SetExtensionPref(
427 extension_id, pref_key, scope, value);
430 void PreferenceAPIBase::RemoveExtensionControlledPref(
431 const std::string& extension_id,
432 const std::string& pref_key,
433 ExtensionPrefsScope scope) {
434 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
435 << "Extension controlled preference key " << pref_key
436 << " not registered.";
438 std::string scope_string;
439 if (pref_names::ScopeToPrefName(scope, &scope_string)) {
440 ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
441 extension_id,
442 scope_string);
443 base::DictionaryValue* preference = update.Get();
444 if (preference)
445 preference->RemoveWithoutPathExpansion(pref_key, NULL);
447 extension_pref_value_map()->RemoveExtensionPref(
448 extension_id, pref_key, scope);
451 bool PreferenceAPIBase::CanExtensionControlPref(
452 const std::string& extension_id,
453 const std::string& pref_key,
454 bool incognito) {
455 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
456 << "Extension controlled preference key " << pref_key
457 << " not registered.";
459 return extension_pref_value_map()->CanExtensionControlPref(
460 extension_id, pref_key, incognito);
463 bool PreferenceAPIBase::DoesExtensionControlPref(
464 const std::string& extension_id,
465 const std::string& pref_key,
466 bool* from_incognito) {
467 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
468 << "Extension controlled preference key " << pref_key
469 << " not registered.";
471 return extension_pref_value_map()->DoesExtensionControlPref(
472 extension_id, pref_key, from_incognito);
475 PreferenceAPI::PreferenceAPI(content::BrowserContext* context)
476 : profile_(Profile::FromBrowserContext(context)) {
477 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
478 std::string event_name;
479 APIPermission::ID permission = APIPermission::kInvalid;
480 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
481 kPrefMapping[i].browser_pref, &event_name, &permission);
482 DCHECK(rv);
483 EventRouter::Get(profile_)->RegisterObserver(this, event_name);
485 content_settings_store()->AddObserver(this);
488 PreferenceAPI::~PreferenceAPI() {
491 void PreferenceAPI::Shutdown() {
492 EventRouter::Get(profile_)->UnregisterObserver(this);
493 if (!extension_prefs()->extensions_disabled())
494 ClearIncognitoSessionOnlyContentSettings();
495 content_settings_store()->RemoveObserver(this);
498 static base::LazyInstance<BrowserContextKeyedAPIFactory<PreferenceAPI> >
499 g_factory = LAZY_INSTANCE_INITIALIZER;
501 // static
502 BrowserContextKeyedAPIFactory<PreferenceAPI>*
503 PreferenceAPI::GetFactoryInstance() {
504 return g_factory.Pointer();
507 // static
508 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) {
509 return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context);
512 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) {
513 preference_event_router_.reset(new PreferenceEventRouter(profile_));
514 EventRouter::Get(profile_)->UnregisterObserver(this);
517 void PreferenceAPI::OnContentSettingChanged(const std::string& extension_id,
518 bool incognito) {
519 if (incognito) {
520 extension_prefs()->UpdateExtensionPref(
521 extension_id,
522 pref_names::kPrefIncognitoContentSettings,
523 content_settings_store()->GetSettingsForExtension(
524 extension_id, kExtensionPrefsScopeIncognitoPersistent));
525 } else {
526 extension_prefs()->UpdateExtensionPref(
527 extension_id,
528 pref_names::kPrefContentSettings,
529 content_settings_store()->GetSettingsForExtension(
530 extension_id, kExtensionPrefsScopeRegular));
534 void PreferenceAPI::ClearIncognitoSessionOnlyContentSettings() {
535 ExtensionIdList extension_ids;
536 extension_prefs()->GetExtensions(&extension_ids);
537 for (ExtensionIdList::iterator extension_id = extension_ids.begin();
538 extension_id != extension_ids.end(); ++extension_id) {
539 content_settings_store()->ClearContentSettingsForExtension(
540 *extension_id, kExtensionPrefsScopeIncognitoSessionOnly);
544 ExtensionPrefs* PreferenceAPI::extension_prefs() {
545 return ExtensionPrefs::Get(profile_);
548 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
549 return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
552 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() {
553 return ContentSettingsService::Get(profile_)->content_settings_store();
556 template <>
557 void
558 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() {
559 DependsOn(ContentSettingsService::GetFactoryInstance());
560 DependsOn(ExtensionPrefsFactory::GetInstance());
561 DependsOn(ExtensionPrefValueMapFactory::GetInstance());
562 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
565 PreferenceFunction::~PreferenceFunction() { }
567 bool PreferenceFunction::ValidateBrowserPref(
568 const std::string& extension_pref_key,
569 PreferenceFunction::PermissionType permission_type,
570 std::string* browser_pref_key) {
571 APIPermission::ID read_permission = APIPermission::kInvalid;
572 APIPermission::ID write_permission = APIPermission::kInvalid;
573 EXTENSION_FUNCTION_VALIDATE(
574 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
575 extension_pref_key,
576 browser_pref_key,
577 &read_permission,
578 &write_permission));
579 APIPermission::ID permission = permission_type == PERMISSION_TYPE_READ
580 ? read_permission
581 : write_permission;
582 if (!extension()->permissions_data()->HasAPIPermission(permission)) {
583 error_ = ErrorUtils::FormatErrorMessage(
584 keys::kPermissionErrorMessage, extension_pref_key);
585 return false;
587 return true;
590 GetPreferenceFunction::~GetPreferenceFunction() { }
592 bool GetPreferenceFunction::RunSync() {
593 std::string pref_key;
594 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
595 base::DictionaryValue* details = NULL;
596 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
598 bool incognito = false;
599 if (details->HasKey(keys::kIncognitoKey))
600 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(keys::kIncognitoKey,
601 &incognito));
603 // Check incognito access.
604 if (incognito && !include_incognito()) {
605 error_ = keys::kIncognitoErrorMessage;
606 return false;
609 // Obtain pref.
610 std::string browser_pref;
611 if (!ValidateBrowserPref(
612 pref_key, PreferenceFunction::PERMISSION_TYPE_READ, &browser_pref)) {
613 return false;
615 PrefService* prefs = incognito ? GetProfile()->GetOffTheRecordPrefs()
616 : GetProfile()->GetPrefs();
617 const PrefService::Preference* pref =
618 prefs->FindPreference(browser_pref.c_str());
619 CHECK(pref);
621 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
623 // Retrieve level of control.
624 std::string level_of_control = helpers::GetLevelOfControl(
625 GetProfile(), extension_id(), browser_pref, incognito);
626 result->SetString(keys::kLevelOfControl, level_of_control);
628 // Retrieve pref value.
629 PrefTransformerInterface* transformer =
630 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
631 base::Value* transformed_value =
632 transformer->BrowserToExtensionPref(pref->GetValue());
633 if (!transformed_value) {
634 LOG(ERROR) <<
635 ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
636 pref->name());
637 return false;
639 result->Set(keys::kValue, transformed_value);
641 // Retrieve incognito status.
642 if (incognito) {
643 ExtensionPrefs* ep = ExtensionPrefs::Get(GetProfile());
644 result->SetBoolean(keys::kIncognitoSpecific,
645 ep->HasIncognitoPrefValue(browser_pref));
648 SetResult(result.release());
649 return true;
652 SetPreferenceFunction::~SetPreferenceFunction() { }
654 bool SetPreferenceFunction::RunSync() {
655 std::string pref_key;
656 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
657 base::DictionaryValue* details = NULL;
658 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
660 base::Value* value = NULL;
661 EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kValue, &value));
663 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
664 if (details->HasKey(keys::kScopeKey)) {
665 std::string scope_str;
666 EXTENSION_FUNCTION_VALIDATE(
667 details->GetString(keys::kScopeKey, &scope_str));
669 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
672 // Check incognito scope.
673 bool incognito =
674 (scope == kExtensionPrefsScopeIncognitoPersistent ||
675 scope == kExtensionPrefsScopeIncognitoSessionOnly);
676 if (incognito) {
677 // Regular profiles can't access incognito unless include_incognito is true.
678 if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
679 error_ = keys::kIncognitoErrorMessage;
680 return false;
682 } else {
683 // Incognito profiles can't access regular mode ever, they only exist in
684 // split mode.
685 if (GetProfile()->IsOffTheRecord()) {
686 error_ = "Can't modify regular settings from an incognito context.";
687 return false;
691 if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
692 !GetProfile()->HasOffTheRecordProfile()) {
693 error_ = keys::kIncognitoSessionOnlyErrorMessage;
694 return false;
697 // Obtain pref.
698 std::string browser_pref;
699 if (!ValidateBrowserPref(
700 pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
701 return false;
703 ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
704 const PrefService::Preference* pref =
705 prefs->pref_service()->FindPreference(browser_pref.c_str());
706 CHECK(pref);
708 // Validate new value.
709 PrefTransformerInterface* transformer =
710 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
711 std::string error;
712 bool bad_message = false;
713 scoped_ptr<base::Value> browser_pref_value(
714 transformer->ExtensionToBrowserPref(value, &error, &bad_message));
715 if (!browser_pref_value) {
716 error_ = error;
717 bad_message_ = bad_message;
718 return false;
720 EXTENSION_FUNCTION_VALIDATE(browser_pref_value->GetType() == pref->GetType());
722 // Validate also that the stored value can be converted back by the
723 // transformer.
724 scoped_ptr<base::Value> extensionPrefValue(
725 transformer->BrowserToExtensionPref(browser_pref_value.get()));
726 if (!extensionPrefValue) {
727 error_ = ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
728 pref->name());
729 bad_message_ = true;
730 return false;
733 PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
734 extension_id(), browser_pref, scope, browser_pref_value.release());
735 return true;
738 ClearPreferenceFunction::~ClearPreferenceFunction() { }
740 bool ClearPreferenceFunction::RunSync() {
741 std::string pref_key;
742 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
743 base::DictionaryValue* details = NULL;
744 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
746 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
747 if (details->HasKey(keys::kScopeKey)) {
748 std::string scope_str;
749 EXTENSION_FUNCTION_VALIDATE(
750 details->GetString(keys::kScopeKey, &scope_str));
752 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
755 // Check incognito scope.
756 bool incognito =
757 (scope == kExtensionPrefsScopeIncognitoPersistent ||
758 scope == kExtensionPrefsScopeIncognitoSessionOnly);
759 if (incognito) {
760 // We don't check incognito permissions here, as an extension should be
761 // always allowed to clear its own settings.
762 } else {
763 // Incognito profiles can't access regular mode ever, they only exist in
764 // split mode.
765 if (GetProfile()->IsOffTheRecord()) {
766 error_ = "Can't modify regular settings from an incognito context.";
767 return false;
771 std::string browser_pref;
772 if (!ValidateBrowserPref(
773 pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
774 return false;
777 PreferenceAPI::Get(GetProfile())
778 ->RemoveExtensionControlledPref(extension_id(), browser_pref, scope);
779 return true;
782 } // namespace extensions