summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/extensions
diff options
context:
space:
mode:
authormpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-07 18:58:19 +0000
committermpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-07 18:58:19 +0000
commit35506359934707a1dc47e0b26684a145835dd9c3 (patch)
treea4c148fec23792743e3f5f024c852f6d668f173d /chrome/renderer/extensions
parentd4d9025c103adaa1b89b130ed229e61947ec40cc (diff)
downloadchromium_src-35506359934707a1dc47e0b26684a145835dd9c3.zip
chromium_src-35506359934707a1dc47e0b26684a145835dd9c3.tar.gz
chromium_src-35506359934707a1dc47e0b26684a145835dd9c3.tar.bz2
Add module-level permissions to extensions.
This first pass is fairly simple. If a permission is not specified in the manifest, the corresponding module will not be exposed to script. For example, without specifying the "tabs" permission, chrome.tabs and chrome.windows will not be available. BUG=12140 TEST=no Review URL: http://codereview.chromium.org/164039 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22745 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/extensions')
-rw-r--r--chrome/renderer/extensions/event_bindings.cc12
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc116
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.h14
3 files changed, 128 insertions, 14 deletions
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc
index b44fe82..d771580 100644
--- a/chrome/renderer/extensions/event_bindings.cc
+++ b/chrome/renderer/extensions/event_bindings.cc
@@ -76,10 +76,20 @@ class ExtensionImpl : public ExtensionBase {
if (args[0]->IsString()) {
std::string event_name(*v8::String::AsciiValue(args[0]));
- if (EventIncrementListenerCount(event_name) == 1) {
+ bool has_permission =
+ ExtensionProcessBindings::CurrentContextHasPermission(event_name);
+
+ // Increment the count even if the caller doesn't have permission, so that
+ // refcounts stay balanced.
+ if (EventIncrementListenerCount(event_name) == 1 && has_permission) {
EventBindings::GetRenderThread()->Send(
new ViewHostMsg_ExtensionAddListener(event_name));
}
+
+ if (!has_permission) {
+ return ExtensionProcessBindings::ThrowPermissionDeniedException(
+ event_name);
+ }
}
return v8::Undefined();
diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
index 131b9a0..09a1311 100644
--- a/chrome/renderer/extensions/extension_process_bindings.cc
+++ b/chrome/renderer/extensions/extension_process_bindings.cc
@@ -5,6 +5,7 @@
#include "chrome/renderer/extensions/extension_process_bindings.h"
#include "base/singleton.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "chrome/renderer/extensions/bindings_utils.h"
@@ -30,6 +31,12 @@ namespace {
// A map of extension ID to vector of page action ids.
typedef std::map< std::string, std::vector<std::string> > PageActionIdMap;
+// A map of permission name to whether its enabled for this extension.
+typedef std::map<std::string, bool> PermissionsMap;
+
+// A map of extension ID to permissions map.
+typedef std::map<std::string, PermissionsMap> ExtensionPermissionsMap;
+
const char kExtensionName[] = "chrome/ExtensionProcessBindings";
const char* kExtensionDeps[] = {
BaseJsV8Extension::kName,
@@ -41,6 +48,7 @@ const char* kExtensionDeps[] = {
struct SingletonData {
std::set<std::string> function_names_;
PageActionIdMap page_action_ids_;
+ ExtensionPermissionsMap permissions_;
};
static std::set<std::string>* GetFunctionNameSet() {
@@ -51,6 +59,10 @@ static PageActionIdMap* GetPageActionMap() {
return &Singleton<SingletonData>()->page_action_ids_;
}
+static PermissionsMap* GetPermissionsMap(const std::string& extension_id) {
+ return &Singleton<SingletonData>()->permissions_[extension_id];
+}
+
class ExtensionImpl : public ExtensionBase {
public:
ExtensionImpl() : ExtensionBase(
@@ -64,6 +76,18 @@ class ExtensionImpl : public ExtensionBase {
}
}
+ // Note: do not call this function before or during the chromeHidden.onLoad
+ // event dispatch. The URL might not have been committed yet and might not
+ // be an extension URL.
+ static std::string ExtensionIdForCurrentContext() {
+ RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext();
+ DCHECK(renderview);
+ GURL url = renderview->webview()->GetMainFrame()->GetURL();
+ if (url.SchemeIs(chrome::kExtensionScheme))
+ return url.host();
+ return std::string();
+ }
+
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name) {
if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) {
@@ -84,20 +108,13 @@ class ExtensionImpl : public ExtensionBase {
}
private:
- static std::string ExtensionIdFromCurrentContext() {
- RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext();
- DCHECK(renderview);
- GURL url = renderview->webview()->GetMainFrame()->GetURL();
- return url.host();
- }
-
static v8::Handle<v8::Value> GetExtensionAPIDefinition(
const v8::Arguments& args) {
return v8::String::New(GetStringResource<IDR_EXTENSION_API_JSON>());
}
static v8::Handle<v8::Value> GetViews(const v8::Arguments& args) {
- std::string extension_id = ExtensionIdFromCurrentContext();
+ std::string extension_id = ExtensionIdForCurrentContext();
ContextList contexts =
bindings_utils::GetContextsForExtension(extension_id);
@@ -145,11 +162,9 @@ class ExtensionImpl : public ExtensionBase {
static v8::Handle<v8::Value> GetCurrentPageActions(
const v8::Arguments& args) {
- std::string extension_id = ExtensionIdFromCurrentContext();
- PageActionIdMap* page_action_map =
- GetPageActionMap();
- PageActionIdMap::const_iterator it =
- page_action_map->find(extension_id);
+ std::string extension_id = *v8::String::Utf8Value(args[0]->ToString());
+ PageActionIdMap* page_action_map = GetPageActionMap();
+ PageActionIdMap::const_iterator it = page_action_map->find(extension_id);
std::vector<std::string> page_actions;
size_t size = 0;
@@ -187,6 +202,9 @@ class ExtensionImpl : public ExtensionBase {
return v8::Undefined();
}
+ if (!ExtensionProcessBindings::CurrentContextHasPermission(name))
+ return ExtensionProcessBindings::ThrowPermissionDeniedException(name);
+
std::string json_args = *v8::String::Utf8Value(args[1]);
int request_id = args[2]->Int32Value();
bool has_callback = args[3]->BooleanValue();
@@ -249,3 +267,75 @@ void ExtensionProcessBindings::SetPageActions(
page_action_map.erase(extension_id);
}
}
+
+// static
+void ExtensionProcessBindings::SetPermissions(
+ const std::string& extension_id,
+ const std::vector<std::string>& permissions) {
+ PermissionsMap& permissions_map = *GetPermissionsMap(extension_id);
+
+ // Default all permissions to false, then enable the ones in the vector.
+ for (size_t i = 0; i < Extension::kNumPermissions; ++i)
+ permissions_map[Extension::kPermissionNames[i]] = false;
+ for (size_t i = 0; i < permissions.size(); ++i)
+ permissions_map[permissions[i]] = true;
+}
+
+// Given a name like "tabs.onConnect", return the permission name required
+// to access that API ("tabs" in this example).
+static std::string GetPermissionName(const std::string& function_name) {
+ size_t first_dot = function_name.find('.');
+ std::string permission_name = function_name.substr(0, first_dot);
+ if (permission_name == "windows")
+ return "tabs"; // windows and tabs are the same permission.
+ return permission_name;
+}
+
+// static
+bool ExtensionProcessBindings::CurrentContextHasPermission(
+ const std::string& function_name) {
+ std::string extension_id = ExtensionImpl::ExtensionIdForCurrentContext();
+ PermissionsMap& permissions_map = *GetPermissionsMap(extension_id);
+ std::string permission_name = GetPermissionName(function_name);
+ PermissionsMap::iterator it = permissions_map.find(permission_name);
+
+ // We explicitly check if the permission entry is present and false, because
+ // some APIs do not have a required permission entry (ie, "chrome.self").
+ return (it == permissions_map.end() || it->second);
+}
+
+// static
+v8::Handle<v8::Value>
+ ExtensionProcessBindings::ThrowPermissionDeniedException(
+ const std::string& function_name) {
+ static const char kMessage[] =
+ "You do not have permission to use 'chrome.%s'. Be sure to declare"
+ " in your manifest what permissions you need.";
+ std::string permission_name = GetPermissionName(function_name);
+ std::string error_msg = StringPrintf(kMessage, permission_name.c_str());
+
+#if EXTENSION_TIME_TO_BREAK_API
+ return v8::ThrowException(v8::Exception::Error(
+ v8::String::New(error_msg.c_str())));
+#else
+ // Call console.error for now.
+
+ v8::HandleScope scope;
+
+ v8::Local<v8::Value> console =
+ v8::Context::GetCurrent()->Global()->Get(v8::String::New("console"));
+ v8::Local<v8::Value> console_error;
+ if (!console.IsEmpty() && console->IsObject())
+ console_error = console->ToObject()->Get(v8::String::New("error"));
+ if (console_error.IsEmpty() || !console_error->IsFunction())
+ return v8::Undefined();
+
+ v8::Local<v8::Function> function =
+ v8::Local<v8::Function>::Cast(console_error);
+ v8::Local<v8::Value> argv[] = { v8::String::New(error_msg.c_str()) };
+ if (!function.IsEmpty())
+ function->Call(console->ToObject(), arraysize(argv), argv);
+
+ return v8::Undefined();
+#endif
+}
diff --git a/chrome/renderer/extensions/extension_process_bindings.h b/chrome/renderer/extensions/extension_process_bindings.h
index 1ce6b47..dd212c5 100644
--- a/chrome/renderer/extensions/extension_process_bindings.h
+++ b/chrome/renderer/extensions/extension_process_bindings.h
@@ -26,6 +26,20 @@ class ExtensionProcessBindings {
// Sets the page action ids for a particular extension.
static void SetPageActions(const std::string& extension_id,
const std::vector<std::string>& page_actions);
+
+ // Sets the permissions for a particular extension.
+ static void SetPermissions(const std::string& extension_id,
+ const std::vector<std::string>& permissions);
+
+ // Check if the extension in the currently running context has permission to
+ // access the given extension function. Must be called with a valid V8
+ // context in scope.
+ static bool CurrentContextHasPermission(const std::string& function_name);
+
+ // Throw a V8 exception indicating that permission to access function_name was
+ // denied. Must be called with a valid V8 context in scope.
+ static v8::Handle<v8::Value> ThrowPermissionDeniedException(
+ const std::string& function_name);
};
#endif // CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_