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