| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/renderer/extensions/extension_process_bindings.h" | 5 #include "chrome/renderer/extensions/extension_process_bindings.h" |
| 6 | 6 |
| 7 #include "base/singleton.h" | 7 #include "base/singleton.h" |
| 8 #include "chrome/common/extensions/extension.h" |
| 8 #include "chrome/common/render_messages.h" | 9 #include "chrome/common/render_messages.h" |
| 9 #include "chrome/common/url_constants.h" | 10 #include "chrome/common/url_constants.h" |
| 10 #include "chrome/renderer/extensions/bindings_utils.h" | 11 #include "chrome/renderer/extensions/bindings_utils.h" |
| 11 #include "chrome/renderer/extensions/event_bindings.h" | 12 #include "chrome/renderer/extensions/event_bindings.h" |
| 12 #include "chrome/renderer/extensions/renderer_extension_bindings.h" | 13 #include "chrome/renderer/extensions/renderer_extension_bindings.h" |
| 13 #include "chrome/renderer/js_only_v8_extensions.h" | 14 #include "chrome/renderer/js_only_v8_extensions.h" |
| 14 #include "chrome/renderer/render_view.h" | 15 #include "chrome/renderer/render_view.h" |
| 15 #include "grit/common_resources.h" | 16 #include "grit/common_resources.h" |
| 16 #include "grit/renderer_resources.h" | 17 #include "grit/renderer_resources.h" |
| 17 #include "webkit/glue/webframe.h" | 18 #include "webkit/glue/webframe.h" |
| 18 | 19 |
| 19 using bindings_utils::GetStringResource; | 20 using bindings_utils::GetStringResource; |
| 20 using bindings_utils::ContextInfo; | 21 using bindings_utils::ContextInfo; |
| 21 using bindings_utils::ContextList; | 22 using bindings_utils::ContextList; |
| 22 using bindings_utils::GetContexts; | 23 using bindings_utils::GetContexts; |
| 23 using bindings_utils::GetPendingRequestMap; | 24 using bindings_utils::GetPendingRequestMap; |
| 24 using bindings_utils::PendingRequest; | 25 using bindings_utils::PendingRequest; |
| 25 using bindings_utils::PendingRequestMap; | 26 using bindings_utils::PendingRequestMap; |
| 26 using bindings_utils::ExtensionBase; | 27 using bindings_utils::ExtensionBase; |
| 27 | 28 |
| 28 namespace { | 29 namespace { |
| 29 | 30 |
| 30 // A map of extension ID to vector of page action ids. | 31 // A map of extension ID to vector of page action ids. |
| 31 typedef std::map< std::string, std::vector<std::string> > PageActionIdMap; | 32 typedef std::map< std::string, std::vector<std::string> > PageActionIdMap; |
| 32 | 33 |
| 34 // A map of permission name to whether its enabled for this extension. |
| 35 typedef std::map<std::string, bool> PermissionsMap; |
| 36 |
| 37 // A map of extension ID to permissions map. |
| 38 typedef std::map<std::string, PermissionsMap> ExtensionPermissionsMap; |
| 39 |
| 33 const char kExtensionName[] = "chrome/ExtensionProcessBindings"; | 40 const char kExtensionName[] = "chrome/ExtensionProcessBindings"; |
| 34 const char* kExtensionDeps[] = { | 41 const char* kExtensionDeps[] = { |
| 35 BaseJsV8Extension::kName, | 42 BaseJsV8Extension::kName, |
| 36 EventBindings::kName, | 43 EventBindings::kName, |
| 37 JsonSchemaJsV8Extension::kName, | 44 JsonSchemaJsV8Extension::kName, |
| 38 RendererExtensionBindings::kName, | 45 RendererExtensionBindings::kName, |
| 39 }; | 46 }; |
| 40 | 47 |
| 41 struct SingletonData { | 48 struct SingletonData { |
| 42 std::set<std::string> function_names_; | 49 std::set<std::string> function_names_; |
| 43 PageActionIdMap page_action_ids_; | 50 PageActionIdMap page_action_ids_; |
| 51 ExtensionPermissionsMap permissions_; |
| 44 }; | 52 }; |
| 45 | 53 |
| 46 static std::set<std::string>* GetFunctionNameSet() { | 54 static std::set<std::string>* GetFunctionNameSet() { |
| 47 return &Singleton<SingletonData>()->function_names_; | 55 return &Singleton<SingletonData>()->function_names_; |
| 48 } | 56 } |
| 49 | 57 |
| 50 static PageActionIdMap* GetPageActionMap() { | 58 static PageActionIdMap* GetPageActionMap() { |
| 51 return &Singleton<SingletonData>()->page_action_ids_; | 59 return &Singleton<SingletonData>()->page_action_ids_; |
| 52 } | 60 } |
| 53 | 61 |
| 62 static PermissionsMap* GetPermissionsMap(const std::string& extension_id) { |
| 63 return &Singleton<SingletonData>()->permissions_[extension_id]; |
| 64 } |
| 65 |
| 54 class ExtensionImpl : public ExtensionBase { | 66 class ExtensionImpl : public ExtensionBase { |
| 55 public: | 67 public: |
| 56 ExtensionImpl() : ExtensionBase( | 68 ExtensionImpl() : ExtensionBase( |
| 57 kExtensionName, GetStringResource<IDR_EXTENSION_PROCESS_BINDINGS_JS>(), | 69 kExtensionName, GetStringResource<IDR_EXTENSION_PROCESS_BINDINGS_JS>(), |
| 58 arraysize(kExtensionDeps), kExtensionDeps) {} | 70 arraysize(kExtensionDeps), kExtensionDeps) {} |
| 59 | 71 |
| 60 static void SetFunctionNames(const std::vector<std::string>& names) { | 72 static void SetFunctionNames(const std::vector<std::string>& names) { |
| 61 std::set<std::string>* name_set = GetFunctionNameSet(); | 73 std::set<std::string>* name_set = GetFunctionNameSet(); |
| 62 for (size_t i = 0; i < names.size(); ++i) { | 74 for (size_t i = 0; i < names.size(); ++i) { |
| 63 name_set->insert(names[i]); | 75 name_set->insert(names[i]); |
| 64 } | 76 } |
| 65 } | 77 } |
| 66 | 78 |
| 79 // Note: do not call this function before or during the chromeHidden.onLoad |
| 80 // event dispatch. The URL might not have been committed yet and might not |
| 81 // be an extension URL. |
| 82 static std::string ExtensionIdForCurrentContext() { |
| 83 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext(); |
| 84 DCHECK(renderview); |
| 85 GURL url = renderview->webview()->GetMainFrame()->GetURL(); |
| 86 if (url.SchemeIs(chrome::kExtensionScheme)) |
| 87 return url.host(); |
| 88 return std::string(); |
| 89 } |
| 90 |
| 67 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 91 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
| 68 v8::Handle<v8::String> name) { | 92 v8::Handle<v8::String> name) { |
| 69 if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) { | 93 if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) { |
| 70 return v8::FunctionTemplate::New(GetExtensionAPIDefinition); | 94 return v8::FunctionTemplate::New(GetExtensionAPIDefinition); |
| 71 } else if (name->Equals(v8::String::New("GetViews"))) { | 95 } else if (name->Equals(v8::String::New("GetViews"))) { |
| 72 return v8::FunctionTemplate::New(GetViews); | 96 return v8::FunctionTemplate::New(GetViews); |
| 73 } else if (name->Equals(v8::String::New("GetNextRequestId"))) { | 97 } else if (name->Equals(v8::String::New("GetNextRequestId"))) { |
| 74 return v8::FunctionTemplate::New(GetNextRequestId); | 98 return v8::FunctionTemplate::New(GetNextRequestId); |
| 75 } else if (name->Equals(v8::String::New("OpenChannelToTab"))) { | 99 } else if (name->Equals(v8::String::New("OpenChannelToTab"))) { |
| 76 return v8::FunctionTemplate::New(OpenChannelToTab); | 100 return v8::FunctionTemplate::New(OpenChannelToTab); |
| 77 } else if (name->Equals(v8::String::New("GetCurrentPageActions"))) { | 101 } else if (name->Equals(v8::String::New("GetCurrentPageActions"))) { |
| 78 return v8::FunctionTemplate::New(GetCurrentPageActions); | 102 return v8::FunctionTemplate::New(GetCurrentPageActions); |
| 79 } else if (name->Equals(v8::String::New("StartRequest"))) { | 103 } else if (name->Equals(v8::String::New("StartRequest"))) { |
| 80 return v8::FunctionTemplate::New(StartRequest); | 104 return v8::FunctionTemplate::New(StartRequest); |
| 81 } | 105 } |
| 82 | 106 |
| 83 return ExtensionBase::GetNativeFunction(name); | 107 return ExtensionBase::GetNativeFunction(name); |
| 84 } | 108 } |
| 85 | 109 |
| 86 private: | 110 private: |
| 87 static std::string ExtensionIdFromCurrentContext() { | |
| 88 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext(); | |
| 89 DCHECK(renderview); | |
| 90 GURL url = renderview->webview()->GetMainFrame()->GetURL(); | |
| 91 return url.host(); | |
| 92 } | |
| 93 | |
| 94 static v8::Handle<v8::Value> GetExtensionAPIDefinition( | 111 static v8::Handle<v8::Value> GetExtensionAPIDefinition( |
| 95 const v8::Arguments& args) { | 112 const v8::Arguments& args) { |
| 96 return v8::String::New(GetStringResource<IDR_EXTENSION_API_JSON>()); | 113 return v8::String::New(GetStringResource<IDR_EXTENSION_API_JSON>()); |
| 97 } | 114 } |
| 98 | 115 |
| 99 static v8::Handle<v8::Value> GetViews(const v8::Arguments& args) { | 116 static v8::Handle<v8::Value> GetViews(const v8::Arguments& args) { |
| 100 std::string extension_id = ExtensionIdFromCurrentContext(); | 117 std::string extension_id = ExtensionIdForCurrentContext(); |
| 101 | 118 |
| 102 ContextList contexts = | 119 ContextList contexts = |
| 103 bindings_utils::GetContextsForExtension(extension_id); | 120 bindings_utils::GetContextsForExtension(extension_id); |
| 104 DCHECK(contexts.size() > 0); | 121 DCHECK(contexts.size() > 0); |
| 105 | 122 |
| 106 v8::Local<v8::Array> views = v8::Array::New(contexts.size()); | 123 v8::Local<v8::Array> views = v8::Array::New(contexts.size()); |
| 107 int index = 0; | 124 int index = 0; |
| 108 ContextList::const_iterator it = contexts.begin(); | 125 ContextList::const_iterator it = contexts.begin(); |
| 109 for (; it != contexts.end(); ++it) { | 126 for (; it != contexts.end(); ++it) { |
| 110 v8::Local<v8::Value> window = (*it)->context->Global()->Get( | 127 v8::Local<v8::Value> window = (*it)->context->Global()->Get( |
| (...skipping 27 matching lines...) Expand all Loading... |
| 138 renderview->Send(new ViewHostMsg_OpenChannelToTab( | 155 renderview->Send(new ViewHostMsg_OpenChannelToTab( |
| 139 renderview->routing_id(), tab_id, extension_id, channel_name, | 156 renderview->routing_id(), tab_id, extension_id, channel_name, |
| 140 &port_id)); | 157 &port_id)); |
| 141 return v8::Integer::New(port_id); | 158 return v8::Integer::New(port_id); |
| 142 } | 159 } |
| 143 return v8::Undefined(); | 160 return v8::Undefined(); |
| 144 } | 161 } |
| 145 | 162 |
| 146 static v8::Handle<v8::Value> GetCurrentPageActions( | 163 static v8::Handle<v8::Value> GetCurrentPageActions( |
| 147 const v8::Arguments& args) { | 164 const v8::Arguments& args) { |
| 148 std::string extension_id = ExtensionIdFromCurrentContext(); | 165 std::string extension_id = *v8::String::Utf8Value(args[0]->ToString()); |
| 149 PageActionIdMap* page_action_map = | 166 PageActionIdMap* page_action_map = GetPageActionMap(); |
| 150 GetPageActionMap(); | 167 PageActionIdMap::const_iterator it = page_action_map->find(extension_id); |
| 151 PageActionIdMap::const_iterator it = | |
| 152 page_action_map->find(extension_id); | |
| 153 | 168 |
| 154 std::vector<std::string> page_actions; | 169 std::vector<std::string> page_actions; |
| 155 size_t size = 0; | 170 size_t size = 0; |
| 156 if (it != page_action_map->end()) { | 171 if (it != page_action_map->end()) { |
| 157 page_actions = it->second; | 172 page_actions = it->second; |
| 158 size = page_actions.size(); | 173 size = page_actions.size(); |
| 159 } | 174 } |
| 160 | 175 |
| 161 v8::Local<v8::Array> page_action_vector = v8::Array::New(size); | 176 v8::Local<v8::Array> page_action_vector = v8::Array::New(size); |
| 162 for (size_t i = 0; i < size; ++i) { | 177 for (size_t i = 0; i < size; ++i) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 180 if (args.Length() != 4 || !args[0]->IsString() || !args[1]->IsString() || | 195 if (args.Length() != 4 || !args[0]->IsString() || !args[1]->IsString() || |
| 181 !args[2]->IsInt32() || !args[3]->IsBoolean()) | 196 !args[2]->IsInt32() || !args[3]->IsBoolean()) |
| 182 return v8::Undefined(); | 197 return v8::Undefined(); |
| 183 | 198 |
| 184 std::string name = *v8::String::AsciiValue(args[0]); | 199 std::string name = *v8::String::AsciiValue(args[0]); |
| 185 if (GetFunctionNameSet()->find(name) == GetFunctionNameSet()->end()) { | 200 if (GetFunctionNameSet()->find(name) == GetFunctionNameSet()->end()) { |
| 186 NOTREACHED() << "Unexpected function " << name; | 201 NOTREACHED() << "Unexpected function " << name; |
| 187 return v8::Undefined(); | 202 return v8::Undefined(); |
| 188 } | 203 } |
| 189 | 204 |
| 205 if (!ExtensionProcessBindings::CurrentContextHasPermission(name)) |
| 206 return ExtensionProcessBindings::ThrowPermissionDeniedException(name); |
| 207 |
| 190 std::string json_args = *v8::String::Utf8Value(args[1]); | 208 std::string json_args = *v8::String::Utf8Value(args[1]); |
| 191 int request_id = args[2]->Int32Value(); | 209 int request_id = args[2]->Int32Value(); |
| 192 bool has_callback = args[3]->BooleanValue(); | 210 bool has_callback = args[3]->BooleanValue(); |
| 193 | 211 |
| 194 v8::Persistent<v8::Context> current_context = | 212 v8::Persistent<v8::Context> current_context = |
| 195 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); | 213 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); |
| 196 DCHECK(!current_context.IsEmpty()); | 214 DCHECK(!current_context.IsEmpty()); |
| 197 GetPendingRequestMap()[request_id].reset(new PendingRequest( | 215 GetPendingRequestMap()[request_id].reset(new PendingRequest( |
| 198 current_context, *v8::String::AsciiValue(args.Data()))); | 216 current_context, *v8::String::AsciiValue(args.Data()))); |
| 199 | 217 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 const std::string& extension_id, | 260 const std::string& extension_id, |
| 243 const std::vector<std::string>& page_actions) { | 261 const std::vector<std::string>& page_actions) { |
| 244 PageActionIdMap& page_action_map = *GetPageActionMap(); | 262 PageActionIdMap& page_action_map = *GetPageActionMap(); |
| 245 if (!page_actions.empty()) { | 263 if (!page_actions.empty()) { |
| 246 page_action_map[extension_id] = page_actions; | 264 page_action_map[extension_id] = page_actions; |
| 247 } else { | 265 } else { |
| 248 if (page_action_map.find(extension_id) != page_action_map.end()) | 266 if (page_action_map.find(extension_id) != page_action_map.end()) |
| 249 page_action_map.erase(extension_id); | 267 page_action_map.erase(extension_id); |
| 250 } | 268 } |
| 251 } | 269 } |
| 270 |
| 271 // static |
| 272 void ExtensionProcessBindings::SetPermissions( |
| 273 const std::string& extension_id, |
| 274 const std::vector<std::string>& permissions) { |
| 275 PermissionsMap& permissions_map = *GetPermissionsMap(extension_id); |
| 276 |
| 277 // Default all permissions to false, then enable the ones in the vector. |
| 278 for (size_t i = 0; i < Extension::kNumPermissions; ++i) |
| 279 permissions_map[Extension::kPermissionNames[i]] = false; |
| 280 for (size_t i = 0; i < permissions.size(); ++i) |
| 281 permissions_map[permissions[i]] = true; |
| 282 } |
| 283 |
| 284 // Given a name like "tabs.onConnect", return the permission name required |
| 285 // to access that API ("tabs" in this example). |
| 286 static std::string GetPermissionName(const std::string& function_name) { |
| 287 size_t first_dot = function_name.find('.'); |
| 288 std::string permission_name = function_name.substr(0, first_dot); |
| 289 if (permission_name == "windows") |
| 290 return "tabs"; // windows and tabs are the same permission. |
| 291 return permission_name; |
| 292 } |
| 293 |
| 294 // static |
| 295 bool ExtensionProcessBindings::CurrentContextHasPermission( |
| 296 const std::string& function_name) { |
| 297 std::string extension_id = ExtensionImpl::ExtensionIdForCurrentContext(); |
| 298 PermissionsMap& permissions_map = *GetPermissionsMap(extension_id); |
| 299 std::string permission_name = GetPermissionName(function_name); |
| 300 PermissionsMap::iterator it = permissions_map.find(permission_name); |
| 301 |
| 302 // We explicitly check if the permission entry is present and false, because |
| 303 // some APIs do not have a required permission entry (ie, "chrome.self"). |
| 304 return (it == permissions_map.end() || it->second); |
| 305 } |
| 306 |
| 307 // static |
| 308 v8::Handle<v8::Value> |
| 309 ExtensionProcessBindings::ThrowPermissionDeniedException( |
| 310 const std::string& function_name) { |
| 311 static const char kMessage[] = |
| 312 "You do not have permission to use 'chrome.%s'. Be sure to declare" |
| 313 " in your manifest what permissions you need."; |
| 314 std::string permission_name = GetPermissionName(function_name); |
| 315 std::string error_msg = StringPrintf(kMessage, permission_name.c_str()); |
| 316 |
| 317 #if EXTENSION_TIME_TO_BREAK_API |
| 318 return v8::ThrowException(v8::Exception::Error( |
| 319 v8::String::New(error_msg.c_str()))); |
| 320 #else |
| 321 // Call console.error for now. |
| 322 |
| 323 v8::HandleScope scope; |
| 324 |
| 325 v8::Local<v8::Value> console = |
| 326 v8::Context::GetCurrent()->Global()->Get(v8::String::New("console")); |
| 327 v8::Local<v8::Value> console_error; |
| 328 if (!console.IsEmpty() && console->IsObject()) |
| 329 console_error = console->ToObject()->Get(v8::String::New("error")); |
| 330 if (console_error.IsEmpty() || !console_error->IsFunction()) |
| 331 return v8::Undefined(); |
| 332 |
| 333 v8::Local<v8::Function> function = |
| 334 v8::Local<v8::Function>::Cast(console_error); |
| 335 v8::Local<v8::Value> argv[] = { v8::String::New(error_msg.c_str()) }; |
| 336 if (!function.IsEmpty()) |
| 337 function->Call(console->ToObject(), arraysize(argv), argv); |
| 338 |
| 339 return v8::Undefined(); |
| 340 #endif |
| 341 } |
| OLD | NEW |