Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: chrome/browser/extensions/extensions_service.cc

Issue 4687005: Track permissions granted to extensions in prefs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: incorporate feedback Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extensions_service.h" 5 #include "chrome/browser/extensions/extensions_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after
920 extension); 920 extension);
921 extensions_.erase(iter); 921 extensions_.erase(iter);
922 922
923 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_, 923 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
924 extension->GetChromeURLOverrides()); 924 extension->GetChromeURLOverrides());
925 925
926 NotifyExtensionUnloaded(extension); 926 NotifyExtensionUnloaded(extension);
927 UpdateActiveExtensionsInCrashReporter(); 927 UpdateActiveExtensionsInCrashReporter();
928 } 928 }
929 929
930 void ExtensionsService::GrantPermissions(const Extension* extension) {
931 DCHECK(extension);
932 ExtensionExtent effective_hosts = extension->GetEffectiveHostPermissions();
933 extension_prefs_->AddGrantedPermissions(extension->id(),
934 extension->api_permissions(),
935 effective_hosts);
936 }
937
938 void ExtensionsService::GrantPermissionsAndEnableExtension(
939 const Extension* extension) {
940 DCHECK(extension);
941 GrantPermissions(extension);
942 extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
943 EnableExtension(extension->id());
944 }
945
930 void ExtensionsService::LoadExtension(const FilePath& extension_path) { 946 void ExtensionsService::LoadExtension(const FilePath& extension_path) {
931 BrowserThread::PostTask( 947 BrowserThread::PostTask(
932 BrowserThread::FILE, FROM_HERE, 948 BrowserThread::FILE, FROM_HERE,
933 NewRunnableMethod( 949 NewRunnableMethod(
934 backend_.get(), 950 backend_.get(),
935 &ExtensionsServiceBackend::LoadSingleExtension, 951 &ExtensionsServiceBackend::LoadSingleExtension,
936 extension_path, scoped_refptr<ExtensionsService>(this))); 952 extension_path, scoped_refptr<ExtensionsService>(this)));
937 } 953 }
938 954
939 void ExtensionsService::LoadComponentExtensions() { 955 void ExtensionsService::LoadComponentExtensions() {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1097 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count); 1113 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
1098 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count); 1114 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count);
1099 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count); 1115 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
1100 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count); 1116 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
1101 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count); 1117 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count);
1102 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count); 1118 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
1103 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction", 1119 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
1104 browser_action_count); 1120 browser_action_count);
1105 } 1121 }
1106 1122
1107
1108 void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, 1123 void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
1109 bool write_to_prefs) { 1124 bool write_to_prefs) {
1110 std::string error; 1125 std::string error;
1111 scoped_refptr<const Extension> extension(NULL); 1126 scoped_refptr<const Extension> extension(NULL);
1112 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) { 1127 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
1113 error = errors::kDisabledByPolicy; 1128 error = errors::kDisabledByPolicy;
1114 } else if (info.extension_manifest.get()) { 1129 } else if (info.extension_manifest.get()) {
1115 bool require_key = info.extension_location != Extension::LOAD; 1130 bool require_key = info.extension_location != Extension::LOAD;
1116 extension = Extension::Create( 1131 extension = Extension::Create(
1117 info.extension_path, info.extension_location, *info.extension_manifest, 1132 info.extension_path, info.extension_location, *info.extension_manifest,
1118 require_key, &error); 1133 require_key, &error);
1119 } else { 1134 } else {
1120 error = errors::kManifestUnreadable; 1135 error = errors::kManifestUnreadable;
1121 } 1136 }
1122 1137
1123 if (!extension) { 1138 if (!extension) {
1124 ReportExtensionLoadError(info.extension_path, 1139 ReportExtensionLoadError(info.extension_path,
1125 error, 1140 error,
1126 NotificationType::EXTENSION_INSTALL_ERROR, 1141 NotificationType::EXTENSION_INSTALL_ERROR,
1127 false); 1142 false);
1128 return; 1143 return;
1129 } 1144 }
1130 1145
1131 if (write_to_prefs) 1146 if (write_to_prefs)
1132 extension_prefs_->UpdateManifest(extension); 1147 extension_prefs_->UpdateManifest(extension);
1133 1148
1134 OnExtensionLoaded(extension, true); 1149 // External extensions are allowed to increase their privileges without
1135 1150 // prompting users.
1136 if (Extension::IsExternalLocation(info.extension_location)) { 1151 if (Extension::IsExternalLocation(info.extension_location)) {
1152 OnExtensionLoaded(extension, true);
1137 BrowserThread::PostTask( 1153 BrowserThread::PostTask(
1138 BrowserThread::FILE, FROM_HERE, 1154 BrowserThread::FILE, FROM_HERE,
1139 NewRunnableMethod( 1155 NewRunnableMethod(
1140 backend_.get(), 1156 backend_.get(),
1141 &ExtensionsServiceBackend::CheckExternalUninstall, 1157 &ExtensionsServiceBackend::CheckExternalUninstall,
1142 scoped_refptr<ExtensionsService>(this), 1158 scoped_refptr<ExtensionsService>(this),
1143 info.extension_id)); 1159 info.extension_id));
1160 } else {
1161 OnExtensionLoaded(extension, false);
1144 } 1162 }
1145 } 1163 }
1146 1164
1147 void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) { 1165 void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) {
1148 // The ChromeURLRequestContexts need to be first to know that the extension 1166 // The ChromeURLRequestContexts need to be first to know that the extension
1149 // was loaded, otherwise a race can arise where a renderer that is created 1167 // was loaded, otherwise a race can arise where a renderer that is created
1150 // for the extension may try to load an extension URL with an extension id 1168 // for the extension may try to load an extension URL with an extension id
1151 // that the request context doesn't yet know about. The profile is responsible 1169 // that the request context doesn't yet know about. The profile is responsible
1152 // for ensuring its URLRequestContexts appropriately discover the loaded 1170 // for ensuring its URLRequestContexts appropriately discover the loaded
1153 // extension. 1171 // extension.
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
1500 1518
1501 // The extension is now loaded, remove its data from unloaded extension map. 1519 // The extension is now loaded, remove its data from unloaded extension map.
1502 unloaded_extension_paths_.erase(extension->id()); 1520 unloaded_extension_paths_.erase(extension->id());
1503 1521
1504 // If the extension was disabled for a reload, then enable it. 1522 // If the extension was disabled for a reload, then enable it.
1505 if (disabled_extension_paths_.erase(extension->id()) > 0) 1523 if (disabled_extension_paths_.erase(extension->id()) > 0)
1506 EnableExtension(extension->id()); 1524 EnableExtension(extension->id());
1507 1525
1508 // TODO(aa): Need to re-evaluate this branch. Does this still make sense now 1526 // TODO(aa): Need to re-evaluate this branch. Does this still make sense now
1509 // that extensions are enabled by default? 1527 // that extensions are enabled by default?
1510 if (extensions_enabled() || 1528 if (extensions_enabled() ||
Aaron Boodman 2010/11/22 07:57:53 I think this long check can be removed now. It is
jstritar 2010/11/22 23:01:08 Done.
1511 extension->is_theme() || 1529 extension->is_theme() ||
1512 extension->location() == Extension::LOAD || 1530 extension->location() == Extension::LOAD ||
1513 extension->location() == Extension::COMPONENT || 1531 extension->location() == Extension::COMPONENT ||
1514 Extension::IsExternalLocation(extension->location())) { 1532 Extension::IsExternalLocation(extension->location())) {
1515 const Extension* old = GetExtensionByIdInternal(extension->id(), 1533 const Extension* old = GetExtensionByIdInternal(extension->id(),
1516 true, true); 1534 true, true);
1517 if (old) { 1535
1536 // We keep track of all permissions the user has granted each extension.
Aaron Boodman 2010/11/22 07:57:53 How about factoring all this big chunk of upgrade
jstritar 2010/11/22 23:01:08 Done.
1537 // This allows extensions to gracefully support backwards compatibility
1538 // by including unknown permissions in their manifests. When the user
1539 // installs the extension, only the recognized permissions are recorded.
1540 // When the unknown permissions become recognized (e.g., through browser
1541 // upgrade), we can prompt the user to accept these new permissions.
1542 // Extensions can also silently upgrade to less permissions, and then
1543 // silently upgrade to a version that adds these permissions back.
1544 //
1545 // For example, pretend that Chrome 10 includes a permission "omnibox"
1546 // for an API that adds suggestions to the omnibox. An extension can
1547 // maintain backwards compatibility while still having "omnibox" in the
1548 // manifest. If a user installs the extension on Chrome 9, the browser
1549 // will record the permissions it recognized, not including "omnibox."
1550 // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
1551 // will disable the extension and prompt the user to approve the increase
1552 // in privileges. The extension could then release a new version that
1553 // removes the "omnibox" permission. When the user upgrades, Chrome will
1554 // still remember that "omnibox" had been granted, so that if the
1555 // extension once again includes "omnibox" in an upgrade, the extension
1556 // can upgrade without requiring this user's approval.
1557
1558 std::set<std::string> granted_apis;
1559 ExtensionExtent granted_extent;
1560
1561 // Add all the recognized permissions to the extension's granted
1562 // permissions list if the granted permissions list hasn't been
1563 // initialized yet or privilege increases are allowed.
1564 if (extension->location() != Extension::COMPONENT &&
Aaron Boodman 2010/11/22 07:57:53 It seems like we only want to store the privileges
jstritar 2010/11/22 23:01:08 Done. I ended up needing to change the allow_privi
1565 (!extension_prefs_->GetGrantedPermissions(
1566 extension->id(), &granted_apis, &granted_extent) ||
1567 allow_privilege_increase)) {
1568 GrantPermissions(extension);
1569 DCHECK(extension_prefs_->GetGrantedPermissions(
Aaron Boodman 2010/11/22 07:57:53 Danger! Never do work with side-effects in DCHECK.
jstritar 2010/11/22 23:01:08 Wow, yeah good point. Fixed.
1570 extension->id(), &granted_apis, &granted_extent));
1571 }
1572
1573 bool is_extension_upgrade = old != NULL;
1574 bool is_privilege_increase = false;
1575
1576 // Here, we check if an extension's privileges have increased in a manner
1577 // that requires the user's approval. This could occur because the browser
1578 // upgraded and recognized additional privileges, or an extension upgrades
1579 // to a version that requires additional privileges.
1580 if ((extension->location() == Extension::INTERNAL || is_extension_upgrade)
Aaron Boodman 2010/11/22 07:57:53 And we could remove the location() check here too:
jstritar 2010/11/22 23:01:08 Done.
1581 && !allow_privilege_increase) {
1582 is_privilege_increase = Extension::IsPrivilegeIncrease(
1583 granted_apis, granted_extent, old, extension);
1584 }
1585
1586 if (is_extension_upgrade) {
1518 // CrxInstaller should have guaranteed that we aren't downgrading. 1587 // CrxInstaller should have guaranteed that we aren't downgrading.
1519 CHECK(extension->version()->CompareTo(*(old->version())) >= 0); 1588 CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
1520 1589
1521 bool allow_silent_upgrade = 1590 // Extensions get upgraded if the privileges are allowed to increase or
1522 allow_privilege_increase || !Extension::IsPrivilegeIncrease( 1591 // the privileges haven't increased.
1523 old, extension); 1592 if (allow_privilege_increase || !is_privilege_increase) {
1524
1525 // Extensions get upgraded if silent upgrades are allowed, otherwise
1526 // they get disabled.
1527 if (allow_silent_upgrade) {
1528 SetBeingUpgraded(old, true); 1593 SetBeingUpgraded(old, true);
1529 SetBeingUpgraded(extension, true); 1594 SetBeingUpgraded(extension, true);
1530 } 1595 }
1531 1596
1532 // To upgrade an extension in place, unload the old one and 1597 // To upgrade an extension in place, unload the old one and
1533 // then load the new one. 1598 // then load the new one.
1534 UnloadExtension(old->id()); 1599 UnloadExtension(old->id());
1535 old = NULL; 1600 old = NULL;
1601 }
1536 1602
1537 if (!allow_silent_upgrade) { 1603 // Extension has changed permissions significantly. Disable it. We
1538 // Extension has changed permissions significantly. Disable it. We 1604 // send a notification below.
1539 // send a notification below. 1605 if (is_privilege_increase) {
1540 extension_prefs_->SetExtensionState(extension, Extension::DISABLED); 1606 extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
1541 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); 1607 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
1542 }
1543 } 1608 }
1544 1609
1545 switch (extension_prefs_->GetExtensionState(extension->id())) { 1610 switch (extension_prefs_->GetExtensionState(extension->id())) {
1546 case Extension::ENABLED: 1611 case Extension::ENABLED:
1547 extensions_.push_back(scoped_extension); 1612 extensions_.push_back(scoped_extension);
1548 1613
1549 NotifyExtensionLoaded(extension); 1614 NotifyExtensionLoaded(extension);
1550 1615
1551 ExtensionDOMUI::RegisterChromeURLOverrides(profile_, 1616 ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
1552 extension->GetChromeURLOverrides()); 1617 extension->GetChromeURLOverrides());
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
1949 } 2014 }
1950 2015
1951 bool ExtensionsService::IsBeingUpgraded(const Extension* extension) { 2016 bool ExtensionsService::IsBeingUpgraded(const Extension* extension) {
1952 return extension_runtime_data_[extension->id()].being_upgraded; 2017 return extension_runtime_data_[extension->id()].being_upgraded;
1953 } 2018 }
1954 2019
1955 void ExtensionsService::SetBeingUpgraded(const Extension* extension, 2020 void ExtensionsService::SetBeingUpgraded(const Extension* extension,
1956 bool value) { 2021 bool value) {
1957 extension_runtime_data_[extension->id()].being_upgraded = value; 2022 extension_runtime_data_[extension->id()].being_upgraded = value;
1958 } 2023 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698