diff options
author | yoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-19 15:37:25 +0000 |
---|---|---|
committer | yoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-19 15:37:25 +0000 |
commit | c41003476ce57ae410821397bedc90310d3dc37b (patch) | |
tree | 6d5138b602c715658594caef851fdfa228662afc | |
parent | 2da80093a7b99a024427c5091b99926d970b108b (diff) | |
download | chromium_src-c41003476ce57ae410821397bedc90310d3dc37b.zip chromium_src-c41003476ce57ae410821397bedc90310d3dc37b.tar.gz chromium_src-c41003476ce57ae410821397bedc90310d3dc37b.tar.bz2 |
Move permission warning message handling from PermissionSet to PermissionMessageProvider.
This refactors PermissionSet to be closer to just a set of permissions and moves the understanding of permission message strings to a utility class.
BUG=162530
Review URL: https://codereview.chromium.org/27446002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229565 0039d316-1c4b-4281-b951-d872f2087c98
21 files changed, 634 insertions, 431 deletions
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc index 9fc6536..cf23aa0 100644 --- a/chrome/browser/extensions/api/permissions/permissions_api.cc +++ b/chrome/browser/extensions/api/permissions/permissions_api.cc @@ -14,6 +14,7 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/permissions/permissions_data.h" #include "extensions/common/error_utils.h" +#include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/permissions/permissions_info.h" #include "extensions/common/url_pattern_set.h" #include "url/gurl.h" @@ -205,8 +206,9 @@ bool PermissionsRequestFunction::RunImpl() { // We don't need to show the prompt if there are no new warnings, or if // we're skipping the confirmation UI. All extension types but INTERNAL // are allowed to silently increase their permission level. - bool has_no_warnings = requested_permissions_->GetWarningMessages( - GetExtension()->GetType()).empty(); + bool has_no_warnings = + PermissionMessageProvider::Get()->GetWarningMessages( + requested_permissions_, GetExtension()->GetType()).empty(); if (auto_confirm_for_tests == PROCEED || has_no_warnings || extension_->location() == Manifest::COMPONENT) { InstallUIProceed(); diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index 2526a53..5b45c47 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc @@ -48,6 +48,7 @@ #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/user_metrics.h" #include "extensions/common/manifest.h" +#include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/user_script.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -300,9 +301,10 @@ CrxInstallerError CrxInstaller::AllowInstall(const Extension* extension) { if (error.empty()) { scoped_refptr<const PermissionSet> expected_permissions = PermissionsData::GetActivePermissions(dummy_extension.get()); - valid = !(expected_permissions->HasLessPrivilegesThan( - PermissionsData::GetActivePermissions(extension), - extension->GetType())); + valid = !(PermissionMessageProvider::Get()->IsPrivilegeIncrease( + expected_permissions, + PermissionsData::GetActivePermissions(extension), + extension->GetType())); } } } diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc index 42767a1..0192142 100644 --- a/chrome/browser/extensions/extension_disabled_ui.cc +++ b/chrome/browser/extensions/extension_disabled_ui.cc @@ -34,6 +34,7 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_source.h" +#include "extensions/common/permissions/permission_message_provider.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" @@ -265,8 +266,8 @@ std::vector<string16> ExtensionDisabledGlobalError::GetBubbleViewMessages() { messages.push_back(l10n_util::GetStringUTF16( IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO)); std::vector<string16> permission_warnings = - extension_->GetActivePermissions()->GetWarningMessages( - extension_->GetType()); + extensions::PermissionMessageProvider::Get()->GetWarningMessages( + extension_->GetActivePermissions(), extension_->GetType()); for (size_t i = 0; i < permission_warnings.size(); ++i) { messages.push_back(l10n_util::GetStringFUTF16( IDS_EXTENSION_PERMISSION_LINE, permission_warnings[i])); diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc index ae201f1..66c7ab9 100644 --- a/chrome/browser/extensions/extension_install_prompt.cc +++ b/chrome/browser/extensions/extension_install_prompt.cc @@ -36,6 +36,7 @@ #include "extensions/common/extension_resource.h" #include "extensions/common/manifest.h" #include "extensions/common/manifest_constants.h" +#include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/url_pattern.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -801,9 +802,11 @@ void ExtensionInstallPrompt::ShowConfirmation() { Manifest::Type extension_type = extension_ ? extension_->GetType() : Manifest::TYPE_UNKNOWN; prompt_.SetPermissions( - permissions_->GetWarningMessages(extension_type)); + extensions::PermissionMessageProvider::Get()-> + GetWarningMessages(permissions_, extension_type)); prompt_.SetPermissionsDetails( - permissions_->GetWarningMessagesDetails(extension_type)); + extensions::PermissionMessageProvider::Get()-> + GetWarningMessagesDetails(permissions_, extension_type)); } switch (prompt_.type()) { diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 52df5fe..c560220 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -99,6 +99,7 @@ #include "extensions/common/error_utils.h" #include "extensions/common/manifest.h" #include "extensions/common/manifest_constants.h" +#include "extensions/common/permissions/permission_message_provider.h" #include "grit/generated_resources.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "sync/api/sync_change.h" @@ -2214,8 +2215,11 @@ void ExtensionService::CheckPermissionsIncrease(const Extension* extension, // 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 = granted_permissions->HasLessPrivilegesThan( - extension->GetActivePermissions().get(), extension->GetType()); + is_privilege_increase = + extensions::PermissionMessageProvider::Get()->IsPrivilegeIncrease( + granted_permissions, + extension->GetActivePermissions().get(), + extension->GetType()); } if (is_extension_installed) { diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index cbd4ec3..05ee3b14 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -251,6 +251,8 @@ 'common/extensions/permissions/chrome_api_permissions.h', 'common/extensions/permissions/chrome_scheme_hosts.cc', 'common/extensions/permissions/chrome_scheme_hosts.h', + 'common/extensions/permissions/chrome_permission_message_provider.cc', + 'common/extensions/permissions/chrome_permission_message_provider.h', 'common/extensions/permissions/media_galleries_permission.cc', 'common/extensions/permissions/media_galleries_permission.h', 'common/extensions/permissions/media_galleries_permission_data.cc', diff --git a/chrome/common/extensions/chrome_extensions_client.cc b/chrome/common/extensions/chrome_extensions_client.cc index fbebb8c..dcc4d5f 100644 --- a/chrome/common/extensions/chrome_extensions_client.cc +++ b/chrome/common/extensions/chrome_extensions_client.cc @@ -26,20 +26,25 @@ ChromeExtensionsClient::ChromeExtensionsClient() ChromeExtensionsClient::~ChromeExtensionsClient() { } +void ChromeExtensionsClient::Initialize() { + RegisterChromeManifestHandlers(); +} + const PermissionsProvider& ChromeExtensionsClient::GetPermissionsProvider() const { return chrome_api_permissions_; } +const PermissionMessageProvider& +ChromeExtensionsClient::GetPermissionMessageProvider() const { + return permission_message_provider_; +} + FeatureProvider* ChromeExtensionsClient::GetFeatureProviderByName( const std::string& name) const { return BaseFeatureProvider::GetByName(name); } -void ChromeExtensionsClient::RegisterManifestHandlers() const { - RegisterChromeManifestHandlers(); -} - void ChromeExtensionsClient::FilterHostPermissions( const URLPatternSet& hosts, URLPatternSet* new_hosts, diff --git a/chrome/common/extensions/chrome_extensions_client.h b/chrome/common/extensions/chrome_extensions_client.h index 4f14a9c..f832172 100644 --- a/chrome/common/extensions/chrome_extensions_client.h +++ b/chrome/common/extensions/chrome_extensions_client.h @@ -9,8 +9,8 @@ #include "base/compiler_specific.h" #include "base/lazy_instance.h" #include "chrome/common/extensions/permissions/chrome_api_permissions.h" +#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" #include "extensions/common/extensions_client.h" -#include "extensions/common/permissions/permissions_provider.h" namespace extensions { @@ -21,8 +21,11 @@ class ChromeExtensionsClient : public ExtensionsClient { ChromeExtensionsClient(); virtual ~ChromeExtensionsClient(); + virtual void Initialize() OVERRIDE; + virtual const PermissionsProvider& GetPermissionsProvider() const OVERRIDE; - virtual void RegisterManifestHandlers() const OVERRIDE; + virtual const PermissionMessageProvider& GetPermissionMessageProvider() const + OVERRIDE; virtual FeatureProvider* GetFeatureProviderByName(const std::string& name) const OVERRIDE; virtual void FilterHostPermissions( @@ -35,6 +38,7 @@ class ChromeExtensionsClient : public ExtensionsClient { private: const ChromeAPIPermissions chrome_api_permissions_; + const ChromePermissionMessageProvider permission_message_provider_; friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsClient>; diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc new file mode 100644 index 0000000..53f8700 --- /dev/null +++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc @@ -0,0 +1,261 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" + +#include "base/stl_util.h" +#include "chrome/common/extensions/permissions/permission_message_util.h" +#include "chrome/common/extensions/permissions/permission_set.h" +#include "extensions/common/extensions_client.h" +#include "extensions/common/permissions/permission_message.h" +#include "extensions/common/url_pattern_set.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace extensions { + +ChromePermissionMessageProvider::ChromePermissionMessageProvider() { +} + +ChromePermissionMessageProvider::~ChromePermissionMessageProvider() { +} + +// static +PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const { + PermissionMessages messages; + + if (permissions->HasEffectiveFullAccess()) { + messages.push_back(PermissionMessage( + PermissionMessage::kFullAccess, + l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS))); + return messages; + } + + std::set<PermissionMessage> host_msgs = + GetHostPermissionMessages(permissions, extension_type); + std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages(permissions); + messages.insert(messages.end(), host_msgs.begin(), host_msgs.end()); + messages.insert(messages.end(), api_msgs.begin(), api_msgs.end()); + + return messages; +} + +// static +std::vector<string16> ChromePermissionMessageProvider::GetWarningMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const { + std::vector<string16> message_strings; + PermissionMessages messages = + GetPermissionMessages(permissions, extension_type); + + bool audio_capture = false; + bool video_capture = false; + for (PermissionMessages::const_iterator i = messages.begin(); + i != messages.end(); ++i) { + switch (i->id()) { + case PermissionMessage::kAudioCapture: + audio_capture = true; + break; + case PermissionMessage::kVideoCapture: + video_capture = true; + break; + default: + break; + } + } + + for (PermissionMessages::const_iterator i = messages.begin(); + i != messages.end(); ++i) { + int id = i->id(); + if (audio_capture && video_capture) { + if (id == PermissionMessage::kAudioCapture) { + message_strings.push_back(l10n_util::GetStringUTF16( + IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE)); + continue; + } else if (id == PermissionMessage::kVideoCapture) { + // The combined message will be pushed above. + continue; + } + } + + message_strings.push_back(i->message()); + } + + return message_strings; +} + +// static +std::vector<string16> +ChromePermissionMessageProvider::GetWarningMessagesDetails( + const PermissionSet* permissions, + Manifest::Type extension_type) const { + std::vector<string16> message_strings; + PermissionMessages messages = + GetPermissionMessages(permissions, extension_type); + + for (PermissionMessages::const_iterator i = messages.begin(); + i != messages.end(); ++i) + message_strings.push_back(i->details()); + + return message_strings; +} + +// static +bool ChromePermissionMessageProvider::IsPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions, + Manifest::Type extension_type) const { + // Things can't get worse than native code access. + if (old_permissions->HasEffectiveFullAccess()) + return false; + + // Otherwise, it's a privilege increase if the new one has full access. + if (new_permissions->HasEffectiveFullAccess()) + return true; + + if (IsHostPrivilegeIncrease(old_permissions, new_permissions, extension_type)) + return true; + + if (IsAPIPrivilegeIncrease(old_permissions, new_permissions)) + return true; + + return false; +} + +std::set<PermissionMessage> +ChromePermissionMessageProvider::GetAPIPermissionMessages( + const PermissionSet* permissions) const { + std::set<PermissionMessage> messages; + for (APIPermissionSet::const_iterator permission_it = + permissions->apis().begin(); + permission_it != permissions->apis().end(); ++permission_it) { + if (permission_it->HasMessages()) { + PermissionMessages new_messages = permission_it->GetMessages(); + messages.insert(new_messages.begin(), new_messages.end()); + } + } + + // A special hack: If kFileSystemWriteDirectory would be displayed, hide + // kFileSystemDirectory and and kFileSystemWrite as the write directory + // message implies the other two. + // TODO(sammc): Remove this. See http://crbug.com/284849. + std::set<PermissionMessage>::iterator write_directory_message = + messages.find(PermissionMessage( + PermissionMessage::kFileSystemWriteDirectory, string16())); + if (write_directory_message != messages.end()) { + messages.erase( + PermissionMessage(PermissionMessage::kFileSystemWrite, string16())); + messages.erase( + PermissionMessage(PermissionMessage::kFileSystemDirectory, string16())); + } + + // A special hack: The warning message for declarativeWebRequest + // permissions speaks about blocking parts of pages, which is a + // subset of what the "<all_urls>" access allows. Therefore we + // display only the "<all_urls>" warning message if both permissions + // are required. + if (permissions->HasEffectiveAccessToAllHosts()) { + messages.erase( + PermissionMessage( + PermissionMessage::kDeclarativeWebRequest, string16())); + } + + return messages; +} + +std::set<PermissionMessage> +ChromePermissionMessageProvider::GetHostPermissionMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const { + std::set<PermissionMessage> messages; + // Since platform apps always use isolated storage, they can't (silently) + // access user data on other domains, so there's no need to prompt. + // Note: this must remain consistent with IsHostPrivilegeIncrease. + // See crbug.com/255229. + if (extension_type == Manifest::TYPE_PLATFORM_APP) + return messages; + + if (permissions->HasEffectiveAccessToAllHosts()) { + messages.insert(PermissionMessage( + PermissionMessage::kHostsAll, + l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS))); + } else { + URLPatternSet regular_hosts; + ExtensionsClient::Get()->FilterHostPermissions( + permissions->effective_hosts(), ®ular_hosts, &messages); + + std::set<std::string> hosts = + permission_message_util::GetDistinctHosts(regular_hosts, true, true); + if (!hosts.empty()) + messages.insert(permission_message_util::CreateFromHostList(hosts)); + } + return messages; +} + +bool ChromePermissionMessageProvider::IsAPIPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions) const { + if (new_permissions == NULL) + return false; + + typedef std::set<PermissionMessage> PermissionMsgSet; + PermissionMsgSet old_warnings = GetAPIPermissionMessages(old_permissions); + PermissionMsgSet new_warnings = GetAPIPermissionMessages(new_permissions); + PermissionMsgSet delta_warnings = + base::STLSetDifference<PermissionMsgSet>(new_warnings, old_warnings); + + // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and + // kFileSystemWrite. + // TODO(sammc): Remove this. See http://crbug.com/284849. + if (old_warnings.find(PermissionMessage( + PermissionMessage::kFileSystemWriteDirectory, string16())) != + old_warnings.end()) { + delta_warnings.erase( + PermissionMessage(PermissionMessage::kFileSystemDirectory, string16())); + delta_warnings.erase( + PermissionMessage(PermissionMessage::kFileSystemWrite, string16())); + } + + // We have less privileges if there are additional warnings present. + return !delta_warnings.empty(); +} + +bool ChromePermissionMessageProvider::IsHostPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions, + Manifest::Type extension_type) const { + // Platform apps host permission changes do not count as privilege increases. + // Note: this must remain consistent with GetHostPermissionMessages. + if (extension_type == Manifest::TYPE_PLATFORM_APP) + return false; + + // If the old permission set can access any host, then it can't be elevated. + if (old_permissions->HasEffectiveAccessToAllHosts()) + return false; + + // Likewise, if the new permission set has full host access, then it must be + // a privilege increase. + if (new_permissions->HasEffectiveAccessToAllHosts()) + return true; + + const URLPatternSet& old_list = old_permissions->effective_hosts(); + const URLPatternSet& new_list = new_permissions->effective_hosts(); + + // TODO(jstritar): This is overly conservative with respect to subdomains. + // For example, going from *.google.com to www.google.com will be + // considered an elevation, even though it is not (http://crbug.com/65337). + std::set<std::string> new_hosts_set( + permission_message_util::GetDistinctHosts(new_list, false, false)); + std::set<std::string> old_hosts_set( + permission_message_util::GetDistinctHosts(old_list, false, false)); + std::set<std::string> new_hosts_only = + base::STLSetDifference<std::set<std::string> >(new_hosts_set, + old_hosts_set); + + return !new_hosts_only.empty(); +} + +} // namespace extensions diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.h b/chrome/common/extensions/permissions/chrome_permission_message_provider.h new file mode 100644 index 0000000..05125f4 --- /dev/null +++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.h @@ -0,0 +1,65 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_PERMISSION_MESSAGE_PROVIDER_H_ +#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_PERMISSION_MESSAGE_PROVIDER_H_ + +#include <set> + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/strings/string16.h" +#include "extensions/common/permissions/permission_message_provider.h" + +namespace extensions { + +class ChromePermissionMessageProvider : public PermissionMessageProvider { + public: + ChromePermissionMessageProvider(); + virtual ~ChromePermissionMessageProvider(); + + // PermissionMessageProvider implementation. + virtual PermissionMessages GetPermissionMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const OVERRIDE; + virtual std::vector<string16> GetWarningMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const OVERRIDE; + virtual std::vector<string16> GetWarningMessagesDetails( + const PermissionSet* permissions, + Manifest::Type extension_type) const OVERRIDE; + virtual bool IsPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions, + Manifest::Type extension_type) const OVERRIDE; + + private: + // Gets the permission messages for the API permissions. + std::set<PermissionMessage> GetAPIPermissionMessages( + const PermissionSet* permissions) const; + + // Gets the permission messages for the host permissions. + std::set<PermissionMessage> GetHostPermissionMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const; + + // Returns true if |new_permissions| has an elevated API privilege level + // compared to |old_permissions|. + bool IsAPIPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions) const; + + // Returns true if |new_permissions| has more host permissions compared to + // |old_permissions|. + bool IsHostPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions, + Manifest::Type extension_type) const; + + DISALLOW_COPY_AND_ASSIGN(ChromePermissionMessageProvider); +}; + +} // namespace extensions + +#endif // CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_PERMISSION_MESSAGE_PROVIDER_H_ diff --git a/chrome/common/extensions/permissions/permission_message_util.cc b/chrome/common/extensions/permissions/permission_message_util.cc index 272ad49..bb43236 100644 --- a/chrome/common/extensions/permissions/permission_message_util.cc +++ b/chrome/common/extensions/permissions/permission_message_util.cc @@ -6,11 +6,34 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/common/extensions/permissions/permission_set.h" +#include "content/public/common/url_constants.h" #include "extensions/common/permissions/permission_message.h" +#include "extensions/common/url_pattern_set.h" #include "grit/generated_resources.h" +#include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "ui/base/l10n/l10n_util.h" using extensions::PermissionMessage; +using extensions::PermissionSet; +using extensions::URLPatternSet; + +namespace { + +// Helper for GetDistinctHosts(): com > net > org > everything else. +bool RcdBetterThan(const std::string& a, const std::string& b) { + if (a == b) + return false; + if (a == "com") + return true; + if (a == "net") + return b != "com"; + if (a == "org") + return b != "com" && b != "net"; + return false; +} + +} // namespace namespace permission_message_util { @@ -69,4 +92,59 @@ PermissionMessage CreateFromHostList(const std::set<std::string>& hosts) { return PermissionMessage(message_id, message, details); } +std::set<std::string> GetDistinctHosts( + const URLPatternSet& host_patterns, + bool include_rcd, + bool exclude_file_scheme) { + // Use a vector to preserve order (also faster than a map on small sets). + // Each item is a host split into two parts: host without RCDs and + // current best RCD. + typedef std::vector<std::pair<std::string, std::string> > HostVector; + HostVector hosts_best_rcd; + for (URLPatternSet::const_iterator i = host_patterns.begin(); + i != host_patterns.end(); ++i) { + if (exclude_file_scheme && i->scheme() == chrome::kFileScheme) + continue; + + std::string host = i->host(); + + // Add the subdomain wildcard back to the host, if necessary. + if (i->match_subdomains()) + host = "*." + host; + + // If the host has an RCD, split it off so we can detect duplicates. + std::string rcd; + size_t reg_len = net::registry_controlled_domains::GetRegistryLength( + host, + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); + if (reg_len && reg_len != std::string::npos) { + if (include_rcd) // else leave rcd empty + rcd = host.substr(host.size() - reg_len); + host = host.substr(0, host.size() - reg_len); + } + + // Check if we've already seen this host. + HostVector::iterator it = hosts_best_rcd.begin(); + for (; it != hosts_best_rcd.end(); ++it) { + if (it->first == host) + break; + } + // If this host was found, replace the RCD if this one is better. + if (it != hosts_best_rcd.end()) { + if (include_rcd && RcdBetterThan(rcd, it->second)) + it->second = rcd; + } else { // Previously unseen host, append it. + hosts_best_rcd.push_back(std::make_pair(host, rcd)); + } + } + + // Build up the final vector by concatenating hosts and RCDs. + std::set<std::string> distinct_hosts; + for (HostVector::iterator it = hosts_best_rcd.begin(); + it != hosts_best_rcd.end(); ++it) + distinct_hosts.insert(it->first + it->second); + return distinct_hosts; +} + } // namespace permission_message_util diff --git a/chrome/common/extensions/permissions/permission_message_util.h b/chrome/common/extensions/permissions/permission_message_util.h index 1ff5a5a..13b41c1 100644 --- a/chrome/common/extensions/permissions/permission_message_util.h +++ b/chrome/common/extensions/permissions/permission_message_util.h @@ -10,6 +10,8 @@ namespace extensions { class PermissionMessage; +class PermissionSet; +class URLPatternSet; } namespace permission_message_util { @@ -19,6 +21,11 @@ namespace permission_message_util { extensions::PermissionMessage CreateFromHostList( const std::set<std::string>& hosts); +std::set<std::string> GetDistinctHosts( + const extensions::URLPatternSet& host_patterns, + bool include_rcd, + bool exclude_file_scheme); + } // namespace permission_message_util #endif // CHROME_COMMON_EXTENSIONS_PERMISSIONS_PERMISSION_MESSAGE_UTIL_H_ diff --git a/chrome/common/extensions/permissions/permission_set.cc b/chrome/common/extensions/permissions/permission_set.cc index 103a80c..9c97014 100644 --- a/chrome/common/extensions/permissions/permission_set.cc +++ b/chrome/common/extensions/permissions/permission_set.cc @@ -8,35 +8,15 @@ #include <iterator> #include <string> -#include "base/stl_util.h" -#include "chrome/common/extensions/permissions/permission_message_util.h" -#include "content/public/common/url_constants.h" -#include "extensions/common/extensions_client.h" #include "extensions/common/permissions/permissions_info.h" #include "extensions/common/url_pattern.h" #include "extensions/common/url_pattern_set.h" -#include "grit/generated_resources.h" -#include "net/base/registry_controlled_domains/registry_controlled_domain.h" -#include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" using extensions::URLPatternSet; namespace { -// Helper for GetDistinctHosts(): com > net > org > everything else. -bool RcdBetterThan(const std::string& a, const std::string& b) { - if (a == b) - return false; - if (a == "com") - return true; - if (a == "net") - return b != "com"; - if (a == "org") - return b != "com" && b != "net"; - return false; -} - void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) { DCHECK(out); for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) { @@ -161,79 +141,6 @@ std::set<std::string> PermissionSet::GetAPIsAsStrings() const { return apis_str; } -PermissionMessages PermissionSet::GetPermissionMessages( - Manifest::Type extension_type) const { - PermissionMessages messages; - - if (HasEffectiveFullAccess()) { - messages.push_back(PermissionMessage( - PermissionMessage::kFullAccess, - l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS))); - return messages; - } - - std::set<PermissionMessage> host_msgs = - GetHostPermissionMessages(extension_type); - std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages(); - messages.insert(messages.end(), host_msgs.begin(), host_msgs.end()); - messages.insert(messages.end(), api_msgs.begin(), api_msgs.end()); - - return messages; -} - -std::vector<string16> PermissionSet::GetWarningMessages( - Manifest::Type extension_type) const { - std::vector<string16> messages; - PermissionMessages permissions = GetPermissionMessages(extension_type); - - bool audio_capture = false; - bool video_capture = false; - for (PermissionMessages::const_iterator i = permissions.begin(); - i != permissions.end(); ++i) { - switch (i->id()) { - case PermissionMessage::kAudioCapture: - audio_capture = true; - break; - case PermissionMessage::kVideoCapture: - video_capture = true; - break; - default: - break; - } - } - - for (PermissionMessages::const_iterator i = permissions.begin(); - i != permissions.end(); ++i) { - int id = i->id(); - if (audio_capture && video_capture) { - if (id == PermissionMessage::kAudioCapture) { - messages.push_back(l10n_util::GetStringUTF16( - IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE)); - continue; - } else if (id == PermissionMessage::kVideoCapture) { - // The combined message will be pushed above. - continue; - } - } - - messages.push_back(i->message()); - } - - return messages; -} - -std::vector<string16> PermissionSet::GetWarningMessagesDetails( - Manifest::Type extension_type) const { - std::vector<string16> messages; - PermissionMessages permissions = GetPermissionMessages(extension_type); - - for (PermissionMessages::const_iterator i = permissions.begin(); - i != permissions.end(); ++i) - messages.push_back(i->details()); - - return messages; -} - bool PermissionSet::IsEmpty() const { // Not default if any host permissions are present. if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty())) @@ -313,84 +220,8 @@ bool PermissionSet::HasEffectiveFullAccess() const { return false; } -bool PermissionSet::HasLessPrivilegesThan( - const PermissionSet* permissions, - Manifest::Type extension_type) const { - // Things can't get worse than native code access. - if (HasEffectiveFullAccess()) - return false; - - // Otherwise, it's a privilege increase if the new one has full access. - if (permissions->HasEffectiveFullAccess()) - return true; - - if (HasLessHostPrivilegesThan(permissions, extension_type)) - return true; - - if (HasLessAPIPrivilegesThan(permissions)) - return true; - - return false; -} - PermissionSet::~PermissionSet() {} -// static -std::set<std::string> PermissionSet::GetDistinctHosts( - const URLPatternSet& host_patterns, - bool include_rcd, - bool exclude_file_scheme) { - // Use a vector to preserve order (also faster than a map on small sets). - // Each item is a host split into two parts: host without RCDs and - // current best RCD. - typedef std::vector<std::pair<std::string, std::string> > HostVector; - HostVector hosts_best_rcd; - for (URLPatternSet::const_iterator i = host_patterns.begin(); - i != host_patterns.end(); ++i) { - if (exclude_file_scheme && i->scheme() == chrome::kFileScheme) - continue; - - std::string host = i->host(); - - // Add the subdomain wildcard back to the host, if necessary. - if (i->match_subdomains()) - host = "*." + host; - - // If the host has an RCD, split it off so we can detect duplicates. - std::string rcd; - size_t reg_len = net::registry_controlled_domains::GetRegistryLength( - host, - net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, - net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); - if (reg_len && reg_len != std::string::npos) { - if (include_rcd) // else leave rcd empty - rcd = host.substr(host.size() - reg_len); - host = host.substr(0, host.size() - reg_len); - } - - // Check if we've already seen this host. - HostVector::iterator it = hosts_best_rcd.begin(); - for (; it != hosts_best_rcd.end(); ++it) { - if (it->first == host) - break; - } - // If this host was found, replace the RCD if this one is better. - if (it != hosts_best_rcd.end()) { - if (include_rcd && RcdBetterThan(rcd, it->second)) - it->second = rcd; - } else { // Previously unseen host, append it. - hosts_best_rcd.push_back(std::make_pair(host, rcd)); - } - } - - // Build up the final vector by concatenating hosts and RCDs. - std::set<std::string> distinct_hosts; - for (HostVector::iterator it = hosts_best_rcd.begin(); - it != hosts_best_rcd.end(); ++it) - distinct_hosts.insert(it->first + it->second); - return distinct_hosts; -} - void PermissionSet::InitImplicitPermissions() { // The downloads permission implies the internal version as well. if (apis_.find(APIPermission::kDownloads) != apis_.end()) @@ -417,127 +248,4 @@ void PermissionSet::InitEffectiveHosts() { explicit_hosts(), scriptable_hosts(), &effective_hosts_); } -std::set<PermissionMessage> PermissionSet::GetAPIPermissionMessages() const { - std::set<PermissionMessage> messages; - for (APIPermissionSet::const_iterator permission_it = apis_.begin(); - permission_it != apis_.end(); ++permission_it) { - if (permission_it->HasMessages()) { - PermissionMessages new_messages = permission_it->GetMessages(); - messages.insert(new_messages.begin(), new_messages.end()); - } - } - - // A special hack: If kFileSystemWriteDirectory would be displayed, hide - // kFileSystemDirectory and and kFileSystemWrite as the write directory - // message implies the other two. - // TODO(sammc): Remove this. See http://crbug.com/284849. - std::set<PermissionMessage>::iterator write_directory_message = - messages.find(PermissionMessage( - PermissionMessage::kFileSystemWriteDirectory, string16())); - if (write_directory_message != messages.end()) { - messages.erase( - PermissionMessage(PermissionMessage::kFileSystemWrite, string16())); - messages.erase( - PermissionMessage(PermissionMessage::kFileSystemDirectory, string16())); - } - - // A special hack: The warning message for declarativeWebRequest - // permissions speaks about blocking parts of pages, which is a - // subset of what the "<all_urls>" access allows. Therefore we - // display only the "<all_urls>" warning message if both permissions - // are required. - if (HasEffectiveAccessToAllHosts()) { - messages.erase( - PermissionMessage( - PermissionMessage::kDeclarativeWebRequest, string16())); - } - - return messages; -} - -std::set<PermissionMessage> PermissionSet::GetHostPermissionMessages( - Manifest::Type extension_type) const { - // Since platform apps always use isolated storage, they can't (silently) - // access user data on other domains, so there's no need to prompt. - // Note: this must remain consistent with HasLessHostPrivilegesThan. - // See crbug.com/255229. - std::set<PermissionMessage> messages; - if (extension_type == Manifest::TYPE_PLATFORM_APP) - return messages; - - if (HasEffectiveAccessToAllHosts()) { - messages.insert(PermissionMessage( - PermissionMessage::kHostsAll, - l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS))); - } else { - URLPatternSet regular_hosts; - ExtensionsClient::Get()->FilterHostPermissions( - effective_hosts_, ®ular_hosts, &messages); - - std::set<std::string> hosts = GetDistinctHosts(regular_hosts, true, true); - if (!hosts.empty()) - messages.insert(permission_message_util::CreateFromHostList(hosts)); - } - return messages; -} - -bool PermissionSet::HasLessAPIPrivilegesThan( - const PermissionSet* permissions) const { - if (permissions == NULL) - return false; - - typedef std::set<PermissionMessage> PermissionMsgSet; - PermissionMsgSet current_warnings = GetAPIPermissionMessages(); - PermissionMsgSet new_warnings = permissions->GetAPIPermissionMessages(); - PermissionMsgSet delta_warnings = - base::STLSetDifference<PermissionMsgSet>(new_warnings, current_warnings); - - // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and - // kFileSystemWrite. - // TODO(sammc): Remove this. See http://crbug.com/284849. - if (current_warnings.find(PermissionMessage( - PermissionMessage::kFileSystemWriteDirectory, string16())) != - current_warnings.end()) { - delta_warnings.erase( - PermissionMessage(PermissionMessage::kFileSystemDirectory, string16())); - delta_warnings.erase( - PermissionMessage(PermissionMessage::kFileSystemWrite, string16())); - } - - // We have less privileges if there are additional warnings present. - return !delta_warnings.empty(); -} - -bool PermissionSet::HasLessHostPrivilegesThan( - const PermissionSet* permissions, - Manifest::Type extension_type) const { - // Platform apps host permission changes do not count as privilege increases. - // Note: this must remain consistent with GetHostPermissionMessages. - if (extension_type == Manifest::TYPE_PLATFORM_APP) - return false; - - // If this permission set can access any host, then it can't be elevated. - if (HasEffectiveAccessToAllHosts()) - return false; - - // Likewise, if the other permission set has full host access, then it must be - // a privilege increase. - if (permissions->HasEffectiveAccessToAllHosts()) - return true; - - const URLPatternSet& old_list = effective_hosts(); - const URLPatternSet& new_list = permissions->effective_hosts(); - - // TODO(jstritar): This is overly conservative with respect to subdomains. - // For example, going from *.google.com to www.google.com will be - // considered an elevation, even though it is not (http://crbug.com/65337). - std::set<std::string> new_hosts_set(GetDistinctHosts(new_list, false, false)); - std::set<std::string> old_hosts_set(GetDistinctHosts(old_list, false, false)); - std::set<std::string> new_hosts_only = - base::STLSetDifference<std::set<std::string> >(new_hosts_set, - old_hosts_set); - - return !new_hosts_only.empty(); -} - } // namespace extensions diff --git a/chrome/common/extensions/permissions/permission_set.h b/chrome/common/extensions/permissions/permission_set.h index 0f78bda..e4cbd43 100644 --- a/chrome/common/extensions/permissions/permission_set.h +++ b/chrome/common/extensions/permissions/permission_set.h @@ -17,7 +17,6 @@ #include "extensions/common/manifest.h" #include "extensions/common/permissions/api_permission.h" #include "extensions/common/permissions/api_permission_set.h" -#include "extensions/common/permissions/permission_message.h" #include "extensions/common/url_pattern_set.h" namespace extensions { @@ -65,20 +64,6 @@ class PermissionSet // Gets the API permissions in this set as a set of strings. std::set<std::string> GetAPIsAsStrings() const; - // Gets the localized permission messages that represent this set. - // The set of permission messages shown varies by extension type. - PermissionMessages GetPermissionMessages(Manifest::Type extension_type) const; - - // Gets the localized permission messages that represent this set (represented - // as strings). The set of permission messages shown varies by extension type. - std::vector<string16> GetWarningMessages(Manifest::Type extension_type) const; - - // Gets the localized permission details for messages that represent this set - // (represented as strings). The set of permission messages shown varies by - // extension type. - std::vector<string16> GetWarningMessagesDetails( - Manifest::Type extension_type) const; - // Returns true if this is an empty set (e.g., the default permission set). bool IsEmpty() const; @@ -115,12 +100,6 @@ class PermissionSet // (e.g. native code). bool HasEffectiveFullAccess() const; - // Returns true if |permissions| has a greater privilege level than this - // permission set (e.g., this permission set has less permissions). - // Whether certain permissions are considered varies by extension type. - bool HasLessPrivilegesThan(const PermissionSet* permissions, - Manifest::Type extension_type) const; - const APIPermissionSet& apis() const { return apis_; } const URLPatternSet& effective_hosts() const { return effective_hosts_; } @@ -130,50 +109,19 @@ class PermissionSet const URLPatternSet& scriptable_hosts() const { return scriptable_hosts_; } private: - FRIEND_TEST_ALL_PREFIXES(PermissionsTest, HasLessHostPrivilegesThan); FRIEND_TEST_ALL_PREFIXES(PermissionsTest, GetWarningMessages_AudioVideo); - FRIEND_TEST_ALL_PREFIXES(PermissionsTest, GetDistinctHosts); - FRIEND_TEST_ALL_PREFIXES(PermissionsTest, - GetDistinctHosts_ComIsBestRcd); - FRIEND_TEST_ALL_PREFIXES(PermissionsTest, - GetDistinctHosts_NetIs2ndBestRcd); - FRIEND_TEST_ALL_PREFIXES(PermissionsTest, - GetDistinctHosts_OrgIs3rdBestRcd); - FRIEND_TEST_ALL_PREFIXES(PermissionsTest, - GetDistinctHosts_FirstInListIs4thBestRcd); friend class base::RefCountedThreadSafe<PermissionSet>; ~PermissionSet(); void AddAPIPermission(APIPermission::ID id); - static std::set<std::string> GetDistinctHosts( - const URLPatternSet& host_patterns, - bool include_rcd, - bool exclude_file_scheme); - // Adds permissions implied independently of other context. void InitImplicitPermissions(); // Initializes the effective host permission based on the data in this set. void InitEffectiveHosts(); - // Gets the permission messages for the API permissions. - std::set<PermissionMessage> GetAPIPermissionMessages() const; - - // Gets the permission messages for the host permissions. - std::set<PermissionMessage> GetHostPermissionMessages( - Manifest::Type extension_type) const; - - // Returns true if |permissions| has an elevated API privilege level than - // this set. - bool HasLessAPIPrivilegesThan(const PermissionSet* permissions) const; - - // Returns true if |permissions| has more host permissions compared to this - // set. - bool HasLessHostPrivilegesThan(const PermissionSet* permissions, - Manifest::Type extension_type) const; - // The api list is used when deciding if an extension can access certain // extension APIs and features. APIPermissionSet apis_; diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc index ef0610f..175b0f7 100644 --- a/chrome/common/extensions/permissions/permission_set_unittest.cc +++ b/chrome/common/extensions/permissions/permission_set_unittest.cc @@ -12,10 +12,13 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_test_util.h" #include "chrome/common/extensions/features/feature_channel.h" +#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" +#include "chrome/common/extensions/permissions/permission_message_util.h" #include "chrome/common/extensions/permissions/permission_set.h" #include "chrome/common/extensions/permissions/permissions_data.h" #include "chrome/common/extensions/permissions/socket_permission.h" #include "extensions/common/error_utils.h" +#include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/permissions/permissions_info.h" #include "testing/gtest/include/gtest/gtest.h" @@ -565,7 +568,7 @@ TEST(PermissionsTest, CreateDifference) { EXPECT_TRUE(set1->IsEmpty()); } -TEST(PermissionsTest, HasLessPrivilegesThan) { +TEST(PermissionsTest, IsPrivilegeIncrease) { const struct { const char* base_name; bool expect_increase; @@ -621,7 +624,8 @@ TEST(PermissionsTest, HasLessPrivilegesThan) { Manifest::Type extension_type = old_extension->GetType(); EXPECT_EQ(kTests[i].expect_increase, - old_p->HasLessPrivilegesThan(new_p.get(), extension_type)) + PermissionMessageProvider::Get()->IsPrivilegeIncrease( + old_p.get(), new_p.get(), extension_type)) << kTests[i].base_name; } } @@ -769,7 +773,8 @@ TEST(PermissionsTest, FileSystemPermissionMessages) { scoped_refptr<PermissionSet> permissions( new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet())); PermissionMessages messages = - permissions->GetPermissionMessages(Manifest::TYPE_PLATFORM_APP); + PermissionMessageProvider::Get()->GetPermissionMessages( + permissions, Manifest::TYPE_PLATFORM_APP); ASSERT_EQ(2u, messages.size()); std::sort(messages.begin(), messages.end()); std::set<PermissionMessage::ID> ids; @@ -789,7 +794,8 @@ TEST(PermissionsTest, HiddenFileSystemPermissionMessages) { scoped_refptr<PermissionSet> permissions( new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet())); PermissionMessages messages = - permissions->GetPermissionMessages(Manifest::TYPE_PLATFORM_APP); + PermissionMessageProvider::Get()->GetPermissionMessages( + permissions, Manifest::TYPE_PLATFORM_APP); ASSERT_EQ(1u, messages.size()); EXPECT_EQ(PermissionMessage::kFileSystemWriteDirectory, messages[0].id()); } @@ -811,18 +817,25 @@ TEST(PermissionsTest, MergedFileSystemPermissionComparison) { scoped_refptr<PermissionSet> write_directory_permissions(new PermissionSet( write_directory_api_permissions, URLPatternSet(), URLPatternSet())); - EXPECT_FALSE(write_directory_permissions->HasLessPrivilegesThan( - write_permissions, Manifest::TYPE_PLATFORM_APP)); - EXPECT_FALSE(write_directory_permissions->HasLessPrivilegesThan( - directory_permissions, Manifest::TYPE_PLATFORM_APP)); - EXPECT_TRUE(write_permissions->HasLessPrivilegesThan( - directory_permissions, Manifest::TYPE_PLATFORM_APP)); - EXPECT_TRUE(write_permissions->HasLessPrivilegesThan( - write_directory_permissions, Manifest::TYPE_PLATFORM_APP)); - EXPECT_TRUE(directory_permissions->HasLessPrivilegesThan( - write_permissions, Manifest::TYPE_PLATFORM_APP)); - EXPECT_TRUE(directory_permissions->HasLessPrivilegesThan( - write_directory_permissions, Manifest::TYPE_PLATFORM_APP)); + const PermissionMessageProvider* provider = PermissionMessageProvider::Get(); + EXPECT_FALSE(provider->IsPrivilegeIncrease(write_directory_permissions, + write_permissions, + Manifest::TYPE_PLATFORM_APP)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(write_directory_permissions, + directory_permissions, + Manifest::TYPE_PLATFORM_APP)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(write_permissions, + directory_permissions, + Manifest::TYPE_PLATFORM_APP)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(write_permissions, + write_directory_permissions, + Manifest::TYPE_PLATFORM_APP)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions, + write_permissions, + Manifest::TYPE_PLATFORM_APP)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions, + write_directory_permissions, + Manifest::TYPE_PLATFORM_APP)); } TEST(PermissionsTest, GetWarningMessages_ManyHosts) { @@ -858,11 +871,12 @@ TEST(PermissionsTest, GetWarningMessages_AudioVideo) { // Both audio and video present. scoped_refptr<Extension> extension = LoadManifest("permissions", "audio-video.json"); + const PermissionMessageProvider* provider = PermissionMessageProvider::Get(); PermissionSet* set = const_cast<PermissionSet*>( extension->GetActivePermissions().get()); std::vector<string16> warnings = - set->GetWarningMessages(extension->GetType()); + provider->GetWarningMessages(set, extension->GetType()); EXPECT_FALSE(Contains(warnings, "Use your microphone")); EXPECT_FALSE(Contains(warnings, "Use your camera")); EXPECT_TRUE(Contains(warnings, "Use your microphone and camera")); @@ -871,7 +885,7 @@ TEST(PermissionsTest, GetWarningMessages_AudioVideo) { // Just audio present. set->apis_.erase(APIPermission::kVideoCapture); - warnings = set->GetWarningMessages(extension->GetType()); + warnings = provider->GetWarningMessages(set, extension->GetType()); EXPECT_EQ(combined_size, warnings.size()); EXPECT_EQ(combined_index, IndexOf(warnings, "Use your microphone")); EXPECT_FALSE(Contains(warnings, "Use your camera")); @@ -880,7 +894,7 @@ TEST(PermissionsTest, GetWarningMessages_AudioVideo) { // Just video present. set->apis_.erase(APIPermission::kAudioCapture); set->apis_.insert(APIPermission::kVideoCapture); - warnings = set->GetWarningMessages(extension->GetType()); + warnings = provider->GetWarningMessages(set, extension->GetType()); EXPECT_EQ(combined_size, warnings.size()); EXPECT_FALSE(Contains(warnings, "Use your microphone")); EXPECT_FALSE(Contains(warnings, "Use your microphone and camera")); @@ -901,9 +915,10 @@ TEST(PermissionsTest, GetWarningMessages_DeclarativeWebRequest) { // permissions do not cover all hosts. scoped_refptr<Extension> extension = LoadManifest("permissions", "web_request_com_host_permissions.json"); + const PermissionMessageProvider* provider = PermissionMessageProvider::Get(); const PermissionSet* set = extension->GetActivePermissions().get(); std::vector<string16> warnings = - set->GetWarningMessages(extension->GetType()); + provider->GetWarningMessages(set, extension->GetType()); EXPECT_TRUE(Contains(warnings, "Block parts of web pages")); EXPECT_FALSE(Contains(warnings, "Access your data on all websites")); @@ -912,7 +927,7 @@ TEST(PermissionsTest, GetWarningMessages_DeclarativeWebRequest) { extension = LoadManifest("permissions", "web_request_all_host_permissions.json"); set = extension->GetActivePermissions().get(); - warnings = set->GetWarningMessages(extension->GetType()); + warnings = provider->GetWarningMessages(set, extension->GetType()); EXPECT_FALSE(Contains(warnings, "Block parts of web pages")); EXPECT_TRUE(Contains(warnings, "Access your data on all websites")); } @@ -1027,7 +1042,8 @@ TEST(PermissionsTest, GetDistinctHosts) { explicit_hosts.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path")); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } { @@ -1039,7 +1055,8 @@ TEST(PermissionsTest, GetDistinctHosts) { explicit_hosts.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path")); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } { @@ -1049,7 +1066,8 @@ TEST(PermissionsTest, GetDistinctHosts) { explicit_hosts.AddPattern( URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path")); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } { @@ -1059,7 +1077,8 @@ TEST(PermissionsTest, GetDistinctHosts) { explicit_hosts.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath")); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } { @@ -1075,7 +1094,8 @@ TEST(PermissionsTest, GetDistinctHosts) { expected.insert("bar.com"); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } { @@ -1105,7 +1125,8 @@ TEST(PermissionsTest, GetDistinctHosts) { expected.insert("www.foo.xyzzy"); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } { @@ -1117,7 +1138,8 @@ TEST(PermissionsTest, GetDistinctHosts) { expected.insert("*.google.com"); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } { @@ -1139,8 +1161,8 @@ TEST(PermissionsTest, GetDistinctHosts) { scoped_refptr<PermissionSet> perm_set(new PermissionSet( empty_perms, explicit_hosts, scriptable_hosts)); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(perm_set->effective_hosts(), - true, true)); + permission_message_util::GetDistinctHosts( + perm_set->effective_hosts(), true, true)); } { @@ -1154,7 +1176,8 @@ TEST(PermissionsTest, GetDistinctHosts) { URLPattern(URLPattern::SCHEME_FILE, "file:///*")); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } } @@ -1176,7 +1199,8 @@ TEST(PermissionsTest, GetDistinctHosts_ComIsBestRcd) { std::set<std::string> expected; expected.insert("www.foo.com"); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } TEST(PermissionsTest, GetDistinctHosts_NetIs2ndBestRcd) { @@ -1196,7 +1220,8 @@ TEST(PermissionsTest, GetDistinctHosts_NetIs2ndBestRcd) { std::set<std::string> expected; expected.insert("www.foo.net"); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } TEST(PermissionsTest, GetDistinctHosts_OrgIs3rdBestRcd) { @@ -1215,7 +1240,8 @@ TEST(PermissionsTest, GetDistinctHosts_OrgIs3rdBestRcd) { std::set<std::string> expected; expected.insert("www.foo.org"); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } TEST(PermissionsTest, GetDistinctHosts_FirstInListIs4thBestRcd) { @@ -1233,11 +1259,13 @@ TEST(PermissionsTest, GetDistinctHosts_FirstInListIs4thBestRcd) { std::set<std::string> expected; expected.insert("www.foo.ca"); EXPECT_EQ(expected, - PermissionSet::GetDistinctHosts(explicit_hosts, true, true)); + permission_message_util::GetDistinctHosts( + explicit_hosts, true, true)); } -TEST(PermissionsTest, HasLessHostPrivilegesThan) { - Manifest::Type extension_type = Manifest::TYPE_EXTENSION; +TEST(PermissionsTest, IsHostPrivilegeIncrease) { + Manifest::Type type = Manifest::TYPE_EXTENSION; + const PermissionMessageProvider* provider = PermissionMessageProvider::Get(); URLPatternSet elist1; URLPatternSet elist2; URLPatternSet slist1; @@ -1259,33 +1287,33 @@ TEST(PermissionsTest, HasLessHostPrivilegesThan) { set1 = new PermissionSet(empty_perms, elist1, slist1); set2 = new PermissionSet(empty_perms, elist2, slist2); - EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type)); - EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type)); // Test that paths are ignored. elist2.ClearPatterns(); elist2.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*")); set2 = new PermissionSet(empty_perms, elist2, slist2); - EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type)); - EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type)); // Test that RCDs are ignored. elist2.ClearPatterns(); elist2.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*")); set2 = new PermissionSet(empty_perms, elist2, slist2); - EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type)); - EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type)); // Test that subdomain wildcards are handled properly. elist2.ClearPatterns(); elist2.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*")); set2 = new PermissionSet(empty_perms, elist2, slist2); - EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type)); // TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337 - // EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get())); + // EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type)); // Test that different domains count as different hosts. elist2.ClearPatterns(); @@ -1294,21 +1322,21 @@ TEST(PermissionsTest, HasLessHostPrivilegesThan) { elist2.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path")); set2 = new PermissionSet(empty_perms, elist2, slist2); - EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type)); - EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type)); // Test that different subdomains count as different hosts. elist2.ClearPatterns(); elist2.AddPattern( URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*")); set2 = new PermissionSet(empty_perms, elist2, slist2); - EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type)); - EXPECT_TRUE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type)); + EXPECT_TRUE(provider->IsPrivilegeIncrease(set2, set1, type)); // Test that platform apps do not have host permissions increases. - extension_type = Manifest::TYPE_PLATFORM_APP; - EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type)); - EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type)); + type = Manifest::TYPE_PLATFORM_APP; + EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type)); + EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type)); } TEST(PermissionsTest, GetAPIsAsStrings) { @@ -1400,10 +1428,11 @@ TEST(PermissionsTest, ChromeURLs) { URLPattern(URLPattern::SCHEME_ALL, "chrome://thumb/")); scoped_refptr<PermissionSet> permissions( new PermissionSet(APIPermissionSet(), allowed_hosts, URLPatternSet())); - permissions->GetPermissionMessages(Manifest::TYPE_EXTENSION); + PermissionMessageProvider::Get()-> + GetPermissionMessages(permissions, Manifest::TYPE_EXTENSION); } -TEST(PermissionsTest, HasLessPrivilegesThan_DeclarativeWebRequest) { +TEST(PermissionsTest, IsPrivilegeIncrease_DeclarativeWebRequest) { scoped_refptr<Extension> extension( LoadManifest("permissions", "permissions_all_urls.json")); scoped_refptr<const PermissionSet> permissions( @@ -1414,7 +1443,10 @@ TEST(PermissionsTest, HasLessPrivilegesThan_DeclarativeWebRequest) { scoped_refptr<const PermissionSet> permissions_dwr( extension_dwr->GetActivePermissions()); - EXPECT_FALSE(permissions->HasLessPrivilegesThan(permissions_dwr.get(), - extension->GetType())); + EXPECT_FALSE(PermissionMessageProvider::Get()-> + IsPrivilegeIncrease(permissions.get(), + permissions_dwr.get(), + extension->GetType())); } + } // namespace extensions diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc index 817259f..f252bd1 100644 --- a/chrome/common/extensions/permissions/permissions_data.cc +++ b/chrome/common/extensions/permissions/permissions_data.cc @@ -23,6 +23,7 @@ #include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_constants.h" #include "extensions/common/permissions/api_permission_set.h" +#include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/permissions/permissions_info.h" #include "extensions/common/switches.h" #include "extensions/common/url_pattern_set.h" @@ -422,8 +423,8 @@ PermissionMessages PermissionsData::GetPermissionMessages( if (ShouldSkipPermissionWarnings(extension)) { return PermissionMessages(); } else { - return GetActivePermissions(extension)->GetPermissionMessages( - extension->GetType()); + return PermissionMessageProvider::Get()->GetPermissionMessages( + GetActivePermissions(extension), extension->GetType()); } } @@ -434,8 +435,8 @@ std::vector<string16> PermissionsData::GetPermissionMessageStrings( if (ShouldSkipPermissionWarnings(extension)) { return std::vector<string16>(); } else { - return GetActivePermissions(extension)->GetWarningMessages( - extension->GetType()); + return PermissionMessageProvider::Get()->GetWarningMessages( + GetActivePermissions(extension), extension->GetType()); } } @@ -446,8 +447,8 @@ std::vector<string16> PermissionsData::GetPermissionMessageDetailsStrings( if (ShouldSkipPermissionWarnings(extension)) { return std::vector<string16>(); } else { - return GetActivePermissions(extension)->GetWarningMessagesDetails( - extension->GetType()); + return PermissionMessageProvider::Get()->GetWarningMessagesDetails( + GetActivePermissions(extension), extension->GetType()); } } diff --git a/extensions/common/extensions_client.cc b/extensions/common/extensions_client.cc index e7f936d..ccca164 100644 --- a/extensions/common/extensions_client.cc +++ b/extensions/common/extensions_client.cc @@ -11,10 +11,6 @@ namespace { ExtensionsClient* g_client = NULL; -void Initialize(ExtensionsClient* client) { - client->RegisterManifestHandlers(); -} - } // namespace ExtensionsClient* ExtensionsClient::Get() { @@ -26,7 +22,7 @@ void ExtensionsClient::Set(ExtensionsClient* client) { if (g_client) return; g_client = client; - Initialize(g_client); + g_client->Initialize(); } } // namespace extensions diff --git a/extensions/common/extensions_client.h b/extensions/common/extensions_client.h index eb3ebfe..ed06d32 100644 --- a/extensions/common/extensions_client.h +++ b/extensions/common/extensions_client.h @@ -12,6 +12,7 @@ namespace extensions { class FeatureProvider; class PermissionMessage; +class PermissionMessageProvider; class PermissionsProvider; class URLPatternSet; @@ -19,16 +20,23 @@ class URLPatternSet; // process. This should be implemented by the client of the extensions system. class ExtensionsClient { public: + // Initializes global state. Not done in the constructor because unit tests + // can create additional ExtensionsClients because the utility thread runs + // in-process. + virtual void Initialize() = 0; + // Returns a PermissionsProvider to initialize the permissions system. virtual const PermissionsProvider& GetPermissionsProvider() const = 0; + // Returns the global PermissionMessageProvider to use to provide permission + // warning strings. + virtual const PermissionMessageProvider& GetPermissionMessageProvider() + const = 0; + // Gets a feature provider for a specific feature type. virtual FeatureProvider* GetFeatureProviderByName(const std::string& name) const = 0; - // Called at startup. Registers the handlers for parsing manifests. - virtual void RegisterManifestHandlers() const = 0; - // Takes the list of all hosts and filters out those with special // permission strings. Adds the regular hosts to |new_hosts|, // and adds the special permission messages to |messages|. diff --git a/extensions/common/permissions/permission_message_provider.cc b/extensions/common/permissions/permission_message_provider.cc new file mode 100644 index 0000000..5650eab --- /dev/null +++ b/extensions/common/permissions/permission_message_provider.cc @@ -0,0 +1,16 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/permissions/permission_message_provider.h" + +#include "extensions/common/extensions_client.h" + +namespace extensions { + +// static +const PermissionMessageProvider* PermissionMessageProvider::Get() { + return &(ExtensionsClient::Get()->GetPermissionMessageProvider()); +} + +} // namespace extensions diff --git a/extensions/common/permissions/permission_message_provider.h b/extensions/common/permissions/permission_message_provider.h new file mode 100644 index 0000000..7f682e3 --- /dev/null +++ b/extensions/common/permissions/permission_message_provider.h @@ -0,0 +1,58 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_COMMON_PERMISSIONS_PERMISSION_MESSAGE_PROVIDER_H_ +#define EXTENSIONS_COMMON_PERMISSIONS_PERMISSION_MESSAGE_PROVIDER_H_ + +#include <vector> + +#include "extensions/common/manifest.h" +#include "extensions/common/permissions/permission_message.h" + +namespace extensions { + +class PermissionSet; + +// The PermissionMessageProvider interprets permissions, translating them +// into warning messages to show to the user. It also determines whether +// a new set of permissions entails showing new warning messages. +class PermissionMessageProvider { + public: + PermissionMessageProvider() {} + virtual ~PermissionMessageProvider() {} + + // Return the global permission message provider. + static const PermissionMessageProvider* Get(); + + // Gets the localized permission messages that represent this set. + // The set of permission messages shown varies by extension type. + virtual PermissionMessages GetPermissionMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const = 0; + + // Gets the localized permission messages that represent this set (represented + // as strings). The set of permission messages shown varies by extension type. + virtual std::vector<string16> GetWarningMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const = 0; + + // Gets the localized permission details for messages that represent this set + // (represented as strings). The set of permission messages shown varies by + // extension type. + virtual std::vector<string16> GetWarningMessagesDetails( + const PermissionSet* permissions, + Manifest::Type extension_type) const = 0; + + // Returns true if |new_permissions| has a greater privilege level than + // |old_permissions|. + // Whether certain permissions are considered varies by extension type. + virtual bool IsPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions, + Manifest::Type extension_type) const = 0; +}; + +} // namespace extensions + +#endif // EXTENSIONS_COMMON_PERMISSIONS_PERMISSION_MESSAGE_PROVIDER_H_ diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index 6c4b3e2..0db3b4f 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -70,6 +70,8 @@ 'common/permissions/api_permission_set.h', 'common/permissions/permission_message.cc', 'common/permissions/permission_message.h', + 'common/permissions/permission_message_provider.cc', + 'common/permissions/permission_message_provider.h', 'common/permissions/permissions_info.cc', 'common/permissions/permissions_info.h', 'common/permissions/permissions_provider.h', |