Home | History | Annotate | Download | only in extensions
      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 
     52 using extensions::NativeHandler;
     53 
     54 ChromeExtensionsDispatcherDelegate::ChromeExtensionsDispatcherDelegate() {
     55 }
     56 
     57 ChromeExtensionsDispatcherDelegate::~ChromeExtensionsDispatcherDelegate() {
     58 }
     59 
     60 scoped_ptr<extensions::ScriptContext>
     61 ChromeExtensionsDispatcherDelegate::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 
     77 void 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 
     94 void 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 
    151 void 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 
    248 void 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 
    288 void 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 
    296 void ChromeExtensionsDispatcherDelegate::SetChannel(int channel) {
    297   extensions::SetCurrentChannel(
    298       static_cast<chrome::VersionInfo::Channel>(channel));
    299 }
    300 
    301 void 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 
    315 void 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