メインコンテンツへ飛ぶ

contextBridge

History

分離されたコンテキスト間に、安全、双方向で同期されたブリッジを作成します

プロセス: レンダラー

分離されたプリロードスクリプトから API をレンダラーに公開する例を以下に示します。

// プリロード (隔離ワールド)
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// レンダラー (メインワールド)

window.electron.doThing()

用語集

メインワールド

"メインワールド" は、メインレンダラーコードが実行される JavaScript コンテキストです。 デフォルトでは、レンダラーでロードしたページはこのワールドでコードを実行します。

隔離ワールド

webPreferencescontextIsolation が有効 (これは Electron 12.0.0 からの既定の動作) になっている場合、preload スクリプトは "隔離ワールド" で実行されます。 コンテキスト分離とその効果の詳細については、セキュリティ のドキュメントを参照してください。

メソッド

contextBridge モジュールには以下のメソッドがあります。

contextBridge.exposeInMainWorld(apiKey, api)

  • apiKey string - window に API を注入するキー。 その API には window[apiKey] でアクセスできます。
  • api Record - あなたの API です。この詳細と動作については下記を参照してください。

contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)

  • worldId Integer - API を注入するワールドの ID です。 0 はデフォルトのワールドで、999 は Electron の contextIsolation 機能で使用されるワールドです。 999 を使用すると、プリロードコンテキストのオブジェクトが公開されます。 隔離ワールドを作成する際には 1000 以上の使用を推奨します。
  • apiKey string - window に API を注入するキー。 その API には window[apiKey] でアクセスできます。
  • api Record - あなたの API です。この詳細と動作については下記を参照してください。

contextBridge.executeInMainWorld(executionScript) 実験的

  • executionScript オブジェクト
    • func (...args: any[]) => any - 実行する JavaScript 関数。 この関数はシリアル化され、バインドされたパラメータと実行コンテキストは失われます。
    • args any[] (任意) - 指定された関数に渡す引数の配列。 これらの引数は 引数 / エラー / 戻り値型のサポート に従って、コンテキスト間でコピーされます。

戻り値 any - メインコンテキストで関数を実行した結果の値のコピー。 コンテキスト間の値のコピー方法については、表を参照してください

使い方

API

exposeInMainWorld に指定する api は、FunctionstringnumberArrayboolean、または文字列のキーで FunctionstringnumberArrayboolean、同じ条件を満たすオブジェクトのいずれかの値の、入れ子でなければなりません。

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')
}
)
// レンダラー (ワールド ID 1004 で隔離されています)

window.electron.doThing()

API 関数

contextBridge を介してバインドした Function 値は、コンテキストが分離されたままになるように Electron を介してプロキシされます。 これにより、以下に概説するいくつかの重要な制限が生じます。

引数 / エラー / 戻り値型のサポート

引数、エラー、戻り値は、ブリッジを介して送信されるときに コピー されるため、使用できるのは特定の型のみです。 高水準なものは、使用したい型をシリアライズおよびデシリアライズして、同じように動作するオブジェクトにできます。 以下の型サポートの表に全てが載っています。

種類複雑さ引数サポート戻り値サポート制限事項
文字列型単純なし
number単純なし
boolean単純なし
Object複雑キーにはこの表の "単純" な型のみの使用をサポートしています。 値にはこの表のものをサポートしています。 プロトタイプの変更は削除されます。 カスタムクラスを送信すると、値はコピーされますが、プロトタイプはコピーされません。
Array複雑制限は Object 型と同じです
エラー複雑送出された Error もコピーされるため、異なるコンテキストで投げられたためにエラーのメッセージやスタックトレースが少し変化することがあります。また、Error オブジェクトのカスタムプロパティは 失われます
Promise複雑なし
Function複雑プロトタイプの変更は削除されます。 クラスまたはコンストラクターを送信しても動作しません。
複製可能型単純複製可能型に関してはリンクのドキュメントを参照してください
Element複雑プロトタイプの変更は削除されます。 カスタム要素の送信は動作しません。
Blob複雑なし
VideoFrame複雑なし
SymbolなしSymbol はコンテキスト間でコピーできないため、削除されます

関心のある型が上記の表にない場合、それはおそらくサポートされていません。

ipcRenderer の露出

ipcRenderer モジュール全体をオブジェクトとして contextBridge 経由で送信しようとすると、ブリッジの受信側に空のオブジェクトを生成します。 ipcRenderer 全体を送信すると、どのコードでも任意のメッセージを送信できるようになり、セキュリティの大きな穴になります。 ipcRenderer を介して操作する際は、以下のように安全なラッパを提供してください。

// プリロード (隔離されたワールド)
contextBridge.exposeInMainWorld('electron', {
onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args))
})
// レンダラー (メインワールド)
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')
}
})