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: 125 virtual base::Value* ExtensionToBrowserPref(const base::Value* extension_pref, 126 std::string* error, 127 bool* bad_message) OVERRIDE { 128 return extension_pref->DeepCopy(); 129 } 130 131 virtual base::Value* BrowserToExtensionPref( 132 const base::Value* browser_pref) OVERRIDE { 133 return browser_pref->DeepCopy(); 134 } 135 }; 136 137 class InvertBooleanTransformer : public PrefTransformerInterface { 138 public: 139 virtual base::Value* ExtensionToBrowserPref(const base::Value* extension_pref, 140 std::string* error, 141 bool* bad_message) OVERRIDE { 142 return InvertBooleanValue(extension_pref); 143 } 144 145 virtual base::Value* BrowserToExtensionPref( 146 const base::Value* browser_pref) OVERRIDE { 147 return InvertBooleanValue(browser_pref); 148 } 149 150 private: 151 static base::Value* InvertBooleanValue(const base::Value* value) { 152 bool bool_value = false; 153 bool result = value->GetAsBoolean(&bool_value); 154 DCHECK(result); 155 return new base::FundamentalValue(!bool_value); 156 } 157 }; 158 159 class NetworkPredictionTransformer : public PrefTransformerInterface { 160 public: 161 virtual base::Value* ExtensionToBrowserPref(const base::Value* extension_pref, 162 std::string* error, 163 bool* bad_message) override { 164 bool bool_value = false; 165 const bool pref_found = extension_pref->GetAsBoolean(&bool_value); 166 DCHECK(pref_found) << "Preference not found."; 167 if (bool_value) { 168 return new base::FundamentalValue( 169 chrome_browser_net::NETWORK_PREDICTION_DEFAULT); 170 } else { 171 return new base::FundamentalValue( 172 chrome_browser_net::NETWORK_PREDICTION_NEVER); 173 } 174 } 175 176 virtual base::Value* BrowserToExtensionPref( 177 const base::Value* browser_pref) override { 178 int int_value = chrome_browser_net::NETWORK_PREDICTION_DEFAULT; 179 const bool pref_found = browser_pref->GetAsInteger(&int_value); 180 DCHECK(pref_found) << "Preference not found."; 181 return new base::FundamentalValue( 182 int_value != chrome_browser_net::NETWORK_PREDICTION_NEVER); 183 } 184 }; 185 186 class PrefMapping { 187 public: 188 static PrefMapping* GetInstance() { 189 return Singleton<PrefMapping>::get(); 190 } 191 192 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref, 193 std::string* browser_pref, 194 APIPermission::ID* read_permission, 195 APIPermission::ID* write_permission) { 196 PrefMap::iterator it = mapping_.find(extension_pref); 197 if (it != mapping_.end()) { 198 *browser_pref = it->second.pref_name; 199 *read_permission = it->second.read_permission; 200 *write_permission = it->second.write_permission; 201 return true; 202 } 203 return false; 204 } 205 206 bool FindEventForBrowserPref(const std::string& browser_pref, 207 std::string* event_name, 208 APIPermission::ID* permission) { 209 PrefMap::iterator it = event_mapping_.find(browser_pref); 210 if (it != event_mapping_.end()) { 211 *event_name = it->second.pref_name; 212 *permission = it->second.read_permission; 213 return true; 214 } 215 return false; 216 } 217 218 PrefTransformerInterface* FindTransformerForBrowserPref( 219 const std::string& browser_pref) { 220 std::map<std::string, PrefTransformerInterface*>::iterator it = 221 transformers_.find(browser_pref); 222 if (it != transformers_.end()) 223 return it->second; 224 else 225 return identity_transformer_.get(); 226 } 227 228 private: 229 friend struct DefaultSingletonTraits<PrefMapping>; 230 231 PrefMapping() { 232 identity_transformer_.reset(new IdentityPrefTransformer()); 233 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) { 234 mapping_[kPrefMapping[i].extension_pref] = 235 PrefMapData(kPrefMapping[i].browser_pref, 236 kPrefMapping[i].read_permission, 237 kPrefMapping[i].write_permission); 238 std::string event_name = 239 base::StringPrintf(kOnPrefChangeFormat, 240 kPrefMapping[i].extension_pref); 241 event_mapping_[kPrefMapping[i].browser_pref] = 242 PrefMapData(event_name, 243 kPrefMapping[i].read_permission, 244 kPrefMapping[i].write_permission); 245 } 246 DCHECK_EQ(arraysize(kPrefMapping), mapping_.size()); 247 DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size()); 248 RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer()); 249 RegisterPrefTransformer(prefs::kBlockThirdPartyCookies, 250 new InvertBooleanTransformer()); 251 RegisterPrefTransformer(prefs::kNetworkPredictionOptions, 252 new NetworkPredictionTransformer()); 253 } 254 255 ~PrefMapping() { 256 STLDeleteContainerPairSecondPointers(transformers_.begin(), 257 transformers_.end()); 258 } 259 260 void RegisterPrefTransformer(const std::string& browser_pref, 261 PrefTransformerInterface* transformer) { 262 DCHECK_EQ(0u, transformers_.count(browser_pref)) << 263 "Trying to register pref transformer for " << browser_pref << " twice"; 264 transformers_[browser_pref] = transformer; 265 } 266 267 struct PrefMapData { 268 PrefMapData() 269 : read_permission(APIPermission::kInvalid), 270 write_permission(APIPermission::kInvalid) {} 271 272 PrefMapData(const std::string& pref_name, 273 APIPermission::ID read, 274 APIPermission::ID write) 275 : pref_name(pref_name), 276 read_permission(read), 277 write_permission(write) {} 278 279 // Browser or extension preference to which the data maps. 280 std::string pref_name; 281 282 // Permission needed to read the preference. 283 APIPermission::ID read_permission; 284 285 // Permission needed to write the preference. 286 APIPermission::ID write_permission; 287 }; 288 289 typedef std::map<std::string, PrefMapData> PrefMap; 290 291 // Mapping from extension pref keys to browser pref keys and permissions. 292 PrefMap mapping_; 293 294 // Mapping from browser pref keys to extension event names and permissions. 295 PrefMap event_mapping_; 296 297 // Mapping from browser pref keys to transformers. 298 std::map<std::string, PrefTransformerInterface*> transformers_; 299 300 scoped_ptr<PrefTransformerInterface> identity_transformer_; 301 302 DISALLOW_COPY_AND_ASSIGN(PrefMapping); 303 }; 304 305 } // namespace 306 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 323 PreferenceEventRouter::~PreferenceEventRouter() { } 324 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 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 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 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 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 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 455 PreferenceAPI::~PreferenceAPI() { 456 } 457 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>* 470 PreferenceAPI::GetFactoryInstance() { 471 return g_factory.Pointer(); 472 } 473 474 // static 475 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) { 476 return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context); 477 } 478 479 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) { 480 preference_event_router_.reset(new PreferenceEventRouter(profile_)); 481 EventRouter::Get(profile_)->UnregisterObserver(this); 482 } 483 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 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 511 ExtensionPrefs* PreferenceAPI::extension_prefs() { 512 return ExtensionPrefs::Get(profile_); 513 } 514 515 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() { 516 return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_); 517 } 518 519 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() { 520 return ContentSettingsService::Get(profile_)->content_settings_store(); 521 } 522 523 template <> 524 void 525 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() { 526 DependsOn(ContentSettingsService::GetFactoryInstance()); 527 DependsOn(ExtensionPrefsFactory::GetInstance()); 528 DependsOn(ExtensionPrefValueMapFactory::GetInstance()); 529 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); 530 } 531 532 PreferenceFunction::~PreferenceFunction() { } 533 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 557 GetPreferenceFunction::~GetPreferenceFunction() { } 558 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 619 SetPreferenceFunction::~SetPreferenceFunction() { } 620 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 705 ClearPreferenceFunction::~ClearPreferenceFunction() { } 706 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