Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / preference / preference_api.cc
blob475eade426cb4ba6fd68660eeb5fd66bf529813a
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/proxy_config/proxy_config_pref_names.h"
27 #include "components/translate/core/common/translate_pref_names.h"
28 #include "content/public/browser/notification_details.h"
29 #include "content/public/browser/notification_source.h"
30 #include "extensions/browser/extension_pref_value_map.h"
31 #include "extensions/browser/extension_pref_value_map_factory.h"
32 #include "extensions/browser/extension_prefs.h"
33 #include "extensions/browser/extension_prefs_factory.h"
34 #include "extensions/browser/extension_system_provider.h"
35 #include "extensions/browser/extensions_browser_client.h"
36 #include "extensions/browser/pref_names.h"
37 #include "extensions/common/error_utils.h"
38 #include "extensions/common/permissions/api_permission.h"
39 #include "extensions/common/permissions/permissions_data.h"
41 namespace keys = extensions::preference_api_constants;
42 namespace helpers = extensions::preference_helpers;
44 using base::DictionaryValue;
46 namespace extensions {
48 namespace {
50 struct PrefMappingEntry {
51 // Name of the preference referenced by the extension API JSON.
52 const char* extension_pref;
54 // Name of the preference in the PrefStores.
55 const char* browser_pref;
57 // Permission required to read and observe this preference.
58 // Use APIPermission::kInvalid for |read_permission| to express that the read
59 // permission should not be granted.
60 APIPermission::ID read_permission;
62 // Permission required to write this preference.
63 // Use APIPermission::kInvalid for |write_permission| to express that the
64 // write permission should not be granted.
65 APIPermission::ID write_permission;
68 const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange";
69 const char kConversionErrorMessage[] =
70 "Internal error: Stored value for preference '*' cannot be converted "
71 "properly.";
73 PrefMappingEntry kPrefMapping[] = {
74 {"spdy_proxy.enabled",
75 data_reduction_proxy::prefs::kDataReductionProxyEnabled,
76 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
77 {"data_reduction.daily_original_length",
78 data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
79 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
80 {"data_reduction.daily_received_length",
81 data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
82 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
83 {"alternateErrorPagesEnabled", prefs::kAlternateErrorPagesEnabled,
84 APIPermission::kPrivacy, APIPermission::kPrivacy},
85 {"autofillEnabled", autofill::prefs::kAutofillEnabled,
86 APIPermission::kPrivacy, APIPermission::kPrivacy},
87 {"hyperlinkAuditingEnabled", prefs::kEnableHyperlinkAuditing,
88 APIPermission::kPrivacy, APIPermission::kPrivacy},
89 {"hotwordSearchEnabled", prefs::kHotwordSearchEnabled,
90 APIPermission::kPrivacy, APIPermission::kPrivacy},
91 {"networkPredictionEnabled", prefs::kNetworkPredictionOptions,
92 APIPermission::kPrivacy, APIPermission::kPrivacy},
93 {"passwordSavingEnabled",
94 password_manager::prefs::kPasswordManagerSavingEnabled,
95 APIPermission::kPrivacy, APIPermission::kPrivacy},
96 {"protectedContentEnabled", prefs::kEnableDRM, APIPermission::kPrivacy,
97 APIPermission::kPrivacy},
98 {"proxy", proxy_config::prefs::kProxy, APIPermission::kProxy,
99 APIPermission::kProxy},
100 {"referrersEnabled", prefs::kEnableReferrers, APIPermission::kPrivacy,
101 APIPermission::kPrivacy},
102 {"safeBrowsingEnabled", prefs::kSafeBrowsingEnabled,
103 APIPermission::kPrivacy, APIPermission::kPrivacy},
104 {"safeBrowsingExtendedReportingEnabled",
105 prefs::kSafeBrowsingExtendedReportingEnabled, APIPermission::kPrivacy,
106 APIPermission::kPrivacy},
107 {"searchSuggestEnabled", prefs::kSearchSuggestEnabled,
108 APIPermission::kPrivacy, APIPermission::kPrivacy},
109 {"spellingServiceEnabled", prefs::kSpellCheckUseSpellingService,
110 APIPermission::kPrivacy, APIPermission::kPrivacy},
111 {"thirdPartyCookiesAllowed", prefs::kBlockThirdPartyCookies,
112 APIPermission::kPrivacy, APIPermission::kPrivacy},
113 {"translationServiceEnabled", prefs::kEnableTranslate,
114 APIPermission::kPrivacy, APIPermission::kPrivacy},
115 #if defined(ENABLE_WEBRTC)
116 {"webRTCMultipleRoutesEnabled", prefs::kWebRTCMultipleRoutesEnabled,
117 APIPermission::kPrivacy, APIPermission::kPrivacy},
118 {"webRTCNonProxiedUdpEnabled", prefs::kWebRTCNonProxiedUdpEnabled,
119 APIPermission::kPrivacy, APIPermission::kPrivacy},
120 #endif
121 // accessibilityFeatures.animationPolicy is available for
122 // all platforms but the others from accessibilityFeatures
123 // is only available for OS_CHROMEOS.
124 {"animationPolicy", prefs::kAnimationPolicy,
125 APIPermission::kAccessibilityFeaturesRead,
126 APIPermission::kAccessibilityFeaturesModify},
127 #if defined(OS_CHROMEOS)
128 {"autoclick", prefs::kAccessibilityAutoclickEnabled,
129 APIPermission::kAccessibilityFeaturesRead,
130 APIPermission::kAccessibilityFeaturesModify},
131 {"highContrast", prefs::kAccessibilityHighContrastEnabled,
132 APIPermission::kAccessibilityFeaturesRead,
133 APIPermission::kAccessibilityFeaturesModify},
134 {"largeCursor", prefs::kAccessibilityLargeCursorEnabled,
135 APIPermission::kAccessibilityFeaturesRead,
136 APIPermission::kAccessibilityFeaturesModify},
137 {"screenMagnifier", prefs::kAccessibilityScreenMagnifierEnabled,
138 APIPermission::kAccessibilityFeaturesRead,
139 APIPermission::kAccessibilityFeaturesModify},
140 {"spokenFeedback", prefs::kAccessibilitySpokenFeedbackEnabled,
141 APIPermission::kAccessibilityFeaturesRead,
142 APIPermission::kAccessibilityFeaturesModify},
143 {"stickyKeys", prefs::kAccessibilityStickyKeysEnabled,
144 APIPermission::kAccessibilityFeaturesRead,
145 APIPermission::kAccessibilityFeaturesModify},
146 {"virtualKeyboard", prefs::kAccessibilityVirtualKeyboardEnabled,
147 APIPermission::kAccessibilityFeaturesRead,
148 APIPermission::kAccessibilityFeaturesModify},
149 #endif
152 class IdentityPrefTransformer : public PrefTransformerInterface {
153 public:
154 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
155 std::string* error,
156 bool* bad_message) override {
157 return extension_pref->DeepCopy();
160 base::Value* BrowserToExtensionPref(
161 const base::Value* browser_pref) override {
162 return browser_pref->DeepCopy();
166 class InvertBooleanTransformer : public PrefTransformerInterface {
167 public:
168 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
169 std::string* error,
170 bool* bad_message) override {
171 return InvertBooleanValue(extension_pref);
174 base::Value* BrowserToExtensionPref(
175 const base::Value* browser_pref) override {
176 return InvertBooleanValue(browser_pref);
179 private:
180 static base::Value* InvertBooleanValue(const base::Value* value) {
181 bool bool_value = false;
182 bool result = value->GetAsBoolean(&bool_value);
183 DCHECK(result);
184 return new base::FundamentalValue(!bool_value);
188 class NetworkPredictionTransformer : public PrefTransformerInterface {
189 public:
190 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
191 std::string* error,
192 bool* bad_message) override {
193 bool bool_value = false;
194 const bool pref_found = extension_pref->GetAsBoolean(&bool_value);
195 DCHECK(pref_found) << "Preference not found.";
196 if (bool_value) {
197 return new base::FundamentalValue(
198 chrome_browser_net::NETWORK_PREDICTION_DEFAULT);
199 } else {
200 return new base::FundamentalValue(
201 chrome_browser_net::NETWORK_PREDICTION_NEVER);
205 base::Value* BrowserToExtensionPref(
206 const base::Value* browser_pref) override {
207 int int_value = chrome_browser_net::NETWORK_PREDICTION_DEFAULT;
208 const bool pref_found = browser_pref->GetAsInteger(&int_value);
209 DCHECK(pref_found) << "Preference not found.";
210 return new base::FundamentalValue(
211 int_value != chrome_browser_net::NETWORK_PREDICTION_NEVER);
215 class PrefMapping {
216 public:
217 static PrefMapping* GetInstance() {
218 return base::Singleton<PrefMapping>::get();
221 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
222 std::string* browser_pref,
223 APIPermission::ID* read_permission,
224 APIPermission::ID* write_permission) {
225 PrefMap::iterator it = mapping_.find(extension_pref);
226 if (it != mapping_.end()) {
227 *browser_pref = it->second.pref_name;
228 *read_permission = it->second.read_permission;
229 *write_permission = it->second.write_permission;
230 return true;
232 return false;
235 bool FindEventForBrowserPref(const std::string& browser_pref,
236 std::string* event_name,
237 APIPermission::ID* permission) {
238 PrefMap::iterator it = event_mapping_.find(browser_pref);
239 if (it != event_mapping_.end()) {
240 *event_name = it->second.pref_name;
241 *permission = it->second.read_permission;
242 return true;
244 return false;
247 PrefTransformerInterface* FindTransformerForBrowserPref(
248 const std::string& browser_pref) {
249 std::map<std::string, PrefTransformerInterface*>::iterator it =
250 transformers_.find(browser_pref);
251 if (it != transformers_.end())
252 return it->second;
253 else
254 return identity_transformer_.get();
257 private:
258 friend struct base::DefaultSingletonTraits<PrefMapping>;
260 PrefMapping() {
261 identity_transformer_.reset(new IdentityPrefTransformer());
262 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
263 mapping_[kPrefMapping[i].extension_pref] =
264 PrefMapData(kPrefMapping[i].browser_pref,
265 kPrefMapping[i].read_permission,
266 kPrefMapping[i].write_permission);
267 std::string event_name =
268 base::StringPrintf(kOnPrefChangeFormat,
269 kPrefMapping[i].extension_pref);
270 event_mapping_[kPrefMapping[i].browser_pref] =
271 PrefMapData(event_name,
272 kPrefMapping[i].read_permission,
273 kPrefMapping[i].write_permission);
275 DCHECK_EQ(arraysize(kPrefMapping), mapping_.size());
276 DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size());
277 RegisterPrefTransformer(proxy_config::prefs::kProxy,
278 new ProxyPrefTransformer());
279 RegisterPrefTransformer(prefs::kBlockThirdPartyCookies,
280 new InvertBooleanTransformer());
281 RegisterPrefTransformer(prefs::kNetworkPredictionOptions,
282 new NetworkPredictionTransformer());
285 ~PrefMapping() {
286 STLDeleteContainerPairSecondPointers(transformers_.begin(),
287 transformers_.end());
290 void RegisterPrefTransformer(const std::string& browser_pref,
291 PrefTransformerInterface* transformer) {
292 DCHECK_EQ(0u, transformers_.count(browser_pref)) <<
293 "Trying to register pref transformer for " << browser_pref << " twice";
294 transformers_[browser_pref] = transformer;
297 struct PrefMapData {
298 PrefMapData()
299 : read_permission(APIPermission::kInvalid),
300 write_permission(APIPermission::kInvalid) {}
302 PrefMapData(const std::string& pref_name,
303 APIPermission::ID read,
304 APIPermission::ID write)
305 : pref_name(pref_name),
306 read_permission(read),
307 write_permission(write) {}
309 // Browser or extension preference to which the data maps.
310 std::string pref_name;
312 // Permission needed to read the preference.
313 APIPermission::ID read_permission;
315 // Permission needed to write the preference.
316 APIPermission::ID write_permission;
319 typedef std::map<std::string, PrefMapData> PrefMap;
321 // Mapping from extension pref keys to browser pref keys and permissions.
322 PrefMap mapping_;
324 // Mapping from browser pref keys to extension event names and permissions.
325 PrefMap event_mapping_;
327 // Mapping from browser pref keys to transformers.
328 std::map<std::string, PrefTransformerInterface*> transformers_;
330 scoped_ptr<PrefTransformerInterface> identity_transformer_;
332 DISALLOW_COPY_AND_ASSIGN(PrefMapping);
335 } // namespace
337 PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
338 : profile_(profile) {
339 registrar_.Init(profile_->GetPrefs());
340 incognito_registrar_.Init(profile_->GetOffTheRecordPrefs());
341 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
342 registrar_.Add(kPrefMapping[i].browser_pref,
343 base::Bind(&PreferenceEventRouter::OnPrefChanged,
344 base::Unretained(this),
345 registrar_.prefs()));
346 incognito_registrar_.Add(kPrefMapping[i].browser_pref,
347 base::Bind(&PreferenceEventRouter::OnPrefChanged,
348 base::Unretained(this),
349 incognito_registrar_.prefs()));
353 PreferenceEventRouter::~PreferenceEventRouter() { }
355 void PreferenceEventRouter::OnPrefChanged(PrefService* pref_service,
356 const std::string& browser_pref) {
357 bool incognito = (pref_service != profile_->GetPrefs());
359 std::string event_name;
360 APIPermission::ID permission = APIPermission::kInvalid;
361 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
362 browser_pref, &event_name, &permission);
363 DCHECK(rv);
365 base::ListValue args;
366 base::DictionaryValue* dict = new base::DictionaryValue();
367 args.Append(dict);
368 const PrefService::Preference* pref =
369 pref_service->FindPreference(browser_pref.c_str());
370 CHECK(pref);
371 PrefTransformerInterface* transformer =
372 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
373 base::Value* transformed_value =
374 transformer->BrowserToExtensionPref(pref->GetValue());
375 if (!transformed_value) {
376 LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
377 pref->name());
378 return;
381 dict->Set(keys::kValue, transformed_value);
382 if (incognito) {
383 ExtensionPrefs* ep = ExtensionPrefs::Get(profile_);
384 dict->SetBoolean(keys::kIncognitoSpecific,
385 ep->HasIncognitoPrefValue(browser_pref));
388 // TODO(kalman): Have a histogram value for each pref type.
389 // This isn't so important for the current use case of these
390 // histograms, which is to track which event types are waking up event
391 // pages, or which are delivered to persistent background pages. Simply
392 // "a setting changed" is enough detail for that. However if we try to
393 // use these histograms for any fine-grained logic (like removing the
394 // string event name altogether), or if we discover this event is
395 // firing a lot and want to understand that better, then this will need
396 // to change.
397 events::HistogramValue histogram_value =
398 events::TYPES_CHROME_SETTING_ON_CHANGE;
399 helpers::DispatchEventToExtensions(profile_, histogram_value, event_name,
400 &args, permission, incognito,
401 browser_pref);
404 void PreferenceAPIBase::SetExtensionControlledPref(
405 const std::string& extension_id,
406 const std::string& pref_key,
407 ExtensionPrefsScope scope,
408 base::Value* value) {
409 #ifndef NDEBUG
410 const PrefService::Preference* pref =
411 extension_prefs()->pref_service()->FindPreference(pref_key.c_str());
412 DCHECK(pref) << "Extension controlled preference key " << pref_key
413 << " not registered.";
414 DCHECK_EQ(pref->GetType(), value->GetType())
415 << "Extension controlled preference " << pref_key << " has wrong type.";
416 #endif
418 std::string scope_string;
419 // ScopeToPrefName() returns false if the scope is not persisted.
420 if (pref_names::ScopeToPrefName(scope, &scope_string)) {
421 // Also store in persisted Preferences file to recover after a
422 // browser restart.
423 ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
424 extension_id,
425 scope_string);
426 base::DictionaryValue* preference = update.Get();
427 if (!preference)
428 preference = update.Create();
429 preference->SetWithoutPathExpansion(pref_key, value->DeepCopy());
431 extension_pref_value_map()->SetExtensionPref(
432 extension_id, pref_key, scope, value);
435 void PreferenceAPIBase::RemoveExtensionControlledPref(
436 const std::string& extension_id,
437 const std::string& pref_key,
438 ExtensionPrefsScope scope) {
439 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
440 << "Extension controlled preference key " << pref_key
441 << " not registered.";
443 std::string scope_string;
444 if (pref_names::ScopeToPrefName(scope, &scope_string)) {
445 ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
446 extension_id,
447 scope_string);
448 base::DictionaryValue* preference = update.Get();
449 if (preference)
450 preference->RemoveWithoutPathExpansion(pref_key, NULL);
452 extension_pref_value_map()->RemoveExtensionPref(
453 extension_id, pref_key, scope);
456 bool PreferenceAPIBase::CanExtensionControlPref(
457 const std::string& extension_id,
458 const std::string& pref_key,
459 bool incognito) {
460 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
461 << "Extension controlled preference key " << pref_key
462 << " not registered.";
464 return extension_pref_value_map()->CanExtensionControlPref(
465 extension_id, pref_key, incognito);
468 bool PreferenceAPIBase::DoesExtensionControlPref(
469 const std::string& extension_id,
470 const std::string& pref_key,
471 bool* from_incognito) {
472 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
473 << "Extension controlled preference key " << pref_key
474 << " not registered.";
476 return extension_pref_value_map()->DoesExtensionControlPref(
477 extension_id, pref_key, from_incognito);
480 PreferenceAPI::PreferenceAPI(content::BrowserContext* context)
481 : profile_(Profile::FromBrowserContext(context)) {
482 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
483 std::string event_name;
484 APIPermission::ID permission = APIPermission::kInvalid;
485 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
486 kPrefMapping[i].browser_pref, &event_name, &permission);
487 DCHECK(rv);
488 EventRouter::Get(profile_)->RegisterObserver(this, event_name);
490 content_settings_store()->AddObserver(this);
493 PreferenceAPI::~PreferenceAPI() {
496 void PreferenceAPI::Shutdown() {
497 EventRouter::Get(profile_)->UnregisterObserver(this);
498 if (!extension_prefs()->extensions_disabled())
499 ClearIncognitoSessionOnlyContentSettings();
500 content_settings_store()->RemoveObserver(this);
503 static base::LazyInstance<BrowserContextKeyedAPIFactory<PreferenceAPI> >
504 g_factory = LAZY_INSTANCE_INITIALIZER;
506 // static
507 BrowserContextKeyedAPIFactory<PreferenceAPI>*
508 PreferenceAPI::GetFactoryInstance() {
509 return g_factory.Pointer();
512 // static
513 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) {
514 return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context);
517 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) {
518 preference_event_router_.reset(new PreferenceEventRouter(profile_));
519 EventRouter::Get(profile_)->UnregisterObserver(this);
522 void PreferenceAPI::OnContentSettingChanged(const std::string& extension_id,
523 bool incognito) {
524 if (incognito) {
525 extension_prefs()->UpdateExtensionPref(
526 extension_id,
527 pref_names::kPrefIncognitoContentSettings,
528 content_settings_store()->GetSettingsForExtension(
529 extension_id, kExtensionPrefsScopeIncognitoPersistent));
530 } else {
531 extension_prefs()->UpdateExtensionPref(
532 extension_id,
533 pref_names::kPrefContentSettings,
534 content_settings_store()->GetSettingsForExtension(
535 extension_id, kExtensionPrefsScopeRegular));
539 void PreferenceAPI::ClearIncognitoSessionOnlyContentSettings() {
540 ExtensionIdList extension_ids;
541 extension_prefs()->GetExtensions(&extension_ids);
542 for (ExtensionIdList::iterator extension_id = extension_ids.begin();
543 extension_id != extension_ids.end(); ++extension_id) {
544 content_settings_store()->ClearContentSettingsForExtension(
545 *extension_id, kExtensionPrefsScopeIncognitoSessionOnly);
549 ExtensionPrefs* PreferenceAPI::extension_prefs() {
550 return ExtensionPrefs::Get(profile_);
553 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
554 return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
557 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() {
558 return ContentSettingsService::Get(profile_)->content_settings_store();
561 template <>
562 void
563 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() {
564 DependsOn(ContentSettingsService::GetFactoryInstance());
565 DependsOn(ExtensionPrefsFactory::GetInstance());
566 DependsOn(ExtensionPrefValueMapFactory::GetInstance());
567 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
570 PreferenceFunction::~PreferenceFunction() { }
572 bool PreferenceFunction::ValidateBrowserPref(
573 const std::string& extension_pref_key,
574 PreferenceFunction::PermissionType permission_type,
575 std::string* browser_pref_key) {
576 APIPermission::ID read_permission = APIPermission::kInvalid;
577 APIPermission::ID write_permission = APIPermission::kInvalid;
578 EXTENSION_FUNCTION_VALIDATE(
579 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
580 extension_pref_key,
581 browser_pref_key,
582 &read_permission,
583 &write_permission));
584 APIPermission::ID permission = permission_type == PERMISSION_TYPE_READ
585 ? read_permission
586 : write_permission;
587 if (!extension()->permissions_data()->HasAPIPermission(permission)) {
588 error_ = ErrorUtils::FormatErrorMessage(
589 keys::kPermissionErrorMessage, extension_pref_key);
590 return false;
592 return true;
595 GetPreferenceFunction::~GetPreferenceFunction() { }
597 bool GetPreferenceFunction::RunSync() {
598 std::string pref_key;
599 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
600 base::DictionaryValue* details = NULL;
601 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
603 bool incognito = false;
604 if (details->HasKey(keys::kIncognitoKey))
605 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(keys::kIncognitoKey,
606 &incognito));
608 // Check incognito access.
609 if (incognito && !include_incognito()) {
610 error_ = keys::kIncognitoErrorMessage;
611 return false;
614 // Obtain pref.
615 std::string browser_pref;
616 if (!ValidateBrowserPref(
617 pref_key, PreferenceFunction::PERMISSION_TYPE_READ, &browser_pref)) {
618 return false;
620 PrefService* prefs = incognito ? GetProfile()->GetOffTheRecordPrefs()
621 : GetProfile()->GetPrefs();
622 const PrefService::Preference* pref =
623 prefs->FindPreference(browser_pref.c_str());
624 CHECK(pref);
626 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
628 // Retrieve level of control.
629 std::string level_of_control = helpers::GetLevelOfControl(
630 GetProfile(), extension_id(), browser_pref, incognito);
631 result->SetString(keys::kLevelOfControl, level_of_control);
633 // Retrieve pref value.
634 PrefTransformerInterface* transformer =
635 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
636 base::Value* transformed_value =
637 transformer->BrowserToExtensionPref(pref->GetValue());
638 if (!transformed_value) {
639 LOG(ERROR) <<
640 ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
641 pref->name());
642 return false;
644 result->Set(keys::kValue, transformed_value);
646 // Retrieve incognito status.
647 if (incognito) {
648 ExtensionPrefs* ep = ExtensionPrefs::Get(GetProfile());
649 result->SetBoolean(keys::kIncognitoSpecific,
650 ep->HasIncognitoPrefValue(browser_pref));
653 SetResult(result.release());
654 return true;
657 SetPreferenceFunction::~SetPreferenceFunction() { }
659 bool SetPreferenceFunction::RunSync() {
660 std::string pref_key;
661 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
662 base::DictionaryValue* details = NULL;
663 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
665 base::Value* value = NULL;
666 EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kValue, &value));
668 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
669 if (details->HasKey(keys::kScopeKey)) {
670 std::string scope_str;
671 EXTENSION_FUNCTION_VALIDATE(
672 details->GetString(keys::kScopeKey, &scope_str));
674 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
677 // Check incognito scope.
678 bool incognito =
679 (scope == kExtensionPrefsScopeIncognitoPersistent ||
680 scope == kExtensionPrefsScopeIncognitoSessionOnly);
681 if (incognito) {
682 // Regular profiles can't access incognito unless include_incognito is true.
683 if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
684 error_ = keys::kIncognitoErrorMessage;
685 return false;
687 } else {
688 // Incognito profiles can't access regular mode ever, they only exist in
689 // split mode.
690 if (GetProfile()->IsOffTheRecord()) {
691 error_ = "Can't modify regular settings from an incognito context.";
692 return false;
696 if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
697 !GetProfile()->HasOffTheRecordProfile()) {
698 error_ = keys::kIncognitoSessionOnlyErrorMessage;
699 return false;
702 // Obtain pref.
703 std::string browser_pref;
704 if (!ValidateBrowserPref(
705 pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
706 return false;
708 ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
709 const PrefService::Preference* pref =
710 prefs->pref_service()->FindPreference(browser_pref.c_str());
711 CHECK(pref);
713 // Validate new value.
714 PrefTransformerInterface* transformer =
715 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
716 std::string error;
717 bool bad_message = false;
718 scoped_ptr<base::Value> browser_pref_value(
719 transformer->ExtensionToBrowserPref(value, &error, &bad_message));
720 if (!browser_pref_value) {
721 error_ = error;
722 bad_message_ = bad_message;
723 return false;
725 EXTENSION_FUNCTION_VALIDATE(browser_pref_value->GetType() == pref->GetType());
727 // Validate also that the stored value can be converted back by the
728 // transformer.
729 scoped_ptr<base::Value> extensionPrefValue(
730 transformer->BrowserToExtensionPref(browser_pref_value.get()));
731 if (!extensionPrefValue) {
732 error_ = ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
733 pref->name());
734 bad_message_ = true;
735 return false;
738 PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
739 extension_id(), browser_pref, scope, browser_pref_value.release());
740 return true;
743 ClearPreferenceFunction::~ClearPreferenceFunction() { }
745 bool ClearPreferenceFunction::RunSync() {
746 std::string pref_key;
747 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
748 base::DictionaryValue* details = NULL;
749 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
751 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
752 if (details->HasKey(keys::kScopeKey)) {
753 std::string scope_str;
754 EXTENSION_FUNCTION_VALIDATE(
755 details->GetString(keys::kScopeKey, &scope_str));
757 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
760 // Check incognito scope.
761 bool incognito =
762 (scope == kExtensionPrefsScopeIncognitoPersistent ||
763 scope == kExtensionPrefsScopeIncognitoSessionOnly);
764 if (incognito) {
765 // We don't check incognito permissions here, as an extension should be
766 // always allowed to clear its own settings.
767 } else {
768 // Incognito profiles can't access regular mode ever, they only exist in
769 // split mode.
770 if (GetProfile()->IsOffTheRecord()) {
771 error_ = "Can't modify regular settings from an incognito context.";
772 return false;
776 std::string browser_pref;
777 if (!ValidateBrowserPref(
778 pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
779 return false;
782 PreferenceAPI::Get(GetProfile())
783 ->RemoveExtensionControlledPref(extension_id(), browser_pref, scope);
784 return true;
787 } // namespace extensions