preference_api.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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/stringprintf.h" 15#include "base/values.h" 16#include "chrome/browser/extensions/api/preference/preference_api_constants.h" 17#include "chrome/browser/extensions/api/preference/preference_helpers.h" 18#include "chrome/browser/extensions/api/proxy/proxy_api.h" 19#include "chrome/browser/extensions/extension_prefs.h" 20#include "chrome/browser/extensions/extension_prefs_scope.h" 21#include "chrome/browser/extensions/extension_service.h" 22#include "chrome/browser/extensions/extension_system.h" 23#include "chrome/browser/profiles/profile.h" 24#include "chrome/common/chrome_notification_types.h" 25#include "chrome/common/extensions/permissions/api_permission.h" 26#include "chrome/common/pref_names.h" 27#include "content/public/browser/notification_details.h" 28#include "content/public/browser/notification_source.h" 29#include "extensions/common/error_utils.h" 30 31namespace keys = extensions::preference_api_constants; 32namespace helpers = extensions::preference_helpers; 33 34namespace extensions { 35 36namespace { 37 38struct PrefMappingEntry { 39 // Name of the preference referenced by the extension API JSON. 40 const char* extension_pref; 41 42 // Name of the preference in the PrefStores. 43 const char* browser_pref; 44 45 // Permission required to access this preference. 46 // Use APIPermission::kInvalid for |permission| to express that no 47 // permission is necessary. 48 APIPermission::ID permission; 49}; 50 51const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange"; 52const char kConversionErrorMessage[] = 53 "Internal error: Stored value for preference '*' cannot be converted " 54 "properly."; 55 56PrefMappingEntry kPrefMapping[] = { 57 { "protectedContentEnabled", 58 prefs::kEnableDRM, 59 APIPermission::kPrivacy 60 }, 61 { "alternateErrorPagesEnabled", 62 prefs::kAlternateErrorPagesEnabled, 63 APIPermission::kPrivacy 64 }, 65 { "autofillEnabled", 66 autofill::prefs::kAutofillEnabled, 67 APIPermission::kPrivacy 68 }, 69 { "hyperlinkAuditingEnabled", 70 prefs::kEnableHyperlinkAuditing, 71 APIPermission::kPrivacy 72 }, 73 { "managedModeEnabled", 74 prefs::kInManagedMode, 75 APIPermission::kManagedModePrivate 76 }, 77 { "networkPredictionEnabled", 78 prefs::kNetworkPredictionEnabled, 79 APIPermission::kPrivacy 80 }, 81 { "proxy", 82 prefs::kProxy, 83 APIPermission::kProxy 84 }, 85 { "referrersEnabled", 86 prefs::kEnableReferrers, 87 APIPermission::kPrivacy 88 }, 89 { "safeBrowsingEnabled", 90 prefs::kSafeBrowsingEnabled, 91 APIPermission::kPrivacy 92 }, 93 { "searchSuggestEnabled", 94 prefs::kSearchSuggestEnabled, 95 APIPermission::kPrivacy 96 }, 97 { "spellingServiceEnabled", 98 prefs::kSpellCheckUseSpellingService, 99 APIPermission::kPrivacy 100 }, 101 { "thirdPartyCookiesAllowed", 102 prefs::kBlockThirdPartyCookies, 103 APIPermission::kPrivacy 104 }, 105 { "translationServiceEnabled", 106 prefs::kEnableTranslate, 107 APIPermission::kPrivacy 108 } 109}; 110 111class IdentityPrefTransformer : public PrefTransformerInterface { 112 public: 113 virtual Value* ExtensionToBrowserPref(const Value* extension_pref, 114 std::string* error, 115 bool* bad_message) OVERRIDE { 116 return extension_pref->DeepCopy(); 117 } 118 119 virtual Value* BrowserToExtensionPref(const Value* browser_pref) OVERRIDE { 120 return browser_pref->DeepCopy(); 121 } 122}; 123 124class InvertBooleanTransformer : public PrefTransformerInterface { 125 public: 126 virtual Value* ExtensionToBrowserPref(const Value* extension_pref, 127 std::string* error, 128 bool* bad_message) OVERRIDE { 129 return InvertBooleanValue(extension_pref); 130 } 131 132 virtual Value* BrowserToExtensionPref(const Value* browser_pref) OVERRIDE { 133 return InvertBooleanValue(browser_pref); 134 } 135 136 private: 137 static Value* InvertBooleanValue(const Value* value) { 138 bool bool_value = false; 139 bool result = value->GetAsBoolean(&bool_value); 140 DCHECK(result); 141 return Value::CreateBooleanValue(!bool_value); 142 } 143}; 144 145class PrefMapping { 146 public: 147 static PrefMapping* GetInstance() { 148 return Singleton<PrefMapping>::get(); 149 } 150 151 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref, 152 std::string* browser_pref, 153 APIPermission::ID* permission) { 154 PrefMap::iterator it = mapping_.find(extension_pref); 155 if (it != mapping_.end()) { 156 *browser_pref = it->second.first; 157 *permission = it->second.second; 158 return true; 159 } 160 return false; 161 } 162 163 bool FindEventForBrowserPref(const std::string& browser_pref, 164 std::string* event_name, 165 APIPermission::ID* permission) { 166 PrefMap::iterator it = event_mapping_.find(browser_pref); 167 if (it != event_mapping_.end()) { 168 *event_name = it->second.first; 169 *permission = it->second.second; 170 return true; 171 } 172 return false; 173 } 174 175 PrefTransformerInterface* FindTransformerForBrowserPref( 176 const std::string& browser_pref) { 177 std::map<std::string, PrefTransformerInterface*>::iterator it = 178 transformers_.find(browser_pref); 179 if (it != transformers_.end()) 180 return it->second; 181 else 182 return identity_transformer_.get(); 183 } 184 185 private: 186 friend struct DefaultSingletonTraits<PrefMapping>; 187 188 PrefMapping() { 189 identity_transformer_.reset(new IdentityPrefTransformer()); 190 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) { 191 mapping_[kPrefMapping[i].extension_pref] = 192 std::make_pair(kPrefMapping[i].browser_pref, 193 kPrefMapping[i].permission); 194 std::string event_name = 195 base::StringPrintf(kOnPrefChangeFormat, 196 kPrefMapping[i].extension_pref); 197 event_mapping_[kPrefMapping[i].browser_pref] = 198 std::make_pair(event_name, kPrefMapping[i].permission); 199 } 200 DCHECK_EQ(arraysize(kPrefMapping), mapping_.size()); 201 DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size()); 202 RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer()); 203 RegisterPrefTransformer(prefs::kBlockThirdPartyCookies, 204 new InvertBooleanTransformer()); 205 } 206 207 ~PrefMapping() { 208 STLDeleteContainerPairSecondPointers(transformers_.begin(), 209 transformers_.end()); 210 } 211 212 void RegisterPrefTransformer(const std::string& browser_pref, 213 PrefTransformerInterface* transformer) { 214 DCHECK_EQ(0u, transformers_.count(browser_pref)) << 215 "Trying to register pref transformer for " << browser_pref << " twice"; 216 transformers_[browser_pref] = transformer; 217 } 218 219 typedef std::map<std::string, 220 std::pair<std::string, APIPermission::ID> > 221 PrefMap; 222 223 // Mapping from extension pref keys to browser pref keys and permissions. 224 PrefMap mapping_; 225 226 // Mapping from browser pref keys to extension event names and permissions. 227 PrefMap event_mapping_; 228 229 // Mapping from browser pref keys to transformers. 230 std::map<std::string, PrefTransformerInterface*> transformers_; 231 232 scoped_ptr<PrefTransformerInterface> identity_transformer_; 233 234 DISALLOW_COPY_AND_ASSIGN(PrefMapping); 235}; 236 237} // namespace 238 239PreferenceEventRouter::PreferenceEventRouter(Profile* profile) 240 : profile_(profile) { 241 registrar_.Init(profile_->GetPrefs()); 242 incognito_registrar_.Init(profile_->GetOffTheRecordPrefs()); 243 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) { 244 registrar_.Add(kPrefMapping[i].browser_pref, 245 base::Bind(&PreferenceEventRouter::OnPrefChanged, 246 base::Unretained(this), 247 registrar_.prefs())); 248 incognito_registrar_.Add(kPrefMapping[i].browser_pref, 249 base::Bind(&PreferenceEventRouter::OnPrefChanged, 250 base::Unretained(this), 251 incognito_registrar_.prefs())); 252 } 253} 254 255PreferenceEventRouter::~PreferenceEventRouter() { } 256 257void PreferenceEventRouter::OnPrefChanged(PrefService* pref_service, 258 const std::string& browser_pref) { 259 bool incognito = (pref_service != profile_->GetPrefs()); 260 261 std::string event_name; 262 APIPermission::ID permission = APIPermission::kInvalid; 263 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref( 264 browser_pref, &event_name, &permission); 265 DCHECK(rv); 266 267 ListValue args; 268 DictionaryValue* dict = new DictionaryValue(); 269 args.Append(dict); 270 const PrefService::Preference* pref = 271 pref_service->FindPreference(browser_pref.c_str()); 272 CHECK(pref); 273 ExtensionService* extension_service = 274 ExtensionSystem::Get(profile_)->extension_service(); 275 PrefTransformerInterface* transformer = 276 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref); 277 Value* transformed_value = 278 transformer->BrowserToExtensionPref(pref->GetValue()); 279 if (!transformed_value) { 280 LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage, 281 pref->name()); 282 return; 283 } 284 285 dict->Set(keys::kValue, transformed_value); 286 if (incognito) { 287 ExtensionPrefs* ep = extension_service->extension_prefs(); 288 dict->SetBoolean(keys::kIncognitoSpecific, 289 ep->HasIncognitoPrefValue(browser_pref)); 290 } 291 292 helpers::DispatchEventToExtensions(profile_, 293 event_name, 294 &args, 295 permission, 296 incognito, 297 browser_pref); 298} 299 300PreferenceAPI::PreferenceAPI(Profile* profile) : profile_(profile) { 301 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) { 302 std::string event_name; 303 APIPermission::ID permission = APIPermission::kInvalid; 304 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref( 305 kPrefMapping[i].browser_pref, &event_name, &permission); 306 DCHECK(rv); 307 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 308 this, event_name); 309 } 310} 311 312PreferenceAPI::~PreferenceAPI() { 313} 314 315void PreferenceAPI::Shutdown() { 316 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 317} 318 319static base::LazyInstance<ProfileKeyedAPIFactory<PreferenceAPI> > 320g_factory = LAZY_INSTANCE_INITIALIZER; 321 322// static 323ProfileKeyedAPIFactory<PreferenceAPI>* PreferenceAPI::GetFactoryInstance() { 324 return &g_factory.Get(); 325} 326 327void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) { 328 preference_event_router_.reset(new PreferenceEventRouter(profile_)); 329 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 330} 331 332PreferenceFunction::~PreferenceFunction() { } 333 334bool PreferenceFunction::ValidateBrowserPref( 335 const std::string& extension_pref_key, 336 std::string* browser_pref_key) { 337 APIPermission::ID permission = APIPermission::kInvalid; 338 EXTENSION_FUNCTION_VALIDATE( 339 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( 340 extension_pref_key, browser_pref_key, &permission)); 341 if (!GetExtension()->HasAPIPermission(permission)) { 342 error_ = ErrorUtils::FormatErrorMessage( 343 keys::kPermissionErrorMessage, extension_pref_key); 344 return false; 345 } 346 return true; 347} 348 349GetPreferenceFunction::~GetPreferenceFunction() { } 350 351bool GetPreferenceFunction::RunImpl() { 352 std::string pref_key; 353 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); 354 DictionaryValue* details = NULL; 355 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details)); 356 357 bool incognito = false; 358 if (details->HasKey(keys::kIncognitoKey)) 359 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(keys::kIncognitoKey, 360 &incognito)); 361 362 // Check incognito access. 363 if (incognito && !include_incognito()) { 364 error_ = keys::kIncognitoErrorMessage; 365 return false; 366 } 367 368 // Obtain pref. 369 std::string browser_pref; 370 if (!ValidateBrowserPref(pref_key, &browser_pref)) 371 return false; 372 PrefService* prefs = incognito ? profile_->GetOffTheRecordPrefs() 373 : profile_->GetPrefs(); 374 const PrefService::Preference* pref = 375 prefs->FindPreference(browser_pref.c_str()); 376 CHECK(pref); 377 378 scoped_ptr<DictionaryValue> result(new DictionaryValue); 379 380 // Retrieve level of control. 381 std::string level_of_control = 382 helpers::GetLevelOfControl(profile_, extension_id(), browser_pref, 383 incognito); 384 result->SetString(keys::kLevelOfControl, level_of_control); 385 386 // Retrieve pref value. 387 PrefTransformerInterface* transformer = 388 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref); 389 Value* transformed_value = 390 transformer->BrowserToExtensionPref(pref->GetValue()); 391 if (!transformed_value) { 392 LOG(ERROR) << 393 ErrorUtils::FormatErrorMessage(kConversionErrorMessage, 394 pref->name()); 395 return false; 396 } 397 result->Set(keys::kValue, transformed_value); 398 399 // Retrieve incognito status. 400 if (incognito) { 401 ExtensionPrefs* ep = 402 ExtensionSystem::Get(profile_)->extension_service()->extension_prefs(); 403 result->SetBoolean(keys::kIncognitoSpecific, 404 ep->HasIncognitoPrefValue(browser_pref)); 405 } 406 407 SetResult(result.release()); 408 return true; 409} 410 411SetPreferenceFunction::~SetPreferenceFunction() { } 412 413bool SetPreferenceFunction::RunImpl() { 414 std::string pref_key; 415 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); 416 DictionaryValue* details = NULL; 417 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details)); 418 419 Value* value = NULL; 420 EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kValue, &value)); 421 422 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular; 423 if (details->HasKey(keys::kScopeKey)) { 424 std::string scope_str; 425 EXTENSION_FUNCTION_VALIDATE( 426 details->GetString(keys::kScopeKey, &scope_str)); 427 428 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope)); 429 } 430 431 // Check incognito scope. 432 bool incognito = 433 (scope == kExtensionPrefsScopeIncognitoPersistent || 434 scope == kExtensionPrefsScopeIncognitoSessionOnly); 435 if (incognito) { 436 // Regular profiles can't access incognito unless include_incognito is true. 437 if (!profile()->IsOffTheRecord() && !include_incognito()) { 438 error_ = keys::kIncognitoErrorMessage; 439 return false; 440 } 441 } else { 442 // Incognito profiles can't access regular mode ever, they only exist in 443 // split mode. 444 if (profile()->IsOffTheRecord()) { 445 error_ = "Can't modify regular settings from an incognito context."; 446 return false; 447 } 448 } 449 450 if (scope == kExtensionPrefsScopeIncognitoSessionOnly && 451 !profile_->HasOffTheRecordProfile()) { 452 error_ = keys::kIncognitoSessionOnlyErrorMessage; 453 return false; 454 } 455 456 // Obtain pref. 457 std::string browser_pref; 458 if (!ValidateBrowserPref(pref_key, &browser_pref)) 459 return false; 460 ExtensionPrefs* prefs = 461 ExtensionSystem::Get(profile_)->extension_service()->extension_prefs(); 462 const PrefService::Preference* pref = 463 prefs->pref_service()->FindPreference(browser_pref.c_str()); 464 CHECK(pref); 465 466 // Validate new value. 467 EXTENSION_FUNCTION_VALIDATE(value->GetType() == pref->GetType()); 468 PrefTransformerInterface* transformer = 469 PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref); 470 std::string error; 471 bool bad_message = false; 472 scoped_ptr<Value> browser_pref_value( 473 transformer->ExtensionToBrowserPref(value, &error, &bad_message)); 474 if (!browser_pref_value) { 475 error_ = error; 476 bad_message_ = bad_message; 477 return false; 478 } 479 480 // Validate also that the stored value can be converted back by the 481 // transformer. 482 scoped_ptr<Value> extensionPrefValue( 483 transformer->BrowserToExtensionPref(browser_pref_value.get())); 484 if (!extensionPrefValue) { 485 error_ = ErrorUtils::FormatErrorMessage(kConversionErrorMessage, 486 pref->name()); 487 bad_message_ = true; 488 return false; 489 } 490 491 prefs->SetExtensionControlledPref(extension_id(), 492 browser_pref, 493 scope, 494 browser_pref_value.release()); 495 return true; 496} 497 498ClearPreferenceFunction::~ClearPreferenceFunction() { } 499 500bool ClearPreferenceFunction::RunImpl() { 501 std::string pref_key; 502 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); 503 DictionaryValue* details = NULL; 504 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details)); 505 506 ExtensionPrefsScope scope = kExtensionPrefsScopeRegular; 507 if (details->HasKey(keys::kScopeKey)) { 508 std::string scope_str; 509 EXTENSION_FUNCTION_VALIDATE( 510 details->GetString(keys::kScopeKey, &scope_str)); 511 512 EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope)); 513 } 514 515 // Check incognito scope. 516 bool incognito = 517 (scope == kExtensionPrefsScopeIncognitoPersistent || 518 scope == kExtensionPrefsScopeIncognitoSessionOnly); 519 if (incognito) { 520 // We don't check incognito permissions here, as an extension should be 521 // always allowed to clear its own settings. 522 } else { 523 // Incognito profiles can't access regular mode ever, they only exist in 524 // split mode. 525 if (profile()->IsOffTheRecord()) { 526 error_ = "Can't modify regular settings from an incognito context."; 527 return false; 528 } 529 } 530 531 std::string browser_pref; 532 if (!ValidateBrowserPref(pref_key, &browser_pref)) 533 return false; 534 535 ExtensionPrefs* prefs = 536 ExtensionSystem::Get(profile_)->extension_service()->extension_prefs(); 537 prefs->RemoveExtensionControlledPref(extension_id(), browser_pref, scope); 538 return true; 539} 540 541} // namespace extensions 542