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
39namespace keys = extensions::preference_api_constants;
40namespace helpers = extensions::preference_helpers;
41
42using base::DictionaryValue;
43
44namespace extensions {
45
46namespace {
47
48struct 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
66const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange";
67const char kConversionErrorMessage[] =
68    "Internal error: Stored value for preference '*' cannot be converted "
69    "properly.";
70
71PrefMappingEntry 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
123class 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
137class 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
159class 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
186class 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
307PreferenceEventRouter::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
323PreferenceEventRouter::~PreferenceEventRouter() { }
324
325void 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
366void 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
397void 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
418bool 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
430bool 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
442PreferenceAPI::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
455PreferenceAPI::~PreferenceAPI() {
456}
457
458void PreferenceAPI::Shutdown() {
459  EventRouter::Get(profile_)->UnregisterObserver(this);
460  if (!extension_prefs()->extensions_disabled())
461    ClearIncognitoSessionOnlyContentSettings();
462  content_settings_store()->RemoveObserver(this);
463}
464
465static base::LazyInstance<BrowserContextKeyedAPIFactory<PreferenceAPI> >
466    g_factory = LAZY_INSTANCE_INITIALIZER;
467
468// static
469BrowserContextKeyedAPIFactory<PreferenceAPI>*
470PreferenceAPI::GetFactoryInstance() {
471  return g_factory.Pointer();
472}
473
474// static
475PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) {
476  return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context);
477}
478
479void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) {
480  preference_event_router_.reset(new PreferenceEventRouter(profile_));
481  EventRouter::Get(profile_)->UnregisterObserver(this);
482}
483
484void 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
501void 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
511ExtensionPrefs* PreferenceAPI::extension_prefs() {
512  return ExtensionPrefs::Get(profile_);
513}
514
515ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
516  return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
517}
518
519scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() {
520  return ContentSettingsService::Get(profile_)->content_settings_store();
521}
522
523template <>
524void
525BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() {
526  DependsOn(ContentSettingsService::GetFactoryInstance());
527  DependsOn(ExtensionPrefsFactory::GetInstance());
528  DependsOn(ExtensionPrefValueMapFactory::GetInstance());
529  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
530}
531
532PreferenceFunction::~PreferenceFunction() { }
533
534bool 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
557GetPreferenceFunction::~GetPreferenceFunction() { }
558
559bool 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
619SetPreferenceFunction::~SetPreferenceFunction() { }
620
621bool 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
705ClearPreferenceFunction::~ClearPreferenceFunction() { }
706
707bool 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