From b16318723556c70d6d407f271e5ad1b7d2402cc9 Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Wed, 1 Nov 2023 13:46:25 -0400 Subject: [PATCH] docs: avoid leaking the `IpcRendererEvent` in `contextBridge` examples (#40321) * docs: avoid leaking the `IpcRendererEvent` in `contextBridge` examples * Update docs/fiddles/ipc/pattern-3/preload.js Co-authored-by: David Sanders * Update docs/tutorial/ipc.md Co-authored-by: David Sanders * Update docs/tutorial/ipc.md Co-authored-by: David Sanders --------- Co-authored-by: David Sanders --- docs/fiddles/ipc/pattern-3/preload.js | 3 ++- docs/fiddles/ipc/pattern-3/renderer.js | 6 +++--- docs/tutorial/ipc.md | 25 ++++++++++++++++++------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/fiddles/ipc/pattern-3/preload.js b/docs/fiddles/ipc/pattern-3/preload.js index 1df2941caac5..b8d275650735 100644 --- a/docs/fiddles/ipc/pattern-3/preload.js +++ b/docs/fiddles/ipc/pattern-3/preload.js @@ -1,5 +1,6 @@ const { contextBridge, ipcRenderer } = require('electron/renderer') contextBridge.exposeInMainWorld('electronAPI', { - handleCounter: (callback) => ipcRenderer.on('update-counter', () => callback()) + onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value)), + counterValue: (value) => ipcRenderer.send('counter-value', value) }) diff --git a/docs/fiddles/ipc/pattern-3/renderer.js b/docs/fiddles/ipc/pattern-3/renderer.js index d7316a5d87f1..c1d97a848331 100644 --- a/docs/fiddles/ipc/pattern-3/renderer.js +++ b/docs/fiddles/ipc/pattern-3/renderer.js @@ -1,8 +1,8 @@ const counter = document.getElementById('counter') -window.electronAPI.handleCounter((event, value) => { +window.electronAPI.onUpdateCounter((value) => { const oldValue = Number(counter.innerText) const newValue = oldValue + value - counter.innerText = newValue - event.sender.send('counter-value', newValue) + counter.innerText = newValue.toString() + window.electronAPI.counterValue(newValue) }) diff --git a/docs/tutorial/ipc.md b/docs/tutorial/ipc.md index 73b5723aebbe..bbd139e81a17 100644 --- a/docs/tutorial/ipc.md +++ b/docs/tutorial/ipc.md @@ -429,7 +429,7 @@ modules in the preload script to expose IPC functionality to the renderer proces const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld('electronAPI', { - onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback) + onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value)) }) ``` @@ -439,6 +439,8 @@ After loading the preload script, your renderer process should have access to th :::caution Security warning We don't directly expose the whole `ipcRenderer.on` API for [security reasons][]. Make sure to limit the renderer's access to Electron APIs as much as possible. +Also don't just pass the callback to `ipcRenderer.on` as this will leak `ipcRenderer` via `event.sender`. +Use a custom handler that invoke the `callback` only with the desired arguments. ::: :::info @@ -486,10 +488,10 @@ To tie it all together, we'll create an interface in the loaded HTML file that c Finally, to make the values update in the HTML document, we'll add a few lines of DOM manipulation so that the value of the `#counter` element is updated whenever we fire an `update-counter` event. -```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(event:Electron.IpcRendererEvent,value:number)=>void)=>void}} +```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(value:number)=>void)=>void}} const counter = document.getElementById('counter') -window.electronAPI.onUpdateCounter((_event, value) => { +window.electronAPI.onUpdateCounter((value) => { const oldValue = Number(counter.innerText) const newValue = oldValue + value counter.innerText = newValue.toString() @@ -506,17 +508,26 @@ There's no equivalent for `ipcRenderer.invoke` for main-to-renderer IPC. Instead send a reply back to the main process from within the `ipcRenderer.on` callback. We can demonstrate this with slight modifications to the code from the previous example. In the -renderer process, use the `event` parameter to send a reply back to the main process through the +renderer process, expose another API to send a reply back to the main process through the `counter-value` channel. -```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(event:Electron.IpcRendererEvent,value:number)=>void)=>void}} +```javascript title='preload.js (Preload Script)' +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('electronAPI', { + onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value)), + counterValue: (value) => ipcRenderer.send('counter-value', value) +}) +``` + +```javascript title='renderer.js (Renderer Process)' @ts-window-type={electronAPI:{onUpdateCounter:(callback:(value:number)=>void)=>void,counterValue:(value:number)=>void}} const counter = document.getElementById('counter') -window.electronAPI.onUpdateCounter((event, value) => { +window.electronAPI.onUpdateCounter((value) => { const oldValue = Number(counter.innerText) const newValue = oldValue + value counter.innerText = newValue.toString() - event.sender.send('counter-value', newValue) + window.electronAPI.counterValue(newValue) }) ```