diff --git a/build-resources/app-icon.png b/build-resources/app-icon.png new file mode 100644 index 00000000..34805908 Binary files /dev/null and b/build-resources/app-icon.png differ diff --git a/electron-builder.config.js b/electron-builder.config.js index 42ebd8a2..b486398f 100644 --- a/electron-builder.config.js +++ b/electron-builder.config.js @@ -58,20 +58,28 @@ module.exports = { to: ".", }, ], - // STAND-IN ICON, not a dedicated app icon: public/icon-512x512.png is the - // PWA manifest icon (512x512 square PNG). electron-builder can generate - // .icns/.ico from a single square PNG at build time (see - // node_modules/app-builder-lib/out/util/iconConverter.js), so this - // produces working icons for every target below - but at only 512x512, - // the largest macOS icns representation (1024x1024 "ICON512@2x") gets - // upsampled and will look soft compared to a real 1024x1024+ source. - // public/branding/Bulwark_Icon_App.svg looks like the intended master for - // this (as opposed to Bulwark_Favicon.png, sized for browser tabs), but - // it's vector and this environment has no SVG rasterizer (rsvg-convert / - // ImageMagick / Inkscape) to turn it into a proper 1024x1024 PNG. A human - // (or a follow-up step with the right tooling) should export - // Bulwark_Icon_App.svg at 1024x1024 and point `icon` at that instead. - icon: "public/icon-512x512.png", + // Dedicated 1024x1024 app icon: the SRC symbol centred on the SRC dark + // ground (#09090b), generated from public/branding/SRC_Symbol.png into + // build-resources/app-icon.png (NOT build/ - that's electron-builder's own + // gitignored output dir; a source asset living inside it would never get + // committed, which is exactly the bug this comment is warning about one + // paragraph down). 1024 is the size macOS actually wants for the largest + // icns representation ("ICON512@2x"), so nothing gets upsampled. + // + // Deliberately NOT public/icon-512x512.png (what this used to point at): + // that file is the *web* PWA manifest icon, so retouching it for the + // desktop app silently changes the browser/PWA install icon too. Separate + // source, separate concern. + // + // NOTE for whoever runs this next: electron-builder does NOT auto-detect a + // file named `electron-builder.config.js` - its search list is + // electron-builder.{yml,yaml,json,json5,js,cjs,mjs,ts}. Packaging must be + // invoked with an explicit `--config electron-builder.config.js`, or every + // setting in this file is silently ignored and you get stock defaults + // (default Electron atom icon, `dist/` output, productName taken from + // package.json's `name`). See the `dist:*` scripts in package.json, which + // exist so nobody has to remember that. + icon: "build-resources/app-icon.png", mac: { target: [ { target: "dmg", arch: ["x64", "arm64"] }, diff --git a/electron/main.ts b/electron/main.ts index 9709e72d..b3c5fed8 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -70,6 +70,51 @@ function getServerDataDirs(): Record { }; } +/** + * Desktop-shell defaults for a fresh, un-configured install. + * + * Setting JMAP_SERVER_URL puts the standalone server into "env-managed" + * mode (see lib/setup/state.ts's detectSetupState()) - the ONLY thing that + * disables the setup wizard short of an operator finishing it by hand. Every + * distributable build of this desktop shell up to 2026-08-05 skipped this, + * so handing someone the packaged app landed them on "Bulwark Webmail + * Setup" asking for a token out of container logs they have no access to - + * caught only by actually launching the packaged .app and looking, not by + * reading the build log. + * + * The rest are CONFIG_ENV_MAP entries (lib/admin/types.ts) that only matter + * while env-managed - once an admin completes the wizard, config.json wins + * for everything except jmapServerUrl itself. allowCustomJmapEndpoint keeps + * the server field on the login screen editable, so this is a starting + * point for the sandbox, not a hard lock to it. + * + * `...process.env` in startStandaloneServer() below is spread AFTER this + * object, so a real deployment env (the Dockerfile path, or a future + * per-install override) still wins over these defaults. + */ +function getDesktopDefaults(): Record { + return { + JMAP_SERVER_URL: "https://stalwart.sandbox.vnc.de", + APP_NAME: "VNCmail+", + APP_SHORT_NAME: "VNCmail+", + LOGIN_LOGO_LIGHT_URL: "/branding/SRC_Symbol.png", + LOGIN_LOGO_DARK_URL: "/branding/SRC_Symbol.png", + LOGIN_COMPANY_NAME: "VNC AG", + FAVICON_URL: "/branding/SRC_Symbol.png", + ALLOW_CUSTOM_JMAP_ENDPOINT: "true", + // The login page's subtitle falls back to the login.title i18n string + // whenever it differs from appName (app/(main)/[locale]/login/page.tsx) + // - a check clearly written for the original Bulwark/"Webmail" pairing, + // where they matched. With APP_NAME overridden to "VNCmail+" they no + // longer match, so the raw translation ("Webmail") surfaces instead of + // anything brand-appropriate. Hiding the subtitle avoids editing a + // shared i18n string that every other deployment (incl. Bulwark + // default) still uses - the SRC logo + "VNCmail+" heading is enough + // context on its own. + LOGIN_SHOW_SUBTITLE: "false", + }; +} + /** * Locates the standalone server's entrypoint. Packaged builds ship it as an * extraResource (see electron-builder.config.js) because .next/standalone @@ -156,6 +201,10 @@ async function startStandaloneServer(): Promise { // what travels over it is. serverProcess = spawn(process.execPath, [serverEntry], { env: { + // First, so any real deployment env (a future per-install override, + // or this same binary run somewhere JMAP_SERVER_URL is already set) + // wins over these desktop-shell defaults - see getDesktopDefaults(). + ...getDesktopDefaults(), ...process.env, ELECTRON_RUN_AS_NODE: "1", PORT: String(port), diff --git a/package.json b/package.json index 32f0e636..59da69c3 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,11 @@ "build:standalone": "npm run build:plugins && next build --webpack && node scripts/assemble-standalone.mjs", "build:electron": "node scripts/build-electron.mjs", "electron:dev": "npm run build:standalone && npm run build:electron && electron .", + "dist:prepare": "npm run build:standalone && npm run build:electron", + "dist:dir": "npm run dist:prepare && electron-builder --config electron-builder.config.js --dir", + "dist:mac": "npm run dist:prepare && electron-builder --config electron-builder.config.js --mac", + "dist:win": "npm run dist:prepare && electron-builder --config electron-builder.config.js --win", + "dist:linux": "npm run dist:prepare && electron-builder --config electron-builder.config.js --linux", "test:electron": "playwright test -c playwright.electron.config.ts", "test:integration:electron": "npm run build:standalone && npm run build:electron && playwright test -c playwright.integration-electron.config.ts" },