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コンテキストです。デフォルトでは、レンダラーにロードしたページはこのワールドでコードを実行します。
分離されたワールド
webPreferences
でcontextIsolation
が有効になっている場合(Electron 12.0.0以降のデフォルトの動作です)、preload
スクリプトは「分離されたワールド」で実行されます。コンテキストの分離とその影響について詳しくは、セキュリティドキュメントをご覧ください。
メソッド
contextBridge
モジュールには、以下のメソッドがあります
contextBridge.exposeInMainWorld(apiKey, api)
apiKey
文字列 - APIをwindow
に挿入するキー。APIはwindow[apiKey]
でアクセスできます。api
任意 - API。このAPIの内容と動作方法については、以下をご覧ください。
contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)
worldId
整数 - APIを挿入するワールドのID。0
はデフォルトのワールド、999
はElectronのcontextIsolation
機能で使用されるワールドです。999を使用すると、プリロードコンテキストのオブジェクトが公開されます。分離されたワールドを作成する際は、1000以上を使用することをお勧めします。apiKey
文字列 - APIをwindow
に挿入するキー。APIはwindow[apiKey]
でアクセスできます。api
任意 - API。このAPIの内容と動作方法については、以下をご覧ください。
使用方法
API
exposeInMainWorld
に提供されるapi
は、Function
、string
、number
、Array
、boolean
、またはキーが文字列で値がFunction
、string
、number
、Array
、boolean
、または同じ条件を満たす別のネストされたオブジェクトであるオブジェクトでなければなりません。
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
})
}
}
}
}
)
exposeInIsolatedWorld
の例を以下に示します
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInIsolatedWorld(
1004,
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (In isolated world id1004)
window.electron.doThing()
API関数
contextBridge
を介してバインドするFunction
値は、コンテキストが分離された状態を維持するためにElectronを介してプロキシされます。これにより、以下に概説するいくつかの重要な制限事項が生じます。
パラメータ/エラー/戻り値の型のサポート
パラメータ、エラー、戻り値はブリッジを介して送信されるときに**コピー**されるため、使用できる型は限られています。大まかに言うと、使用したい型が同じオブジェクトにシリアライズおよびデシリアライズできる場合は、機能します。完全を期すために、型のサポートの表を以下に示します
型 | 複雑度 | パラメータサポート | 戻り値サポート | 制限事項 |
---|---|---|---|---|
string | 単純 | ✅ | ✅ | N/A |
number | 単純 | ✅ | ✅ | N/A |
boolean | 単純 | ✅ | ✅ | N/A |
Object | 複合 | ✅ | ✅ | キーは、この表の「単純」型のみを使用してサポートする必要があります。値はこの表でサポートされている必要があります。プロトタイプの変更は破棄されます。カスタムクラスを送信すると、値はコピーされますが、プロトタイプはコピーされません。 |
Array | 複合 | ✅ | ✅ | Object 型と同じ制限事項 |
Error | 複合 | ✅ | ✅ | スローされるエラーもコピーされます。これは、異なるコンテキストでスローされるため、エラーのメッセージとスタックトレースがわずかに変更される可能性があり、Errorオブジェクトのカスタムプロパティは失われます |
Promise | 複合 | ✅ | ✅ | N/A |
Function | 複合 | ✅ | ✅ | プロトタイプの変更は破棄されます。クラスまたはコンストラクタの送信は機能しません。 |
クローン可能な型 | 単純 | ✅ | ✅ | クローン可能な型に関するリンク先のドキュメントを参照してください |
Element | 複合 | ✅ | ✅ | プロトタイプの変更は破棄されます。カスタム要素の送信は機能しません。 |
Blob | 複合 | ✅ | ✅ | N/A |
Symbol | N/A | ❌ | ❌ | シンボルはコンテキスト間でコピーできないため、破棄されます |
気になる型が上記の表にない場合は、おそらくサポートされていません。
ipcRendererの公開
ipcRenderer
モジュール全体をオブジェクトとしてcontextBridge
を介して送信しようとすると、ブリッジの受信側で空のオブジェクトが生成されます。ipcRenderer
を完全に送信すると、あらゆるコードがあらゆるメッセージを送信できるようになり、セキュリティ上の弱点になります。ipcRenderer
を介して対話するには、以下のような安全なラッパーを提供します
// Preload (Isolated World)
contextBridge.exposeInMainWorld('electron', {
onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args))
})
// Renderer (Main World)
window.electron.onMyEventName(data => { /* ... */ })
Nodeグローバルシンボルの公開
プリロードスクリプトは、contextBridge
を使用して、レンダラーにNode APIへのアクセスを許可できます。上記で説明したサポートされている型の表は、contextBridge
を介して公開するNode APIにも適用されます。多くの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')
}
})