summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authoryoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-15 23:07:41 +0000
committeryoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-15 23:07:41 +0000
commite4452d31c6aadb6e9c86836e8b45c0c151223826 (patch)
tree465eb8100a1d86ab889cd9f3f709df1703597a81 /extensions
parent741c3917b61418986e76534c2bc68394f6f23d29 (diff)
downloadchromium_src-e4452d31c6aadb6e9c86836e8b45c0c151223826.zip
chromium_src-e4452d31c6aadb6e9c86836e8b45c0c151223826.tar.gz
chromium_src-e4452d31c6aadb6e9c86836e8b45c0c151223826.tar.bz2
Move Extension and PermissionsData to extensions/common.
BUG=298586 R=cdn@chromium.org, miket@chromium.org, sky@chromium.org TBR=cdn@chromium.org Review URL: https://codereview.chromium.org/15239002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@235462 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions')
-rw-r--r--extensions/DEPS6
-rw-r--r--extensions/browser/DEPS1
-rw-r--r--extensions/browser/admin_policy.cc2
-rw-r--r--extensions/browser/admin_policy_unittest.cc2
-rw-r--r--extensions/browser/extension_function.h2
-rw-r--r--extensions/browser/info_map.cc2
-rw-r--r--extensions/browser/info_map_unittest.cc2
-rw-r--r--extensions/browser/lazy_background_task_queue.cc2
-rw-r--r--extensions/browser/lazy_background_task_queue_unittest.cc2
-rw-r--r--extensions/browser/process_manager.cc2
-rw-r--r--extensions/common/DEPS4
-rw-r--r--extensions/common/extension.cc792
-rw-r--r--extensions/common/extension.h535
-rw-r--r--extensions/common/extension_api.cc4
-rw-r--r--extensions/common/extension_builder.cc2
-rw-r--r--extensions/common/manifest_handler.cc2
-rw-r--r--extensions/common/manifest_handler_unittest.cc2
-rw-r--r--extensions/common/manifest_handlers/background_info.cc2
-rw-r--r--extensions/common/manifest_handlers/background_info.h2
-rw-r--r--extensions/common/manifest_handlers/incognito_info.cc2
-rw-r--r--extensions/common/manifest_handlers/incognito_info.h2
-rw-r--r--extensions/common/permissions/permissions_data.cc626
-rw-r--r--extensions/common/permissions/permissions_data.h218
-rw-r--r--extensions/common/permissions/permissions_data_unittest.cc620
-rw-r--r--extensions/extensions.gyp4
25 files changed, 2820 insertions, 20 deletions
diff --git a/extensions/DEPS b/extensions/DEPS
index 2b0dd51..f286a2e 100644
--- a/extensions/DEPS
+++ b/extensions/DEPS
@@ -17,4 +17,10 @@ specific_include_rules = {
"^manifest_permission_set_unittest\.cc$": [
"+chrome/common/extensions/extension_messages.h",
],
+ "^permissions_data_unittest\.cc$": [
+ "+chrome/common/chrome_version_info.h",
+ "+chrome/common/extensions/extension_test_util.h",
+ "+chrome/common/extensions/features/feature_channel.h",
+ "+chrome/common/extensions/permissions/socket_permission.h",
+ ],
}
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index eb64dd1..55fbba0 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -17,7 +17,6 @@ include_rules = [
"+chrome/browser/extensions/extension_system.h",
"+chrome/browser/extensions/extension_util.h",
"+chrome/browser/renderer_host/chrome_render_message_filter.h",
- "+chrome/common/extensions/extension.h",
"+chrome/common/extensions/extension_messages.h",
"+chrome/common/extensions/extension_set.h",
"+grit/generated_resources.h",
diff --git a/extensions/browser/admin_policy.cc b/extensions/browser/admin_policy.cc
index 2cc0b57..903c4e0 100644
--- a/extensions/browser/admin_policy.cc
+++ b/extensions/browser/admin_policy.cc
@@ -5,7 +5,7 @@
#include "extensions/browser/admin_policy.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/extensions/browser/admin_policy_unittest.cc b/extensions/browser/admin_policy_unittest.cc
index 02d606d..f85e3ef 100644
--- a/extensions/browser/admin_policy_unittest.cc
+++ b/extensions/browser/admin_policy_unittest.cc
@@ -5,7 +5,7 @@
#include "extensions/browser/admin_policy.h"
#include "base/values.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 69effe0..aa0ed03 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -16,10 +16,10 @@
#include "base/process/process.h"
#include "base/sequenced_task_runner_helpers.h"
#include "chrome/browser/extensions/extension_function_histogram_value.h"
-#include "chrome/common/extensions/extension.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/console_message_level.h"
#include "extensions/browser/info_map.h"
+#include "extensions/common/extension.h"
#include "ipc/ipc_message.h"
class ChromeRenderMessageFilter;
diff --git a/extensions/browser/info_map.cc b/extensions/browser/info_map.cc
index 012f719..2bff206 100644
--- a/extensions/browser/info_map.cc
+++ b/extensions/browser/info_map.cc
@@ -4,10 +4,10 @@
#include "extensions/browser/info_map.h"
-#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_set.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
using content::BrowserThread;
diff --git a/extensions/browser/info_map_unittest.cc b/extensions/browser/info_map_unittest.cc
index b023eed..8eaf488 100644
--- a/extensions/browser/info_map_unittest.cc
+++ b/extensions/browser/info_map_unittest.cc
@@ -6,9 +6,9 @@
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/extension.h"
#include "content/public/test/test_browser_thread.h"
#include "extensions/browser/info_map.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/extensions/browser/lazy_background_task_queue.cc b/extensions/browser/lazy_background_task_queue.cc
index 987908b..f53cdd3 100644
--- a/extensions/browser/lazy_background_task_queue.cc
+++ b/extensions/browser/lazy_background_task_queue.cc
@@ -9,7 +9,6 @@
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/notification_service.h"
@@ -20,6 +19,7 @@
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/process_map.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/background_info.h"
#include "extensions/common/view_type.h"
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc
index 863a520..35c02b8 100644
--- a/extensions/browser/lazy_background_task_queue_unittest.cc
+++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -8,10 +8,10 @@
#include "base/command_line.h"
#include "chrome/browser/extensions/extension_service_unittest.h"
#include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/common/extensions/extension.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "extensions/browser/process_manager.h"
+#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc
index 3ae5be4..cccb800 100644
--- a/extensions/browser/process_manager.cc
+++ b/extensions/browser/process_manager.cc
@@ -19,7 +19,6 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -36,6 +35,7 @@
#include "content/public/common/renderer_preferences.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/view_type_utils.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/background_info.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "extensions/common/switches.h"
diff --git a/extensions/common/DEPS b/extensions/common/DEPS
index 34509b4..6a9adce 100644
--- a/extensions/common/DEPS
+++ b/extensions/common/DEPS
@@ -9,10 +9,10 @@ include_rules = [
#
# TODO(benwells): Remove these. http://crbug.com/162530
"+chrome/common/extensions/api/generated_schemas.h",
- "+chrome/common/extensions/extension.h",
- "+chrome/common/extensions/permissions/permissions_data.h",
+ "+grit/chromium_strings.h",
"+grit/common_resources.h",
"+grit/extensions_api_resources.h",
+ "+grit/theme_resources.h",
# TODO(jamescook): Extract extensions-related strings from this file.
"+grit/generated_resources.h",
]
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
new file mode 100644
index 0000000..f38d547
--- /dev/null
+++ b/extensions/common/extension.cc
@@ -0,0 +1,792 @@
+// Copyright (c) 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/extension.h"
+
+#include "base/base64.h"
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/id_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handler.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "extensions/common/switches.h"
+#include "extensions/common/url_pattern_set.h"
+#include "grit/chromium_strings.h"
+#include "grit/theme_resources.h"
+#include "net/base/net_util.h"
+#include "url/url_util.h"
+
+#if defined(OS_WIN)
+#include "grit/generated_resources.h"
+#endif
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace values = manifest_values;
+namespace errors = manifest_errors;
+
+namespace {
+
+const int kModernManifestVersion = 2;
+const int kPEMOutputColumns = 65;
+
+// KEY MARKERS
+const char kKeyBeginHeaderMarker[] = "-----BEGIN";
+const char kKeyBeginFooterMarker[] = "-----END";
+const char kKeyInfoEndMarker[] = "KEY-----";
+const char kPublic[] = "PUBLIC";
+const char kPrivate[] = "PRIVATE";
+
+bool ContainsReservedCharacters(const base::FilePath& path) {
+ // We should disallow backslash '\\' as file path separator even on Windows,
+ // because the backslash is not regarded as file path separator on Linux/Mac.
+ // Extensions are cross-platform.
+ // Since FilePath uses backslash '\\' as file path separator on Windows, so we
+ // need to check manually.
+ if (path.value().find('\\') != path.value().npos)
+ return true;
+ return !net::IsSafePortableRelativePath(path);
+}
+
+} // namespace
+
+const char Extension::kMimeType[] = "application/x-chrome-extension";
+
+const int Extension::kValidWebExtentSchemes =
+ URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
+
+const int Extension::kValidHostPermissionSchemes = URLPattern::SCHEME_CHROMEUI |
+ URLPattern::SCHEME_HTTP |
+ URLPattern::SCHEME_HTTPS |
+ URLPattern::SCHEME_FILE |
+ URLPattern::SCHEME_FTP;
+
+//
+// Extension
+//
+
+// static
+scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
+ Manifest::Location location,
+ const base::DictionaryValue& value,
+ int flags,
+ std::string* utf8_error) {
+ return Extension::Create(path,
+ location,
+ value,
+ flags,
+ std::string(), // ID is ignored if empty.
+ utf8_error);
+}
+
+// TODO(sungguk): Continue removing std::string errors and replacing
+// with string16. See http://crbug.com/71980.
+scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
+ Manifest::Location location,
+ const base::DictionaryValue& value,
+ int flags,
+ const std::string& explicit_id,
+ std::string* utf8_error) {
+ DCHECK(utf8_error);
+ string16 error;
+ scoped_ptr<extensions::Manifest> manifest(
+ new extensions::Manifest(
+ location, scoped_ptr<base::DictionaryValue>(value.DeepCopy())));
+
+ if (!InitExtensionID(manifest.get(), path, explicit_id, flags, &error)) {
+ *utf8_error = UTF16ToUTF8(error);
+ return NULL;
+ }
+
+ std::vector<InstallWarning> install_warnings;
+ if (!manifest->ValidateManifest(utf8_error, &install_warnings)) {
+ return NULL;
+ }
+
+ scoped_refptr<Extension> extension = new Extension(path, manifest.Pass());
+ extension->install_warnings_.swap(install_warnings);
+
+ if (!extension->InitFromValue(flags, &error)) {
+ *utf8_error = UTF16ToUTF8(error);
+ return NULL;
+ }
+
+ return extension;
+}
+
+// static
+bool Extension::IdIsValid(const std::string& id) {
+ // Verify that the id is legal.
+ if (id.size() != (id_util::kIdSize * 2))
+ return false;
+
+ // We only support lowercase IDs, because IDs can be used as URL components
+ // (where GURL will lowercase it).
+ std::string temp = StringToLowerASCII(id);
+ for (size_t i = 0; i < temp.size(); i++)
+ if (temp[i] < 'a' || temp[i] > 'p')
+ return false;
+
+ return true;
+}
+
+Manifest::Type Extension::GetType() const {
+ return converted_from_user_script() ?
+ Manifest::TYPE_USER_SCRIPT : manifest_->type();
+}
+
+// static
+GURL Extension::GetResourceURL(const GURL& extension_url,
+ const std::string& relative_path) {
+ DCHECK(extension_url.SchemeIs(extensions::kExtensionScheme));
+ DCHECK_EQ("/", extension_url.path());
+
+ std::string path = relative_path;
+
+ // If the relative path starts with "/", it is "absolute" relative to the
+ // extension base directory, but extension_url is already specified to refer
+ // to that base directory, so strip the leading "/" if present.
+ if (relative_path.size() > 0 && relative_path[0] == '/')
+ path = relative_path.substr(1);
+
+ GURL ret_val = GURL(extension_url.spec() + path);
+ DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
+
+ return ret_val;
+}
+
+bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
+ const std::string& resource) const {
+ return pattern_set.MatchesURL(extension_url_.Resolve(resource));
+}
+
+ExtensionResource Extension::GetResource(
+ const std::string& relative_path) const {
+ std::string new_path = relative_path;
+ // We have some legacy data where resources have leading slashes.
+ // See: http://crbug.com/121164
+ if (!new_path.empty() && new_path.at(0) == '/')
+ new_path.erase(0, 1);
+ base::FilePath relative_file_path = base::FilePath::FromUTF8Unsafe(new_path);
+ if (ContainsReservedCharacters(relative_file_path))
+ return ExtensionResource();
+ ExtensionResource r(id(), path(), relative_file_path);
+ if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
+ r.set_follow_symlinks_anywhere();
+ }
+ return r;
+}
+
+ExtensionResource Extension::GetResource(
+ const base::FilePath& relative_file_path) const {
+ if (ContainsReservedCharacters(relative_file_path))
+ return ExtensionResource();
+ ExtensionResource r(id(), path(), relative_file_path);
+ if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
+ r.set_follow_symlinks_anywhere();
+ }
+ return r;
+}
+
+// TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
+// util class in base:
+// http://code.google.com/p/chromium/issues/detail?id=13572
+// static
+bool Extension::ParsePEMKeyBytes(const std::string& input,
+ std::string* output) {
+ DCHECK(output);
+ if (!output)
+ return false;
+ if (input.length() == 0)
+ return false;
+
+ std::string working = input;
+ if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
+ working = CollapseWhitespaceASCII(working, true);
+ size_t header_pos = working.find(kKeyInfoEndMarker,
+ sizeof(kKeyBeginHeaderMarker) - 1);
+ if (header_pos == std::string::npos)
+ return false;
+ size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
+ size_t end_pos = working.rfind(kKeyBeginFooterMarker);
+ if (end_pos == std::string::npos)
+ return false;
+ if (start_pos >= end_pos)
+ return false;
+
+ working = working.substr(start_pos, end_pos - start_pos);
+ if (working.length() == 0)
+ return false;
+ }
+
+ return base::Base64Decode(working, output);
+}
+
+// static
+bool Extension::ProducePEM(const std::string& input, std::string* output) {
+ DCHECK(output);
+ return (input.length() == 0) ? false : base::Base64Encode(input, output);
+}
+
+// static
+bool Extension::FormatPEMForFileOutput(const std::string& input,
+ std::string* output,
+ bool is_public) {
+ DCHECK(output);
+ if (input.length() == 0)
+ return false;
+ *output = "";
+ output->append(kKeyBeginHeaderMarker);
+ output->append(" ");
+ output->append(is_public ? kPublic : kPrivate);
+ output->append(" ");
+ output->append(kKeyInfoEndMarker);
+ output->append("\n");
+ for (size_t i = 0; i < input.length(); ) {
+ int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
+ output->append(input.substr(i, slice));
+ output->append("\n");
+ i += slice;
+ }
+ output->append(kKeyBeginFooterMarker);
+ output->append(" ");
+ output->append(is_public ? kPublic : kPrivate);
+ output->append(" ");
+ output->append(kKeyInfoEndMarker);
+ output->append("\n");
+
+ return true;
+}
+
+// static
+GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
+ return GURL(std::string(extensions::kExtensionScheme) +
+ content::kStandardSchemeSeparator + extension_id + "/");
+}
+
+bool Extension::HasAPIPermission(APIPermission::ID permission) const {
+ return PermissionsData::HasAPIPermission(this, permission);
+}
+
+bool Extension::HasAPIPermission(const std::string& permission_name) const {
+ return PermissionsData::HasAPIPermission(this, permission_name);
+}
+
+scoped_refptr<const PermissionSet> Extension::GetActivePermissions() const {
+ return PermissionsData::GetActivePermissions(this);
+}
+
+bool Extension::ShowConfigureContextMenus() const {
+ // Don't show context menu for component extensions. We might want to show
+ // options for component extension button but now there is no component
+ // extension with options. All other menu items like uninstall have
+ // no sense for component extensions.
+ return location() != Manifest::COMPONENT;
+}
+
+bool Extension::OverlapsWithOrigin(const GURL& origin) const {
+ if (url() == origin)
+ return true;
+
+ if (web_extent().is_empty())
+ return false;
+
+ // Note: patterns and extents ignore port numbers.
+ URLPattern origin_only_pattern(kValidWebExtentSchemes);
+ if (!origin_only_pattern.SetScheme(origin.scheme()))
+ return false;
+ origin_only_pattern.SetHost(origin.host());
+ origin_only_pattern.SetPath("/*");
+
+ URLPatternSet origin_only_pattern_list;
+ origin_only_pattern_list.AddPattern(origin_only_pattern);
+
+ return web_extent().OverlapsWith(origin_only_pattern_list);
+}
+
+bool Extension::RequiresSortOrdinal() const {
+ return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
+}
+
+bool Extension::ShouldDisplayInAppLauncher() const {
+ // Only apps should be displayed in the launcher.
+ return is_app() && display_in_launcher_;
+}
+
+bool Extension::ShouldDisplayInNewTabPage() const {
+ // Only apps should be displayed on the NTP.
+ return is_app() && display_in_new_tab_page_;
+}
+
+bool Extension::ShouldDisplayInExtensionSettings() const {
+ // Don't show for themes since the settings UI isn't really useful for them.
+ if (is_theme())
+ return false;
+
+ // Don't show component extensions and invisible apps.
+ if (ShouldNotBeVisible())
+ return false;
+
+ // Always show unpacked extensions and apps.
+ if (Manifest::IsUnpackedLocation(location()))
+ return true;
+
+ // Unless they are unpacked, never show hosted apps. Note: We intentionally
+ // show packaged apps and platform apps because there are some pieces of
+ // functionality that are only available in chrome://extensions/ but which
+ // are needed for packaged and platform apps. For example, inspecting
+ // background pages. See http://crbug.com/116134.
+ if (is_hosted_app())
+ return false;
+
+ return true;
+}
+
+bool Extension::ShouldNotBeVisible() const {
+ // Don't show component extensions because they are only extensions as an
+ // implementation detail of Chrome.
+ if (location() == Manifest::COMPONENT &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kShowComponentExtensionOptions)) {
+ return true;
+ }
+
+ // Always show unpacked extensions and apps.
+ if (Manifest::IsUnpackedLocation(location()))
+ return false;
+
+ // Don't show apps that aren't visible in either launcher or ntp.
+ if (is_app() && !ShouldDisplayInAppLauncher() && !ShouldDisplayInNewTabPage())
+ return true;
+
+ return false;
+}
+
+Extension::ManifestData* Extension::GetManifestData(const std::string& key)
+ const {
+ DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
+ ManifestDataMap::const_iterator iter = manifest_data_.find(key);
+ if (iter != manifest_data_.end())
+ return iter->second.get();
+ return NULL;
+}
+
+void Extension::SetManifestData(const std::string& key,
+ Extension::ManifestData* data) {
+ DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
+ manifest_data_[key] = linked_ptr<ManifestData>(data);
+}
+
+Manifest::Location Extension::location() const {
+ return manifest_->location();
+}
+
+const std::string& Extension::id() const {
+ return manifest_->extension_id();
+}
+
+const std::string Extension::VersionString() const {
+ return version()->GetString();
+}
+
+void Extension::AddInstallWarning(const InstallWarning& new_warning) {
+ install_warnings_.push_back(new_warning);
+}
+
+void Extension::AddInstallWarnings(
+ const std::vector<InstallWarning>& new_warnings) {
+ install_warnings_.insert(install_warnings_.end(),
+ new_warnings.begin(), new_warnings.end());
+}
+
+bool Extension::is_app() const {
+ return manifest_->is_app();
+}
+
+bool Extension::is_platform_app() const {
+ return manifest_->is_platform_app();
+}
+
+bool Extension::is_hosted_app() const {
+ return manifest()->is_hosted_app();
+}
+
+bool Extension::is_legacy_packaged_app() const {
+ return manifest()->is_legacy_packaged_app();
+}
+
+bool Extension::is_extension() const {
+ return manifest()->is_extension();
+}
+
+bool Extension::can_be_incognito_enabled() const {
+ // Only component platform apps are supported in incognito.
+ return !is_platform_app() || location() == Manifest::COMPONENT;
+}
+
+bool Extension::force_incognito_enabled() const {
+ return PermissionsData::HasAPIPermission(this, APIPermission::kProxy);
+}
+
+void Extension::AddWebExtentPattern(const URLPattern& pattern) {
+ extent_.AddPattern(pattern);
+}
+
+bool Extension::is_theme() const {
+ return manifest()->is_theme();
+}
+
+// static
+bool Extension::InitExtensionID(extensions::Manifest* manifest,
+ const base::FilePath& path,
+ const std::string& explicit_id,
+ int creation_flags,
+ string16* error) {
+ if (!explicit_id.empty()) {
+ manifest->set_extension_id(explicit_id);
+ return true;
+ }
+
+ if (manifest->HasKey(keys::kPublicKey)) {
+ std::string public_key;
+ std::string public_key_bytes;
+ if (!manifest->GetString(keys::kPublicKey, &public_key) ||
+ !ParsePEMKeyBytes(public_key, &public_key_bytes)) {
+ *error = ASCIIToUTF16(errors::kInvalidKey);
+ return false;
+ }
+ std::string extension_id = id_util::GenerateId(public_key_bytes);
+ manifest->set_extension_id(extension_id);
+ return true;
+ }
+
+ if (creation_flags & REQUIRE_KEY) {
+ *error = ASCIIToUTF16(errors::kInvalidKey);
+ return false;
+ } else {
+ // If there is a path, we generate the ID from it. This is useful for
+ // development mode, because it keeps the ID stable across restarts and
+ // reloading the extension.
+ std::string extension_id = id_util::GenerateIdForPath(path);
+ if (extension_id.empty()) {
+ NOTREACHED() << "Could not create ID from path.";
+ return false;
+ }
+ manifest->set_extension_id(extension_id);
+ return true;
+ }
+}
+
+Extension::Extension(const base::FilePath& path,
+ scoped_ptr<extensions::Manifest> manifest)
+ : manifest_version_(0),
+ converted_from_user_script_(false),
+ manifest_(manifest.release()),
+ finished_parsing_manifest_(false),
+ display_in_launcher_(true),
+ display_in_new_tab_page_(true),
+ wants_file_access_(false),
+ creation_flags_(0) {
+ DCHECK(path.empty() || path.IsAbsolute());
+ path_ = id_util::MaybeNormalizePath(path);
+}
+
+Extension::~Extension() {
+}
+
+bool Extension::InitFromValue(int flags, string16* error) {
+ DCHECK(error);
+
+ creation_flags_ = flags;
+
+ // Important to load manifest version first because many other features
+ // depend on its value.
+ if (!LoadManifestVersion(error))
+ return false;
+
+ if (!LoadRequiredFeatures(error))
+ return false;
+
+ // We don't need to validate because InitExtensionID already did that.
+ manifest_->GetString(keys::kPublicKey, &public_key_);
+
+ extension_url_ = Extension::GetBaseURLFromExtensionId(id());
+
+ // Load App settings. LoadExtent at least has to be done before
+ // ParsePermissions(), because the valid permissions depend on what type of
+ // package this is.
+ if (is_app() && !LoadAppFeatures(error))
+ return false;
+
+ permissions_data_.reset(new PermissionsData);
+ if (!permissions_data_->ParsePermissions(this, error))
+ return false;
+
+ if (manifest_->HasKey(keys::kConvertedFromUserScript)) {
+ manifest_->GetBoolean(keys::kConvertedFromUserScript,
+ &converted_from_user_script_);
+ }
+
+ if (!LoadSharedFeatures(error))
+ return false;
+
+ finished_parsing_manifest_ = true;
+
+ permissions_data_->InitializeManifestPermissions(this);
+ permissions_data_->FinalizePermissions(this);
+
+ return true;
+}
+
+bool Extension::LoadRequiredFeatures(string16* error) {
+ if (!LoadName(error) ||
+ !LoadVersion(error))
+ return false;
+ return true;
+}
+
+bool Extension::LoadName(string16* error) {
+ string16 localized_name;
+ if (!manifest_->GetString(keys::kName, &localized_name)) {
+ *error = ASCIIToUTF16(errors::kInvalidName);
+ return false;
+ }
+ non_localized_name_ = UTF16ToUTF8(localized_name);
+ base::i18n::AdjustStringForLocaleDirection(&localized_name);
+ name_ = UTF16ToUTF8(localized_name);
+ return true;
+}
+
+bool Extension::LoadVersion(string16* error) {
+ std::string version_str;
+ if (!manifest_->GetString(keys::kVersion, &version_str)) {
+ *error = ASCIIToUTF16(errors::kInvalidVersion);
+ return false;
+ }
+ version_.reset(new Version(version_str));
+ if (!version_->IsValid() || version_->components().size() > 4) {
+ *error = ASCIIToUTF16(errors::kInvalidVersion);
+ return false;
+ }
+ return true;
+}
+
+bool Extension::LoadAppFeatures(string16* error) {
+ if (!LoadExtent(keys::kWebURLs, &extent_,
+ errors::kInvalidWebURLs, errors::kInvalidWebURL, error)) {
+ return false;
+ }
+ if (manifest_->HasKey(keys::kDisplayInLauncher) &&
+ !manifest_->GetBoolean(keys::kDisplayInLauncher, &display_in_launcher_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDisplayInLauncher);
+ return false;
+ }
+ if (manifest_->HasKey(keys::kDisplayInNewTabPage)) {
+ if (!manifest_->GetBoolean(keys::kDisplayInNewTabPage,
+ &display_in_new_tab_page_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDisplayInNewTabPage);
+ return false;
+ }
+ } else {
+ // Inherit default from display_in_launcher property.
+ display_in_new_tab_page_ = display_in_launcher_;
+ }
+ return true;
+}
+
+bool Extension::LoadExtent(const char* key,
+ URLPatternSet* extent,
+ const char* list_error,
+ const char* value_error,
+ string16* error) {
+ const base::Value* temp_pattern_value = NULL;
+ if (!manifest_->Get(key, &temp_pattern_value))
+ return true;
+
+ const base::ListValue* pattern_list = NULL;
+ if (!temp_pattern_value->GetAsList(&pattern_list)) {
+ *error = ASCIIToUTF16(list_error);
+ return false;
+ }
+
+ for (size_t i = 0; i < pattern_list->GetSize(); ++i) {
+ std::string pattern_string;
+ if (!pattern_list->GetString(i, &pattern_string)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(value_error,
+ base::UintToString(i),
+ errors::kExpectString);
+ return false;
+ }
+
+ URLPattern pattern(kValidWebExtentSchemes);
+ URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
+ if (parse_result == URLPattern::PARSE_ERROR_EMPTY_PATH) {
+ pattern_string += "/";
+ parse_result = pattern.Parse(pattern_string);
+ }
+
+ if (parse_result != URLPattern::PARSE_SUCCESS) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ value_error,
+ base::UintToString(i),
+ URLPattern::GetParseResultString(parse_result));
+ return false;
+ }
+
+ // Do not allow authors to claim "<all_urls>".
+ if (pattern.match_all_urls()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ value_error,
+ base::UintToString(i),
+ errors::kCannotClaimAllURLsInExtent);
+ return false;
+ }
+
+ // Do not allow authors to claim "*" for host.
+ if (pattern.host().empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ value_error,
+ base::UintToString(i),
+ errors::kCannotClaimAllHostsInExtent);
+ return false;
+ }
+
+ // We do not allow authors to put wildcards in their paths. Instead, we
+ // imply one at the end.
+ if (pattern.path().find('*') != std::string::npos) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ value_error,
+ base::UintToString(i),
+ errors::kNoWildCardsInPaths);
+ return false;
+ }
+ pattern.SetPath(pattern.path() + '*');
+
+ extent->AddPattern(pattern);
+ }
+
+ return true;
+}
+
+bool Extension::LoadSharedFeatures(string16* error) {
+ if (!LoadDescription(error) ||
+ !ManifestHandler::ParseExtension(this, error) ||
+ !LoadShortName(error))
+ return false;
+
+ return true;
+}
+
+bool Extension::LoadDescription(string16* error) {
+ if (manifest_->HasKey(keys::kDescription) &&
+ !manifest_->GetString(keys::kDescription, &description_)) {
+ *error = ASCIIToUTF16(errors::kInvalidDescription);
+ return false;
+ }
+ return true;
+}
+
+bool Extension::LoadManifestVersion(string16* error) {
+ // Get the original value out of the dictionary so that we can validate it
+ // more strictly.
+ if (manifest_->value()->HasKey(keys::kManifestVersion)) {
+ int manifest_version = 1;
+ if (!manifest_->GetInteger(keys::kManifestVersion, &manifest_version) ||
+ manifest_version < 1) {
+ *error = ASCIIToUTF16(errors::kInvalidManifestVersion);
+ return false;
+ }
+ }
+
+ manifest_version_ = manifest_->GetManifestVersion();
+ if (manifest_version_ < kModernManifestVersion &&
+ ((creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowLegacyExtensionManifests)) ||
+ GetType() == Manifest::TYPE_PLATFORM_APP)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidManifestVersionOld,
+ base::IntToString(kModernManifestVersion),
+ is_platform_app() ? "apps" : "extensions");
+ return false;
+ }
+
+ return true;
+}
+
+bool Extension::LoadShortName(string16* error) {
+ if (manifest_->HasKey(keys::kShortName)) {
+ string16 localized_short_name;
+ if (!manifest_->GetString(keys::kShortName, &localized_short_name) ||
+ localized_short_name.empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidShortName);
+ return false;
+ }
+
+ base::i18n::AdjustStringForLocaleDirection(&localized_short_name);
+ short_name_ = UTF16ToUTF8(localized_short_name);
+ } else {
+ short_name_ = name_;
+ }
+ return true;
+}
+
+ExtensionInfo::ExtensionInfo(const base::DictionaryValue* manifest,
+ const std::string& id,
+ const base::FilePath& path,
+ Manifest::Location location)
+ : extension_id(id),
+ extension_path(path),
+ extension_location(location) {
+ if (manifest)
+ extension_manifest.reset(manifest->DeepCopy());
+}
+
+ExtensionInfo::~ExtensionInfo() {}
+
+InstalledExtensionInfo::InstalledExtensionInfo(
+ const Extension* extension,
+ bool is_update,
+ const std::string& old_name)
+ : extension(extension),
+ is_update(is_update),
+ old_name(old_name) {}
+
+UnloadedExtensionInfo::UnloadedExtensionInfo(
+ const Extension* extension,
+ UnloadedExtensionInfo::Reason reason)
+ : reason(reason),
+ extension(extension) {}
+
+UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
+ const Extension* extension,
+ const PermissionSet* permissions,
+ Reason reason)
+ : reason(reason),
+ extension(extension),
+ permissions(permissions) {}
+
+} // namespace extensions
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
new file mode 100644
index 0000000..642efb2
--- /dev/null
+++ b/extensions/common/extension.h
@@ -0,0 +1,535 @@
+// Copyright (c) 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_EXTENSION_H_
+#define EXTENSIONS_COMMON_EXTENSION_H_
+
+#include <algorithm>
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/files/file_path.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "extensions/common/extension_resource.h"
+#include "extensions/common/install_warning.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/url_pattern.h"
+#include "extensions/common/url_pattern_set.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/gfx/size.h"
+#include "url/gurl.h"
+
+class ExtensionAction;
+class SkBitmap;
+
+namespace base {
+class DictionaryValue;
+class Version;
+}
+
+namespace gfx {
+class ImageSkia;
+}
+
+namespace extensions {
+class PermissionsData;
+class APIPermissionSet;
+class ManifestPermissionSet;
+class PermissionSet;
+
+// Represents a Chrome extension.
+// Once created, an Extension object is immutable, with the exception of its
+// RuntimeData. This makes it safe to use on any thread, since access to the
+// RuntimeData is protected by a lock.
+class Extension : public base::RefCountedThreadSafe<Extension> {
+ public:
+ struct ManifestData;
+
+ typedef std::map<const std::string, linked_ptr<ManifestData> >
+ ManifestDataMap;
+
+ enum State {
+ DISABLED = 0,
+ ENABLED,
+ // An external extension that the user uninstalled. We should not reinstall
+ // such extensions on startup.
+ EXTERNAL_EXTENSION_UNINSTALLED,
+ // Special state for component extensions, since they are always loaded by
+ // the component loader, and should never be auto-installed on startup.
+ ENABLED_COMPONENT,
+ NUM_STATES
+ };
+
+ // Used to record the reason an extension was disabled.
+ enum DeprecatedDisableReason {
+ DEPRECATED_DISABLE_UNKNOWN,
+ DEPRECATED_DISABLE_USER_ACTION,
+ DEPRECATED_DISABLE_PERMISSIONS_INCREASE,
+ DEPRECATED_DISABLE_RELOAD,
+ DEPRECATED_DISABLE_LAST, // Not used.
+ };
+
+ enum DisableReason {
+ DISABLE_NONE = 0,
+ DISABLE_USER_ACTION = 1 << 0,
+ DISABLE_PERMISSIONS_INCREASE = 1 << 1,
+ DISABLE_RELOAD = 1 << 2,
+ DISABLE_UNSUPPORTED_REQUIREMENT = 1 << 3,
+ DISABLE_SIDELOAD_WIPEOUT = 1 << 4,
+ DISABLE_UNKNOWN_FROM_SYNC = 1 << 5,
+ DISABLE_PERMISSIONS_CONSENT = 1 << 6, // Unused - abandoned experiment.
+ DISABLE_KNOWN_DISABLED = 1 << 7,
+
+ // Disabled because we could not verify the install.
+ DISABLE_NOT_VERIFIED = 1 << 8,
+ };
+
+ enum InstallType {
+ INSTALL_ERROR,
+ DOWNGRADE,
+ REINSTALL,
+ UPGRADE,
+ NEW_INSTALL
+ };
+
+ // A base class for parsed manifest data that APIs want to store on
+ // the extension. Related to base::SupportsUserData, but with an immutable
+ // thread-safe interface to match Extension.
+ struct ManifestData {
+ virtual ~ManifestData() {}
+ };
+
+ enum InitFromValueFlags {
+ NO_FLAGS = 0,
+
+ // Usually, the id of an extension is generated by the "key" property of
+ // its manifest, but if |REQUIRE_KEY| is not set, a temporary ID will be
+ // generated based on the path.
+ REQUIRE_KEY = 1 << 0,
+
+ // Requires the extension to have an up-to-date manifest version.
+ // Typically, we'll support multiple manifest versions during a version
+ // transition. This flag signals that we want to require the most modern
+ // manifest version that Chrome understands.
+ REQUIRE_MODERN_MANIFEST_VERSION = 1 << 1,
+
+ // |ALLOW_FILE_ACCESS| indicates that the user is allowing this extension
+ // to have file access. If it's not present, then permissions and content
+ // scripts that match file:/// URLs will be filtered out.
+ ALLOW_FILE_ACCESS = 1 << 2,
+
+ // |FROM_WEBSTORE| indicates that the extension was installed from the
+ // Chrome Web Store.
+ FROM_WEBSTORE = 1 << 3,
+
+ // |FROM_BOOKMARK| indicates the extension was created using a mock App
+ // created from a bookmark.
+ FROM_BOOKMARK = 1 << 4,
+
+ // |FOLLOW_SYMLINKS_ANYWHERE| means that resources can be symlinks to
+ // anywhere in the filesystem, rather than being restricted to the
+ // extension directory.
+ FOLLOW_SYMLINKS_ANYWHERE = 1 << 5,
+
+ // |ERROR_ON_PRIVATE_KEY| means that private keys inside an
+ // extension should be errors rather than warnings.
+ ERROR_ON_PRIVATE_KEY = 1 << 6,
+
+ // |WAS_INSTALLED_BY_DEFAULT| installed by default when the profile was
+ // created.
+ WAS_INSTALLED_BY_DEFAULT = 1 << 7,
+
+ // Unused - was part of an abandoned experiment.
+ REQUIRE_PERMISSIONS_CONSENT = 1 << 8,
+ };
+
+ static scoped_refptr<Extension> Create(const base::FilePath& path,
+ Manifest::Location location,
+ const base::DictionaryValue& value,
+ int flags,
+ std::string* error);
+
+ // In a few special circumstances, we want to create an Extension and give it
+ // an explicit id. Most consumers should just use the other Create() method.
+ static scoped_refptr<Extension> Create(const base::FilePath& path,
+ Manifest::Location location,
+ const base::DictionaryValue& value,
+ int flags,
+ const std::string& explicit_id,
+ std::string* error);
+
+ // Valid schemes for web extent URLPatterns.
+ static const int kValidWebExtentSchemes;
+
+ // Valid schemes for host permission URLPatterns.
+ static const int kValidHostPermissionSchemes;
+
+ // The mimetype used for extensions.
+ static const char kMimeType[];
+
+ // Checks to see if the extension has a valid ID.
+ static bool IdIsValid(const std::string& id);
+
+ // See Type definition in Manifest.
+ Manifest::Type GetType() const;
+
+ // Returns an absolute url to a resource inside of an extension. The
+ // |extension_url| argument should be the url() from an Extension object. The
+ // |relative_path| can be untrusted user input. The returned URL will either
+ // be invalid() or a child of |extension_url|.
+ // NOTE: Static so that it can be used from multiple threads.
+ static GURL GetResourceURL(const GURL& extension_url,
+ const std::string& relative_path);
+ GURL GetResourceURL(const std::string& relative_path) const {
+ return GetResourceURL(url(), relative_path);
+ }
+
+ // Returns true if the resource matches a pattern in the pattern_set.
+ bool ResourceMatches(const URLPatternSet& pattern_set,
+ const std::string& resource) const;
+
+ // Returns an extension resource object. |relative_path| should be UTF8
+ // encoded.
+ ExtensionResource GetResource(const std::string& relative_path) const;
+
+ // As above, but with |relative_path| following the file system's encoding.
+ ExtensionResource GetResource(const base::FilePath& relative_path) const;
+
+ // |input| is expected to be the text of an rsa public or private key. It
+ // tolerates the presence or absence of bracking header/footer like this:
+ // -----(BEGIN|END) [RSA PUBLIC/PRIVATE] KEY-----
+ // and may contain newlines.
+ static bool ParsePEMKeyBytes(const std::string& input, std::string* output);
+
+ // Does a simple base64 encoding of |input| into |output|.
+ static bool ProducePEM(const std::string& input, std::string* output);
+
+ // Expects base64 encoded |input| and formats into |output| including
+ // the appropriate header & footer.
+ static bool FormatPEMForFileOutput(const std::string& input,
+ std::string* output,
+ bool is_public);
+
+ // Returns the base extension url for a given |extension_id|.
+ static GURL GetBaseURLFromExtensionId(const std::string& extension_id);
+
+ // DEPRECATED: These methods have been moved to PermissionsData.
+ // TODO(rdevlin.cronin): remove these once all calls have been updated.
+ bool HasAPIPermission(APIPermission::ID permission) const;
+ bool HasAPIPermission(const std::string& permission_name) const;
+ scoped_refptr<const PermissionSet> GetActivePermissions() const;
+
+ // Whether context menu should be shown for page and browser actions.
+ bool ShowConfigureContextMenus() const;
+
+ // Returns true if this extension or app includes areas within |origin|.
+ bool OverlapsWithOrigin(const GURL& origin) const;
+
+ // Returns true if the extension requires a valid ordinal for sorting, e.g.,
+ // for displaying in a launcher or new tab page.
+ bool RequiresSortOrdinal() const;
+
+ // Returns true if the extension should be displayed in the app launcher.
+ bool ShouldDisplayInAppLauncher() const;
+
+ // Returns true if the extension should be displayed in the browser NTP.
+ bool ShouldDisplayInNewTabPage() const;
+
+ // Returns true if the extension should be displayed in the extension
+ // settings page (i.e. chrome://extensions).
+ bool ShouldDisplayInExtensionSettings() const;
+
+ // Returns true if the extension should not be shown anywhere. This is
+ // mostly the same as the extension being a component extension, but also
+ // includes non-component apps that are hidden from the app launcher and ntp.
+ bool ShouldNotBeVisible() const;
+
+ // Get the manifest data associated with the key, or NULL if there is none.
+ // Can only be called after InitValue is finished.
+ ManifestData* GetManifestData(const std::string& key) const;
+
+ // Sets |data| to be associated with the key. Takes ownership of |data|.
+ // Can only be called before InitValue is finished. Not thread-safe;
+ // all SetManifestData calls should be on only one thread.
+ void SetManifestData(const std::string& key, ManifestData* data);
+
+ // Accessors:
+
+ const base::FilePath& path() const { return path_; }
+ const GURL& url() const { return extension_url_; }
+ Manifest::Location location() const;
+ const std::string& id() const;
+ const base::Version* version() const { return version_.get(); }
+ const std::string VersionString() const;
+ const std::string& name() const { return name_; }
+ const std::string& short_name() const { return short_name_; }
+ const std::string& non_localized_name() const { return non_localized_name_; }
+ // Base64-encoded version of the key used to sign this extension.
+ // In pseudocode, returns
+ // base::Base64Encode(RSAPrivateKey(pem_file).ExportPublicKey()).
+ const std::string& public_key() const { return public_key_; }
+ const std::string& description() const { return description_; }
+ int manifest_version() const { return manifest_version_; }
+ bool converted_from_user_script() const {
+ return converted_from_user_script_;
+ }
+ PermissionsData* permissions_data() { return permissions_data_.get(); }
+ const PermissionsData* permissions_data() const {
+ return permissions_data_.get();
+ }
+
+ // Appends |new_warning[s]| to install_warnings_.
+ void AddInstallWarning(const InstallWarning& new_warning);
+ void AddInstallWarnings(const std::vector<InstallWarning>& new_warnings);
+ const std::vector<InstallWarning>& install_warnings() const {
+ return install_warnings_;
+ }
+ const extensions::Manifest* manifest() const {
+ return manifest_.get();
+ }
+ bool wants_file_access() const { return wants_file_access_; }
+ // TODO(rdevlin.cronin): This is needed for ContentScriptsHandler, and should
+ // be moved out as part of crbug.com/159265. This should not be used anywhere
+ // else.
+ void set_wants_file_access(bool wants_file_access) {
+ wants_file_access_ = wants_file_access;
+ }
+ int creation_flags() const { return creation_flags_; }
+ bool from_webstore() const { return (creation_flags_ & FROM_WEBSTORE) != 0; }
+ bool from_bookmark() const { return (creation_flags_ & FROM_BOOKMARK) != 0; }
+ bool was_installed_by_default() const {
+ return (creation_flags_ & WAS_INSTALLED_BY_DEFAULT) != 0;
+ }
+
+ // App-related.
+ bool is_app() const;
+ bool is_platform_app() const;
+ bool is_hosted_app() const;
+ bool is_legacy_packaged_app() const;
+ bool is_extension() const;
+ bool can_be_incognito_enabled() const;
+ bool force_incognito_enabled() const;
+
+ void AddWebExtentPattern(const URLPattern& pattern);
+ const URLPatternSet& web_extent() const { return extent_; }
+
+ // Theme-related.
+ bool is_theme() const;
+
+ private:
+ friend class base::RefCountedThreadSafe<Extension>;
+
+ // Chooses the extension ID for an extension based on a variety of criteria.
+ // The chosen ID will be set in |manifest|.
+ static bool InitExtensionID(extensions::Manifest* manifest,
+ const base::FilePath& path,
+ const std::string& explicit_id,
+ int creation_flags,
+ string16* error);
+
+ Extension(const base::FilePath& path,
+ scoped_ptr<extensions::Manifest> manifest);
+ virtual ~Extension();
+
+ // Initialize the extension from a parsed manifest.
+ // TODO(aa): Rename to just Init()? There's no Value here anymore.
+ // TODO(aa): It is really weird the way this class essentially contains a copy
+ // of the underlying DictionaryValue in its members. We should decide to
+ // either wrap the DictionaryValue and go with that only, or we should parse
+ // into strong types and discard the value. But doing both is bad.
+ bool InitFromValue(int flags, string16* error);
+
+ // The following are helpers for InitFromValue to load various features of the
+ // extension from the manifest.
+
+ bool LoadRequiredFeatures(string16* error);
+ bool LoadName(string16* error);
+ bool LoadVersion(string16* error);
+
+ bool LoadAppFeatures(string16* error);
+ bool LoadExtent(const char* key,
+ URLPatternSet* extent,
+ const char* list_error,
+ const char* value_error,
+ string16* error);
+
+ bool LoadSharedFeatures(string16* error);
+ bool LoadDescription(string16* error);
+ bool LoadManifestVersion(string16* error);
+ bool LoadShortName(string16* error);
+
+ bool CheckMinimumChromeVersion(string16* error) const;
+
+ // The extension's human-readable name. Name is used for display purpose. It
+ // might be wrapped with unicode bidi control characters so that it is
+ // displayed correctly in RTL context.
+ // NOTE: Name is UTF-8 and may contain non-ascii characters.
+ std::string name_;
+
+ // A non-localized version of the extension's name. This is useful for
+ // debug output.
+ std::string non_localized_name_;
+
+ // A short version of the extension's name. This can be used as an alternative
+ // to the name where there is insufficient space to display the full name. If
+ // an extension has not explicitly specified a short name, the value of this
+ // member variable will be the full name rather than an empty string.
+ std::string short_name_;
+
+ // The version of this extension's manifest. We increase the manifest
+ // version when making breaking changes to the extension system.
+ // Version 1 was the first manifest version (implied by a lack of a
+ // manifest_version attribute in the extension's manifest). We initialize
+ // this member variable to 0 to distinguish the "uninitialized" case from
+ // the case when we know the manifest version actually is 1.
+ int manifest_version_;
+
+ // The absolute path to the directory the extension is stored in.
+ base::FilePath path_;
+
+ // Defines the set of URLs in the extension's web content.
+ URLPatternSet extent_;
+
+ scoped_ptr<PermissionsData> permissions_data_;
+
+ // Any warnings that occurred when trying to create/parse the extension.
+ std::vector<InstallWarning> install_warnings_;
+
+ // The base extension url for the extension.
+ GURL extension_url_;
+
+ // The extension's version.
+ scoped_ptr<base::Version> version_;
+
+ // An optional longer description of the extension.
+ std::string description_;
+
+ // True if the extension was generated from a user script. (We show slightly
+ // different UI if so).
+ bool converted_from_user_script_;
+
+ // The public key used to sign the contents of the crx package.
+ std::string public_key_;
+
+ // The manifest from which this extension was created.
+ scoped_ptr<Manifest> manifest_;
+
+ // Stored parsed manifest data.
+ ManifestDataMap manifest_data_;
+
+ // Set to true at the end of InitValue when initialization is finished.
+ bool finished_parsing_manifest_;
+
+ // Ensures that any call to GetManifestData() prior to finishing
+ // initialization happens from the same thread (this can happen when certain
+ // parts of the initialization process need information from previous parts).
+ base::ThreadChecker thread_checker_;
+
+ // Should this app be shown in the app launcher.
+ bool display_in_launcher_;
+
+ // Should this app be shown in the browser New Tab Page.
+ bool display_in_new_tab_page_;
+
+ // Whether the extension has host permissions or user script patterns that
+ // imply access to file:/// scheme URLs (the user may not have actually
+ // granted it that access).
+ bool wants_file_access_;
+
+ // The flags that were passed to InitFromValue.
+ int creation_flags_;
+
+ DISALLOW_COPY_AND_ASSIGN(Extension);
+};
+
+typedef std::vector<scoped_refptr<const Extension> > ExtensionList;
+typedef std::set<std::string> ExtensionIdSet;
+typedef std::vector<std::string> ExtensionIdList;
+
+// Handy struct to pass core extension info around.
+struct ExtensionInfo {
+ ExtensionInfo(const base::DictionaryValue* manifest,
+ const std::string& id,
+ const base::FilePath& path,
+ Manifest::Location location);
+ ~ExtensionInfo();
+
+ scoped_ptr<base::DictionaryValue> extension_manifest;
+ std::string extension_id;
+ base::FilePath extension_path;
+ Manifest::Location extension_location;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExtensionInfo);
+};
+
+struct InstalledExtensionInfo {
+ // The extension being installed - this should always be non-NULL.
+ const Extension* extension;
+
+ // True if the extension is being updated; false if it is being installed.
+ bool is_update;
+
+ // The name of the extension prior to this update. Will be empty if
+ // |is_update| is false.
+ std::string old_name;
+
+ InstalledExtensionInfo(const Extension* extension,
+ bool is_update,
+ const std::string& old_name);
+};
+
+struct UnloadedExtensionInfo {
+ enum Reason {
+ REASON_DISABLE, // Extension is being disabled.
+ REASON_UPDATE, // Extension is being updated to a newer version.
+ REASON_UNINSTALL, // Extension is being uninstalled.
+ REASON_TERMINATE, // Extension has terminated.
+ REASON_BLACKLIST, // Extension has been blacklisted.
+ };
+
+ Reason reason;
+
+ // The extension being unloaded - this should always be non-NULL.
+ const Extension* extension;
+
+ UnloadedExtensionInfo(const Extension* extension, Reason reason);
+};
+
+// The details sent for EXTENSION_PERMISSIONS_UPDATED notifications.
+struct UpdatedExtensionPermissionsInfo {
+ enum Reason {
+ ADDED, // The permissions were added to the extension.
+ REMOVED, // The permissions were removed from the extension.
+ };
+
+ Reason reason;
+
+ // The extension who's permissions have changed.
+ const Extension* extension;
+
+ // The permissions that have changed. For Reason::ADDED, this would contain
+ // only the permissions that have added, and for Reason::REMOVED, this would
+ // only contain the removed permissions.
+ const PermissionSet* permissions;
+
+ UpdatedExtensionPermissionsInfo(
+ const Extension* extension,
+ const PermissionSet* permissions,
+ Reason reason);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_EXTENSION_H_
diff --git a/extensions/common/extension_api.cc b/extensions/common/extension_api.cc
index a8b2fa0..dd68ffd 100644
--- a/extensions/common/extension_api.cc
+++ b/extensions/common/extension_api.cc
@@ -17,11 +17,11 @@
#include "base/strings/string_util.h"
#include "base/values.h"
#include "chrome/common/extensions/api/generated_schemas.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/permissions_data.h"
+#include "extensions/common/extension.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_provider.h"
#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
#include "grit/common_resources.h"
#include "grit/extensions_api_resources.h"
#include "ui/base/resource/resource_bundle.h"
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc
index ef5a14f..f993e94 100644
--- a/extensions/common/extension_builder.cc
+++ b/extensions/common/extension_builder.cc
@@ -4,7 +4,7 @@
#include "extensions/common/extension_builder.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
namespace extensions {
diff --git a/extensions/common/manifest_handler.cc b/extensions/common/manifest_handler.cc
index 944389d..4546f32 100644
--- a/extensions/common/manifest_handler.cc
+++ b/extensions/common/manifest_handler.cc
@@ -8,7 +8,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
#include "extensions/common/permissions/manifest_permission.h"
#include "extensions/common/permissions/manifest_permission_set.h"
diff --git a/extensions/common/manifest_handler_unittest.cc b/extensions/common/manifest_handler_unittest.cc
index 620f0d6..9a3a292 100644
--- a/extensions/common/manifest_handler_unittest.cc
+++ b/extensions/common/manifest_handler_unittest.cc
@@ -9,7 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/install_warning.h"
#include "extensions/common/manifest_handler.h"
diff --git a/extensions/common/manifest_handlers/background_info.cc b/extensions/common/manifest_handlers/background_info.cc
index f32cc4b..1ec404e 100644
--- a/extensions/common/manifest_handlers/background_info.cc
+++ b/extensions/common/manifest_handlers/background_info.cc
@@ -10,12 +10,12 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/common/extensions/permissions/permissions_data.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/file_util.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/switches.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/extensions/common/manifest_handlers/background_info.h b/extensions/common/manifest_handlers/background_info.h
index 40d4920..113c341 100644
--- a/extensions/common/manifest_handlers/background_info.h
+++ b/extensions/common/manifest_handlers/background_info.h
@@ -9,7 +9,7 @@
#include <vector>
#include "base/values.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_handler.h"
#include "url/gurl.h"
diff --git a/extensions/common/manifest_handlers/incognito_info.cc b/extensions/common/manifest_handlers/incognito_info.cc
index 686c84b..b57a8a6 100644
--- a/extensions/common/manifest_handlers/incognito_info.cc
+++ b/extensions/common/manifest_handlers/incognito_info.cc
@@ -7,7 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
diff --git a/extensions/common/manifest_handlers/incognito_info.h b/extensions/common/manifest_handlers/incognito_info.h
index b275761..cd44934 100644
--- a/extensions/common/manifest_handlers/incognito_info.h
+++ b/extensions/common/manifest_handlers/incognito_info.h
@@ -6,7 +6,7 @@
#define EXTENSIONS_COMMON_MANIFEST_HANDLERS_INCOGNITO_INFO_H_
#include "base/strings/string16.h"
-#include "chrome/common/extensions/extension.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_handler.h"
namespace extensions {
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc
new file mode 100644
index 0000000..f43d1d7
--- /dev/null
+++ b/extensions/common/permissions/permissions_data.cc
@@ -0,0 +1,626 @@
+// Copyright (c) 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/permissions_data.h"
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extensions_client.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/features/feature_provider.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handler.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permission_message_provider.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "extensions/common/switches.h"
+#include "extensions/common/url_pattern_set.h"
+#include "extensions/common/user_script.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
+
+// Custom checks for the experimental permission that can't be expressed in
+// _permission_features.json.
+bool CanSpecifyExperimentalPermission(const Extension* extension) {
+ if (extension->location() == Manifest::COMPONENT)
+ return true;
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalExtensionApis)) {
+ return true;
+ }
+
+ // We rely on the webstore to check access to experimental. This way we can
+ // whitelist extensions to have access to experimental in just the store, and
+ // not have to push a new version of the client.
+ if (extension->from_webstore())
+ return true;
+
+ return false;
+}
+
+// Checks whether the host |pattern| is allowed for the given |extension|,
+// given API permissions |permissions|.
+bool CanSpecifyHostPermission(const Extension* extension,
+ const URLPattern& pattern,
+ const APIPermissionSet& permissions) {
+ if (!pattern.match_all_urls() &&
+ pattern.MatchesScheme(chrome::kChromeUIScheme)) {
+ URLPatternSet chrome_scheme_hosts = ExtensionsClient::Get()->
+ GetPermittedChromeSchemeHosts(extension, permissions);
+ if (chrome_scheme_hosts.ContainsPattern(pattern))
+ return true;
+
+ // Component extensions can have access to all of chrome://*.
+ if (PermissionsData::CanExecuteScriptEverywhere(extension))
+ return true;
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kExtensionsOnChromeURLs)) {
+ return true;
+ }
+
+ // TODO(aboxhall): return from_webstore() when webstore handles blocking
+ // extensions which request chrome:// urls
+ return false;
+ }
+
+ // Otherwise, the valid schemes were handled by URLPattern.
+ return true;
+}
+
+// Parses the host and api permissions from the specified permission |key|
+// from |extension|'s manifest.
+bool ParseHelper(Extension* extension,
+ const char* key,
+ APIPermissionSet* api_permissions,
+ URLPatternSet* host_permissions,
+ string16* error) {
+ if (!extension->manifest()->HasKey(key))
+ return true;
+
+ const base::ListValue* permissions = NULL;
+ if (!extension->manifest()->GetList(key, &permissions)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions,
+ std::string());
+ return false;
+ }
+
+ // NOTE: We need to get the APIPermission before we check if features
+ // associated with them are available because the feature system does not
+ // know about aliases.
+
+ std::vector<std::string> host_data;
+ if (!APIPermissionSet::ParseFromJSON(
+ permissions, APIPermissionSet::kDisallowInternalPermissions,
+ api_permissions, error, &host_data)) {
+ return false;
+ }
+
+ // Verify feature availability of permissions.
+ std::vector<APIPermission::ID> to_remove;
+ FeatureProvider* permission_features =
+ FeatureProvider::GetPermissionFeatures();
+ for (APIPermissionSet::const_iterator iter = api_permissions->begin();
+ iter != api_permissions->end(); ++iter) {
+ Feature* feature = permission_features->GetFeature(iter->name());
+
+ // The feature should exist since we just got an APIPermission for it. The
+ // two systems should be updated together whenever a permission is added.
+ DCHECK(feature);
+ // http://crbug.com/176381
+ if (!feature) {
+ to_remove.push_back(iter->id());
+ continue;
+ }
+
+ Feature::Availability availability = feature->IsAvailableToManifest(
+ extension->id(),
+ extension->GetType(),
+ Feature::ConvertLocation(extension->location()),
+ extension->manifest_version());
+
+ if (!availability.is_available()) {
+ // Don't fail, but warn the developer that the manifest contains
+ // unrecognized permissions. This may happen legitimately if the
+ // extensions requests platform- or channel-specific permissions.
+ extension->AddInstallWarning(InstallWarning(availability.message(),
+ feature->name()));
+ to_remove.push_back(iter->id());
+ continue;
+ }
+
+ if (iter->id() == APIPermission::kExperimental) {
+ if (!CanSpecifyExperimentalPermission(extension)) {
+ *error = ASCIIToUTF16(errors::kExperimentalFlagRequired);
+ return false;
+ }
+ }
+ }
+
+ api_permissions->AddImpliedPermissions();
+
+ // Remove permissions that are not available to this extension.
+ for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin();
+ iter != to_remove.end(); ++iter) {
+ api_permissions->erase(*iter);
+ }
+
+ // Parse host pattern permissions.
+ const int kAllowedSchemes =
+ PermissionsData::CanExecuteScriptEverywhere(extension) ?
+ URLPattern::SCHEME_ALL : Extension::kValidHostPermissionSchemes;
+
+ for (std::vector<std::string>::const_iterator iter = host_data.begin();
+ iter != host_data.end(); ++iter) {
+ const std::string& permission_str = *iter;
+
+ // Check if it's a host pattern permission.
+ URLPattern pattern = URLPattern(kAllowedSchemes);
+ URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
+ if (parse_result == URLPattern::PARSE_SUCCESS) {
+ // The path component is not used for host permissions, so we force it
+ // to match all paths.
+ pattern.SetPath("/*");
+ int valid_schemes = pattern.valid_schemes();
+ if (pattern.MatchesScheme(chrome::kFileScheme) &&
+ !PermissionsData::CanExecuteScriptEverywhere(extension)) {
+ extension->set_wants_file_access(true);
+ if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS))
+ valid_schemes &= ~URLPattern::SCHEME_FILE;
+ }
+
+ if (pattern.scheme() != chrome::kChromeUIScheme &&
+ !PermissionsData::CanExecuteScriptEverywhere(extension)) {
+ // Keep chrome:// in allowed schemes only if it's explicitly requested
+ // or CanExecuteScriptEverywhere is true. If the
+ // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission
+ // will fail, so don't check the flag here.
+ valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
+ }
+ pattern.SetValidSchemes(valid_schemes);
+
+ if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) {
+ // TODO(aboxhall): make a warning (see pattern.match_all_urls() block
+ // below).
+ extension->AddInstallWarning(InstallWarning(
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidPermissionScheme, permission_str),
+ key,
+ permission_str));
+ continue;
+ }
+
+ host_permissions->AddPattern(pattern);
+ // We need to make sure all_urls matches chrome://favicon and (maybe)
+ // chrome://thumbnail, so add them back in to host_permissions separately.
+ if (pattern.match_all_urls()) {
+ host_permissions->AddPatterns(
+ ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
+ extension, *api_permissions));
+ }
+ continue;
+ }
+
+ // It's probably an unknown API permission. Do not throw an error so
+ // extensions can retain backwards compatability (http://crbug.com/42742).
+ extension->AddInstallWarning(InstallWarning(
+ ErrorUtils::FormatErrorMessage(
+ manifest_errors::kPermissionUnknownOrMalformed,
+ permission_str),
+ key,
+ permission_str));
+ }
+
+ return true;
+}
+
+// Returns true if this extension id is from a trusted provider.
+bool IsTrustedId(const std::string& extension_id) {
+ // See http://b/4946060 for more details.
+ return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
+}
+
+} // namespace
+
+struct PermissionsData::InitialPermissions {
+ APIPermissionSet api_permissions;
+ ManifestPermissionSet manifest_permissions;
+ URLPatternSet host_permissions;
+ URLPatternSet scriptable_hosts;
+};
+
+PermissionsData::PermissionsData() {
+}
+
+PermissionsData::~PermissionsData() {
+}
+
+// static
+void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
+ g_policy_delegate = delegate;
+}
+
+// static
+const PermissionSet* PermissionsData::GetOptionalPermissions(
+ const Extension* extension) {
+ return extension->permissions_data()->optional_permission_set_.get();
+}
+
+// static
+const PermissionSet* PermissionsData::GetRequiredPermissions(
+ const Extension* extension) {
+ return extension->permissions_data()->required_permission_set_.get();
+}
+
+// static
+const APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
+ const Extension* extension) {
+ return &extension->permissions_data()->
+ initial_required_permissions_->api_permissions;
+}
+
+// static
+APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
+ Extension* extension) {
+ return &extension->permissions_data()->
+ initial_required_permissions_->api_permissions;
+}
+
+// static
+void PermissionsData::SetInitialScriptableHosts(
+ Extension* extension, const URLPatternSet& scriptable_hosts) {
+ extension->permissions_data()->
+ initial_required_permissions_->scriptable_hosts = scriptable_hosts;
+}
+
+// static
+void PermissionsData::SetActivePermissions(const Extension* extension,
+ const PermissionSet* permissions) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ extension->permissions_data()->active_permissions_ = permissions;
+}
+
+// static
+scoped_refptr<const PermissionSet> PermissionsData::GetActivePermissions(
+ const Extension* extension) {
+ return extension->permissions_data()->active_permissions_;
+}
+
+// static
+scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
+ const Extension* extension,
+ int tab_id) {
+ CHECK_GE(tab_id, 0);
+ TabPermissionsMap::const_iterator iter =
+ extension->permissions_data()->tab_specific_permissions_.find(tab_id);
+ return
+ (iter != extension->permissions_data()->tab_specific_permissions_.end())
+ ? iter->second
+ : NULL;
+}
+
+// static
+void PermissionsData::UpdateTabSpecificPermissions(
+ const Extension* extension,
+ int tab_id,
+ scoped_refptr<const PermissionSet> permissions) {
+ CHECK_GE(tab_id, 0);
+ TabPermissionsMap* tab_permissions =
+ &extension->permissions_data()->tab_specific_permissions_;
+ if (tab_permissions->count(tab_id)) {
+ (*tab_permissions)[tab_id] = PermissionSet::CreateUnion(
+ (*tab_permissions)[tab_id].get(), permissions.get());
+ } else {
+ (*tab_permissions)[tab_id] = permissions;
+ }
+}
+
+// static
+void PermissionsData::ClearTabSpecificPermissions(
+ const Extension* extension,
+ int tab_id) {
+ CHECK_GE(tab_id, 0);
+ extension->permissions_data()->tab_specific_permissions_.erase(tab_id);
+}
+
+// static
+bool PermissionsData::HasAPIPermission(const Extension* extension,
+ APIPermission::ID permission) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ return GetActivePermissions(extension)->HasAPIPermission(permission);
+}
+
+// static
+bool PermissionsData::HasAPIPermission(
+ const Extension* extension,
+ const std::string& permission_name) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ return GetActivePermissions(extension)->HasAPIPermission(permission_name);
+}
+
+// static
+bool PermissionsData::HasAPIPermissionForTab(
+ const Extension* extension,
+ int tab_id,
+ APIPermission::ID permission) {
+ if (HasAPIPermission(extension, permission))
+ return true;
+
+ // Place autolock below the HasAPIPermission() check, since HasAPIPermission
+ // also acquires the lock.
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ scoped_refptr<const PermissionSet> tab_permissions =
+ GetTabSpecificPermissions(extension, tab_id);
+ return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
+}
+
+// static
+bool PermissionsData::CheckAPIPermissionWithParam(
+ const Extension* extension,
+ APIPermission::ID permission,
+ const APIPermission::CheckParam* param) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ return GetActivePermissions(extension)->CheckAPIPermissionWithParam(
+ permission, param);
+}
+
+// static
+const URLPatternSet& PermissionsData::GetEffectiveHostPermissions(
+ const Extension* extension) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ return GetActivePermissions(extension)->effective_hosts();
+}
+
+// static
+bool PermissionsData::CanSilentlyIncreasePermissions(
+ const Extension* extension) {
+ return extension->location() != Manifest::INTERNAL;
+}
+
+// static
+bool PermissionsData::ShouldSkipPermissionWarnings(const Extension* extension) {
+ return IsTrustedId(extension->id());
+}
+
+// static
+bool PermissionsData::HasHostPermission(const Extension* extension,
+ const GURL& url) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ return GetActivePermissions(extension)->HasExplicitAccessToOrigin(url);
+}
+
+// static
+bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension* extension) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ return GetActivePermissions(extension)->HasEffectiveAccessToAllHosts();
+}
+
+// static
+PermissionMessages PermissionsData::GetPermissionMessages(
+ const Extension* extension) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ if (ShouldSkipPermissionWarnings(extension)) {
+ return PermissionMessages();
+ } else {
+ return PermissionMessageProvider::Get()->GetPermissionMessages(
+ GetActivePermissions(extension), extension->GetType());
+ }
+}
+
+// static
+std::vector<string16> PermissionsData::GetPermissionMessageStrings(
+ const Extension* extension) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ if (ShouldSkipPermissionWarnings(extension)) {
+ return std::vector<string16>();
+ } else {
+ return PermissionMessageProvider::Get()->GetWarningMessages(
+ GetActivePermissions(extension), extension->GetType());
+ }
+}
+
+// static
+std::vector<string16> PermissionsData::GetPermissionMessageDetailsStrings(
+ const Extension* extension) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ if (ShouldSkipPermissionWarnings(extension)) {
+ return std::vector<string16>();
+ } else {
+ return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
+ GetActivePermissions(extension), extension->GetType());
+ }
+}
+
+// static
+bool PermissionsData::CanExecuteScriptOnPage(const Extension* extension,
+ const GURL& document_url,
+ const GURL& top_frame_url,
+ int tab_id,
+ const UserScript* script,
+ int process_id,
+ std::string* error) {
+ base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ bool can_execute_everywhere = CanExecuteScriptEverywhere(extension);
+
+ if (g_policy_delegate &&
+ !g_policy_delegate->CanExecuteScriptOnPage(
+ extension, document_url, top_frame_url, tab_id,
+ script, process_id, error))
+ return false;
+
+ if (!can_execute_everywhere &&
+ !ExtensionsClient::Get()->IsScriptableURL(document_url, error)) {
+ return false;
+ }
+
+ if (!command_line->HasSwitch(switches::kExtensionsOnChromeURLs)) {
+ if (document_url.SchemeIs(chrome::kChromeUIScheme) &&
+ !can_execute_everywhere) {
+ if (error)
+ *error = errors::kCannotAccessChromeUrl;
+ return false;
+ }
+ }
+
+ if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
+ top_frame_url.GetOrigin() !=
+ Extension::GetBaseURLFromExtensionId(extension->id()).GetOrigin() &&
+ !can_execute_everywhere) {
+ if (error)
+ *error = errors::kCannotAccessExtensionUrl;
+ return false;
+ }
+
+ // If a tab ID is specified, try the tab-specific permissions.
+ if (tab_id >= 0) {
+ scoped_refptr<const PermissionSet> tab_permissions =
+ GetTabSpecificPermissions(extension, tab_id);
+ if (tab_permissions.get() &&
+ tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
+ return true;
+ }
+ }
+
+ bool can_access = false;
+
+ if (script) {
+ // If a script is specified, use its matches.
+ can_access = script->MatchesURL(document_url);
+ } else {
+ // Otherwise, see if this extension has permission to execute script
+ // programmatically on pages.
+ can_access = GetActivePermissions(extension)->
+ HasExplicitAccessToOrigin(document_url);
+ }
+
+ if (!can_access && error) {
+ *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
+ document_url.spec());
+ }
+
+ return can_access;
+}
+
+// static
+bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
+ if (extension->location() == Manifest::COMPONENT)
+ return true;
+
+ const ExtensionsClient::ScriptingWhitelist& whitelist =
+ ExtensionsClient::Get()->GetScriptingWhitelist();
+
+ return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
+ whitelist.end();
+}
+
+// static
+bool PermissionsData::CanCaptureVisiblePage(const Extension* extension,
+ const GURL& page_url,
+ int tab_id,
+ std::string* error) {
+ if (tab_id >= 0) {
+ scoped_refptr<const PermissionSet> tab_permissions =
+ GetTabSpecificPermissions(extension, tab_id);
+ if (tab_permissions.get() &&
+ tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) {
+ return true;
+ }
+ }
+
+ if (HasHostPermission(extension, page_url) ||
+ page_url.GetOrigin() == extension->url()) {
+ return true;
+ }
+
+ if (error) {
+ *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
+ page_url.spec());
+ }
+ return false;
+}
+
+bool PermissionsData::ParsePermissions(Extension* extension, string16* error) {
+ initial_required_permissions_.reset(new InitialPermissions);
+ if (!ParseHelper(extension,
+ keys::kPermissions,
+ &initial_required_permissions_->api_permissions,
+ &initial_required_permissions_->host_permissions,
+ error)) {
+ return false;
+ }
+
+ // TODO(jeremya/kalman) do this via the features system by exposing the
+ // app.window API to platform apps, with no dependency on any permissions.
+ // See http://crbug.com/120069.
+ if (extension->is_platform_app()) {
+ initial_required_permissions_->api_permissions.insert(
+ APIPermission::kAppCurrentWindowInternal);
+ initial_required_permissions_->api_permissions.insert(
+ APIPermission::kAppRuntime);
+ initial_required_permissions_->api_permissions.insert(
+ APIPermission::kAppWindow);
+ }
+
+ initial_optional_permissions_.reset(new InitialPermissions);
+ if (!ParseHelper(extension,
+ keys::kOptionalPermissions,
+ &initial_optional_permissions_->api_permissions,
+ &initial_optional_permissions_->host_permissions,
+ error)) {
+ return false;
+ }
+
+ return true;
+}
+
+void PermissionsData::InitializeManifestPermissions(Extension* extension) {
+ ManifestHandler::AddExtensionInitialRequiredPermissions(
+ extension, &initial_required_permissions_->manifest_permissions);
+}
+
+void PermissionsData::FinalizePermissions(Extension* extension) {
+ active_permissions_ = new PermissionSet(
+ initial_required_permissions_->api_permissions,
+ initial_required_permissions_->manifest_permissions,
+ initial_required_permissions_->host_permissions,
+ initial_required_permissions_->scriptable_hosts);
+
+ required_permission_set_ = new PermissionSet(
+ initial_required_permissions_->api_permissions,
+ initial_required_permissions_->manifest_permissions,
+ initial_required_permissions_->host_permissions,
+ initial_required_permissions_->scriptable_hosts);
+
+ optional_permission_set_ = new PermissionSet(
+ initial_optional_permissions_->api_permissions,
+ initial_optional_permissions_->manifest_permissions,
+ initial_optional_permissions_->host_permissions,
+ URLPatternSet());
+
+ initial_required_permissions_.reset();
+ initial_optional_permissions_.reset();
+}
+
+} // namespace extensions
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h
new file mode 100644
index 0000000..72b9d24
--- /dev/null
+++ b/extensions/common/permissions/permissions_data.h
@@ -0,0 +1,218 @@
+// Copyright (c) 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_PERMISSIONS_DATA_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_PERMISSIONS_DATA_H_
+
+#include <map>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/synchronization/lock.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permission_message.h"
+
+class GURL;
+
+namespace extensions {
+
+class PermissionSet;
+class APIPermissionSet;
+class Extension;
+class ManifestPermissionSet;
+class URLPatternSet;
+class UserScript;
+
+// A container for the permissions data of the extension; also responsible for
+// parsing the "permissions" and "optional_permissions" manifest keys. This
+// class also contains the active (runtime) permissions for the extension.
+class PermissionsData {
+ public:
+ PermissionsData();
+ ~PermissionsData();
+
+ // Delegate class to allow different contexts (e.g. browser vs renderer) to
+ // have control over policy decisions.
+ class PolicyDelegate {
+ public:
+ virtual ~PolicyDelegate() {}
+
+ // Returns false if script access should be blocked on this page.
+ // Otherwise, default policy should decide.
+ virtual bool CanExecuteScriptOnPage(const Extension* extension,
+ const GURL& document_url,
+ const GURL& top_document_url,
+ int tab_id,
+ const UserScript* script,
+ int process_id,
+ std::string* error) = 0;
+ };
+
+ static void SetPolicyDelegate(PolicyDelegate* delegate);
+
+ // Return the optional or required permission set for the given |extension|.
+ static const PermissionSet* GetOptionalPermissions(
+ const Extension* extension);
+ static const PermissionSet* GetRequiredPermissions(
+ const Extension* extension);
+
+ // Return the temporary API permission set which is used during extension
+ // initialization. Once initialization completes, this is NULL.
+ static const APIPermissionSet* GetInitialAPIPermissions(
+ const Extension* extension);
+ static APIPermissionSet* GetInitialAPIPermissions(Extension* extension);
+
+ // Set the scriptable hosts for the given |extension| during initialization.
+ static void SetInitialScriptableHosts(Extension* extension,
+ const URLPatternSet& scriptable_hosts);
+
+ // Return the active (runtime) permissions for the given |extension|.
+ static scoped_refptr<const PermissionSet> GetActivePermissions(
+ const Extension* extension);
+ // Sets the runtime permissions of the given |extension| to |permissions|.
+ static void SetActivePermissions(const Extension* extension,
+ const PermissionSet* active);
+
+ // Gets the tab-specific host permissions of |tab_id|, or NULL if there
+ // aren't any.
+ static scoped_refptr<const PermissionSet> GetTabSpecificPermissions(
+ const Extension* extension,
+ int tab_id);
+ // Updates the tab-specific permissions of |tab_id| to include those from
+ // |permissions|.
+ static void UpdateTabSpecificPermissions(
+ const Extension* extension,
+ int tab_id,
+ scoped_refptr<const PermissionSet> permissions);
+ // Clears the tab-specific permissions of |tab_id|.
+ static void ClearTabSpecificPermissions(const Extension* extension,
+ int tab_id);
+
+ // Returns true if the |extension| has the given |permission|. Prefer
+ // IsExtensionWithPermissionOrSuggestInConsole when developers may be using an
+ // api that requires a permission they didn't know about, e.g. open web apis.
+ // Note this does not include APIs with no corresponding permission, like
+ // "runtime" or "browserAction".
+ // TODO(mpcomplete): drop the "API" from these names, it's confusing.
+ static bool HasAPIPermission(const Extension* extension,
+ APIPermission::ID permission);
+ static bool HasAPIPermission(const Extension* extension,
+ const std::string& permission_name);
+ static bool HasAPIPermissionForTab(const Extension* extension,
+ int tab_id,
+ APIPermission::ID permission);
+
+ static bool CheckAPIPermissionWithParam(
+ const Extension* extension,
+ APIPermission::ID permission,
+ const APIPermission::CheckParam* param);
+
+ static const URLPatternSet& GetEffectiveHostPermissions(
+ const Extension* extension);
+
+ // Returns true if the |extension| can silently increase its permission level.
+ // Users must approve permissions for unpacked and packed extensions in the
+ // following situations:
+ // - when installing or upgrading packed extensions
+ // - when installing unpacked extensions that have NPAPI plugins
+ // - when either type of extension requests optional permissions
+ static bool CanSilentlyIncreasePermissions(const Extension* extension);
+
+ // Returns true if the extension does not require permission warnings
+ // to be displayed at install time.
+ static bool ShouldSkipPermissionWarnings(const Extension* extension);
+
+ // Whether the |extension| has access to the given |url|.
+ static bool HasHostPermission(const Extension* extension, const GURL& url);
+
+ // Whether the |extension| has effective access to all hosts. This is true if
+ // there is a content script that matches all hosts, if there is a host
+ // permission grants access to all hosts (like <all_urls>) or an api
+ // permission that effectively grants access to all hosts (e.g. proxy,
+ // network, etc.)
+ static bool HasEffectiveAccessToAllHosts(const Extension* extension);
+
+ // Returns the full list of permission messages that the given |extension|
+ // should display at install time.
+ static PermissionMessages GetPermissionMessages(const Extension* extension);
+ // Returns the full list of permission messages that the given |extension|
+ // should display at install time. The messages are returned as strings
+ // for convenience.
+ static std::vector<string16> GetPermissionMessageStrings(
+ const Extension* extension);
+
+ // Returns the full list of permission details for messages that the given
+ // |extension| should display at install time. The messages are returned as
+ // strings for convenience.
+ static std::vector<string16> GetPermissionMessageDetailsStrings(
+ const Extension* extension);
+
+ // Returns true if the given |extension| can execute script on a page. If a
+ // UserScript object is passed, permission to run that specific script is
+ // checked (using its matches list). Otherwise, permission to execute script
+ // programmatically is checked (using the extension's host permission).
+ //
+ // This method is also aware of certain special pages that extensions are
+ // usually not allowed to run script on.
+ static bool CanExecuteScriptOnPage(const Extension* extension,
+ const GURL& document_url,
+ const GURL& top_document_url,
+ int tab_id,
+ const UserScript* script,
+ int process_id,
+ std::string* error);
+
+ // Returns true if the given |extension| is a COMPONENT extension, or if it is
+ // on the whitelist of extensions that can script all pages.
+ static bool CanExecuteScriptEverywhere(const Extension* extension);
+
+ // Returns true if the |extension| is allowed to obtain the contents of a
+ // page as an image. Since a page may contain sensitive information, this
+ // is restricted to the extension's host permissions as well as the
+ // extension page itself.
+ static bool CanCaptureVisiblePage(const Extension* extension,
+ const GURL& page_url,
+ int tab_id,
+ std::string* error);
+
+ // Parse the permissions of a given extension in the initialization process.
+ bool ParsePermissions(Extension* extension, string16* error);
+
+ // Ensure manifest handlers provide their custom manifest permissions.
+ void InitializeManifestPermissions(Extension* extension);
+
+ // Finalize permissions after the initialization process completes.
+ void FinalizePermissions(Extension* extension);
+
+ private:
+ struct InitialPermissions;
+ typedef std::map<int, scoped_refptr<const PermissionSet> > TabPermissionsMap;
+
+ // Temporary permissions during the initialization process; NULL after
+ // initialization completes.
+ scoped_ptr<InitialPermissions> initial_required_permissions_;
+ scoped_ptr<InitialPermissions> initial_optional_permissions_;
+
+ // The set of permissions the extension can request at runtime.
+ scoped_refptr<const PermissionSet> optional_permission_set_;
+
+ // The extension's required / default set of permissions.
+ scoped_refptr<const PermissionSet> required_permission_set_;
+
+ mutable base::Lock runtime_lock_;
+
+ // The permission's which are currently active on the extension during
+ // runtime.
+ mutable scoped_refptr<const PermissionSet> active_permissions_;
+
+ mutable TabPermissionsMap tab_specific_permissions_;
+
+ DISALLOW_COPY_AND_ASSIGN(PermissionsData);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_PERMISSIONS_PERMISSIONS_DATA_H_
diff --git a/extensions/common/permissions/permissions_data_unittest.cc b/extensions/common/permissions/permissions_data_unittest.cc
new file mode 100644
index 0000000..3ea4856
--- /dev/null
+++ b/extensions/common/permissions/permissions_data_unittest.cc
@@ -0,0 +1,620 @@
+// Copyright (c) 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 <vector>
+
+#include "base/command_line.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/extensions/extension_test_util.h"
+#include "chrome/common/extensions/features/feature_channel.h"
+#include "chrome/common/extensions/permissions/socket_permission.h"
+#include "content/public/common/socket_permission_request.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/id_util.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/switches.h"
+#include "extensions/common/url_pattern_set.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::SocketPermissionRequest;
+using extension_test_util::LoadManifest;
+using extension_test_util::LoadManifestUnchecked;
+using extension_test_util::LoadManifestStrict;
+
+namespace extensions {
+
+namespace {
+
+bool CheckSocketPermission(
+ scoped_refptr<Extension> extension,
+ SocketPermissionRequest::OperationType type,
+ const char* host,
+ int port) {
+ SocketPermission::CheckParam param(type, host, port);
+ return PermissionsData::CheckAPIPermissionWithParam(
+ extension.get(), APIPermission::kSocket, &param);
+}
+
+} // namespace
+
+TEST(ExtensionPermissionsTest, EffectiveHostPermissions) {
+ scoped_refptr<Extension> extension;
+ URLPatternSet hosts;
+
+ extension = LoadManifest("effective_host_permissions", "empty.json");
+ EXPECT_EQ(0u,
+ PermissionsData::GetEffectiveHostPermissions(extension.get())
+ .patterns().size());
+ EXPECT_FALSE(hosts.MatchesURL(GURL("http://www.google.com")));
+ EXPECT_FALSE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions", "one_host.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.google.com")));
+ EXPECT_FALSE(hosts.MatchesURL(GURL("https://www.google.com")));
+ EXPECT_FALSE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions",
+ "one_host_wildcard.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://google.com")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://foo.google.com")));
+ EXPECT_FALSE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions", "two_hosts.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.reddit.com")));
+ EXPECT_FALSE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions",
+ "https_not_considered.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://google.com")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("https://google.com")));
+ EXPECT_FALSE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions",
+ "two_content_scripts.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://google.com")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.reddit.com")));
+ EXPECT_TRUE(extension->GetActivePermissions()->HasEffectiveAccessToURL(
+ GURL("http://www.reddit.com")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://news.ycombinator.com")));
+ EXPECT_TRUE(extension->GetActivePermissions()->HasEffectiveAccessToURL(
+ GURL("http://news.ycombinator.com")));
+ EXPECT_FALSE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions", "all_hosts.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://test/")));
+ EXPECT_FALSE(hosts.MatchesURL(GURL("https://test/")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions", "all_hosts2.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://test/")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+
+ extension = LoadManifest("effective_host_permissions", "all_hosts3.json");
+ hosts = PermissionsData::GetEffectiveHostPermissions(extension.get());
+ EXPECT_FALSE(hosts.MatchesURL(GURL("http://test/")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("https://test/")));
+ EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(PermissionsData::HasEffectiveAccessToAllHosts(extension.get()));
+}
+
+TEST(ExtensionPermissionsTest, SocketPermissions) {
+ // Set feature current channel to appropriate value.
+ ScopedCurrentChannel scoped_channel(chrome::VersionInfo::CHANNEL_DEV);
+ scoped_refptr<Extension> extension;
+ std::string error;
+
+ extension = LoadManifest("socket_permissions", "empty.json");
+ EXPECT_FALSE(CheckSocketPermission(extension,
+ SocketPermissionRequest::TCP_CONNECT, "www.example.com", 80));
+
+ extension = LoadManifestUnchecked("socket_permissions",
+ "socket1.json",
+ Manifest::INTERNAL, Extension::NO_FLAGS,
+ &error);
+ EXPECT_TRUE(extension.get() == NULL);
+ ASSERT_EQ(ErrorUtils::FormatErrorMessage(
+ manifest_errors::kInvalidPermission, "socket"),
+ error);
+
+ extension = LoadManifest("socket_permissions", "socket2.json");
+ EXPECT_TRUE(CheckSocketPermission(extension,
+ SocketPermissionRequest::TCP_CONNECT, "www.example.com", 80));
+ EXPECT_FALSE(CheckSocketPermission(
+ extension, SocketPermissionRequest::UDP_BIND, "", 80));
+ EXPECT_TRUE(CheckSocketPermission(
+ extension, SocketPermissionRequest::UDP_BIND, "", 8888));
+
+ EXPECT_FALSE(CheckSocketPermission(
+ extension, SocketPermissionRequest::UDP_SEND_TO, "example.com", 1900));
+ EXPECT_TRUE(CheckSocketPermission(
+ extension,
+ SocketPermissionRequest::UDP_SEND_TO,
+ "239.255.255.250", 1900));
+}
+
+TEST(ExtensionPermissionsTest, GetPermissionMessages_ManyAPIPermissions) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("permissions", "many-apis.json");
+ std::vector<string16> warnings =
+ PermissionsData::GetPermissionMessageStrings(extension.get());
+ ASSERT_EQ(6u, warnings.size());
+ EXPECT_EQ("Access your data on api.flickr.com",
+ UTF16ToUTF8(warnings[0]));
+ EXPECT_EQ("Read and modify your bookmarks", UTF16ToUTF8(warnings[1]));
+ EXPECT_EQ("Detect your physical location", UTF16ToUTF8(warnings[2]));
+ EXPECT_EQ("Read and modify your browsing history", UTF16ToUTF8(warnings[3]));
+ EXPECT_EQ("Access your tabs and browsing activity", UTF16ToUTF8(warnings[4]));
+ EXPECT_EQ("Manage your apps, extensions, and themes",
+ UTF16ToUTF8(warnings[5]));
+}
+
+TEST(ExtensionPermissionsTest, GetPermissionMessages_ManyHostsPermissions) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("permissions", "more-than-3-hosts.json");
+ std::vector<string16> warnings =
+ PermissionsData::GetPermissionMessageStrings(extension.get());
+ std::vector<string16> warnings_details =
+ PermissionsData::GetPermissionMessageDetailsStrings(extension.get());
+ ASSERT_EQ(1u, warnings.size());
+ ASSERT_EQ(1u, warnings_details.size());
+ EXPECT_EQ("Access your data on 5 websites", UTF16ToUTF8(warnings[0]));
+ EXPECT_EQ("- www.a.com\n- www.b.com\n- www.c.com\n- www.d.com\n- www.e.com",
+ UTF16ToUTF8(warnings_details[0]));
+}
+
+TEST(ExtensionPermissionsTest, GetPermissionMessages_LocationApiPermission) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("permissions",
+ "location-api.json",
+ Manifest::COMPONENT,
+ Extension::NO_FLAGS);
+ std::vector<string16> warnings =
+ PermissionsData::GetPermissionMessageStrings(extension.get());
+ ASSERT_EQ(1u, warnings.size());
+ EXPECT_EQ("Detect your physical location", UTF16ToUTF8(warnings[0]));
+}
+
+TEST(ExtensionPermissionsTest, GetPermissionMessages_ManyHosts) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("permissions", "many-hosts.json");
+ std::vector<string16> warnings =
+ PermissionsData::GetPermissionMessageStrings(extension.get());
+ ASSERT_EQ(1u, warnings.size());
+ EXPECT_EQ("Access your data on encrypted.google.com and www.google.com",
+ UTF16ToUTF8(warnings[0]));
+}
+
+TEST(ExtensionPermissionsTest, GetPermissionMessages_Plugins) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("permissions", "plugins.json");
+ std::vector<string16> warnings =
+ PermissionsData::GetPermissionMessageStrings(extension.get());
+// We don't parse the plugins key on Chrome OS, so it should not ask for any
+// permissions.
+#if defined(OS_CHROMEOS)
+ ASSERT_EQ(0u, warnings.size());
+#else
+ ASSERT_EQ(1u, warnings.size());
+ EXPECT_EQ("Access all data on your computer and the websites you visit",
+ UTF16ToUTF8(warnings[0]));
+#endif
+}
+
+// Base class for testing the CanExecuteScriptOnPage and CanCaptureVisiblePage
+// methods of Extension for extensions with various permissions.
+class ExtensionScriptAndCaptureVisibleTest : public testing::Test {
+ protected:
+ ExtensionScriptAndCaptureVisibleTest()
+ : http_url("http://www.google.com"),
+ http_url_with_path("http://www.google.com/index.html"),
+ https_url("https://www.google.com"),
+ file_url("file:///foo/bar"),
+ favicon_url("chrome://favicon/http://www.google.com"),
+ extension_url("chrome-extension://" +
+ id_util::GenerateIdForPath(
+ base::FilePath(FILE_PATH_LITERAL("foo")))),
+ settings_url("chrome://settings"),
+ about_url("about:flags") {
+ urls_.insert(http_url);
+ urls_.insert(http_url_with_path);
+ urls_.insert(https_url);
+ urls_.insert(file_url);
+ urls_.insert(favicon_url);
+ urls_.insert(extension_url);
+ urls_.insert(settings_url);
+ urls_.insert(about_url);
+ // Ignore the policy delegate for this test.
+ PermissionsData::SetPolicyDelegate(NULL);
+ }
+
+ bool AllowedScript(const Extension* extension, const GURL& url,
+ const GURL& top_url) {
+ return PermissionsData::CanExecuteScriptOnPage(
+ extension, url, top_url, -1, NULL, -1, NULL);
+ }
+
+ bool BlockedScript(const Extension* extension, const GURL& url,
+ const GURL& top_url) {
+ return !PermissionsData::CanExecuteScriptOnPage(
+ extension, url, top_url, -1, NULL, -1, NULL);
+ }
+
+ bool Allowed(const Extension* extension, const GURL& url) {
+ return Allowed(extension, url, -1);
+ }
+
+ bool Allowed(const Extension* extension, const GURL& url, int tab_id) {
+ return (PermissionsData::CanExecuteScriptOnPage(
+ extension, url, url, tab_id, NULL, -1, NULL) &&
+ PermissionsData::CanCaptureVisiblePage(
+ extension, url, tab_id, NULL));
+ }
+
+ bool CaptureOnly(const Extension* extension, const GURL& url) {
+ return CaptureOnly(extension, url, -1);
+ }
+
+ bool CaptureOnly(const Extension* extension, const GURL& url, int tab_id) {
+ return !PermissionsData::CanExecuteScriptOnPage(
+ extension, url, url, tab_id, NULL, -1, NULL) &&
+ PermissionsData::CanCaptureVisiblePage(extension, url, tab_id, NULL);
+ }
+
+ bool Blocked(const Extension* extension, const GURL& url) {
+ return Blocked(extension, url, -1);
+ }
+
+ bool Blocked(const Extension* extension, const GURL& url, int tab_id) {
+ return !(PermissionsData::CanExecuteScriptOnPage(
+ extension, url, url, tab_id, NULL, -1, NULL) ||
+ PermissionsData::CanCaptureVisiblePage(
+ extension, url, tab_id, NULL));
+ }
+
+ bool AllowedExclusivelyOnTab(
+ const Extension* extension,
+ const std::set<GURL>& allowed_urls,
+ int tab_id) {
+ bool result = true;
+ for (std::set<GURL>::iterator it = urls_.begin(); it != urls_.end(); ++it) {
+ const GURL& url = *it;
+ if (allowed_urls.count(url))
+ result &= Allowed(extension, url, tab_id);
+ else
+ result &= Blocked(extension, url, tab_id);
+ }
+ return result;
+ }
+
+ // URLs that are "safe" to provide scripting and capture visible tab access
+ // to if the permissions allow it.
+ const GURL http_url;
+ const GURL http_url_with_path;
+ const GURL https_url;
+ const GURL file_url;
+
+ // We should allow host permission but not scripting permission for favicon
+ // urls.
+ const GURL favicon_url;
+
+ // URLs that regular extensions should never get access to.
+ const GURL extension_url;
+ const GURL settings_url;
+ const GURL about_url;
+
+ private:
+ // The set of all URLs above.
+ std::set<GURL> urls_;
+};
+
+TEST_F(ExtensionScriptAndCaptureVisibleTest, Permissions) {
+ // Test <all_urls> for regular extensions.
+ scoped_refptr<Extension> extension = LoadManifestStrict("script_and_capture",
+ "extension_regular_all.json");
+
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Allowed(extension.get(), https_url));
+ EXPECT_TRUE(Blocked(extension.get(), file_url));
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(CaptureOnly(extension.get(), favicon_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(Blocked(extension.get(), extension_url));
+
+ // Test access to iframed content.
+ GURL within_extension_url = extension->GetResourceURL("page.html");
+ EXPECT_TRUE(AllowedScript(extension.get(), http_url, http_url_with_path));
+ EXPECT_TRUE(AllowedScript(extension.get(), https_url, http_url_with_path));
+ EXPECT_TRUE(AllowedScript(extension.get(), http_url, within_extension_url));
+ EXPECT_TRUE(AllowedScript(extension.get(), https_url, within_extension_url));
+ EXPECT_TRUE(BlockedScript(extension.get(), http_url, extension_url));
+ EXPECT_TRUE(BlockedScript(extension.get(), https_url, extension_url));
+
+ EXPECT_FALSE(
+ PermissionsData::HasHostPermission(extension.get(), settings_url));
+ EXPECT_FALSE(PermissionsData::HasHostPermission(extension.get(), about_url));
+ EXPECT_TRUE(PermissionsData::HasHostPermission(extension.get(), favicon_url));
+
+ // Test * for scheme, which implies just the http/https schemes.
+ extension = LoadManifestStrict("script_and_capture",
+ "extension_wildcard.json");
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Allowed(extension.get(), https_url));
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(Blocked(extension.get(), file_url));
+ EXPECT_TRUE(Blocked(extension.get(), favicon_url));
+ extension =
+ LoadManifest("script_and_capture", "extension_wildcard_settings.json");
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+
+ // Having chrome://*/ should not work for regular extensions. Note that
+ // for favicon access, we require the explicit pattern chrome://favicon/*.
+ std::string error;
+ extension = LoadManifestUnchecked("script_and_capture",
+ "extension_wildcard_chrome.json",
+ Manifest::INTERNAL, Extension::NO_FLAGS,
+ &error);
+ std::vector<InstallWarning> warnings = extension->install_warnings();
+ EXPECT_FALSE(warnings.empty());
+ EXPECT_EQ(ErrorUtils::FormatErrorMessage(
+ manifest_errors::kInvalidPermissionScheme,
+ "chrome://*/"),
+ warnings[0].message);
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), favicon_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+
+ // Having chrome://favicon/* should not give you chrome://*
+ extension = LoadManifestStrict("script_and_capture",
+ "extension_chrome_favicon_wildcard.json");
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(CaptureOnly(extension.get(), favicon_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(PermissionsData::HasHostPermission(extension.get(), favicon_url));
+
+ // Having http://favicon should not give you chrome://favicon
+ extension = LoadManifestStrict("script_and_capture",
+ "extension_http_favicon.json");
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), favicon_url));
+
+ // Component extensions with <all_urls> should get everything.
+ extension = LoadManifest("script_and_capture", "extension_component_all.json",
+ Manifest::COMPONENT, Extension::NO_FLAGS);
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Allowed(extension.get(), https_url));
+ EXPECT_TRUE(Allowed(extension.get(), settings_url));
+ EXPECT_TRUE(Allowed(extension.get(), about_url));
+ EXPECT_TRUE(Allowed(extension.get(), favicon_url));
+ EXPECT_TRUE(PermissionsData::HasHostPermission(extension.get(), favicon_url));
+
+ // Component extensions should only get access to what they ask for.
+ extension = LoadManifest("script_and_capture",
+ "extension_component_google.json", Manifest::COMPONENT,
+ Extension::NO_FLAGS);
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Blocked(extension.get(), https_url));
+ EXPECT_TRUE(Blocked(extension.get(), file_url));
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), favicon_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(Blocked(extension.get(), extension_url));
+ EXPECT_FALSE(
+ PermissionsData::HasHostPermission(extension.get(), settings_url));
+}
+
+TEST_F(ExtensionScriptAndCaptureVisibleTest, PermissionsWithChromeURLsEnabled) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kExtensionsOnChromeURLs);
+
+ scoped_refptr<Extension> extension;
+
+ // Test <all_urls> for regular extensions.
+ extension = LoadManifestStrict("script_and_capture",
+ "extension_regular_all.json");
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Allowed(extension.get(), https_url));
+ EXPECT_TRUE(Blocked(extension.get(), file_url));
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Allowed(extension.get(), favicon_url)); // chrome:// requested
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(Blocked(extension.get(), extension_url));
+
+ // Test access to iframed content.
+ GURL within_extension_url = extension->GetResourceURL("page.html");
+ EXPECT_TRUE(AllowedScript(extension.get(), http_url, http_url_with_path));
+ EXPECT_TRUE(AllowedScript(extension.get(), https_url, http_url_with_path));
+ EXPECT_TRUE(AllowedScript(extension.get(), http_url, within_extension_url));
+ EXPECT_TRUE(AllowedScript(extension.get(), https_url, within_extension_url));
+ EXPECT_TRUE(BlockedScript(extension.get(), http_url, extension_url));
+ EXPECT_TRUE(BlockedScript(extension.get(), https_url, extension_url));
+
+ EXPECT_FALSE(
+ PermissionsData::HasHostPermission(extension.get(), settings_url));
+ EXPECT_FALSE(PermissionsData::HasHostPermission(extension.get(), about_url));
+ EXPECT_TRUE(PermissionsData::HasHostPermission(extension.get(), favicon_url));
+
+ // Test * for scheme, which implies just the http/https schemes.
+ extension = LoadManifestStrict("script_and_capture",
+ "extension_wildcard.json");
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Allowed(extension.get(), https_url));
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(Blocked(extension.get(), file_url));
+ EXPECT_TRUE(Blocked(extension.get(), favicon_url));
+ extension =
+ LoadManifest("script_and_capture", "extension_wildcard_settings.json");
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+
+ // Having chrome://*/ should work for regular extensions with the flag
+ // enabled.
+ std::string error;
+ extension = LoadManifestUnchecked("script_and_capture",
+ "extension_wildcard_chrome.json",
+ Manifest::INTERNAL, Extension::NO_FLAGS,
+ &error);
+ EXPECT_FALSE(extension.get() == NULL);
+ EXPECT_TRUE(Blocked(extension.get(), http_url));
+ EXPECT_TRUE(Blocked(extension.get(), https_url));
+ EXPECT_TRUE(Allowed(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(Blocked(extension.get(), file_url));
+ EXPECT_TRUE(Allowed(extension.get(), favicon_url)); // chrome:// requested
+
+ // Having chrome://favicon/* should not give you chrome://*
+ extension = LoadManifestStrict("script_and_capture",
+ "extension_chrome_favicon_wildcard.json");
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Allowed(extension.get(), favicon_url)); // chrome:// requested
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(PermissionsData::HasHostPermission(extension.get(), favicon_url));
+
+ // Having http://favicon should not give you chrome://favicon
+ extension = LoadManifestStrict("script_and_capture",
+ "extension_http_favicon.json");
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), favicon_url));
+
+ // Component extensions with <all_urls> should get everything.
+ extension = LoadManifest("script_and_capture", "extension_component_all.json",
+ Manifest::COMPONENT, Extension::NO_FLAGS);
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Allowed(extension.get(), https_url));
+ EXPECT_TRUE(Allowed(extension.get(), settings_url));
+ EXPECT_TRUE(Allowed(extension.get(), about_url));
+ EXPECT_TRUE(Allowed(extension.get(), favicon_url));
+ EXPECT_TRUE(PermissionsData::HasHostPermission(extension.get(), favicon_url));
+
+ // Component extensions should only get access to what they ask for.
+ extension = LoadManifest("script_and_capture",
+ "extension_component_google.json", Manifest::COMPONENT,
+ Extension::NO_FLAGS);
+ EXPECT_TRUE(Allowed(extension.get(), http_url));
+ EXPECT_TRUE(Blocked(extension.get(), https_url));
+ EXPECT_TRUE(Blocked(extension.get(), file_url));
+ EXPECT_TRUE(Blocked(extension.get(), settings_url));
+ EXPECT_TRUE(Blocked(extension.get(), favicon_url));
+ EXPECT_TRUE(Blocked(extension.get(), about_url));
+ EXPECT_TRUE(Blocked(extension.get(), extension_url));
+ EXPECT_FALSE(
+ PermissionsData::HasHostPermission(extension.get(), settings_url));
+}
+
+TEST_F(ExtensionScriptAndCaptureVisibleTest, TabSpecific) {
+ scoped_refptr<Extension> extension =
+ LoadManifestStrict("script_and_capture", "tab_specific.json");
+
+ EXPECT_FALSE(PermissionsData::GetTabSpecificPermissions(extension.get(), 0)
+ .get());
+ EXPECT_FALSE(PermissionsData::GetTabSpecificPermissions(extension.get(), 1)
+ .get());
+ EXPECT_FALSE(PermissionsData::GetTabSpecificPermissions(extension.get(), 2)
+ .get());
+
+ std::set<GURL> no_urls;
+
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 0));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 1));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 2));
+
+ URLPatternSet allowed_hosts;
+ allowed_hosts.AddPattern(URLPattern(URLPattern::SCHEME_ALL,
+ http_url.spec()));
+ std::set<GURL> allowed_urls;
+ allowed_urls.insert(http_url);
+ // http_url_with_path() will also be allowed, because Extension should be
+ // considering the security origin of the URL not the URL itself, and
+ // http_url is in allowed_hosts.
+ allowed_urls.insert(http_url_with_path);
+
+ {
+ scoped_refptr<PermissionSet> permissions(
+ new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+ allowed_hosts, URLPatternSet()));
+ PermissionsData::UpdateTabSpecificPermissions(
+ extension.get(), 0, permissions);
+ EXPECT_EQ(permissions->explicit_hosts(),
+ PermissionsData::GetTabSpecificPermissions(extension.get(), 0)
+ ->explicit_hosts());
+ }
+
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), allowed_urls, 0));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 1));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 2));
+
+ PermissionsData::ClearTabSpecificPermissions(extension.get(), 0);
+ EXPECT_FALSE(PermissionsData::GetTabSpecificPermissions(extension.get(), 0)
+ .get());
+
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 0));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 1));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 2));
+
+ std::set<GURL> more_allowed_urls = allowed_urls;
+ more_allowed_urls.insert(https_url);
+ URLPatternSet more_allowed_hosts = allowed_hosts;
+ more_allowed_hosts.AddPattern(URLPattern(URLPattern::SCHEME_ALL,
+ https_url.spec()));
+
+ {
+ scoped_refptr<PermissionSet> permissions(
+ new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+ allowed_hosts, URLPatternSet()));
+ PermissionsData::UpdateTabSpecificPermissions(
+ extension.get(), 0, permissions);
+ EXPECT_EQ(permissions->explicit_hosts(),
+ PermissionsData::GetTabSpecificPermissions(extension.get(), 0)
+ ->explicit_hosts());
+
+ permissions = new PermissionSet(APIPermissionSet(),
+ ManifestPermissionSet(),
+ more_allowed_hosts,
+ URLPatternSet());
+ PermissionsData::UpdateTabSpecificPermissions(
+ extension.get(), 1, permissions);
+ EXPECT_EQ(permissions->explicit_hosts(),
+ PermissionsData::GetTabSpecificPermissions(extension.get(), 1)
+ ->explicit_hosts());
+ }
+
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), allowed_urls, 0));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), more_allowed_urls, 1));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 2));
+
+ PermissionsData::ClearTabSpecificPermissions(extension.get(), 0);
+ EXPECT_FALSE(PermissionsData::GetTabSpecificPermissions(extension.get(), 0)
+ .get());
+
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 0));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), more_allowed_urls, 1));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 2));
+
+ PermissionsData::ClearTabSpecificPermissions(extension.get(), 1);
+ EXPECT_FALSE(PermissionsData::GetTabSpecificPermissions(extension.get(), 1)
+ .get());
+
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 0));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 1));
+ EXPECT_TRUE(AllowedExclusivelyOnTab(extension.get(), no_urls, 2));
+}
+
+} // namespace extensions
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index d673ac1..16d55b5 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -36,6 +36,8 @@
'common/event_filtering_info.h',
'common/event_matcher.cc',
'common/event_matcher.h',
+ 'common/extension.cc',
+ 'common/extension.h',
'common/extension_api.cc',
'common/extension_api.h',
'common/extension_api_stub.cc',
@@ -100,6 +102,8 @@
'common/permissions/permission_message_provider.h',
'common/permissions/permission_set.cc',
'common/permissions/permission_set.h',
+ 'common/permissions/permissions_data.cc',
+ 'common/permissions/permissions_data.h',
'common/permissions/permissions_info.cc',
'common/permissions/permissions_info.h',
'common/permissions/permissions_provider.h',