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