Saltar al contenido principal

contextBridge

History

Cree un puente seguro, bidireccional y sincrónico a través de contextos aislados

Proceso: Renderer

A continuación se muestra un ejemplo de exponer una API a un renderer desde un script de precarga aislado:

// Preload (Isolated World)
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (Main World)

window.electron.doThing()

Glosario

Main World

El "Main World" es el contexto de JavaScript que corre tu código renderer principal. Por defecto, la página que cargas en el tu renderer ejecuta código en este mundo.

Mundo aislado

Cuando contextIsolation está activado en tu webPreferences (este es el comportamiento por defecto desde Electron 12.0.0), tus scripts preload corren en un "Mundo aislado". Puede leer más sobre aislamiento del contexto y que afecta en los documentos security.

Métodos

El módulo contextBridge tiene los siguientes métodos:

contextBridge.exposeInMainWorld(apiKey, api)

  • apiKey string - La clave para inyectar la API en la ventana window. La API será accesible en window[apiKey].
  • api any - Tu API más información sobre qué puede ser esta API y como funciona esta disponible a continuación.

contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)

  • worldId Integer - The ID of the world to inject the API into. 0 is the default world, 999 is the world used by Electron's contextIsolation feature. Using 999 would expose the object for preload context. We recommend using 1000+ while creating isolated world.
  • apiKey string - La clave para inyectar la API en la ventana window. La API será accesible en window[apiKey].
  • api any - Tu API más información sobre qué puede ser esta API y como funciona esta disponible a continuación.

Uso

API

La api proveeida a exposeInMainWorld debe ser una Function, string, number, Array, boolean, o un objeto cuya llaves son strings y los valores son una Function, string, number, Array, boolean, u otro objeto anidado que cumpa con las mismas condiciones.

Los valores Function se transfieren a otro contexto y todos los demás valores son copiados y congedados. Cualquier dato / primitivos enviado en la API se vuelve inmutable y las actualizaciones de una lado del puente no resulta en una actualización en el otro lado.

A continuación se muestra un ejemplo de una API compleja:

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing'),
myPromises: [Promise.resolve(), Promise.reject(new Error('whoops'))],
anAsyncFunction: async () => 123,
data: {
myFlags: ['a', 'b', 'c'],
bootTime: 1234
},
nestedAPI: {
evenDeeper: {
youCanDoThisAsMuchAsYouWant: {
fn: () => ({
returnData: 123
})
}
}
}
}
)

An example of exposeInIsolatedWorld is shown below:

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInIsolatedWorld(
1004,
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (In isolated world id1004)

window.electron.doThing()

Funciones API

Los valores de Function que enlazas a través de contextBridge son proxyados a través de Electron para asegurar que los contextos permanezcan aislados. Esto da como resultado algunas limitaciones claves que hemos descrito a continuación.

Parámetro / Error / Tipo de Retorno soportado

Dado que los parámetros, errores y valores de retorno son copiados cuando son enviados sobre el puente, solo hay ciertos tipos que pueden ser usados. En un nivel alto, si el tipo que desea usar se puede serializar y deserializar en el mismo objeto, funcionará. A continuación, se incluye una tabla de soporte de tipo para que esté completa:

TipoComplejidadSoporte de parámetrosValor de Retorno SoportadoLimitaciones
stringSimpleN/A
numberSimpleN/A
booleanoSimpleN/A
ObjectComplejoLas llaves deben ser soportadas usando solo los tipos "Simple" en esta tabla. Los valores deben ser soportadas en esta tabla. Las modificaciones del prototipo se eliminan. Enviar clases personalizadas copiará valores pero no el prototipo.
ArrayComplejoMismas limitaciones para el tipo Object
ErrorComplejoErrors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object will be lost
PromiseComplejoN/A
FunctionComplejoLas modificaciones del prototipo se eliminan. Enviar clases o constructores no funcionará.
Tipos ClonablesSimpleVeer el documento vinculado en tipos clonables
ElementoComplejoLas modificaciones del prototipo se eliminan. Enviar elementos personalizados no funcionará.
BlobComplejoN/A
SímboloN/ALos Symbols no pueden ser copiados a través de contextos así que son eliminados

Si el tipo que te interesa no está en la tabla anterior, probablemente no esté soportado.

Exposing ipcRenderer

Attempting to send the entire ipcRenderer module as an object over the contextBridge will result in an empty object on the receiving side of the bridge. Sending over ipcRenderer in full can let any code send any message, which is a security footgun. To interact through ipcRenderer, provide a safe wrapper like below:

// Preload (Isolated World)
contextBridge.exposeInMainWorld('electron', {
onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args))
})
// Renderer (Main World)
window.electron.onMyEventName(data => { /* ... */ })

Exponer Global Symbols de Node

El contextBridge puede ser utilizado por el script de precarga para dar acceso al renderizador a las APIs de Node. La tabla de tipos soportados descrita anteriormente aplica también a las APIs de Node que expongas a través de contextBridge. Tenga en cuenta que muchas APIs de Nodo conceden acceso a los recursos del sistema local. Se muy cauteloso sobre que APIs y globales expones a contenido remoto que no es de confianza.

const { contextBridge } = require('electron')
const crypto = require('node:crypto')
contextBridge.exposeInMainWorld('nodeCrypto', {
sha256sum (data) {
const hash = crypto.createHash('sha256')
hash.update(data)
return hash.digest('hex')
}
})