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