contextBridge
History
Version(s) | Changes |
---|---|
None |
|
Cree un puente seguro, bidireccional y sincrónico a través de contextos aislados
Process: 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". You can read more about context isolation and what it affects in the security docs.
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 ventanawindow
. La API será accesible enwindow[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'scontextIsolation
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 ventanawindow
. La API será accesible enwindow[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:
Tipo | Complejidad | Soporte de parámetros | Valor de Retorno Soportado | Limitaciones |
---|---|---|---|---|
string | Simple | ✅ | ✅ | N/A |
number | Simple | ✅ | ✅ | N/A |
booleano | Simple | ✅ | ✅ | N/A |
Object | Complejo | ✅ | ✅ | Las 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. |
Array | Complejo | ✅ | ✅ | Mismas limitaciones para el tipo Object |
Error | Complejo | ✅ | ✅ | Errors 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 |
Promise | Complejo | ✅ | ✅ | N/A |
Function | Complejo | ✅ | ✅ | Las modificaciones del prototipo se eliminan. Enviar clases o constructores no funcionará. |
Tipos Clonables | Simple | ✅ | ✅ | Veer el documento vinculado en tipos clonables |
Elemento | Complejo | ✅ | ✅ | Las modificaciones del prototipo se eliminan. Enviar elementos personalizados no funcionará. |
Blob | Complejo | ✅ | ✅ | N/A |
Símbolo | N/A | ❌ | ❌ | Los 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')
}
})