• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
IdentityPrefTransformer()71   IdentityPrefTransformer() { }
~IdentityPrefTransformer()72   virtual ~IdentityPrefTransformer() { }
73 
ExtensionToBrowserPref(const Value * extension_pref,std::string * error)74   virtual Value* ExtensionToBrowserPref(const Value* extension_pref,
75                                         std::string* error) {
76     return extension_pref->DeepCopy();
77   }
78 
BrowserToExtensionPref(const Value * browser_pref)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.
GetLevelOfControl(Profile * profile,const std::string & extension_id,const std::string & browser_pref,bool incognito)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:
GetInstance()112   static PrefMapping* GetInstance() {
113     return Singleton<PrefMapping>::get();
114   }
115 
FindBrowserPrefForExtensionPref(const std::string & extension_pref,std::string * browser_pref,std::string * permission)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 
FindEventForBrowserPref(const std::string & browser_pref,std::string * event_name,std::string * permission)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 
FindTransformerForBrowserPref(const std::string & browser_pref)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 
PrefMapping()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 
~PrefMapping()172   ~PrefMapping() {
173     STLDeleteContainerPairSecondPointers(transformers_.begin(),
174                                          transformers_.end());
175   }
176 
RegisterPrefTransformer(const std::string & browser_pref,PrefTransformerInterface * transformer)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 
ExtensionPreferenceEventRouter(Profile * profile)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 
~ExtensionPreferenceEventRouter()210 ExtensionPreferenceEventRouter::~ExtensionPreferenceEventRouter() { }
211 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
OnPrefChanged(PrefService * pref_service,const std::string & browser_pref)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 
DispatchEvent(const std::string & extension_id,const std::string & event_name,const std::string & json_args)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 
~GetPreferenceFunction()286 GetPreferenceFunction::~GetPreferenceFunction() { }
287 
RunImpl()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 
~SetPreferenceFunction()336 SetPreferenceFunction::~SetPreferenceFunction() { }
337 
RunImpl()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 
~ClearPreferenceFunction()385 ClearPreferenceFunction::~ClearPreferenceFunction() { }
386 
RunImpl()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