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?
Enable nodeIntegration option when creating a windowconst window = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, }, }); You should understand all potential security risk when enabling this option. Do not enable this option if you load some third-party resources to BrowserWindow.
Electron node integration refers to the ability of accessing Node. js resources from within the “renderer” thread (the UI). It is enabled by default in Quasar CLI, although Electron is encouraging developers to turn it off as a security precaution.
However, Electron applications are notoriously known to have security issues. Since they combine traditional web technologies with the code running on and having access to the operating system through the Node.
To begin developing an Electron app, you need to install the Node. js runtime and its bundled npm package manager onto your system. We recommend that you use the latest long-term support (LTS) version. Please install Node.
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.
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.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With