Browse Source

fix: ensure ElectronBrowser mojo service is only bound to appropriate render frames (#33344)

* fix: ensure ElectronBrowser mojo service is only bound to authorized render frames

Notes: no-notes

* refactor: extract electron API IPC to its own mojo interface

* fix: just check main frame not primary main frame

Co-authored-by: Samuel Attard <[email protected]>
Co-authored-by: Samuel Attard <[email protected]>
trop[bot] 3 years ago
parent
commit
e9fa834757

+ 4 - 2
filenames.gni

@@ -350,6 +350,8 @@ filenames = {
     "shell/browser/child_web_contents_tracker.h",
     "shell/browser/cookie_change_notifier.cc",
     "shell/browser/cookie_change_notifier.h",
+    "shell/browser/electron_api_ipc_handler_impl.cc",
+    "shell/browser/electron_api_ipc_handler_impl.h",
     "shell/browser/electron_autofill_driver.cc",
     "shell/browser/electron_autofill_driver.h",
     "shell/browser/electron_autofill_driver_factory.cc",
@@ -358,8 +360,6 @@ filenames = {
     "shell/browser/electron_browser_client.h",
     "shell/browser/electron_browser_context.cc",
     "shell/browser/electron_browser_context.h",
-    "shell/browser/electron_browser_handler_impl.cc",
-    "shell/browser/electron_browser_handler_impl.h",
     "shell/browser/electron_browser_main_parts.cc",
     "shell/browser/electron_browser_main_parts.h",
     "shell/browser/electron_download_manager_delegate.cc",
@@ -376,6 +376,8 @@ filenames = {
     "shell/browser/electron_quota_permission_context.h",
     "shell/browser/electron_speech_recognition_manager_delegate.cc",
     "shell/browser/electron_speech_recognition_manager_delegate.h",
+    "shell/browser/electron_web_contents_utility_handler_impl.cc",
+    "shell/browser/electron_web_contents_utility_handler_impl.h",
     "shell/browser/electron_web_ui_controller_factory.cc",
     "shell/browser/electron_web_ui_controller_factory.h",
     "shell/browser/event_emitter_mixin.cc",

+ 7 - 6
shell/browser/api/electron_api_web_contents.cc

@@ -1727,7 +1727,7 @@ void WebContents::Message(bool internal,
   // webContents.emit('-ipc-message', new Event(), internal, channel,
   // arguments);
   EmitWithSender("-ipc-message", render_frame_host,
-                 electron::mojom::ElectronBrowser::InvokeCallback(), internal,
+                 electron::mojom::ElectronApiIPC::InvokeCallback(), internal,
                  channel, std::move(arguments));
 }
 
@@ -1735,7 +1735,7 @@ void WebContents::Invoke(
     bool internal,
     const std::string& channel,
     blink::CloneableMessage arguments,
-    electron::mojom::ElectronBrowser::InvokeCallback callback,
+    electron::mojom::ElectronApiIPC::InvokeCallback callback,
     content::RenderFrameHost* render_frame_host) {
   TRACE_EVENT1("electron", "WebContents::Invoke", "channel", channel);
   // webContents.emit('-ipc-invoke', new Event(), internal, channel, arguments);
@@ -1761,7 +1761,7 @@ void WebContents::ReceivePostMessage(
   v8::Local<v8::Value> message_value =
       electron::DeserializeV8Value(isolate, message);
   EmitWithSender("-ipc-ports", render_frame_host,
-                 electron::mojom::ElectronBrowser::InvokeCallback(), false,
+                 electron::mojom::ElectronApiIPC::InvokeCallback(), false,
                  channel, message_value, std::move(wrapped_ports));
 }
 
@@ -1769,7 +1769,7 @@ void WebContents::MessageSync(
     bool internal,
     const std::string& channel,
     blink::CloneableMessage arguments,
-    electron::mojom::ElectronBrowser::MessageSyncCallback callback,
+    electron::mojom::ElectronApiIPC::MessageSyncCallback callback,
     content::RenderFrameHost* render_frame_host) {
   TRACE_EVENT1("electron", "WebContents::MessageSync", "channel", channel);
   // webContents.emit('-ipc-message-sync', new Event(sender, message), internal,
@@ -1807,7 +1807,7 @@ void WebContents::MessageHost(const std::string& channel,
   TRACE_EVENT1("electron", "WebContents::MessageHost", "channel", channel);
   // webContents.emit('ipc-message-host', new Event(), channel, args);
   EmitWithSender("ipc-message-host", render_frame_host,
-                 electron::mojom::ElectronBrowser::InvokeCallback(), channel,
+                 electron::mojom::ElectronApiIPC::InvokeCallback(), channel,
                  std::move(arguments));
 }
 
@@ -3246,7 +3246,8 @@ void WebContents::SetTemporaryZoomLevel(double level) {
 }
 
 void WebContents::DoGetZoomLevel(
-    electron::mojom::ElectronBrowser::DoGetZoomLevelCallback callback) {
+    electron::mojom::ElectronWebContentsUtility::DoGetZoomLevelCallback
+        callback) {
   std::move(callback).Run(GetZoomLevel());
 }
 

+ 10 - 6
shell/browser/api/electron_api_web_contents.h

@@ -355,7 +355,7 @@ class WebContents : public ExclusiveAccessContext,
   template <typename... Args>
   bool EmitWithSender(base::StringPiece name,
                       content::RenderFrameHost* sender,
-                      electron::mojom::ElectronBrowser::InvokeCallback callback,
+                      electron::mojom::ElectronApiIPC::InvokeCallback callback,
                       Args&&... args) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
@@ -399,7 +399,7 @@ class WebContents : public ExclusiveAccessContext,
     fullscreen_frame_ = rfh;
   }
 
-  // mojom::ElectronBrowser
+  // mojom::ElectronApiIPC
   void Message(bool internal,
                const std::string& channel,
                blink::CloneableMessage arguments,
@@ -407,9 +407,8 @@ class WebContents : public ExclusiveAccessContext,
   void Invoke(bool internal,
               const std::string& channel,
               blink::CloneableMessage arguments,
-              electron::mojom::ElectronBrowser::InvokeCallback callback,
+              electron::mojom::ElectronApiIPC::InvokeCallback callback,
               content::RenderFrameHost* render_frame_host);
-  void OnFirstNonEmptyLayout(content::RenderFrameHost* render_frame_host);
   void ReceivePostMessage(const std::string& channel,
                           blink::TransferableMessage message,
                           content::RenderFrameHost* render_frame_host);
@@ -417,7 +416,7 @@ class WebContents : public ExclusiveAccessContext,
       bool internal,
       const std::string& channel,
       blink::CloneableMessage arguments,
-      electron::mojom::ElectronBrowser::MessageSyncCallback callback,
+      electron::mojom::ElectronApiIPC::MessageSyncCallback callback,
       content::RenderFrameHost* render_frame_host);
   void MessageTo(int32_t web_contents_id,
                  const std::string& channel,
@@ -425,10 +424,15 @@ class WebContents : public ExclusiveAccessContext,
   void MessageHost(const std::string& channel,
                    blink::CloneableMessage arguments,
                    content::RenderFrameHost* render_frame_host);
+
+  // mojom::ElectronWebContentsUtility
+  void OnFirstNonEmptyLayout(content::RenderFrameHost* render_frame_host);
   void UpdateDraggableRegions(std::vector<mojom::DraggableRegionPtr> regions);
   void SetTemporaryZoomLevel(double level);
   void DoGetZoomLevel(
-      electron::mojom::ElectronBrowser::DoGetZoomLevelCallback callback);
+      electron::mojom::ElectronWebContentsUtility::DoGetZoomLevelCallback
+          callback);
+
   void SetImageAnimationPolicy(const std::string& new_policy);
 
   // Grants |origin| access to |device|.

+ 1 - 1
shell/browser/api/event.h

@@ -13,7 +13,7 @@ namespace gin_helper {
 
 class Event : public gin::Wrappable<Event> {
  public:
-  using InvokeCallback = electron::mojom::ElectronBrowser::InvokeCallback;
+  using InvokeCallback = electron::mojom::ElectronApiIPC::InvokeCallback;
 
   static gin::WrapperInfo kWrapperInfo;
 

+ 108 - 0
shell/browser/electron_api_ipc_handler_impl.cc

@@ -0,0 +1,108 @@
+// Copyright (c) 2022 Slack Technologies, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "shell/browser/electron_api_ipc_handler_impl.h"
+
+#include <utility>
+
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+
+namespace electron {
+ElectronApiIPCHandlerImpl::ElectronApiIPCHandlerImpl(
+    content::RenderFrameHost* frame_host,
+    mojo::PendingAssociatedReceiver<mojom::ElectronApiIPC> receiver)
+    : render_process_id_(frame_host->GetProcess()->GetID()),
+      render_frame_id_(frame_host->GetRoutingID()) {
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(frame_host);
+  DCHECK(web_contents);
+  content::WebContentsObserver::Observe(web_contents);
+
+  receiver_.Bind(std::move(receiver));
+  receiver_.set_disconnect_handler(base::BindOnce(
+      &ElectronApiIPCHandlerImpl::OnConnectionError, GetWeakPtr()));
+}
+
+ElectronApiIPCHandlerImpl::~ElectronApiIPCHandlerImpl() = default;
+
+void ElectronApiIPCHandlerImpl::WebContentsDestroyed() {
+  delete this;
+}
+
+void ElectronApiIPCHandlerImpl::OnConnectionError() {
+  delete this;
+}
+
+void ElectronApiIPCHandlerImpl::Message(bool internal,
+                                        const std::string& channel,
+                                        blink::CloneableMessage arguments) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->Message(internal, channel, std::move(arguments),
+                              GetRenderFrameHost());
+  }
+}
+void ElectronApiIPCHandlerImpl::Invoke(bool internal,
+                                       const std::string& channel,
+                                       blink::CloneableMessage arguments,
+                                       InvokeCallback callback) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->Invoke(internal, channel, std::move(arguments),
+                             std::move(callback), GetRenderFrameHost());
+  }
+}
+
+void ElectronApiIPCHandlerImpl::ReceivePostMessage(
+    const std::string& channel,
+    blink::TransferableMessage message) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->ReceivePostMessage(channel, std::move(message),
+                                         GetRenderFrameHost());
+  }
+}
+
+void ElectronApiIPCHandlerImpl::MessageSync(bool internal,
+                                            const std::string& channel,
+                                            blink::CloneableMessage arguments,
+                                            MessageSyncCallback callback) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->MessageSync(internal, channel, std::move(arguments),
+                                  std::move(callback), GetRenderFrameHost());
+  }
+}
+
+void ElectronApiIPCHandlerImpl::MessageTo(int32_t web_contents_id,
+                                          const std::string& channel,
+                                          blink::CloneableMessage arguments) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->MessageTo(web_contents_id, channel, std::move(arguments));
+  }
+}
+
+void ElectronApiIPCHandlerImpl::MessageHost(const std::string& channel,
+                                            blink::CloneableMessage arguments) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->MessageHost(channel, std::move(arguments),
+                                  GetRenderFrameHost());
+  }
+}
+
+content::RenderFrameHost* ElectronApiIPCHandlerImpl::GetRenderFrameHost() {
+  return content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
+}
+
+// static
+void ElectronApiIPCHandlerImpl::Create(
+    content::RenderFrameHost* frame_host,
+    mojo::PendingAssociatedReceiver<mojom::ElectronApiIPC> receiver) {
+  new ElectronApiIPCHandlerImpl(frame_host, std::move(receiver));
+}
+}  // namespace electron

+ 16 - 21
shell/browser/electron_browser_handler_impl.h → shell/browser/electron_api_ipc_handler_impl.h

@@ -1,9 +1,9 @@
-// Copyright (c) 2019 Slack Technologies, Inc.
+// Copyright (c) 2022 Slack Technologies, Inc.
 // Use of this source code is governed by the MIT license that can be
 // found in the LICENSE file.
 
-#ifndef ELECTRON_SHELL_BROWSER_ELECTRON_BROWSER_HANDLER_IMPL_H_
-#define ELECTRON_SHELL_BROWSER_ELECTRON_BROWSER_HANDLER_IMPL_H_
+#ifndef ELECTRON_SHELL_BROWSER_ELECTRON_API_IPC_HANDLER_IMPL_H_
+#define ELECTRON_SHELL_BROWSER_ELECTRON_API_IPC_HANDLER_IMPL_H_
 
 #include <string>
 #include <vector>
@@ -18,23 +18,23 @@ class RenderFrameHost;
 }
 
 namespace electron {
-class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser,
-                                   public content::WebContentsObserver {
+class ElectronApiIPCHandlerImpl : public mojom::ElectronApiIPC,
+                                  public content::WebContentsObserver {
  public:
-  explicit ElectronBrowserHandlerImpl(
+  explicit ElectronApiIPCHandlerImpl(
       content::RenderFrameHost* render_frame_host,
-      mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver);
+      mojo::PendingAssociatedReceiver<mojom::ElectronApiIPC> receiver);
 
   static void Create(
       content::RenderFrameHost* frame_host,
-      mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver);
+      mojo::PendingAssociatedReceiver<mojom::ElectronApiIPC> receiver);
 
   // disable copy
-  ElectronBrowserHandlerImpl(const ElectronBrowserHandlerImpl&) = delete;
-  ElectronBrowserHandlerImpl& operator=(const ElectronBrowserHandlerImpl&) =
+  ElectronApiIPCHandlerImpl(const ElectronApiIPCHandlerImpl&) = delete;
+  ElectronApiIPCHandlerImpl& operator=(const ElectronApiIPCHandlerImpl&) =
       delete;
 
-  // mojom::ElectronBrowser:
+  // mojom::ElectronApiIPC:
   void Message(bool internal,
                const std::string& channel,
                blink::CloneableMessage arguments) override;
@@ -42,7 +42,6 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser,
               const std::string& channel,
               blink::CloneableMessage arguments,
               InvokeCallback callback) override;
-  void OnFirstNonEmptyLayout() override;
   void ReceivePostMessage(const std::string& channel,
                           blink::TransferableMessage message) override;
   void MessageSync(bool internal,
@@ -54,17 +53,13 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser,
                  blink::CloneableMessage arguments) override;
   void MessageHost(const std::string& channel,
                    blink::CloneableMessage arguments) override;
-  void UpdateDraggableRegions(
-      std::vector<mojom::DraggableRegionPtr> regions) override;
-  void SetTemporaryZoomLevel(double level) override;
-  void DoGetZoomLevel(DoGetZoomLevelCallback callback) override;
 
-  base::WeakPtr<ElectronBrowserHandlerImpl> GetWeakPtr() {
+  base::WeakPtr<ElectronApiIPCHandlerImpl> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
 
  private:
-  ~ElectronBrowserHandlerImpl() override;
+  ~ElectronApiIPCHandlerImpl() override;
 
   // content::WebContentsObserver:
   void WebContentsDestroyed() override;
@@ -76,9 +71,9 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser,
   const int render_process_id_;
   const int render_frame_id_;
 
-  mojo::AssociatedReceiver<mojom::ElectronBrowser> receiver_{this};
+  mojo::AssociatedReceiver<mojom::ElectronApiIPC> receiver_{this};
 
-  base::WeakPtrFactory<ElectronBrowserHandlerImpl> weak_factory_{this};
+  base::WeakPtrFactory<ElectronApiIPCHandlerImpl> weak_factory_{this};
 };
 }  // namespace electron
-#endif  // ELECTRON_SHELL_BROWSER_ELECTRON_BROWSER_HANDLER_IMPL_H_
+#endif  // ELECTRON_SHELL_BROWSER_ELECTRON_API_IPC_HANDLER_IMPL_H_

+ 25 - 5
shell/browser/electron_browser_client.cc

@@ -74,13 +74,14 @@
 #include "shell/browser/api/electron_api_web_request.h"
 #include "shell/browser/badging/badge_manager.h"
 #include "shell/browser/child_web_contents_tracker.h"
+#include "shell/browser/electron_api_ipc_handler_impl.h"
 #include "shell/browser/electron_autofill_driver_factory.h"
 #include "shell/browser/electron_browser_context.h"
-#include "shell/browser/electron_browser_handler_impl.h"
 #include "shell/browser/electron_browser_main_parts.h"
 #include "shell/browser/electron_navigation_throttle.h"
 #include "shell/browser/electron_quota_permission_context.h"
 #include "shell/browser/electron_speech_recognition_manager_delegate.h"
+#include "shell/browser/electron_web_contents_utility_handler_impl.h"
 #include "shell/browser/font_defaults.h"
 #include "shell/browser/javascript_environment.h"
 #include "shell/browser/media/media_capture_devices_dispatcher.h"
@@ -1493,14 +1494,33 @@ void ElectronBrowserClient::
             render_frame_host,  // NOLINT(runtime/references)
         blink::AssociatedInterfaceRegistry&
             associated_registry) {  // NOLINT(runtime/references)
+  auto* contents =
+      content::WebContents::FromRenderFrameHost(&render_frame_host);
+  if (contents) {
+    auto* prefs = WebContentsPreferences::From(contents);
+    if (render_frame_host.GetFrameTreeNodeId() ==
+            contents->GetMainFrame()->GetFrameTreeNodeId() ||
+        (prefs && prefs->AllowsNodeIntegrationInSubFrames())) {
+      associated_registry.AddInterface(base::BindRepeating(
+          [](content::RenderFrameHost* render_frame_host,
+             mojo::PendingAssociatedReceiver<electron::mojom::ElectronApiIPC>
+                 receiver) {
+            ElectronApiIPCHandlerImpl::Create(render_frame_host,
+                                              std::move(receiver));
+          },
+          &render_frame_host));
+    }
+  }
+
   associated_registry.AddInterface(base::BindRepeating(
       [](content::RenderFrameHost* render_frame_host,
-         mojo::PendingAssociatedReceiver<electron::mojom::ElectronBrowser>
-             receiver) {
-        ElectronBrowserHandlerImpl::Create(render_frame_host,
-                                           std::move(receiver));
+         mojo::PendingAssociatedReceiver<
+             electron::mojom::ElectronWebContentsUtility> receiver) {
+        ElectronWebContentsUtilityHandlerImpl::Create(render_frame_host,
+                                                      std::move(receiver));
       },
       &render_frame_host));
+
   associated_registry.AddInterface(base::BindRepeating(
       [](content::RenderFrameHost* render_frame_host,
          mojo::PendingAssociatedReceiver<mojom::ElectronAutofillDriver>

+ 0 - 141
shell/browser/electron_browser_handler_impl.cc

@@ -1,141 +0,0 @@
-// Copyright (c) 2019 Slack Technologies, Inc.
-// Use of this source code is governed by the MIT license that can be
-// found in the LICENSE file.
-
-#include "shell/browser/electron_browser_handler_impl.h"
-
-#include <utility>
-
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
-
-namespace electron {
-ElectronBrowserHandlerImpl::ElectronBrowserHandlerImpl(
-    content::RenderFrameHost* frame_host,
-    mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver)
-    : render_process_id_(frame_host->GetProcess()->GetID()),
-      render_frame_id_(frame_host->GetRoutingID()) {
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(frame_host);
-  DCHECK(web_contents);
-  content::WebContentsObserver::Observe(web_contents);
-
-  receiver_.Bind(std::move(receiver));
-  receiver_.set_disconnect_handler(base::BindOnce(
-      &ElectronBrowserHandlerImpl::OnConnectionError, GetWeakPtr()));
-}
-
-ElectronBrowserHandlerImpl::~ElectronBrowserHandlerImpl() = default;
-
-void ElectronBrowserHandlerImpl::WebContentsDestroyed() {
-  delete this;
-}
-
-void ElectronBrowserHandlerImpl::OnConnectionError() {
-  delete this;
-}
-
-void ElectronBrowserHandlerImpl::Message(bool internal,
-                                         const std::string& channel,
-                                         blink::CloneableMessage arguments) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->Message(internal, channel, std::move(arguments),
-                              GetRenderFrameHost());
-  }
-}
-void ElectronBrowserHandlerImpl::Invoke(bool internal,
-                                        const std::string& channel,
-                                        blink::CloneableMessage arguments,
-                                        InvokeCallback callback) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->Invoke(internal, channel, std::move(arguments),
-                             std::move(callback), GetRenderFrameHost());
-  }
-}
-
-void ElectronBrowserHandlerImpl::OnFirstNonEmptyLayout() {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->OnFirstNonEmptyLayout(GetRenderFrameHost());
-  }
-}
-
-void ElectronBrowserHandlerImpl::ReceivePostMessage(
-    const std::string& channel,
-    blink::TransferableMessage message) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->ReceivePostMessage(channel, std::move(message),
-                                         GetRenderFrameHost());
-  }
-}
-
-void ElectronBrowserHandlerImpl::MessageSync(bool internal,
-                                             const std::string& channel,
-                                             blink::CloneableMessage arguments,
-                                             MessageSyncCallback callback) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->MessageSync(internal, channel, std::move(arguments),
-                                  std::move(callback), GetRenderFrameHost());
-  }
-}
-
-void ElectronBrowserHandlerImpl::MessageTo(int32_t web_contents_id,
-                                           const std::string& channel,
-                                           blink::CloneableMessage arguments) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->MessageTo(web_contents_id, channel, std::move(arguments));
-  }
-}
-
-void ElectronBrowserHandlerImpl::MessageHost(
-    const std::string& channel,
-    blink::CloneableMessage arguments) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->MessageHost(channel, std::move(arguments),
-                                  GetRenderFrameHost());
-  }
-}
-
-void ElectronBrowserHandlerImpl::UpdateDraggableRegions(
-    std::vector<mojom::DraggableRegionPtr> regions) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->UpdateDraggableRegions(std::move(regions));
-  }
-}
-
-void ElectronBrowserHandlerImpl::SetTemporaryZoomLevel(double level) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->SetTemporaryZoomLevel(level);
-  }
-}
-
-void ElectronBrowserHandlerImpl::DoGetZoomLevel(
-    DoGetZoomLevelCallback callback) {
-  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
-  if (api_web_contents) {
-    api_web_contents->DoGetZoomLevel(std::move(callback));
-  }
-}
-
-content::RenderFrameHost* ElectronBrowserHandlerImpl::GetRenderFrameHost() {
-  return content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
-}
-
-// static
-void ElectronBrowserHandlerImpl::Create(
-    content::RenderFrameHost* frame_host,
-    mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver) {
-  new ElectronBrowserHandlerImpl(frame_host, std::move(receiver));
-}
-}  // namespace electron

+ 83 - 0
shell/browser/electron_web_contents_utility_handler_impl.cc

@@ -0,0 +1,83 @@
+// Copyright (c) 2022 Slack Technologies, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "shell/browser/electron_web_contents_utility_handler_impl.h"
+
+#include <utility>
+
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+
+namespace electron {
+ElectronWebContentsUtilityHandlerImpl::ElectronWebContentsUtilityHandlerImpl(
+    content::RenderFrameHost* frame_host,
+    mojo::PendingAssociatedReceiver<mojom::ElectronWebContentsUtility> receiver)
+    : render_process_id_(frame_host->GetProcess()->GetID()),
+      render_frame_id_(frame_host->GetRoutingID()) {
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(frame_host);
+  DCHECK(web_contents);
+  content::WebContentsObserver::Observe(web_contents);
+
+  receiver_.Bind(std::move(receiver));
+  receiver_.set_disconnect_handler(base::BindOnce(
+      &ElectronWebContentsUtilityHandlerImpl::OnConnectionError, GetWeakPtr()));
+}
+
+ElectronWebContentsUtilityHandlerImpl::
+    ~ElectronWebContentsUtilityHandlerImpl() = default;
+
+void ElectronWebContentsUtilityHandlerImpl::WebContentsDestroyed() {
+  delete this;
+}
+
+void ElectronWebContentsUtilityHandlerImpl::OnConnectionError() {
+  delete this;
+}
+
+void ElectronWebContentsUtilityHandlerImpl::OnFirstNonEmptyLayout() {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->OnFirstNonEmptyLayout(GetRenderFrameHost());
+  }
+}
+
+void ElectronWebContentsUtilityHandlerImpl::UpdateDraggableRegions(
+    std::vector<mojom::DraggableRegionPtr> regions) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->UpdateDraggableRegions(std::move(regions));
+  }
+}
+
+void ElectronWebContentsUtilityHandlerImpl::SetTemporaryZoomLevel(
+    double level) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->SetTemporaryZoomLevel(level);
+  }
+}
+
+void ElectronWebContentsUtilityHandlerImpl::DoGetZoomLevel(
+    DoGetZoomLevelCallback callback) {
+  api::WebContents* api_web_contents = api::WebContents::From(web_contents());
+  if (api_web_contents) {
+    api_web_contents->DoGetZoomLevel(std::move(callback));
+  }
+}
+
+content::RenderFrameHost*
+ElectronWebContentsUtilityHandlerImpl::GetRenderFrameHost() {
+  return content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
+}
+
+// static
+void ElectronWebContentsUtilityHandlerImpl::Create(
+    content::RenderFrameHost* frame_host,
+    mojo::PendingAssociatedReceiver<mojom::ElectronWebContentsUtility>
+        receiver) {
+  new ElectronWebContentsUtilityHandlerImpl(frame_host, std::move(receiver));
+}
+}  // namespace electron

+ 71 - 0
shell/browser/electron_web_contents_utility_handler_impl.h

@@ -0,0 +1,71 @@
+// Copyright (c) 2022 Slack Technologies, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef ELECTRON_SHELL_BROWSER_ELECTRON_WEB_CONTENTS_UTILITY_HANDLER_IMPL_H_
+#define ELECTRON_SHELL_BROWSER_ELECTRON_WEB_CONTENTS_UTILITY_HANDLER_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "electron/shell/common/api/api.mojom.h"
+#include "shell/browser/api/electron_api_web_contents.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace electron {
+class ElectronWebContentsUtilityHandlerImpl
+    : public mojom::ElectronWebContentsUtility,
+      public content::WebContentsObserver {
+ public:
+  explicit ElectronWebContentsUtilityHandlerImpl(
+      content::RenderFrameHost* render_frame_host,
+      mojo::PendingAssociatedReceiver<mojom::ElectronWebContentsUtility>
+          receiver);
+
+  static void Create(
+      content::RenderFrameHost* frame_host,
+      mojo::PendingAssociatedReceiver<mojom::ElectronWebContentsUtility>
+          receiver);
+
+  // disable copy
+  ElectronWebContentsUtilityHandlerImpl(
+      const ElectronWebContentsUtilityHandlerImpl&) = delete;
+  ElectronWebContentsUtilityHandlerImpl& operator=(
+      const ElectronWebContentsUtilityHandlerImpl&) = delete;
+
+  // mojom::ElectronWebContentsUtility:
+  void OnFirstNonEmptyLayout() override;
+  void UpdateDraggableRegions(
+      std::vector<mojom::DraggableRegionPtr> regions) override;
+  void SetTemporaryZoomLevel(double level) override;
+  void DoGetZoomLevel(DoGetZoomLevelCallback callback) override;
+
+  base::WeakPtr<ElectronWebContentsUtilityHandlerImpl> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+ private:
+  ~ElectronWebContentsUtilityHandlerImpl() override;
+
+  // content::WebContentsObserver:
+  void WebContentsDestroyed() override;
+
+  void OnConnectionError();
+
+  content::RenderFrameHost* GetRenderFrameHost();
+
+  const int render_process_id_;
+  const int render_frame_id_;
+
+  mojo::AssociatedReceiver<mojom::ElectronWebContentsUtility> receiver_{this};
+
+  base::WeakPtrFactory<ElectronWebContentsUtilityHandlerImpl> weak_factory_{
+      this};
+};
+}  // namespace electron
+#endif  // ELECTRON_SHELL_BROWSER_ELECTRON_WEB_CONTENTS_UTILITY_HANDLER_IMPL_H_

+ 3 - 0
shell/browser/web_contents_preferences.h

@@ -71,6 +71,9 @@ class WebContentsPreferences
   bool ShouldDisableHtmlFullscreenWindowResize() const {
     return disable_html_fullscreen_window_resize_;
   }
+  bool AllowsNodeIntegrationInSubFrames() const {
+    return node_integration_in_sub_frames_;
+  }
   bool ShouldDisableDialogs() const { return disable_dialogs_; }
   bool ShouldUseSafeDialogs() const { return safe_dialogs_; }
   bool GetSafeDialogsMessage(std::string* message) const;

+ 15 - 13
shell/common/api/api.mojom

@@ -31,7 +31,21 @@ struct DraggableRegion {
   gfx.mojom.Rect bounds;
 };
 
-interface ElectronBrowser {
+interface ElectronWebContentsUtility {
+  // Informs underlying WebContents that first non-empty layout was performed
+  // by compositor.
+  OnFirstNonEmptyLayout();
+
+  UpdateDraggableRegions(
+    array<DraggableRegion> regions);
+
+  SetTemporaryZoomLevel(double zoom_level);
+
+  [Sync]
+  DoGetZoomLevel() => (double result);
+};
+
+interface ElectronApiIPC {
   // Emits an event on |channel| from the ipcMain JavaScript object in the main
   // process.
   Message(
@@ -46,10 +60,6 @@ interface ElectronBrowser {
       string channel,
       blink.mojom.CloneableMessage arguments) => (blink.mojom.CloneableMessage result);
 
-  // Informs underlying WebContents that first non-empty layout was performed
-  // by compositor.
-  OnFirstNonEmptyLayout();
-
   ReceivePostMessage(string channel, blink.mojom.TransferableMessage message);
 
   // Emits an event on |channel| from the ipcMain JavaScript object in the main
@@ -70,12 +80,4 @@ interface ElectronBrowser {
   MessageHost(
     string channel,
     blink.mojom.CloneableMessage arguments);
-
-  UpdateDraggableRegions(
-    array<DraggableRegion> regions);
-
-  SetTemporaryZoomLevel(double zoom_level);
-
-  [Sync]
-  DoGetZoomLevel() => (double result);
 };

+ 1 - 1
shell/common/gin_helper/event_emitter.cc

@@ -54,7 +54,7 @@ v8::Local<v8::Object> CreateNativeEvent(
     v8::Isolate* isolate,
     v8::Local<v8::Object> sender,
     content::RenderFrameHost* frame,
-    electron::mojom::ElectronBrowser::MessageSyncCallback callback) {
+    electron::mojom::ElectronApiIPC::MessageSyncCallback callback) {
   v8::Local<v8::Object> event;
   if (frame && callback) {
     gin::Handle<Event> native_event = Event::Create(isolate);

+ 1 - 1
shell/common/gin_helper/event_emitter.h

@@ -29,7 +29,7 @@ v8::Local<v8::Object> CreateNativeEvent(
     v8::Isolate* isolate,
     v8::Local<v8::Object> sender,
     content::RenderFrameHost* frame,
-    electron::mojom::ElectronBrowser::MessageSyncCallback callback);
+    electron::mojom::ElectronApiIPC::MessageSyncCallback callback);
 
 }  // namespace internal
 

+ 19 - 20
shell/renderer/api/electron_api_ipc_renderer.cc

@@ -60,16 +60,16 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
     weak_context_.SetWeak();
 
     render_frame->GetRemoteAssociatedInterfaces()->GetInterface(
-        &electron_browser_remote_);
+        &electron_ipc_remote_);
   }
 
-  void OnDestruct() override { electron_browser_remote_.reset(); }
+  void OnDestruct() override { electron_ipc_remote_.reset(); }
 
   void WillReleaseScriptContext(v8::Local<v8::Context> context,
                                 int32_t world_id) override {
     if (weak_context_.IsEmpty() ||
         weak_context_.Get(context->GetIsolate()) == context)
-      electron_browser_remote_.reset();
+      electron_ipc_remote_.reset();
   }
 
   // gin::Wrappable:
@@ -92,7 +92,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
                    bool internal,
                    const std::string& channel,
                    v8::Local<v8::Value> arguments) {
-    if (!electron_browser_remote_) {
+    if (!electron_ipc_remote_) {
       thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
       return;
     }
@@ -100,7 +100,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return;
     }
-    electron_browser_remote_->Message(internal, channel, std::move(message));
+    electron_ipc_remote_->Message(internal, channel, std::move(message));
   }
 
   v8::Local<v8::Promise> Invoke(v8::Isolate* isolate,
@@ -108,7 +108,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
                                 bool internal,
                                 const std::string& channel,
                                 v8::Local<v8::Value> arguments) {
-    if (!electron_browser_remote_) {
+    if (!electron_ipc_remote_) {
       thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
       return v8::Local<v8::Promise>();
     }
@@ -119,7 +119,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
     gin_helper::Promise<blink::CloneableMessage> p(isolate);
     auto handle = p.GetHandle();
 
-    electron_browser_remote_->Invoke(
+    electron_ipc_remote_->Invoke(
         internal, channel, std::move(message),
         base::BindOnce(
             [](gin_helper::Promise<blink::CloneableMessage> p,
@@ -134,7 +134,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
                    const std::string& channel,
                    v8::Local<v8::Value> message_value,
                    absl::optional<v8::Local<v8::Value>> transfer) {
-    if (!electron_browser_remote_) {
+    if (!electron_ipc_remote_) {
       thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
       return;
     }
@@ -166,8 +166,8 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
     }
 
     transferable_message.ports = std::move(ports);
-    electron_browser_remote_->ReceivePostMessage(
-        channel, std::move(transferable_message));
+    electron_ipc_remote_->ReceivePostMessage(channel,
+                                             std::move(transferable_message));
   }
 
   void SendTo(v8::Isolate* isolate,
@@ -175,7 +175,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
               int32_t web_contents_id,
               const std::string& channel,
               v8::Local<v8::Value> arguments) {
-    if (!electron_browser_remote_) {
+    if (!electron_ipc_remote_) {
       thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
       return;
     }
@@ -183,15 +183,15 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return;
     }
-    electron_browser_remote_->MessageTo(web_contents_id, channel,
-                                        std::move(message));
+    electron_ipc_remote_->MessageTo(web_contents_id, channel,
+                                    std::move(message));
   }
 
   void SendToHost(v8::Isolate* isolate,
                   gin_helper::ErrorThrower thrower,
                   const std::string& channel,
                   v8::Local<v8::Value> arguments) {
-    if (!electron_browser_remote_) {
+    if (!electron_ipc_remote_) {
       thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
       return;
     }
@@ -199,7 +199,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return;
     }
-    electron_browser_remote_->MessageHost(channel, std::move(message));
+    electron_ipc_remote_->MessageHost(channel, std::move(message));
   }
 
   v8::Local<v8::Value> SendSync(v8::Isolate* isolate,
@@ -207,7 +207,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
                                 bool internal,
                                 const std::string& channel,
                                 v8::Local<v8::Value> arguments) {
-    if (!electron_browser_remote_) {
+    if (!electron_ipc_remote_) {
       thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
       return v8::Local<v8::Value>();
     }
@@ -217,14 +217,13 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
     }
 
     blink::CloneableMessage result;
-    electron_browser_remote_->MessageSync(internal, channel, std::move(message),
-                                          &result);
+    electron_ipc_remote_->MessageSync(internal, channel, std::move(message),
+                                      &result);
     return electron::DeserializeV8Value(isolate, result);
   }
 
   v8::Global<v8::Context> weak_context_;
-  mojo::AssociatedRemote<electron::mojom::ElectronBrowser>
-      electron_browser_remote_;
+  mojo::AssociatedRemote<electron::mojom::ElectronApiIPC> electron_ipc_remote_;
 };
 
 gin::WrapperInfo IPCRenderer::kWrapperInfo = {gin::kEmbedderNativeGin};

+ 8 - 6
shell/renderer/api/electron_api_web_frame.cc

@@ -453,10 +453,11 @@ class WebFrameRenderer : public gin::Wrappable<WebFrameRenderer>,
     if (!MaybeGetRenderFrame(isolate, "setZoomLevel", &render_frame))
       return;
 
-    mojo::AssociatedRemote<mojom::ElectronBrowser> browser_remote;
+    mojo::AssociatedRemote<mojom::ElectronWebContentsUtility>
+        web_contents_utility_remote;
     render_frame->GetRemoteAssociatedInterfaces()->GetInterface(
-        &browser_remote);
-    browser_remote->SetTemporaryZoomLevel(level);
+        &web_contents_utility_remote);
+    web_contents_utility_remote->SetTemporaryZoomLevel(level);
   }
 
   double GetZoomLevel(v8::Isolate* isolate) {
@@ -465,10 +466,11 @@ class WebFrameRenderer : public gin::Wrappable<WebFrameRenderer>,
     if (!MaybeGetRenderFrame(isolate, "getZoomLevel", &render_frame))
       return result;
 
-    mojo::AssociatedRemote<mojom::ElectronBrowser> browser_remote;
+    mojo::AssociatedRemote<mojom::ElectronWebContentsUtility>
+        web_contents_utility_remote;
     render_frame->GetRemoteAssociatedInterfaces()->GetInterface(
-        &browser_remote);
-    browser_remote->DoGetZoomLevel(&result);
+        &web_contents_utility_remote);
+    web_contents_utility_remote->DoGetZoomLevel(&result);
     return result;
   }
 

+ 9 - 6
shell/renderer/electron_render_frame_observer.cc

@@ -149,9 +149,11 @@ void ElectronRenderFrameObserver::DraggableRegionsChanged() {
     regions.push_back(std::move(region));
   }
 
-  mojo::AssociatedRemote<mojom::ElectronBrowser> browser_remote;
-  render_frame_->GetRemoteAssociatedInterfaces()->GetInterface(&browser_remote);
-  browser_remote->UpdateDraggableRegions(std::move(regions));
+  mojo::AssociatedRemote<mojom::ElectronWebContentsUtility>
+      web_contents_utility_remote;
+  render_frame_->GetRemoteAssociatedInterfaces()->GetInterface(
+      &web_contents_utility_remote);
+  web_contents_utility_remote->UpdateDraggableRegions(std::move(regions));
 }
 
 void ElectronRenderFrameObserver::WillReleaseScriptContext(
@@ -168,10 +170,11 @@ void ElectronRenderFrameObserver::OnDestruct() {
 void ElectronRenderFrameObserver::DidMeaningfulLayout(
     blink::WebMeaningfulLayout layout_type) {
   if (layout_type == blink::WebMeaningfulLayout::kVisuallyNonEmpty) {
-    mojo::AssociatedRemote<mojom::ElectronBrowser> browser_remote;
+    mojo::AssociatedRemote<mojom::ElectronWebContentsUtility>
+        web_contents_utility_remote;
     render_frame_->GetRemoteAssociatedInterfaces()->GetInterface(
-        &browser_remote);
-    browser_remote->OnFirstNonEmptyLayout();
+        &web_contents_utility_remote);
+    web_contents_utility_remote->OnFirstNonEmptyLayout();
   }
 }