Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Electron 'contextBridge'

To provide suitable levels of security when loading remote content, it is stated that a BrowserWindow's contextIsolation and nodeIntegration options must be enabled and disabled respectively. In this scenario, Node/Electron APIs will not be available to the main renderer process. In order to expose specific functionality, the window's preload script may exploit Electron's contextBridge feature, providing the main renderer with access to selected Node/Electron APIs.

Despite information provided in the Electron docs, concrete examples of contextBridge usage are lacking overall. In general, existing documentation/tutorials do not focus on adopting secure practices when implementing an Electron app.

The following is a single contextBridge usage example I've managed to find online: https://github.com/reZach/secure-electron-template

Would you be able to provide additional resources/examples which might be useful for the implementation of a secure Electron app (which relies on the contextBridge functionality)?

Insight regarding contextBridge best practices is also highly appreciated.

like image 951
Questionnaire Avatar asked Jan 30 '20 19:01

Questionnaire


People also ask

What is contextBridge?

Create a safe, bi-directional, synchronous bridge across isolated contexts. Process: Renderer. An example of exposing an API to a renderer from an isolated preload script is given below: // Preload (Isolated World)

What is contextIsolation?

​ Context Isolation is a feature that ensures that both your preload scripts and Electron's internal logic run in a separate context to the website you load in a webContents .

What is electron preload?

Summary​ A preload script contains code that runs before your web page is loaded into the browser window. It has access to both DOM APIs and Node. js environment, and is often used to expose privileged APIs to the renderer via the contextBridge API.


1 Answers

Here are all the steps to set this up

  1. In your main electron index.js file, point to the preload script in your BrowserWindow config object:

new BrowserWindow({
  webPreferences: {
    preload: path.resolve(app.getAppPath(), 'preload.js')
  }
})
  1. The preload.js needs to be in your app folder. I use webpack to compile everything, so the preload.js file is not where my js code is, it's in the app directory where electron-builder will compile the executable. Here's what the preload.js contains:

process.once('loaded', () => {
  const { contextBridge, ipcRenderer, shell } = require('electron')
  
  contextBridge.exposeInMainWorld('electron', {
    on (eventName, callback) {
      ipcRenderer.on(eventName, callback)
    },

    async invoke (eventName, ...params) {
      return await ipcRenderer.invoke(eventName, ...params)
    },

    async shellOpenExternal (url) {
      await shell.openExternal(url)
    },

    async shellOpenPath (file) {
      await shell.openPath(file)
    },

    async shellTrashItem (file) {
      await shell.trashItem(file)
    }
  })
})
  1. All this is part of the node.js code. Now let's see how we use this code in our renderer code, the chrome client side code.

window.electron.on('nodeJSEvent', (event, param1, param2) => {
  console.log('nodeJSEvent has been called with params', param1, param2)
})

const foo = await window.electron.invoke('nodeJSEvent', param1, param2)
console.log(foo)

await window.electron.shellOpenExternal(url)

await window.electron.shellOpenPath(file)

await window.electron.shellTrashItem(file)

That's it. All this code is about giving the possibility to the client side code to call nodejs code that we define in the preload script.

like image 144
dreamLo Avatar answered Sep 28 '22 02:09

dreamLo