Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / extensions / api / preference / preference_api.cc
blob11d795286b09b08a25cc6d51c8f3006b430a449a
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/translate/core/common/translate_pref_names.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_source.h"
28 #include "extensions/browser/extension_pref_value_map.h"
29 #include "extensions/browser/extension_pref_value_map_factory.h"
30 #include "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_prefs_factory.h"
32 #include "extensions/browser/extension_system_provider.h"
33 #include "extensions/browser/extensions_browser_client.h"
34 #include "extensions/browser/pref_names.h"
35 #include "extensions/common/error_utils.h"
36 #include "extensions/common/permissions/api_permission.h"
37 #include "extensions/common/permissions/permissions_data.h"
39 namespace keys = extensions::preference_api_constants;
40 namespace helpers = extensions::preference_helpers;
42 using base::DictionaryValue;
44 namespace extensions {
46 namespace {
48 struct PrefMappingEntry {
49 // Name of the preference referenced by the extension API JSON.
50 const char* extension_pref;
52 // Name of the preference in the PrefStores.
53 const char* browser_pref;
55 // Permission required to read and observe this preference.
56 // Use APIPermission::kInvalid for |read_permission| to express that the read
57 // permission should not be granted.
58 APIPermission::ID read_permission;
60 // Permission required to write this preference.
61 // Use APIPermission::kInvalid for |write_permission| to express that the
62 // write permission should not be granted.
63 APIPermission::ID write_permission;
66 const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange";
67 const char kConversionErrorMessage[] =
68 "Internal error: Stored value for preference '*' cannot be converted "
69 "properly.";
71 PrefMappingEntry kPrefMapping[] = {
72 {"spdy_proxy.enabled",
73 data_reduction_proxy::prefs::kDataReductionProxyEnabled,
74 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
75 {"data_reduction.daily_original_length",
76 data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
77 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
78 {"data_reduction.daily_received_length",
79 data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
80 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
81 {"data_reduction.update_daily_lengths",
82 data_reduction_proxy::prefs::kUpdateDailyReceivedContentLengths,
83 APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy},
84 {"alternateErrorPagesEnabled", prefs::kAlternateErrorPagesEnabled,
85 APIPermission::kPrivacy, APIPermission::kPrivacy},
86 {"autofillEnabled", autofill::prefs::kAutofillEnabled,
87 APIPermission::kPrivacy, APIPermission::kPrivacy},
88 {"hyperlinkAuditingEnabled", prefs::kEnableHyperlinkAuditing,
89 APIPermission::kPrivacy, APIPermission::kPrivacy},
90 {"hotwordSearchEnabled", prefs::kHotwordSearchEnabled,
91 APIPermission::kPrivacy, APIPermission::kPrivacy},
92 {"networkPredictionEnabled", prefs::kNetworkPredictionOptions,
93 APIPermission::kPrivacy, APIPermission::kPrivacy},
94 {"passwordSavingEnabled",
95 password_manager::prefs::kPasswordManagerSavingEnabled,
96 APIPermission::kPrivacy, APIPermission::kPrivacy},
97 {"protectedContentEnabled", prefs::kEnableDRM, APIPermission::kPrivacy,
98 APIPermission::kPrivacy},
99 {"proxy", prefs::kProxy, APIPermission::kProxy, 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 #endif
119 // accessibilityFeatures.animationPolicy is available for
120 // all platforms but the others from accessibilityFeatures
121 // is only available for OS_CHROMEOS.
122 {"animationPolicy", prefs::kAnimationPolicy,
123 APIPermission::kAccessibilityFeaturesRead,
124 APIPermission::kAccessibilityFeaturesModify},
125 #if defined(OS_CHROMEOS)
126 {"autoclick", prefs::kAccessibilityAutoclickEnabled,
127 APIPermission::kAccessibilityFeaturesRead,
128 APIPermission::kAccessibilityFeaturesModify},
129 {"highContrast", prefs::kAccessibilityHighContrastEnabled,
130 APIPermission::kAccessibilityFeaturesRead,
131 APIPermission::kAccessibilityFeaturesModify},
132 {"largeCursor", prefs::kAccessibilityLargeCursorEnabled,
133 APIPermission::kAccessibilityFeaturesRead,
134 APIPermission::kAccessibilityFeaturesModify},
135 {"screenMagnifier", prefs::kAccessibilityScreenMagnifierEnabled,
136 APIPermission::kAccessibilityFeaturesRead,
137 APIPermission::kAccessibilityFeaturesModify},
138 {"spokenFeedback", prefs::kAccessibilitySpokenFeedbackEnabled,
139 APIPermission::kAccessibilityFeaturesRead,
140 APIPermission::kAccessibilityFeaturesModify},
141 {"stickyKeys", prefs::kAccessibilityStickyKeysEnabled,
142 APIPermission::kAccessibilityFeaturesRead,
143 APIPermission::kAccessibilityFeaturesModify},
144 {"virtualKeyboard", prefs::kAccessibilityVirtualKeyboardEnabled,
145 APIPermission::kAccessibilityFeaturesRead,
146 APIPermission::kAccessibilityFeaturesModify},
147 #endif
150 class IdentityPrefTransformer : public PrefTransformerInterface {
151 public:
152 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
153 std::string* error,
154 bool* bad_message) override {
155 return extension_pref->DeepCopy();
158 base::Value* BrowserToExtensionPref(
159 const base::Value* browser_pref) override {
160 return browser_pref->DeepCopy();
164 class InvertBooleanTransformer : public PrefTransformerInterface {
165 public:
166 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
167 std::string* error,
168 bool* bad_message) override {
169 return InvertBooleanValue(extension_pref);
172 base::Value* BrowserToExtensionPref(
173 const base::Value* browser_pref) override {
174 return InvertBooleanValue(browser_pref);
177 private:
178 static base::Value* InvertBooleanValue(const base::Value* value) {
179 bool bool_value = false;
180 bool result = value->GetAsBoolean(&bool_value);
181 DCHECK(result);
182 return new base::FundamentalValue(!bool_value);
186 class NetworkPredictionTransformer : public PrefTransformerInterface {
187 public:
188 base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
189 std::string* error,
190 bool* bad_message) override {
191 bool bool_value = false;
192 const bool pref_found = extension_pref->GetAsBoolean(&bool_value);
193 DCHECK(pref_found) << "Preference not found.";
194 if (bool_value) {
195 return new base::FundamentalValue(
196 chrome_browser_net::NETWORK_PREDICTION_DEFAULT);
197 } else {
198 return new base::FundamentalValue(
199 chrome_browser_net::NETWORK_PREDICTION_NEVER);
203 base::Value* BrowserToExtensionPref(
204 const base::Value* browser_pref) override {
205 int int_value = chrome_browser_net::NETWORK_PREDICTION_DEFAULT;
206 const bool pref_found = browser_pref->GetAsInteger(&int_value);
207 DCHECK(pref_found) << "Preference not found.";
208 return new base::FundamentalValue(
209 int_value != chrome_browser_net::NETWORK_PREDICTION_NEVER);
213 class PrefMapping {
214 public:
215 static PrefMapping* GetInstance() {
216 return Singleton<PrefMapping>::get();
219 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
220 std::string* browser_pref,
221 APIPermission::ID* read_permission,
222 APIPermission::ID* write_permission) {
223 PrefMap::iterator it = mapping_.find(extension_pref);
224 if (it != mapping_.end()) {
225 *browser_pref = it->second.pref_name;
226 *read_permission = it->second.read_permission;
227 *write_permission = it->second.write_permission;
228 return true;
230 return false;
233 bool FindEventForBrowserPref(const std::string& browser_pref,
234 std::string* event_name,
235 APIPermission::ID* permission) {
236 PrefMap::iterator it = event_mapping_.find(browser_pref);
237 if (it != event_mapping_.end()) {
238 *event_name = it->second.pref_name;
239 *permission = it->second.read_permission;
240 return true;
242 return false;
245 PrefTransformerInterface* FindTransformerForBrowserPref(
246 const std::string& browser_pref) {
247 std::map<std::string, PrefTransformerInterface*>::iterator it =
248 transformers_.find(browser_pref);
249 if (it != transformers_.end())
250 return it->second;
251 else
252 return identity_transformer_.get();
255 private:
256 friend struct DefaultSingletonTraits<PrefMapping>;
258 PrefMapping() {
259 identity_transformer_.reset(new IdentityPrefTransformer());
260 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
261 mapping_[kPrefMapping[i].extension_pref] =
262 PrefMapData(kPrefMapping[i].browser_pref,
263 kPrefMapping[i].read_permission,
264 kPrefMapping[i].write_permission);
265 std::string event_name =
266 base::StringPrintf(kOnPrefChangeFormat,
267 kPrefMapping[i].extension_pref);
268 event_mapping_[kPrefMapping[i].browser_pref] =
269 PrefMapData(event_name,
270 kPrefMapping[i].read_permission,
271 kPrefMapping[i].write_permission);
273 DCHECK_EQ(arraysize(kPrefMapping), mapping_.size());
274 DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size());
275 RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer());
276 RegisterPrefTransformer(prefs::kBlockThirdPartyCookies,
277 new InvertBooleanTransformer());
278 RegisterPrefTransformer(prefs::kNetworkPredictionOptions,
279 new NetworkPredictionTransformer());
282 ~PrefMapping() {
283 STLDeleteContainerPairSecondPointers(transformers_.begin(),
284 transformers_.end());
287 void RegisterPrefTransformer(const std::string& browser_pref,
288 PrefTransformerInterface* transformer) {
289 DCHECK_EQ(0u, transformers_.count(browser_pref)) <<
290 "Trying to register pref transformer for " << browser_pref << " twice";
291 transformers_[browser_pref] = transformer;
294 struct PrefMapData {
295 PrefMapData()
296 : read_permission(APIPermission::kInvalid),
297 write_permission(APIPermission::kInvalid) {}
299 PrefMapData(const std::string& pref_name,
300 APIPermission::ID read,
301 APIPermission::ID write)
302 : pref_name(pref_name),
303 read_permission(read),
304 write_permission(write) {}
306 // Browser or extension preference to which the data maps.
307 std::string pref_name;
309 // Permission needed to read the preference.
310 APIPermission::ID read_permission;
312 // Permission needed to write the preference.
313 APIPermission::ID write_permission;
316 typedef std::map<std::string, PrefMapData> PrefMap;
318 // Mapping from extension pref keys to browser pref keys and permissions.
319 PrefMap mapping_;
321 // Mapping from browser pref keys to extension event names and permissions.
322 PrefMap event_mapping_;
324 // Mapping from browser pref keys to transformers.
325 std::map<std::string, PrefTransformerInterface*> transformers_;
327 scoped_ptr<PrefTransformerInterface> identity_transformer_;
329 DISALLOW_COPY_AND_ASSIGN(PrefMapping);
332 } // namespace
334 PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
335 : profile_(profile) {
336 registrar_.Init(profile_->GetPrefs());
337 incognito_registrar_.Init(profile_->GetOffTheRecordPrefs());
338 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
339 registrar_.Add(kPrefMapping[i].browser_pref,
340 base::Bind(&PreferenceEventRouter::OnPrefChanged,
341 base::Unretained(this),
342 registrar_.prefs()));
343 incognito_registrar_.Add(kPrefMapping[i].browser_pref,
344 base::Bind(&PreferenceEventRouter::OnPrefChanged,
345 base::Unretained(this),
346 incognito_registrar_.prefs()));
350 PreferenceEventRouter::~PreferenceEventRouter() { }
352 void PreferenceEventRouter::OnPrefChanged(PrefService* pref_service,
353 const std::string& browser_pref) {
354 bool incognito = (pref_service != profile_->GetPrefs());
356 std::string event_name;
357 APIPermission::ID permission = APIPermission::kInvalid;
358 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
359 browser_pref, &event_name, &permission);
360 DCHECK(rv);
362 base::ListValue args;
363 base::DictionaryValue* dict = new base::DictionaryValue();
364 args.Append(dict);
365 const PrefService::Preference* pref =
366 pref_service->FindPreference(browser_pref.c_str());
367 CHECK(pref);
368 PrefTransformerInterface* transformer =
369 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
370 base::Value* transformed_value =
371 transformer->BrowserToExtensionPref(pref->GetValue());
372 if (!transformed_value) {
373 LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
374 pref->name());
375 return;
378 dict->Set(keys::kValue, transformed_value);
379 if (incognito) {
380 ExtensionPrefs* ep = ExtensionPrefs::Get(profile_);
381 dict->SetBoolean(keys::kIncognitoSpecific,
382 ep->HasIncognitoPrefValue(browser_pref));
385 helpers::DispatchEventToExtensions(profile_,
386 event_name,
387 &args,
388 permission,
389 incognito,
390 browser_pref);
393 void PreferenceAPIBase::SetExtensionControlledPref(
394 const std::string& extension_id,
395 const std::string& pref_key,
396 ExtensionPrefsScope scope,
397 base::Value* value) {
398 #ifndef NDEBUG
399 const PrefService::Preference* pref =
400 extension_prefs()->pref_service()->FindPreference(pref_key.c_str());
401 DCHECK(pref) << "Extension controlled preference key " << pref_key
402 << " not registered.";
403 DCHECK_EQ(pref->GetType(), value->GetType())
404 << "Extension controlled preference " << pref_key << " has wrong type.";
405 #endif
407 std::string scope_string;
408 // ScopeToPrefName() returns false if the scope is not persisted.
409 if (pref_names::ScopeToPrefName(scope, &scope_string)) {
410 // Also store in persisted Preferences file to recover after a
411 // browser restart.
412 ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
413 extension_id,
414 scope_string);
415 base::DictionaryValue* preference = update.Get();
416 if (!preference)
417 preference = update.Create();
418 preference->SetWithoutPathExpansion(pref_key, value->DeepCopy());
420 extension_pref_value_map()->SetExtensionPref(
421 extension_id, pref_key, scope, value);
424 void PreferenceAPIBase::RemoveExtensionControlledPref(
425 const std::string& extension_id,
426 const std::string& pref_key,
427 ExtensionPrefsScope scope) {
428 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
429 << "Extension controlled preference key " << pref_key
430 << " not registered.";
432 std::string scope_string;
433 if (pref_names::ScopeToPrefName(scope, &scope_string)) {
434 ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
435 extension_id,
436 scope_string);
437 base::DictionaryValue* preference = update.Get();
438 if (preference)
439 preference->RemoveWithoutPathExpansion(pref_key, NULL);
441 extension_pref_value_map()->RemoveExtensionPref(
442 extension_id, pref_key, scope);
445 bool PreferenceAPIBase::CanExtensionControlPref(
446 const std::string& extension_id,
447 const std::string& pref_key,
448 bool incognito) {
449 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
450 << "Extension controlled preference key " << pref_key
451 << " not registered.";
453 return extension_pref_value_map()->CanExtensionControlPref(
454 extension_id, pref_key, incognito);
457 bool PreferenceAPIBase::DoesExtensionControlPref(
458 const std::string& extension_id,
459 const std::string& pref_key,
460 bool* from_incognito) {
461 DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
462 << "Extension controlled preference key " << pref_key
463 << " not registered.";
465 return extension_pref_value_map()->DoesExtensionControlPref(
466 extension_id, pref_key, from_incognito);
469 PreferenceAPI::PreferenceAPI(content::BrowserContext* context)
470 : profile_(Profile::FromBrowserContext(context)) {
471 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
472 std::string event_name;
473 APIPermission::ID permission = APIPermission::kInvalid;
474 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
475 kPrefMapping[i].browser_pref, &event_name, &permission);
476 DCHECK(rv);
477 EventRouter::Get(profile_)->RegisterObserver(this, event_name);
479 content_settings_store()->AddObserver(this);
482 PreferenceAPI::~PreferenceAPI() {
485 void PreferenceAPI::Shutdown() {
486 EventRouter::Get(profile_)->UnregisterObserver(this);
487 if (!extension_prefs()->extensions_disabled())
488 ClearIncognitoSessionOnlyContentSettings();
489 content_settings_store()->RemoveObserver(this);
492 static base::LazyInstance<BrowserContextKeyedAPIFactory<PreferenceAPI> >
493 g_factory = LAZY_INSTANCE_INITIALIZER;
495 // static
496 BrowserContextKeyedAPIFactory<PreferenceAPI>*
497 PreferenceAPI::GetFactoryInstance() {
498 return g_factory.Pointer();
501 // static
502 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) {
503 return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context);
506 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) {
507 preference_event_router_.reset(new PreferenceEventRouter(profile_));
508 EventRouter::Get(profile_)->UnregisterObserver(this);
511 void PreferenceAPI::OnContentSettingChanged(const std::string& extension_id,
512 bool incognito) {
513 if (incognito) {
514 extension_prefs()->UpdateExtensionPref(
515 extension_id,
516 pref_names::kPrefIncognitoContentSettings,
517 content_settings_store()->GetSettingsForExtension(
518 extension_id, kExtensionPrefsScopeIncognitoPersistent));
519 } else {
520 extension_prefs()->UpdateExtensionPref(
521 extension_id,
522 pref_names::kPrefContentSettings,
523 content_settings_store()->GetSettingsForExtension(
524 extension_id, kExtensionPrefsScopeRegular));
528 void PreferenceAPI::ClearIncognitoSessionOnlyContentSettings() {
529 ExtensionIdList extension_ids;
530 extension_prefs()->GetExtensions(&extension_ids);
531 for (ExtensionIdList::iterator extension_id = extension_ids.begin();
532 extension_id != extension_ids.end(); ++extension_id) {
533 content_settings_store()->ClearContentSettingsForExtension(
534 *extension_id, kExtensionPrefsScopeIncognitoSessionOnly);
538 ExtensionPrefs* PreferenceAPI::extension_prefs() {
539 return ExtensionPrefs::Get(profile_);
542 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
543 return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
546 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() {
547 return ContentSettingsService::Get(profile_)->content_settings_store();
550 template <>
551 void
552 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() {
553 DependsOn(ContentSettingsService::GetFactoryInstance());
554 DependsOn(ExtensionPrefsFactory::GetInstance());
555 DependsOn(ExtensionPrefValueMapFactory::GetInstance());
556 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
559 PreferenceFunction::~PreferenceFunction() { }
561 bool PreferenceFunction::ValidateBrowserPref(
562 const std::string& extension_pref_key,
563 PreferenceFunction::PermissionType permission_type,
564 std::string* browser_pref_key) {
565 APIPermission::ID read_permission = APIPermission::kInvalid;
566 APIPermission::ID write_permission = APIPermission::kInvalid;
567 EXTENSION_FUNCTION_VALIDATE(
568 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
569 extension_pref_key,
570 browser_pref_key,
571 &read_permission,
572 &write_permission));
573 APIPermission::ID permission = permission_type == PERMISSION_TYPE_READ
574 ? read_permission
575 : write_permission;
576 if (!extension()->permissions_data()->HasAPIPermission(permission)) {
577 error_ = ErrorUtils::FormatErrorMessage(
578 keys::kPermissionErrorMessage, extension_pref_key);
579 return false;
581 return true;
584 GetPreferenceFunction::~GetPreferenceFunction() { }
586 bool GetPreferenceFunction::RunSync() {
587 std::string pref_key;
588 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
589 base::DictionaryValue* details = NULL;
590 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
592 bool incognito = false;
593 if (details->HasKey(keys::kIncognitoKey))
594 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(keys::kIncognitoKey,
595 &incognito));
597 // Check incognito access.
598 if (incognito && !include_incognito()) {
599 error_ = keys::kIncognitoErrorMessage;
600 return false;
603 // Obtain pref.
604 std::string browser_pref;
605 if (!ValidateBrowserPref(
606 pref_key, PreferenceFunction::PERMISSION_TYPE_READ, &browser_pref)) {
607 return false;
609 PrefService* prefs = incognito ? GetProfile()->GetOffTheRecordPrefs()
610 : GetProfile()->GetPrefs();
611 const PrefService::Preference* pref =
612 prefs->FindPreference(browser_pref.c_str());
613 CHECK(pref);
615 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
617 // Retrieve level of control.
618 std::string level_of_control = helpers::GetLevelOfControl(
619 GetProfile(), extension_id(), browser_pref, incognito);
620 result->SetString(keys::kLevelOfControl, level_of_control);
622 // Retrieve pref value.
623 PrefTransformerInterface* transformer =
624 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
625 base::Value* transformed_value =
626 transformer->BrowserToExtensionPref(pref->GetValue());
627 if (!transformed_value) {
628 LOG(ERROR) <<
629 ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
630 pref->name());
631 return false;
633 result->Set(keys::kValue, transformed_value);
635 // Retrieve incognito status.
636 if (incognito) {
637 ExtensionPrefs* ep = ExtensionPrefs::Get(GetProfile());
638 result->SetBoolean(keys::kIncognitoSpecific,
639 ep->HasIncognitoPrefValue(browser_pref));
642 SetResult(result.release());
643 return true;
646 SetPreferenceFunction::~SetPreferenceFunction() { }
648 bool SetPreferenceFunction::RunSync() {
649 std::string pref_key;
650 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
651 base::DictionaryValue* details = NULL;
652 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
654 base::Value* value = NULL;
655 EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kValue, &value));
657 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
658 if (details->HasKey(keys::kScopeKey)) {
659 std::string scope_str;
660 EXTENSION_FUNCTION_VALIDATE(
661 details->GetString(keys::kScopeKey, &scope_str));
663 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
666 // Check incognito scope.
667 bool incognito =
668 (scope == kExtensionPrefsScopeIncognitoPersistent ||
669 scope == kExtensionPrefsScopeIncognitoSessionOnly);
670 if (incognito) {
671 // Regular profiles can't access incognito unless include_incognito is true.
672 if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
673 error_ = keys::kIncognitoErrorMessage;
674 return false;
676 } else {
677 // Incognito profiles can't access regular mode ever, they only exist in
678 // split mode.
679 if (GetProfile()->IsOffTheRecord()) {
680 error_ = "Can't modify regular settings from an incognito context.";
681 return false;
685 if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
686 !GetProfile()->HasOffTheRecordProfile()) {
687 error_ = keys::kIncognitoSessionOnlyErrorMessage;
688 return false;
691 // Obtain pref.
692 std::string browser_pref;
693 if (!ValidateBrowserPref(
694 pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
695 return false;
697 ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
698 const PrefService::Preference* pref =
699 prefs->pref_service()->FindPreference(browser_pref.c_str());
700 CHECK(pref);
702 // Validate new value.
703 PrefTransformerInterface* transformer =
704 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
705 std::string error;
706 bool bad_message = false;
707 scoped_ptr<base::Value> browser_pref_value(
708 transformer->ExtensionToBrowserPref(value, &error, &bad_message));
709 if (!browser_pref_value) {
710 error_ = error;
711 bad_message_ = bad_message;
712 return false;
714 EXTENSION_FUNCTION_VALIDATE(browser_pref_value->GetType() == pref->GetType());
716 // Validate also that the stored value can be converted back by the
717 // transformer.
718 scoped_ptr<base::Value> extensionPrefValue(
719 transformer->BrowserToExtensionPref(browser_pref_value.get()));
720 if (!extensionPrefValue) {
721 error_ = ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
722 pref->name());
723 bad_message_ = true;
724 return false;
727 PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
728 extension_id(), browser_pref, scope, browser_pref_value.release());
729 return true;
732 ClearPreferenceFunction::~ClearPreferenceFunction() { }
734 bool ClearPreferenceFunction::RunSync() {
735 std::string pref_key;
736 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
737 base::DictionaryValue* details = NULL;
738 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
740 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
741 if (details->HasKey(keys::kScopeKey)) {
742 std::string scope_str;
743 EXTENSION_FUNCTION_VALIDATE(
744 details->GetString(keys::kScopeKey, &scope_str));
746 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
749 // Check incognito scope.
750 bool incognito =
751 (scope == kExtensionPrefsScopeIncognitoPersistent ||
752 scope == kExtensionPrefsScopeIncognitoSessionOnly);
753 if (incognito) {
754 // We don't check incognito permissions here, as an extension should be
755 // always allowed to clear its own settings.
756 } else {
757 // Incognito profiles can't access regular mode ever, they only exist in
758 // split mode.
759 if (GetProfile()->IsOffTheRecord()) {
760 error_ = "Can't modify regular settings from an incognito context.";
761 return false;
765 std::string browser_pref;
766 if (!ValidateBrowserPref(
767 pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
768 return false;
771 PreferenceAPI::Get(GetProfile())
772 ->RemoveExtensionControlledPref(extension_id(), browser_pref, scope);
773 return true;
776 } // namespace extensions