diff --git a/app/electron/main.js b/app/electron/main.js index 624ab64..5cd92da 100644 --- a/app/electron/main.js +++ b/app/electron/main.js @@ -4,6 +4,9 @@ const { session } = require("electron"); const path = require("path"); +const isDev = process.env.NODE_ENV === "development"; +const port = 40992; // Hardcoded; needs to match webpack.development.js and package.json +const selfHost = `http://localhost:${port}`; // 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. @@ -15,7 +18,7 @@ function createWindow() { width: 800, height: 600, webPreferences: { - devTools: true, // todo set to false in prod + devTools: isDev, nodeIntegration: false, nodeIntegrationInWorker: false, nodeIntegrationInSubFrames: false, @@ -26,7 +29,12 @@ function createWindow() { }); // Load app - win.loadFile(path.join(__dirname, "../dist/index.html")); + if (isDev) { + win.loadURL(selfHost); + win.webContents.openDevTools(); + } else { + win.loadFile(path.join(__dirname, "../dist/index.html")); + } // Emitted when the window is closed. win.on("closed", () => { @@ -46,7 +54,7 @@ function createWindow() { callback(true); // Approve permission request } else { console.error(`The application tried to request permission for '${permission}'. This permission was not whitelisted and has been blocked.`); - + callback(false); // Deny } }); @@ -78,7 +86,7 @@ app.on("activate", () => { app.on("web-contents-created", (event, contents) => { contents.on("will-navigate", (event, navigationUrl) => { const parsedUrl = new URL(navigationUrl); - const validOrigins = []; + const validOrigins = [selfHost]; // Log and prevent the app from navigating to a new page if that page's origin is not whitelisted if (!validOrigins.includes(parsedUrl.origin)) { @@ -88,6 +96,7 @@ app.on("web-contents-created", (event, contents) => { return; } }); + contents.on("will-redirect", (event, navigationUrl) => { const parsedUrl = new URL(navigationUrl); const validOrigins = []; @@ -100,10 +109,8 @@ app.on("web-contents-created", (event, contents) => { return; } }); -}); -// https://electronjs.org/docs/tutorial/security#13-disable-or-limit-creation-of-new-windows -app.on("web-contents-created", (event, contents) => { + // https://electronjs.org/docs/tutorial/security#13-disable-or-limit-creation-of-new-windows contents.on("new-window", async (event, navigationUrl) => { // Log and prevent opening up a new window diff --git a/package-lock.json b/package-lock.json index 974fbf4..25c2e36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1231,6 +1231,21 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + } + } + }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", @@ -2324,6 +2339,58 @@ "sha.js": "^2.4.8" } }, + "cross-env": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz", + "integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -4550,6 +4617,14 @@ "uglify-js": "3.4.x" } }, + "html-parse-stringify2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz", + "integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=", + "requires": { + "void-elements": "^2.0.1" + } + }, "html-webpack-plugin": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", @@ -4673,6 +4748,25 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, + "i18next-node-fs-backend": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/i18next-node-fs-backend/-/i18next-node-fs-backend-2.1.3.tgz", + "integrity": "sha512-CreMFiVl3ChlMc5ys/e0QfuLFOZyFcL40Jj6jaKD6DxZ/GCUMxPI9BpU43QMWUgC7r+PClpxg2cGXAl0CjG04g==", + "requires": { + "js-yaml": "3.13.1", + "json5": "2.0.0" + }, + "dependencies": { + "json5": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.0.0.tgz", + "integrity": "sha512-0EdQvHuLm7yJ7lyG5dp7Q3X2ku++BG5ZHaJ5FTnaXpKqDrw4pMxel5Bt3oAYMthnrthFBdnZ1FcsXTPyrQlV0w==", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5039,6 +5133,22 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + } + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5434,8 +5544,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mississippi": { "version": "3.0.0", @@ -6419,6 +6528,15 @@ "scheduler": "^0.18.0" } }, + "react-i18next": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.2.7.tgz", + "integrity": "sha512-BBm6/ch6jgvpIBwyitNd0G7Z49+wNeyJ6x0rZFcXX6NPrla2GuDGH+oKSjmYRg8IqtL6aG9CwWb06YJCrXbk6w==", + "requires": { + "@babel/runtime": "^7.3.1", + "html-parse-stringify2": "2.0.1" + } + }, "react-is": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", @@ -8224,6 +8342,11 @@ "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "dev": true }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", diff --git a/package.json b/package.json index e1b7c68..3ecdd69 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,18 @@ "private": true, "main": "app/electron/main.js", "scripts": { - "dev": "concurrently \"webpack-dev-server --config ./webpack.development.js\" \"opener http://localhost:40992\"", - "electron": "npx webpack --config ./webpack.production.js && electron ." + "dev-server": "cross-env NODE_ENV=development webpack-dev-server --config ./webpack.development.js", + "open-local": "opener http://localhost:40992", + "dev-slim": "concurrently \"npm run dev-server\" \"npm run open-local\"", + "dev": "concurrently \"npm run dev-server\" \"cross-env NODE_ENV=development electron .\"", + "prod": "cross-env NODE_ENV=production npx webpack --mode=production --config ./webpack.production.js && electron ." }, "repository": { "type": "git", "url": "git+https://github.com/reZach/secure-electron-template.git" }, "keywords": [], - "author": "", + "author": "reZach", "license": "GPL-3.0-only", "bugs": { "url": "https://github.com/reZach/secure-electron-template/issues" @@ -27,6 +30,7 @@ "babel-loader": "^8.0.6", "babel-plugin-module-resolver": "^4.0.0", "concurrently": "^5.0.2", + "cross-env": "^6.0.3", "csp-html-webpack-plugin": "^3.0.4", "electron": "^7.1.7", "html-loader": "^0.5.5", @@ -40,8 +44,10 @@ "dependencies": { "@reduxjs/toolkit": "^1.2.1", "connected-react-router": "^6.6.1", + "i18next-node-fs-backend": "^2.1.3", "react": "^16.12.0", "react-dom": "^16.12.0", + "react-i18next": "^11.2.7", "react-redux": "^7.1.3", "react-router": "^5.1.2", "react-router-dom": "^5.1.2",