electron_sandboxed_renderer_client.cc 8.0 KB

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