Chromium Code Reviews| Index: chrome/browser/extensions/extensions_service.cc |
| diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc |
| index 02c4bcca0b3415527fec18024161d0337310ed9c..3bf1a9aadfb5b492b5c5fc12c1355d48c49ada9b 100644 |
| --- a/chrome/browser/extensions/extensions_service.cc |
| +++ b/chrome/browser/extensions/extensions_service.cc |
| @@ -629,7 +629,7 @@ void ExtensionsService::InstallExtension(const FilePath& extension_path) { |
| new CrxInstaller(install_directory_, |
| this, // frontend |
| NULL)); // no client (silent install) |
| - installer->set_allow_privilege_increase(true); |
| + installer->set_allow_privilege_increase(false); |
| installer->InstallCrx(extension_path); |
| } |
| @@ -927,6 +927,22 @@ void ExtensionsService::DisableExtension(const std::string& extension_id) { |
| UpdateActiveExtensionsInCrashReporter(); |
| } |
| +void ExtensionsService::GrantPermissions(const Extension* extension) { |
| + CHECK(extension); |
| + ExtensionExtent effective_hosts = extension->GetEffectiveHostPermissions(); |
| + extension_prefs_->AddGrantedPermissions(extension->id(), |
| + extension->api_permissions(), |
| + effective_hosts); |
| +} |
| + |
| +void ExtensionsService::GrantPermissionsAndEnableExtension( |
| + const Extension* extension) { |
| + CHECK(extension); |
| + GrantPermissions(extension); |
| + extension_prefs_->SetDidExtensionEscalatePermissions(extension, false); |
| + EnableExtension(extension->id()); |
| +} |
| + |
| void ExtensionsService::LoadExtension(const FilePath& extension_path) { |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| @@ -959,7 +975,7 @@ void ExtensionsService::LoadComponentExtensions() { |
| return; |
| } |
| - OnExtensionLoaded(extension, false); // Don't allow privilege increase. |
| + OnExtensionLoaded(extension, true); |
| } |
| } |
| @@ -1104,7 +1120,6 @@ void ExtensionsService::LoadAllExtensions() { |
| browser_action_count); |
| } |
| - |
| void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, |
| bool write_to_prefs) { |
| std::string error; |
| @@ -1131,9 +1146,10 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, |
| if (write_to_prefs) |
| extension_prefs_->UpdateManifest(extension); |
| - OnExtensionLoaded(extension, true); |
| - |
| + // External extensions are allowed to increase their privileges without |
| + // prompting users. |
| if (Extension::IsExternalLocation(info.extension_location)) { |
| + OnExtensionLoaded(extension, true); |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| NewRunnableMethod( |
| @@ -1141,6 +1157,8 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, |
| &ExtensionsServiceBackend::CheckExternalUninstall, |
| scoped_refptr<ExtensionsService>(this), |
| info.extension_id)); |
| + } else { |
| + OnExtensionLoaded(extension, false); |
| } |
| } |
| @@ -1506,63 +1524,29 @@ void ExtensionsService::OnExtensionLoaded(const Extension* extension, |
| if (disabled_extension_paths_.erase(extension->id()) > 0) |
| EnableExtension(extension->id()); |
| - // TODO(aa): Need to re-evaluate this branch. Does this still make sense now |
| - // that extensions are enabled by default? |
| - if (extensions_enabled() || |
| - extension->is_theme() || |
| - extension->location() == Extension::LOAD || |
| - extension->location() == Extension::COMPONENT || |
| - Extension::IsExternalLocation(extension->location())) { |
| - const Extension* old = GetExtensionByIdInternal(extension->id(), |
| - true, true); |
| - if (old) { |
| - // CrxInstaller should have guaranteed that we aren't downgrading. |
| - CHECK(extension->version()->CompareTo(*(old->version())) >= 0); |
| - |
| - bool allow_silent_upgrade = |
| - allow_privilege_increase || !Extension::IsPrivilegeIncrease( |
| - old, extension); |
| - |
| - // Extensions get upgraded if silent upgrades are allowed, otherwise |
| - // they get disabled. |
| - if (allow_silent_upgrade) { |
| - SetBeingUpgraded(old, true); |
| - SetBeingUpgraded(extension, true); |
| - } |
| - |
| - // To upgrade an extension in place, unload the old one and |
| - // then load the new one. |
| - UnloadExtension(old->id()); |
| - old = NULL; |
| + // Check if the extension's privileges have changed and disable the extension |
| + // if necessary. |
| + DisableIfPrivilegeIncrease(extension, allow_privilege_increase); |
| - if (!allow_silent_upgrade) { |
| - // Extension has changed permissions significantly. Disable it. We |
| - // send a notification below. |
| - extension_prefs_->SetExtensionState(extension, Extension::DISABLED); |
| - extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); |
| - } |
| - } |
| + switch (extension_prefs_->GetExtensionState(extension->id())) { |
| + case Extension::ENABLED: |
| + extensions_.push_back(scoped_extension); |
| - switch (extension_prefs_->GetExtensionState(extension->id())) { |
| - case Extension::ENABLED: |
| - extensions_.push_back(scoped_extension); |
| + NotifyExtensionLoaded(extension); |
| - NotifyExtensionLoaded(extension); |
| - |
| - ExtensionDOMUI::RegisterChromeURLOverrides(profile_, |
| - extension->GetChromeURLOverrides()); |
| - break; |
| - case Extension::DISABLED: |
| - disabled_extensions_.push_back(scoped_extension); |
| - NotificationService::current()->Notify( |
| - NotificationType::EXTENSION_UPDATE_DISABLED, |
| - Source<Profile>(profile_), |
| - Details<const Extension>(extension)); |
| - break; |
| - default: |
| - NOTREACHED(); |
| - break; |
| - } |
| + ExtensionDOMUI::RegisterChromeURLOverrides( |
| + profile_, extension->GetChromeURLOverrides()); |
| + break; |
| + case Extension::DISABLED: |
| + disabled_extensions_.push_back(scoped_extension); |
| + NotificationService::current()->Notify( |
| + NotificationType::EXTENSION_UPDATE_DISABLED, |
| + Source<Profile>(profile_), |
| + Details<const Extension>(extension)); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| } |
| SetBeingUpgraded(extension, false); |
| @@ -1580,6 +1564,83 @@ void ExtensionsService::OnExtensionLoaded(const Extension* extension, |
| } |
| } |
| +void ExtensionsService::DisableIfPrivilegeIncrease( |
| + const Extension* extension, bool allow_privilege_increase) { |
|
Aaron Boodman
2010/11/23 00:06:38
As we talked about in IRC, I think everything woul
|
| + // We keep track of all permissions the user has granted each extension. |
| + // This allows extensions to gracefully support backwards compatibility |
| + // by including unknown permissions in their manifests. When the user |
| + // installs the extension, only the recognized permissions are recorded. |
| + // When the unknown permissions become recognized (e.g., through browser |
| + // upgrade), we can prompt the user to accept these new permissions. |
| + // Extensions can also silently upgrade to less permissions, and then |
| + // silently upgrade to a version that adds these permissions back. |
| + // |
| + // For example, pretend that Chrome 10 includes a permission "omnibox" |
| + // for an API that adds suggestions to the omnibox. An extension can |
| + // maintain backwards compatibility while still having "omnibox" in the |
| + // manifest. If a user installs the extension on Chrome 9, the browser |
| + // will record the permissions it recognized, not including "omnibox." |
| + // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome |
| + // will disable the extension and prompt the user to approve the increase |
| + // in privileges. The extension could then release a new version that |
| + // removes the "omnibox" permission. When the user upgrades, Chrome will |
| + // still remember that "omnibox" had been granted, so that if the |
| + // extension once again includes "omnibox" in an upgrade, the extension |
| + // can upgrade without requiring this user's approval. |
| + const Extension* old = GetExtensionByIdInternal(extension->id(), |
| + true, true); |
| + std::set<std::string> granted_apis; |
| + ExtensionExtent granted_extent; |
| + |
| + bool is_extension_upgrade = old != NULL; |
| + bool is_privilege_increase = false; |
| + |
| + // We only record the granted permissions in the extension preferences |
| + // for extensions that aren't allowed to silently increase privileges. |
| + if (!allow_privilege_increase) { |
| + // Add all the recognized permissions to the extension's granted |
| + // permissions list if the granted permissions list hasn't been |
| + // initialized yet. |
| + if (!extension_prefs_->GetGrantedPermissions( |
| + extension->id(), &granted_apis, &granted_extent)) { |
| + GrantPermissions(extension); |
| + CHECK(extension_prefs_->GetGrantedPermissions( |
| + extension->id(), &granted_apis, &granted_extent)); |
| + } |
| + |
| + // Here, we check if an extension's privileges have increased in a manner |
| + // that requires the user's approval. This could occur because the browser |
| + // upgraded and recognized additional privileges, or an extension upgrades |
| + // to a version that requires additional privileges. |
| + is_privilege_increase = Extension::IsPrivilegeIncrease( |
| + granted_apis, granted_extent, old, extension); |
| + } |
| + |
| + if (is_extension_upgrade) { |
| + // CrxInstaller should have guaranteed that we aren't downgrading. |
| + CHECK(extension->version()->CompareTo(*(old->version())) >= 0); |
| + |
| + // Extensions get upgraded if the privileges are allowed to increase or |
| + // the privileges haven't increased. |
| + if (allow_privilege_increase || !is_privilege_increase) { |
| + SetBeingUpgraded(old, true); |
| + SetBeingUpgraded(extension, true); |
| + } |
| + |
| + // To upgrade an extension in place, unload the old one and |
| + // then load the new one. |
| + UnloadExtension(old->id()); |
| + old = NULL; |
| + } |
| + |
| + // Extension has changed permissions significantly. Disable it. A |
| + // notification should be sent by the caller. |
| + if (is_privilege_increase) { |
| + extension_prefs_->SetExtensionState(extension, Extension::DISABLED); |
| + extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); |
| + } |
| +} |
| + |
| void ExtensionsService::UpdateActiveExtensionsInCrashReporter() { |
| std::set<std::string> extension_ids; |
| for (size_t i = 0; i < extensions_.size(); ++i) { |