fix(electron): real VNCmail+ branding, not just a rename

Every prior distributable DMG this session was built with plain `npx
electron-builder`, never `--config electron-builder.config.js`. electron-
builder does not auto-detect a file named electron-builder.config.js (its
search list is .yml/.yaml/.json/.json5/.js/.cjs/.mjs/.ts, not .config.js),
so the config - correct productName/appId/icon and all - was silently
ignored on every build. Caught only by actually launching the packaged
.app: it booted to "Bulwark Webmail Setup" demanding a token from
container logs, default Electron atom icon, output in dist/ instead of
dist-electron-builds/.

Fixes, each verified against the packaged .app (Playwright _electron.launch,
not the build log):
- Add dist:mac/win/linux/dir scripts that pass --config explicitly, so this
  can't recur.
- Dedicated 1024x1024 app icon (build-resources/app-icon.png, SRC symbol on
  #09090b) instead of reusing the web PWA manifest icon. Verified: icns
  ships at 1024x1024, pixel-identical to the source (mean diff 0.0/255).
- electron/main.ts: getDesktopDefaults() sets JMAP_SERVER_URL to the sandbox
  (the ONLY thing that puts the server into "env-managed" mode and skips
  the setup wizard - see lib/setup/state.ts), plus APP_NAME/login logo/
  favicon/company-name env vars, spread before ...process.env so a real
  deployment still overrides. Verified: packaged app now opens straight to
  a login screen with the JMAP endpoint field pre-filled
  https://stalwart.sandbox.vnc.de, title "VNCmail+", SRC logo.
- LOGIN_SHOW_SUBTITLE=false: the subtitle falls back to the login.title
  i18n string ("Webmail") whenever it differs from APP_NAME - a check
  written for the original Bulwark pairing where they matched. Hiding it
  avoids touching that shared string for every other deployment.
This commit is contained in:
Bernd Rodler
2026-08-05 21:01:38 +02:00
parent e44f2ac97e
commit e1a12b2c23
4 changed files with 76 additions and 14 deletions
+49
View File
@@ -70,6 +70,51 @@ function getServerDataDirs(): Record<string, string> {
};
}
/**
* 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<string, string> {
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<string> {
// 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),