renderer_client_base.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. // Copyright (c) 2017 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/renderer/renderer_client_base.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/command_line.h"
  10. #include "base/strings/string_split.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "components/network_hints/renderer/web_prescient_networking_impl.h"
  13. #include "content/common/buildflags.h"
  14. #include "content/public/common/content_constants.h"
  15. #include "content/public/common/content_switches.h"
  16. #include "content/public/renderer/render_frame.h"
  17. #include "content/public/renderer/render_thread.h"
  18. #include "content/public/renderer/render_view.h"
  19. #include "electron/buildflags/buildflags.h"
  20. #include "printing/buildflags/buildflags.h"
  21. #include "shell/common/color_util.h"
  22. #include "shell/common/gin_helper/dictionary.h"
  23. #include "shell/common/native_mate_converters/value_converter.h"
  24. #include "shell/common/options_switches.h"
  25. #include "shell/renderer/browser_exposed_renderer_interfaces.h"
  26. #include "shell/renderer/content_settings_observer.h"
  27. #include "shell/renderer/electron_api_service_impl.h"
  28. #include "shell/renderer/electron_autofill_agent.h"
  29. #include "shell/renderer/electron_render_frame_observer.h"
  30. #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
  31. #include "third_party/blink/public/web/blink.h"
  32. #include "third_party/blink/public/web/web_custom_element.h" // NOLINT(build/include_alpha)
  33. #include "third_party/blink/public/web/web_frame_widget.h"
  34. #include "third_party/blink/public/web/web_plugin_params.h"
  35. #include "third_party/blink/public/web/web_script_source.h"
  36. #include "third_party/blink/public/web/web_security_policy.h"
  37. #include "third_party/blink/public/web/web_view.h"
  38. #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" // nogncheck
  39. #if defined(OS_MACOSX)
  40. #include "base/strings/sys_string_conversions.h"
  41. #endif
  42. #if defined(OS_WIN)
  43. #include <shlobj.h>
  44. #endif
  45. #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  46. #include "components/spellcheck/renderer/spellcheck.h"
  47. #include "components/spellcheck/renderer/spellcheck_provider.h"
  48. #endif
  49. #if BUILDFLAG(ENABLE_PDF_VIEWER)
  50. #include "shell/common/electron_constants.h"
  51. #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
  52. #if BUILDFLAG(ENABLE_PEPPER_FLASH)
  53. #include "chrome/renderer/pepper/pepper_helper.h"
  54. #endif // BUILDFLAG(ENABLE_PEPPER_FLASH)
  55. #if BUILDFLAG(ENABLE_PRINTING)
  56. #include "components/printing/renderer/print_render_frame_helper.h"
  57. #include "printing/print_settings.h"
  58. #include "shell/renderer/printing/print_render_frame_helper_delegate.h"
  59. #endif // BUILDFLAG(ENABLE_PRINTING)
  60. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  61. #include "extensions/common/extensions_client.h"
  62. #include "extensions/renderer/dispatcher.h"
  63. #include "extensions/renderer/extension_frame_helper.h"
  64. #include "extensions/renderer/guest_view/extensions_guest_view_container.h"
  65. #include "extensions/renderer/guest_view/extensions_guest_view_container_dispatcher.h"
  66. #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h"
  67. #include "shell/common/extensions/electron_extensions_client.h"
  68. #include "shell/renderer/extensions/electron_extensions_renderer_client.h"
  69. #endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  70. namespace electron {
  71. namespace {
  72. std::vector<std::string> ParseSchemesCLISwitch(base::CommandLine* command_line,
  73. const char* switch_name) {
  74. std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name);
  75. return base::SplitString(custom_schemes, ",", base::TRIM_WHITESPACE,
  76. base::SPLIT_WANT_NONEMPTY);
  77. }
  78. } // namespace
  79. RendererClientBase::RendererClientBase() {
  80. auto* command_line = base::CommandLine::ForCurrentProcess();
  81. // Parse --standard-schemes=scheme1,scheme2
  82. std::vector<std::string> standard_schemes_list =
  83. ParseSchemesCLISwitch(command_line, switches::kStandardSchemes);
  84. for (const std::string& scheme : standard_schemes_list)
  85. url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITH_HOST);
  86. isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
  87. switches::kContextIsolation);
  88. // We rely on the unique process host id which is notified to the
  89. // renderer process via command line switch from the content layer,
  90. // if this switch is removed from the content layer for some reason,
  91. // we should define our own.
  92. DCHECK(command_line->HasSwitch(::switches::kRendererClientId));
  93. renderer_client_id_ =
  94. command_line->GetSwitchValueASCII(::switches::kRendererClientId);
  95. }
  96. RendererClientBase::~RendererClientBase() = default;
  97. void RendererClientBase::DidCreateScriptContext(
  98. v8::Handle<v8::Context> context,
  99. content::RenderFrame* render_frame) {
  100. // global.setHidden("contextId", `${processHostId}-${++next_context_id_}`)
  101. auto context_id = base::StringPrintf(
  102. "%s-%" PRId64, renderer_client_id_.c_str(), ++next_context_id_);
  103. gin_helper::Dictionary global(context->GetIsolate(), context->Global());
  104. global.SetHidden("contextId", context_id);
  105. #if BUILDFLAG(ENABLE_REMOTE_MODULE)
  106. auto* command_line = base::CommandLine::ForCurrentProcess();
  107. bool enableRemoteModule =
  108. command_line->HasSwitch(switches::kEnableRemoteModule);
  109. global.SetHidden("enableRemoteModule", enableRemoteModule);
  110. #endif
  111. }
  112. void RendererClientBase::AddRenderBindings(
  113. v8::Isolate* isolate,
  114. v8::Local<v8::Object> binding_object) {}
  115. void RendererClientBase::RenderThreadStarted() {
  116. auto* command_line = base::CommandLine::ForCurrentProcess();
  117. #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
  118. // On macOS, popup menus are rendered by the main process by default.
  119. // This causes problems in OSR, since when the popup is rendered separately,
  120. // it won't be captured in the rendered image.
  121. if (command_line->HasSwitch(options::kOffscreen)) {
  122. blink::WebView::SetUseExternalPopupMenus(false);
  123. }
  124. #endif
  125. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  126. auto* thread = content::RenderThread::Get();
  127. extensions_client_.reset(CreateExtensionsClient());
  128. extensions::ExtensionsClient::Set(extensions_client_.get());
  129. extensions_renderer_client_.reset(new ElectronExtensionsRendererClient);
  130. extensions::ExtensionsRendererClient::Set(extensions_renderer_client_.get());
  131. thread->AddObserver(extensions_renderer_client_->GetDispatcher());
  132. #endif
  133. #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  134. if (command_line->HasSwitch(switches::kEnableSpellcheck))
  135. spellcheck_ = std::make_unique<SpellCheck>(this);
  136. #endif
  137. blink::WebCustomElement::AddEmbedderCustomElementName("webview");
  138. blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin");
  139. WTF::String extension_scheme("chrome-extension");
  140. // Extension resources are HTTP-like and safe to expose to the fetch API. The
  141. // rules for the fetch API are consistent with XHR.
  142. blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(
  143. extension_scheme);
  144. // Extension resources, when loaded as the top-level document, should bypass
  145. // Blink's strict first-party origin checks.
  146. blink::SchemeRegistry::RegisterURLSchemeAsFirstPartyWhenTopLevel(
  147. extension_scheme);
  148. // In Chrome we should set extension's origins to match the pages they can
  149. // work on, but in Electron currently we just let extensions do anything.
  150. blink::SchemeRegistry::RegisterURLSchemeAsSecure(extension_scheme);
  151. blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
  152. extension_scheme);
  153. // Parse --secure-schemes=scheme1,scheme2
  154. std::vector<std::string> secure_schemes_list =
  155. ParseSchemesCLISwitch(command_line, switches::kSecureSchemes);
  156. for (const std::string& scheme : secure_schemes_list)
  157. blink::SchemeRegistry::RegisterURLSchemeAsSecure(
  158. WTF::String::FromUTF8(scheme.data(), scheme.length()));
  159. std::vector<std::string> fetch_enabled_schemes =
  160. ParseSchemesCLISwitch(command_line, switches::kFetchSchemes);
  161. for (const std::string& scheme : fetch_enabled_schemes) {
  162. blink::WebSecurityPolicy::RegisterURLSchemeAsSupportingFetchAPI(
  163. blink::WebString::FromASCII(scheme));
  164. }
  165. std::vector<std::string> service_worker_schemes =
  166. ParseSchemesCLISwitch(command_line, switches::kServiceWorkerSchemes);
  167. for (const std::string& scheme : service_worker_schemes)
  168. blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers(
  169. blink::WebString::FromASCII(scheme));
  170. std::vector<std::string> csp_bypassing_schemes =
  171. ParseSchemesCLISwitch(command_line, switches::kBypassCSPSchemes);
  172. for (const std::string& scheme : csp_bypassing_schemes)
  173. blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
  174. WTF::String::FromUTF8(scheme.data(), scheme.length()));
  175. // Allow file scheme to handle service worker by default.
  176. // FIXME(zcbenz): Can this be moved elsewhere?
  177. blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file");
  178. blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI("file");
  179. #if defined(OS_WIN)
  180. // Set ApplicationUserModelID in renderer process.
  181. base::string16 app_id =
  182. command_line->GetSwitchValueNative(switches::kAppUserModelId);
  183. if (!app_id.empty()) {
  184. SetCurrentProcessExplicitAppUserModelID(app_id.c_str());
  185. }
  186. #endif
  187. }
  188. void RendererClientBase::ExposeInterfacesToBrowser(mojo::BinderMap* binders) {
  189. // NOTE: Do not add binders directly within this method. Instead, modify the
  190. // definition of |ExposeElectronRendererInterfacesToBrowser()| to ensure
  191. // security review coverage.
  192. ExposeElectronRendererInterfacesToBrowser(this, binders);
  193. }
  194. void RendererClientBase::RenderFrameCreated(
  195. content::RenderFrame* render_frame) {
  196. #if defined(TOOLKIT_VIEWS)
  197. new AutofillAgent(render_frame,
  198. render_frame->GetAssociatedInterfaceRegistry());
  199. #endif
  200. #if BUILDFLAG(ENABLE_PEPPER_FLASH)
  201. new PepperHelper(render_frame);
  202. #endif
  203. new ContentSettingsObserver(render_frame);
  204. #if BUILDFLAG(ENABLE_PRINTING)
  205. new printing::PrintRenderFrameHelper(
  206. render_frame,
  207. std::make_unique<electron::PrintRenderFrameHelperDelegate>());
  208. #endif
  209. // Note: ElectronApiServiceImpl has to be created now to capture the
  210. // DidCreateDocumentElement event.
  211. auto* service = new ElectronApiServiceImpl(render_frame, this);
  212. render_frame->GetAssociatedInterfaceRegistry()->AddInterface(
  213. base::BindRepeating(&ElectronApiServiceImpl::BindTo,
  214. service->GetWeakPtr()));
  215. #if BUILDFLAG(ENABLE_PDF_VIEWER)
  216. // Allow access to file scheme from pdf viewer.
  217. blink::WebSecurityPolicy::AddOriginAccessWhitelistEntry(
  218. GURL(kPdfViewerUIOrigin), "file", "", true);
  219. #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
  220. content::RenderView* render_view = render_frame->GetRenderView();
  221. if (render_frame->IsMainFrame() && render_view) {
  222. blink::WebView* webview = render_view->GetWebView();
  223. if (webview) {
  224. base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
  225. if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview.
  226. webview->SetBaseBackgroundColor(SK_ColorTRANSPARENT);
  227. } else { // normal window.
  228. std::string name = cmd->GetSwitchValueASCII(switches::kBackgroundColor);
  229. SkColor color =
  230. name.empty() ? SK_ColorTRANSPARENT : ParseHexColor(name);
  231. webview->SetBaseBackgroundColor(color);
  232. }
  233. }
  234. }
  235. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  236. auto* dispatcher = extensions_renderer_client_->GetDispatcher();
  237. // ExtensionFrameHelper destroys itself when the RenderFrame is destroyed.
  238. new extensions::ExtensionFrameHelper(render_frame, dispatcher);
  239. dispatcher->OnRenderFrameCreated(render_frame);
  240. #endif
  241. #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  242. auto* command_line = base::CommandLine::ForCurrentProcess();
  243. if (command_line->HasSwitch(switches::kEnableSpellcheck))
  244. new SpellCheckProvider(render_frame, spellcheck_.get(), this);
  245. #endif
  246. }
  247. #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  248. void RendererClientBase::GetInterface(
  249. const std::string& interface_name,
  250. mojo::ScopedMessagePipeHandle interface_pipe) {
  251. // TODO(crbug.com/977637): Get rid of the use of this implementation of
  252. // |service_manager::LocalInterfaceProvider|. This was done only to avoid
  253. // churning spellcheck code while eliminating the "chrome" and
  254. // "chrome_renderer" services. Spellcheck is (and should remain) the only
  255. // consumer of this implementation.
  256. content::RenderThread::Get()->BindHostReceiver(
  257. mojo::GenericPendingReceiver(interface_name, std::move(interface_pipe)));
  258. }
  259. #endif
  260. void RendererClientBase::DidClearWindowObject(
  261. content::RenderFrame* render_frame) {
  262. // Make sure every page will get a script context created.
  263. render_frame->GetWebFrame()->ExecuteScript(blink::WebScriptSource("void 0"));
  264. }
  265. bool RendererClientBase::OverrideCreatePlugin(
  266. content::RenderFrame* render_frame,
  267. const blink::WebPluginParams& params,
  268. blink::WebPlugin** plugin) {
  269. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  270. if (params.mime_type.Utf8() == content::kBrowserPluginMimeType ||
  271. #if BUILDFLAG(ENABLE_PDF_VIEWER)
  272. params.mime_type.Utf8() == kPdfPluginMimeType ||
  273. #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
  274. command_line->HasSwitch(switches::kEnablePlugins))
  275. return false;
  276. *plugin = nullptr;
  277. return true;
  278. }
  279. void RendererClientBase::AddSupportedKeySystems(
  280. std::vector<std::unique_ptr<::media::KeySystemProperties>>* key_systems) {
  281. #if defined(WIDEVINE_CDM_AVAILABLE)
  282. key_systems_provider_.AddSupportedKeySystems(key_systems);
  283. #endif
  284. }
  285. bool RendererClientBase::IsKeySystemsUpdateNeeded() {
  286. #if defined(WIDEVINE_CDM_AVAILABLE)
  287. return key_systems_provider_.IsKeySystemsUpdateNeeded();
  288. #else
  289. return false;
  290. #endif
  291. }
  292. void RendererClientBase::DidSetUserAgent(const std::string& user_agent) {
  293. #if BUILDFLAG(ENABLE_PRINTING)
  294. printing::SetAgent(user_agent);
  295. #endif
  296. }
  297. std::unique_ptr<blink::WebPrescientNetworking>
  298. RendererClientBase::CreatePrescientNetworking(
  299. content::RenderFrame* render_frame) {
  300. return std::make_unique<network_hints::WebPrescientNetworkingImpl>(
  301. render_frame);
  302. }
  303. void RendererClientBase::RunScriptsAtDocumentStart(
  304. content::RenderFrame* render_frame) {
  305. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  306. extensions_renderer_client_.get()->RunScriptsAtDocumentStart(render_frame);
  307. #endif
  308. }
  309. void RendererClientBase::RunScriptsAtDocumentIdle(
  310. content::RenderFrame* render_frame) {
  311. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  312. extensions_renderer_client_.get()->RunScriptsAtDocumentIdle(render_frame);
  313. #endif
  314. }
  315. void RendererClientBase::RunScriptsAtDocumentEnd(
  316. content::RenderFrame* render_frame) {
  317. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  318. extensions_renderer_client_.get()->RunScriptsAtDocumentEnd(render_frame);
  319. #endif
  320. }
  321. v8::Local<v8::Context> RendererClientBase::GetContext(
  322. blink::WebLocalFrame* frame,
  323. v8::Isolate* isolate) const {
  324. if (isolated_world())
  325. return frame->WorldScriptContext(isolate, World::ISOLATED_WORLD);
  326. else
  327. return frame->MainWorldScriptContext();
  328. }
  329. v8::Local<v8::Value> RendererClientBase::RunScript(
  330. v8::Local<v8::Context> context,
  331. v8::Local<v8::String> source) {
  332. auto maybe_script = v8::Script::Compile(context, source);
  333. v8::Local<v8::Script> script;
  334. if (!maybe_script.ToLocal(&script))
  335. return v8::Local<v8::Value>();
  336. return script->Run(context).ToLocalChecked();
  337. }
  338. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  339. extensions::ExtensionsClient* RendererClientBase::CreateExtensionsClient() {
  340. return new ElectronExtensionsClient;
  341. }
  342. #endif
  343. bool RendererClientBase::IsWebViewFrame(
  344. v8::Handle<v8::Context> context,
  345. content::RenderFrame* render_frame) const {
  346. auto* isolate = context->GetIsolate();
  347. if (render_frame->IsMainFrame())
  348. return false;
  349. gin::Dictionary window_dict(
  350. isolate, GetContext(render_frame->GetWebFrame(), isolate)->Global());
  351. v8::Local<v8::Object> frame_element;
  352. if (!window_dict.Get("frameElement", &frame_element))
  353. return false;
  354. gin_helper::Dictionary frame_element_dict(isolate, frame_element);
  355. v8::Local<v8::Object> internal;
  356. if (!frame_element_dict.GetHidden("internal", &internal))
  357. return false;
  358. return !internal.IsEmpty();
  359. }
  360. } // namespace electron