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