• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/extensions/api/preference/preference_api.h"
6 
7 #include <map>
8 #include <utility>
9 
10 #include "base/lazy_instance.h"
11 #include "base/memory/singleton.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/stl_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/extensions/api/content_settings/content_settings_service.h"
18 #include "chrome/browser/extensions/api/preference/preference_api_constants.h"
19 #include "chrome/browser/extensions/api/preference/preference_helpers.h"
20 #include "chrome/browser/extensions/api/proxy/proxy_api.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/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:
ExtensionToBrowserPref(const base::Value * extension_pref,std::string * error,bool * bad_message)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 
BrowserToExtensionPref(const base::Value * browser_pref)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:
ExtensionToBrowserPref(const base::Value * extension_pref,std::string * error,bool * bad_message)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 
BrowserToExtensionPref(const base::Value * browser_pref)145   virtual base::Value* BrowserToExtensionPref(
146       const base::Value* browser_pref) OVERRIDE {
147     return InvertBooleanValue(browser_pref);
148   }
149 
150  private:
InvertBooleanValue(const base::Value * value)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:
ExtensionToBrowserPref(const base::Value * extension_pref,std::string * error,bool * bad_message)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 
BrowserToExtensionPref(const base::Value * browser_pref)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:
GetInstance()188   static PrefMapping* GetInstance() {
189     return Singleton<PrefMapping>::get();
190   }
191 
FindBrowserPrefForExtensionPref(const std::string & extension_pref,std::string * browser_pref,APIPermission::ID * read_permission,APIPermission::ID * write_permission)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 
FindEventForBrowserPref(const std::string & browser_pref,std::string * event_name,APIPermission::ID * permission)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 
FindTransformerForBrowserPref(const std::string & browser_pref)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 
PrefMapping()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 
~PrefMapping()255   ~PrefMapping() {
256     STLDeleteContainerPairSecondPointers(transformers_.begin(),
257                                          transformers_.end());
258   }
259 
RegisterPrefTransformer(const std::string & browser_pref,PrefTransformerInterface * transformer)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 {
PrefMapDataextensions::__anon4dc180040111::PrefMapping::PrefMapData268     PrefMapData()
269         : read_permission(APIPermission::kInvalid),
270           write_permission(APIPermission::kInvalid) {}
271 
PrefMapDataextensions::__anon4dc180040111::PrefMapping::PrefMapData272     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 
PreferenceEventRouter(Profile * profile)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 
~PreferenceEventRouter()323 PreferenceEventRouter::~PreferenceEventRouter() { }
324 
OnPrefChanged(PrefService * pref_service,const std::string & browser_pref)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 
SetExtensionControlledPref(const std::string & extension_id,const std::string & pref_key,ExtensionPrefsScope scope,base::Value * value)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 
RemoveExtensionControlledPref(const std::string & extension_id,const std::string & pref_key,ExtensionPrefsScope scope)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 
CanExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool incognito)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 
DoesExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool * from_incognito)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 
PreferenceAPI(content::BrowserContext * context)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 
~PreferenceAPI()455 PreferenceAPI::~PreferenceAPI() {
456 }
457 
Shutdown()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>*
GetFactoryInstance()470 PreferenceAPI::GetFactoryInstance() {
471   return g_factory.Pointer();
472 }
473 
474 // static
Get(content::BrowserContext * context)475 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) {
476   return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context);
477 }
478 
OnListenerAdded(const EventListenerInfo & details)479 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) {
480   preference_event_router_.reset(new PreferenceEventRouter(profile_));
481   EventRouter::Get(profile_)->UnregisterObserver(this);
482 }
483 
OnContentSettingChanged(const std::string & extension_id,bool incognito)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 
ClearIncognitoSessionOnlyContentSettings()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 
extension_prefs()511 ExtensionPrefs* PreferenceAPI::extension_prefs() {
512   return ExtensionPrefs::Get(profile_);
513 }
514 
extension_pref_value_map()515 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
516   return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
517 }
518 
content_settings_store()519 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() {
520   return ContentSettingsService::Get(profile_)->content_settings_store();
521 }
522 
523 template <>
524 void
DeclareFactoryDependencies()525 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() {
526   DependsOn(ContentSettingsService::GetFactoryInstance());
527   DependsOn(ExtensionPrefsFactory::GetInstance());
528   DependsOn(ExtensionPrefValueMapFactory::GetInstance());
529   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
530 }
531 
~PreferenceFunction()532 PreferenceFunction::~PreferenceFunction() { }
533 
ValidateBrowserPref(const std::string & extension_pref_key,PreferenceFunction::PermissionType permission_type,std::string * browser_pref_key)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 
~GetPreferenceFunction()557 GetPreferenceFunction::~GetPreferenceFunction() { }
558 
RunSync()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 
~SetPreferenceFunction()619 SetPreferenceFunction::~SetPreferenceFunction() { }
620 
RunSync()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 
~ClearPreferenceFunction()705 ClearPreferenceFunction::~ClearPreferenceFunction() { }
706 
RunSync()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