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: 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 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: 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 141 virtual base::Value* BrowserToExtensionPref( 142 const base::Value* browser_pref) OVERRIDE { 143 return InvertBooleanValue(browser_pref); 144 } 145 146 private: 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: 157 static PrefMapping* GetInstance() { 158 return Singleton<PrefMapping>::get(); 159 } 160 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 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 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 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 222 ~PrefMapping() { 223 STLDeleteContainerPairSecondPointers(transformers_.begin(), 224 transformers_.end()); 225 } 226 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 { 235 PrefMapData() 236 : read_permission(APIPermission::kInvalid), 237 write_permission(APIPermission::kInvalid) {} 238 239 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 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 290 PreferenceEventRouter::~PreferenceEventRouter() { } 291 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 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 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 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 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 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 422 PreferenceAPI::~PreferenceAPI() { 423 } 424 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>* 437 PreferenceAPI::GetFactoryInstance() { 438 return g_factory.Pointer(); 439 } 440 441 // static 442 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) { 443 return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context); 444 } 445 446 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) { 447 preference_event_router_.reset(new PreferenceEventRouter(profile_)); 448 EventRouter::Get(profile_)->UnregisterObserver(this); 449 } 450 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 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 478 ExtensionPrefs* PreferenceAPI::extension_prefs() { 479 return ExtensionPrefs::Get(profile_); 480 } 481 482 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() { 483 return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_); 484 } 485 486 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() { 487 return ContentSettingsService::Get(profile_)->content_settings_store(); 488 } 489 490 template <> 491 void 492 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() { 493 DependsOn(ContentSettingsService::GetFactoryInstance()); 494 DependsOn(ExtensionPrefsFactory::GetInstance()); 495 DependsOn(ExtensionPrefValueMapFactory::GetInstance()); 496 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); 497 } 498 499 PreferenceFunction::~PreferenceFunction() { } 500 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 524 GetPreferenceFunction::~GetPreferenceFunction() { } 525 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 586 SetPreferenceFunction::~SetPreferenceFunction() { } 587 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 672 ClearPreferenceFunction::~ClearPreferenceFunction() { } 673 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