electron_sandboxed_renderer_client.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright (c) 2016 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/electron_sandboxed_renderer_client.h"
  5. #include <iterator>
  6. #include <vector>
  7. #include "base/base_paths.h"
  8. #include "base/command_line.h"
  9. #include "base/process/process_metrics.h"
  10. #include "content/public/renderer/render_frame.h"
  11. #include "shell/common/api/electron_bindings.h"
  12. #include "shell/common/application_info.h"
  13. #include "shell/common/gin_helper/dictionary.h"
  14. #include "shell/common/gin_helper/microtasks_scope.h"
  15. #include "shell/common/node_includes.h"
  16. #include "shell/common/node_util.h"
  17. #include "shell/common/options_switches.h"
  18. #include "shell/renderer/electron_render_frame_observer.h"
  19. #include "shell/renderer/preload_realm_context.h"
  20. #include "shell/renderer/preload_utils.h"
  21. #include "shell/renderer/service_worker_data.h"
  22. #include "third_party/blink/public/common/web_preferences/web_preferences.h"
  23. #include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
  24. #include "third_party/blink/public/web/blink.h"
  25. #include "third_party/blink/public/web/web_document.h"
  26. #include "third_party/electron_node/src/node_binding.h"
  27. namespace electron {
  28. namespace {
  29. // Data which only lives on the service worker's thread
  30. constinit thread_local ServiceWorkerData* service_worker_data = nullptr;
  31. constexpr std::string_view kEmitProcessEventKey = "emit-process-event";
  32. void InvokeEmitProcessEvent(v8::Local<v8::Context> context,
  33. const std::string& event_name) {
  34. auto* isolate = context->GetIsolate();
  35. // set by sandboxed_renderer/init.js
  36. auto binding_key = gin::ConvertToV8(isolate, kEmitProcessEventKey)
  37. ->ToString(context)
  38. .ToLocalChecked();
  39. auto private_binding_key = v8::Private::ForApi(isolate, binding_key);
  40. auto global_object = context->Global();
  41. v8::Local<v8::Value> callback_value;
  42. if (!global_object->GetPrivate(context, private_binding_key)
  43. .ToLocal(&callback_value))
  44. return;
  45. if (callback_value.IsEmpty() || !callback_value->IsFunction())
  46. return;
  47. auto callback = callback_value.As<v8::Function>();
  48. v8::Local<v8::Value> args[] = {gin::ConvertToV8(isolate, event_name)};
  49. std::ignore =
  50. callback->Call(context, callback, std::size(args), std::data(args));
  51. }
  52. } // namespace
  53. ElectronSandboxedRendererClient::ElectronSandboxedRendererClient() {
  54. // Explicitly register electron's builtin bindings.
  55. NodeBindings::RegisterBuiltinBindings();
  56. metrics_ = base::ProcessMetrics::CreateCurrentProcessMetrics();
  57. }
  58. ElectronSandboxedRendererClient::~ElectronSandboxedRendererClient() = default;
  59. void ElectronSandboxedRendererClient::InitializeBindings(
  60. v8::Local<v8::Object> binding,
  61. v8::Local<v8::Context> context,
  62. content::RenderFrame* render_frame) {
  63. auto* isolate = context->GetIsolate();
  64. gin_helper::Dictionary b(isolate, binding);
  65. b.SetMethod("get", preload_utils::GetBinding);
  66. b.SetMethod("createPreloadScript", preload_utils::CreatePreloadScript);
  67. auto process = gin_helper::Dictionary::CreateEmpty(isolate);
  68. b.Set("process", process);
  69. ElectronBindings::BindProcess(isolate, &process, metrics_.get());
  70. BindProcess(isolate, &process, render_frame);
  71. process.SetMethod("uptime", preload_utils::Uptime);
  72. process.Set("argv", base::CommandLine::ForCurrentProcess()->argv());
  73. process.SetReadOnly("pid", base::GetCurrentProcId());
  74. process.SetReadOnly("sandboxed", true);
  75. process.SetReadOnly("type", "renderer");
  76. }
  77. void ElectronSandboxedRendererClient::RenderFrameCreated(
  78. content::RenderFrame* render_frame) {
  79. new ElectronRenderFrameObserver(render_frame, this);
  80. RendererClientBase::RenderFrameCreated(render_frame);
  81. }
  82. void ElectronSandboxedRendererClient::RunScriptsAtDocumentStart(
  83. content::RenderFrame* render_frame) {
  84. RendererClientBase::RunScriptsAtDocumentStart(render_frame);
  85. EmitProcessEvent(render_frame, "document-start");
  86. }
  87. void ElectronSandboxedRendererClient::RunScriptsAtDocumentEnd(
  88. content::RenderFrame* render_frame) {
  89. RendererClientBase::RunScriptsAtDocumentEnd(render_frame);
  90. EmitProcessEvent(render_frame, "document-end");
  91. }
  92. void ElectronSandboxedRendererClient::DidCreateScriptContext(
  93. v8::Local<v8::Context> context,
  94. content::RenderFrame* render_frame) {
  95. // Only allow preload for the main frame or
  96. // For devtools we still want to run the preload_bundle script
  97. // Or when nodeSupport is explicitly enabled in sub frames
  98. if (!ShouldLoadPreload(context, render_frame))
  99. return;
  100. injected_frames_.insert(render_frame);
  101. // Wrap the bundle into a function that receives the binding object as
  102. // argument.
  103. auto* isolate = context->GetIsolate();
  104. auto binding = v8::Object::New(isolate);
  105. InitializeBindings(binding, context, render_frame);
  106. std::vector<v8::Local<v8::String>> sandbox_preload_bundle_params = {
  107. node::FIXED_ONE_BYTE_STRING(isolate, "binding")};
  108. std::vector<v8::Local<v8::Value>> sandbox_preload_bundle_args = {binding};
  109. util::CompileAndCall(
  110. isolate->GetCurrentContext(), "electron/js2c/sandbox_bundle",
  111. &sandbox_preload_bundle_params, &sandbox_preload_bundle_args);
  112. v8::HandleScope handle_scope(isolate);
  113. v8::Context::Scope context_scope(context);
  114. InvokeEmitProcessEvent(context, "loaded");
  115. }
  116. void ElectronSandboxedRendererClient::WillReleaseScriptContext(
  117. v8::Local<v8::Context> context,
  118. content::RenderFrame* render_frame) {
  119. if (injected_frames_.erase(render_frame) == 0)
  120. return;
  121. auto* isolate = context->GetIsolate();
  122. gin_helper::MicrotasksScope microtasks_scope{
  123. context, false, v8::MicrotasksScope::kDoNotRunMicrotasks};
  124. v8::HandleScope handle_scope(isolate);
  125. v8::Context::Scope context_scope(context);
  126. InvokeEmitProcessEvent(context, "exit");
  127. }
  128. void ElectronSandboxedRendererClient::EmitProcessEvent(
  129. content::RenderFrame* render_frame,
  130. const char* event_name) {
  131. if (!injected_frames_.contains(render_frame))
  132. return;
  133. blink::WebLocalFrame* frame = render_frame->GetWebFrame();
  134. v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
  135. v8::HandleScope handle_scope{isolate};
  136. v8::Local<v8::Context> context = GetContext(frame, isolate);
  137. gin_helper::MicrotasksScope microtasks_scope{
  138. context, false, v8::MicrotasksScope::kDoNotRunMicrotasks};
  139. v8::Context::Scope context_scope(context);
  140. InvokeEmitProcessEvent(context, event_name);
  141. }
  142. void ElectronSandboxedRendererClient::WillEvaluateServiceWorkerOnWorkerThread(
  143. blink::WebServiceWorkerContextProxy* context_proxy,
  144. v8::Local<v8::Context> v8_context,
  145. int64_t service_worker_version_id,
  146. const GURL& service_worker_scope,
  147. const GURL& script_url,
  148. const blink::ServiceWorkerToken& service_worker_token) {
  149. RendererClientBase::WillEvaluateServiceWorkerOnWorkerThread(
  150. context_proxy, v8_context, service_worker_version_id,
  151. service_worker_scope, script_url, service_worker_token);
  152. auto* command_line = base::CommandLine::ForCurrentProcess();
  153. if (command_line->HasSwitch(switches::kServiceWorkerPreload)) {
  154. if (!service_worker_data) {
  155. service_worker_data = new ServiceWorkerData(
  156. context_proxy, service_worker_version_id, v8_context);
  157. }
  158. preload_realm::OnCreatePreloadableV8Context(v8_context,
  159. service_worker_data);
  160. }
  161. }
  162. void ElectronSandboxedRendererClient::
  163. WillDestroyServiceWorkerContextOnWorkerThread(
  164. v8::Local<v8::Context> context,
  165. int64_t service_worker_version_id,
  166. const GURL& service_worker_scope,
  167. const GURL& script_url) {
  168. if (service_worker_data) {
  169. DCHECK_EQ(service_worker_version_id,
  170. service_worker_data->service_worker_version_id());
  171. delete service_worker_data;
  172. service_worker_data = nullptr;
  173. }
  174. RendererClientBase::WillDestroyServiceWorkerContextOnWorkerThread(
  175. context, service_worker_version_id, service_worker_scope, script_url);
  176. }
  177. } // namespace electron