Use extension API features instead of kNonPermissionModulesNames.
This migrates the constants in permission_set.cc to _api_features.json.
This includes a slight behavior change. Some modules with manifest keys, like
browserAction, omnibox, and commands, used to be accessible even without the
manifest key present. After this patch, they will be inaccessible. I don't
think that should be an issue in practice, because the modules wouldn't do
anything if there was no manifest key present.
BUG=234790,265006
Review URL: https://chromiumcodereview.appspot.com/20818004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@215161 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/declarative/declarative_api.cc b/chrome/browser/extensions/api/declarative/declarative_api.cc
index 4274b20..9f2f5cc 100644
--- a/chrome/browser/extensions/api/declarative/declarative_api.cc
+++ b/chrome/browser/extensions/api/declarative/declarative_api.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/extensions/extension_system_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/events.h"
+#include "chrome/common/extensions/api/extension_api.h"
#include "content/public/browser/browser_thread.h"
using extensions::api::events::Rule;
@@ -29,7 +30,11 @@
bool RulesFunction::HasPermission() {
std::string event_name;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
- return extension_->HasAPIPermission(event_name);
+ Feature::Availability availability =
+ ExtensionAPI::GetSharedInstance()->IsAvailable(
+ event_name, extension_, Feature::BLESSED_EXTENSION_CONTEXT,
+ source_url());
+ return availability.is_available();
}
bool RulesFunction::RunImpl() {
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
index 5684f63..aa9bf22d 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
@@ -33,11 +33,12 @@
const char kRuleId4[] = "rule4";
} // namespace
+using extension_test_util::LoadManifest;
+using extension_test_util::LoadManifestUnchecked;
+
namespace extensions {
using base::Value;
-using extension_test_util::LoadManifest;
-using extension_test_util::LoadManifestUnchecked;
using testing::HasSubstr;
namespace helpers = extension_web_request_api_helpers;
diff --git a/chrome/browser/extensions/api/management/management_api_browsertest.cc b/chrome/browser/extensions/api/management/management_api_browsertest.cc
index 9f73188..51663c9 100644
--- a/chrome/browser/extensions/api/management/management_api_browsertest.cc
+++ b/chrome/browser/extensions/api/management/management_api_browsertest.cc
@@ -95,6 +95,16 @@
}
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
+ SelfUninstallNoPermissions) {
+ ExtensionTestMessageListener listener1("success", false);
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("management/self_uninstall_helper")));
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("management/self_uninstall_noperm")));
+ ASSERT_TRUE(listener1.WaitUntilSatisfied());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
UninstallWithConfirmDialog) {
ExtensionService* service = ExtensionSystem::Get(browser()->profile())->
extension_service();
diff --git a/chrome/browser/extensions/api/management/management_apitest.cc b/chrome/browser/extensions/api/management/management_apitest.cc
index 0203b2f..6e98c56 100644
--- a/chrome/browser/extensions/api/management/management_apitest.cc
+++ b/chrome/browser/extensions/api/management/management_apitest.cc
@@ -108,6 +108,11 @@
ASSERT_TRUE(RunExtensionSubtest("management/test", "basics.html"));
}
+IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, NoPermission) {
+ LoadExtensions();
+ ASSERT_TRUE(RunExtensionSubtest("management/no_permission", "test.html"));
+}
+
// Disabled: http://crbug.com/174411
#if defined(OS_WIN)
#define MAYBE_Uninstall DISABLED_Uninstall
diff --git a/chrome/browser/extensions/api/storage/settings_test_util.cc b/chrome/browser/extensions/api/storage/settings_test_util.cc
index 3d8d110..07b635e 100644
--- a/chrome/browser/extensions/api/storage/settings_test_util.cc
+++ b/chrome/browser/extensions/api/storage/settings_test_util.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/extensions/api/storage/settings_frontend.h"
#include "chrome/browser/extensions/extension_system_factory.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
namespace extensions {
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 3e6a3972..766a106 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -15,6 +15,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/api/extension_api.h"
#include "chrome/common/extensions/extension_messages.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
@@ -23,6 +24,8 @@
using content::BrowserThread;
using content::RenderViewHost;
+using extensions::ExtensionAPI;
+using extensions::Feature;
// static
void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) {
@@ -70,7 +73,10 @@
}
bool ExtensionFunction::HasPermission() {
- return extension_->HasAPIPermission(name_);
+ Feature::Availability availability =
+ ExtensionAPI::GetSharedInstance()->IsAvailable(
+ name_, extension_, Feature::BLESSED_EXTENSION_CONTEXT, source_url());
+ return availability.is_available();
}
void ExtensionFunction::OnQuotaExceeded(const std::string& violation_error) {
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 18f6c81f..e846c00e 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -41,6 +41,7 @@
using extensions::api::activity_log_private::BlockedChromeActivityDetail;
using extensions::Extension;
using extensions::ExtensionAPI;
+using extensions::Feature;
using content::RenderViewHost;
namespace {
@@ -473,8 +474,8 @@
// to just the permissions they explicitly request. They should not have access
// to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally
// are available without permission.
-// TODO(asargent/kalman) - get rid of this when the features system can express
-// the "non permission" permissions.
+// TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove
+// it altogether).
bool AllowHostedAppAPICall(const Extension& extension,
const GURL& source_url,
const std::string& function_name) {
@@ -484,11 +485,11 @@
if (!extension.web_extent().MatchesURL(source_url))
return false;
- // We just allow the hosted app's explicit permissions, plus chrome.test.
- scoped_refptr<const extensions::PermissionSet> permissions =
- extension.GetActivePermissions();
- return (permissions->HasAccessToFunction(function_name, false) ||
- StartsWithASCII(function_name, "test.", true /*case_sensitive*/));
+ Feature::Availability availability =
+ ExtensionAPI::GetSharedInstance()->IsAvailable(
+ function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT,
+ source_url);
+ return availability.is_available();
}
} // namespace
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 94d2972..26e0d7a 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -44,6 +44,26 @@
"channel": "stable",
"contexts": ["blessed_extension", "unblessed_extension", "content_script"]
},
+ "app.getDetails": {
+ "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+ "matches": []
+ },
+ "app.getDetailsForFrame": {
+ "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+ "matches": []
+ },
+ "app.getIsInstalled": {
+ "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+ "matches": []
+ },
+ "app.installState": {
+ "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+ "matches": []
+ },
+ "app.runningState": {
+ "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+ "matches": []
+ },
"audio": {
"dependencies": ["permission:audio"],
"contexts": ["blessed_extension"]
@@ -300,6 +320,16 @@
"dependencies": ["permission:management"],
"contexts": ["blessed_extension"]
},
+ "management.getPermissionWarningsByManifest": {
+ "dependencies": [],
+ "channel": "stable",
+ "extension_types": ["extension", "packaged_app", "platform_app"]
+ },
+ "management.uninstallSelf": {
+ "dependencies": [],
+ "channel": "stable",
+ "extension_types": ["extension", "packaged_app", "platform_app"]
+ },
"mediaGalleries": {
"dependencies": ["permission:mediaGalleries"],
"contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index 4d0d45f2..360db62 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -309,10 +309,6 @@
const Extension* extension,
Feature::Context context,
const GURL& url) {
- std::string feature_type;
- std::string feature_name;
- SplitDependencyName(full_name, &feature_type, &feature_name);
-
Feature* feature = GetFeatureDependency(full_name);
CHECK(feature) << full_name;
diff --git a/chrome/common/extensions/api/extension_api_unittest.cc b/chrome/common/extensions/api/extension_api_unittest.cc
index a424674..89d6129 100644
--- a/chrome/common/extensions/api/extension_api_unittest.cc
+++ b/chrome/common/extensions/api/extension_api_unittest.cc
@@ -19,6 +19,7 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/extension_test_util.h"
#include "chrome/common/extensions/features/api_feature.h"
#include "chrome/common/extensions/features/base_feature_provider.h"
#include "chrome/common/extensions/features/simple_feature.h"
@@ -27,6 +28,8 @@
namespace extensions {
+using extension_test_util::BuildExtension;
+
SimpleFeature* CreateAPIFeature() {
return new APIFeature();
}
@@ -480,7 +483,7 @@
scoped_ptr<ExtensionAPI> extension_api(
ExtensionAPI::CreateWithDefaultConfiguration());
- // "runtime" should not be available in hosted apps.
+ // "runtime" and "tabs" should not be available in hosted apps.
EXPECT_FALSE(extension_api->IsAvailable("runtime",
extension.get(),
Feature::BLESSED_EXTENSION_CONTEXT,
@@ -497,6 +500,10 @@
extension.get(),
Feature::BLESSED_EXTENSION_CONTEXT,
GURL()).is_available());
+ EXPECT_FALSE(extension_api->IsAvailable("tabs.create",
+ extension.get(),
+ Feature::BLESSED_EXTENSION_CONTEXT,
+ GURL()).is_available());
}
TEST(ExtensionAPITest, AppAndFriendsAvailability) {
@@ -783,4 +790,83 @@
EXPECT_EQ("fully.qualified.Type", type);
}
+// Tests API availability with an empty manifest.
+TEST(ExtensionAPITest, NoPermissions) {
+ const struct {
+ const char* permission_name;
+ bool expect_success;
+ } kTests[] = {
+ // Test default module/package permission.
+ { "extension", true },
+ { "i18n", true },
+ { "permissions", true },
+ { "runtime", true },
+ { "test", true },
+ // These require manifest keys.
+ { "browserAction", false },
+ { "pageAction", false },
+ { "pageActions", false },
+ // Some negative tests.
+ { "bookmarks", false },
+ { "cookies", false },
+ { "history", false },
+ // Make sure we find the module name after stripping '.'
+ { "runtime.abcd.onStartup", true },
+ // Test Tabs functions.
+ { "tabs.create", true },
+ { "tabs.duplicate", true },
+ { "tabs.onRemoved", true },
+ { "tabs.remove", true },
+ { "tabs.update", true },
+ { "tabs.getSelected", true },
+ { "tabs.onUpdated", true },
+ // Test some whitelisted functions. These require no permissions.
+ { "app.getDetails", true },
+ { "app.getDetailsForFrame", true },
+ { "app.getIsInstalled", true },
+ { "app.installState", true },
+ { "app.runningState", true },
+ { "management.getPermissionWarningsByManifest", true },
+ { "management.uninstallSelf", true },
+ // But other functions in those modules do.
+ { "management.getPermissionWarningsById", false },
+ };
+
+ scoped_ptr<ExtensionAPI> extension_api(
+ ExtensionAPI::CreateWithDefaultConfiguration());
+ scoped_refptr<Extension> extension =
+ BuildExtension(ExtensionBuilder().Pass()).Build();
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
+ EXPECT_EQ(kTests[i].expect_success,
+ extension_api->IsAvailable(kTests[i].permission_name,
+ extension.get(),
+ Feature::BLESSED_EXTENSION_CONTEXT,
+ GURL()).is_available())
+ << "Permission being tested: " << kTests[i].permission_name;
+ }
+}
+
+// Tests that permissions that require manifest keys are available when those
+// keys are present.
+TEST(ExtensionAPITest, ManifestKeys) {
+ scoped_ptr<ExtensionAPI> extension_api(
+ ExtensionAPI::CreateWithDefaultConfiguration());
+
+ scoped_refptr<Extension> extension =
+ BuildExtension(ExtensionBuilder().Pass())
+ .MergeManifest(DictionaryBuilder().Set("browser_action",
+ DictionaryBuilder().Pass()))
+ .Build();
+
+ EXPECT_TRUE(extension_api->IsAvailable("browserAction",
+ extension.get(),
+ Feature::BLESSED_EXTENSION_CONTEXT,
+ GURL()).is_available());
+ EXPECT_FALSE(extension_api->IsAvailable("pageAction",
+ extension.get(),
+ Feature::BLESSED_EXTENSION_CONTEXT,
+ GURL()).is_available());
+}
+
} // namespace extensions
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 9c94936..a5f9f2f 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -335,8 +335,8 @@
return PermissionsData::HasAPIPermission(this, permission);
}
-bool Extension::HasAPIPermission(const std::string& function_name) const {
- return PermissionsData::HasAPIPermission(this, function_name);
+bool Extension::HasAPIPermission(const std::string& permission_name) const {
+ return PermissionsData::HasAPIPermission(this, permission_name);
}
scoped_refptr<const PermissionSet> Extension::GetActivePermissions() const {
@@ -480,7 +480,7 @@
}
bool Extension::force_incognito_enabled() const {
- return GetActivePermissions()->HasAnyAccessToAPI("proxy");
+ return PermissionsData::HasAPIPermission(this, APIPermission::kProxy);
}
void Extension::AddWebExtentPattern(const URLPattern& pattern) {
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 7f759a1..f9134d45 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -228,7 +228,7 @@
// DEPRECATED: These methods have been moved to PermissionsData.
// TODO(rdevlin.cronin): remove these once all calls have been updated.
bool HasAPIPermission(APIPermission::ID permission) const;
- bool HasAPIPermission(const std::string& function_name) const;
+ bool HasAPIPermission(const std::string& permission_name) const;
scoped_refptr<const PermissionSet> GetActivePermissions() const;
// Whether context menu should be shown for page and browser actions.
diff --git a/chrome/common/extensions/extension_builder.cc b/chrome/common/extensions/extension_builder.cc
index 22739aa..c7786f8b 100644
--- a/chrome/common/extensions/extension_builder.cc
+++ b/chrome/common/extensions/extension_builder.cc
@@ -43,6 +43,11 @@
return *this;
}
+ExtensionBuilder& ExtensionBuilder::MergeManifest(DictionaryBuilder& builder) {
+ manifest_->MergeDictionary(builder.Build().get());
+ return *this;
+}
+
ExtensionBuilder& ExtensionBuilder::AddFlags(int init_from_value_flags) {
flags_ |= init_from_value_flags;
return *this;
diff --git a/chrome/common/extensions/extension_builder.h b/chrome/common/extensions/extension_builder.h
index aca5b1b..c55eb73 100644
--- a/chrome/common/extensions/extension_builder.h
+++ b/chrome/common/extensions/extension_builder.h
@@ -26,6 +26,10 @@
// CHECKs that the extension was created successfully.
scoped_refptr<Extension> Build();
+ // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
+ // other functions, e.g. UseBuilder(ExtensionBuilder().Pass())
+ ExtensionBuilder& Pass() { return *this; }
+
// Defaults to FilePath().
ExtensionBuilder& SetPath(const base::FilePath& path);
@@ -37,6 +41,10 @@
return SetManifest(manifest_builder.Build());
}
+ // Adds the keys from the DictionaryBuilder to the manifest, with new keys
+ // taking precedence.
+ ExtensionBuilder& MergeManifest(DictionaryBuilder& builder);
+
ExtensionBuilder& AddFlags(int init_from_value_flags);
// Defaults to the default extension ID created in Extension::Create.
diff --git a/chrome/common/extensions/extension_test_util.cc b/chrome/common/extensions/extension_test_util.cc
index b0e13e3..02e9b22 100644
--- a/chrome/common/extensions/extension_test_util.cc
+++ b/chrome/common/extensions/extension_test_util.cc
@@ -10,12 +10,38 @@
#include "base/values.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_builder.h"
#include "chrome/common/extensions/extension_manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
+using extensions::DictionaryBuilder;
using extensions::Extension;
+using extensions::ExtensionBuilder;
+using extensions::ListBuilder;
using extensions::Manifest;
+namespace extensions {
+namespace extension_test_util {
+
+ExtensionBuilder& BuildExtension(ExtensionBuilder& builder) {
+ return builder
+ .SetManifest(DictionaryBuilder()
+ .Set("name", "Test extension")
+ .Set("version", "1.0")
+ .Set("manifest_version", 2));
+}
+
+ExtensionBuilder& BuildExtensionWithPermissions(ExtensionBuilder& builder,
+ ListBuilder& permissions) {
+ return
+ BuildExtension(builder)
+ .MergeManifest(
+ DictionaryBuilder().Set("permissions", permissions));
+}
+
+} // namespace extension_test_util
+} // namespace extensions
+
namespace extension_test_util {
scoped_refptr<Extension> CreateExtensionWithID(std::string id) {
diff --git a/chrome/common/extensions/extension_test_util.h b/chrome/common/extensions/extension_test_util.h
index 12e5104..500bdb7 100644
--- a/chrome/common/extensions/extension_test_util.h
+++ b/chrome/common/extensions/extension_test_util.h
@@ -8,11 +8,22 @@
#include <string>
#include "base/memory/ref_counted.h"
+#include "chrome/common/extensions/extension_builder.h"
#include "chrome/common/extensions/manifest.h"
namespace extensions {
class Extension;
-}
+
+// Newer functions go here.
+// TODO(mpcomplete): migrate older functions over.
+namespace extension_test_util {
+
+ExtensionBuilder& BuildExtension(ExtensionBuilder& builder);
+ExtensionBuilder& BuildExtensionWithPermissions(ExtensionBuilder& builder,
+ ListBuilder& permissions);
+
+} // namespace extension_test_util
+} // namespace extensions
namespace extension_test_util {
diff --git a/chrome/common/extensions/features/permission_feature.cc b/chrome/common/extensions/features/permission_feature.cc
index 90e53a8..5beb26f 100644
--- a/chrome/common/extensions/features/permission_feature.cc
+++ b/chrome/common/extensions/features/permission_feature.cc
@@ -27,7 +27,7 @@
if (!availability.is_available())
return availability;
- if (extension && !extension->HasAPIPermission(name()))
+ if (extension && !PermissionsData::HasAPIPermission(extension, name()))
return CreateAvailability(NOT_PRESENT, extension->GetType());
return CreateAvailability(IS_AVAILABLE);
@@ -49,4 +49,4 @@
return std::string();
}
-} // namespace
+} // namespace extensions
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index d965aaa..5f25934 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -87,6 +87,7 @@
kIdentity,
kIdentityPrivate,
kIdle,
+ kInfobars,
kInput,
kInputMethodPrivate,
kLocation,
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index dd9c142..03e2808 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -97,6 +97,7 @@
IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY,
PermissionMessage::kBrowsingHistory },
{ APIPermission::kIdle, "idle" },
+ { APIPermission::kInfobars, "infobars" },
{ APIPermission::kInput, "input", APIPermissionInfo::kFlagNone,
IDS_EXTENSION_PROMPT_WARNING_INPUT,
PermissionMessage::kInput },
diff --git a/chrome/common/extensions/permissions/permission_set.cc b/chrome/common/extensions/permissions/permission_set.cc
index 39bed89..1ad56469 100644
--- a/chrome/common/extensions/permissions/permission_set.cc
+++ b/chrome/common/extensions/permissions/permission_set.cc
@@ -37,44 +37,6 @@
return false;
}
-// Names of API modules that can be used without listing it in the
-// permissions section of the manifest.
-const char* kNonPermissionModuleNames[] = {
- "browserAction",
- "commands",
- "devtools",
- "events",
- "extension",
- "i18n",
- "omnibox",
- "pageAction",
- "pageActions",
- "permissions",
- "runtime",
- "scriptBadge",
- "tabs",
- "test",
- "types",
- "windows"
-};
-const size_t kNumNonPermissionModuleNames =
- arraysize(kNonPermissionModuleNames);
-
-// Names of functions (within modules requiring permissions) that can be used
-// without asking for the module permission. In other words, functions you can
-// use with no permissions specified.
-const char* kNonPermissionFunctionNames[] = {
- "app.getDetails",
- "app.getDetailsForFrame",
- "app.getIsInstalled",
- "app.installState",
- "app.runningState",
- "management.getPermissionWarningsByManifest",
- "management.uninstallSelf",
-};
-const size_t kNumNonPermissionFunctionNames =
- arraysize(kNonPermissionFunctionNames);
-
void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
DCHECK(out);
for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
@@ -84,19 +46,6 @@
}
}
-// Strips out the API name from a function or event name.
-// Functions will be of the form api_name.function
-// Events will be of the form api_name/id or api_name.optional.stuff
-std::string GetPermissionName(const std::string& function_name) {
- size_t separator = function_name.find_first_of("./");
- if (separator != std::string::npos)
- return function_name.substr(0, separator);
- else
- return function_name;
-}
-
-
-
} // namespace
namespace extensions {
@@ -229,21 +178,7 @@
return apis_str;
}
-bool PermissionSet::HasAnyAccessToAPI(
- const std::string& api_name) const {
- if (HasAccessToFunction(api_name, true))
- return true;
-
- for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) {
- if (api_name == GetPermissionName(kNonPermissionFunctionNames[i]))
- return true;
- }
-
- return false;
-}
-
-std::set<std::string>
- PermissionSet::GetDistinctHostsForDisplay() const {
+std::set<std::string> PermissionSet::GetDistinctHostsForDisplay() const {
URLPatternSet hosts_displayed_as_url;
// Filters out every URL pattern that matches chrome:// scheme.
for (URLPatternSet::const_iterator i = effective_hosts_.begin();
@@ -360,6 +295,13 @@
return apis().find(id) != apis().end();
}
+bool PermissionSet::HasAPIPermission(const std::string& permission_name) const {
+ const APIPermissionInfo* permission =
+ PermissionsInfo::GetInstance()->GetByName(permission_name);
+ CHECK(permission) << permission_name;
+ return (permission && apis_.count(permission->id()));
+}
+
bool PermissionSet::CheckAPIPermission(APIPermission::ID permission) const {
return CheckAPIPermissionWithParam(permission, NULL);
}
@@ -373,45 +315,6 @@
return iter->Check(param);
}
-bool PermissionSet::HasAccessToFunction(
- const std::string& function_name, bool allow_implicit) const {
- // TODO(jstritar): Embed this information in each permission and add a method
- // like GrantsAccess(function_name) to APIPermission. A "default"
- // permission can then handle the modules and functions that everyone can
- // access.
- if (allow_implicit) {
- for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) {
- if (function_name == kNonPermissionFunctionNames[i])
- return true;
- }
- }
-
- // Search for increasingly smaller substrings of |function_name| to see if we
- // find a matching permission or non-permission module name. E.g. for
- // "a.b.c", we'll search on "a.b.c", then "a.b", and finally "a".
- std::string name = function_name;
- size_t lastdot;
- do {
- const APIPermissionInfo* permission =
- PermissionsInfo::GetInstance()->GetByName(name);
- if (permission && apis_.count(permission->id()))
- return true;
-
- if (allow_implicit) {
- for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) {
- if (name == kNonPermissionModuleNames[i]) {
- return true;
- }
- }
- }
- lastdot = name.find_last_of("./");
- if (lastdot != std::string::npos)
- name = std::string(name, 0, lastdot);
- } while (lastdot != std::string::npos);
-
- return false;
-}
-
bool PermissionSet::HasExplicitAccessToOrigin(
const GURL& origin) const {
return explicit_hosts().MatchesURL(origin);
diff --git a/chrome/common/extensions/permissions/permission_set.h b/chrome/common/extensions/permissions/permission_set.h
index 9d669da..10e4d86 100644
--- a/chrome/common/extensions/permissions/permission_set.h
+++ b/chrome/common/extensions/permissions/permission_set.h
@@ -70,12 +70,6 @@
// Gets the API permissions in this set as a set of strings.
std::set<std::string> GetAPIsAsStrings() const;
- // Returns whether this namespace has any functions which the extension has
- // permission to use. For example, even though the extension may not have
- // the "tabs" permission, "tabs.create" requires no permissions so
- // HasAnyAccessToAPI("tabs") will return true.
- bool HasAnyAccessToAPI(const std::string& api_name) const;
-
// Gets the localized permission messages that represent this set.
// The set of permission messages shown varies by extension type.
PermissionMessages GetPermissionMessages(Manifest::Type extension_type) const;
@@ -96,6 +90,11 @@
// Returns true if the set has the specified API permission.
bool HasAPIPermission(APIPermission::ID permission) const;
+ // Returns true if the |extension| explicitly requests access to the given
+ // |permission_name|. Note this does not include APIs without no corresponding
+ // permission, like "runtime" or "browserAction".
+ bool HasAPIPermission(const std::string& permission_name) const;
+
// Returns true if the set allows the given permission with the default
// permission detal.
bool CheckAPIPermission(APIPermission::ID permission) const;
@@ -104,13 +103,6 @@
bool CheckAPIPermissionWithParam(APIPermission::ID permission,
const APIPermission::CheckParam* param) const;
- // Returns true if the permissions in this set grant access to the specified
- // |function_name|. The |allow_implicit| flag controls whether we
- // want to strictly check against just the explicit permissions, or also
- // include implicit "no permission needed" namespaces/functions.
- bool HasAccessToFunction(const std::string& function_name,
- bool allow_implicit) const;
-
// Returns true if this includes permission to access |origin|.
bool HasExplicitAccessToOrigin(const GURL& origin) const;
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 3076507b..8d5d7958 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -710,6 +710,7 @@
skip.insert(APIPermission::kFileBrowserHandlerInternal);
skip.insert(APIPermission::kFileBrowserPrivate);
skip.insert(APIPermission::kIdentityPrivate);
+ skip.insert(APIPermission::kInfobars);
skip.insert(APIPermission::kInputMethodPrivate);
skip.insert(APIPermission::kMediaGalleriesPrivate);
skip.insert(APIPermission::kMediaPlayerPrivate);
@@ -759,77 +760,6 @@
}
}
-// Tests the default permissions (empty API permission set).
-TEST(PermissionsTest, DefaultFunctionAccess) {
- const struct {
- const char* permission_name;
- bool expect_success;
- } kTests[] = {
- // Negative test.
- { "non_existing_permission", false },
- // Test default module/package permission.
- { "browserAction", true },
- { "devtools", true },
- { "extension", true },
- { "i18n", true },
- { "pageAction", true },
- { "pageActions", true },
- { "test", true },
- // Some negative tests.
- { "bookmarks", false },
- { "cookies", false },
- { "history", false },
- // Make sure we find the module name after stripping '.' and '/'.
- { "browserAction/abcd/onClick", true },
- { "browserAction.abcd.onClick", true },
- // Test Tabs functions.
- { "tabs.create", true},
- { "tabs.duplicate", true},
- { "tabs.update", true},
- { "tabs.getSelected", true},
- { "tabs.onUpdated", true },
- };
-
- scoped_refptr<PermissionSet> empty = new PermissionSet();
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
- EXPECT_EQ(kTests[i].expect_success,
- empty->HasAccessToFunction(kTests[i].permission_name, true))
- << "Permission being tested: " << kTests[i].permission_name;
- }
-}
-
-// Tests the default permissions (empty API permission set).
-TEST(PermissionsTest, DefaultAnyAPIAccess) {
- const struct {
- const char* api_name;
- bool expect_success;
- } kTests[] = {
- // Negative test.
- { "non_existing_permission", false },
- // Test default module/package permission.
- { "browserAction", true },
- { "devtools", true },
- { "extension", true },
- { "i18n", true },
- { "pageAction", true },
- { "pageActions", true },
- { "test", true },
- // Some negative tests.
- { "bookmarks", false },
- { "cookies", false },
- { "history", false },
- // Negative APIs that have positive individual functions.
- { "management", true},
- { "tabs", true},
- };
-
- scoped_refptr<PermissionSet> empty = new PermissionSet();
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
- EXPECT_EQ(kTests[i].expect_success,
- empty->HasAnyAccessToAPI(kTests[i].api_name));
- }
-}
-
TEST(PermissionsTest, GetWarningMessages_ManyHosts) {
scoped_refptr<Extension> extension;
diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc
index 6330620..8b5796eb 100644
--- a/chrome/common/extensions/permissions/permissions_data.cc
+++ b/chrome/common/extensions/permissions/permissions_data.cc
@@ -356,11 +356,11 @@
}
// static
-bool PermissionsData::HasAPIPermission(const Extension* extension,
- const std::string& function_name) {
+bool PermissionsData::HasAPIPermission(
+ const Extension* extension,
+ const std::string& permission_name) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
- return GetActivePermissions(extension)->HasAccessToFunction(
- function_name, true); // include implicit
+ return GetActivePermissions(extension)->HasAPIPermission(permission_name);
}
// static
diff --git a/chrome/common/extensions/permissions/permissions_data.h b/chrome/common/extensions/permissions/permissions_data.h
index 57f6555..18e3787 100644
--- a/chrome/common/extensions/permissions/permissions_data.h
+++ b/chrome/common/extensions/permissions/permissions_data.h
@@ -93,10 +93,13 @@
// Returns true if the |extension| has the given |permission|. Prefer
// IsExtensionWithPermissionOrSuggestInConsole when developers may be using an
// api that requires a permission they didn't know about, e.g. open web apis.
+ // Note this does not include APIs with no corresponding permission, like
+ // "runtime" or "browserAction".
+ // TODO(mpcomplete): drop the "API" from these names, it's confusing.
static bool HasAPIPermission(const Extension* extension,
APIPermission::ID permission);
static bool HasAPIPermission(const Extension* extension,
- const std::string& function_name);
+ const std::string& permission_name);
static bool HasAPIPermissionForTab(const Extension* extension,
int tab_id,
APIPermission::ID permission);
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index b689006..a4d1cda 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -151,53 +151,6 @@
"239.255.255.250", 1900));
}
-// This tests the API permissions with an empty manifest (one that just
-// specifies a name and a version and nothing else).
-TEST(ExtensionPermissionsTest, ApiPermissions) {
- const struct {
- const char* permission_name;
- bool expect_success;
- } kTests[] = {
- // Negative test.
- { "non_existing_permission", false },
- // Test default module/package permission.
- { "browserAction", true },
- { "devtools", true },
- { "extension", true },
- { "i18n", true },
- { "pageAction", true },
- { "pageActions", true },
- { "test", true },
- // Some negative tests.
- { "bookmarks", false },
- { "cookies", false },
- { "history", false },
- // Make sure we find the module name after stripping '.' and '/'.
- { "browserAction/abcd/onClick", true },
- { "browserAction.abcd.onClick", true },
- // Test Tabs functions.
- { "tabs.create", true},
- { "tabs.duplicate", true},
- { "tabs.onRemoved", true},
- { "tabs.remove", true},
- { "tabs.update", true},
- { "tabs.getSelected", true},
- { "tabs.onUpdated", true },
- // Test getPermissionWarnings functions. Only one requires permissions.
- { "management.getPermissionWarningsById", false },
- { "management.getPermissionWarningsByManifest", true },
- };
-
- scoped_refptr<Extension> extension;
- extension = LoadManifest("empty_manifest", "empty.json");
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
- EXPECT_EQ(kTests[i].expect_success,
- extension->HasAPIPermission(kTests[i].permission_name))
- << "Permission being tested: " << kTests[i].permission_name;
- }
-}
-
TEST(ExtensionPermissionsTest, GetPermissionMessages_ManyAPIPermissions) {
scoped_refptr<Extension> extension;
extension = LoadManifest("permissions", "many-apis.json");
diff --git a/chrome/common/extensions/value_builder.h b/chrome/common/extensions/value_builder.h
index 48e9133..db272c5 100644
--- a/chrome/common/extensions/value_builder.h
+++ b/chrome/common/extensions/value_builder.h
@@ -20,8 +20,8 @@
// .Append("foo").Append("bar") /* No .Build() */);
//
// Because of limitations in C++03, and to avoid extra copies, you can't pass a
-// just-constructed Builder into another Builder's method without setting at
-// least 1 field.
+// just-constructed Builder into another Builder's method directly. Use the
+// Pass() method.
//
// The Build() method invalidates its builder, and returns ownership of the
// built value.
@@ -49,6 +49,10 @@
explicit DictionaryBuilder(const base::DictionaryValue& init);
~DictionaryBuilder();
+ // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
+ // other functions.
+ DictionaryBuilder& Pass() { return *this; }
+
// Can only be called once, after which it's invalid to use the builder.
scoped_ptr<base::DictionaryValue> Build() { return dict_.Pass(); }
@@ -73,6 +77,10 @@
explicit ListBuilder(const base::ListValue& init);
~ListBuilder();
+ // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
+ // other functions.
+ ListBuilder& Pass() { return *this; }
+
// Can only be called once, after which it's invalid to use the builder.
scoped_ptr<base::ListValue> Build() { return list_.Pass(); }
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js b/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js
index 2a2524d..8c29e62b 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js
+++ b/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js
@@ -58,11 +58,11 @@
}
// Makes an API call that the extension doesn't have permission for.
-// Don't add the management permission or this test won't test the code path.
+// Don't add the bookmarks permission or this test won't test the code path.
function makeBlockedApiCall() {
resetStatus();
try {
- var allExtensions = chrome.management.getAll();
+ var allExtensions = chrome.bookmarks.getTree();
} catch (err) { }
appendCompleted('makeBlockedApiCall');
}
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
index cf7af969..7a552b04 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
+++ b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
@@ -45,9 +45,9 @@
'blocked_call', function response() { });
},
// Blocked api calls only log the api module name and not the
- // function, so this is intentionally 'management' rather than
- // 'management.getAll'.
- expected_activity: ['management']
+ // function, so this is intentionally 'bookmarks' rather than
+ // 'bookmarks.getTree'.
+ expected_activity: ['bookmarks']
});
testCases.push({
func: function triggerObjectMethods() {
diff --git a/chrome/test/data/extensions/api_test/management/no_permission/manifest.json b/chrome/test/data/extensions/api_test/management/no_permission/manifest.json
new file mode 100644
index 0000000..5ce966a
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/no_permission/manifest.json
@@ -0,0 +1,5 @@
+{
+ "name": "Test that permissionless management APIs work without permission",
+ "version": "0.1",
+ "manifest_version": 2
+}
diff --git a/chrome/test/data/extensions/api_test/management/no_permission/test.html b/chrome/test/data/extensions/api_test/management/no_permission/test.html
new file mode 100644
index 0000000..5000771
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/no_permission/test.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved. Use of this
+ * source code is governed by a BSD-style license that can be found in the
+ * LICENSE file.
+-->
+<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/management/no_permission/test.js b/chrome/test/data/extensions/api_test/management/no_permission/test.js
new file mode 100644
index 0000000..07e1e07
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/no_permission/test.js
@@ -0,0 +1,18 @@
+// 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.
+
+var tests = [
+ function permissionWarnings() {
+ var manifest_str = "{ \"name\": \"Location!\", \"version\": \"1.0\", " +
+ "\"permissions\": [\"location\"] }";
+
+ chrome.management.getPermissionWarningsByManifest(
+ manifest_str, chrome.test.callback(function(warnings) {
+ chrome.test.assertEq(1, warnings.length);
+ chrome.test.assertEq("Detect your physical location", warnings[0]);
+ }));
+ },
+];
+
+chrome.test.runTests(tests);
diff --git a/chrome/test/data/extensions/management/self_uninstall_noperm/background.js b/chrome/test/data/extensions/management/self_uninstall_noperm/background.js
new file mode 100644
index 0000000..e13b844f
--- /dev/null
+++ b/chrome/test/data/extensions/management/self_uninstall_noperm/background.js
@@ -0,0 +1,9 @@
+// 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.
+
+// Wait for the API test framework to decide we're done loading before
+// uninstalling, or it'll wait forever.
+chrome.runtime.onInstalled.addListener(function() {
+ chrome.management.uninstallSelf();
+});
diff --git a/chrome/test/data/extensions/management/self_uninstall_noperm/manifest.json b/chrome/test/data/extensions/management/self_uninstall_noperm/manifest.json
new file mode 100644
index 0000000..90c7d23
--- /dev/null
+++ b/chrome/test/data/extensions/management/self_uninstall_noperm/manifest.json
@@ -0,0 +1,9 @@
+{
+ "name": "Self Uninstall Test (no permissions)",
+ "version": "0.1",
+ "manifest_version": 2,
+ "background": {
+ "scripts": ["background.js"]
+ }
+}
+