extension_prefs.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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/extension_prefs.h" 6 7#include "base/string_util.h" 8#include "base/string_number_conversions.h" 9#include "base/utf_string_conversions.h" 10#include "chrome/common/extensions/extension.h" 11#include "chrome/common/pref_names.h" 12 13using base::Time; 14 15namespace { 16 17// Additional preferences keys 18 19// Where an extension was installed from. (see Extension::Location) 20const char kPrefLocation[] = "location"; 21 22// Enabled, disabled, killed, etc. (see Extension::State) 23const char kPrefState[] = "state"; 24 25// The path to the current version's manifest file. 26const char kPrefPath[] = "path"; 27 28// The dictionary containing the extension's manifest. 29const char kPrefManifest[] = "manifest"; 30 31// The version number. 32const char kPrefVersion[] = "manifest.version"; 33 34// Indicates if an extension is blacklisted: 35const char kPrefBlacklist[] = "blacklist"; 36 37// Indicates whether to show an install warning when the user enables. 38const char kExtensionDidEscalatePermissions[] = "install_warning_on_enable"; 39 40// A preference that tracks admin policy regarding which extensions the user 41// can and can not install. This preference is a list object, containing 42// strings that list extension ids. Denylist can contain "*" meaning all 43// extensions. 44const char kExtensionInstallAllowList[] = "extensions.install.allowlist"; 45const char kExtensionInstallDenyList[] = "extensions.install.denylist"; 46 47// A preference that tracks browser action toolbar configuration. This is a list 48// object stored in the Preferences file. The extensions are stored by ID. 49const char kExtensionToolbar[] = "extensions.toolbar"; 50 51// The key for a serialized Time value indicating the start of the day (from the 52// server's perspective) an extension last included a "ping" parameter during 53// its update check. 54const char kLastPingDay[] = "lastpingday"; 55 56// Path for settings specific to blacklist update. 57const char kExtensionsBlacklistUpdate[] = "extensions.blacklistupdate"; 58 59// Path and sub-keys for the idle install info dictionary preference. 60const char kIdleInstallInfo[] = "idle_install_info"; 61const char kIdleInstallInfoCrxPath[] = "crx_path"; 62const char kIdleInstallInfoVersion[] = "version"; 63const char kIdleInstallInfoFetchTime[] = "fetch_time"; 64 65 66// A preference that, if true, will allow this extension to run in incognito 67// mode. 68const char kPrefIncognitoEnabled[] = "incognito"; 69 70// A preference to control whether an extension is allowed to inject script in 71// pages with file URLs. 72const char kPrefAllowFileAccess[] = "allowFileAccess"; 73 74// A preference set by the web store to indicate login information for 75// purchased apps. 76const char kWebStoreLogin[] = "extensions.webstore_login"; 77 78// A preference set by the the NTP to persist the desired launch container type 79// used for apps. 80const char kPrefLaunchType[] = "launchType"; 81 82} // namespace 83 84//////////////////////////////////////////////////////////////////////////////// 85 86namespace { 87 88// TODO(asargent) - This is cleanup code for a key that was introduced into 89// the extensions.settings sub-dictionary which wasn't a valid extension 90// id. We can remove this in a couple of months. (See http://crbug.com/40017 91// and http://crbug.com/39745 for more details). 92static void CleanupBadExtensionKeys(PrefService* prefs) { 93 DictionaryValue* dictionary = 94 prefs->GetMutableDictionary(ExtensionPrefs::kExtensionsPref); 95 std::set<std::string> bad_keys; 96 for (DictionaryValue::key_iterator i = dictionary->begin_keys(); 97 i != dictionary->end_keys(); ++i) { 98 const std::string& key_name(*i); 99 if (!Extension::IdIsValid(key_name)) { 100 bad_keys.insert(key_name); 101 } 102 } 103 bool dirty = false; 104 for (std::set<std::string>::iterator i = bad_keys.begin(); 105 i != bad_keys.end(); ++i) { 106 dirty = true; 107 dictionary->Remove(*i, NULL); 108 } 109 if (dirty) 110 prefs->ScheduleSavePersistentPrefs(); 111} 112 113} // namespace 114 115ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir) 116 : prefs_(prefs), 117 install_directory_(root_dir) { 118 // TODO(asargent) - Remove this in a couple of months. (See comment above 119 // CleanupBadExtensionKeys). 120 CleanupBadExtensionKeys(prefs); 121 122 MakePathsRelative(); 123} 124 125// static 126const char ExtensionPrefs::kExtensionsPref[] = "extensions.settings"; 127 128static FilePath::StringType MakePathRelative(const FilePath& parent, 129 const FilePath& child, 130 bool *dirty) { 131 if (!parent.IsParent(child)) 132 return child.value(); 133 134 if (dirty) 135 *dirty = true; 136 FilePath::StringType retval = child.value().substr( 137 parent.value().length()); 138 if (FilePath::IsSeparator(retval[0])) 139 return retval.substr(1); 140 else 141 return retval; 142} 143 144void ExtensionPrefs::MakePathsRelative() { 145 bool dirty = false; 146 const DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref); 147 if (!dict || dict->empty()) 148 return; 149 150 for (DictionaryValue::key_iterator i = dict->begin_keys(); 151 i != dict->end_keys(); ++i) { 152 DictionaryValue* extension_dict; 153 if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict)) 154 continue; 155 int location_value; 156 if (extension_dict->GetInteger(kPrefLocation, &location_value) && 157 location_value == Extension::LOAD) { 158 // Unpacked extensions can have absolute paths. 159 continue; 160 } 161 FilePath::StringType path_string; 162 if (!extension_dict->GetString(kPrefPath, &path_string)) 163 continue; 164 FilePath path(path_string); 165 if (path.IsAbsolute()) { 166 extension_dict->SetString(kPrefPath, 167 MakePathRelative(install_directory_, path, &dirty)); 168 } 169 } 170 if (dirty) 171 SavePrefsAndNotify(); 172} 173 174void ExtensionPrefs::MakePathsAbsolute(DictionaryValue* dict) { 175 if (!dict || dict->empty()) 176 return; 177 178 for (DictionaryValue::key_iterator i = dict->begin_keys(); 179 i != dict->end_keys(); ++i) { 180 DictionaryValue* extension_dict; 181 if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict)) { 182 NOTREACHED(); 183 continue; 184 } 185 186 int location_value; 187 if (extension_dict->GetInteger(kPrefLocation, &location_value) && 188 location_value == Extension::LOAD) { 189 // Unpacked extensions will already have absolute paths. 190 continue; 191 } 192 193 FilePath::StringType path_string; 194 if (!extension_dict->GetString(kPrefPath, &path_string)) 195 continue; 196 197 DCHECK(!FilePath(path_string).IsAbsolute()); 198 extension_dict->SetString( 199 kPrefPath, install_directory_.Append(path_string).value()); 200 } 201} 202 203DictionaryValue* ExtensionPrefs::CopyCurrentExtensions() { 204 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); 205 if (extensions) { 206 DictionaryValue* copy = 207 static_cast<DictionaryValue*>(extensions->DeepCopy()); 208 MakePathsAbsolute(copy); 209 return copy; 210 } 211 return new DictionaryValue; 212} 213 214bool ExtensionPrefs::ReadBooleanFromPref( 215 DictionaryValue* ext, const std::string& pref_key) { 216 if (!ext->HasKey(pref_key)) return false; 217 bool bool_value = false; 218 if (!ext->GetBoolean(pref_key, &bool_value)) { 219 NOTREACHED() << "Failed to fetch " << pref_key << " flag."; 220 // In case we could not fetch the flag, we treat it as false. 221 return false; 222 } 223 return bool_value; 224} 225 226bool ExtensionPrefs::ReadExtensionPrefBoolean( 227 const std::string& extension_id, const std::string& pref_key) { 228 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); 229 if (!extensions) 230 return false; 231 232 DictionaryValue* ext = NULL; 233 if (!extensions->GetDictionary(extension_id, &ext)) { 234 // No such extension yet. 235 return false; 236 } 237 return ReadBooleanFromPref(ext, pref_key); 238} 239 240bool ExtensionPrefs::ReadIntegerFromPref( 241 DictionaryValue* ext, const std::string& pref_key, int* out_value) { 242 if (!ext->HasKey(pref_key)) return false; 243 if (!ext->GetInteger(pref_key, out_value)) { 244 NOTREACHED() << "Failed to fetch " << pref_key << " flag."; 245 // In case we could not fetch the flag, we treat it as false. 246 return false; 247 } 248 return out_value != NULL; 249} 250 251bool ExtensionPrefs::ReadExtensionPrefInteger( 252 const std::string& extension_id, const std::string& pref_key, 253 int* out_value) { 254 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); 255 if (!extensions) 256 return false; 257 DictionaryValue* ext = NULL; 258 if (!extensions->GetDictionary(extension_id, &ext)) { 259 // No such extension yet. 260 return false; 261 } 262 return ReadIntegerFromPref(ext, pref_key, out_value); 263} 264 265void ExtensionPrefs::SavePrefsAndNotify() { 266 prefs_->ScheduleSavePersistentPrefs(); 267 prefs_->pref_notifier()->OnUserPreferenceSet(kExtensionsPref); 268} 269 270bool ExtensionPrefs::IsBlacklistBitSet(DictionaryValue* ext) { 271 return ReadBooleanFromPref(ext, kPrefBlacklist); 272} 273 274bool ExtensionPrefs::IsExtensionBlacklisted(const std::string& extension_id) { 275 return ReadExtensionPrefBoolean(extension_id, kPrefBlacklist); 276} 277 278bool ExtensionPrefs::IsExtensionAllowedByPolicy( 279 const std::string& extension_id) { 280 std::string string_value; 281 282 const ListValue* blacklist = prefs_->GetList(kExtensionInstallDenyList); 283 if (!blacklist || blacklist->empty()) 284 return true; 285 286 // Check the whitelist first. 287 const ListValue* whitelist = prefs_->GetList(kExtensionInstallAllowList); 288 if (whitelist) { 289 for (ListValue::const_iterator it = whitelist->begin(); 290 it != whitelist->end(); ++it) { 291 if (!(*it)->GetAsString(&string_value)) 292 LOG(WARNING) << "Failed to read whitelist string."; 293 else if (string_value == extension_id) 294 return true; 295 } 296 } 297 298 // Then check the blacklist (the admin blacklist, not the Google blacklist). 299 if (blacklist) { 300 for (ListValue::const_iterator it = blacklist->begin(); 301 it != blacklist->end(); ++it) { 302 if (!(*it)->GetAsString(&string_value)) { 303 LOG(WARNING) << "Failed to read blacklist string."; 304 } else { 305 if (string_value == "*") 306 return false; // Only whitelisted extensions are allowed. 307 if (string_value == extension_id) 308 return false; 309 } 310 } 311 } 312 313 return true; 314} 315 316bool ExtensionPrefs::DidExtensionEscalatePermissions( 317 const std::string& extension_id) { 318 return ReadExtensionPrefBoolean(extension_id, 319 kExtensionDidEscalatePermissions); 320} 321 322void ExtensionPrefs::SetDidExtensionEscalatePermissions( 323 Extension* extension, bool did_escalate) { 324 UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions, 325 Value::CreateBooleanValue(did_escalate)); 326 prefs_->ScheduleSavePersistentPrefs(); 327} 328 329void ExtensionPrefs::UpdateBlacklist( 330 const std::set<std::string>& blacklist_set) { 331 std::vector<std::string> remove_pref_ids; 332 std::set<std::string> used_id_set; 333 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); 334 335 if (extensions) { 336 for (DictionaryValue::key_iterator extension_id = extensions->begin_keys(); 337 extension_id != extensions->end_keys(); ++extension_id) { 338 DictionaryValue* ext; 339 if (!extensions->GetDictionaryWithoutPathExpansion(*extension_id, &ext)) { 340 NOTREACHED() << "Invalid pref for extension " << *extension_id; 341 continue; 342 } 343 const std::string& id(*extension_id); 344 if (blacklist_set.find(id) == blacklist_set.end()) { 345 if (!IsBlacklistBitSet(ext)) { 346 // This extension is not in blacklist. And it was not blacklisted 347 // before. 348 continue; 349 } else { 350 if (ext->size() == 1) { 351 // We should remove the entry if the only flag here is blacklist. 352 remove_pref_ids.push_back(id); 353 } else { 354 // Remove the blacklist bit. 355 ext->Remove(kPrefBlacklist, NULL); 356 } 357 } 358 } else { 359 if (!IsBlacklistBitSet(ext)) { 360 // Only set the blacklist if it was not set. 361 ext->SetBoolean(kPrefBlacklist, true); 362 } 363 // Keep the record if this extension is already processed. 364 used_id_set.insert(id); 365 } 366 } 367 } 368 369 // Iterate the leftovers to set blacklist in pref 370 std::set<std::string>::const_iterator set_itr = blacklist_set.begin(); 371 for (; set_itr != blacklist_set.end(); ++set_itr) { 372 if (used_id_set.find(*set_itr) == used_id_set.end()) { 373 UpdateExtensionPref(*set_itr, kPrefBlacklist, 374 Value::CreateBooleanValue(true)); 375 } 376 } 377 for (unsigned int i = 0; i < remove_pref_ids.size(); ++i) { 378 DeleteExtensionPrefs(remove_pref_ids[i]); 379 } 380 SavePrefsAndNotify(); 381 return; 382} 383 384Time ExtensionPrefs::LastPingDayImpl(const DictionaryValue* dictionary) const { 385 if (dictionary && dictionary->HasKey(kLastPingDay)) { 386 std::string string_value; 387 int64 value; 388 dictionary->GetString(kLastPingDay, &string_value); 389 if (base::StringToInt64(string_value, &value)) { 390 return Time::FromInternalValue(value); 391 } 392 } 393 return Time(); 394} 395 396void ExtensionPrefs::SetLastPingDayImpl(const Time& time, 397 DictionaryValue* dictionary) { 398 if (!dictionary) { 399 NOTREACHED(); 400 return; 401 } 402 std::string value = base::Int64ToString(time.ToInternalValue()); 403 dictionary->SetString(kLastPingDay, value); 404 SavePrefsAndNotify(); 405} 406 407Time ExtensionPrefs::LastPingDay(const std::string& extension_id) const { 408 DCHECK(Extension::IdIsValid(extension_id)); 409 return LastPingDayImpl(GetExtensionPref(extension_id)); 410} 411 412Time ExtensionPrefs::BlacklistLastPingDay() const { 413 return LastPingDayImpl(prefs_->GetDictionary(kExtensionsBlacklistUpdate)); 414} 415 416void ExtensionPrefs::SetLastPingDay(const std::string& extension_id, 417 const Time& time) { 418 DCHECK(Extension::IdIsValid(extension_id)); 419 SetLastPingDayImpl(time, GetExtensionPref(extension_id)); 420} 421 422void ExtensionPrefs::SetBlacklistLastPingDay(const Time& time) { 423 SetLastPingDayImpl(time, 424 prefs_->GetMutableDictionary(kExtensionsBlacklistUpdate)); 425} 426 427bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) { 428 return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled); 429} 430 431void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id, 432 bool enabled) { 433 UpdateExtensionPref(extension_id, kPrefIncognitoEnabled, 434 Value::CreateBooleanValue(enabled)); 435 SavePrefsAndNotify(); 436} 437 438bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) { 439 return ReadExtensionPrefBoolean(extension_id, kPrefAllowFileAccess); 440} 441 442void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id, 443 bool allow) { 444 UpdateExtensionPref(extension_id, kPrefAllowFileAccess, 445 Value::CreateBooleanValue(allow)); 446 SavePrefsAndNotify(); 447} 448 449ExtensionPrefs::LaunchType ExtensionPrefs::GetLaunchType( 450 const std::string& extension_id) { 451 int value; 452 if (ReadExtensionPrefInteger(extension_id, kPrefLaunchType, &value) && ( 453 value == LAUNCH_PINNED || 454 value == LAUNCH_REGULAR || 455 value == LAUNCH_FULLSCREEN)) { 456 return static_cast<LaunchType>(value); 457 } 458 return LAUNCH_PINNED; 459} 460 461void ExtensionPrefs::SetLaunchType(const std::string& extension_id, 462 LaunchType launch_type) { 463 UpdateExtensionPref(extension_id, kPrefLaunchType, 464 Value::CreateIntegerValue(static_cast<int>(launch_type))); 465 SavePrefsAndNotify(); 466} 467 468void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) { 469 const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref); 470 if (!dict || dict->empty()) 471 return; 472 473 for (DictionaryValue::key_iterator i = dict->begin_keys(); 474 i != dict->end_keys(); ++i) { 475 const std::string& key_name(*i); 476 if (!Extension::IdIsValid(key_name)) { 477 LOG(WARNING) << "Invalid external extension ID encountered: " << key_name; 478 continue; 479 } 480 481 DictionaryValue* extension; 482 if (!dict->GetDictionary(key_name, &extension)) { 483 NOTREACHED(); 484 continue; 485 } 486 487 // Check to see if the extension has been killed. 488 int state; 489 if (extension->GetInteger(kPrefState, &state) && 490 state == static_cast<int>(Extension::KILLBIT)) { 491 killed_ids->insert(StringToLowerASCII(key_name)); 492 } 493 } 494} 495 496std::vector<std::string> ExtensionPrefs::GetToolbarOrder() { 497 std::vector<std::string> extension_ids; 498 const ListValue* toolbar_order = prefs_->GetList(kExtensionToolbar); 499 if (toolbar_order) { 500 for (size_t i = 0; i < toolbar_order->GetSize(); ++i) { 501 std::string extension_id; 502 if (toolbar_order->GetString(i, &extension_id)) 503 extension_ids.push_back(extension_id); 504 } 505 } 506 return extension_ids; 507} 508 509void ExtensionPrefs::SetToolbarOrder( 510 const std::vector<std::string>& extension_ids) { 511 ListValue* toolbar_order = prefs_->GetMutableList(kExtensionToolbar); 512 toolbar_order->Clear(); 513 for (std::vector<std::string>::const_iterator iter = extension_ids.begin(); 514 iter != extension_ids.end(); ++iter) { 515 toolbar_order->Append(new StringValue(*iter)); 516 } 517 SavePrefsAndNotify(); 518} 519 520void ExtensionPrefs::OnExtensionInstalled( 521 Extension* extension, Extension::State initial_state, 522 bool initial_incognito_enabled) { 523 const std::string& id = extension->id(); 524 UpdateExtensionPref(id, kPrefState, 525 Value::CreateIntegerValue(initial_state)); 526 UpdateExtensionPref(id, kPrefIncognitoEnabled, 527 Value::CreateBooleanValue(initial_incognito_enabled)); 528 UpdateExtensionPref(id, kPrefLocation, 529 Value::CreateIntegerValue(extension->location())); 530 FilePath::StringType path = MakePathRelative(install_directory_, 531 extension->path(), NULL); 532 UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path)); 533 // We store prefs about LOAD extensions, but don't cache their manifest 534 // since it may change on disk. 535 if (extension->location() != Extension::LOAD) { 536 UpdateExtensionPref(id, kPrefManifest, 537 extension->manifest_value()->DeepCopy()); 538 } 539 SavePrefsAndNotify(); 540} 541 542void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id, 543 const Extension::Location& location, 544 bool external_uninstall) { 545 // For external extensions, we save a preference reminding ourself not to try 546 // and install the extension anymore (except when |external_uninstall| is 547 // true, which signifies that the registry key was deleted or the pref file 548 // no longer lists the extension). 549 if (!external_uninstall && Extension::IsExternalLocation(location)) { 550 UpdateExtensionPref(extension_id, kPrefState, 551 Value::CreateIntegerValue(Extension::KILLBIT)); 552 SavePrefsAndNotify(); 553 } else { 554 DeleteExtensionPrefs(extension_id); 555 } 556} 557 558Extension::State ExtensionPrefs::GetExtensionState( 559 const std::string& extension_id) { 560 DictionaryValue* extension = GetExtensionPref(extension_id); 561 562 // If the extension doesn't have a pref, it's a --load-extension. 563 if (!extension) 564 return Extension::ENABLED; 565 566 int state = -1; 567 if (!extension->GetInteger(kPrefState, &state) || 568 state < 0 || state >= Extension::NUM_STATES) { 569 LOG(ERROR) << "Bad or missing pref 'state' for extension '" 570 << extension_id << "'"; 571 return Extension::ENABLED; 572 } 573 return static_cast<Extension::State>(state); 574} 575 576void ExtensionPrefs::SetExtensionState(Extension* extension, 577 Extension::State state) { 578 UpdateExtensionPref(extension->id(), kPrefState, 579 Value::CreateIntegerValue(state)); 580 SavePrefsAndNotify(); 581} 582 583std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) { 584 DictionaryValue* extension = GetExtensionPref(extension_id); 585 if (!extension) 586 return std::string(); 587 588 std::string version; 589 if (!extension->GetString(kPrefVersion, &version)) { 590 LOG(ERROR) << "Bad or missing pref 'version' for extension '" 591 << extension_id << "'"; 592 } 593 594 return version; 595} 596 597void ExtensionPrefs::UpdateManifest(Extension* extension) { 598 if (extension->location() != Extension::LOAD) { 599 UpdateExtensionPref(extension->id(), kPrefManifest, 600 extension->manifest_value()->DeepCopy()); 601 SavePrefsAndNotify(); 602 } 603} 604 605FilePath ExtensionPrefs::GetExtensionPath(const std::string& extension_id) { 606 const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref); 607 if (!dict || dict->empty()) 608 return FilePath(); 609 610 std::string path; 611 if (!dict->GetString(extension_id + "." + kPrefPath, &path)) 612 return FilePath(); 613 614 return install_directory_.Append(FilePath::FromWStringHack(UTF8ToWide(path))); 615} 616 617void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id, 618 const std::string& key, 619 Value* data_value) { 620 if (!Extension::IdIsValid(extension_id)) { 621 NOTREACHED() << "Invalid extension_id " << extension_id; 622 return; 623 } 624 DictionaryValue* extension = GetOrCreateExtensionPref(extension_id); 625 extension->Set(key, data_value); 626} 627 628void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) { 629 DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref); 630 if (dict->HasKey(extension_id)) { 631 dict->Remove(extension_id, NULL); 632 SavePrefsAndNotify(); 633 } 634} 635 636DictionaryValue* ExtensionPrefs::GetOrCreateExtensionPref( 637 const std::string& extension_id) { 638 DCHECK(Extension::IdIsValid(extension_id)); 639 DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref); 640 DictionaryValue* extension = NULL; 641 if (!dict->GetDictionary(extension_id, &extension)) { 642 // Extension pref does not exist, create it. 643 extension = new DictionaryValue(); 644 dict->Set(extension_id, extension); 645 } 646 return extension; 647} 648 649DictionaryValue* ExtensionPrefs::GetExtensionPref( 650 const std::string& extension_id) const { 651 const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref); 652 if (!dict) 653 return NULL; 654 DictionaryValue* extension = NULL; 655 dict->GetDictionary(extension_id, &extension); 656 return extension; 657} 658 659// Helper function for GetInstalledExtensionsInfo. 660static ExtensionInfo* GetInstalledExtensionInfoImpl( 661 DictionaryValue* extension_data, 662 DictionaryValue::key_iterator extension_id) { 663 DictionaryValue* ext; 664 if (!extension_data->GetDictionaryWithoutPathExpansion(*extension_id, &ext)) { 665 LOG(WARNING) << "Invalid pref for extension " << *extension_id; 666 NOTREACHED(); 667 return NULL; 668 } 669 if (ext->HasKey(kPrefBlacklist)) { 670 bool is_blacklisted = false; 671 if (!ext->GetBoolean(kPrefBlacklist, &is_blacklisted)) { 672 NOTREACHED() << "Invalid blacklist pref:" << *extension_id; 673 return NULL; 674 } 675 if (is_blacklisted) { 676 return NULL; 677 } 678 } 679 int state_value; 680 if (!ext->GetInteger(kPrefState, &state_value)) { 681 // This can legitimately happen if we store preferences for component 682 // extensions. 683 return NULL; 684 } 685 if (state_value == Extension::KILLBIT) { 686 LOG(WARNING) << "External extension has been uninstalled by the user " 687 << *extension_id; 688 return NULL; 689 } 690 FilePath::StringType path; 691 if (!ext->GetString(kPrefPath, &path)) { 692 return NULL; 693 } 694 int location_value; 695 if (!ext->GetInteger(kPrefLocation, &location_value)) { 696 return NULL; 697 } 698 699 // Only the following extension types can be installed permanently in the 700 // preferences. 701 Extension::Location location = 702 static_cast<Extension::Location>(location_value); 703 if (location != Extension::INTERNAL && 704 location != Extension::LOAD && 705 !Extension::IsExternalLocation(location)) { 706 NOTREACHED(); 707 return NULL; 708 } 709 710 DictionaryValue* manifest = NULL; 711 if (location != Extension::LOAD && 712 !ext->GetDictionary(kPrefManifest, &manifest)) { 713 LOG(WARNING) << "Missing manifest for extension " << *extension_id; 714 // Just a warning for now. 715 } 716 717 return new ExtensionInfo(manifest, *extension_id, FilePath(path), location); 718} 719 720ExtensionPrefs::ExtensionsInfo* ExtensionPrefs::GetInstalledExtensionsInfo() { 721 scoped_ptr<DictionaryValue> extension_data(CopyCurrentExtensions()); 722 723 ExtensionsInfo* extensions_info = new ExtensionsInfo; 724 725 for (DictionaryValue::key_iterator extension_id( 726 extension_data->begin_keys()); 727 extension_id != extension_data->end_keys(); ++extension_id) { 728 if (!Extension::IdIsValid(*extension_id)) 729 continue; 730 731 ExtensionInfo* info = GetInstalledExtensionInfoImpl(extension_data.get(), 732 extension_id); 733 if (info) 734 extensions_info->push_back(linked_ptr<ExtensionInfo>(info)); 735 } 736 737 return extensions_info; 738} 739 740ExtensionInfo* ExtensionPrefs::GetInstalledExtensionInfo( 741 const std::string& extension_id) { 742 scoped_ptr<DictionaryValue> extension_data(CopyCurrentExtensions()); 743 744 for (DictionaryValue::key_iterator extension_iter( 745 extension_data->begin_keys()); 746 extension_iter != extension_data->end_keys(); ++extension_iter) { 747 if (*extension_iter == extension_id) { 748 return GetInstalledExtensionInfoImpl(extension_data.get(), 749 extension_iter); 750 } 751 } 752 753 return NULL; 754} 755 756void ExtensionPrefs::SetIdleInstallInfo(const std::string& extension_id, 757 const FilePath& crx_path, 758 const std::string& version, 759 const base::Time& fetch_time) { 760 DictionaryValue* extension_prefs = GetExtensionPref(extension_id); 761 if (!extension_prefs) { 762 NOTREACHED(); 763 return; 764 } 765 extension_prefs->Remove(kIdleInstallInfo, NULL); 766 DictionaryValue* info = new DictionaryValue(); 767 info->SetString(kIdleInstallInfoCrxPath, crx_path.value()); 768 info->SetString(kIdleInstallInfoVersion, version); 769 info->SetString(kIdleInstallInfoFetchTime, 770 base::Int64ToString(fetch_time.ToInternalValue())); 771 extension_prefs->Set(kIdleInstallInfo, info); 772 SavePrefsAndNotify(); 773} 774 775bool ExtensionPrefs::RemoveIdleInstallInfo(const std::string& extension_id) { 776 DictionaryValue* extension_prefs = GetExtensionPref(extension_id); 777 if (!extension_prefs) 778 return false; 779 bool result = extension_prefs->Remove(kIdleInstallInfo, NULL); 780 SavePrefsAndNotify(); 781 return result; 782} 783 784bool ExtensionPrefs::GetIdleInstallInfo(const std::string& extension_id, 785 FilePath* crx_path, 786 std::string* version, 787 base::Time* fetch_time) { 788 DictionaryValue* extension_prefs = GetExtensionPref(extension_id); 789 if (!extension_prefs) 790 return false; 791 792 // Do all the reads from the prefs together, and don't do any assignment 793 // to the out parameters unless all the reads succeed. 794 DictionaryValue* info = NULL; 795 if (!extension_prefs->GetDictionary(kIdleInstallInfo, &info)) 796 return false; 797 798 FilePath::StringType path_string; 799 if (!info->GetString(kIdleInstallInfoCrxPath, &path_string)) 800 return false; 801 802 std::string tmp_version; 803 if (!info->GetString(kIdleInstallInfoVersion, &tmp_version)) 804 return false; 805 806 std::string fetch_time_string; 807 if (!info->GetString(kIdleInstallInfoFetchTime, &fetch_time_string)) 808 return false; 809 810 int64 fetch_time_value; 811 if (!base::StringToInt64(fetch_time_string, &fetch_time_value)) 812 return false; 813 814 if (crx_path) 815 *crx_path = FilePath(path_string); 816 817 if (version) 818 *version = tmp_version; 819 820 if (fetch_time) 821 *fetch_time = base::Time::FromInternalValue(fetch_time_value); 822 823 return true; 824} 825 826std::set<std::string> ExtensionPrefs::GetIdleInstallInfoIds() { 827 std::set<std::string> result; 828 829 const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref); 830 if (!extensions) 831 return result; 832 833 for (DictionaryValue::key_iterator iter = extensions->begin_keys(); 834 iter != extensions->end_keys(); ++iter) { 835 const std::string& id(*iter); 836 if (!Extension::IdIsValid(id)) { 837 NOTREACHED(); 838 continue; 839 } 840 841 DictionaryValue* extension_prefs = GetExtensionPref(id); 842 if (!extension_prefs) 843 continue; 844 845 DictionaryValue* info = NULL; 846 if (extension_prefs->GetDictionary(kIdleInstallInfo, &info)) 847 result.insert(id); 848 } 849 return result; 850} 851 852bool ExtensionPrefs::GetWebStoreLogin(std::string* result) { 853 if (prefs_->HasPrefPath(kWebStoreLogin)) { 854 *result = prefs_->GetString(kWebStoreLogin); 855 return true; 856 } 857 return false; 858} 859 860void ExtensionPrefs::SetWebStoreLogin(const std::string& login) { 861 prefs_->SetString(kWebStoreLogin, login); 862 SavePrefsAndNotify(); 863} 864 865// static 866void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) { 867 prefs->RegisterDictionaryPref(kExtensionsPref); 868 prefs->RegisterListPref(kExtensionToolbar); 869 prefs->RegisterIntegerPref(prefs::kExtensionToolbarSize, -1); 870 prefs->RegisterDictionaryPref(kExtensionsBlacklistUpdate); 871 prefs->RegisterListPref(kExtensionInstallAllowList); 872 prefs->RegisterListPref(kExtensionInstallDenyList); 873 prefs->RegisterStringPref(kWebStoreLogin, std::string() /* default_value */); 874} 875