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"
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
{
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 "
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
},
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
},
152 class IdentityPrefTransformer
: public PrefTransformerInterface
{
154 base::Value
* ExtensionToBrowserPref(const base::Value
* extension_pref
,
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
{
168 base::Value
* ExtensionToBrowserPref(const base::Value
* extension_pref
,
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
);
180 static base::Value
* InvertBooleanValue(const base::Value
* value
) {
181 bool bool_value
= false;
182 bool result
= value
->GetAsBoolean(&bool_value
);
184 return new base::FundamentalValue(!bool_value
);
188 class NetworkPredictionTransformer
: public PrefTransformerInterface
{
190 base::Value
* ExtensionToBrowserPref(const base::Value
* extension_pref
,
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.";
197 return new base::FundamentalValue(
198 chrome_browser_net::NETWORK_PREDICTION_DEFAULT
);
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
);
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
;
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
;
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())
254 return identity_transformer_
.get();
258 friend struct base::DefaultSingletonTraits
<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());
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
;
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.
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
);
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
);
365 base::ListValue args
;
366 base::DictionaryValue
* dict
= new base::DictionaryValue();
368 const PrefService::Preference
* pref
=
369 pref_service
->FindPreference(browser_pref
.c_str());
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
,
381 dict
->Set(keys::kValue
, transformed_value
);
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
397 events::HistogramValue histogram_value
=
398 events::TYPES_CHROME_SETTING_ON_CHANGE
;
399 helpers::DispatchEventToExtensions(profile_
, histogram_value
, event_name
,
400 &args
, permission
, incognito
,
404 void PreferenceAPIBase::SetExtensionControlledPref(
405 const std::string
& extension_id
,
406 const std::string
& pref_key
,
407 ExtensionPrefsScope scope
,
408 base::Value
* value
) {
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.";
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
423 ExtensionPrefs::ScopedDictionaryUpdate
update(extension_prefs(),
426 base::DictionaryValue
* preference
= update
.Get();
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(),
448 base::DictionaryValue
* preference
= update
.Get();
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
,
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
);
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
;
507 BrowserContextKeyedAPIFactory
<PreferenceAPI
>*
508 PreferenceAPI::GetFactoryInstance() {
509 return g_factory
.Pointer();
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
,
525 extension_prefs()->UpdateExtensionPref(
527 pref_names::kPrefIncognitoContentSettings
,
528 content_settings_store()->GetSettingsForExtension(
529 extension_id
, kExtensionPrefsScopeIncognitoPersistent
));
531 extension_prefs()->UpdateExtensionPref(
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();
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(
584 APIPermission::ID permission
= permission_type
== PERMISSION_TYPE_READ
587 if (!extension()->permissions_data()->HasAPIPermission(permission
)) {
588 error_
= ErrorUtils::FormatErrorMessage(
589 keys::kPermissionErrorMessage
, extension_pref_key
);
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
,
608 // Check incognito access.
609 if (incognito
&& !include_incognito()) {
610 error_
= keys::kIncognitoErrorMessage
;
615 std::string browser_pref
;
616 if (!ValidateBrowserPref(
617 pref_key
, PreferenceFunction::PERMISSION_TYPE_READ
, &browser_pref
)) {
620 PrefService
* prefs
= incognito
? GetProfile()->GetOffTheRecordPrefs()
621 : GetProfile()->GetPrefs();
622 const PrefService::Preference
* pref
=
623 prefs
->FindPreference(browser_pref
.c_str());
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
) {
640 ErrorUtils::FormatErrorMessage(kConversionErrorMessage
,
644 result
->Set(keys::kValue
, transformed_value
);
646 // Retrieve incognito status.
648 ExtensionPrefs
* ep
= ExtensionPrefs::Get(GetProfile());
649 result
->SetBoolean(keys::kIncognitoSpecific
,
650 ep
->HasIncognitoPrefValue(browser_pref
));
653 SetResult(result
.release());
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.
679 (scope
== kExtensionPrefsScopeIncognitoPersistent
||
680 scope
== kExtensionPrefsScopeIncognitoSessionOnly
);
682 // Regular profiles can't access incognito unless include_incognito is true.
683 if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
684 error_
= keys::kIncognitoErrorMessage
;
688 // Incognito profiles can't access regular mode ever, they only exist in
690 if (GetProfile()->IsOffTheRecord()) {
691 error_
= "Can't modify regular settings from an incognito context.";
696 if (scope
== kExtensionPrefsScopeIncognitoSessionOnly
&&
697 !GetProfile()->HasOffTheRecordProfile()) {
698 error_
= keys::kIncognitoSessionOnlyErrorMessage
;
703 std::string browser_pref
;
704 if (!ValidateBrowserPref(
705 pref_key
, PreferenceFunction::PERMISSION_TYPE_WRITE
, &browser_pref
)) {
708 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(GetProfile());
709 const PrefService::Preference
* pref
=
710 prefs
->pref_service()->FindPreference(browser_pref
.c_str());
713 // Validate new value.
714 PrefTransformerInterface
* transformer
=
715 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref
);
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
) {
722 bad_message_
= bad_message
;
725 EXTENSION_FUNCTION_VALIDATE(browser_pref_value
->GetType() == pref
->GetType());
727 // Validate also that the stored value can be converted back by the
729 scoped_ptr
<base::Value
> extensionPrefValue(
730 transformer
->BrowserToExtensionPref(browser_pref_value
.get()));
731 if (!extensionPrefValue
) {
732 error_
= ErrorUtils::FormatErrorMessage(kConversionErrorMessage
,
738 PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
739 extension_id(), browser_pref
, scope
, browser_pref_value
.release());
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.
762 (scope
== kExtensionPrefsScopeIncognitoPersistent
||
763 scope
== kExtensionPrefsScopeIncognitoSessionOnly
);
765 // We don't check incognito permissions here, as an extension should be
766 // always allowed to clear its own settings.
768 // Incognito profiles can't access regular mode ever, they only exist in
770 if (GetProfile()->IsOffTheRecord()) {
771 error_
= "Can't modify regular settings from an incognito context.";
776 std::string browser_pref
;
777 if (!ValidateBrowserPref(
778 pref_key
, PreferenceFunction::PERMISSION_TYPE_WRITE
, &browser_pref
)) {
782 PreferenceAPI::Get(GetProfile())
783 ->RemoveExtensionControlledPref(extension_id(), browser_pref
, scope
);
787 } // namespace extensions