From 78c5e9c7061fff7f550ebeb28711a47143f3c0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Thu, 5 Sep 2024 13:20:44 +0200 Subject: [PATCH] [PM-5506] Enable electron fuses (#10073) --- apps/desktop/scripts/after-pack.js | 59 ++++++++++++++++++++++++++++++ package-lock.json | 28 ++++++++++++++ package.json | 1 + 3 files changed, 88 insertions(+) diff --git a/apps/desktop/scripts/after-pack.js b/apps/desktop/scripts/after-pack.js index 1d23a9b52b..7d58898815 100644 --- a/apps/desktop/scripts/after-pack.js +++ b/apps/desktop/scripts/after-pack.js @@ -3,6 +3,8 @@ require("dotenv").config(); const child_process = require("child_process"); const path = require("path"); +const { flipFuses, FuseVersion, FuseV1Options } = require("@electron/fuses"); +const builder = require("electron-builder"); const fse = require("fs-extra"); exports.default = run; @@ -11,6 +13,10 @@ async function run(context) { console.log("## After pack"); // console.log(context); + if (context.packager.platform.nodeName !== "darwin" || context.arch === builder.Arch.universal) { + await addElectronFuses(context); + } + if (context.electronPlatformName === "linux") { console.log("Creating memory-protection wrapper script"); const appOutDir = context.appOutDir; @@ -83,3 +89,56 @@ function getIdentities(csc_name) { return { id, name }; }); } + +/** + * @param {import("electron-builder").AfterPackContext} context + */ +async function addElectronFuses(context) { + const platform = context.packager.platform.nodeName; + + const ext = { + darwin: ".app", + win32: ".exe", + linux: "", + }[platform]; + + const IS_LINUX = platform === "linux"; + const executableName = IS_LINUX + ? context.packager.appInfo.productFilename.toLowerCase().replace("-dev", "").replace(" ", "-") + : context.packager.appInfo.productFilename; // .toLowerCase() to accomodate Linux file named `name` but productFileName is `Name` -- Replaces '-dev' because on Linux the executable name is `name` even for the DEV builds + + const electronBinaryPath = path.join(context.appOutDir, `${executableName}${ext}`); + + console.log("## Adding fuses to the electron binary", electronBinaryPath); + + await flipFuses(electronBinaryPath, { + version: FuseVersion.V1, + strictlyRequireAllFuses: true, + resetAdHocDarwinSignature: platform === "darwin" && context.arch === builder.Arch.universal, + + // List of fuses and their default values is available at: + // https://www.electronjs.org/docs/latest/tutorial/fuses + + [FuseV1Options.RunAsNode]: false, + [FuseV1Options.EnableCookieEncryption]: true, + [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false, + [FuseV1Options.EnableNodeCliInspectArguments]: false, + + // Currently, asar integrity is only implemented for macOS and Windows + // https://www.electronjs.org/docs/latest/tutorial/asar-integrity + // On macOS, it works by default, but on Windows it requires the + // asarIntegrity feature of electron-builder v25, currently in alpha + // https://github.com/electron-userland/electron-builder/releases/tag/v25.0.0-alpha.10 + [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: platform === "darwin", + + [FuseV1Options.OnlyLoadAppFromAsar]: true, + + // App refuses to open when enabled + [FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]: false, + + // To disable this, we should stop using the file:// protocol to load the app bundle + // This can be done by defining a custom app:// protocol and loading the bundle from there, + // but then any requests to the server will be blocked by CORS policy + [FuseV1Options.GrantFileProtocolExtraPrivileges]: true, + }); +} diff --git a/package-lock.json b/package-lock.json index cb0d391541..73149dded8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@angular/platform-browser": "16.2.12", "@angular/platform-browser-dynamic": "16.2.12", "@angular/router": "16.2.12", + "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "12.0.1", "@microsoft/signalr": "8.0.7", @@ -5100,6 +5101,33 @@ "node": "*" } }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@electron/get": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", diff --git a/package.json b/package.json index 391474243b..872849eb85 100644 --- a/package.json +++ b/package.json @@ -157,6 +157,7 @@ "@angular/platform-browser": "16.2.12", "@angular/platform-browser-dynamic": "16.2.12", "@angular/router": "16.2.12", + "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "12.0.1", "@microsoft/signalr": "8.0.7",