Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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/extension_preference_api.h"
      6 
      7 #include <map>
      8 
      9 #include "base/json/json_writer.h"
     10 #include "base/memory/singleton.h"
     11 #include "base/stl_util-inl.h"
     12 #include "base/stringprintf.h"
     13 #include "base/values.h"
     14 #include "chrome/browser/extensions/extension_event_router.h"
     15 #include "chrome/browser/extensions/extension_prefs.h"
     16 #include "chrome/browser/extensions/extension_proxy_api.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/profiles/profile.h"
     19 #include "chrome/common/pref_names.h"
     20 #include "content/common/notification_type.h"
     21 #include "content/common/notification_service.h"
     22 
     23 namespace {
     24 
     25 struct PrefMappingEntry {
     26   const char* extension_pref;
     27   const char* browser_pref;
     28   const char* permission;
     29 };
     30 
     31 const char kNotControllable[] = "NotControllable";
     32 const char kControlledByOtherExtensions[] = "ControlledByOtherExtensions";
     33 const char kControllableByThisExtension[] = "ControllableByThisExtension";
     34 const char kControlledByThisExtension[] = "ControlledByThisExtension";
     35 
     36 const char kIncognito[] = "incognito";
     37 const char kIncognitoSpecific[] = "incognitoSpecific";
     38 const char kLevelOfControl[] = "levelOfControl";
     39 const char kValue[] = "value";
     40 
     41 const char kOnPrefChangeFormat[] = "experimental.preferences.%s.onChange";
     42 
     43 const char kIncognitoErrorMessage[] =
     44     "You do not have permission to access incognito preferences.";
     45 
     46 const char kPermissionErrorMessage[] =
     47     "You do not have permission to access the preference '%s'. "
     48     "Be sure to declare in your manifest what permissions you need.";
     49 
     50 PrefMappingEntry kPrefMapping[] = {
     51   { "blockThirdPartyCookies",
     52     prefs::kBlockThirdPartyCookies,
     53     Extension::kContentSettingsPermission
     54   },
     55   { "enableReferrers",
     56     prefs::kEnableReferrers,
     57     Extension::kContentSettingsPermission
     58   },
     59   { "enableHyperlinkAuditing",
     60     prefs::kEnableHyperlinkAuditing,
     61     Extension::kContentSettingsPermission
     62   },
     63   { "proxy",
     64     prefs::kProxy,
     65     Extension::kProxyPermission
     66   },
     67 };
     68 
     69 class IdentityPrefTransformer : public PrefTransformerInterface {
     70  public:
     71   IdentityPrefTransformer() { }
     72   virtual ~IdentityPrefTransformer() { }
     73 
     74   virtual Value* ExtensionToBrowserPref(const Value* extension_pref,
     75                                         std::string* error) {
     76     return extension_pref->DeepCopy();
     77   }
     78 
     79   virtual Value* BrowserToExtensionPref(const Value* browser_pref) {
     80     return browser_pref->DeepCopy();
     81   }
     82 };
     83 
     84 // Returns a string constant (defined in the API) indicating the level of
     85 // control this extension has over the specified preference.
     86 const char* GetLevelOfControl(
     87     Profile* profile,
     88     const std::string& extension_id,
     89     const std::string& browser_pref,
     90     bool incognito) {
     91   PrefService* prefs = incognito ? profile->GetOffTheRecordPrefs()
     92                                  : profile->GetPrefs();
     93   const PrefService::Preference* pref =
     94       prefs->FindPreference(browser_pref.c_str());
     95   CHECK(pref);
     96   ExtensionPrefs* ep = profile->GetExtensionService()->extension_prefs();
     97 
     98   if (!pref->IsExtensionModifiable())
     99     return kNotControllable;
    100 
    101   if (ep->DoesExtensionControlPref(extension_id, browser_pref, incognito))
    102     return kControlledByThisExtension;
    103 
    104   if (ep->CanExtensionControlPref(extension_id, browser_pref, incognito))
    105     return kControllableByThisExtension;
    106 
    107   return kControlledByOtherExtensions;
    108 }
    109 
    110 class PrefMapping {
    111  public:
    112   static PrefMapping* GetInstance() {
    113     return Singleton<PrefMapping>::get();
    114   }
    115 
    116   bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
    117                                        std::string* browser_pref,
    118                                        std::string* permission) {
    119     std::map<std::string, std::pair<std::string, std::string> >::iterator it =
    120         mapping_.find(extension_pref);
    121     if (it != mapping_.end()) {
    122       *browser_pref = it->second.first;
    123       *permission = it->second.second;
    124       return true;
    125     }
    126     return false;
    127   }
    128 
    129   bool FindEventForBrowserPref(const std::string& browser_pref,
    130                                std::string* event_name,
    131                                std::string* permission) {
    132     std::map<std::string, std::pair<std::string, std::string> >::iterator it =
    133         event_mapping_.find(browser_pref);
    134     if (it != event_mapping_.end()) {
    135       *event_name = it->second.first;
    136       *permission = it->second.second;
    137       return true;
    138     }
    139     return false;
    140   }
    141 
    142   PrefTransformerInterface* FindTransformerForBrowserPref(
    143       const std::string& browser_pref) {
    144     std::map<std::string, PrefTransformerInterface*>::iterator it =
    145         transformers_.find(browser_pref);
    146     if (it != transformers_.end())
    147       return it->second;
    148     else
    149       return identity_transformer_.get();
    150   }
    151 
    152  private:
    153   friend struct DefaultSingletonTraits<PrefMapping>;
    154 
    155   PrefMapping() {
    156     identity_transformer_.reset(new IdentityPrefTransformer());
    157     for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
    158       mapping_[kPrefMapping[i].extension_pref] =
    159           std::make_pair(kPrefMapping[i].browser_pref,
    160                          kPrefMapping[i].permission);
    161       std::string event_name =
    162           base::StringPrintf(kOnPrefChangeFormat,
    163                              kPrefMapping[i].extension_pref);
    164       event_mapping_[kPrefMapping[i].browser_pref] =
    165           std::make_pair(event_name, kPrefMapping[i].permission);
    166     }
    167     DCHECK_EQ(arraysize(kPrefMapping), mapping_.size());
    168     DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size());
    169     RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer());
    170   }
    171 
    172   ~PrefMapping() {
    173     STLDeleteContainerPairSecondPointers(transformers_.begin(),
    174                                          transformers_.end());
    175   }
    176 
    177   void RegisterPrefTransformer(const std::string& browser_pref,
    178                                PrefTransformerInterface* transformer) {
    179     DCHECK_EQ(0u, transformers_.count(browser_pref)) <<
    180         "Trying to register pref transformer for " << browser_pref << " twice";
    181     transformers_[browser_pref] = transformer;
    182   }
    183 
    184   // Mapping from extension pref keys to browser pref keys and permissions.
    185   std::map<std::string, std::pair<std::string, std::string> > mapping_;
    186 
    187   // Mapping from browser pref keys to extension event names and permissions.
    188   std::map<std::string, std::pair<std::string, std::string> > event_mapping_;
    189 
    190   // Mapping from browser pref keys to transformers.
    191   std::map<std::string, PrefTransformerInterface*> transformers_;
    192 
    193   scoped_ptr<PrefTransformerInterface> identity_transformer_;
    194 
    195   DISALLOW_COPY_AND_ASSIGN(PrefMapping);
    196 };
    197 
    198 }  // namespace
    199 
    200 ExtensionPreferenceEventRouter::ExtensionPreferenceEventRouter(
    201     Profile* profile) : profile_(profile) {
    202   registrar_.Init(profile_->GetPrefs());
    203   incognito_registrar_.Init(profile_->GetOffTheRecordPrefs());
    204   for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
    205     registrar_.Add(kPrefMapping[i].browser_pref, this);
    206     incognito_registrar_.Add(kPrefMapping[i].browser_pref, this);
    207   }
    208 }
    209 
    210 ExtensionPreferenceEventRouter::~ExtensionPreferenceEventRouter() { }
    211 
    212 void ExtensionPreferenceEventRouter::Observe(
    213     NotificationType type,
    214     const NotificationSource& source,
    215     const NotificationDetails& details) {
    216   if (type == NotificationType::PREF_CHANGED) {
    217     const std::string* pref_key =
    218         Details<const std::string>(details).ptr();
    219     OnPrefChanged(Source<PrefService>(source).ptr(), *pref_key);
    220   } else {
    221     NOTREACHED();
    222   }
    223 }
    224 
    225 void ExtensionPreferenceEventRouter::OnPrefChanged(
    226     PrefService* pref_service,
    227     const std::string& browser_pref) {
    228   bool incognito = (pref_service != profile_->GetPrefs());
    229 
    230   std::string event_name;
    231   std::string permission;
    232   bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
    233       browser_pref, &event_name, &permission);
    234   DCHECK(rv);
    235 
    236   ListValue args;
    237   DictionaryValue* dict = new DictionaryValue();
    238   args.Append(dict);
    239   const PrefService::Preference* pref =
    240       pref_service->FindPreference(browser_pref.c_str());
    241   CHECK(pref);
    242   ExtensionService* extension_service = profile_->GetExtensionService();
    243   PrefTransformerInterface* transformer =
    244       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
    245   dict->Set(kValue, transformer->BrowserToExtensionPref(pref->GetValue()));
    246   if (incognito) {
    247     ExtensionPrefs* ep = extension_service->extension_prefs();
    248     dict->Set(
    249         kIncognitoSpecific,
    250         Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref)));
    251   }
    252 
    253   ExtensionEventRouter* router = profile_->GetExtensionEventRouter();
    254   if (!router || !router->HasEventListener(event_name))
    255     return;
    256   const ExtensionList* extensions = extension_service->extensions();
    257   for (ExtensionList::const_iterator it = extensions->begin();
    258        it != extensions->end(); ++it) {
    259     std::string extension_id = (*it)->id();
    260     // TODO(bauerb): Only iterate over registered event listeners.
    261     if (router->ExtensionHasEventListener(extension_id, event_name) &&
    262         (*it)->HasApiPermission(permission) &&
    263         (!incognito || extension_service->CanCrossIncognito(*it))) {
    264       std::string level_of_control =
    265           GetLevelOfControl(profile_, extension_id, browser_pref, incognito);
    266       dict->Set(kLevelOfControl, Value::CreateStringValue(level_of_control));
    267 
    268       std::string json_args;
    269       base::JSONWriter::Write(&args, false, &json_args);
    270 
    271       DispatchEvent(extension_id, event_name, json_args);
    272     }
    273   }
    274 }
    275 
    276 void ExtensionPreferenceEventRouter::DispatchEvent(
    277     const std::string& extension_id,
    278     const std::string& event_name,
    279     const std::string& json_args) {
    280   profile_->GetExtensionEventRouter()->DispatchEventToExtension(
    281       extension_id, event_name, json_args, NULL, GURL());
    282 }
    283 
    284 // TODO(battre): Factor out common parts once this is stable.
    285 
    286 GetPreferenceFunction::~GetPreferenceFunction() { }
    287 
    288 bool GetPreferenceFunction::RunImpl() {
    289   std::string pref_key;
    290   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
    291   DictionaryValue* details = NULL;
    292   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
    293 
    294   bool incognito = false;
    295   if (details->HasKey(kIncognito))
    296     EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(kIncognito, &incognito));
    297 
    298   if (incognito && !include_incognito()) {
    299     error_ = kIncognitoErrorMessage;
    300     return false;
    301   }
    302 
    303   PrefService* prefs = incognito ? profile_->GetOffTheRecordPrefs()
    304                                  : profile_->GetPrefs();
    305   std::string browser_pref;
    306   std::string permission;
    307   EXTENSION_FUNCTION_VALIDATE(
    308       PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
    309           pref_key, &browser_pref, &permission));
    310   if (!GetExtension()->HasApiPermission(permission)) {
    311     error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str());
    312     return false;
    313   }
    314 
    315   const PrefService::Preference* pref =
    316       prefs->FindPreference(browser_pref.c_str());
    317   CHECK(pref);
    318   std::string level_of_control =
    319       GetLevelOfControl(profile_, extension_id(), browser_pref, incognito);
    320 
    321   scoped_ptr<DictionaryValue> result(new DictionaryValue);
    322   PrefTransformerInterface* transformer =
    323       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
    324   result->Set(kValue, transformer->BrowserToExtensionPref(pref->GetValue()));
    325   result->Set(kLevelOfControl, Value::CreateStringValue(level_of_control));
    326   if (incognito) {
    327     ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs();
    328     result->Set(
    329         kIncognitoSpecific,
    330         Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref)));
    331   }
    332   result_.reset(result.release());
    333   return true;
    334 }
    335 
    336 SetPreferenceFunction::~SetPreferenceFunction() { }
    337 
    338 bool SetPreferenceFunction::RunImpl() {
    339   std::string pref_key;
    340   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
    341   DictionaryValue* details = NULL;
    342   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
    343 
    344   Value* value = NULL;
    345   EXTENSION_FUNCTION_VALIDATE(details->Get(kValue, &value));
    346 
    347   bool incognito = false;
    348   if (details->HasKey(kIncognito))
    349     EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(kIncognito, &incognito));
    350 
    351   if (incognito && !include_incognito()) {
    352     error_ = kIncognitoErrorMessage;
    353     return false;
    354   }
    355 
    356   std::string browser_pref;
    357   std::string permission;
    358   EXTENSION_FUNCTION_VALIDATE(
    359       PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
    360           pref_key, &browser_pref, &permission));
    361   if (!GetExtension()->HasApiPermission(permission)) {
    362     error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str());
    363     return false;
    364   }
    365   ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs();
    366   const PrefService::Preference* pref =
    367       prefs->pref_service()->FindPreference(browser_pref.c_str());
    368   CHECK(pref);
    369   EXTENSION_FUNCTION_VALIDATE(value->GetType() == pref->GetType());
    370   PrefTransformerInterface* transformer =
    371       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
    372   std::string error;
    373   Value* browserPrefValue = transformer->ExtensionToBrowserPref(value, &error);
    374   if (!browserPrefValue) {
    375     error_ = error;
    376     return false;
    377   }
    378   prefs->SetExtensionControlledPref(extension_id(),
    379                                     browser_pref,
    380                                     incognito,
    381                                     browserPrefValue);
    382   return true;
    383 }
    384 
    385 ClearPreferenceFunction::~ClearPreferenceFunction() { }
    386 
    387 bool ClearPreferenceFunction::RunImpl() {
    388   std::string pref_key;
    389   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
    390   DictionaryValue* details = NULL;
    391   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
    392 
    393   bool incognito = false;
    394   if (details->HasKey(kIncognito))
    395     EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(kIncognito, &incognito));
    396 
    397   // We don't check incognito permissions here, as an extension should be always
    398   // allowed to clear its own settings.
    399 
    400   std::string browser_pref;
    401   std::string permission;
    402   EXTENSION_FUNCTION_VALIDATE(
    403       PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
    404           pref_key, &browser_pref, &permission));
    405   if (!GetExtension()->HasApiPermission(permission)) {
    406     error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str());
    407     return false;
    408   }
    409   ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs();
    410   prefs->RemoveExtensionControlledPref(extension_id(), browser_pref, incognito);
    411   return true;
    412 }
    413