• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/extensions/api/preference/preference_api.h"
6 
7 #include <map>
8 #include <utility>
9 
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/profiles/profile.h"
23 #include "chrome/common/pref_names.h"
24 #include "components/translate/core/common/translate_pref_names.h"
25 #include "content/public/browser/notification_details.h"
26 #include "content/public/browser/notification_source.h"
27 #include "extensions/browser/extension_pref_value_map.h"
28 #include "extensions/browser/extension_pref_value_map_factory.h"
29 #include "extensions/browser/extension_prefs.h"
30 #include "extensions/browser/extension_prefs_factory.h"
31 #include "extensions/browser/extension_system_provider.h"
32 #include "extensions/browser/extensions_browser_client.h"
33 #include "extensions/browser/pref_names.h"
34 #include "extensions/common/error_utils.h"
35 #include "extensions/common/permissions/api_permission.h"
36 #include "extensions/common/permissions/permissions_data.h"
37 
38 namespace keys = extensions::preference_api_constants;
39 namespace helpers = extensions::preference_helpers;
40 
41 using base::DictionaryValue;
42 
43 namespace extensions {
44 
45 namespace {
46 
47 struct PrefMappingEntry {
48   // Name of the preference referenced by the extension API JSON.
49   const char* extension_pref;
50 
51   // Name of the preference in the PrefStores.
52   const char* browser_pref;
53 
54   // Permission required to read and observe this preference.
55   // Use APIPermission::kInvalid for |read_permission| to express that the read
56   // permission should not be granted.
57   APIPermission::ID read_permission;
58 
59   // Permission required to write this preference.
60   // Use APIPermission::kInvalid for |write_permission| to express that the
61   // write permission should not be granted.
62   APIPermission::ID write_permission;
63 };
64 
65 const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange";
66 const char kConversionErrorMessage[] =
67     "Internal error: Stored value for preference '*' cannot be converted "
68     "properly.";
69 
70 PrefMappingEntry kPrefMapping[] = {
71     {"protectedContentEnabled", prefs::kEnableDRM, APIPermission::kPrivacy,
72      APIPermission::kPrivacy},
73     {"alternateErrorPagesEnabled", prefs::kAlternateErrorPagesEnabled,
74      APIPermission::kPrivacy, APIPermission::kPrivacy},
75     {"autofillEnabled", autofill::prefs::kAutofillEnabled,
76      APIPermission::kPrivacy, APIPermission::kPrivacy},
77     {"hyperlinkAuditingEnabled", prefs::kEnableHyperlinkAuditing,
78      APIPermission::kPrivacy, APIPermission::kPrivacy},
79     {"networkPredictionEnabled", prefs::kNetworkPredictionEnabled,
80      APIPermission::kPrivacy, APIPermission::kPrivacy},
81     {"proxy", prefs::kProxy, APIPermission::kProxy, APIPermission::kProxy},
82     {"referrersEnabled", prefs::kEnableReferrers, APIPermission::kPrivacy,
83      APIPermission::kPrivacy},
84     {"safeBrowsingEnabled", prefs::kSafeBrowsingEnabled,
85      APIPermission::kPrivacy, APIPermission::kPrivacy},
86     {"searchSuggestEnabled", prefs::kSearchSuggestEnabled,
87      APIPermission::kPrivacy, APIPermission::kPrivacy},
88     {"spellingServiceEnabled", prefs::kSpellCheckUseSpellingService,
89      APIPermission::kPrivacy, APIPermission::kPrivacy},
90     {"thirdPartyCookiesAllowed", prefs::kBlockThirdPartyCookies,
91      APIPermission::kPrivacy, APIPermission::kPrivacy},
92     {"translationServiceEnabled", prefs::kEnableTranslate,
93      APIPermission::kPrivacy, APIPermission::kPrivacy},
94 #if defined(OS_CHROMEOS)
95     {"autoclick", prefs::kAccessibilityAutoclickEnabled,
96      APIPermission::kAccessibilityFeaturesRead,
97      APIPermission::kAccessibilityFeaturesModify},
98     {"highContrast", prefs::kAccessibilityHighContrastEnabled,
99      APIPermission::kAccessibilityFeaturesRead,
100      APIPermission::kAccessibilityFeaturesModify},
101     {"largeCursor", prefs::kAccessibilityLargeCursorEnabled,
102      APIPermission::kAccessibilityFeaturesRead,
103      APIPermission::kAccessibilityFeaturesModify},
104     {"screenMagnifier", prefs::kAccessibilityScreenMagnifierEnabled,
105      APIPermission::kAccessibilityFeaturesRead,
106      APIPermission::kAccessibilityFeaturesModify},
107     {"spokenFeedback", prefs::kAccessibilitySpokenFeedbackEnabled,
108      APIPermission::kAccessibilityFeaturesRead,
109      APIPermission::kAccessibilityFeaturesModify},
110     {"stickyKeys", prefs::kAccessibilityStickyKeysEnabled,
111      APIPermission::kAccessibilityFeaturesRead,
112      APIPermission::kAccessibilityFeaturesModify},
113     {"virtualKeyboard", prefs::kAccessibilityVirtualKeyboardEnabled,
114      APIPermission::kAccessibilityFeaturesRead,
115      APIPermission::kAccessibilityFeaturesModify},
116 #endif
117 };
118 
119 class IdentityPrefTransformer : public PrefTransformerInterface {
120  public:
ExtensionToBrowserPref(const base::Value * extension_pref,std::string * error,bool * bad_message)121   virtual base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
122                                               std::string* error,
123                                               bool* bad_message) OVERRIDE {
124     return extension_pref->DeepCopy();
125   }
126 
BrowserToExtensionPref(const base::Value * browser_pref)127   virtual base::Value* BrowserToExtensionPref(
128       const base::Value* browser_pref) OVERRIDE {
129     return browser_pref->DeepCopy();
130   }
131 };
132 
133 class InvertBooleanTransformer : public PrefTransformerInterface {
134  public:
ExtensionToBrowserPref(const base::Value * extension_pref,std::string * error,bool * bad_message)135   virtual base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
136                                               std::string* error,
137                                               bool* bad_message) OVERRIDE {
138     return InvertBooleanValue(extension_pref);
139   }
140 
BrowserToExtensionPref(const base::Value * browser_pref)141   virtual base::Value* BrowserToExtensionPref(
142       const base::Value* browser_pref) OVERRIDE {
143     return InvertBooleanValue(browser_pref);
144   }
145 
146  private:
InvertBooleanValue(const base::Value * value)147   static base::Value* InvertBooleanValue(const base::Value* value) {
148     bool bool_value = false;
149     bool result = value->GetAsBoolean(&bool_value);
150     DCHECK(result);
151     return new base::FundamentalValue(!bool_value);
152   }
153 };
154 
155 class PrefMapping {
156  public:
GetInstance()157   static PrefMapping* GetInstance() {
158     return Singleton<PrefMapping>::get();
159   }
160 
FindBrowserPrefForExtensionPref(const std::string & extension_pref,std::string * browser_pref,APIPermission::ID * read_permission,APIPermission::ID * write_permission)161   bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
162                                        std::string* browser_pref,
163                                        APIPermission::ID* read_permission,
164                                        APIPermission::ID* write_permission) {
165     PrefMap::iterator it = mapping_.find(extension_pref);
166     if (it != mapping_.end()) {
167       *browser_pref = it->second.pref_name;
168       *read_permission = it->second.read_permission;
169       *write_permission = it->second.write_permission;
170       return true;
171     }
172     return false;
173   }
174 
FindEventForBrowserPref(const std::string & browser_pref,std::string * event_name,APIPermission::ID * permission)175   bool FindEventForBrowserPref(const std::string& browser_pref,
176                                std::string* event_name,
177                                APIPermission::ID* permission) {
178     PrefMap::iterator it = event_mapping_.find(browser_pref);
179     if (it != event_mapping_.end()) {
180       *event_name = it->second.pref_name;
181       *permission = it->second.read_permission;
182       return true;
183     }
184     return false;
185   }
186 
FindTransformerForBrowserPref(const std::string & browser_pref)187   PrefTransformerInterface* FindTransformerForBrowserPref(
188       const std::string& browser_pref) {
189     std::map<std::string, PrefTransformerInterface*>::iterator it =
190         transformers_.find(browser_pref);
191     if (it != transformers_.end())
192       return it->second;
193     else
194       return identity_transformer_.get();
195   }
196 
197  private:
198   friend struct DefaultSingletonTraits<PrefMapping>;
199 
PrefMapping()200   PrefMapping() {
201     identity_transformer_.reset(new IdentityPrefTransformer());
202     for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
203       mapping_[kPrefMapping[i].extension_pref] =
204           PrefMapData(kPrefMapping[i].browser_pref,
205                       kPrefMapping[i].read_permission,
206                       kPrefMapping[i].write_permission);
207       std::string event_name =
208           base::StringPrintf(kOnPrefChangeFormat,
209                              kPrefMapping[i].extension_pref);
210       event_mapping_[kPrefMapping[i].browser_pref] =
211           PrefMapData(event_name,
212                       kPrefMapping[i].read_permission,
213                       kPrefMapping[i].write_permission);
214     }
215     DCHECK_EQ(arraysize(kPrefMapping), mapping_.size());
216     DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size());
217     RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer());
218     RegisterPrefTransformer(prefs::kBlockThirdPartyCookies,
219                             new InvertBooleanTransformer());
220   }
221 
~PrefMapping()222   ~PrefMapping() {
223     STLDeleteContainerPairSecondPointers(transformers_.begin(),
224                                          transformers_.end());
225   }
226 
RegisterPrefTransformer(const std::string & browser_pref,PrefTransformerInterface * transformer)227   void RegisterPrefTransformer(const std::string& browser_pref,
228                                PrefTransformerInterface* transformer) {
229     DCHECK_EQ(0u, transformers_.count(browser_pref)) <<
230         "Trying to register pref transformer for " << browser_pref << " twice";
231     transformers_[browser_pref] = transformer;
232   }
233 
234   struct PrefMapData {
PrefMapDataextensions::__anon520ac3f10111::PrefMapping::PrefMapData235     PrefMapData()
236         : read_permission(APIPermission::kInvalid),
237           write_permission(APIPermission::kInvalid) {}
238 
PrefMapDataextensions::__anon520ac3f10111::PrefMapping::PrefMapData239     PrefMapData(const std::string& pref_name,
240                 APIPermission::ID read,
241                 APIPermission::ID write)
242         : pref_name(pref_name),
243           read_permission(read),
244           write_permission(write) {}
245 
246     // Browser or extension preference to which the data maps.
247     std::string pref_name;
248 
249     // Permission needed to read the preference.
250     APIPermission::ID read_permission;
251 
252     // Permission needed to write the preference.
253     APIPermission::ID write_permission;
254   };
255 
256   typedef std::map<std::string, PrefMapData> PrefMap;
257 
258   // Mapping from extension pref keys to browser pref keys and permissions.
259   PrefMap mapping_;
260 
261   // Mapping from browser pref keys to extension event names and permissions.
262   PrefMap event_mapping_;
263 
264   // Mapping from browser pref keys to transformers.
265   std::map<std::string, PrefTransformerInterface*> transformers_;
266 
267   scoped_ptr<PrefTransformerInterface> identity_transformer_;
268 
269   DISALLOW_COPY_AND_ASSIGN(PrefMapping);
270 };
271 
272 }  // namespace
273 
PreferenceEventRouter(Profile * profile)274 PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
275     : profile_(profile) {
276   registrar_.Init(profile_->GetPrefs());
277   incognito_registrar_.Init(profile_->GetOffTheRecordPrefs());
278   for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
279     registrar_.Add(kPrefMapping[i].browser_pref,
280                    base::Bind(&PreferenceEventRouter::OnPrefChanged,
281                               base::Unretained(this),
282                               registrar_.prefs()));
283     incognito_registrar_.Add(kPrefMapping[i].browser_pref,
284                              base::Bind(&PreferenceEventRouter::OnPrefChanged,
285                                         base::Unretained(this),
286                                         incognito_registrar_.prefs()));
287   }
288 }
289 
~PreferenceEventRouter()290 PreferenceEventRouter::~PreferenceEventRouter() { }
291 
OnPrefChanged(PrefService * pref_service,const std::string & browser_pref)292 void PreferenceEventRouter::OnPrefChanged(PrefService* pref_service,
293                                           const std::string& browser_pref) {
294   bool incognito = (pref_service != profile_->GetPrefs());
295 
296   std::string event_name;
297   APIPermission::ID permission = APIPermission::kInvalid;
298   bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
299       browser_pref, &event_name, &permission);
300   DCHECK(rv);
301 
302   base::ListValue args;
303   base::DictionaryValue* dict = new base::DictionaryValue();
304   args.Append(dict);
305   const PrefService::Preference* pref =
306       pref_service->FindPreference(browser_pref.c_str());
307   CHECK(pref);
308   PrefTransformerInterface* transformer =
309       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
310   base::Value* transformed_value =
311       transformer->BrowserToExtensionPref(pref->GetValue());
312   if (!transformed_value) {
313     LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
314                                                  pref->name());
315     return;
316   }
317 
318   dict->Set(keys::kValue, transformed_value);
319   if (incognito) {
320     ExtensionPrefs* ep = ExtensionPrefs::Get(profile_);
321     dict->SetBoolean(keys::kIncognitoSpecific,
322                      ep->HasIncognitoPrefValue(browser_pref));
323   }
324 
325   helpers::DispatchEventToExtensions(profile_,
326                                      event_name,
327                                      &args,
328                                      permission,
329                                      incognito,
330                                      browser_pref);
331 }
332 
SetExtensionControlledPref(const std::string & extension_id,const std::string & pref_key,ExtensionPrefsScope scope,base::Value * value)333 void PreferenceAPIBase::SetExtensionControlledPref(
334     const std::string& extension_id,
335     const std::string& pref_key,
336     ExtensionPrefsScope scope,
337     base::Value* value) {
338 #ifndef NDEBUG
339   const PrefService::Preference* pref =
340       extension_prefs()->pref_service()->FindPreference(pref_key.c_str());
341   DCHECK(pref) << "Extension controlled preference key " << pref_key
342                << " not registered.";
343   DCHECK_EQ(pref->GetType(), value->GetType())
344       << "Extension controlled preference " << pref_key << " has wrong type.";
345 #endif
346 
347   std::string scope_string;
348   // ScopeToPrefName() returns false if the scope is not persisted.
349   if (pref_names::ScopeToPrefName(scope, &scope_string)) {
350     // Also store in persisted Preferences file to recover after a
351     // browser restart.
352     ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
353                                                   extension_id,
354                                                   scope_string);
355     base::DictionaryValue* preference = update.Get();
356     if (!preference)
357       preference = update.Create();
358     preference->SetWithoutPathExpansion(pref_key, value->DeepCopy());
359   }
360   extension_pref_value_map()->SetExtensionPref(
361       extension_id, pref_key, scope, value);
362 }
363 
RemoveExtensionControlledPref(const std::string & extension_id,const std::string & pref_key,ExtensionPrefsScope scope)364 void PreferenceAPIBase::RemoveExtensionControlledPref(
365     const std::string& extension_id,
366     const std::string& pref_key,
367     ExtensionPrefsScope scope) {
368   DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
369       << "Extension controlled preference key " << pref_key
370       << " not registered.";
371 
372   std::string scope_string;
373   if (pref_names::ScopeToPrefName(scope, &scope_string)) {
374     ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
375                                                   extension_id,
376                                                   scope_string);
377     base::DictionaryValue* preference = update.Get();
378     if (preference)
379       preference->RemoveWithoutPathExpansion(pref_key, NULL);
380   }
381   extension_pref_value_map()->RemoveExtensionPref(
382       extension_id, pref_key, scope);
383 }
384 
CanExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool incognito)385 bool PreferenceAPIBase::CanExtensionControlPref(
386      const std::string& extension_id,
387      const std::string& pref_key,
388      bool incognito) {
389   DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
390       << "Extension controlled preference key " << pref_key
391       << " not registered.";
392 
393   return extension_pref_value_map()->CanExtensionControlPref(
394        extension_id, pref_key, incognito);
395 }
396 
DoesExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool * from_incognito)397 bool PreferenceAPIBase::DoesExtensionControlPref(
398     const std::string& extension_id,
399     const std::string& pref_key,
400     bool* from_incognito) {
401   DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
402       << "Extension controlled preference key " << pref_key
403       << " not registered.";
404 
405   return extension_pref_value_map()->DoesExtensionControlPref(
406       extension_id, pref_key, from_incognito);
407 }
408 
PreferenceAPI(content::BrowserContext * context)409 PreferenceAPI::PreferenceAPI(content::BrowserContext* context)
410     : profile_(Profile::FromBrowserContext(context)) {
411   for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
412     std::string event_name;
413     APIPermission::ID permission = APIPermission::kInvalid;
414     bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
415         kPrefMapping[i].browser_pref, &event_name, &permission);
416     DCHECK(rv);
417     EventRouter::Get(profile_)->RegisterObserver(this, event_name);
418   }
419   content_settings_store()->AddObserver(this);
420 }
421 
~PreferenceAPI()422 PreferenceAPI::~PreferenceAPI() {
423 }
424 
Shutdown()425 void PreferenceAPI::Shutdown() {
426   EventRouter::Get(profile_)->UnregisterObserver(this);
427   if (!extension_prefs()->extensions_disabled())
428     ClearIncognitoSessionOnlyContentSettings();
429   content_settings_store()->RemoveObserver(this);
430 }
431 
432 static base::LazyInstance<BrowserContextKeyedAPIFactory<PreferenceAPI> >
433     g_factory = LAZY_INSTANCE_INITIALIZER;
434 
435 // static
436 BrowserContextKeyedAPIFactory<PreferenceAPI>*
GetFactoryInstance()437 PreferenceAPI::GetFactoryInstance() {
438   return g_factory.Pointer();
439 }
440 
441 // static
Get(content::BrowserContext * context)442 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) {
443   return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context);
444 }
445 
OnListenerAdded(const EventListenerInfo & details)446 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) {
447   preference_event_router_.reset(new PreferenceEventRouter(profile_));
448   EventRouter::Get(profile_)->UnregisterObserver(this);
449 }
450 
OnContentSettingChanged(const std::string & extension_id,bool incognito)451 void PreferenceAPI::OnContentSettingChanged(const std::string& extension_id,
452                                             bool incognito) {
453   if (incognito) {
454     extension_prefs()->UpdateExtensionPref(
455         extension_id,
456         pref_names::kPrefIncognitoContentSettings,
457         content_settings_store()->GetSettingsForExtension(
458             extension_id, kExtensionPrefsScopeIncognitoPersistent));
459   } else {
460     extension_prefs()->UpdateExtensionPref(
461         extension_id,
462         pref_names::kPrefContentSettings,
463         content_settings_store()->GetSettingsForExtension(
464             extension_id, kExtensionPrefsScopeRegular));
465   }
466 }
467 
ClearIncognitoSessionOnlyContentSettings()468 void PreferenceAPI::ClearIncognitoSessionOnlyContentSettings() {
469   ExtensionIdList extension_ids;
470   extension_prefs()->GetExtensions(&extension_ids);
471   for (ExtensionIdList::iterator extension_id = extension_ids.begin();
472        extension_id != extension_ids.end(); ++extension_id) {
473     content_settings_store()->ClearContentSettingsForExtension(
474         *extension_id, kExtensionPrefsScopeIncognitoSessionOnly);
475   }
476 }
477 
extension_prefs()478 ExtensionPrefs* PreferenceAPI::extension_prefs() {
479   return ExtensionPrefs::Get(profile_);
480 }
481 
extension_pref_value_map()482 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
483   return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
484 }
485 
content_settings_store()486 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() {
487   return ContentSettingsService::Get(profile_)->content_settings_store();
488 }
489 
490 template <>
491 void
DeclareFactoryDependencies()492 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() {
493   DependsOn(ContentSettingsService::GetFactoryInstance());
494   DependsOn(ExtensionPrefsFactory::GetInstance());
495   DependsOn(ExtensionPrefValueMapFactory::GetInstance());
496   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
497 }
498 
~PreferenceFunction()499 PreferenceFunction::~PreferenceFunction() { }
500 
ValidateBrowserPref(const std::string & extension_pref_key,PreferenceFunction::PermissionType permission_type,std::string * browser_pref_key)501 bool PreferenceFunction::ValidateBrowserPref(
502     const std::string& extension_pref_key,
503     PreferenceFunction::PermissionType permission_type,
504     std::string* browser_pref_key) {
505   APIPermission::ID read_permission = APIPermission::kInvalid;
506   APIPermission::ID write_permission = APIPermission::kInvalid;
507   EXTENSION_FUNCTION_VALIDATE(
508       PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
509           extension_pref_key,
510           browser_pref_key,
511           &read_permission,
512           &write_permission));
513   APIPermission::ID permission = permission_type == PERMISSION_TYPE_READ
514                                      ? read_permission
515                                      : write_permission;
516   if (!GetExtension()->permissions_data()->HasAPIPermission(permission)) {
517     error_ = ErrorUtils::FormatErrorMessage(
518         keys::kPermissionErrorMessage, extension_pref_key);
519     return false;
520   }
521   return true;
522 }
523 
~GetPreferenceFunction()524 GetPreferenceFunction::~GetPreferenceFunction() { }
525 
RunSync()526 bool GetPreferenceFunction::RunSync() {
527   std::string pref_key;
528   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
529   base::DictionaryValue* details = NULL;
530   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
531 
532   bool incognito = false;
533   if (details->HasKey(keys::kIncognitoKey))
534     EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(keys::kIncognitoKey,
535                                                     &incognito));
536 
537   // Check incognito access.
538   if (incognito && !include_incognito()) {
539     error_ = keys::kIncognitoErrorMessage;
540     return false;
541   }
542 
543   // Obtain pref.
544   std::string browser_pref;
545   if (!ValidateBrowserPref(
546           pref_key, PreferenceFunction::PERMISSION_TYPE_READ, &browser_pref)) {
547     return false;
548   }
549   PrefService* prefs = incognito ? GetProfile()->GetOffTheRecordPrefs()
550                                  : GetProfile()->GetPrefs();
551   const PrefService::Preference* pref =
552       prefs->FindPreference(browser_pref.c_str());
553   CHECK(pref);
554 
555   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
556 
557   // Retrieve level of control.
558   std::string level_of_control = helpers::GetLevelOfControl(
559       GetProfile(), extension_id(), browser_pref, incognito);
560   result->SetString(keys::kLevelOfControl, level_of_control);
561 
562   // Retrieve pref value.
563   PrefTransformerInterface* transformer =
564       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
565   base::Value* transformed_value =
566       transformer->BrowserToExtensionPref(pref->GetValue());
567   if (!transformed_value) {
568     LOG(ERROR) <<
569         ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
570                                                 pref->name());
571     return false;
572   }
573   result->Set(keys::kValue, transformed_value);
574 
575   // Retrieve incognito status.
576   if (incognito) {
577     ExtensionPrefs* ep = ExtensionPrefs::Get(GetProfile());
578     result->SetBoolean(keys::kIncognitoSpecific,
579                        ep->HasIncognitoPrefValue(browser_pref));
580   }
581 
582   SetResult(result.release());
583   return true;
584 }
585 
~SetPreferenceFunction()586 SetPreferenceFunction::~SetPreferenceFunction() { }
587 
RunSync()588 bool SetPreferenceFunction::RunSync() {
589   std::string pref_key;
590   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
591   base::DictionaryValue* details = NULL;
592   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
593 
594   base::Value* value = NULL;
595   EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kValue, &value));
596 
597   ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
598   if (details->HasKey(keys::kScopeKey)) {
599     std::string scope_str;
600     EXTENSION_FUNCTION_VALIDATE(
601         details->GetString(keys::kScopeKey, &scope_str));
602 
603     EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
604   }
605 
606   // Check incognito scope.
607   bool incognito =
608       (scope == kExtensionPrefsScopeIncognitoPersistent ||
609        scope == kExtensionPrefsScopeIncognitoSessionOnly);
610   if (incognito) {
611     // Regular profiles can't access incognito unless include_incognito is true.
612     if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
613       error_ = keys::kIncognitoErrorMessage;
614       return false;
615     }
616   } else {
617     // Incognito profiles can't access regular mode ever, they only exist in
618     // split mode.
619     if (GetProfile()->IsOffTheRecord()) {
620       error_ = "Can't modify regular settings from an incognito context.";
621       return false;
622     }
623   }
624 
625   if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
626       !GetProfile()->HasOffTheRecordProfile()) {
627     error_ = keys::kIncognitoSessionOnlyErrorMessage;
628     return false;
629   }
630 
631   // Obtain pref.
632   std::string browser_pref;
633   if (!ValidateBrowserPref(
634           pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
635     return false;
636   }
637   ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
638   const PrefService::Preference* pref =
639       prefs->pref_service()->FindPreference(browser_pref.c_str());
640   CHECK(pref);
641 
642   // Validate new value.
643   EXTENSION_FUNCTION_VALIDATE(value->GetType() == pref->GetType());
644   PrefTransformerInterface* transformer =
645       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
646   std::string error;
647   bool bad_message = false;
648   scoped_ptr<base::Value> browser_pref_value(
649       transformer->ExtensionToBrowserPref(value, &error, &bad_message));
650   if (!browser_pref_value) {
651     error_ = error;
652     bad_message_ = bad_message;
653     return false;
654   }
655 
656   // Validate also that the stored value can be converted back by the
657   // transformer.
658   scoped_ptr<base::Value> extensionPrefValue(
659       transformer->BrowserToExtensionPref(browser_pref_value.get()));
660   if (!extensionPrefValue) {
661     error_ =  ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
662                                                       pref->name());
663     bad_message_ = true;
664     return false;
665   }
666 
667   PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
668       extension_id(), browser_pref, scope, browser_pref_value.release());
669   return true;
670 }
671 
~ClearPreferenceFunction()672 ClearPreferenceFunction::~ClearPreferenceFunction() { }
673 
RunSync()674 bool ClearPreferenceFunction::RunSync() {
675   std::string pref_key;
676   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
677   base::DictionaryValue* details = NULL;
678   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
679 
680   ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
681   if (details->HasKey(keys::kScopeKey)) {
682     std::string scope_str;
683     EXTENSION_FUNCTION_VALIDATE(
684         details->GetString(keys::kScopeKey, &scope_str));
685 
686     EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
687   }
688 
689   // Check incognito scope.
690   bool incognito =
691       (scope == kExtensionPrefsScopeIncognitoPersistent ||
692        scope == kExtensionPrefsScopeIncognitoSessionOnly);
693   if (incognito) {
694     // We don't check incognito permissions here, as an extension should be
695     // always allowed to clear its own settings.
696   } else {
697     // Incognito profiles can't access regular mode ever, they only exist in
698     // split mode.
699     if (GetProfile()->IsOffTheRecord()) {
700       error_ = "Can't modify regular settings from an incognito context.";
701       return false;
702     }
703   }
704 
705   std::string browser_pref;
706   if (!ValidateBrowserPref(
707           pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
708     return false;
709   }
710 
711   PreferenceAPI::Get(GetProfile())
712       ->RemoveExtensionControlledPref(extension_id(), browser_pref, scope);
713   return true;
714 }
715 
716 }  // namespace extensions
717