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.
4
5#include "chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.h"
6
7#include "base/command_line.h"
8#include "base/sha1.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/automation_internal_custom_bindings.h"
18#include "chrome/renderer/extensions/chrome_v8_context.h"
19#include "chrome/renderer/extensions/enterprise_platform_keys_natives.h"
20#include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
21#include "chrome/renderer/extensions/file_manager_private_custom_bindings.h"
22#include "chrome/renderer/extensions/media_galleries_custom_bindings.h"
23#include "chrome/renderer/extensions/notifications_native_handler.h"
24#include "chrome/renderer/extensions/page_capture_custom_bindings.h"
25#include "chrome/renderer/extensions/sync_file_system_custom_bindings.h"
26#include "chrome/renderer/extensions/tab_finder.h"
27#include "chrome/renderer/extensions/tabs_custom_bindings.h"
28#include "chrome/renderer/extensions/webstore_bindings.h"
29#include "content/public/renderer/render_thread.h"
30#include "content/public/renderer/render_view.h"
31#include "extensions/common/extension.h"
32#include "extensions/common/feature_switch.h"
33#include "extensions/common/permissions/api_permission_set.h"
34#include "extensions/common/permissions/manifest_permission_set.h"
35#include "extensions/common/permissions/permission_set.h"
36#include "extensions/common/permissions/permissions_data.h"
37#include "extensions/common/switches.h"
38#include "extensions/common/url_pattern_set.h"
39#include "extensions/renderer/dispatcher.h"
40#include "extensions/renderer/native_handler.h"
41#include "extensions/renderer/resource_bundle_source_map.h"
42#include "extensions/renderer/script_context.h"
43#include "third_party/WebKit/public/platform/WebString.h"
44#include "third_party/WebKit/public/web/WebDocument.h"
45#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
46#include "third_party/WebKit/public/web/WebView.h"
47
48#if defined(ENABLE_WEBRTC)
49#include "chrome/renderer/extensions/cast_streaming_native_handler.h"
50#endif
51
52using extensions::NativeHandler;
53
54ChromeExtensionsDispatcherDelegate::ChromeExtensionsDispatcherDelegate() {
55}
56
57ChromeExtensionsDispatcherDelegate::~ChromeExtensionsDispatcherDelegate() {
58}
59
60scoped_ptr<extensions::ScriptContext>
61ChromeExtensionsDispatcherDelegate::CreateScriptContext(
62    const v8::Handle<v8::Context>& v8_context,
63    blink::WebFrame* frame,
64    const extensions::Extension* extension,
65    extensions::Feature::Context context_type,
66    const extensions::Extension* effective_extension,
67    extensions::Feature::Context effective_context_type) {
68  return scoped_ptr<extensions::ScriptContext>(
69      new extensions::ChromeV8Context(v8_context,
70                                      frame,
71                                      extension,
72                                      context_type,
73                                      effective_extension,
74                                      effective_context_type));
75}
76
77void ChromeExtensionsDispatcherDelegate::InitOriginPermissions(
78    const extensions::Extension* extension,
79    bool is_extension_active) {
80  // TODO(jstritar): We should try to remove this special case. Also, these
81  // whitelist entries need to be updated when the kManagement permission
82  // changes.
83  if (is_extension_active &&
84      extension->permissions_data()->HasAPIPermission(
85          extensions::APIPermission::kManagement)) {
86    blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(
87        extension->url(),
88        blink::WebString::fromUTF8(content::kChromeUIScheme),
89        blink::WebString::fromUTF8(chrome::kChromeUIExtensionIconHost),
90        false);
91  }
92}
93
94void ChromeExtensionsDispatcherDelegate::RegisterNativeHandlers(
95    extensions::Dispatcher* dispatcher,
96    extensions::ModuleSystem* module_system,
97    extensions::ScriptContext* context) {
98#if !defined(ENABLE_EXTENSIONS)
99  return;
100#endif
101  module_system->RegisterNativeHandler(
102      "app",
103      scoped_ptr<NativeHandler>(
104          new extensions::AppBindings(dispatcher, context)));
105  module_system->RegisterNativeHandler(
106      "sync_file_system",
107      scoped_ptr<NativeHandler>(
108          new extensions::SyncFileSystemCustomBindings(context)));
109  module_system->RegisterNativeHandler(
110      "enterprise_platform_keys_natives",
111      scoped_ptr<NativeHandler>(
112          new extensions::EnterprisePlatformKeysNatives(context)));
113  module_system->RegisterNativeHandler(
114      "file_browser_handler",
115      scoped_ptr<NativeHandler>(
116          new extensions::FileBrowserHandlerCustomBindings(context)));
117  module_system->RegisterNativeHandler(
118      "file_manager_private",
119      scoped_ptr<NativeHandler>(
120          new extensions::FileManagerPrivateCustomBindings(context)));
121  module_system->RegisterNativeHandler(
122      "notifications_private",
123      scoped_ptr<NativeHandler>(
124          new extensions::NotificationsNativeHandler(context)));
125  module_system->RegisterNativeHandler(
126      "mediaGalleries",
127      scoped_ptr<NativeHandler>(
128          new extensions::MediaGalleriesCustomBindings(context)));
129  module_system->RegisterNativeHandler(
130      "page_capture",
131      scoped_ptr<NativeHandler>(
132          new extensions::PageCaptureCustomBindings(context)));
133  module_system->RegisterNativeHandler(
134      "tabs",
135      scoped_ptr<NativeHandler>(new extensions::TabsCustomBindings(context)));
136  module_system->RegisterNativeHandler(
137      "webstore",
138      scoped_ptr<NativeHandler>(new extensions::WebstoreBindings(context)));
139#if defined(ENABLE_WEBRTC)
140  module_system->RegisterNativeHandler(
141      "cast_streaming_natives",
142      scoped_ptr<NativeHandler>(
143          new extensions::CastStreamingNativeHandler(context)));
144#endif
145  module_system->RegisterNativeHandler(
146      "automationInternal",
147      scoped_ptr<NativeHandler>(
148          new extensions::AutomationInternalCustomBindings(context)));
149}
150
151void ChromeExtensionsDispatcherDelegate::PopulateSourceMap(
152    extensions::ResourceBundleSourceMap* source_map) {
153  // Custom bindings.
154  source_map->RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
155  source_map->RegisterSource("automation", IDR_AUTOMATION_CUSTOM_BINDINGS_JS);
156  source_map->RegisterSource("automationEvent", IDR_AUTOMATION_EVENT_JS);
157  source_map->RegisterSource("automationNode", IDR_AUTOMATION_NODE_JS);
158  source_map->RegisterSource("browserAction",
159                             IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
160  source_map->RegisterSource("declarativeContent",
161                             IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS);
162  source_map->RegisterSource("desktopCapture",
163                             IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS);
164  source_map->RegisterSource("developerPrivate",
165                             IDR_DEVELOPER_PRIVATE_CUSTOM_BINDINGS_JS);
166  source_map->RegisterSource("downloads", IDR_DOWNLOADS_CUSTOM_BINDINGS_JS);
167  source_map->RegisterSource("enterprise.platformKeys",
168                             IDR_ENTERPRISE_PLATFORM_KEYS_CUSTOM_BINDINGS_JS);
169  source_map->RegisterSource("enterprise.platformKeys.internalAPI",
170                             IDR_ENTERPRISE_PLATFORM_KEYS_INTERNAL_API_JS);
171  source_map->RegisterSource("enterprise.platformKeys.Key",
172                             IDR_ENTERPRISE_PLATFORM_KEYS_KEY_JS);
173  source_map->RegisterSource("enterprise.platformKeys.KeyPair",
174                             IDR_ENTERPRISE_PLATFORM_KEYS_KEY_PAIR_JS);
175  source_map->RegisterSource("enterprise.platformKeys.SubtleCrypto",
176                             IDR_ENTERPRISE_PLATFORM_KEYS_SUBTLE_CRYPTO_JS);
177  source_map->RegisterSource("enterprise.platformKeys.Token",
178                             IDR_ENTERPRISE_PLATFORM_KEYS_TOKEN_JS);
179  source_map->RegisterSource("enterprise.platformKeys.utils",
180                             IDR_ENTERPRISE_PLATFORM_KEYS_UTILS_JS);
181  source_map->RegisterSource("feedbackPrivate",
182                             IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS);
183  source_map->RegisterSource("fileBrowserHandler",
184                             IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
185  source_map->RegisterSource("fileManagerPrivate",
186                             IDR_FILE_MANAGER_PRIVATE_CUSTOM_BINDINGS_JS);
187  source_map->RegisterSource("fileSystem", IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
188  source_map->RegisterSource("fileSystemProvider",
189                             IDR_FILE_SYSTEM_PROVIDER_CUSTOM_BINDINGS_JS);
190  source_map->RegisterSource("gcm", IDR_GCM_CUSTOM_BINDINGS_JS);
191  source_map->RegisterSource("identity", IDR_IDENTITY_CUSTOM_BINDINGS_JS);
192  source_map->RegisterSource("imageWriterPrivate",
193                             IDR_IMAGE_WRITER_PRIVATE_CUSTOM_BINDINGS_JS);
194  source_map->RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
195  source_map->RegisterSource("logPrivate", IDR_LOG_PRIVATE_CUSTOM_BINDINGS_JS);
196  source_map->RegisterSource("mediaGalleries",
197                             IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS);
198  source_map->RegisterSource("notifications",
199                             IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS);
200  source_map->RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
201  source_map->RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
202  source_map->RegisterSource("pageCapture",
203                             IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
204  source_map->RegisterSource("syncFileSystem",
205                             IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
206  source_map->RegisterSource("systemIndicator",
207                             IDR_SYSTEM_INDICATOR_CUSTOM_BINDINGS_JS);
208  source_map->RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS);
209  source_map->RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS);
210  source_map->RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS);
211  source_map->RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
212#if defined(ENABLE_WEBRTC)
213  source_map->RegisterSource("cast.streaming.rtpStream",
214                             IDR_CAST_STREAMING_RTP_STREAM_CUSTOM_BINDINGS_JS);
215  source_map->RegisterSource("cast.streaming.session",
216                             IDR_CAST_STREAMING_SESSION_CUSTOM_BINDINGS_JS);
217  source_map->RegisterSource(
218      "cast.streaming.udpTransport",
219      IDR_CAST_STREAMING_UDP_TRANSPORT_CUSTOM_BINDINGS_JS);
220#endif
221  source_map->RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
222
223  // Custom types sources.
224  source_map->RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
225  source_map->RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
226  source_map->RegisterSource("ChromeDirectSetting",
227                             IDR_CHROME_DIRECT_SETTING_JS);
228
229  // Platform app sources that are not API-specific..
230  source_map->RegisterSource("appView", IDR_APP_VIEW_JS);
231  source_map->RegisterSource("fileEntryBindingUtil",
232                             IDR_FILE_ENTRY_BINDING_UTIL_JS);
233  source_map->RegisterSource("extensionOptions", IDR_EXTENSION_OPTIONS_JS);
234  source_map->RegisterSource("extensionOptionsEvents",
235                             IDR_EXTENSION_OPTIONS_EVENTS_JS);
236  source_map->RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS);
237  source_map->RegisterSource("chromeWebViewInternal",
238                             IDR_CHROME_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS);
239  source_map->RegisterSource("chromeWebView", IDR_CHROME_WEB_VIEW_JS);
240  source_map->RegisterSource("chromeWebViewExperimental",
241                             IDR_CHROME_WEB_VIEW_EXPERIMENTAL_JS);
242  source_map->RegisterSource("webViewRequest",
243                             IDR_WEB_VIEW_REQUEST_CUSTOM_BINDINGS_JS);
244  source_map->RegisterSource("denyAppView", IDR_APP_VIEW_DENY_JS);
245  source_map->RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS);
246}
247
248void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
249    extensions::ScriptContext* context,
250    bool is_within_platform_app) {
251  extensions::ModuleSystem* module_system = context->module_system();
252  extensions::Feature::Context context_type = context->context_type();
253
254  // TODO(kalman, fsamuel): Eagerly calling Require on context startup is
255  // expensive. It would be better if there were a light way of detecting when
256  // a webview or appview is created and only then set up the infrastructure.
257  if (context_type == extensions::Feature::BLESSED_EXTENSION_CONTEXT &&
258      is_within_platform_app &&
259      extensions::GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV &&
260      CommandLine::ForCurrentProcess()->HasSwitch(
261          extensions::switches::kEnableAppWindowControls)) {
262    module_system->Require("windowControls");
263  }
264
265  // Note: setting up the WebView class here, not the chrome.webview API.
266  // The API will be automatically set up when first used.
267  if (context->GetAvailability("webViewInternal").is_available()) {
268    module_system->Require("chromeWebView");
269    if (context->GetAvailability("webViewExperimentalInternal")
270            .is_available()) {
271      module_system->Require("chromeWebViewExperimental");
272    }
273  }
274
275  if (extensions::FeatureSwitch::app_view()->IsEnabled() &&
276      context->GetAvailability("appViewEmbedderInternal").is_available()) {
277    module_system->Require("appView");
278  } else if (context_type == extensions::Feature::BLESSED_EXTENSION_CONTEXT) {
279    module_system->Require("denyAppView");
280  }
281
282  if (extensions::FeatureSwitch::embedded_extension_options()->IsEnabled() &&
283      context->GetAvailability("extensionOptionsInternal").is_available()) {
284    module_system->Require("extensionOptions");
285  }
286}
287
288void ChromeExtensionsDispatcherDelegate::OnActiveExtensionsUpdated(
289    const std::set<std::string>& extension_ids) {
290  // In single-process mode, the browser process reports the active extensions.
291  if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kSingleProcess))
292    return;
293  crash_keys::SetActiveExtensions(extension_ids);
294}
295
296void ChromeExtensionsDispatcherDelegate::SetChannel(int channel) {
297  extensions::SetCurrentChannel(
298      static_cast<chrome::VersionInfo::Channel>(channel));
299}
300
301void ChromeExtensionsDispatcherDelegate::ClearTabSpecificPermissions(
302    const extensions::Dispatcher* dispatcher,
303    int tab_id,
304    const std::vector<std::string>& extension_ids) {
305  for (std::vector<std::string>::const_iterator it = extension_ids.begin();
306       it != extension_ids.end();
307       ++it) {
308    const extensions::Extension* extension =
309        dispatcher->extensions()->GetByID(*it);
310    if (extension)
311      extension->permissions_data()->ClearTabSpecificPermissions(tab_id);
312  }
313}
314
315void ChromeExtensionsDispatcherDelegate::UpdateTabSpecificPermissions(
316    const extensions::Dispatcher* dispatcher,
317    const GURL& url,
318    int tab_id,
319    const std::string& extension_id,
320    const extensions::URLPatternSet& origin_set) {
321  content::RenderView* view = extensions::TabFinder::Find(tab_id);
322
323  // For now, the message should only be sent to the render view that contains
324  // the target tab. This may change. Either way, if this is the target tab it
325  // gives us the chance to check against the URL to avoid races.
326  DCHECK(view);
327  GURL active_url(view->GetWebView()->mainFrame()->document().url());
328  if (active_url != url)
329    return;
330
331  const extensions::Extension* extension =
332      dispatcher->extensions()->GetByID(extension_id);
333  if (!extension)
334    return;
335
336  extension->permissions_data()->UpdateTabSpecificPermissions(
337      tab_id,
338      new extensions::PermissionSet(extensions::APIPermissionSet(),
339                                    extensions::ManifestPermissionSet(),
340                                    origin_set,
341                                    extensions::URLPatternSet()));
342}
343