4
votes

Avec contextIsolation = true, est-il possible d'utiliser ipcRenderer?

Voici ma configuration:

Étape 1. Créez un fichier preload.js avec le code:

  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
      contextIsolation: true,
      nodeIntegration: false,
      preload: __dirname + '/preload.js'
    }
  });

Étape 2. Préchargez ce fichier dans votre main.js via webPreferences:

console.log(window.ipcRenderer); // Works!

Étape 3. Dans un moteur de rendu:

  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      preload: __dirname + '/preload.js'
    }
  });

En suivant maintenant le guide de sécurité d'Electron, je souhaite activer contextIsolation = true : https://electronjs.org/docs/tutorial/security#3-enable-context-isolation-for-remote-content

Étape 2bis.

window.ipcRenderer = require('electron').ipcRenderer;


1 commentaires

J'ai mis à jour ma réponse, si vous cherchez toujours une réponse.


3 Réponses :


0
votes

Notez cette phrase au milieu de description de l'isolation du contexte . C'est facile à rater.

L'API Electron ne sera disponible que dans le script préchargement et non dans la page chargée.

On dirait que la réponse est non.


3 commentaires

Savez-vous comment les processus principal et de rendu peuvent-ils communiquer dans ce cas?


@amaurymartiny Sur la base de mes tests, Node est totalement désactivé dans le moteur de rendu (même s'il n'y a pas de webview ), et je ne peux pas exiger ipcRenderer , donc il ne semble pas comme le rendu peut parler à main. Cela étant dit, il est un peu étrange que ce soit le comportement, car je pensais que cela n'affecterait que la vue Web / préchargement et c'est la raison pour laquelle j'ai publié ce problème.


@amaurymartiny Cela pourrait aider. On dirait que les API Electron sont disponibles en précharge et en main. Vous devriez donc toujours pouvoir envoyer des messages de préchargement à main, mais pas du moteur de rendu de la vue Web / préchargement à l’autre moteur de rendu «enveloppant»



5
votes

nouvelle réponse

Vous pouvez suivre la configuration décrite ici a >. Cette configuration est utilisée dans secure-electron-template En gros, voici ce que vous pouvez faire:

main.js

let win;

async function createWindow() {

  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      nodeIntegrationInWorker: false,
      nodeIntegrationInSubFrames: false,
      contextIsolation: true,
      enableRemoteModule: false,
      preload: path.join(__dirname, "preload.js")
    }
  });
}

preload.js strong >

const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld(
    "electron",
    {
        ipcRenderer: ipcRenderer
    }
);

index.html

<!doctype html>
<html lang="en-US">
<head>
    <meta charset="utf-8"/>
    <title>Title</title>
</head>
<body>
    <script>
        window.api.receive("fromMain", (data) => {
            console.log(`Received ${data} from main process`);
        });
        window.api.send("toMain", "some data");
    </script>
</body>
</html>

original

Vous sont toujours capables d'utiliser ipcRenderer dans un processus de rendu avec contextIsolation défini sur true. Le contextBridge est ce que vous souhaitez utiliser, bien qu'il existe un bug actuel qui vous empêche d'appeler ipcRenderer.on dans un processus de rendu; tout ce que vous pouvez faire est d'envoyer du processus de rendu au processus principal.

Ce code est extrait de secure-electron-template un modèle pour Electron construit avec la sécurité à l'esprit. (Je suis l'auteur)

preload.js

const {
    contextBridge,
    ipcRenderer
} = require("electron");

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
    "api", {
        send: (channel, data) => {
            // whitelist channels
            let validChannels = ["toMain"];
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, data);
            }
        },
        receive: (channel, func) => {
            let validChannels = ["fromMain"];
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender` 
                ipcRenderer.on(channel, (event, ...args) => func(...args));
            }
        }
    }
);

main.js p>

const {
  app,
  BrowserWindow,
  ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;

async function createWindow() {

  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false, // is default value after Electron v5
      contextIsolation: true, // protect against prototype pollution
      enableRemoteModule: false, // turn off remote
      preload: path.join(__dirname, "preload.js") // use a preload script
    }
  });

  // Load app
  win.loadFile(path.join(__dirname, "dist/index.html"));

  // rest of code..
}

app.on("ready", createWindow);

ipcMain.on("toMain", (event, args) => {
  fs.readFile("path/to/file", (error, data) => {
    // Do something with file contents

    // Send result back to renderer process
    win.webContents.send("fromMain", responseObj);
  });
});

un fichier renderer.js

window.electron.ipcRenderer

h1>


2 commentaires

Ceci n'est toujours pas sûr. Même avec un contextBridge, exposer l'intégralité de l'ipcRenderer en tant que méthode au moteur de rendu peut conduire à des abus: electronjs.org/docs/tutorial/...


@ user1679669 Nous exposons un sous-ensemble d'opérations autorisées sur ipcRenderer, qui n'est pas le même que le lien que vous avez publié. Veuillez consulter la section nouvelle réponse pour un meilleur exemple de ce que vous pouvez faire.



0
votes

Veuillez vérifier ceci . Ça marche pour moi. J'utilise CRA et Electron.

preload.js

    {
      "dependencies": {
        "cross-env": "7.0.2",
        "deepmerge": "4.2.2",
        "electron-is-dev": "1.2.0",
        "electron-log": "4.2.2",
        "electron-updater": "4.3.1",
        "sequelize-cli": "6.2.0",
        "sequelize": "6.3.3",
        "sqlite3": "5.0.0",
        "umzug": "2.3.0",
        "uuid": "8.2.0"
      },
      "devDependencies": {
        "concurrently": "5.2.0",
        "electron": "9.1.0",
        "electron-builder": "22.7.0",
        "spectron": "11.1.0",
        "wait-on": "5.1.0",
        "xvfb-maybe": "0.2.1"
      }
    }

main.js

XXX

preloadUtils.js

    const { MESSAGE_TYPES, sendMessage } = window.ELECTRON || {};
    
    if (!MESSAGE_TYPES) return;
    
    const actions = {
      [MESSAGE_TYPES.INITIAL_DATA_SYNC]: (event, initialSync) => {
        console.log(MESSAGE_TYPES.INITIAL_DATA_SYNC, initialSync);
      },
    
      [MESSAGE_TYPES.ONLINE_MODEL_SYNC]: (event, message) => {
        console.log(MESSAGE_TYPES.ONLINE_MODEL_SYNC, message);
      },
    
      [MESSAGE_TYPES.APP_ONLINE]: (event, isOnline) => {
        console.log(MESSAGE_TYPES.APP_ONLINE, isOnline);
      },
    };
    
    const registerActions = () => {
      const { onReceiveMessage } = window.ELECTRON;
    
      Object.keys(actions).forEach((messageType) => {
        onReceiveMessage(messageType, actions[messageType]);
      });
    };
    
    registerActions();

messageTypes.js

XXX

actions.js (moteur de rendu)

    module.exports = {
      DNS_ONLINE_STATUS: 'dns-online-status',
      APP_ONLINE_STATUS: 'online-status',
      ONLINE_MODEL_SYNC: 'online-model-sync',
      APP_ONLINE: 'app-online',
      INITIAL_DATA_SYNC: 'INITIAL_DATA_SYNC',
      GET_MESSAGE_TYPES: 'GET_MESSAGE_TYPES',
    };

package.json p>

    const { ipcMain } = require('electron');
    const MESSAGE_TYPES = require('../utils/messageTypes');
    
    const registerPreloadImports = () => {
      ipcMain.on(MESSAGE_TYPES.GET_MESSAGE_TYPES, (event, message) => {
        event.returnValue = MESSAGE_TYPES;
      });
    };
    
    module.exports = registerPreloadImports;


0 commentaires