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