From fd749d1e0bb0a1a2bc81a8fc47ffecfe62d48559 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 10 Mar 2026 15:06:57 -0300 Subject: [PATCH] fix(electron): auto-generate JWT_SECRET and STORAGE_ENCRYPTION_KEY if missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In packaged Electron on macOS/Windows/Linux, there is no .env file. The Next.js server needs JWT_SECRET and STORAGE_ENCRYPTION_KEY to start — without them it crashes silently, causing ERR_CONNECTION_REFUSED and a black screen in the Electron window. Fix: Generate cryptographically random values with crypto.randomBytes() on first launch, persist them in userData/electron-env.json, and pass them to the spawned server.js process via the env option. Root cause: macOS users reported 'app black screen' (#252) and ERR_CONNECTION_REFUSED — this was the Next.js server crashing at startup because these env vars don't exist in the desktop OS environment. --- electron/main.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/electron/main.js b/electron/main.js index ad05633e..d006e666 100644 --- a/electron/main.js +++ b/electron/main.js @@ -383,6 +383,35 @@ function startNextServer() { return; } + // ── Auto-generate required env vars for Electron ── + // In packaged Electron, there is no .env file — JWT_SECRET and + // STORAGE_ENCRYPTION_KEY must be generated once and persisted. + const envFilePath = path.join(app.getPath("userData"), "electron-env.json"); + let persistedEnv = {}; + try { + if (fs.existsSync(envFilePath)) { + persistedEnv = JSON.parse(fs.readFileSync(envFilePath, "utf8")); + } + } catch { + /* ignore read errors */ + } + + if (!persistedEnv.JWT_SECRET) { + persistedEnv.JWT_SECRET = require("crypto").randomBytes(64).toString("hex"); + } + if (!persistedEnv.STORAGE_ENCRYPTION_KEY) { + persistedEnv.STORAGE_ENCRYPTION_KEY = require("crypto").randomBytes(32).toString("hex"); + } + if (!persistedEnv.STORAGE_ENCRYPTION_KEY_VERSION) { + persistedEnv.STORAGE_ENCRYPTION_KEY_VERSION = "v1"; + } + + try { + fs.writeFileSync(envFilePath, JSON.stringify(persistedEnv, null, 2)); + } catch { + /* ignore write errors */ + } + console.log("[Electron] Starting Next.js server on port", serverPort); sendToRenderer("server-status", { status: "starting", port: serverPort }); @@ -391,6 +420,7 @@ function startNextServer() { cwd: NEXT_SERVER_PATH, env: { ...process.env, + ...persistedEnv, PORT: String(serverPort), NODE_ENV: "production", },