Reputation: 321
I am stuck when creating custom window controls like close, min/max and restore with nodeIntegration turned off. I created the buttons in my renderer's local html file
main.js
mainWindow = new BrowserWindow({
x, y, width, height,
frame: false,
show: false,
webPreferences: { devTools: true }
});
mainWindow.loadURL(url.format({
protocol: 'file:',
slashes: true,
pathname: path.join(__dirname, 'assets', 'index.html')
}));
index.html
<div id='minimize' class='noSelect'></div>
<div id='maximize' class='noSelect'></div>
<div id='restore' class='noSelect'></div>
<div id='close' class='noSelect'></div>
<script type='text/javascript' src='../assets/js/index.js'></script>
By default, nodeIntegration is off so index.js
has no access to Node. However, I need to be able to add functionality to the buttons to close, min/max and restore the window.
index.js
const { remote } = require('electron');
const mainWindow = remote.getCurrentWindow();
document.getElementById('close').addEventListener('click', () => {
mainWindow.close();
});
This wouldn't work because of nodeIntegration being disabled. Is it safe to have it enabled in a local page? If not, what is a safe way of doing this?
Upvotes: 16
Views: 30065
Reputation: 3442
TL;DR: Enabling nodeIntegration
only imposes risks if you load and execute code from untrusted sources, i.e. the internet or from user input.
If you are completely sure that your application will only run the code you have created (and no NodeJS module loads scripts from the internet), basically, there is no to very little risk if enabling nodeIntegration
.
However, if you allow the user to run code (i.e. input and then eval
it) or you provide plug-in APIs from which you do not have any control over the plug-ins loaded, the risk level rises because NodeJS allows any NodeJS script, ex., to manipulate the filesystem.
On the other hand, if you disable nodeIntegration
, you have no way of communicating with the main process or manipulating the BrowserWindow
, thus cannot create custom window controls. However, you can use a "preload" script file to build a bridge between the completely isolated renderer and the NodeJS world.
This is done by creating a script file which is then passed to the BrowserWindow
as the preload:
configuration option upon creation. Electron's documentation has some examples to get you started. Also, it's a good idea to familiarise yourself with Eelectron's security recommendations.
Upvotes: 32
Reputation: 9
you don't need nodeIntegration since it delivers security issues, Instead use preload.js file
Why ?
-> Electron's main process (main.js) is a Node.js environment that has full OS access, renderer process (renderer.js) renders web pages not node.js because anyone can take data and can see the functionalities.
-> To bridge electron's different process types together, we need special script called 'preload.js'
-> preload script are injected before a webpage loads in the renderer.
Upvotes: 0
Reputation: 3592
Keep in mind, that in year 2021 you do not need nodeIntegration
to communicate with the main
process from the renderer
process.
Instead, you use message passing, like this:
main.js
const {app, BrowserWindow, ipcMain} = require("electron");
const path = require("path");
app.whenReady().then(open_window);
function open_window() {
// Explain: Create app window.
const appWin = new BrowserWindow({
width: 800,
height: 600,
opacity: 0.5,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
// Explain: Render the app.
void minisWindow.loadFile("index.html");
// Spec: User can hide App window by clicking the button.
ipcMain.on("hide-me", () => appWin.minimize());
// Spec-start: When User focuses App window - it becomes fully opaque.
ipcMain.on("make-window-opaque", () => appWin.setOpacity(1));
appWin.on("show", () => minisWindow.setOpacity(1));
appWin.on("blur", () => minisWindow.setOpacity(0.5));
// Spec-end.
}
preload.js
const {ipcRenderer} = require("electron");
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener("DOMContentLoaded", () => {
// Spec: User can hide App window by clicking the button.
document.querySelector("#hideBtn").addEventListener("click",
() => ipcRenderer.send("hide-me"));
});
// Spec: When User focuses App window - it becomes fully opaque.
document.body.addEventListener("click", () => ipcRenderer.send("make-window-opaque"));
});
This example illustrates two instances of message passing:
#hideBtn
button - a message is dispatched that instructs main
to hide the window.clickz
event on the body
) - a message is dispatched that instructs main
to make the window fully opaque.Upvotes: 9