Aller au contenu principal

contextBridge

History

Crée un pont synchrone sécurisé, bidirectionnel entre des contextes isolés

Process: Renderer

Exemple d’une API exposée à un moteur de rendu à partir d’un script de preload:

// Preload (Univers Isolé)
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (Univers principal)

window.electron.doThing()

Glossaire

Univers principal (Main World)

« Main World » est le contexte JavaScript dans lequel votre code de rendu principal s'exécute. Par défaut, la page que vous chargez dans votre moteur de rendu exécute son code dans cet univers.

Univers isolé (Isolated World)

Votre script preload s'exécute dans un "Isolated World" lorsque contextIsolation est activé dans vos webPreferences (ce qui est le comportement par défaut depuis Electron 12.0.0). You can read more about context isolation and what it affects in the security docs.

Méthodes

Le module contextBridge possède les méthodes suivantes :

contextBridge.exposeInMainWorld(apiKey, api)

  • apiKey string - Clé à utiliser pour injecter l'API dans fenêtre. L’API sera accessible par window[apiKey].
  • api any- Votre API, plus d'informations sur ce que peut être cette API et son fonctionnement est disponible ci-dessous.

contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)

  • worldId Integer - L'ID de l'univers dans lequel injecter l'API. 0 est l'univers par défaut, 999 est celui utilisé par la fonctionnalité contextIsolation d'Electron. Utiliser 999 exposera l'objet pour le contexte du préchargement. Nous vous recommandons d’utiliser les valeurs 1000 et+ lors de la création d’un univers isolé.
  • apiKey string - Clé à utiliser pour injecter l'API dans fenêtre. L’API sera accessible par window[apiKey].
  • api any- Votre API, plus d'informations sur ce que peut être cette API et son fonctionnement est disponible ci-dessous.

Utilisation

API

L' api fournie à exposeInMainWorld peut être du type Function, string, number, Array, boolean ou un objet dont les clés sont des chaînes de caractères et les valeurs du type Function, string, number, Array, boolean ou bien encore un autre objet imbriqué remplissant les mêmes conditions.

Les valeurs de type Function sont "proxyfiées" vers l'autre contexte et toutes les autres valeurs sont copiées et gelées. Toutes les données ou primitives envoyées à l'API deviennent immuables et les mises à jour d'un coté ou de l'autre du contextBridge ne donnent pas lieu à une mise à jour de l'autre côté.

Exemple d’API complexe:

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
})
}
}
}
}
)

Voici ci-dessous un exemple de l'utilisation de exposeInIsolatedWorld:

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInIsolatedWorld(
1004,
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Rendu (Dans l'univers isolé id1004)

window.electron.doThing()

Fonction de l'API

Les valeurs de type Function que vous liez à travers le contextBridge sont servies par l'intermédiaire d'Electron qui agit en tant que proxy pour s'assurer que les contextes restent isolés. Ceci entraîne certaines restrictions décrites ci-dessous.

Prise en charge des paramètres, erreurs et type de retour

Étant donné que les paramètres, erreurs et valeurs de retour sont copiés lors de leur transmission par le contextBrideg, seuls certains types peuvent être utilisés. Mais si le type que vous voulez utiliser peut être sérialisé et désérialisé dans le même objet cela fonctionnera. Une table des types supportés est incluse en complément:

TypeComplexitéPrise en charge de paramètresPrise en charge de valeur de retourLimitations
stringSimpleN/A
numberSimpleN/A
booleanSimpleN/A
ObjetComplexeLes clés prises en charge ne doivent utiliser que les types "Simple" dans cette table. Les valeurs doivent être supportées dans cette table. Les modifications du prototype sont supprimées. L'envoi de classes personnalisées copiera les valeurs mais pas le prototype.
ArrayComplexeLimitation identique au type Object
ErreurComplexeLes erreurs levées sont également copiées, ce qui peut entraîner une légère modification du message et de la trace de pile de l’erreur en raison du lancement dans un contexte différent, toutes les propriétés personnalisées de l’objet Error seront également perdues
PromiseComplexeN/A
FunctionComplexeLes modifications du prototype sont supprimées. L'envoi de classes ou de constructeurs ne fonctionnera pas.
Types clonablesSimpleVoir le document lié sur les types clonables
ÉlémentComplexeLes modifications du prototype sont supprimées. L'envoi d'éléments personnalisés ne fonctionnera pas.
Objet blobComplexeN/A
SymboleN/ALes symboles ne peuvent pas être copiés de contexte à contexte, donc ils sont abandonnés

Si le type qui vous intéresse n'est pas dans la table ci-dessus, il n'est probablement pas pris en charge.

Exposition de l'ipcRenderer

Toute tentative d'envoie du module ipcRenderer entier comme un objet via le contextBridge entraînera la réception d'un objet vide du côté récepteur du pont. L'envoie de l'ipcRenderer dans son intégralité permettrait à n'importe quel code d'envoyer n'importe quel message et équivaudrait à se tirer une balle dans le pied. Pour interagir à travers ipcRenderer, vous devrez alors utiliser un wrapper sûr comme ci-dessous:

// Preload (Isolated World)
contextBridge.exposeInMainWorld('electron', {
onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args))
})
// Renderer (Main World)
window.electron.onMyEventName(data => { /* ... */ })

Exposition des symboles globaux de Node

Le contextBridge peut être utilisé par le script de préchargement pour donner à votre moteur de rendu l'accès aux API de Node. La table des types supportés ci-dessus s'applique également aux API Node que vous exposez à travers contextBridge. Notez bien que de nombreuses API Node accordent l'accès aux ressources du système local. Soyez donc très prudent quant aux globales et aux API que vous pourriez exposer à des contenus distants non fiables.

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')
}
})