contextBridge
Создайте безопасный двусторонний синхронный мост между изолированными контекстами
Процесс: Рендеринг
Ниже приведён пример экспонирования API для рендера из изолированного скрипта предварительной загрузки:
// Preload (Isolated World)
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (Main World) window.electron.doThing()
Глоссарий
Основной мир
«Основной мир» — это контекст JavaScript, в котором выполняется код основного кода рендеринга. По умолчанию код страницы, загруженной в вашем рендере, выполняется в этом мире.
Изолированный мир
Когда contextIsolation включён в вашем webPreferences (это стандартное поведение с Electron 12.0.0), ваши скрипты preload выполняются в «Изолированном мире». Подробнее об изоляции контекстов и её последствиях можно узнать в документации по безопасности.
Методы
Модуль contextBridge имеет следующие методы:
contextBridge.exposeInMainWorld(apiKey, api)
-
apiKeyстрока - Ключ для вставки API вwindow. API будет доступно вwindow[apiKey]. -
apiлюбой - Ваш API. Более подробную информацию о том, каким может быть этот API и как он работает, можно найти ниже.
Использование
API
API, предоставленное exposeInMainWorld, должно быть Function, string, number, Array, boolean или объектом, ключи которого — строки, а значения — Function, string, number, Array, boolean или другой вложенный объект, удовлетворяющий тем же условиям.
Значения Function проксируются в другой контекст, а все остальные значения копируются и замораживаются. Любые данные/примитивы, отправленные в API, становятся неизменяемыми, а обновления с одной стороны моста не приводят к обновлению с другой.
Пример сложного API представлен ниже:
const { contextBridge } = 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
})
}
}
}
}
)
Функции API
Значения Function, которые вы привязываете через contextBridge, проксируются через Electron, чтобы гарантировать изоляцию контекстов. Это приводит к некоторым ключевым ограничениям, которые мы описали ниже.
Поддержка параметров/ошибок/типов возвращаемых значений
Поскольку параметры, ошибки и значения возвращаемых данных копируются при передаче через мост, существуют лишь определённые типы, которые могут быть использованы. В общих чертах, если тип, который вы хотите использовать, может быть сериализован и десериализован в тот же объект, он будет работать. Для полноты ниже приведена таблица поддержки типов:
| Тип | Сложность | Поддержка параметров | Поддержка возвращаемых значений | Ограничения |
|---|---|---|---|---|
string |
Простой | ✅ | ✅ | Нет |
number |
Простой | ✅ | ✅ | Нет |
boolean |
Простой | ✅ | ✅ | Нет |
Object |
Сложный | ✅ | ✅ | Ключи должны поддерживаться, используя только «Простые» типы в этой таблице. Значения должны поддерживаться в этой таблице. Изменения прототипа отбрасываются. Отправка пользовательских классов скопирует значения, но не прототип. |
Array |
Сложный | ✅ | ✅ | Те же ограничения, что и для типа Object |
Error |
Сложный | ✅ | ✅ | Выбрасываемые ошибки также копируются, что может привести к незначительному изменению сообщения и трассировки стека ошибки из-за её выбрасывания в другом контексте, а любые пользовательские свойства объекта Error будут потеряны |
Promise |
Сложный | ✅ | ✅ | Нет |
Function |
Сложный | ✅ | ✅ | Изменения прототипа отбрасываются. Отправка классов или конструкторов не сработает. |
| Клонируемые типы | Простой | ✅ | ✅ | См. связанный документ по клонируемым типам |
Element |
Сложный | ✅ | ✅ | Изменения прототипа отбрасываются. Отправка пользовательских элементов не сработает. |
Blob |
Сложный | ✅ | ✅ | Нет |
Symbol |
Нет | ❌ | ❌ | Символы не могут быть скопированы между контекстами, поэтому они отбрасываются |
Если нужный вам тип не указан в таблице, скорее всего, он не поддерживается.
Экспонирование глобальных символов Node
contextBridge может использоваться скриптом предварительной загрузки, чтобы предоставить вашему рендереру доступ к Node API. Таблица поддерживаемых типов, описанная выше, также применима к Node API, которые вы экспонируете через contextBridge. Обратите внимание, что многие Node API предоставляют доступ к локальным системным ресурсам. Будьте очень осторожны, какие глобальные переменные и API вы экспонируете ненадёжному удалённому содержимому.
const { contextBridge } = require('electron')
const crypto = require('crypto')
contextBridge.exposeInMainWorld('nodeCrypto', {
sha256sum (data) {
const hash = crypto.createHash('sha256')
hash.update(data)
return hash.digest('hex')
}
})
© GitHub Inc.
Licensed under the MIT license.
https://www.electronjs.org/docs/latest/api/context-bridge