contextBridge
History
| Version(s) | Changes |
|---|---|
None |
|
Создает безопасный, двунаправленный, синхронный мост через изолированные контексты
Process: Renderer
Пример предоставления API-интерфейса средству визуализации из изолированного сценария предварительной загрузки приведен ниже:
// Предварительная загрузка (Isolated World/Изолированный Мир)
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Рендер (Main World/Основной Мир)
window.electron.doThing()
Глоссарий
Main World / Основной Мир
"Main World" - это контекст javascript, в котором запускается ваш основной код рендера. По умолчанию загружаемая вами страница выполняет код в этом контексте.
Isolated World / Изолированный Мир
Когда contextIsolation включен в вашем webPreferences (Это стандартное поведение в Electron 12.0.0) ваши preload скрипты выполняются в "Isolated World". You can read more about context isolation and what it affects in the security docs.
Методы
Модуль contextBridge имеет следующие методы:
contextBridge.exposeInMainWorld(apiKey, api)
apiKeystring - Ключ для вставки API вwindow. API будет доступен вwindow[apiKey].apiRecord - Ваш объект API, более подробная информация о том, что это и как он будет работать, доступна ниже.
contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)
worldIdInteger - The ID of the world to inject the API into.0is the default world,999is the world used by Electron'scontextIsolationfeature. Using 999 would expose the object for preload context. We recommend using 1000+ while creating isolated world.apiKeystring - Ключ для вставки API вwindow. API будет доступен вwindow[apiKey].apiRecord - Ваш объект API, более подробная информация о том, что это и как он будет работать, доступна ниже.
contextBridge.executeInMainWorld(executionScript) Экспериментально
- Объект
executionScriptfunc(...args: any[]) => any - A JavaScript function to execute. This function will be serialized which means that any bound parameters and execution context will be lost.argsany[] (optional) - An array of arguments to pass to the provided function. These arguments will be copied between worlds in accordance with the table of supported types.
Returns any - A copy of the resulting value from executing the function in the main world. Refer to the table on how values are copied between worlds.
Usage
API
The api provided to exposeInMainWorld must be a Function, string, number, Array, boolean, or an object whose keys are strings and values are a Function, string, number, Array, boolean, or another nested object that meets the same conditions.
Значения Function передаются в другой контекст, а все остальные значения копируются и заморожены. То есть Любые данные / примитивы, отправленные в объекте API, становятся неизменяемыми, и обновления на любой стороне моста не приводят к обновлению на другой стороне.
Пример сложного объекта API показан ниже:
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()
Функции API
Значения Function, которые вы связываете через contextBridge, передаются через Electron, чтобы гарантировать, что контексты остаются изолированными. Это приводит к некоторым ключевым ограничениям, которые мы описали ниже.
Параметр / Ошибка / Поддержка возвращаемого типа
Поскольку параметры, ошибки и возвращаемые значения скопированы при отправке через мост, существуют только определенные типы, которые могут быть использованы. На высоком уровне, если тип, который вы хотите использовать, может быть сериализован и десериализован в один и тот же объект, то он будет работать. Ниже для полноты изложения приводится таблица поддержки типов:
| Тип | Сложность | Поддержка параметров | Возврат значения поддержки | Ограничения |
|---|---|---|---|---|
string | Простой | ✅ | ✅ | Нет |
number | Простой | ✅ | ✅ | Нет |
boolean | Простой | ✅ | ✅ | Нет |
Object | Сложный | ✅ | ✅ | Ключи должны поддерживаться «Простыми» типами в этой таблице. Значения должны поддерживаться в этой таблице. Модификации прототипа отбрасываются. Отправка пользовательских классов будет копировать значения, но не прототип. |
Array | Сложный | ✅ | ✅ | Те же ограничения, что и в типе Object |
Error | Сложный | ✅ | ✅ | 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 | Сложный | ✅ | ✅ | Нет |
Function | Сложный | ✅ | ✅ | Модификации прототипа отбрасываются. Отправка классов или конструкторов не будет работать. |
| Cloneable Types | Простой | ✅ | ✅ | Смотрите связанный документ по клонируемым типам |
Element | Сложный | ✅ | ✅ | Модификации прототипа отбрасываются. Отправка пользовательских элементов не будет работать. |
Blob | Сложный | ✅ | ✅ | Нет |
Symbol | Нет | ❌ | ❌ | Символы не могут быть скопированы в разных контекстах, поэтому они отбрасываются |
Если тип, о котором вы хотите использовать, не находится в приведенной выше таблице, то он, вероятно, не поддерживается.
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 => { /* ... */ })
Exposing Node Global Symbols
contextBridge может использоваться скриптом preload для предоставления вашему устройству доступа к узлам API. Таблица поддерживаемых типов, описанная выше, также применяется к Node API, которые вы используете через contextBridge. Пожалуйста, обратите внимание, что многие Node API предоставляют доступ к локальным системным ресурсам. Будьте очень осторожны относительно того, какие глобальные переменные и API вы предоставляете в ненадежном удаленном контенте.
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')
}
})