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 |