1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.h"
7 #include "base/command_line.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "chrome/common/chrome_switches.h"
11 #include "chrome/common/chrome_version_info.h"
12 #include "chrome/common/crash_keys.h"
13 #include "chrome/common/extensions/features/feature_channel.h"
14 #include "chrome/common/url_constants.h"
15 #include "chrome/grit/renderer_resources.h"
16 #include "chrome/renderer/extensions/app_bindings.h"
17 #include "chrome/renderer/extensions/app_window_custom_bindings.h"
18 #include "chrome/renderer/extensions/automation_internal_custom_bindings.h"
19 #include "chrome/renderer/extensions/chrome_v8_context.h"
20 #include "chrome/renderer/extensions/enterprise_platform_keys_natives.h"
21 #include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
22 #include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
23 #include "chrome/renderer/extensions/media_galleries_custom_bindings.h"
24 #include "chrome/renderer/extensions/notifications_native_handler.h"
25 #include "chrome/renderer/extensions/page_actions_custom_bindings.h"
26 #include "chrome/renderer/extensions/page_capture_custom_bindings.h"
27 #include "chrome/renderer/extensions/sync_file_system_custom_bindings.h"
28 #include "chrome/renderer/extensions/tab_finder.h"
29 #include "chrome/renderer/extensions/tabs_custom_bindings.h"
30 #include "chrome/renderer/extensions/webstore_bindings.h"
31 #include "content/public/renderer/render_thread.h"
32 #include "content/public/renderer/render_view.h"
33 #include "extensions/common/extension.h"
34 #include "extensions/common/feature_switch.h"
35 #include "extensions/common/permissions/api_permission_set.h"
36 #include "extensions/common/permissions/manifest_permission_set.h"
37 #include "extensions/common/permissions/permission_set.h"
38 #include "extensions/common/permissions/permissions_data.h"
39 #include "extensions/common/url_pattern_set.h"
40 #include "extensions/renderer/dispatcher.h"
41 #include "extensions/renderer/native_handler.h"
42 #include "extensions/renderer/resource_bundle_source_map.h"
43 #include "extensions/renderer/script_context.h"
44 #include "third_party/WebKit/public/platform/WebString.h"
45 #include "third_party/WebKit/public/web/WebDocument.h"
46 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
47 #include "third_party/WebKit/public/web/WebView.h"
49 #if defined(ENABLE_WEBRTC)
50 #include "chrome/renderer/extensions/cast_streaming_native_handler.h"
53 using extensions::NativeHandler
;
55 ChromeExtensionsDispatcherDelegate::ChromeExtensionsDispatcherDelegate()
56 : webrequest_used_(false) {
59 ChromeExtensionsDispatcherDelegate::~ChromeExtensionsDispatcherDelegate() {
62 scoped_ptr
<extensions::ScriptContext
>
63 ChromeExtensionsDispatcherDelegate::CreateScriptContext(
64 const v8::Handle
<v8::Context
>& v8_context
,
65 blink::WebFrame
* frame
,
66 const extensions::Extension
* extension
,
67 extensions::Feature::Context context_type
) {
68 return scoped_ptr
<extensions::ScriptContext
>(new extensions::ChromeV8Context(
69 v8_context
, frame
, extension
, context_type
));
72 void ChromeExtensionsDispatcherDelegate::InitOriginPermissions(
73 const extensions::Extension
* extension
,
74 bool is_extension_active
) {
75 // TODO(jstritar): We should try to remove this special case. Also, these
76 // whitelist entries need to be updated when the kManagement permission
78 if (is_extension_active
&&
79 extension
->permissions_data()->HasAPIPermission(
80 extensions::APIPermission::kManagement
)) {
81 blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(
83 blink::WebString::fromUTF8(content::kChromeUIScheme
),
84 blink::WebString::fromUTF8(chrome::kChromeUIExtensionIconHost
),
89 void ChromeExtensionsDispatcherDelegate::RegisterNativeHandlers(
90 extensions::Dispatcher
* dispatcher
,
91 extensions::ModuleSystem
* module_system
,
92 extensions::ScriptContext
* context
) {
93 #if !defined(ENABLE_EXTENSIONS)
96 module_system
->RegisterNativeHandler(
98 scoped_ptr
<NativeHandler
>(
99 new extensions::AppBindings(dispatcher
, context
)));
100 module_system
->RegisterNativeHandler(
101 "app_window_natives",
102 scoped_ptr
<NativeHandler
>(
103 new extensions::AppWindowCustomBindings(dispatcher
, context
)));
104 module_system
->RegisterNativeHandler(
106 scoped_ptr
<NativeHandler
>(
107 new extensions::SyncFileSystemCustomBindings(context
)));
108 module_system
->RegisterNativeHandler(
109 "enterprise_platform_keys_natives",
110 scoped_ptr
<NativeHandler
>(
111 new extensions::EnterprisePlatformKeysNatives(context
)));
112 module_system
->RegisterNativeHandler(
113 "file_browser_handler",
114 scoped_ptr
<NativeHandler
>(
115 new extensions::FileBrowserHandlerCustomBindings(context
)));
116 module_system
->RegisterNativeHandler(
117 "file_browser_private",
118 scoped_ptr
<NativeHandler
>(
119 new extensions::FileBrowserPrivateCustomBindings(context
)));
120 module_system
->RegisterNativeHandler(
121 "notifications_private",
122 scoped_ptr
<NativeHandler
>(
123 new extensions::NotificationsNativeHandler(context
)));
124 module_system
->RegisterNativeHandler(
126 scoped_ptr
<NativeHandler
>(
127 new extensions::MediaGalleriesCustomBindings(context
)));
128 module_system
->RegisterNativeHandler(
130 scoped_ptr
<NativeHandler
>(
131 new extensions::PageActionsCustomBindings(dispatcher
, context
)));
132 module_system
->RegisterNativeHandler(
134 scoped_ptr
<NativeHandler
>(
135 new extensions::PageCaptureCustomBindings(context
)));
136 module_system
->RegisterNativeHandler(
138 scoped_ptr
<NativeHandler
>(new extensions::TabsCustomBindings(context
)));
139 module_system
->RegisterNativeHandler(
141 scoped_ptr
<NativeHandler
>(new extensions::WebstoreBindings(context
)));
142 #if defined(ENABLE_WEBRTC)
143 module_system
->RegisterNativeHandler(
144 "cast_streaming_natives",
145 scoped_ptr
<NativeHandler
>(
146 new extensions::CastStreamingNativeHandler(context
)));
148 module_system
->RegisterNativeHandler(
149 "automationInternal",
150 scoped_ptr
<NativeHandler
>(
151 new extensions::AutomationInternalCustomBindings(context
)));
154 void ChromeExtensionsDispatcherDelegate::PopulateSourceMap(
155 extensions::ResourceBundleSourceMap
* source_map
) {
157 source_map
->RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS
);
158 source_map
->RegisterSource("app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS
);
159 source_map
->RegisterSource("automation", IDR_AUTOMATION_CUSTOM_BINDINGS_JS
);
160 source_map
->RegisterSource("automationEvent", IDR_AUTOMATION_EVENT_JS
);
161 source_map
->RegisterSource("automationNode", IDR_AUTOMATION_NODE_JS
);
162 source_map
->RegisterSource("browserAction",
163 IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS
);
164 source_map
->RegisterSource("declarativeContent",
165 IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS
);
166 source_map
->RegisterSource("declarativeWebRequest",
167 IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS
);
168 source_map
->RegisterSource("desktopCapture",
169 IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS
);
170 source_map
->RegisterSource("developerPrivate",
171 IDR_DEVELOPER_PRIVATE_CUSTOM_BINDINGS_JS
);
172 source_map
->RegisterSource("downloads", IDR_DOWNLOADS_CUSTOM_BINDINGS_JS
);
173 source_map
->RegisterSource("enterprise.platformKeys",
174 IDR_ENTERPRISE_PLATFORM_KEYS_CUSTOM_BINDINGS_JS
);
175 source_map
->RegisterSource("enterprise.platformKeys.internalAPI",
176 IDR_ENTERPRISE_PLATFORM_KEYS_INTERNAL_API_JS
);
177 source_map
->RegisterSource("enterprise.platformKeys.Key",
178 IDR_ENTERPRISE_PLATFORM_KEYS_KEY_JS
);
179 source_map
->RegisterSource("enterprise.platformKeys.KeyPair",
180 IDR_ENTERPRISE_PLATFORM_KEYS_KEY_PAIR_JS
);
181 source_map
->RegisterSource("enterprise.platformKeys.SubtleCrypto",
182 IDR_ENTERPRISE_PLATFORM_KEYS_SUBTLE_CRYPTO_JS
);
183 source_map
->RegisterSource("enterprise.platformKeys.Token",
184 IDR_ENTERPRISE_PLATFORM_KEYS_TOKEN_JS
);
185 source_map
->RegisterSource("enterprise.platformKeys.utils",
186 IDR_ENTERPRISE_PLATFORM_KEYS_UTILS_JS
);
187 source_map
->RegisterSource("feedbackPrivate",
188 IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS
);
189 source_map
->RegisterSource("fileBrowserHandler",
190 IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS
);
191 source_map
->RegisterSource("fileBrowserPrivate",
192 IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS
);
193 source_map
->RegisterSource("fileSystem", IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS
);
194 source_map
->RegisterSource("fileSystemProvider",
195 IDR_FILE_SYSTEM_PROVIDER_CUSTOM_BINDINGS_JS
);
196 source_map
->RegisterSource("gcm", IDR_GCM_CUSTOM_BINDINGS_JS
);
197 source_map
->RegisterSource("identity", IDR_IDENTITY_CUSTOM_BINDINGS_JS
);
198 source_map
->RegisterSource("imageWriterPrivate",
199 IDR_IMAGE_WRITER_PRIVATE_CUSTOM_BINDINGS_JS
);
200 source_map
->RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS
);
201 source_map
->RegisterSource("logPrivate", IDR_LOG_PRIVATE_CUSTOM_BINDINGS_JS
);
202 source_map
->RegisterSource("mediaGalleries",
203 IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS
);
204 source_map
->RegisterSource("notifications",
205 IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS
);
206 source_map
->RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS
);
207 source_map
->RegisterSource("pageActions",
208 IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS
);
209 source_map
->RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS
);
210 source_map
->RegisterSource("pageCapture",
211 IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS
);
212 source_map
->RegisterSource("syncFileSystem",
213 IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS
);
214 source_map
->RegisterSource("systemIndicator",
215 IDR_SYSTEM_INDICATOR_CUSTOM_BINDINGS_JS
);
216 source_map
->RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS
);
217 source_map
->RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS
);
218 source_map
->RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS
);
219 source_map
->RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS
);
220 source_map
->RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS
);
221 source_map
->RegisterSource("webRequestInternal",
222 IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS
);
223 #if defined(ENABLE_WEBRTC)
224 source_map
->RegisterSource("cast.streaming.rtpStream",
225 IDR_CAST_STREAMING_RTP_STREAM_CUSTOM_BINDINGS_JS
);
226 source_map
->RegisterSource("cast.streaming.session",
227 IDR_CAST_STREAMING_SESSION_CUSTOM_BINDINGS_JS
);
228 source_map
->RegisterSource(
229 "cast.streaming.udpTransport",
230 IDR_CAST_STREAMING_UDP_TRANSPORT_CUSTOM_BINDINGS_JS
);
232 source_map
->RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS
);
233 source_map
->RegisterSource("windowControls", IDR_WINDOW_CONTROLS_JS
);
235 // Custom types sources.
236 source_map
->RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS
);
237 source_map
->RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS
);
238 source_map
->RegisterSource("ChromeDirectSetting",
239 IDR_CHROME_DIRECT_SETTING_JS
);
241 // Platform app sources that are not API-specific..
242 source_map
->RegisterSource("appView", IDR_APP_VIEW_JS
);
243 source_map
->RegisterSource("fileEntryBindingUtil",
244 IDR_FILE_ENTRY_BINDING_UTIL_JS
);
245 source_map
->RegisterSource("extensionOptions", IDR_EXTENSION_OPTIONS_JS
);
246 source_map
->RegisterSource("extensionOptionsEvents",
247 IDR_EXTENSION_OPTIONS_EVENTS_JS
);
248 source_map
->RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS
);
249 source_map
->RegisterSource("webViewInternal",
250 IDR_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS
);
251 // Note: webView not webview so that this doesn't interfere with the
252 // chrome.webview API bindings.
253 source_map
->RegisterSource("webView", IDR_WEB_VIEW_JS
);
254 source_map
->RegisterSource("webViewEvents", IDR_WEB_VIEW_EVENTS_JS
);
255 source_map
->RegisterSource("webViewExperimental",
256 IDR_WEB_VIEW_EXPERIMENTAL_JS
);
257 source_map
->RegisterSource("webViewRequest",
258 IDR_WEB_VIEW_REQUEST_CUSTOM_BINDINGS_JS
);
259 source_map
->RegisterSource("denyAppView", IDR_APP_VIEW_DENY_JS
);
260 source_map
->RegisterSource("denyWebView", IDR_WEB_VIEW_DENY_JS
);
261 source_map
->RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS
);
264 void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
265 extensions::ScriptContext
* context
,
266 bool is_within_platform_app
) {
267 extensions::ModuleSystem
* module_system
= context
->module_system();
268 extensions::Feature::Context context_type
= context
->context_type();
270 // TODO(kalman, fsamuel): Eagerly calling Require on context startup is
271 // expensive. It would be better if there were a light way of detecting when
272 // a webview or appview is created and only then set up the infrastructure.
273 if (context_type
== extensions::Feature::BLESSED_EXTENSION_CONTEXT
&&
274 is_within_platform_app
&&
275 extensions::GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV
&&
276 CommandLine::ForCurrentProcess()->HasSwitch(
277 ::switches::kEnableAppWindowControls
)) {
278 module_system
->Require("windowControls");
281 const extensions::Extension
* extension
= context
->extension();
283 // We used to limit WebView to |BLESSED_EXTENSION_CONTEXT| within platform
284 // apps. An ext/app runs in a blessed extension context, if it is the active
285 // extension in the current process, in other words, if it is loaded in a top
286 // frame. To support webview in a non-frame extension, we have to allow
287 // unblessed extension context as well.
288 // Note: setting up the WebView class here, not the chrome.webview API.
289 // The API will be automatically set up when first used.
290 if (context_type
== extensions::Feature::BLESSED_EXTENSION_CONTEXT
||
291 context_type
== extensions::Feature::UNBLESSED_EXTENSION_CONTEXT
) {
292 // TODO(fsamuel): Use context->GetAvailability("webViewInternal").
293 if (extension
->permissions_data()->HasAPIPermission(
294 extensions::APIPermission::kWebView
)) {
295 module_system
->Require("webView");
296 if (extensions::GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV
) {
297 module_system
->Require("webViewExperimental");
299 // TODO(asargent) We need a whitelist for webview experimental.
301 std::string id_hash
= base::SHA1HashString(extension
->id());
302 std::string hexencoded_id_hash
=
303 base::HexEncode(id_hash
.c_str(), id_hash
.length());
304 if (hexencoded_id_hash
== "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578" ||
305 hexencoded_id_hash
== "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB" ||
306 hexencoded_id_hash
== "1A26E32DE447A17CBE5E9750CDBA78F58539B39C" ||
307 hexencoded_id_hash
== "59048028102D7B4C681DBC7BC6CD980C3DC66DA3") {
308 module_system
->Require("webViewExperimental");
312 module_system
->Require("denyWebView");
316 if (context_type
== extensions::Feature::BLESSED_EXTENSION_CONTEXT
) {
317 // TODO(fsamuel): Use context->GetAvailability("appViewInternal").
318 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAppView
) &&
319 extension
->permissions_data()->HasAPIPermission(
320 extensions::APIPermission::kAppView
)) {
321 module_system
->Require("appView");
323 module_system
->Require("denyAppView");
327 if (extensions::FeatureSwitch::embedded_extension_options()->IsEnabled() &&
328 context
->GetAvailability("extensionOptionsInternal").is_available()) {
329 module_system
->Require("extensionOptions");
333 void ChromeExtensionsDispatcherDelegate::OnActiveExtensionsUpdated(
334 const std::set
<std::string
>& extension_ids
) {
335 // In single-process mode, the browser process reports the active extensions.
336 if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kSingleProcess
))
338 crash_keys::SetActiveExtensions(extension_ids
);
341 void ChromeExtensionsDispatcherDelegate::SetChannel(int channel
) {
342 extensions::SetCurrentChannel(
343 static_cast<chrome::VersionInfo::Channel
>(channel
));
346 void ChromeExtensionsDispatcherDelegate::ClearTabSpecificPermissions(
347 const extensions::Dispatcher
* dispatcher
,
349 const std::vector
<std::string
>& extension_ids
) {
350 for (std::vector
<std::string
>::const_iterator it
= extension_ids
.begin();
351 it
!= extension_ids
.end();
353 const extensions::Extension
* extension
=
354 dispatcher
->extensions()->GetByID(*it
);
356 extension
->permissions_data()->ClearTabSpecificPermissions(tab_id
);
360 void ChromeExtensionsDispatcherDelegate::UpdateTabSpecificPermissions(
361 const extensions::Dispatcher
* dispatcher
,
364 const std::string
& extension_id
,
365 const extensions::URLPatternSet
& origin_set
) {
366 content::RenderView
* view
= extensions::TabFinder::Find(tab_id
);
368 // For now, the message should only be sent to the render view that contains
369 // the target tab. This may change. Either way, if this is the target tab it
370 // gives us the chance to check against the URL to avoid races.
372 GURL
active_url(view
->GetWebView()->mainFrame()->document().url());
373 if (active_url
!= url
)
376 const extensions::Extension
* extension
=
377 dispatcher
->extensions()->GetByID(extension_id
);
381 extension
->permissions_data()->UpdateTabSpecificPermissions(
383 new extensions::PermissionSet(extensions::APIPermissionSet(),
384 extensions::ManifestPermissionSet(),
386 extensions::URLPatternSet()));
389 void ChromeExtensionsDispatcherDelegate::HandleWebRequestAPIUsage(
390 bool webrequest_used
) {
391 webrequest_used_
= webrequest_used
;