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