| Index: chrome/renderer/extensions/extension_process_bindings.cc
 | 
| diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
 | 
| index 131b9a037e8ce64368179ae734190b2881a48f30..09a13119e68e0f8fc346fc44cb6742a6bbc03626 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
 | 
| +}
 | 
| 
 |