summaryrefslogtreecommitdiffstats
path: root/extensions/common/manifest_handlers
diff options
context:
space:
mode:
authorrockot <rockot@chromium.org>2014-12-08 19:09:18 -0800
committerCommit bot <commit-bot@chromium.org>2014-12-09 03:09:44 +0000
commita980ec6fb4d0dffeb35cca31e36512717e765463 (patch)
tree97ab3a91bafe3971a7cdd0b8ed8e6264b92877c4 /extensions/common/manifest_handlers
parent4989e6046a5c34d02356dd84c70f18f1e9a16188 (diff)
downloadchromium_src-a980ec6fb4d0dffeb35cca31e36512717e765463.zip
chromium_src-a980ec6fb4d0dffeb35cca31e36512717e765463.tar.gz
chromium_src-a980ec6fb4d0dffeb35cca31e36512717e765463.tar.bz2
Add content_capabilities manifest feature
This adds basic manifest data parsing support for the content_capabilities feature, which is - for now - constrained to a whitelist. BUG=409269 Review URL: https://codereview.chromium.org/780703003 Cr-Commit-Position: refs/heads/master@{#307407}
Diffstat (limited to 'extensions/common/manifest_handlers')
-rw-r--r--extensions/common/manifest_handlers/content_capabilities_handler.cc109
-rw-r--r--extensions/common/manifest_handlers/content_capabilities_handler.h50
-rw-r--r--extensions/common/manifest_handlers/content_capabilities_manifest_unittest.cc90
3 files changed, 249 insertions, 0 deletions
diff --git a/extensions/common/manifest_handlers/content_capabilities_handler.cc b/extensions/common/manifest_handlers/content_capabilities_handler.cc
new file mode 100644
index 0000000..a55bb82
--- /dev/null
+++ b/extensions/common/manifest_handlers/content_capabilities_handler.cc
@@ -0,0 +1,109 @@
+// Copyright 2014 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/manifest_handlers/content_capabilities_handler.h"
+
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/api/extensions_manifest_types.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/install_warning.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "extensions/common/url_pattern.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+using core_api::extensions_manifest_types::ContentCapabilities;
+
+ContentCapabilitiesInfo::ContentCapabilitiesInfo() {
+}
+
+ContentCapabilitiesInfo::~ContentCapabilitiesInfo() {
+}
+
+static base::LazyInstance<ContentCapabilitiesInfo>
+g_empty_content_capabilities_info = LAZY_INSTANCE_INITIALIZER;
+
+// static
+const ContentCapabilitiesInfo& ContentCapabilitiesInfo::Get(
+ const Extension* extension) {
+ ContentCapabilitiesInfo* info = static_cast<ContentCapabilitiesInfo*>(
+ extension->GetManifestData(keys::kContentCapabilities));
+ return info ? *info : g_empty_content_capabilities_info.Get();
+}
+
+ContentCapabilitiesHandler::ContentCapabilitiesHandler() {
+}
+
+ContentCapabilitiesHandler::~ContentCapabilitiesHandler() {
+}
+
+bool ContentCapabilitiesHandler::Parse(Extension* extension,
+ base::string16* error) {
+ scoped_ptr<ContentCapabilitiesInfo> info(new ContentCapabilitiesInfo);
+
+ const base::Value* value = NULL;
+ if (!extension->manifest()->Get(keys::kContentCapabilities, &value)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidContentCapabilities);
+ return false;
+ }
+
+ scoped_ptr<ContentCapabilities> capabilities(ContentCapabilities::FromValue(
+ *value, error));
+ if (!capabilities)
+ return false;
+
+ std::string url_error;
+ URLPatternSet potential_url_patterns;
+ if (!potential_url_patterns.Populate(capabilities->matches,
+ URLPattern::SCHEME_HTTPS, false /* allow_file_access */,
+ &url_error)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidContentCapabilitiesMatch, url_error);
+ return false;
+ }
+
+ // Filter wildcard URL patterns and emit warnings for them.
+ std::set<URLPattern> valid_url_patterns;
+ for (const URLPattern& pattern : potential_url_patterns) {
+ if (pattern.match_subdomains() || pattern.ImpliesAllHosts()) {
+ extension->AddInstallWarning(InstallWarning(
+ errors::kInvalidContentCapabilitiesMatchOrigin));
+ } else {
+ valid_url_patterns.insert(pattern);
+ }
+ }
+ info->url_patterns = URLPatternSet(valid_url_patterns);
+
+ // Filter invalid permissions and emit warnings for them.
+ for (const std::string& permission_name : capabilities->permissions) {
+ const APIPermissionInfo* permission_info = PermissionsInfo::GetInstance()
+ ->GetByName(permission_name);
+ if (!permission_info || !permission_info->supports_content_capabilities()) {
+ extension->AddInstallWarning(InstallWarning(
+ errors::kInvalidContentCapabilitiesPermission,
+ keys::kContentCapabilities,
+ permission_name));
+ } else {
+ info->permissions.insert(permission_info->CreateAPIPermission());
+ }
+ }
+
+ extension->SetManifestData(keys::kContentCapabilities, info.release());
+ return true;
+}
+
+const std::vector<std::string> ContentCapabilitiesHandler::Keys()
+ const {
+ return SingleKey(keys::kContentCapabilities);
+}
+
+} // namespace extensions
diff --git a/extensions/common/manifest_handlers/content_capabilities_handler.h b/extensions/common/manifest_handlers/content_capabilities_handler.h
new file mode 100644
index 0000000..ef1bd11
--- /dev/null
+++ b/extensions/common/manifest_handlers/content_capabilities_handler.h
@@ -0,0 +1,50 @@
+// Copyright 2014 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_MANIFEST_HANDLERS_CONTENT_CAPABILITIES_HANDLER_H_
+#define EXTENSIONS_COMMON_MANIFEST_HANDLERS_CONTENT_CAPABILITIES_HANDLER_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/url_pattern_set.h"
+
+namespace extensions {
+
+// Manifest data describing an extension's set of granted content capabilities.
+struct ContentCapabilitiesInfo : public Extension::ManifestData {
+ // The set of API permissions to be granted to web content.
+ APIPermissionSet permissions;
+
+ // The URL pattern set which should be used to decide which content is granted
+ // these capabilities.
+ URLPatternSet url_patterns;
+
+ ContentCapabilitiesInfo();
+ ~ContentCapabilitiesInfo() override;
+
+ static const ContentCapabilitiesInfo& Get(const Extension* extension);
+};
+
+// Parses the "content_capabilities" manifest key.
+class ContentCapabilitiesHandler : public ManifestHandler {
+ public:
+ ContentCapabilitiesHandler();
+ ~ContentCapabilitiesHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ const std::vector<std::string> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentCapabilitiesHandler);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_MANIFEST_HANDLERS_CONTENT_CAPABILITIES_HANDLER_H_
diff --git a/extensions/common/manifest_handlers/content_capabilities_manifest_unittest.cc b/extensions/common/manifest_handlers/content_capabilities_manifest_unittest.cc
new file mode 100644
index 0000000..e9f78c3
--- /dev/null
+++ b/extensions/common/manifest_handlers/content_capabilities_manifest_unittest.cc
@@ -0,0 +1,90 @@
+// Copyright 2014 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 "base/command_line.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/content_capabilities_handler.h"
+#include "extensions/common/manifest_test.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/extensions_api_permissions.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "extensions/common/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+using extensions::APIPermission;
+
+class ContentCapabilitiesManifestTest : public ManifestTest {
+ std::string GetTestExtensionID() const override {
+ return std::string("apdfllckaahabafndbhieahigkjlhalf");
+ }
+};
+
+TEST_F(ContentCapabilitiesManifestTest, RejectDomainWildcards) {
+ scoped_refptr<Extension> extension(LoadAndExpectWarning(
+ "content_capabilities_domain_wildcard.json",
+ manifest_errors::kInvalidContentCapabilitiesMatchOrigin));
+ const ContentCapabilitiesInfo& info = ContentCapabilitiesInfo::Get(
+ extension.get());
+ // Make sure the wildcard is not included in the pattern set.
+ EXPECT_FALSE(info.url_patterns.MatchesURL(GURL("https://bar.example.com/")));
+ EXPECT_TRUE(info.url_patterns.MatchesURL(GURL("https://foo.example.com/")));
+}
+
+TEST_F(ContentCapabilitiesManifestTest, RejectedAllHosts) {
+ scoped_refptr<Extension> extension(LoadAndExpectWarning(
+ "content_capabilities_all_hosts.json",
+ manifest_errors::kInvalidContentCapabilitiesMatchOrigin));
+ const ContentCapabilitiesInfo& info = ContentCapabilitiesInfo::Get(
+ extension.get());
+ // Make sure the wildcard is not included in the pattern set.
+ EXPECT_FALSE(info.url_patterns.MatchesURL(GURL("https://nonspecific.com/")));
+ EXPECT_TRUE(info.url_patterns.MatchesURL(GURL("https://example.com/")));
+}
+
+TEST_F(ContentCapabilitiesManifestTest, InvalidPermission) {
+ scoped_refptr<Extension> extension(LoadAndExpectWarning(
+ "content_capabilities_invalid_permission.json",
+ manifest_errors::kInvalidContentCapabilitiesPermission));
+ const ContentCapabilitiesInfo& info = ContentCapabilitiesInfo::Get(
+ extension.get());
+ // Make sure the invalid permission is not included in the permission set.
+ EXPECT_EQ(3u, info.permissions.size());
+ EXPECT_EQ(1u, info.permissions.count(APIPermission::kClipboardRead));
+ EXPECT_EQ(1u, info.permissions.count(APIPermission::kClipboardWrite));
+ EXPECT_EQ(1u, info.permissions.count(APIPermission::kUnlimitedStorage));
+ EXPECT_EQ(0u, info.permissions.count(APIPermission::kUsb));
+}
+
+TEST_F(ContentCapabilitiesManifestTest, InvalidValue) {
+ LoadAndExpectError("content_capabilities_invalid_value.json",
+ "expected dictionary, got list");
+}
+
+TEST_F(ContentCapabilitiesManifestTest, RejectNonHttpsUrlPatterns) {
+ LoadAndExpectError("content_capabilities_non_https_matches.json",
+ manifest_errors::kInvalidContentCapabilitiesMatch);
+}
+
+TEST_F(ContentCapabilitiesManifestTest, Valid) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("content_capabilities_valid.json"));
+ const ContentCapabilitiesInfo& info = ContentCapabilitiesInfo::Get(
+ extension.get());
+ EXPECT_EQ(1u, info.url_patterns.size());
+ EXPECT_FALSE(info.url_patterns.MatchesURL(GURL("http://valid.example.com/")));
+ EXPECT_FALSE(info.url_patterns.MatchesURL(GURL("https://foo.example.com/")));
+ EXPECT_FALSE(info.url_patterns.MatchesURL(GURL("https://example.com/")));
+ EXPECT_TRUE(info.url_patterns.MatchesURL(GURL("https://valid.example.com/")));
+ EXPECT_EQ(3u, info.permissions.size());
+ EXPECT_EQ(1u, info.permissions.count(APIPermission::kClipboardRead));
+ EXPECT_EQ(1u, info.permissions.count(APIPermission::kClipboardWrite));
+ EXPECT_EQ(1u, info.permissions.count(APIPermission::kUnlimitedStorage));
+ EXPECT_EQ(0u, info.permissions.count(APIPermission::kUsb));
+}
+
+
+} // namespace extensions