Files
enricobuehler 1e2b956de6 fix(web,tray,host): review follow-ups — pair the halves, and stop two comments overclaiming
Review of the parent commit. One real defect, the rest accuracy.

The resolver could hand back a MISMATCHED pair, which is the one invariant its
own header promised it never would: `nativeCert` came from `dirname(cert)` and
`nativeKey` from `dirname(key)`, two independent directories, so
("/a/cert.pem", "/b/key.pem") resolved to /a/native-cert.pem + /b/native-key.pem
— two unrelated files presented as a pair. No shipped launcher splits them, but
the guard is one comparison and it is the whole point of the module.

Rewritten off a suffix test instead of `node:path`, which fixes two more things
in passing. `node:path` resolves per-RUNTIME, so a POSIX CI runner reads
`C:\ProgramData\punktfunk\cert.pem` as one long filename and never swaps — and
Windows, where windows/service.rs hands us exactly that, is the platform the CI
job can never exercise. The suffix test gives the same answer everywhere and is
now covered by a win32 case. It also leaves the prefix VERBATIM, where
`join(dirname(p), …)` normalised /a/b/../cert.pem into a different directory the
moment `b` was a symlink.

Existence is no longer enough: `pf_paths::write_secret_file` is
create+truncate+write rather than temp+rename, so a console starting mid-write
could adopt a 0-byte cert and leave `Bun.serve` throwing on every restart. Not
every launcher retries forever — the Steam Deck unit is `Restart=on-failure`
under the default rate limit, i.e. permanently dead. The check is now a
non-empty stat, mirroring the host's own `!c.trim().is_empty()`. Verified: with
native-cert.pem truncated to 0 bytes the console starts and serves the legacy
pair.

Two comments of mine overclaimed and are corrected rather than left to mislead:

  * serve() said "cert.pem existing implies the native pair does too". False on
    an upgraded host whose native clients pinned the legacy cert — load_or_adopt
    returns it and writes no native files at all. The ordering claim that IS
    true is narrower: whenever that call writes a native pair, it does so before
    cert.pem appears.
  * the tray said the console entry "always opens the same URL regardless of the
    probe". True of the menu entry, but win.rs gates the tray-icon single-click
    on console_up. Also notes that the Windows probe was never pinned to begin
    with (punktfunk_config_dir is None off Linux), so that half is a no-op.

Rest is doc drift the parent commit annotated in two launchers but not the other
four: web.env.example, README, web-run.cmd, and the ci.yml comment that still
said the web test step was "Scoped to server/".

18/18 web tests (was 14), biome and rustfmt clean, and the runtime check re-run
against a fresh build: both pairs -> P-256 with SANs; 0-byte native cert ->
legacy RSA, console still serving.
2026-08-24 22:45:47 +02:00

69 lines
3.8 KiB
Batchfile

@echo off
rem punktfunk web console launcher - DEV convenience, run BY HAND (in-repo tree). On an installed
rem host the PunktfunkHost service supervises the console itself (service.rs "web console child" -
rem no scheduled task, no launcher script); a dev host running from target\release has no installed
rem web payload next to its exe, so this script is how you serve the in-repo web\.output against it.
rem It sources the host's mgmt bearer token + the console login password from %ProgramData%\punktfunk\,
rem points the /api proxy at the host's loopback HTTPS mgmt API, and serves the self-contained
rem (no-node_modules) Nitro console over HTTPS (HTTP/1.1 over TLS) on :47992 with the host's identity
rem cert. %~dp0 = <repo>\web\ . The console runs on bun (the Nitro `bun` preset + Bun.serve TLS
rem entry) - set BUN below to your bun.exe. Rebuild after a web change with `bun run build` in web\ .
setlocal EnableExtensions
set "PFDATA=%ProgramData%\punktfunk"
set "TOKENFILE=%PFDATA%\mgmt-token"
set "PWFILE=%PFDATA%\web-password"
set "CERTFILE=%PFDATA%\cert.pem"
set "KEYFILE=%PFDATA%\key.pem"
rem The host's `serve` writes the mgmt token + identity cert on first run. Until they exist the proxy
rem has no credential and no TLS material, so WAIT for them (mirrors the service supervisor's gate)
rem rather than silently serving plain HTTP. ~5 min at 2 s, then give up.
set /a PFWAITS=0
:pfwait
if exist "%TOKENFILE%" if exist "%CERTFILE%" goto pfready
if %PFWAITS% GEQ 150 (
echo [punktfunk-web] gave up waiting for "%TOKENFILE%" + "%CERTFILE%" - is the punktfunk host running?
exit /b 1
)
if %PFWAITS%==0 echo [punktfunk-web] waiting for the host to write the mgmt token + identity cert...
set /a PFWAITS+=1
ping -n 3 127.0.0.1 >nul 2>&1
goto pfwait
:pfready
rem Both files are single KEY=VALUE lines: PUNKTFUNK_MGMT_TOKEN=... and PUNKTFUNK_UI_PASSWORD=... .
rem Split on the first '=' and import each into the environment.
for /f "usebackq tokens=1* delims==" %%A in ("%TOKENFILE%") do set "%%A=%%B"
if exist "%PWFILE%" for /f "usebackq tokens=1* delims==" %%A in ("%PWFILE%") do set "%%A=%%B"
rem Fixed deployment wiring (the Windows analogue of scripts/punktfunk-web.service).
set "PORT=47992"
set "HOST=0.0.0.0"
set "PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990"
rem ...unless the host published a different one. `serve` writes mgmt-endpoint in the same single
rem KEY=VALUE form as the token above, carrying the port it ACTUALLY bound - so a host moved off
rem 47990 (PUNKTFUNK_MGMT_BIND, e.g. to share the box with a Sunshine fork whose web UI owns that
rem port) brings the console with it. Imported AFTER the default so it wins; absent on an older host,
rem and then the default above stands.
set "ENDPOINTFILE=%PFDATA%\mgmt-endpoint"
if exist "%ENDPOINTFILE%" for /f "usebackq tokens=1* delims==" %%A in ("%ENDPOINTFILE%") do set "%%A=%%B"
rem No NODE_TLS_REJECT_UNAUTHORIZED: the host's self-signed cert is accepted only for the loopback
rem proxy hop, scoped inside the proxy code (Bun per-request TLS), not process-wide.
rem Serve HTTPS (HTTP/1.1 over TLS) with the host's identity cert; mark the session cookie Secure.
rem These name the LEGACY pair; the server prefers native-cert.pem/native-key.pem beside them when
rem both exist (the identity split - web\nitro-entry\tls-paths.mjs). Don't "fix" them to the native
rem names: a host that never took the split has no native pair, and the fallback lives in there.
set "PUNKTFUNK_UI_TLS_CERT=%CERTFILE%"
set "PUNKTFUNK_UI_TLS_KEY=%KEYFILE%"
set "PUNKTFUNK_UI_SECURE=1"
rem Bun runtime (override BUN if yours lives elsewhere / is on PATH as just `bun`).
if not defined BUN set "BUN=bun.exe"
set "SERVER=%~dp0.output\server\index.mjs"
if not exist "%SERVER%" (
echo [punktfunk-web] built server missing at "%SERVER%" - build it: cd web ^&^& bun run build
exit /b 1
)
"%BUN%" "%SERVER%"