summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/active_tab_permission_granter.cc3
-rw-r--r--chrome/browser/extensions/api/permissions/permissions_api_helpers.cc9
-rw-r--r--chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc2
-rw-r--r--chrome/browser/extensions/api/permissions/permissions_apitest.cc4
-rw-r--r--chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc2
-rw-r--r--chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc2
-rw-r--r--chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc2
-rw-r--r--chrome/browser/extensions/extension_prefs.cc71
-rw-r--r--chrome/browser/extensions/extension_prefs_unittest.cc15
-rw-r--r--chrome/browser/extensions/permissions_updater.cc17
-rw-r--r--chrome/browser/extensions/permissions_updater_unittest.cc11
-rw-r--r--chrome/browser/themes/theme_syncable_service_unittest.cc4
-rw-r--r--chrome/chrome_common.gypi8
-rw-r--r--chrome/chrome_tests_unit.gypi2
-rw-r--r--chrome/common/extensions/api/sockets/sockets_handler.cc155
-rw-r--r--chrome/common/extensions/api/sockets/sockets_handler.h68
-rw-r--r--chrome/common/extensions/api/sockets/sockets_manifest_data.cc51
-rw-r--r--chrome/common/extensions/api/sockets/sockets_manifest_data.h54
-rw-r--r--chrome/common/extensions/api/sockets/sockets_manifest_handler.cc46
-rw-r--r--chrome/common/extensions/api/sockets/sockets_manifest_handler.h41
-rw-r--r--chrome/common/extensions/api/sockets/sockets_manifest_permission.cc386
-rw-r--r--chrome/common/extensions/api/sockets/sockets_manifest_permission.h100
-rw-r--r--chrome/common/extensions/api/sockets/sockets_manifest_permission_unittest.cc186
-rw-r--r--chrome/common/extensions/chrome_manifest_handlers.cc4
-rw-r--r--chrome/common/extensions/extension.cc1
-rw-r--r--chrome/common/extensions/extension.h1
-rw-r--r--chrome/common/extensions/extension_messages.cc45
-rw-r--r--chrome/common/extensions/extension_messages.h27
-rw-r--r--chrome/common/extensions/permissions/chrome_permission_message_provider.cc20
-rw-r--r--chrome/common/extensions/permissions/chrome_permission_message_provider.h4
-rw-r--r--chrome/common/extensions/permissions/permission_set_unittest.cc104
-rw-r--r--chrome/common/extensions/permissions/permissions_data.cc11
-rw-r--r--chrome/common/extensions/permissions/permissions_data.h4
-rw-r--r--chrome/common/extensions/permissions/permissions_data_unittest.cc7
-rw-r--r--chrome/renderer/extensions/dispatcher.cc21
-rw-r--r--chrome/renderer/extensions/dispatcher.h8
-rw-r--r--extensions/DEPS3
-rw-r--r--extensions/common/extensions_client.h1
-rw-r--r--extensions/common/manifest_handler.cc44
-rw-r--r--extensions/common/manifest_handler.h35
-rw-r--r--extensions/common/permissions/api_permission_set.cc174
-rw-r--r--extensions/common/permissions/api_permission_set.h128
-rw-r--r--extensions/common/permissions/base_set_operators.h288
-rw-r--r--extensions/common/permissions/manifest_permission.cc13
-rw-r--r--extensions/common/permissions/manifest_permission.h88
-rw-r--r--extensions/common/permissions/manifest_permission_set.cc93
-rw-r--r--extensions/common/permissions/manifest_permission_set.h47
-rw-r--r--extensions/common/permissions/manifest_permission_set_unittest.cc272
-rw-r--r--extensions/common/permissions/permission_set.cc30
-rw-r--r--extensions/common/permissions/permission_set.h17
-rw-r--r--extensions/extensions.gyp5
51 files changed, 2108 insertions, 626 deletions
diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc
index d8c0ce6..aebeb39 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/active_tab_permission_granter.cc
@@ -59,7 +59,8 @@ void ActiveTabPermissionGranter::GrantIfRequested(const Extension* extension) {
if (!new_apis.empty() || !new_hosts.is_empty()) {
granted_extensions_.Insert(extension);
scoped_refptr<const PermissionSet> new_permissions =
- new PermissionSet(new_apis, new_hosts, URLPatternSet());
+ new PermissionSet(new_apis, ManifestPermissionSet(),
+ new_hosts, URLPatternSet());
PermissionsData::UpdateTabSpecificPermissions(extension,
tab_id_,
new_permissions);
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
index 620c8c5..2b90287 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
@@ -56,6 +56,9 @@ scoped_ptr<Permissions> PackPermissionSet(const PermissionSet* set) {
}
}
+ // TODO(rpaquay): We currently don't expose manifest permissions
+ // to apps/extensions via the permissions API.
+
permissions->origins.reset(new std::vector<std::string>());
URLPatternSet hosts = set->explicit_hosts();
for (URLPatternSet::const_iterator i = hosts.begin(); i != hosts.end(); ++i)
@@ -121,6 +124,10 @@ scoped_refptr<PermissionSet> UnpackPermissionSet(
}
}
+ // TODO(rpaquay): We currently don't expose manifest permissions
+ // to apps/extensions via the permissions API.
+ ManifestPermissionSet manifest_permissions;
+
URLPatternSet origins;
if (permissions.origins.get()) {
for (std::vector<std::string>::iterator it = permissions.origins->begin();
@@ -142,7 +149,7 @@ scoped_refptr<PermissionSet> UnpackPermissionSet(
}
return scoped_refptr<PermissionSet>(
- new PermissionSet(apis, origins, URLPatternSet()));
+ new PermissionSet(apis, manifest_permissions, origins, URLPatternSet()));
}
} // namespace permissions_api_helpers
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
index fe3e860..4ac1b81 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
@@ -37,7 +37,7 @@ TEST(ExtensionPermissionsAPIHelpers, Pack) {
AddPattern(&hosts, "http://b.com/*");
scoped_refptr<PermissionSet> permission_set =
- new PermissionSet(apis, hosts, URLPatternSet());
+ new PermissionSet(apis, ManifestPermissionSet(), hosts, URLPatternSet());
// Pack the permission set to value and verify its contents.
scoped_ptr<Permissions> permissions(PackPermissionSet(permission_set.get()));
diff --git a/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
index 736112f..e3e1552 100644
--- a/chrome/browser/extensions/api/permissions/permissions_apitest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
@@ -72,10 +72,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, OptionalPermissionsGranted) {
// Mark all the tested APIs as granted to bypass the confirmation UI.
APIPermissionSet apis;
apis.insert(APIPermission::kBookmark);
+ ManifestPermissionSet manifest_permissions;
URLPatternSet explicit_hosts;
AddPattern(&explicit_hosts, "http://*.c.com/*");
scoped_refptr<PermissionSet> granted_permissions =
- new PermissionSet(apis, explicit_hosts, URLPatternSet());
+ new PermissionSet(apis, manifest_permissions,
+ explicit_hosts, URLPatternSet());
ExtensionPrefs* prefs =
browser()->profile()->GetExtensionService()->extension_prefs();
diff --git a/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc b/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc
index 729587f..fbf02dc 100644
--- a/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc
+++ b/chrome/browser/extensions/api/sockets_tcp/sockets_tcp_api.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/extensions/api/socket/tcp_socket.h"
#include "chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.h"
-#include "chrome/common/extensions/api/sockets/sockets_handler.h"
+#include "chrome/common/extensions/api/sockets/sockets_manifest_data.h"
#include "content/public/common/socket_permission_request.h"
#include "net/base/net_errors.h"
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
index cace238..e914a5a 100644
--- a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
+++ b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/extensions/api/socket/tcp_socket.h"
#include "chrome/browser/extensions/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h"
-#include "chrome/common/extensions/api/sockets/sockets_handler.h"
+#include "chrome/common/extensions/api/sockets/sockets_manifest_data.h"
#include "chrome/common/extensions/permissions/permissions_data.h"
#include "chrome/common/extensions/permissions/socket_permission.h"
#include "content/public/common/socket_permission_request.h"
diff --git a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
index 5939c44..fd8101c 100644
--- a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
+++ b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/extensions/api/socket/udp_socket.h"
#include "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h"
-#include "chrome/common/extensions/api/sockets/sockets_handler.h"
+#include "chrome/common/extensions/api/sockets/sockets_manifest_data.h"
#include "content/public/common/socket_permission_request.h"
#include "net/base/net_errors.h"
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index f021de4..d6394e8 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -157,6 +157,7 @@ const char kPrefGrantedPermissions[] = "granted_permissions";
// The preference names for PermissionSet values.
const char kPrefAPIs[] = "api";
+const char kPrefManifestPermissions[] = "manifest_permissions";
const char kPrefExplicitHosts[] = "explicit_host";
const char kPrefScriptableHosts[] = "scriptable_host";
@@ -545,6 +546,18 @@ PermissionSet* ExtensionPrefs::ReadPrefAsPermissionSet(
&apis, NULL, NULL);
}
+ // Retrieve the Manifest Keys permissions. Please refer to
+ // |SetExtensionPrefPermissionSet| for manifest_permissions_values format.
+ ManifestPermissionSet manifest_permissions;
+ const ListValue* manifest_permissions_values = NULL;
+ std::string manifest_permission_pref =
+ JoinPrefs(pref_key, kPrefManifestPermissions);
+ if (ReadPrefAsList(extension_id, manifest_permission_pref,
+ &manifest_permissions_values)) {
+ ManifestPermissionSet::ParseFromJSON(
+ manifest_permissions_values, &manifest_permissions, NULL, NULL);
+ }
+
// Retrieve the explicit host permissions.
URLPatternSet explicit_hosts;
ReadPrefAsURLPatternSet(
@@ -557,37 +570,51 @@ PermissionSet* ExtensionPrefs::ReadPrefAsPermissionSet(
extension_id, JoinPrefs(pref_key, kPrefScriptableHosts),
&scriptable_hosts, UserScript::ValidUserScriptSchemes());
- return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
-}
-
-void ExtensionPrefs::SetExtensionPrefPermissionSet(
- const std::string& extension_id,
- const std::string& pref_key,
- const PermissionSet* new_value) {
- // Set the API permissions.
- // The format of api_values is:
- // [ "permission_name1", // permissions do not support detail.
- // "permission_name2",
- // {"permission_name3": value },
- // // permission supports detail, permission detail will be stored in value.
- // ...
- // ]
- ListValue* api_values = new ListValue();
- APIPermissionSet apis = new_value->apis();
- std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
- for (APIPermissionSet::const_iterator i = apis.begin();
- i != apis.end(); ++i) {
+ return new PermissionSet(
+ apis, manifest_permissions, explicit_hosts, scriptable_hosts);
+}
+
+// Set the API or Manifest permissions.
+// The format of api_values is:
+// [ "permission_name1", // permissions do not support detail.
+// "permission_name2",
+// {"permission_name3": value },
+// // permission supports detail, permission detail will be stored in value.
+// ...
+// ]
+template<typename T>
+static ListValue* CreatePermissionList(const T& permissions) {
+ ListValue* values = new ListValue();
+ for (typename T::const_iterator i = permissions.begin();
+ i != permissions.end(); ++i) {
scoped_ptr<Value> detail(i->ToValue());
if (detail) {
DictionaryValue* tmp = new DictionaryValue();
tmp->Set(i->name(), detail.release());
- api_values->Append(tmp);
+ values->Append(tmp);
} else {
- api_values->Append(new base::StringValue(i->name()));
+ values->Append(new base::StringValue(i->name()));
}
}
+ return values;
+}
+
+void ExtensionPrefs::SetExtensionPrefPermissionSet(
+ const std::string& extension_id,
+ const std::string& pref_key,
+ const PermissionSet* new_value) {
+ std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
+ ListValue* api_values = CreatePermissionList(new_value->apis());
UpdateExtensionPref(extension_id, api_pref, api_values);
+ std::string manifest_permissions_pref =
+ JoinPrefs(pref_key, kPrefManifestPermissions);
+ ListValue* manifest_permissions_values = CreatePermissionList(
+ new_value->manifest_permissions());
+ UpdateExtensionPref(extension_id,
+ manifest_permissions_pref,
+ manifest_permissions_values);
+
// Set the explicit host permissions.
if (!new_value->explicit_hosts().is_empty()) {
SetExtensionPrefURLPatternSet(extension_id,
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 511aeed..3d1d24f 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -222,6 +222,7 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
AddPattern(&shost_permissions_, "http://example.com/*");
APIPermissionSet empty_set;
+ ManifestPermissionSet empty_manifest_permissions;
URLPatternSet empty_extent;
scoped_refptr<PermissionSet> permissions;
scoped_refptr<PermissionSet> granted_permissions;
@@ -232,7 +233,7 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
EXPECT_TRUE(granted_permissions->IsEmpty());
permissions = new PermissionSet(
- api_perm_set1_, empty_extent, empty_extent);
+ api_perm_set1_, empty_manifest_permissions, empty_extent, empty_extent);
// Add part of the api permissions.
prefs()->AddGrantedPermissions(extension_id_, permissions.get());
@@ -246,7 +247,7 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
// Add part of the explicit host permissions.
permissions = new PermissionSet(
- empty_set, ehost_perm_set1_, empty_extent);
+ empty_set, empty_manifest_permissions, ehost_perm_set1_, empty_extent);
prefs()->AddGrantedPermissions(extension_id_, permissions.get());
granted_permissions = prefs()->GetGrantedPermissions(extension_id_);
EXPECT_FALSE(granted_permissions->IsEmpty());
@@ -259,7 +260,7 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
// Add part of the scriptable host permissions.
permissions = new PermissionSet(
- empty_set, empty_extent, shost_perm_set1_);
+ empty_set, empty_manifest_permissions, empty_extent, shost_perm_set1_);
prefs()->AddGrantedPermissions(extension_id_, permissions.get());
granted_permissions = prefs()->GetGrantedPermissions(extension_id_);
EXPECT_FALSE(granted_permissions->IsEmpty());
@@ -276,7 +277,8 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
// Add the rest of the permissions.
permissions = new PermissionSet(
- api_perm_set2_, ehost_perm_set2_, shost_perm_set2_);
+ api_perm_set2_, empty_manifest_permissions,
+ ehost_perm_set2_, shost_perm_set2_);
APIPermissionSet::Union(expected_apis, api_perm_set2_, &api_permissions_);
@@ -334,6 +336,8 @@ class ExtensionPrefsActivePermissions : public ExtensionPrefsTest {
api_perms.insert(APIPermission::kBookmark);
api_perms.insert(APIPermission::kHistory);
+ ManifestPermissionSet empty_manifest_permissions;
+
URLPatternSet ehosts;
AddPattern(&ehosts, "http://*.google.com/*");
AddPattern(&ehosts, "http://example.com/*");
@@ -343,7 +347,8 @@ class ExtensionPrefsActivePermissions : public ExtensionPrefsTest {
AddPattern(&shosts, "https://*.google.com/*");
AddPattern(&shosts, "http://reddit.com/r/test/*");
- active_perms_ = new PermissionSet(api_perms, ehosts, shosts);
+ active_perms_ = new PermissionSet(
+ api_perms, empty_manifest_permissions, ehosts, shosts);
// Make sure the active permissions start empty.
scoped_refptr<PermissionSet> active(
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc
index f8a928e..1e38cb8 100644
--- a/chrome/browser/extensions/permissions_updater.cc
+++ b/chrome/browser/extensions/permissions_updater.cc
@@ -138,13 +138,16 @@ void PermissionsUpdater::NotifyPermissionsUpdated(
!i.IsAtEnd(); i.Advance()) {
RenderProcessHost* host = i.GetCurrentValue();
Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
- if (profile_->IsSameProfile(profile))
- host->Send(new ExtensionMsg_UpdatePermissions(
- static_cast<int>(reason),
- extension->id(),
- changed->apis(),
- changed->explicit_hosts(),
- changed->scriptable_hosts()));
+ if (profile_->IsSameProfile(profile)) {
+ ExtensionMsg_UpdatePermissions_Params info;
+ info.reason_id = static_cast<int>(reason);
+ info.extension_id = extension->id();
+ info.apis = changed->apis();
+ info.manifest_permissions = changed->manifest_permissions();
+ info.explicit_hosts = changed->explicit_hosts();
+ info.scriptable_hosts = changed->scriptable_hosts();
+ host->Send(new ExtensionMsg_UpdatePermissions(info));
+ }
}
// Trigger the onAdded and onRemoved events in the extension.
diff --git a/chrome/browser/extensions/permissions_updater_unittest.cc b/chrome/browser/extensions/permissions_updater_unittest.cc
index 30d71dc..7a0e431 100644
--- a/chrome/browser/extensions/permissions_updater_unittest.cc
+++ b/chrome/browser/extensions/permissions_updater_unittest.cc
@@ -119,10 +119,13 @@ TEST_F(PermissionsUpdaterTest, AddAndRemovePermissions) {
APIPermissionSet default_apis;
default_apis.insert(APIPermission::kManagement);
+ ManifestPermissionSet empty_manifest_permissions;
+
URLPatternSet default_hosts;
AddPattern(&default_hosts, "http://a.com/*");
scoped_refptr<PermissionSet> default_permissions =
- new PermissionSet(default_apis, default_hosts, URLPatternSet());
+ new PermissionSet(default_apis, empty_manifest_permissions,
+ default_hosts, URLPatternSet());
// Make sure it loaded properly.
scoped_refptr<const PermissionSet> permissions =
@@ -138,7 +141,8 @@ TEST_F(PermissionsUpdaterTest, AddAndRemovePermissions) {
AddPattern(&hosts, "http://*.c.com/*");
scoped_refptr<PermissionSet> delta =
- new PermissionSet(apis, hosts, URLPatternSet());
+ new PermissionSet(apis, empty_manifest_permissions,
+ hosts, URLPatternSet());
PermissionsUpdaterListener listener;
PermissionsUpdater updater(profile_.get());
@@ -175,7 +179,8 @@ TEST_F(PermissionsUpdaterTest, AddAndRemovePermissions) {
// In the second part of the test, we'll remove the permissions that we
// just added except for 'notification'.
apis.erase(APIPermission::kNotification);
- delta = new PermissionSet(apis, hosts, URLPatternSet());
+ delta = new PermissionSet(apis, empty_manifest_permissions,
+ hosts, URLPatternSet());
listener.Reset();
updater.RemovePermissions(extension.get(), delta.get());
diff --git a/chrome/browser/themes/theme_syncable_service_unittest.cc b/chrome/browser/themes/theme_syncable_service_unittest.cc
index 82e721b..b95adbe 100644
--- a/chrome/browser/themes/theme_syncable_service_unittest.cc
+++ b/chrome/browser/themes/theme_syncable_service_unittest.cc
@@ -207,9 +207,11 @@ class ThemeSyncableServiceTest : public testing::Test {
GetThemeLocation(),
kCustomThemeUrl);
extensions::APIPermissionSet empty_set;
+ extensions::ManifestPermissionSet empty_manifest_permissions;
extensions::URLPatternSet empty_extent;
scoped_refptr<extensions::PermissionSet> permissions =
- new extensions::PermissionSet(empty_set, empty_extent, empty_extent);
+ new extensions::PermissionSet(empty_set, empty_manifest_permissions,
+ empty_extent, empty_extent);
service->extension_prefs()->AddGrantedPermissions(
theme_extension_->id(), permissions.get());
service->AddExtension(theme_extension_.get());
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index dbd07b6..1f0f67f 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -145,8 +145,12 @@
'common/extensions/api/omnibox/omnibox_handler.h',
'common/extensions/api/plugins/plugins_handler.cc',
'common/extensions/api/plugins/plugins_handler.h',
- 'common/extensions/api/sockets/sockets_handler.cc',
- 'common/extensions/api/sockets/sockets_handler.h',
+ 'common/extensions/api/sockets/sockets_manifest_handler.cc',
+ 'common/extensions/api/sockets/sockets_manifest_handler.h',
+ 'common/extensions/api/sockets/sockets_manifest_data.cc',
+ 'common/extensions/api/sockets/sockets_manifest_data.h',
+ 'common/extensions/api/sockets/sockets_manifest_permission.cc',
+ 'common/extensions/api/sockets/sockets_manifest_permission.h',
'common/extensions/api/speech/tts_engine_manifest_handler.cc',
'common/extensions/api/speech/tts_engine_manifest_handler.h',
'common/extensions/api/spellcheck/spellcheck_handler.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index b86305f..b648e4c 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -540,6 +540,7 @@
'../extensions/common/matcher/url_matcher_unittest.cc',
'../extensions/common/one_shot_event_unittest.cc',
'../extensions/common/permissions/api_permission_set_unittest.cc',
+ '../extensions/common/permissions/manifest_permission_set_unittest.cc',
'../extensions/common/url_pattern_set_unittest.cc',
'../extensions/common/url_pattern_unittest.cc',
'../extensions/common/user_script_unittest.cc',
@@ -1800,6 +1801,7 @@
'common/extensions/api/file_browser_handlers/file_browser_handler_manifest_unittest.cc',
'common/extensions/api/i18n/default_locale_manifest_unittest.cc',
'common/extensions/api/identity/extension_manifests_auth_unittest.cc',
+ 'common/extensions/api/sockets/sockets_manifest_permission_unittest.cc',
'common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc',
'common/extensions/command_unittest.cc',
'common/extensions/csp_validator_unittest.cc',
diff --git a/chrome/common/extensions/api/sockets/sockets_handler.cc b/chrome/common/extensions/api/sockets/sockets_handler.cc
deleted file mode 100644
index a1b51c2..0000000
--- a/chrome/common/extensions/api/sockets/sockets_handler.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/extensions/api/sockets/sockets_handler.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/common/extensions/api/manifest_types.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/permissions_data.h"
-#include "chrome/common/extensions/permissions/socket_permission_data.h"
-#include "extensions/common/error_utils.h"
-#include "extensions/common/manifest_constants.h"
-#include "extensions/common/permissions/api_permission_set.h"
-
-namespace extensions {
-
-namespace sockets_errors {
-const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'";
-}
-
-namespace keys = extensions::manifest_keys;
-namespace errors = sockets_errors;
-using api::manifest_types::Sockets;
-
-SocketsHandler::SocketsHandler() {}
-
-SocketsHandler::~SocketsHandler() {}
-
-bool SocketsHandler::Parse(Extension* extension, string16* error) {
- const base::Value* sockets = NULL;
- CHECK(extension->manifest()->Get(keys::kSockets, &sockets));
- std::vector<InstallWarning> install_warnings;
- scoped_ptr<SocketsManifestData> data =
- SocketsManifestData::FromValue(*sockets,
- &install_warnings,
- error);
- if (!data)
- return false;
-
- extension->AddInstallWarnings(install_warnings);
- extension->SetManifestData(keys::kSockets, data.release());
- return true;
-}
-
-const std::vector<std::string> SocketsHandler::Keys() const {
- return SingleKey(manifest_keys::kSockets);
-}
-
-SocketsManifestData::SocketsManifestData() {}
-SocketsManifestData::~SocketsManifestData() {}
-
-// static
-SocketsManifestData* SocketsManifestData::Get(const Extension* extension) {
- return static_cast<SocketsManifestData*>(
- extension->GetManifestData(keys::kSockets));
-}
-
-// static
-bool SocketsManifestData::CheckRequest(
- const Extension* extension,
- const content::SocketPermissionRequest& request) {
- SocketsManifestData* data = SocketsManifestData::Get(extension);
- if (data == NULL)
- return false;
-
- return data->CheckRequestImpl(extension, request);
-}
-
-// static
-scoped_ptr<SocketsManifestData> SocketsManifestData::FromValue(
- const base::Value& value,
- std::vector<InstallWarning>* install_warnings,
- string16* error) {
- scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error);
- if (!sockets)
- return scoped_ptr<SocketsManifestData>();
-
- scoped_ptr<SocketsManifestData> result(new SocketsManifestData());
- if (sockets->udp) {
- if (!ParseHostPattern(result.get(),
- content::SocketPermissionRequest::UDP_BIND,
- sockets->udp->bind,
- error)) {
- return scoped_ptr<SocketsManifestData>();
- }
- if (!ParseHostPattern(result.get(),
- content::SocketPermissionRequest::UDP_SEND_TO,
- sockets->udp->send,
- error)) {
- return scoped_ptr<SocketsManifestData>();
- }
- if (!ParseHostPattern(result.get(),
- content::SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
- sockets->udp->multicast_membership,
- error)) {
- return scoped_ptr<SocketsManifestData>();
- }
- }
- if (sockets->tcp) {
- if (!ParseHostPattern(result.get(),
- content::SocketPermissionRequest::TCP_CONNECT,
- sockets->tcp->connect,
- error)) {
- return scoped_ptr<SocketsManifestData>();
- }
- }
- if (sockets->tcp_server) {
- if (!ParseHostPattern(result.get(),
- content::SocketPermissionRequest::TCP_LISTEN,
- sockets->tcp_server->listen,
- error)) {
- return scoped_ptr<SocketsManifestData>();
- }
- }
- return result.Pass();
-}
-
-// static
-bool SocketsManifestData::ParseHostPattern(
- SocketsManifestData* manifest_data,
- content::SocketPermissionRequest::OperationType operation_type,
- const scoped_ptr<std::string>& value,
- string16* error) {
- if (value) {
- SocketPermissionEntry entry;
- if (!SocketPermissionEntry::ParseHostPattern(
- operation_type, *value, &entry)) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kErrorInvalidHostPattern, *value);
- return false;
- }
- manifest_data->AddPermission(entry);
- }
- return true;
-}
-
-void SocketsManifestData::AddPermission(const SocketPermissionEntry& entry) {
- permissions_.insert(entry);
-}
-
-bool SocketsManifestData::CheckRequestImpl(
- const Extension* extension,
- const content::SocketPermissionRequest& request) {
- for (PermissionSet::const_iterator it = permissions_.begin();
- it != permissions_.end(); ++it) {
- if (it->Check(request))
- return true;
- }
- return false;
-}
-
-} // namespace extensions
diff --git a/chrome/common/extensions/api/sockets/sockets_handler.h b/chrome/common/extensions/api/sockets/sockets_handler.h
deleted file mode 100644
index 2859407..0000000
--- a/chrome/common/extensions/api/sockets/sockets_handler.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_HANDLER_H_
-#define CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_HANDLER_H_
-
-#include "base/strings/string16.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/socket_permission_data.h"
-#include "extensions/common/manifest_handler.h"
-
-namespace extensions {
-
-// Parses the "sockets" manifest key.
-class SocketsHandler : public ManifestHandler {
- public:
- SocketsHandler();
- virtual ~SocketsHandler();
-
- virtual bool Parse(Extension* extension, string16* error) OVERRIDE;
-
- private:
- virtual const std::vector<std::string> Keys() const OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(SocketsHandler);
-};
-
-// The parsed form of the "sockets" manifest entry.
-class SocketsManifestData : public Extension::ManifestData {
- public:
- SocketsManifestData();
- virtual ~SocketsManifestData();
-
- // Gets the ExternallyConnectableInfo for |extension|, or NULL if none was
- // specified.
- static SocketsManifestData* Get(const Extension* extension);
-
- static bool CheckRequest(const Extension* extension,
- const content::SocketPermissionRequest& request);
-
- // Tries to construct the info based on |value|, as it would have appeared in
- // the manifest. Sets |error| and returns an empty scoped_ptr on failure.
- static scoped_ptr<SocketsManifestData> FromValue(
- const base::Value& value,
- std::vector<InstallWarning>* install_warnings,
- string16* error);
-
- private:
- typedef std::set<SocketPermissionEntry> PermissionSet;
-
- static bool ParseHostPattern(
- SocketsManifestData* manifest_data,
- content::SocketPermissionRequest::OperationType operation_type,
- const scoped_ptr<std::string>& value,
- string16* error);
-
- void AddPermission(const SocketPermissionEntry& entry);
-
- bool CheckRequestImpl(const Extension* extension,
- const content::SocketPermissionRequest& request);
-
- PermissionSet permissions_;
-};
-
-} // namespace extensions
-
-#endif // CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_HANDLER_H_
diff --git a/chrome/common/extensions/api/sockets/sockets_manifest_data.cc b/chrome/common/extensions/api/sockets/sockets_manifest_data.cc
new file mode 100644
index 0000000..b00c8e0
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_manifest_data.cc
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/api/sockets/sockets_manifest_data.h"
+
+#include "chrome/common/extensions/api/sockets/sockets_manifest_permission.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+SocketsManifestData::SocketsManifestData(
+ scoped_ptr<SocketsManifestPermission> permission)
+ : permission_(permission.Pass()) {
+ DCHECK(permission_);
+}
+
+SocketsManifestData::~SocketsManifestData() {}
+
+// static
+SocketsManifestData* SocketsManifestData::Get(
+ const Extension* extension) {
+ return static_cast<SocketsManifestData*>(
+ extension->GetManifestData(manifest_keys::kSockets));
+}
+
+// static
+bool SocketsManifestData::CheckRequest(
+ const Extension* extension,
+ const content::SocketPermissionRequest& request) {
+ const SocketsManifestData* data = SocketsManifestData::Get(extension);
+ if (data)
+ return data->permission()->CheckRequest(extension, request);
+
+ return false;
+}
+
+// static
+scoped_ptr<SocketsManifestData> SocketsManifestData::FromValue(
+ const base::Value& value,
+ string16* error) {
+ scoped_ptr<SocketsManifestPermission> permission =
+ SocketsManifestPermission::FromValue(value, error);
+ if (!permission)
+ return scoped_ptr<SocketsManifestData>();
+
+ return scoped_ptr<SocketsManifestData>(
+ new SocketsManifestData(permission.Pass())).Pass();
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/api/sockets/sockets_manifest_data.h b/chrome/common/extensions/api/sockets/sockets_manifest_data.h
new file mode 100644
index 0000000..b220617
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_manifest_data.h
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_DATA_H_
+#define CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_DATA_H_
+
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "chrome/common/extensions/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace content {
+struct SocketPermissionRequest;
+}
+
+namespace extensions {
+class SocketsManifestPermission;
+}
+
+namespace extensions {
+
+// The parsed form of the "sockets" manifest entry.
+class SocketsManifestData : public Extension::ManifestData {
+ public:
+ explicit SocketsManifestData(
+ scoped_ptr<SocketsManifestPermission> permission);
+ virtual ~SocketsManifestData();
+
+ // Gets the SocketsManifestData for |extension|, or NULL if none was
+ // specified.
+ static SocketsManifestData* Get(const Extension* extension);
+
+ static bool CheckRequest(const Extension* extension,
+ const content::SocketPermissionRequest& request);
+
+ // Tries to construct the info based on |value|, as it would have appeared in
+ // the manifest. Sets |error| and returns an empty scoped_ptr on failure.
+ static scoped_ptr<SocketsManifestData> FromValue(
+ const base::Value& value,
+ string16* error);
+
+ const SocketsManifestPermission* permission() const {
+ return permission_.get();
+ }
+
+ private:
+ scoped_ptr<SocketsManifestPermission> permission_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_DATA_H_
diff --git a/chrome/common/extensions/api/sockets/sockets_manifest_handler.cc b/chrome/common/extensions/api/sockets/sockets_manifest_handler.cc
new file mode 100644
index 0000000..2e57ddc
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_manifest_handler.cc
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/api/sockets/sockets_manifest_handler.h"
+
+#include "chrome/common/extensions/api/sockets/sockets_manifest_data.h"
+#include "chrome/common/extensions/api/sockets/sockets_manifest_permission.h"
+#include "chrome/common/extensions/extension.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+SocketsManifestHandler::SocketsManifestHandler() {}
+
+SocketsManifestHandler::~SocketsManifestHandler() {}
+
+bool SocketsManifestHandler::Parse(Extension* extension, string16* error) {
+ const base::Value* sockets = NULL;
+ CHECK(extension->manifest()->Get(manifest_keys::kSockets, &sockets));
+ scoped_ptr<SocketsManifestData> data =
+ SocketsManifestData::FromValue(*sockets, error);
+ if (!data)
+ return false;
+
+ extension->SetManifestData(manifest_keys::kSockets, data.release());
+ return true;
+}
+
+ManifestPermission* SocketsManifestHandler::CreatePermission() {
+ return new SocketsManifestPermission();
+}
+
+ManifestPermission* SocketsManifestHandler::CreateInitialRequiredPermission(
+ const Extension* extension) {
+ SocketsManifestData* data = SocketsManifestData::Get(extension);
+ if (data)
+ return data->permission()->Clone();
+ return NULL;
+}
+
+const std::vector<std::string> SocketsManifestHandler::Keys() const {
+ return SingleKey(manifest_keys::kSockets);
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/api/sockets/sockets_manifest_handler.h b/chrome/common/extensions/api/sockets/sockets_manifest_handler.h
new file mode 100644
index 0000000..17dc401
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_manifest_handler.h
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+class Extension;
+class ManifestPermission;
+}
+
+namespace extensions {
+
+// Parses the "sockets" manifest key.
+class SocketsManifestHandler : public ManifestHandler {
+ public:
+ SocketsManifestHandler();
+ virtual ~SocketsManifestHandler();
+
+ // ManifestHandler overrides.
+ virtual bool Parse(Extension* extension, string16* error) OVERRIDE;
+ virtual ManifestPermission* CreatePermission() OVERRIDE;
+ virtual ManifestPermission* CreateInitialRequiredPermission(
+ const Extension* extension) OVERRIDE;
+
+ private:
+ // ManifestHandler overrides.
+ virtual const std::vector<std::string> Keys() const OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(SocketsManifestHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_HANDLER_H_
diff --git a/chrome/common/extensions/api/sockets/sockets_manifest_permission.cc b/chrome/common/extensions/api/sockets/sockets_manifest_permission.cc
new file mode 100644
index 0000000..b654d38
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_manifest_permission.cc
@@ -0,0 +1,386 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/api/sockets/sockets_manifest_permission.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/extensions/api/manifest_types.h"
+#include "chrome/common/extensions/api/sockets/sockets_manifest_data.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "grit/generated_resources.h"
+#include "ipc/ipc_message.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+namespace sockets_errors {
+const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'";
+}
+
+namespace errors = sockets_errors;
+using api::manifest_types::Sockets;
+using content::SocketPermissionRequest;
+
+SocketsManifestPermission::SocketsManifestPermission()
+ : kinds_(kNone) {
+}
+
+SocketsManifestPermission::~SocketsManifestPermission() {}
+
+// static
+scoped_ptr<SocketsManifestPermission> SocketsManifestPermission::FromValue(
+ const base::Value& value,
+ string16* error) {
+ scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error);
+ if (!sockets)
+ return scoped_ptr<SocketsManifestPermission>();
+
+ scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
+ if (sockets->udp) {
+ result->kinds_ |= kUdpPermission;
+ if (!ParseHostPattern(result.get(),
+ SocketPermissionRequest::UDP_BIND,
+ sockets->udp->bind,
+ error)) {
+ return scoped_ptr<SocketsManifestPermission>();
+ }
+ if (!ParseHostPattern(result.get(),
+ SocketPermissionRequest::UDP_SEND_TO,
+ sockets->udp->send,
+ error)) {
+ return scoped_ptr<SocketsManifestPermission>();
+ }
+ if (!ParseHostPattern(result.get(),
+ SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
+ sockets->udp->multicast_membership,
+ error)) {
+ return scoped_ptr<SocketsManifestPermission>();
+ }
+ }
+ if (sockets->tcp) {
+ result->kinds_ |= kTcpPermission;
+ if (!ParseHostPattern(result.get(),
+ SocketPermissionRequest::TCP_CONNECT,
+ sockets->tcp->connect,
+ error)) {
+ return scoped_ptr<SocketsManifestPermission>();
+ }
+ }
+ if (sockets->tcp_server) {
+ result->kinds_ |= kTcpServerPermission;
+ if (!ParseHostPattern(result.get(),
+ SocketPermissionRequest::TCP_LISTEN,
+ sockets->tcp_server->listen,
+ error)) {
+ return scoped_ptr<SocketsManifestPermission>();
+ }
+ }
+ return result.Pass();
+}
+
+bool SocketsManifestPermission::CheckRequest(
+ const Extension* extension,
+ const SocketPermissionRequest& request) const {
+ for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
+ it != permissions_.end(); ++it) {
+ if (it->Check(request))
+ return true;
+ }
+ return false;
+}
+
+std::string SocketsManifestPermission::name() const {
+ return manifest_keys::kSockets;
+}
+
+std::string SocketsManifestPermission::id() const {
+ return name();
+}
+
+bool SocketsManifestPermission::HasMessages() const {
+ bool is_empty = permissions_.empty() && (kinds_ == kNone);
+ return !is_empty;
+}
+
+PermissionMessages SocketsManifestPermission::GetMessages() const {
+ // TODO(rpaquay): This function and callees is (almost) a copy/paste
+ // from extensions::SocketPermissiona.
+ PermissionMessages result;
+ if (!AddAnyHostMessage(result)) {
+ AddSpecificHostMessage(result);
+ AddSubdomainHostMessage(result);
+ }
+ AddNetworkListMessage(result);
+ return result;
+}
+
+bool SocketsManifestPermission::FromValue(const base::Value* value) {
+ if (!value)
+ return false;
+ string16 error;
+ scoped_ptr<SocketsManifestPermission> data(
+ SocketsManifestPermission::FromValue(*value, &error));
+
+ if (!data)
+ return false;
+
+ permissions_ = data->permissions_;
+ kinds_ = data->kinds_;
+ return true;
+}
+
+scoped_ptr<base::Value> SocketsManifestPermission::ToValue() const {
+ Sockets sockets;
+ if (has_udp()) {
+ sockets.udp.reset(new Sockets::Udp());
+ sockets.udp->bind = CreateHostPattern(SocketPermissionRequest::UDP_BIND);
+ sockets.udp->send = CreateHostPattern(SocketPermissionRequest::UDP_SEND_TO);
+ sockets.udp->multicast_membership =
+ CreateHostPattern(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP);
+ }
+ if (has_tcp()) {
+ sockets.tcp.reset(new Sockets::Tcp());
+ sockets.tcp->connect =
+ CreateHostPattern(SocketPermissionRequest::TCP_CONNECT);
+ }
+ if (has_tcp_server()) {
+ sockets.tcp_server.reset(new Sockets::TcpServer());
+ sockets.tcp_server->listen =
+ CreateHostPattern(SocketPermissionRequest::TCP_LISTEN);
+ }
+
+ return scoped_ptr<base::Value>(sockets.ToValue().release()).Pass();
+}
+
+ManifestPermission* SocketsManifestPermission::Clone() const {
+ scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
+ result->permissions_ = permissions_;
+ result->kinds_ = kinds_;
+ return result.release();
+}
+
+ManifestPermission* SocketsManifestPermission::Diff(
+ const ManifestPermission* rhs) const {
+ const SocketsManifestPermission* other =
+ static_cast<const SocketsManifestPermission*>(rhs);
+
+ scoped_ptr<SocketsManifestPermission> data(new SocketsManifestPermission());
+ std::set_difference(
+ permissions_.begin(), permissions_.end(),
+ other->permissions_.begin(), other->permissions_.end(),
+ std::inserter<SocketPermissionEntrySet>(
+ data->permissions_, data->permissions_.begin()));
+
+ data->kinds_ = (kinds_ & (~other->kinds_));
+
+ // Note: We may need to fix up |kinds_| because any permission entry
+ // in a given group (udp, tcp, etc.) implies the corresponding kind bit set.
+ data->kinds_ |= HasOperationType(data->permissions_,
+ SocketPermissionRequest::UDP_BIND, kUdpPermission);
+ data->kinds_ |= HasOperationType(data->permissions_,
+ SocketPermissionRequest::UDP_SEND_TO, kUdpPermission);
+ data->kinds_ |= HasOperationType(data->permissions_,
+ SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, kUdpPermission);
+ data->kinds_ |= HasOperationType(data->permissions_,
+ SocketPermissionRequest::TCP_CONNECT, kTcpPermission);
+ data->kinds_ |= HasOperationType(data->permissions_,
+ SocketPermissionRequest::TCP_LISTEN, kTcpServerPermission);
+ return data.release();
+}
+
+ManifestPermission* SocketsManifestPermission::Union(
+ const ManifestPermission* rhs) const {
+ const SocketsManifestPermission* other =
+ static_cast<const SocketsManifestPermission*>(rhs);
+
+ scoped_ptr<SocketsManifestPermission> data(new SocketsManifestPermission());
+ std::set_union(
+ permissions_.begin(), permissions_.end(),
+ other->permissions_.begin(), other->permissions_.end(),
+ std::inserter<SocketPermissionEntrySet>(
+ data->permissions_, data->permissions_.begin()));
+
+ data->kinds_ = (kinds_ | other->kinds_);
+ return data.release();
+}
+
+ManifestPermission* SocketsManifestPermission::Intersect(
+ const ManifestPermission* rhs) const {
+ const SocketsManifestPermission* other =
+ static_cast<const SocketsManifestPermission*>(rhs);
+
+ scoped_ptr<SocketsManifestPermission> data(new SocketsManifestPermission());
+ std::set_intersection(
+ permissions_.begin(), permissions_.end(),
+ other->permissions_.begin(), other->permissions_.end(),
+ std::inserter<SocketPermissionEntrySet>(
+ data->permissions_, data->permissions_.begin()));
+
+ data->kinds_ = (kinds_ & other->kinds_);
+ return data.release();
+}
+
+bool SocketsManifestPermission::Contains(const ManifestPermission* rhs) const {
+ const SocketsManifestPermission* other =
+ static_cast<const SocketsManifestPermission*>(rhs);
+
+ return std::includes(
+ permissions_.begin(), permissions_.end(),
+ other->permissions_.begin(), other->permissions_.end()) &&
+ ((kinds_ | other->kinds_) == kinds_);
+}
+
+bool SocketsManifestPermission::Equal(const ManifestPermission* rhs) const {
+ const SocketsManifestPermission* other =
+ static_cast<const SocketsManifestPermission*>(rhs);
+
+ return (permissions_ == other->permissions_) &&
+ (kinds_ == other->kinds_);
+}
+
+void SocketsManifestPermission::Write(IPC::Message* m) const {
+ IPC::WriteParam(m, permissions_);
+ IPC::WriteParam(m, kinds_);
+}
+
+bool SocketsManifestPermission::Read(const IPC::Message* m,
+ PickleIterator* iter) {
+ return IPC::ReadParam(m, iter, &permissions_) &&
+ IPC::ReadParam(m, iter, &kinds_);
+}
+
+void SocketsManifestPermission::Log(std::string* log) const {
+ IPC::LogParam(permissions_, log);
+ IPC::LogParam(kinds_, log);
+}
+
+// static
+bool SocketsManifestPermission::ParseHostPattern(
+ SocketsManifestPermission* manifest_data,
+ SocketPermissionRequest::OperationType operation_type,
+ const scoped_ptr<std::string>& value,
+ string16* error) {
+ if (value) {
+ SocketPermissionEntry entry;
+ if (!SocketPermissionEntry::ParseHostPattern(
+ operation_type, *value, &entry)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kErrorInvalidHostPattern, *value);
+ return false;
+ }
+ manifest_data->AddPermission(entry);
+ }
+ return true;
+}
+
+// static
+SocketsManifestPermission::PermissionKind SocketsManifestPermission::
+ HasOperationType(const SocketPermissionEntrySet& set,
+ SocketPermissionRequest::OperationType operation_type,
+ PermissionKind kind) {
+ for (SocketPermissionEntrySet::const_iterator it = set.begin();
+ it != set.end() ; ++it) {
+ if (it->pattern().type == operation_type)
+ return kind;
+ }
+ return kNone;
+}
+
+
+scoped_ptr<std::string> SocketsManifestPermission::CreateHostPattern(
+ SocketPermissionRequest::OperationType operation_type) const {
+ scoped_ptr<std::string> result;
+ for (SocketPermissionEntrySet::const_iterator it =
+ entries().begin(); it != entries().end() ; ++it) {
+ if (it->pattern().type == operation_type) {
+ result.reset(new std::string(it->GetHostPatternAsString()));
+ break;
+ }
+ }
+ return result.Pass();
+}
+
+void SocketsManifestPermission::AddPermission(
+ const SocketPermissionEntry& entry) {
+ permissions_.insert(entry);
+}
+
+bool SocketsManifestPermission::AddAnyHostMessage(
+ PermissionMessages& messages) const {
+ for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
+ it != permissions_.end(); ++it) {
+ if (it->IsAddressBoundType() &&
+ it->GetHostType() == SocketPermissionEntry::ANY_HOST) {
+ messages.push_back(PermissionMessage(
+ PermissionMessage::kSocketAnyHost,
+ l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST)));
+ return true;
+ }
+ }
+ return false;
+}
+
+void SocketsManifestPermission::AddSubdomainHostMessage(
+ PermissionMessages& messages) const {
+ std::set<string16> domains;
+ for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
+ it != permissions_.end(); ++it) {
+ if (it->GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS)
+ domains.insert(UTF8ToUTF16(it->pattern().host));
+ }
+ if (!domains.empty()) {
+ int id = (domains.size() == 1) ?
+ IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN :
+ IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS;
+ messages.push_back(PermissionMessage(
+ PermissionMessage::kSocketDomainHosts,
+ l10n_util::GetStringFUTF16(
+ id,
+ JoinString(
+ std::vector<string16>(
+ domains.begin(), domains.end()), ' '))));
+ }
+}
+
+void SocketsManifestPermission::AddSpecificHostMessage(
+ PermissionMessages& messages) const {
+ std::set<string16> hostnames;
+ for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
+ it != permissions_.end(); ++it) {
+ if (it->GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS)
+ hostnames.insert(UTF8ToUTF16(it->pattern().host));
+ }
+ if (!hostnames.empty()) {
+ int id = (hostnames.size() == 1) ?
+ IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST :
+ IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS;
+ messages.push_back(PermissionMessage(
+ PermissionMessage::kSocketSpecificHosts,
+ l10n_util::GetStringFUTF16(
+ id,
+ JoinString(
+ std::vector<string16>(
+ hostnames.begin(), hostnames.end()), ' '))));
+ }
+}
+
+void SocketsManifestPermission::AddNetworkListMessage(
+ PermissionMessages& messages) const {
+ for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
+ it != permissions_.end(); ++it) {
+ if (it->pattern().type == SocketPermissionRequest::NETWORK_STATE) {
+ messages.push_back(PermissionMessage(
+ PermissionMessage::kNetworkState,
+ l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE)));
+ }
+ }
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/api/sockets/sockets_manifest_permission.h b/chrome/common/extensions/api/sockets/sockets_manifest_permission.h
new file mode 100644
index 0000000..ca65b0f
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_manifest_permission.h
@@ -0,0 +1,100 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_PERMISSION_H_
+#define CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_PERMISSION_H_
+
+#include <set>
+#include <vector>
+
+#include "chrome/common/extensions/permissions/socket_permission_entry.h"
+#include "extensions/common/install_warning.h"
+#include "extensions/common/permissions/manifest_permission.h"
+
+namespace content {
+struct SocketPermissionRequest;
+}
+
+namespace extensions {
+class Extension;
+}
+
+namespace extensions {
+
+class SocketsManifestPermission : public ManifestPermission {
+ public:
+ typedef std::set<SocketPermissionEntry> SocketPermissionEntrySet;
+ enum PermissionKind {
+ kNone = 0,
+ kTcpPermission = 1 << 0,
+ kUdpPermission = 1 << 1,
+ kTcpServerPermission = 1 << 2
+ };
+
+ SocketsManifestPermission();
+ virtual ~SocketsManifestPermission();
+
+ // Tries to construct the info based on |value|, as it would have appeared in
+ // the manifest. Sets |error| and returns an empty scoped_ptr on failure.
+ static scoped_ptr<SocketsManifestPermission> FromValue(
+ const base::Value& value,
+ string16* error);
+
+ bool CheckRequest(const Extension* extension,
+ const content::SocketPermissionRequest& request) const;
+
+ // extensions::ManifestPermission overrides.
+ virtual std::string name() const OVERRIDE;
+ virtual std::string id() const OVERRIDE;
+ virtual bool HasMessages() const OVERRIDE;
+ virtual PermissionMessages GetMessages() const OVERRIDE;
+ virtual bool FromValue(const base::Value* value) OVERRIDE;
+ virtual scoped_ptr<base::Value> ToValue() const OVERRIDE;
+ virtual ManifestPermission* Clone() const OVERRIDE;
+ virtual ManifestPermission* Diff(const ManifestPermission* rhs) const
+ OVERRIDE;
+ virtual ManifestPermission* Union(const ManifestPermission* rhs) const
+ OVERRIDE;
+ virtual ManifestPermission* Intersect(const ManifestPermission* rhs) const
+ OVERRIDE;
+ virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE;
+ virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE;
+ virtual void Write(IPC::Message* m) const OVERRIDE;
+ virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE;
+ virtual void Log(std::string* log) const OVERRIDE;
+
+ bool has_udp() const { return (kinds_ & kUdpPermission) != 0; }
+ bool has_tcp() const { return (kinds_ & kTcpPermission) != 0; }
+ bool has_tcp_server() const { return (kinds_ & kTcpServerPermission) != 0; }
+ const SocketPermissionEntrySet& entries() const { return permissions_; }
+
+ private:
+ static bool ParseHostPattern(
+ SocketsManifestPermission* manifest_data,
+ content::SocketPermissionRequest::OperationType operation_type,
+ const scoped_ptr<std::string>& value,
+ string16* error);
+
+ static PermissionKind HasOperationType(
+ const SocketPermissionEntrySet& set,
+ content::SocketPermissionRequest::OperationType operation_type,
+ PermissionKind kind);
+
+ scoped_ptr<std::string> CreateHostPattern(
+ content::SocketPermissionRequest::OperationType operation_type) const;
+
+ void AddPermission(const SocketPermissionEntry& entry);
+
+ bool AddAnyHostMessage(PermissionMessages& messages) const;
+ void AddSubdomainHostMessage(PermissionMessages& messages) const;
+ void AddSpecificHostMessage(PermissionMessages& messages) const;
+ void AddNetworkListMessage(PermissionMessages& messages) const;
+
+ SocketPermissionEntrySet permissions_;
+ int kinds_; // PermissionKind bits
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_MANIFEST_PERMISSION_H_
diff --git a/chrome/common/extensions/api/sockets/sockets_manifest_permission_unittest.cc b/chrome/common/extensions/api/sockets/sockets_manifest_permission_unittest.cc
new file mode 100644
index 0000000..67ece853
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_manifest_permission_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_reader.h"
+#include "base/pickle.h"
+#include "base/values.h"
+#include "chrome/common/extensions/api/sockets/sockets_manifest_permission.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "extensions/common/manifest_constants.h"
+#include "ipc/ipc_message.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+static void AssertEmptyPermission(const SocketsManifestPermission* permission) {
+ EXPECT_TRUE(permission);
+ EXPECT_EQ(std::string(extensions::manifest_keys::kSockets), permission->id());
+ EXPECT_EQ(permission->id(), permission->name());
+ EXPECT_FALSE(permission->HasMessages());
+ EXPECT_EQ(0u, permission->entries().size());
+}
+
+} // namespace
+
+TEST(SocketsManifestPermissionTest, Empty) {
+ // Construction
+ scoped_ptr<SocketsManifestPermission> permission(
+ new SocketsManifestPermission());
+ AssertEmptyPermission(permission.get());
+
+ // Clone()/Equal()
+ scoped_ptr<SocketsManifestPermission> clone(
+ static_cast<SocketsManifestPermission*>(permission->Clone()));
+ AssertEmptyPermission(clone.get());
+
+ EXPECT_TRUE(permission->Equal(clone.get()));
+
+ // ToValue()/FromValue()
+ scoped_ptr<const base::Value> value(permission->ToValue());
+ EXPECT_TRUE(value.get());
+
+ scoped_ptr<SocketsManifestPermission> permission2(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission2->FromValue(value.get()));
+ AssertEmptyPermission(permission2.get());
+
+ // Union/Diff/Intersection
+ scoped_ptr<SocketsManifestPermission> diff_perm(
+ static_cast<SocketsManifestPermission*>(permission->Diff(clone.get())));
+ AssertEmptyPermission(diff_perm.get());
+
+ scoped_ptr<SocketsManifestPermission> union_perm(
+ static_cast<SocketsManifestPermission*>(permission->Union(clone.get())));
+ AssertEmptyPermission(union_perm.get());
+
+ scoped_ptr<SocketsManifestPermission> intersect_perm(
+ static_cast<SocketsManifestPermission*>(
+ permission->Intersect(clone.get())));
+ AssertEmptyPermission(intersect_perm.get());
+
+ // IPC
+ scoped_ptr<SocketsManifestPermission> ipc_perm(
+ new SocketsManifestPermission());
+ scoped_ptr<SocketsManifestPermission> ipc_perm2(
+ new SocketsManifestPermission());
+
+ IPC::Message m;
+ ipc_perm->Write(&m);
+ PickleIterator iter(m);
+ EXPECT_TRUE(ipc_perm2->Read(&m, &iter));
+ AssertEmptyPermission(ipc_perm2.get());
+}
+
+TEST(SocketsManifestPermissionTest, General) {
+ std::string udp_send_string = "{ \"udp\": { \"send\": \"\" } }";
+ scoped_ptr<base::Value> udp_send(base::JSONReader::Read(udp_send_string));
+ EXPECT_TRUE(udp_send);
+
+ std::string udp_bind_string = "{ \"udp\": { \"bind\": \"127.0.0.1:3007\" } }";
+ scoped_ptr<base::Value> udp_bind(base::JSONReader::Read(udp_bind_string));
+ EXPECT_TRUE(udp_bind);
+
+ std::string tcp_connect_string =
+ "{ \"tcp\": { \"connect\": \"127.0.0.1:80\" } }";
+ scoped_ptr<base::Value> tcp_connect(
+ base::JSONReader::Read(tcp_connect_string));
+ EXPECT_TRUE(tcp_connect);
+
+ std::string tcp_server_listen_string =
+ "{ \"tcpServer\": { \"listen\": \"127.0.0.1:80\" } }";
+ scoped_ptr<base::Value> tcp_server_listen(
+ base::JSONReader::Read(tcp_server_listen_string));
+ EXPECT_TRUE(tcp_server_listen);
+
+ // FromValue()
+ scoped_ptr<SocketsManifestPermission> permission1(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission1->FromValue(udp_send.get()));
+ EXPECT_EQ(1u, permission1->entries().size());
+
+ scoped_ptr<SocketsManifestPermission> permission2(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission2->FromValue(udp_bind.get()));
+ EXPECT_EQ(1u, permission2->entries().size());
+
+ scoped_ptr<SocketsManifestPermission> permission3(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission3->FromValue(tcp_connect.get()));
+ EXPECT_EQ(1u, permission3->entries().size());
+
+ scoped_ptr<SocketsManifestPermission> permission4(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission4->FromValue(tcp_server_listen.get()));
+ EXPECT_EQ(1u, permission4->entries().size());
+
+ // ToValue()
+ scoped_ptr<base::Value> value1 = permission1->ToValue();
+ EXPECT_TRUE(value1);
+ scoped_ptr<SocketsManifestPermission> permission1_1(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission1_1->FromValue(value1.get()));
+ EXPECT_TRUE(permission1->Equal(permission1_1.get()));
+
+ scoped_ptr<base::Value> value2 = permission2->ToValue();
+ EXPECT_TRUE(value2);
+ scoped_ptr<SocketsManifestPermission> permission2_1(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission2_1->FromValue(value2.get()));
+ EXPECT_TRUE(permission2->Equal(permission2_1.get()));
+
+ scoped_ptr<base::Value> value3 = permission3->ToValue();
+ EXPECT_TRUE(value3);
+ scoped_ptr<SocketsManifestPermission> permission3_1(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission3_1->FromValue(value3.get()));
+ EXPECT_TRUE(permission3->Equal(permission3_1.get()));
+
+ scoped_ptr<base::Value> value4 = permission4->ToValue();
+ EXPECT_TRUE(value4);
+ scoped_ptr<SocketsManifestPermission> permission4_1(
+ new SocketsManifestPermission());
+ EXPECT_TRUE(permission4_1->FromValue(value4.get()));
+ EXPECT_TRUE(permission4->Equal(permission4_1.get()));
+
+ // Union/Diff/Intersection
+ scoped_ptr<SocketsManifestPermission> union_perm(
+ static_cast<SocketsManifestPermission*>(
+ permission1->Union(permission2.get())));
+ EXPECT_TRUE(union_perm);
+ EXPECT_EQ(2u, union_perm->entries().size());
+
+ EXPECT_TRUE(union_perm->Contains(permission1.get()));
+ EXPECT_TRUE(union_perm->Contains(permission2.get()));
+ EXPECT_FALSE(union_perm->Contains(permission3.get()));
+ EXPECT_FALSE(union_perm->Contains(permission4.get()));
+
+ scoped_ptr<SocketsManifestPermission> diff_perm1(
+ static_cast<SocketsManifestPermission*>(
+ permission1->Diff(permission2.get())));
+ EXPECT_TRUE(diff_perm1);
+ EXPECT_EQ(1u, diff_perm1->entries().size());
+
+ EXPECT_TRUE(permission1->Equal(diff_perm1.get()));
+ EXPECT_TRUE(diff_perm1->Equal(permission1.get()));
+
+ scoped_ptr<SocketsManifestPermission> diff_perm2(
+ static_cast<SocketsManifestPermission*>(
+ permission1->Diff(union_perm.get())));
+ EXPECT_TRUE(diff_perm2);
+ AssertEmptyPermission(diff_perm2.get());
+
+ scoped_ptr<SocketsManifestPermission> intersect_perm1(
+ static_cast<SocketsManifestPermission*>(
+ union_perm->Intersect(permission1.get())));
+ EXPECT_TRUE(intersect_perm1);
+ EXPECT_EQ(1u, intersect_perm1->entries().size());
+
+ EXPECT_TRUE(permission1->Equal(intersect_perm1.get()));
+ EXPECT_TRUE(intersect_perm1->Equal(permission1.get()));
+
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/chrome_manifest_handlers.cc b/chrome/common/extensions/chrome_manifest_handlers.cc
index 3363b79..e832639 100644
--- a/chrome/common/extensions/chrome_manifest_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -20,7 +20,7 @@
#include "chrome/common/extensions/api/media_galleries_private/media_galleries_handler.h"
#include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
#include "chrome/common/extensions/api/plugins/plugins_handler.h"
-#include "chrome/common/extensions/api/sockets/sockets_handler.h"
+#include "chrome/common/extensions/api/sockets/sockets_manifest_handler.h"
#include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
#include "chrome/common/extensions/api/spellcheck/spellcheck_handler.h"
#include "chrome/common/extensions/api/system_indicator/system_indicator_handler.h"
@@ -90,7 +90,7 @@ void RegisterChromeManifestHandlers() {
(new SettingsOverridesHandler)->Register();
(new ScriptBadgeHandler)->Register();
(new SharedModuleHandler)->Register();
- (new SocketsHandler)->Register();
+ (new SocketsManifestHandler)->Register();
(new SpellcheckHandler)->Register();
(new StorageSchemaManifestHandler)->Register();
(new SystemIndicatorHandler)->Register();
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index e118bdc..71018cc 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -557,6 +557,7 @@ bool Extension::InitFromValue(int flags, string16* error) {
finished_parsing_manifest_ = true;
+ permissions_data_->InitializeManifestPermissions(this);
permissions_data_->FinalizePermissions(this);
return true;
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index d88b4da..2bb79eb 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -45,6 +45,7 @@ class ImageSkia;
namespace extensions {
class PermissionsData;
class APIPermissionSet;
+class ManifestPermissionSet;
class PermissionSet;
// Represents a Chrome extension.
diff --git a/chrome/common/extensions/extension_messages.cc b/chrome/common/extensions/extension_messages.cc
index 0e3c5e4..a8acbf8 100644
--- a/chrome/common/extensions/extension_messages.cc
+++ b/chrome/common/extensions/extension_messages.cc
@@ -9,14 +9,17 @@
#include "chrome/common/extensions/permissions/permissions_data.h"
#include "content/public/common/common_param_traits.h"
#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_handler.h"
#include "extensions/common/permissions/permissions_info.h"
using extensions::APIPermission;
using extensions::APIPermissionInfo;
-using extensions::APIPermissionMap;
using extensions::APIPermissionSet;
using extensions::Extension;
using extensions::Manifest;
+using extensions::ManifestHandler;
+using extensions::ManifestPermission;
+using extensions::ManifestPermissionSet;
using extensions::PermissionSet;
using extensions::URLPatternSet;
@@ -32,6 +35,8 @@ ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params(
location(extension->location()),
path(extension->path()),
apis(extension->GetActivePermissions()->apis()),
+ manifest_permissions(
+ extension->GetActivePermissions()->manifest_permissions()),
explicit_hosts(extension->GetActivePermissions()->explicit_hosts()),
scriptable_hosts(extension->GetActivePermissions()->scriptable_hosts()),
id(extension->id()),
@@ -45,7 +50,8 @@ scoped_refptr<Extension> ExtensionMsg_Loaded_Params::ConvertToExtension(
if (extension.get()) {
extensions::PermissionsData::SetActivePermissions(
extension.get(),
- new PermissionSet(apis, explicit_hosts, scriptable_hosts));
+ new PermissionSet(apis, manifest_permissions,
+ explicit_hosts, scriptable_hosts));
}
return extension;
}
@@ -183,6 +189,41 @@ void ParamTraits<APIPermissionSet>::Log(
LogParam(p.map(), l);
}
+void ParamTraits<ManifestPermissionSet>::Write(
+ Message* m, const param_type& p) {
+ ManifestPermissionSet::const_iterator it = p.begin();
+ const ManifestPermissionSet::const_iterator end = p.end();
+ WriteParam(m, p.size());
+ for (; it != end; ++it) {
+ WriteParam(m, it->name());
+ it->Write(m);
+ }
+}
+
+bool ParamTraits<ManifestPermissionSet>::Read(
+ const Message* m, PickleIterator* iter, param_type* r) {
+ size_t size;
+ if (!ReadParam(m, iter, &size))
+ return false;
+ for (size_t i = 0; i < size; ++i) {
+ std::string name;
+ if (!ReadParam(m, iter, &name))
+ return false;
+ scoped_ptr<ManifestPermission> p(ManifestHandler::CreatePermission(name));
+ if (!p)
+ return false;
+ if (!p->Read(m, iter))
+ return false;
+ r->insert(p.release());
+ }
+ return true;
+}
+
+void ParamTraits<ManifestPermissionSet>::Log(
+ const param_type& p, std::string* l) {
+ LogParam(p.map(), l);
+}
+
void ParamTraits<ExtensionMsg_Loaded_Params>::Write(Message* m,
const param_type& p) {
WriteParam(m, p.location);
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 8e0d843..f7f6a09 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -143,6 +143,16 @@ IPC_STRUCT_BEGIN(ExtensionMsg_ExternalConnectionInfo)
IPC_STRUCT_MEMBER(GURL, source_url)
IPC_STRUCT_END()
+// Parameters structure for ExtensionMsg_UpdatePermissions.
+IPC_STRUCT_BEGIN(ExtensionMsg_UpdatePermissions_Params)
+ IPC_STRUCT_MEMBER(int /* UpdateExtensionPermissionsInfo::REASON */, reason_id)
+ IPC_STRUCT_MEMBER(std::string, extension_id)
+ IPC_STRUCT_MEMBER(extensions::APIPermissionSet, apis)
+ IPC_STRUCT_MEMBER(extensions::ManifestPermissionSet, manifest_permissions)
+ IPC_STRUCT_MEMBER(extensions::URLPatternSet, explicit_hosts)
+ IPC_STRUCT_MEMBER(extensions::URLPatternSet, scriptable_hosts)
+IPC_STRUCT_END()
+
IPC_STRUCT_TRAITS_BEGIN(WebApplicationInfo::IconInfo)
IPC_STRUCT_TRAITS_MEMBER(url)
IPC_STRUCT_TRAITS_MEMBER(width)
@@ -233,6 +243,7 @@ struct ExtensionMsg_Loaded_Params {
// The extension's active permissions.
extensions::APIPermissionSet apis;
+ extensions::ManifestPermissionSet manifest_permissions;
extensions::URLPatternSet explicit_hosts;
extensions::URLPatternSet scriptable_hosts;
@@ -284,6 +295,14 @@ struct ParamTraits<extensions::APIPermissionSet> {
};
template <>
+struct ParamTraits<extensions::ManifestPermissionSet> {
+ typedef extensions::ManifestPermissionSet param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
struct ParamTraits<ExtensionMsg_Loaded_Params> {
typedef ExtensionMsg_Loaded_Params param_type;
static void Write(Message* m, const param_type& p);
@@ -374,12 +393,8 @@ IPC_MESSAGE_ROUTED1(ExtensionMsg_SetTabId,
int /* id of tab */)
// Tell the renderer to update an extension's permission set.
-IPC_MESSAGE_CONTROL5(ExtensionMsg_UpdatePermissions,
- int /* UpdateExtensionPermissionsInfo::REASON */,
- std::string /* extension_id */,
- extensions::APIPermissionSet /* permissions */,
- extensions::URLPatternSet /* explicit_hosts */,
- extensions::URLPatternSet /* scriptable_hosts */)
+IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdatePermissions,
+ ExtensionMsg_UpdatePermissions_Params)
// Tell the renderer about new tab-specific permissions for an extension.
IPC_MESSAGE_CONTROL4(ExtensionMsg_UpdateTabSpecificPermissions,
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
index e5105cb..cd04710 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
@@ -37,8 +37,12 @@ PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages(
std::set<PermissionMessage> host_msgs =
GetHostPermissionMessages(permissions, extension_type);
std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages(permissions);
+ std::set<PermissionMessage> manifest_permission_msgs =
+ GetManifestPermissionMessages(permissions);
messages.insert(messages.end(), host_msgs.begin(), host_msgs.end());
messages.insert(messages.end(), api_msgs.begin(), api_msgs.end());
+ messages.insert(messages.end(), manifest_permission_msgs.begin(),
+ manifest_permission_msgs.end());
return messages;
}
@@ -193,6 +197,22 @@ ChromePermissionMessageProvider::GetAPIPermissionMessages(
}
std::set<PermissionMessage>
+ChromePermissionMessageProvider::GetManifestPermissionMessages(
+ const PermissionSet* permissions) const {
+ std::set<PermissionMessage> messages;
+ for (ManifestPermissionSet::const_iterator permission_it =
+ permissions->manifest_permissions().begin();
+ permission_it != permissions->manifest_permissions().end();
+ ++permission_it) {
+ if (permission_it->HasMessages()) {
+ PermissionMessages new_messages = permission_it->GetMessages();
+ messages.insert(new_messages.begin(), new_messages.end());
+ }
+ }
+ return messages;
+}
+
+std::set<PermissionMessage>
ChromePermissionMessageProvider::GetHostPermissionMessages(
const PermissionSet* permissions,
Manifest::Type extension_type) const {
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.h b/chrome/common/extensions/permissions/chrome_permission_message_provider.h
index 05125f4..44b122c 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_provider.h
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.h
@@ -39,6 +39,10 @@ class ChromePermissionMessageProvider : public PermissionMessageProvider {
std::set<PermissionMessage> GetAPIPermissionMessages(
const PermissionSet* permissions) const;
+ // Gets the permission messages for the Manifest permissions.
+ std::set<PermissionMessage> GetManifestPermissionMessages(
+ const PermissionSet* permissions) const;
+
// Gets the permission messages for the host permissions.
std::set<PermissionMessage> GetHostPermissionMessages(
const PermissionSet* permissions,
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 7ee32eb..302df86 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -202,6 +202,7 @@ TEST(PermissionsTest, EffectiveHostPermissions) {
TEST(PermissionsTest, ExplicitAccessToOrigin) {
APIPermissionSet apis;
+ ManifestPermissionSet manifest_permissions;
URLPatternSet explicit_hosts;
URLPatternSet scriptable_hosts;
@@ -210,7 +211,7 @@ TEST(PermissionsTest, ExplicitAccessToOrigin) {
AddPattern(&explicit_hosts, "http://www.example.com/a/particular/path/*");
scoped_refptr<PermissionSet> perm_set = new PermissionSet(
- apis, explicit_hosts, scriptable_hosts);
+ apis, manifest_permissions, explicit_hosts, scriptable_hosts);
ASSERT_TRUE(perm_set->HasExplicitAccessToOrigin(
GURL("http://www.google.com/")));
ASSERT_TRUE(perm_set->HasExplicitAccessToOrigin(
@@ -226,6 +227,7 @@ TEST(PermissionsTest, ExplicitAccessToOrigin) {
TEST(PermissionsTest, CreateUnion) {
APIPermission* permission = NULL;
+ ManifestPermissionSet manifest_permissions;
APIPermissionSet apis1;
APIPermissionSet apis2;
APIPermissionSet expected_apis;
@@ -270,8 +272,10 @@ TEST(PermissionsTest, CreateUnion) {
AddPattern(&expected_explicit_hosts, "http://*.google.com/*");
AddPattern(&effective_hosts, "http://*.google.com/*");
- set1 = new PermissionSet(apis1, explicit_hosts1, scriptable_hosts1);
- set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
+ set1 = new PermissionSet(apis1, manifest_permissions,
+ explicit_hosts1, scriptable_hosts1);
+ set2 = new PermissionSet(apis2, manifest_permissions,
+ explicit_hosts2, scriptable_hosts2);
union_set = PermissionSet::CreateUnion(set1.get(), set2.get());
EXPECT_TRUE(set1->Contains(*set2.get()));
EXPECT_TRUE(set1->Contains(*union_set.get()));
@@ -332,7 +336,8 @@ TEST(PermissionsTest, CreateUnion) {
URLPatternSet::CreateUnion(
explicit_hosts2, scriptable_hosts2, &effective_hosts);
- set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
+ set2 = new PermissionSet(apis2, manifest_permissions,
+ explicit_hosts2, scriptable_hosts2);
union_set = PermissionSet::CreateUnion(set1.get(), set2.get());
EXPECT_FALSE(set1->Contains(*set2.get()));
@@ -353,6 +358,7 @@ TEST(PermissionsTest, CreateUnion) {
TEST(PermissionsTest, CreateIntersection) {
APIPermission* permission = NULL;
+ ManifestPermissionSet manifest_permissions;
APIPermissionSet apis1;
APIPermissionSet apis2;
APIPermissionSet expected_apis;
@@ -393,8 +399,10 @@ TEST(PermissionsTest, CreateIntersection) {
AddPattern(&explicit_hosts1, "http://*.google.com/*");
AddPattern(&scriptable_hosts1, "http://www.reddit.com/*");
- set1 = new PermissionSet(apis1, explicit_hosts1, scriptable_hosts1);
- set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
+ set1 = new PermissionSet(apis1, manifest_permissions,
+ explicit_hosts1, scriptable_hosts1);
+ set2 = new PermissionSet(apis2, manifest_permissions,
+ explicit_hosts2, scriptable_hosts2);
new_set = PermissionSet::CreateIntersection(set1.get(), set2.get());
EXPECT_TRUE(set1->Contains(*new_set.get()));
EXPECT_TRUE(set2->Contains(*new_set.get()));
@@ -447,7 +455,8 @@ TEST(PermissionsTest, CreateIntersection) {
effective_hosts.ClearPatterns();
AddPattern(&effective_hosts, "http://*.google.com/*");
- set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
+ set2 = new PermissionSet(apis2, manifest_permissions,
+ explicit_hosts2, scriptable_hosts2);
new_set = PermissionSet::CreateIntersection(set1.get(), set2.get());
EXPECT_TRUE(set1->Contains(*new_set.get()));
@@ -468,6 +477,7 @@ TEST(PermissionsTest, CreateIntersection) {
TEST(PermissionsTest, CreateDifference) {
APIPermission* permission = NULL;
+ ManifestPermissionSet manifest_permissions;
APIPermissionSet apis1;
APIPermissionSet apis2;
APIPermissionSet expected_apis;
@@ -508,8 +518,10 @@ TEST(PermissionsTest, CreateDifference) {
AddPattern(&explicit_hosts1, "http://*.google.com/*");
AddPattern(&scriptable_hosts1, "http://www.reddit.com/*");
- set1 = new PermissionSet(apis1, explicit_hosts1, scriptable_hosts1);
- set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
+ set1 = new PermissionSet(apis1, manifest_permissions,
+ explicit_hosts1, scriptable_hosts1);
+ set2 = new PermissionSet(apis2, manifest_permissions,
+ explicit_hosts2, scriptable_hosts2);
new_set = PermissionSet::CreateDifference(set1.get(), set2.get());
EXPECT_EQ(*set1.get(), *new_set.get());
@@ -550,7 +562,8 @@ TEST(PermissionsTest, CreateDifference) {
effective_hosts.ClearPatterns();
AddPattern(&effective_hosts, "http://www.reddit.com/*");
- set2 = new PermissionSet(apis2, explicit_hosts2, scriptable_hosts2);
+ set2 = new PermissionSet(apis2, manifest_permissions,
+ explicit_hosts2, scriptable_hosts2);
new_set = PermissionSet::CreateDifference(set1.get(), set2.get());
EXPECT_TRUE(set1->Contains(*new_set.get()));
@@ -773,7 +786,8 @@ TEST(PermissionsTest, FileSystemPermissionMessages) {
api_permissions.insert(APIPermission::kFileSystemWrite);
api_permissions.insert(APIPermission::kFileSystemDirectory);
scoped_refptr<PermissionSet> permissions(
- new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet()));
+ new PermissionSet(api_permissions, ManifestPermissionSet(),
+ URLPatternSet(), URLPatternSet()));
PermissionMessages messages =
PermissionMessageProvider::Get()->GetPermissionMessages(
permissions, Manifest::TYPE_PLATFORM_APP);
@@ -794,7 +808,8 @@ TEST(PermissionsTest, HiddenFileSystemPermissionMessages) {
api_permissions.insert(APIPermission::kFileSystemDirectory);
api_permissions.insert(APIPermission::kFileSystemWriteDirectory);
scoped_refptr<PermissionSet> permissions(
- new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet()));
+ new PermissionSet(api_permissions, ManifestPermissionSet(),
+ URLPatternSet(), URLPatternSet()));
PermissionMessages messages =
PermissionMessageProvider::Get()->GetPermissionMessages(
permissions, Manifest::TYPE_PLATFORM_APP);
@@ -805,19 +820,24 @@ TEST(PermissionsTest, HiddenFileSystemPermissionMessages) {
TEST(PermissionsTest, MergedFileSystemPermissionComparison) {
APIPermissionSet write_api_permissions;
write_api_permissions.insert(APIPermission::kFileSystemWrite);
- scoped_refptr<PermissionSet> write_permissions(new PermissionSet(
- write_api_permissions, URLPatternSet(), URLPatternSet()));
+ scoped_refptr<PermissionSet> write_permissions(
+ new PermissionSet(write_api_permissions, ManifestPermissionSet(),
+ URLPatternSet(), URLPatternSet()));
APIPermissionSet directory_api_permissions;
directory_api_permissions.insert(APIPermission::kFileSystemDirectory);
- scoped_refptr<PermissionSet> directory_permissions(new PermissionSet(
- directory_api_permissions, URLPatternSet(), URLPatternSet()));
+ scoped_refptr<PermissionSet> directory_permissions(
+ new PermissionSet(directory_api_permissions, ManifestPermissionSet(),
+ URLPatternSet(), URLPatternSet()));
APIPermissionSet write_directory_api_permissions;
write_directory_api_permissions.insert(
APIPermission::kFileSystemWriteDirectory);
- scoped_refptr<PermissionSet> write_directory_permissions(new PermissionSet(
- write_directory_api_permissions, URLPatternSet(), URLPatternSet()));
+ scoped_refptr<PermissionSet> write_directory_permissions(
+ new PermissionSet(write_directory_api_permissions,
+ ManifestPermissionSet(),
+ URLPatternSet(),
+ URLPatternSet()));
const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
EXPECT_FALSE(provider->IsPrivilegeIncrease(write_directory_permissions,
@@ -1161,7 +1181,8 @@ TEST(PermissionsTest, GetDistinctHosts) {
expected.insert("*.example.com");
scoped_refptr<PermissionSet> perm_set(new PermissionSet(
- empty_perms, explicit_hosts, scriptable_hosts));
+ empty_perms, ManifestPermissionSet(),
+ explicit_hosts, scriptable_hosts));
EXPECT_EQ(expected,
permission_message_util::GetDistinctHosts(
perm_set->effective_hosts(), true, true));
@@ -1268,6 +1289,7 @@ TEST(PermissionsTest, GetDistinctHosts_FirstInListIs4thBestRcd) {
TEST(PermissionsTest, IsHostPrivilegeIncrease) {
Manifest::Type type = Manifest::TYPE_EXTENSION;
const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
+ ManifestPermissionSet empty_manifest_permissions;
URLPatternSet elist1;
URLPatternSet elist2;
URLPatternSet slist1;
@@ -1286,8 +1308,10 @@ TEST(PermissionsTest, IsHostPrivilegeIncrease) {
elist2.AddPattern(
URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
- set1 = new PermissionSet(empty_perms, elist1, slist1);
- set2 = new PermissionSet(empty_perms, elist2, slist2);
+ set1 = new PermissionSet(empty_perms, empty_manifest_permissions,
+ elist1, slist1);
+ set2 = new PermissionSet(empty_perms, empty_manifest_permissions,
+ elist2, slist2);
EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
@@ -1296,7 +1320,8 @@ TEST(PermissionsTest, IsHostPrivilegeIncrease) {
elist2.ClearPatterns();
elist2.AddPattern(
URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*"));
- set2 = new PermissionSet(empty_perms, elist2, slist2);
+ set2 = new PermissionSet(empty_perms, empty_manifest_permissions,
+ elist2, slist2);
EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
@@ -1304,7 +1329,8 @@ TEST(PermissionsTest, IsHostPrivilegeIncrease) {
elist2.ClearPatterns();
elist2.AddPattern(
URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*"));
- set2 = new PermissionSet(empty_perms, elist2, slist2);
+ set2 = new PermissionSet(empty_perms, empty_manifest_permissions,
+ elist2, slist2);
EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
@@ -1312,7 +1338,8 @@ TEST(PermissionsTest, IsHostPrivilegeIncrease) {
elist2.ClearPatterns();
elist2.AddPattern(
URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*"));
- set2 = new PermissionSet(empty_perms, elist2, slist2);
+ set2 = new PermissionSet(empty_perms, empty_manifest_permissions,
+ elist2, slist2);
EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
// TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337
// EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
@@ -1323,7 +1350,8 @@ TEST(PermissionsTest, IsHostPrivilegeIncrease) {
URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
elist2.AddPattern(
URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path"));
- set2 = new PermissionSet(empty_perms, elist2, slist2);
+ set2 = new PermissionSet(empty_perms, empty_manifest_permissions,
+ elist2, slist2);
EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
@@ -1331,7 +1359,8 @@ TEST(PermissionsTest, IsHostPrivilegeIncrease) {
elist2.ClearPatterns();
elist2.AddPattern(
URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*"));
- set2 = new PermissionSet(empty_perms, elist2, slist2);
+ set2 = new PermissionSet(empty_perms, empty_manifest_permissions,
+ elist2, slist2);
EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
EXPECT_TRUE(provider->IsPrivilegeIncrease(set2, set1, type));
@@ -1351,7 +1380,7 @@ TEST(PermissionsTest, GetAPIsAsStrings) {
apis.insert(APIPermission::kTab);
scoped_refptr<PermissionSet> perm_set = new PermissionSet(
- apis, empty_set, empty_set);
+ apis, ManifestPermissionSet(), empty_set, empty_set);
std::set<std::string> api_names = perm_set->GetAPIsAsStrings();
// The result is correct if it has the same number of elements
@@ -1369,25 +1398,26 @@ TEST(PermissionsTest, IsEmpty) {
EXPECT_TRUE(empty->IsEmpty());
scoped_refptr<PermissionSet> perm_set;
- perm_set = new PermissionSet(empty_apis, empty_extent, empty_extent);
+ perm_set = new PermissionSet(empty_apis, ManifestPermissionSet(),
+ empty_extent, empty_extent);
EXPECT_TRUE(perm_set->IsEmpty());
APIPermissionSet non_empty_apis;
non_empty_apis.insert(APIPermission::kBackground);
- perm_set = new PermissionSet(
- non_empty_apis, empty_extent, empty_extent);
+ perm_set = new PermissionSet(non_empty_apis, ManifestPermissionSet(),
+ empty_extent, empty_extent);
EXPECT_FALSE(perm_set->IsEmpty());
// Try non standard host
URLPatternSet non_empty_extent;
AddPattern(&non_empty_extent, "http://www.google.com/*");
- perm_set = new PermissionSet(
- empty_apis, non_empty_extent, empty_extent);
+ perm_set = new PermissionSet(empty_apis, ManifestPermissionSet(),
+ non_empty_extent, empty_extent);
EXPECT_FALSE(perm_set->IsEmpty());
- perm_set = new PermissionSet(
- empty_apis, empty_extent, non_empty_extent);
+ perm_set = new PermissionSet(empty_apis, ManifestPermissionSet(),
+ empty_extent, non_empty_extent);
EXPECT_FALSE(perm_set->IsEmpty());
}
@@ -1399,7 +1429,8 @@ TEST(PermissionsTest, ImpliedPermissions) {
EXPECT_EQ(2U, apis.size());
scoped_refptr<PermissionSet> perm_set;
- perm_set = new PermissionSet(apis, empty_extent, empty_extent);
+ perm_set = new PermissionSet(apis, ManifestPermissionSet(),
+ empty_extent, empty_extent);
EXPECT_EQ(4U, perm_set->apis().size());
}
@@ -1429,7 +1460,8 @@ TEST(PermissionsTest, ChromeURLs) {
allowed_hosts.AddPattern(
URLPattern(URLPattern::SCHEME_ALL, "chrome://thumb/"));
scoped_refptr<PermissionSet> permissions(
- new PermissionSet(APIPermissionSet(), allowed_hosts, URLPatternSet()));
+ new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+ allowed_hosts, URLPatternSet()));
PermissionMessageProvider::Get()->
GetPermissionMessages(permissions, Manifest::TYPE_EXTENSION);
}
diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc
index 961d719..e023712 100644
--- a/chrome/common/extensions/permissions/permissions_data.cc
+++ b/chrome/common/extensions/permissions/permissions_data.cc
@@ -12,6 +12,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
@@ -20,6 +21,7 @@
#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"
@@ -244,6 +246,7 @@ bool IsTrustedId(const std::string& extension_id) {
struct PermissionsData::InitialPermissions {
APIPermissionSet api_permissions;
+ ManifestPermissionSet manifest_permissions;
URLPatternSet host_permissions;
URLPatternSet scriptable_hosts;
};
@@ -593,19 +596,27 @@ bool PermissionsData::ParsePermissions(Extension* extension, string16* error) {
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());
diff --git a/chrome/common/extensions/permissions/permissions_data.h b/chrome/common/extensions/permissions/permissions_data.h
index 60534ec..d0b6413 100644
--- a/chrome/common/extensions/permissions/permissions_data.h
+++ b/chrome/common/extensions/permissions/permissions_data.h
@@ -22,6 +22,7 @@ namespace extensions {
class PermissionSet;
class APIPermissionSet;
class Extension;
+class ManifestPermissionSet;
class URLPatternSet;
class UserScript;
@@ -180,6 +181,9 @@ class PermissionsData {
// 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);
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index c2bdb07..f4e0d3e 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -548,7 +548,8 @@ TEST_F(ExtensionScriptAndCaptureVisibleTest, TabSpecific) {
{
scoped_refptr<PermissionSet> permissions(
- new PermissionSet(APIPermissionSet(), allowed_hosts, URLPatternSet()));
+ new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+ allowed_hosts, URLPatternSet()));
PermissionsData::UpdateTabSpecificPermissions(
extension.get(), 0, permissions);
EXPECT_EQ(permissions->explicit_hosts(),
@@ -576,7 +577,8 @@ TEST_F(ExtensionScriptAndCaptureVisibleTest, TabSpecific) {
{
scoped_refptr<PermissionSet> permissions(
- new PermissionSet(APIPermissionSet(), allowed_hosts, URLPatternSet()));
+ new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+ allowed_hosts, URLPatternSet()));
PermissionsData::UpdateTabSpecificPermissions(
extension.get(), 0, permissions);
EXPECT_EQ(permissions->explicit_hosts(),
@@ -584,6 +586,7 @@ TEST_F(ExtensionScriptAndCaptureVisibleTest, TabSpecific) {
->explicit_hosts());
permissions = new PermissionSet(APIPermissionSet(),
+ ManifestPermissionSet(),
more_allowed_hosts,
URLPatternSet());
PermissionsData::UpdateTabSpecificPermissions(
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc
index ea5ca21..943e97d 100644
--- a/chrome/renderer/extensions/dispatcher.cc
+++ b/chrome/renderer/extensions/dispatcher.cc
@@ -1375,17 +1375,23 @@ void Dispatcher::AddOrRemoveBindings(const std::string& extension_id) {
base::Unretained(this)));
}
-void Dispatcher::OnUpdatePermissions(int reason_id,
- const std::string& extension_id,
- const APIPermissionSet& apis,
- const URLPatternSet& explicit_hosts,
- const URLPatternSet& scriptable_hosts) {
+void Dispatcher::OnUpdatePermissions(
+ const ExtensionMsg_UpdatePermissions_Params& params) {
+ int reason_id = params.reason_id;
+ const std::string& extension_id = params.extension_id;
+ const APIPermissionSet& apis = params.apis;
+ const ManifestPermissionSet& manifest_permissions =
+ params.manifest_permissions;
+ const URLPatternSet& explicit_hosts = params.explicit_hosts;
+ const URLPatternSet& scriptable_hosts = params.scriptable_hosts;
+
const Extension* extension = extensions_.GetByID(extension_id);
if (!extension)
return;
scoped_refptr<const PermissionSet> delta =
- new PermissionSet(apis, explicit_hosts, scriptable_hosts);
+ new PermissionSet(apis, manifest_permissions,
+ explicit_hosts, scriptable_hosts);
scoped_refptr<const PermissionSet> old_active =
extension->GetActivePermissions();
UpdatedExtensionPermissionsInfo::Reason reason =
@@ -1428,7 +1434,8 @@ void Dispatcher::OnUpdateTabSpecificPermissions(
PermissionsData::UpdateTabSpecificPermissions(
extension,
tab_id,
- new PermissionSet(APIPermissionSet(), origin_set, URLPatternSet()));
+ new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+ origin_set, URLPatternSet()));
}
void Dispatcher::OnClearTabSpecificPermissions(
diff --git a/chrome/renderer/extensions/dispatcher.h b/chrome/renderer/extensions/dispatcher.h
index 1501614..209f0e5 100644
--- a/chrome/renderer/extensions/dispatcher.h
+++ b/chrome/renderer/extensions/dispatcher.h
@@ -31,6 +31,7 @@ class ModuleSystem;
class URLPattern;
struct ExtensionMsg_ExternalConnectionInfo;
struct ExtensionMsg_Loaded_Params;
+struct ExtensionMsg_UpdatePermissions_Params;
namespace blink {
class WebFrame;
@@ -50,6 +51,7 @@ namespace extensions {
class ContentWatcher;
class Extension;
class FilteredEventRouter;
+class ManifestPermissionSet;
class RequestSender;
class UserScriptSlave;
struct Message;
@@ -179,11 +181,7 @@ class Dispatcher : public content::RenderProcessObserver {
void OnPageActionsUpdated(const std::string& extension_id,
const std::vector<std::string>& page_actions);
void OnActivateExtension(const std::string& extension_id);
- void OnUpdatePermissions(int reason_id,
- const std::string& extension_id,
- const APIPermissionSet& apis,
- const URLPatternSet& explicit_hosts,
- const URLPatternSet& scriptable_hosts);
+ void OnUpdatePermissions(const ExtensionMsg_UpdatePermissions_Params& params);
void OnUpdateTabSpecificPermissions(int page_id,
int tab_id,
const std::string& extension_id,
diff --git a/extensions/DEPS b/extensions/DEPS
index cd158fe..2b0dd51 100644
--- a/extensions/DEPS
+++ b/extensions/DEPS
@@ -14,4 +14,7 @@ specific_include_rules = {
"^api_permission_set_unittest\.cc$": [
"+chrome/common/extensions/extension_messages.h",
],
+ "^manifest_permission_set_unittest\.cc$": [
+ "+chrome/common/extensions/extension_messages.h",
+ ],
}
diff --git a/extensions/common/extensions_client.h b/extensions/common/extensions_client.h
index 594e75b..fb6aba8 100644
--- a/extensions/common/extensions_client.h
+++ b/extensions/common/extensions_client.h
@@ -16,6 +16,7 @@ namespace extensions {
class APIPermissionSet;
class Extension;
class FeatureProvider;
+class ManifestPermissionSet;
class PermissionMessage;
class PermissionMessageProvider;
class PermissionsProvider;
diff --git a/extensions/common/manifest_handler.cc b/extensions/common/manifest_handler.cc
index 43e6bd8..944389d 100644
--- a/extensions/common/manifest_handler.cc
+++ b/extensions/common/manifest_handler.cc
@@ -9,6 +9,8 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "chrome/common/extensions/extension.h"
+#include "extensions/common/permissions/manifest_permission.h"
+#include "extensions/common/permissions/manifest_permission_set.h"
namespace extensions {
@@ -57,6 +59,15 @@ void ManifestHandler::Register() {
GetRegistry()->RegisterManifestHandler(keys[i], this_linked);
}
+ManifestPermission* ManifestHandler::CreatePermission() {
+ return NULL;
+}
+
+ManifestPermission* ManifestHandler::CreateInitialRequiredPermission(
+ const Extension* extension) {
+ return NULL;
+}
+
// static
void ManifestHandler::FinalizeRegistration() {
GetRegistry()->Finalize();
@@ -80,6 +91,18 @@ bool ManifestHandler::ValidateExtension(const Extension* extension,
}
// static
+ManifestPermission* ManifestHandler::CreatePermission(const std::string& name) {
+ return GetRegistry()->CreatePermission(name);
+}
+
+// static
+void ManifestHandler::AddExtensionInitialRequiredPermissions(
+ const Extension* extension, ManifestPermissionSet* permission_set) {
+ return GetRegistry()->AddExtensionInitialRequiredPermissions(extension,
+ permission_set);
+}
+
+// static
const std::vector<std::string> ManifestHandler::SingleKey(
const std::string& key) {
return std::vector<std::string>(1, key);
@@ -144,6 +167,27 @@ bool ManifestHandlerRegistry::ValidateExtension(
return true;
}
+ManifestPermission* ManifestHandlerRegistry::CreatePermission(
+ const std::string& name) {
+ ManifestHandlerMap::const_iterator it = handlers_.find(name);
+ if (it == handlers_.end())
+ return NULL;
+
+ return it->second->CreatePermission();
+}
+
+void ManifestHandlerRegistry::AddExtensionInitialRequiredPermissions(
+ const Extension* extension, ManifestPermissionSet* permission_set) {
+ for (ManifestHandlerMap::const_iterator it = handlers_.begin();
+ it != handlers_.end(); ++it) {
+ ManifestPermission* permission =
+ it->second->CreateInitialRequiredPermission(extension);
+ if (permission) {
+ permission_set->insert(permission);
+ }
+ }
+}
+
// static
ManifestHandlerRegistry* ManifestHandlerRegistry::SetForTesting(
ManifestHandlerRegistry* new_registry) {
diff --git a/extensions/common/manifest_handler.h b/extensions/common/manifest_handler.h
index fd7b571..90fbe84 100644
--- a/extensions/common/manifest_handler.h
+++ b/extensions/common/manifest_handler.h
@@ -16,6 +16,8 @@
namespace extensions {
class Extension;
+class ManifestPermission;
+class ManifestPermissionSet;
// An interface for clients that recognize and parse keys in extension
// manifests.
@@ -64,6 +66,19 @@ class ManifestHandler {
// (new MyManifestHandler)->Register();
void Register();
+ // Creates a |ManifestPermission| instance for the given manifest key |name|.
+ // The returned permission does not contain any permission data, so this
+ // method is usually used before calling |FromValue| or |Read|. Returns
+ // |NULL| if the manifest handler does not support custom permissions.
+ virtual ManifestPermission* CreatePermission();
+
+ // Creates a |ManifestPermission| instance containing the initial set of
+ // required manifest permissions for the given |extension|. Returns |NULL| if
+ // the manifest handler does not support custom permissions or if there was
+ // no manifest key in the extension manifest for this handler.
+ virtual ManifestPermission* CreateInitialRequiredPermission(
+ const Extension* extension);
+
// Calling FinalizeRegistration indicates that there are no more
// manifest handlers to be registered.
static void FinalizeRegistration();
@@ -79,6 +94,20 @@ class ManifestHandler {
std::string* error,
std::vector<InstallWarning>* warnings);
+ // Calls |CreatePermission| on the manifest handler for |key|. Returns |NULL|
+ // if there is no manifest handler for |key| or if the manifest handler for
+ // |key| does not support custom permissions.
+ static ManifestPermission* CreatePermission(const std::string& key);
+
+ // Calls |CreateInitialRequiredPermission| on all registered manifest handlers
+ // and adds the returned permissions to |permission_set|. Note this should be
+ // called after all manifest data elements have been read, parsed and stored
+ // in the manifest data property of |extension|, as manifest handlers need
+ // access to their manifest data to initialize their required manifest
+ // permission.
+ static void AddExtensionInitialRequiredPermissions(
+ const Extension* extension, ManifestPermissionSet* permission_set);
+
protected:
// A convenience method for handlers that only register for 1 key,
// so that they can define keys() { return SingleKey(kKey); }
@@ -108,6 +137,12 @@ class ManifestHandlerRegistry {
std::string* error,
std::vector<InstallWarning>* warnings);
+ ManifestPermission* CreatePermission(const std::string& key);
+
+ void AddExtensionInitialRequiredPermissions(
+ const Extension* extension,
+ ManifestPermissionSet* permission_set);
+
// Overrides the current global ManifestHandlerRegistry with
// |registry|, returning the current one.
static ManifestHandlerRegistry* SetForTesting(
diff --git a/extensions/common/permissions/api_permission_set.cc b/extensions/common/permissions/api_permission_set.cc
index ebaf8d8..0ed7769 100644
--- a/extensions/common/permissions/api_permission_set.cc
+++ b/extensions/common/permissions/api_permission_set.cc
@@ -109,51 +109,6 @@ bool ParseChildPermissions(const std::string& base_name,
} // namespace
-APIPermissionSet::APIPermissionSet() {
-}
-
-APIPermissionSet::APIPermissionSet(const APIPermissionSet& set) {
- this->operator=(set);
-}
-
-APIPermissionSet::~APIPermissionSet() {
-}
-
-APIPermissionSet::const_iterator::const_iterator(
- const APIPermissionMap::const_iterator& it)
- : it_(it) {
-}
-
-APIPermissionSet::const_iterator::const_iterator(
- const const_iterator& ids_it)
- : it_(ids_it.it_) {
-}
-
-APIPermissionSet& APIPermissionSet::operator=(const APIPermissionSet& rhs) {
- const_iterator it = rhs.begin();
- const const_iterator end = rhs.end();
- while (it != end) {
- insert(it->Clone());
- ++it;
- }
- return *this;
-}
-
-bool APIPermissionSet::operator==(const APIPermissionSet& rhs) const {
- const_iterator it = begin();
- const_iterator rhs_it = rhs.begin();
- const_iterator it_end = end();
- const_iterator rhs_it_end = rhs.end();
-
- while (it != it_end && rhs_it != rhs_it_end) {
- if (!it->Equal(*rhs_it))
- return false;
- ++it;
- ++rhs_it;
- }
- return it == it_end && rhs_it == rhs_it_end;
-}
-
void APIPermissionSet::insert(APIPermission::ID id) {
const APIPermissionInfo* permission_info =
PermissionsInfo::GetInstance()->GetByID(id);
@@ -161,130 +116,7 @@ void APIPermissionSet::insert(APIPermission::ID id) {
}
void APIPermissionSet::insert(APIPermission* permission) {
- map_[permission->id()].reset(permission);
-}
-
-bool APIPermissionSet::Contains(const APIPermissionSet& rhs) const {
- APIPermissionSet::const_iterator it1 = begin();
- APIPermissionSet::const_iterator it2 = rhs.begin();
- APIPermissionSet::const_iterator end1 = end();
- APIPermissionSet::const_iterator end2 = rhs.end();
-
- while (it1 != end1 && it2 != end2) {
- if (it1->id() > it2->id()) {
- return false;
- } else if (it1->id() < it2->id()) {
- ++it1;
- } else {
- if (!it1->Contains(*it2))
- return false;
- ++it1;
- ++it2;
- }
- }
-
- return it2 == end2;
-}
-
-void APIPermissionSet::Difference(
- const APIPermissionSet& set1,
- const APIPermissionSet& set2,
- APIPermissionSet* set3) {
- CHECK(set3);
- set3->clear();
-
- APIPermissionSet::const_iterator it1 = set1.begin();
- APIPermissionSet::const_iterator it2 = set2.begin();
- const APIPermissionSet::const_iterator end1 = set1.end();
- const APIPermissionSet::const_iterator end2 = set2.end();
-
- while (it1 != end1 && it2 != end2) {
- if (it1->id() < it2->id()) {
- set3->insert(it1->Clone());
- ++it1;
- } else if (it1->id() > it2->id()) {
- ++it2;
- } else {
- APIPermission* p = it1->Diff(*it2);
- if (p)
- set3->insert(p);
- ++it1;
- ++it2;
- }
- }
-
- while (it1 != end1) {
- set3->insert(it1->Clone());
- ++it1;
- }
-}
-
-void APIPermissionSet::Intersection(
- const APIPermissionSet& set1,
- const APIPermissionSet& set2,
- APIPermissionSet* set3) {
- DCHECK(set3);
- set3->clear();
-
- APIPermissionSet::const_iterator it1 = set1.begin();
- APIPermissionSet::const_iterator it2 = set2.begin();
- const APIPermissionSet::const_iterator end1 = set1.end();
- const APIPermissionSet::const_iterator end2 = set2.end();
-
- while (it1 != end1 && it2 != end2) {
- if (it1->id() < it2->id()) {
- ++it1;
- } else if (it1->id() > it2->id()) {
- ++it2;
- } else {
- APIPermission* p = it1->Intersect(*it2);
- if (p)
- set3->insert(p);
- ++it1;
- ++it2;
- }
- }
-}
-
-void APIPermissionSet::Union(
- const APIPermissionSet& set1,
- const APIPermissionSet& set2,
- APIPermissionSet* set3) {
- DCHECK(set3);
- set3->clear();
-
- APIPermissionSet::const_iterator it1 = set1.begin();
- APIPermissionSet::const_iterator it2 = set2.begin();
- const APIPermissionSet::const_iterator end1 = set1.end();
- const APIPermissionSet::const_iterator end2 = set2.end();
-
- while (true) {
- if (it1 == end1) {
- while (it2 != end2) {
- set3->insert(it2->Clone());
- ++it2;
- }
- break;
- }
- if (it2 == end2) {
- while (it1 != end1) {
- set3->insert(it1->Clone());
- ++it1;
- }
- break;
- }
- if (it1->id() < it2->id()) {
- set3->insert(it1->Clone());
- ++it1;
- } else if (it1->id() > it2->id()) {
- set3->insert(it2->Clone());
- ++it2;
- } else {
- set3->insert(it1->Union(*it2));
- ++it1;
- ++it2;
- }
- }
+ BaseSetOperators<APIPermissionSet>::insert(permission);
}
// static
@@ -334,8 +166,8 @@ void APIPermissionSet::AddImpliedPermissions() {
// The fileSystem.write and fileSystem.directory permissions imply
// fileSystem.writeDirectory.
// TODO(sammc): Remove this. See http://crbug.com/284849.
- if (ContainsKey(map_, APIPermission::kFileSystemWrite) &&
- ContainsKey(map_, APIPermission::kFileSystemDirectory)) {
+ if (ContainsKey(map(), APIPermission::kFileSystemWrite) &&
+ ContainsKey(map(), APIPermission::kFileSystemDirectory)) {
insert(APIPermission::kFileSystemWriteDirectory);
}
}
diff --git a/extensions/common/permissions/api_permission_set.h b/extensions/common/permissions/api_permission_set.h
index 9b6f26d..c5dd248 100644
--- a/extensions/common/permissions/api_permission_set.h
+++ b/extensions/common/permissions/api_permission_set.h
@@ -5,11 +5,9 @@
#ifndef EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_SET_H_
#define EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_SET_H_
-#include <iterator>
-#include <map>
-#include "base/memory/linked_ptr.h"
#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/base_set_operators.h"
namespace base {
class ListValue;
@@ -18,48 +16,16 @@ class ListValue;
namespace extensions {
class Extension;
+class APIPermissionSet;
-typedef std::map<APIPermission::ID,
- linked_ptr<APIPermission> > APIPermissionMap;
+template<>
+struct BaseSetOperatorsTraits<APIPermissionSet> {
+ typedef APIPermission ElementType;
+ typedef APIPermission::ID ElementIDType;
+};
-class APIPermissionSet {
+class APIPermissionSet : public BaseSetOperators<APIPermissionSet> {
public:
- class const_iterator :
- public std::iterator<std::input_iterator_tag, const APIPermission*> {
- public:
- const_iterator(const APIPermissionMap::const_iterator& it);
- const_iterator(const const_iterator& ids_it);
-
- const_iterator& operator++() {
- ++it_;
- return *this;
- }
-
- const_iterator operator++(int) {
- const_iterator tmp(it_++);
- return tmp;
- }
-
- bool operator==(const const_iterator& rhs) const {
- return it_ == rhs.it_;
- }
-
- bool operator!=(const const_iterator& rhs) const {
- return it_ != rhs.it_;
- }
-
- const APIPermission* operator*() const {
- return it_->second.get();
- }
-
- const APIPermission* operator->() const {
- return it_->second.get();
- }
-
- private:
- APIPermissionMap::const_iterator it_;
- };
-
enum ParseSource {
// Don't allow internal permissions to be parsed (e.g. entries in the
// "permissions" list in a manifest).
@@ -70,87 +36,16 @@ class APIPermissionSet {
kAllowInternalPermissions,
};
- APIPermissionSet();
-
- APIPermissionSet(const APIPermissionSet& set);
-
- ~APIPermissionSet();
-
- const_iterator begin() const {
- return const_iterator(map().begin());
- }
-
- const_iterator end() const {
- return map().end();
- }
-
- const_iterator find(APIPermission::ID id) const {
- return map().find(id);
- }
-
- const APIPermissionMap& map() const {
- return map_;
- }
-
- APIPermissionMap& map() {
- return map_;
- }
-
- void clear() {
- map_.clear();
- }
-
- size_t count(APIPermission::ID id) const {
- return map().count(id);
- }
-
- bool empty() const {
- return map().empty();
- }
-
- size_t erase(APIPermission::ID id) {
- return map().erase(id);
- }
-
- size_t size() const {
- return map().size();
- }
-
- APIPermissionSet& operator=(const APIPermissionSet& rhs);
-
- bool operator==(const APIPermissionSet& rhs) const;
-
- bool operator!=(const APIPermissionSet& rhs) const {
- return !operator==(rhs);
- }
-
void insert(APIPermission::ID id);
// Insert |permission| into the APIPermissionSet. The APIPermissionSet will
// take the ownership of |permission|,
void insert(APIPermission* permission);
- bool Contains(const APIPermissionSet& rhs) const;
-
- static void Difference(
- const APIPermissionSet& set1,
- const APIPermissionSet& set2,
- APIPermissionSet* set3);
-
- static void Intersection(
- const APIPermissionSet& set1,
- const APIPermissionSet& set2,
- APIPermissionSet* set3);
-
- static void Union(
- const APIPermissionSet& set1,
- const APIPermissionSet& set2,
- APIPermissionSet* set3);
-
// Parses permissions from |permissions| and adds the parsed permissions to
// |api_permissions|. If |source| is kDisallowInternalPermissions, treat
- // permissions with kFlagInternal as errors. If |unhandled_permissions|
- // is not NULL, the names of all permissions that couldn't be parsed will be
+ // permissions with kFlagInternal as errors. If |unhandled_permissions| is
+ // not NULL, the names of all permissions that couldn't be parsed will be
// added to this vector. If |error| is NULL, parsing will continue with the
// next permission if invalid data is detected. If |error| is not NULL, it
// will be set to an error message and false is returned when an invalid
@@ -163,9 +58,6 @@ class APIPermissionSet {
std::vector<std::string>* unhandled_permissions);
void AddImpliedPermissions();
-
- private:
- APIPermissionMap map_;
};
} // namespace extensions
diff --git a/extensions/common/permissions/base_set_operators.h b/extensions/common/permissions/base_set_operators.h
new file mode 100644
index 0000000..38ff091
--- /dev/null
+++ b/extensions/common/permissions/base_set_operators.h
@@ -0,0 +1,288 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_
+
+#include <iterator>
+#include <map>
+
+#include "base/memory/linked_ptr.h"
+#include "base/template_util.h"
+
+namespace extensions {
+
+// Traits for template paramater of |BaseSetOperators<T>|. Specializations
+// should define |ElementType| for the type of elements to store in the set,
+// and |EmementIDType| for the type of element identifiers.
+template <typename T>
+struct BaseSetOperatorsTraits {};
+
+// Set operations shared by |APIPermissionSet| and |ManifestPermissionSet|.
+//
+// TODO(rpaquay): It would be nice to remove the need for the sub-classes and
+// instead directly use this class where needed.
+template <typename T>
+class BaseSetOperators {
+ public:
+ typedef typename BaseSetOperatorsTraits<T>::ElementType ElementType;
+ typedef typename BaseSetOperatorsTraits<T>::ElementIDType ElementIDType;
+ typedef std::map<ElementIDType, linked_ptr<ElementType> > Map;
+
+ class const_iterator :
+ public std::iterator<std::input_iterator_tag, const ElementType*> {
+ public:
+ const_iterator(const typename Map::const_iterator& it) : it_(it) {}
+ const_iterator(const const_iterator& ids_it) : it_(ids_it.it_) {}
+
+ const_iterator& operator++() {
+ ++it_;
+ return *this;
+ }
+
+ const_iterator operator++(int) {
+ const_iterator tmp(it_++);
+ return tmp;
+ }
+
+ bool operator==(const const_iterator& rhs) const {
+ return it_ == rhs.it_;
+ }
+
+ bool operator!=(const const_iterator& rhs) const {
+ return it_ != rhs.it_;
+ }
+
+ const ElementType* operator*() const {
+ return it_->second.get();
+ }
+
+ const ElementType* operator->() const {
+ return it_->second.get();
+ }
+
+ private:
+ typename Map::const_iterator it_;
+ };
+
+ BaseSetOperators() {
+ // Ensure |T| is convertible to us, so we can safely downcast when calling
+ // methods that must exist in |T|.
+ COMPILE_ASSERT((base::is_convertible<T*, BaseSetOperators<T>*>::value),
+ U_ptr_must_implicitly_convert_to_T_ptr);
+ }
+
+ BaseSetOperators(const T& set) {
+ this->operator=(set);
+ }
+
+ ~BaseSetOperators() {}
+
+ T& operator=(const T& rhs) {
+ return Assign(rhs);
+ }
+
+ bool operator==(const T& rhs) const {
+ return Equal(rhs);
+ }
+
+ bool operator!=(const T& rhs) const {
+ return !operator==(rhs);
+ }
+
+ T& Assign(const T& rhs) {
+ const_iterator it = rhs.begin();
+ const const_iterator end = rhs.end();
+ while (it != end) {
+ insert(it->Clone());
+ ++it;
+ }
+ return *static_cast<T*>(this);
+ }
+
+ bool Equal(const T& rhs) const {
+ const_iterator it = begin();
+ const_iterator rhs_it = rhs.begin();
+ const_iterator it_end = end();
+ const_iterator rhs_it_end = rhs.end();
+
+ while (it != it_end && rhs_it != rhs_it_end) {
+ if (it->id() > rhs_it->id())
+ return false;
+ else if (it->id() < rhs_it->id())
+ return false;
+ else if (!it->Equal(*rhs_it))
+ return false;
+ ++it;
+ ++rhs_it;
+ }
+ return it == it_end && rhs_it == rhs_it_end;
+ }
+
+ bool Contains(const T& rhs) const {
+ const_iterator it1 = begin();
+ const_iterator it2 = rhs.begin();
+ const_iterator end1 = end();
+ const_iterator end2 = rhs.end();
+
+ while (it1 != end1 && it2 != end2) {
+ if (it1->id() > it2->id()) {
+ return false;
+ } else if (it1->id() < it2->id()) {
+ ++it1;
+ } else {
+ if (!it1->Contains(*it2))
+ return false;
+ ++it1;
+ ++it2;
+ }
+ }
+
+ return it2 == end2;
+ }
+
+ static void Difference(const T& set1, const T& set2, T* set3) {
+ CHECK(set3);
+ set3->clear();
+
+ const_iterator it1 = set1.begin();
+ const_iterator it2 = set2.begin();
+ const const_iterator end1 = set1.end();
+ const const_iterator end2 = set2.end();
+
+ while (it1 != end1 && it2 != end2) {
+ if (it1->id() < it2->id()) {
+ set3->insert(it1->Clone());
+ ++it1;
+ } else if (it1->id() > it2->id()) {
+ ++it2;
+ } else {
+ ElementType* p = it1->Diff(*it2);
+ if (p)
+ set3->insert(p);
+ ++it1;
+ ++it2;
+ }
+ }
+
+ while (it1 != end1) {
+ set3->insert(it1->Clone());
+ ++it1;
+ }
+ }
+
+ static void Intersection(const T& set1, const T& set2, T* set3) {
+ DCHECK(set3);
+ set3->clear();
+
+ const_iterator it1 = set1.begin();
+ const_iterator it2 = set2.begin();
+ const const_iterator end1 = set1.end();
+ const const_iterator end2 = set2.end();
+
+ while (it1 != end1 && it2 != end2) {
+ if (it1->id() < it2->id()) {
+ ++it1;
+ } else if (it1->id() > it2->id()) {
+ ++it2;
+ } else {
+ ElementType* p = it1->Intersect(*it2);
+ if (p)
+ set3->insert(p);
+ ++it1;
+ ++it2;
+ }
+ }
+ }
+
+ static void Union(const T& set1, const T& set2, T* set3) {
+ DCHECK(set3);
+ set3->clear();
+
+ const_iterator it1 = set1.begin();
+ const_iterator it2 = set2.begin();
+ const const_iterator end1 = set1.end();
+ const const_iterator end2 = set2.end();
+
+ while (true) {
+ if (it1 == end1) {
+ while (it2 != end2) {
+ set3->insert(it2->Clone());
+ ++it2;
+ }
+ break;
+ }
+ if (it2 == end2) {
+ while (it1 != end1) {
+ set3->insert(it1->Clone());
+ ++it1;
+ }
+ break;
+ }
+ if (it1->id() < it2->id()) {
+ set3->insert(it1->Clone());
+ ++it1;
+ } else if (it1->id() > it2->id()) {
+ set3->insert(it2->Clone());
+ ++it2;
+ } else {
+ set3->insert(it1->Union(*it2));
+ ++it1;
+ ++it2;
+ }
+ }
+ }
+
+ const_iterator begin() const {
+ return const_iterator(map().begin());
+ }
+
+ const_iterator end() const {
+ return map().end();
+ }
+
+ const_iterator find(ElementIDType id) const {
+ return map().find(id);
+ }
+
+ size_t count(ElementIDType id) const {
+ return map().count(id);
+ }
+
+ bool empty() const {
+ return map().empty();
+ }
+
+ size_t erase(ElementIDType id) {
+ return map().erase(id);
+ }
+
+ // Take ownership and insert |item| into the set.
+ void insert(ElementType* item) {
+ map_[item->id()].reset(item);
+ }
+
+ size_t size() const {
+ return map().size();
+ }
+
+ const Map& map() const {
+ return map_;
+ }
+
+ Map& map() {
+ return map_;
+ }
+
+ void clear() {
+ map_.clear();
+ }
+
+ private:
+ Map map_;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_
diff --git a/extensions/common/permissions/manifest_permission.cc b/extensions/common/permissions/manifest_permission.cc
new file mode 100644
index 0000000..b15c541
--- /dev/null
+++ b/extensions/common/permissions/manifest_permission.cc
@@ -0,0 +1,13 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/permissions/manifest_permission.h"
+
+namespace extensions {
+
+ManifestPermission::ManifestPermission() {}
+
+ManifestPermission::~ManifestPermission() { }
+
+} // namespace extensions
diff --git a/extensions/common/permissions/manifest_permission.h b/extensions/common/permissions/manifest_permission.h
new file mode 100644
index 0000000..af9e035
--- /dev/null
+++ b/extensions/common/permissions/manifest_permission.h
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_COMMON_PERMISSIONS_MANIFEST_PERMISSION_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_MANIFEST_PERMISSION_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "extensions/common/permissions/permission_message.h"
+
+class PickleIterator;
+
+namespace base {
+class Value;
+class ListValue;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace extensions {
+
+// Represent the custom behavior of a top-level manifest entry contributing to
+// permission messages and storage.
+class ManifestPermission {
+ public:
+ ManifestPermission();
+ virtual ~ManifestPermission();
+
+ // The manifest key this permission applies to.
+ virtual std::string name() const = 0;
+
+ // Same as name(), needed for compatibility with APIPermission.
+ virtual std::string id() const = 0;
+
+ // Returns true if this permission has any PermissionMessages.
+ virtual bool HasMessages() const = 0;
+
+ // Returns the localized permission messages of this permission.
+ virtual PermissionMessages GetMessages() const = 0;
+
+ // Parses the ManifestPermission from |value|. Returns false if error happens.
+ virtual bool FromValue(const base::Value* value) = 0;
+
+ // Stores this into a new created Value.
+ virtual scoped_ptr<base::Value> ToValue() const = 0;
+
+ // Clones this.
+ virtual ManifestPermission* Clone() const = 0;
+
+ // Returns a new manifest permission which equals this - |rhs|.
+ virtual ManifestPermission* Diff(const ManifestPermission* rhs) const = 0;
+
+ // Returns a new manifest permission which equals the union of this and |rhs|.
+ virtual ManifestPermission* Union(const ManifestPermission* rhs) const = 0;
+
+ // Returns a new manifest permission which equals the intersect of this and
+ // |rhs|.
+ virtual ManifestPermission* Intersect(const ManifestPermission* rhs)
+ const = 0;
+
+ // Returns true if |rhs| is a subset of this.
+ virtual bool Contains(const ManifestPermission* rhs) const = 0;
+
+ // Returns true if |rhs| is equal to this.
+ virtual bool Equal(const ManifestPermission* rhs) const = 0;
+
+ // IPC functions
+ // Writes this into the given IPC message |m|.
+ virtual void Write(IPC::Message* m) const = 0;
+
+ // Reads from the given IPC message |m|.
+ virtual bool Read(const IPC::Message* m, PickleIterator* iter) = 0;
+
+ // Logs this permission.
+ virtual void Log(std::string* log) const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ManifestPermission);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_PERMISSIONS_MANIFEST_PERMISSION_H_
diff --git a/extensions/common/permissions/manifest_permission_set.cc b/extensions/common/permissions/manifest_permission_set.cc
new file mode 100644
index 0000000..821159f
--- /dev/null
+++ b/extensions/common/permissions/manifest_permission_set.cc
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/permissions/manifest_permission_set.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handler.h"
+#include "extensions/common/permissions/manifest_permission.h"
+
+namespace {
+
+using extensions::ErrorUtils;
+using extensions::ManifestPermission;
+using extensions::ManifestPermissionSet;
+using extensions::ManifestHandler;
+namespace errors = extensions::manifest_errors;
+
+bool CreateManifestPermission(
+ const std::string& permission_name,
+ const base::Value* permission_value,
+ ManifestPermissionSet* manifest_permissions,
+ string16* error,
+ std::vector<std::string>* unhandled_permissions) {
+
+ scoped_ptr<ManifestPermission> permission(
+ ManifestHandler::CreatePermission(permission_name));
+
+ if (!permission) {
+ if (unhandled_permissions)
+ unhandled_permissions->push_back(permission_name);
+ else
+ LOG(WARNING) << "Unknown permission[" << permission_name << "].";
+ return true;
+ }
+
+ if (!permission->FromValue(permission_value)) {
+ if (error) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPermission, permission_name);
+ return false;
+ }
+ LOG(WARNING) << "Parse permission failed.";
+ return true;
+ } else {
+ manifest_permissions->insert(permission.release());
+ return true;
+ }
+}
+
+} // namespace
+
+namespace extensions {
+
+// static
+bool ManifestPermissionSet::ParseFromJSON(
+ const base::ListValue* permissions,
+ ManifestPermissionSet* manifest_permissions,
+ string16* error,
+ std::vector<std::string>* unhandled_permissions) {
+ for (size_t i = 0; i < permissions->GetSize(); ++i) {
+ std::string permission_name;
+ const base::Value* permission_value = NULL;
+ if (!permissions->GetString(i, &permission_name)) {
+ const base::DictionaryValue* dict = NULL;
+ // permission should be a string or a single key dict.
+ if (!permissions->GetDictionary(i, &dict) || dict->size() != 1) {
+ if (error) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidPermission, base::IntToString(i));
+ return false;
+ }
+ LOG(WARNING) << "Permission is not a string or single key dict.";
+ continue;
+ }
+ base::DictionaryValue::Iterator it(*dict);
+ permission_name = it.key();
+ permission_value = &it.value();
+ }
+
+ if (!CreateManifestPermission(permission_name, permission_value,
+ manifest_permissions, error,
+ unhandled_permissions))
+ return false;
+ }
+ return true;
+}
+
+} // namespace extensions
diff --git a/extensions/common/permissions/manifest_permission_set.h b/extensions/common/permissions/manifest_permission_set.h
new file mode 100644
index 0000000..e9683bc
--- /dev/null
+++ b/extensions/common/permissions/manifest_permission_set.h
@@ -0,0 +1,47 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_COMMON_PERMISSIONS_MANIFEST_PERMISSION_SET_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_MANIFEST_PERMISSION_SET_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "extensions/common/permissions/base_set_operators.h"
+
+namespace base {
+class ListValue;
+} // namespace base
+
+namespace extensions {
+
+class Extension;
+class ManifestPermission;
+class ManifestPermissionSet;
+
+template<>
+struct BaseSetOperatorsTraits<ManifestPermissionSet> {
+ typedef ManifestPermission ElementType;
+ typedef std::string ElementIDType;
+};
+
+class ManifestPermissionSet : public BaseSetOperators<ManifestPermissionSet> {
+ public:
+ // Parses permissions from |permissions| and adds the parsed permissions to
+ // |manifest_permissions|. If |unhandled_permissions| is not NULL, the names
+ // of all permissions that couldn't be parsed will be added to this vector.
+ // If |error| is NULL, parsing will continue with the next permission if
+ // invalid data is detected. If |error| is not NULL, it will be set to an
+ // error message and false is returned when an invalid permission is found.
+ static bool ParseFromJSON(
+ const base::ListValue* permissions,
+ ManifestPermissionSet* manifest_permissions,
+ string16* error,
+ std::vector<std::string>* unhandled_permissions);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_PERMISSIONS_MANIFEST_PERMISSION_SET_H_
diff --git a/extensions/common/permissions/manifest_permission_set_unittest.cc b/extensions/common/permissions/manifest_permission_set_unittest.cc
new file mode 100644
index 0000000..a0191c3
--- /dev/null
+++ b/extensions/common/permissions/manifest_permission_set_unittest.cc
@@ -0,0 +1,272 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/pickle.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "extensions/common/permissions/manifest_permission.h"
+#include "extensions/common/permissions/manifest_permission_set.h"
+#include "ipc/ipc_message.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class MockManifestPermission : public ManifestPermission {
+ public:
+ MockManifestPermission(const std::string& name)
+ : name_(name) {
+ }
+
+ virtual std::string name() const OVERRIDE {
+ return name_;
+ }
+
+ virtual std::string id() const OVERRIDE {
+ return name();
+ }
+
+ virtual bool HasMessages() const OVERRIDE {
+ return false;
+ }
+
+ virtual PermissionMessages GetMessages() const OVERRIDE {
+ return PermissionMessages();
+ }
+
+ virtual bool FromValue(const base::Value* value) OVERRIDE {
+ return false;
+ }
+
+ virtual scoped_ptr<base::Value> ToValue() const OVERRIDE {
+ return scoped_ptr<base::Value>(base::Value::CreateNullValue());
+ }
+
+ virtual ManifestPermission* Clone() const OVERRIDE {
+ return new MockManifestPermission(name_);
+ }
+
+ virtual ManifestPermission* Diff(const ManifestPermission* rhs)
+ const OVERRIDE {
+ const MockManifestPermission* other =
+ static_cast<const MockManifestPermission*>(rhs);
+ EXPECT_EQ(name_, other->name_);
+ return NULL;
+ }
+
+ virtual ManifestPermission* Union(const ManifestPermission* rhs)
+ const OVERRIDE {
+ const MockManifestPermission* other =
+ static_cast<const MockManifestPermission*>(rhs);
+ EXPECT_EQ(name_, other->name_);
+ return new MockManifestPermission(name_);
+ }
+
+ virtual ManifestPermission* Intersect(const ManifestPermission* rhs)
+ const OVERRIDE {
+ const MockManifestPermission* other =
+ static_cast<const MockManifestPermission*>(rhs);
+ EXPECT_EQ(name_, other->name_);
+ return new MockManifestPermission(name_);
+ }
+
+ virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE {
+ const MockManifestPermission* other =
+ static_cast<const MockManifestPermission*>(rhs);
+ EXPECT_EQ(name_, other->name_);
+ return true;
+ }
+
+ virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE {
+ const MockManifestPermission* other =
+ static_cast<const MockManifestPermission*>(rhs);
+ EXPECT_EQ(name_, other->name_);
+ return true;
+ }
+
+ virtual void Write(IPC::Message* m) const OVERRIDE {
+ IPC::WriteParam(m, name_);
+ }
+
+ virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE {
+ std::string read_name;
+ bool result = IPC::ReadParam(m, iter, &read_name);
+ if (!result)
+ return result;
+ EXPECT_EQ(read_name, name_);
+ return true;
+ }
+
+ virtual void Log(std::string* log) const OVERRIDE {
+ }
+
+ private:
+ std::string name_;
+};
+
+TEST(ManifestPermissionSetTest, General) {
+ ManifestPermissionSet set;
+ set.insert(new MockManifestPermission("p1"));
+ set.insert(new MockManifestPermission("p2"));
+ set.insert(new MockManifestPermission("p3"));
+ set.insert(new MockManifestPermission("p4"));
+ set.insert(new MockManifestPermission("p5"));
+
+ EXPECT_EQ(set.find("p1")->id(), "p1");
+ EXPECT_TRUE(set.find("p10") == set.end());
+
+ EXPECT_EQ(set.size(), 5u);
+
+ EXPECT_EQ(set.erase("p1"), 1u);
+ EXPECT_EQ(set.size(), 4u);
+
+ EXPECT_EQ(set.erase("p1"), 0u);
+ EXPECT_EQ(set.size(), 4u);
+}
+
+TEST(ManifestPermissionSetTest, CreateUnion) {
+ ManifestPermissionSet permissions1;
+ ManifestPermissionSet permissions2;
+ ManifestPermissionSet expected_permissions;
+ ManifestPermissionSet result;
+
+ ManifestPermission* permission = new MockManifestPermission("p3");
+
+ // Union with an empty set.
+ permissions1.insert(new MockManifestPermission("p1"));
+ permissions1.insert(new MockManifestPermission("p2"));
+ permissions1.insert(permission->Clone());
+ expected_permissions.insert(new MockManifestPermission("p1"));
+ expected_permissions.insert(new MockManifestPermission("p2"));
+ expected_permissions.insert(permission);
+
+ ManifestPermissionSet::Union(permissions1, permissions2, &result);
+
+ EXPECT_TRUE(permissions1.Contains(permissions2));
+ EXPECT_TRUE(permissions1.Contains(result));
+ EXPECT_FALSE(permissions2.Contains(permissions1));
+ EXPECT_FALSE(permissions2.Contains(result));
+ EXPECT_TRUE(result.Contains(permissions1));
+ EXPECT_TRUE(result.Contains(permissions2));
+
+ EXPECT_EQ(expected_permissions, result);
+
+ // Now use a real second set.
+ permissions2.insert(new MockManifestPermission("p1"));
+ permissions2.insert(new MockManifestPermission("p2"));
+ permissions2.insert(new MockManifestPermission("p33"));
+ permissions2.insert(new MockManifestPermission("p4"));
+ permissions2.insert(new MockManifestPermission("p5"));
+
+ expected_permissions.insert(new MockManifestPermission("p1"));
+ expected_permissions.insert(new MockManifestPermission("p2"));
+ expected_permissions.insert(new MockManifestPermission("p3"));
+ expected_permissions.insert(new MockManifestPermission("p4"));
+ expected_permissions.insert(new MockManifestPermission("p5"));
+ expected_permissions.insert(new MockManifestPermission("p33"));
+
+ ManifestPermissionSet::Union(permissions1, permissions2, &result);
+
+ {
+ ManifestPermissionSet set1;
+ set1.insert(new MockManifestPermission("p1"));
+ set1.insert(new MockManifestPermission("p2"));
+ ManifestPermissionSet set2;
+ set2.insert(new MockManifestPermission("p3"));
+
+ EXPECT_FALSE(set1.Contains(set2));
+ EXPECT_FALSE(set2.Contains(set1));
+ }
+
+ EXPECT_FALSE(permissions1.Contains(permissions2));
+ EXPECT_FALSE(permissions1.Contains(result));
+ EXPECT_FALSE(permissions2.Contains(permissions1));
+ EXPECT_FALSE(permissions2.Contains(result));
+ EXPECT_TRUE(result.Contains(permissions1));
+ EXPECT_TRUE(result.Contains(permissions2));
+
+ EXPECT_EQ(expected_permissions, result);
+}
+
+TEST(ManifestPermissionSetTest, CreateIntersection) {
+ ManifestPermissionSet permissions1;
+ ManifestPermissionSet permissions2;
+ ManifestPermissionSet expected_permissions;
+ ManifestPermissionSet result;
+
+ // Intersection with an empty set.
+ permissions1.insert(new MockManifestPermission("p1"));
+ permissions1.insert(new MockManifestPermission("p2"));
+ permissions1.insert(new MockManifestPermission("p3"));
+
+ ManifestPermissionSet::Intersection(permissions1, permissions2, &result);
+ EXPECT_TRUE(permissions1.Contains(result));
+ EXPECT_TRUE(permissions2.Contains(result));
+ EXPECT_TRUE(permissions1.Contains(permissions2));
+ EXPECT_FALSE(permissions2.Contains(permissions1));
+ EXPECT_FALSE(result.Contains(permissions1));
+ EXPECT_TRUE(result.Contains(permissions2));
+
+ EXPECT_TRUE(result.empty());
+ EXPECT_EQ(expected_permissions, result);
+
+ // Now use a real second set.
+ permissions2.insert(new MockManifestPermission("p1"));
+ permissions2.insert(new MockManifestPermission("p3"));
+ permissions2.insert(new MockManifestPermission("p4"));
+ permissions2.insert(new MockManifestPermission("p5"));
+
+ expected_permissions.insert(new MockManifestPermission("p1"));
+ expected_permissions.insert(new MockManifestPermission("p3"));
+
+ ManifestPermissionSet::Intersection(permissions1, permissions2, &result);
+
+ EXPECT_TRUE(permissions1.Contains(result));
+ EXPECT_TRUE(permissions2.Contains(result));
+ EXPECT_FALSE(permissions1.Contains(permissions2));
+ EXPECT_FALSE(permissions2.Contains(permissions1));
+ EXPECT_FALSE(result.Contains(permissions1));
+ EXPECT_FALSE(result.Contains(permissions2));
+
+ EXPECT_EQ(expected_permissions, result);
+}
+
+TEST(ManifestPermissionSetTest, CreateDifference) {
+ ManifestPermissionSet permissions1;
+ ManifestPermissionSet permissions2;
+ ManifestPermissionSet expected_permissions;
+ ManifestPermissionSet result;
+
+ // Difference with an empty set.
+ permissions1.insert(new MockManifestPermission("p1"));
+ permissions1.insert(new MockManifestPermission("p2"));
+ permissions1.insert(new MockManifestPermission("p3"));
+
+ ManifestPermissionSet::Difference(permissions1, permissions2, &result);
+
+ EXPECT_EQ(permissions1, result);
+
+ // Now use a real second set.
+ permissions2.insert(new MockManifestPermission("p1"));
+ permissions2.insert(new MockManifestPermission("p2"));
+ permissions2.insert(new MockManifestPermission("p4"));
+ permissions2.insert(new MockManifestPermission("p5"));
+ permissions2.insert(new MockManifestPermission("p6"));
+
+ expected_permissions.insert(new MockManifestPermission("p3"));
+
+ ManifestPermissionSet::Difference(permissions1, permissions2, &result);
+
+ EXPECT_TRUE(permissions1.Contains(result));
+ EXPECT_FALSE(permissions2.Contains(result));
+
+ EXPECT_EQ(expected_permissions, result);
+
+ // |result| = |permissions1| - |permissions2| -->
+ // |result| intersect |permissions2| == empty_set
+ ManifestPermissionSet result2;
+ ManifestPermissionSet::Intersection(result, permissions2, &result2);
+ EXPECT_TRUE(result2.empty());
+}
+
+} // namespace extensions
diff --git a/extensions/common/permissions/permission_set.cc b/extensions/common/permissions/permission_set.cc
index d3f46fc..8ec1cbe 100644
--- a/extensions/common/permissions/permission_set.cc
+++ b/extensions/common/permissions/permission_set.cc
@@ -38,9 +38,11 @@ PermissionSet::PermissionSet() {}
PermissionSet::PermissionSet(
const APIPermissionSet& apis,
+ const ManifestPermissionSet& manifest_permissions,
const URLPatternSet& explicit_hosts,
const URLPatternSet& scriptable_hosts)
: apis_(apis),
+ manifest_permissions_(manifest_permissions),
scriptable_hosts_(scriptable_hosts) {
AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
InitImplicitPermissions();
@@ -58,6 +60,11 @@ PermissionSet* PermissionSet::CreateDifference(
APIPermissionSet apis;
APIPermissionSet::Difference(set1_safe->apis(), set2_safe->apis(), &apis);
+ ManifestPermissionSet manifest_permissions;
+ ManifestPermissionSet::Difference(set1_safe->manifest_permissions(),
+ set2_safe->manifest_permissions(),
+ &manifest_permissions);
+
URLPatternSet explicit_hosts;
URLPatternSet::CreateDifference(set1_safe->explicit_hosts(),
set2_safe->explicit_hosts(),
@@ -68,7 +75,8 @@ PermissionSet* PermissionSet::CreateDifference(
set2_safe->scriptable_hosts(),
&scriptable_hosts);
- return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
+ return new PermissionSet(apis, manifest_permissions,
+ explicit_hosts, scriptable_hosts);
}
// static
@@ -82,6 +90,11 @@ PermissionSet* PermissionSet::CreateIntersection(
APIPermissionSet apis;
APIPermissionSet::Intersection(set1_safe->apis(), set2_safe->apis(), &apis);
+ ManifestPermissionSet manifest_permissions;
+ ManifestPermissionSet::Intersection(set1_safe->manifest_permissions(),
+ set2_safe->manifest_permissions(),
+ &manifest_permissions);
+
URLPatternSet explicit_hosts;
URLPatternSet::CreateIntersection(set1_safe->explicit_hosts(),
set2_safe->explicit_hosts(),
@@ -92,7 +105,8 @@ PermissionSet* PermissionSet::CreateIntersection(
set2_safe->scriptable_hosts(),
&scriptable_hosts);
- return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
+ return new PermissionSet(apis, manifest_permissions,
+ explicit_hosts, scriptable_hosts);
}
// static
@@ -106,6 +120,11 @@ PermissionSet* PermissionSet::CreateUnion(
APIPermissionSet apis;
APIPermissionSet::Union(set1_safe->apis(), set2_safe->apis(), &apis);
+ ManifestPermissionSet manifest_permissions;
+ ManifestPermissionSet::Union(set1_safe->manifest_permissions(),
+ set2_safe->manifest_permissions(),
+ &manifest_permissions);
+
URLPatternSet explicit_hosts;
URLPatternSet::CreateUnion(set1_safe->explicit_hosts(),
set2_safe->explicit_hosts(),
@@ -116,18 +135,21 @@ PermissionSet* PermissionSet::CreateUnion(
set2_safe->scriptable_hosts(),
&scriptable_hosts);
- return new PermissionSet(apis, explicit_hosts, scriptable_hosts);
+ return new PermissionSet(apis, manifest_permissions,
+ explicit_hosts, scriptable_hosts);
}
bool PermissionSet::operator==(
const PermissionSet& rhs) const {
return apis_ == rhs.apis_ &&
+ manifest_permissions_ == rhs.manifest_permissions_ &&
scriptable_hosts_ == rhs.scriptable_hosts_ &&
explicit_hosts_ == rhs.explicit_hosts_;
}
bool PermissionSet::Contains(const PermissionSet& set) const {
return apis_.Contains(set.apis()) &&
+ manifest_permissions_.Contains(set.manifest_permissions()) &&
explicit_hosts().Contains(set.explicit_hosts()) &&
scriptable_hosts().Contains(set.scriptable_hosts());
}
@@ -147,7 +169,7 @@ bool PermissionSet::IsEmpty() const {
return false;
// Or if it has no api permissions.
- return apis().empty();
+ return apis().empty() && manifest_permissions().empty();
}
bool PermissionSet::HasAPIPermission(
diff --git a/extensions/common/permissions/permission_set.h b/extensions/common/permissions/permission_set.h
index a0e4b34..9e6a7b9 100644
--- a/extensions/common/permissions/permission_set.h
+++ b/extensions/common/permissions/permission_set.h
@@ -17,6 +17,8 @@
#include "extensions/common/manifest.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/manifest_permission.h"
+#include "extensions/common/permissions/manifest_permission_set.h"
#include "extensions/common/url_pattern_set.h"
namespace extensions {
@@ -32,10 +34,11 @@ class PermissionSet
PermissionSet();
// Creates a new permission set based on the specified data: the API
- // permissions, host permissions, and scriptable hosts. The effective hosts
- // of the newly created permission set will be inferred from the given
- // host permissions.
+ // permissions, manifest key permissions, host permissions, and scriptable
+ // hosts. The effective hosts of the newly created permission set will be
+ // inferred from the given host permissions.
PermissionSet(const APIPermissionSet& apis,
+ const ManifestPermissionSet& manifest_permissions,
const URLPatternSet& explicit_hosts,
const URLPatternSet& scriptable_hosts);
@@ -102,6 +105,10 @@ class PermissionSet
const APIPermissionSet& apis() const { return apis_; }
+ const ManifestPermissionSet& manifest_permissions() const {
+ return manifest_permissions_;
+ }
+
const URLPatternSet& effective_hosts() const { return effective_hosts_; }
const URLPatternSet& explicit_hosts() const { return explicit_hosts_; }
@@ -126,6 +133,10 @@ class PermissionSet
// extension APIs and features.
APIPermissionSet apis_;
+ // The manifest key permission list is used when deciding if an extension
+ // can access certain extension APIs and features.
+ ManifestPermissionSet manifest_permissions_;
+
// The list of hosts that can be accessed directly from the extension.
// TODO(jstritar): Rename to "hosts_"?
URLPatternSet explicit_hosts_;
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index 5053b9b..d673ac1 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -89,6 +89,11 @@
'common/permissions/api_permission.h',
'common/permissions/api_permission_set.cc',
'common/permissions/api_permission_set.h',
+ 'common/permissions/base_set_operators.h',
+ 'common/permissions/manifest_permission.cc',
+ 'common/permissions/manifest_permission.h',
+ 'common/permissions/manifest_permission_set.cc',
+ 'common/permissions/manifest_permission_set.h',
'common/permissions/permission_message.cc',
'common/permissions/permission_message.h',
'common/permissions/permission_message_provider.cc',