Files
parking_solution/apps/web/src/lib/desktop-csrf.ts
T
julian 8fa66c9911
Build & push images / images (push) Successful in 2m51s
Release desktop / bundle (push) Successful in 41m19s
fix(desktop): WS ticket auth for the live feed; desktop logs never reached the server
The v0.1.4 Origin fix cleared only the first of two gates in /api/ws's
preHandler. The second, req.jwtVerify(), reads the HttpOnly cookie — which
tauri-plugin-websocket (a bare tungstenite client, no cookie jar) can never
send. Every desktop handshake 401'd and use-live-feed reconnected every 10s
(confirmed in the park-2 server log).

- routes/ws.ts: POST /api/ws/ticket (cookie + CSRF auth) mints a 30s,
  single-use, in-memory ticket; the WS preHandler accepts it via an
  x-ws-ticket header after the Origin check, then the same report:read
  role check. Browser cookie path unchanged; JWT stays out of JS.
- platform-ws.ts: fetch a ticket before connect, send it with the Origin
  header; connect failures now go through logClient (rate-limited).
- logger.ts: flush read the CSRF token from document.cookie, null on
  desktop, so every desktop POST /api/logs 403'd and was dropped silently —
  no desktop client log had ever reached app_logs. Stash moved to a
  dependency-free lib/desktop-csrf.ts shared by api.ts and logger.ts.
- backend-config.ts: ConnectScreen probe uses the unauthenticated /health
  (now also returns app: "parking-system") instead of accepting any 401.
- README: local-AppImage release gate — tauri dev runs at
  http://localhost:5173, not tauri://localhost, so none of these
  origin-dependent bugs reproduce there.
- wiki: new section + log entry; four citation corrections.

Requires the server image with this commit deployed before the new desktop
build connects (the ticket endpoint must exist).

Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
2026-09-04 12:09:30 +02:00

26 lines
1.1 KiB
TypeScript

// Desktop-only in-memory CSRF token stash.
//
// tauri-plugin-http's fetch() runs through Rust's reqwest, which keeps its OWN
// cookie jar separate from the webview — document.cookie on tauri://localhost
// never sees the parking_csrf cookie the server sets (open upstream bug,
// tauri-apps/tauri#13045). The cookie IS still sent to the server by reqwest;
// only the client-side READ is broken. So the server echoes the same value in
// the login / me response body (sessionView's csrfToken, routes/auth.ts) and
// the desktop client keeps it here, echoing THIS in X-CSRF-Token instead of
// reading document.cookie.
//
// One module, no imports, so BOTH echo sites can share it without a cycle:
// api.ts (sets it, uses it for apiFetch mutations) and logger.ts (uses it for
// the /api/logs flush — which api.ts imports, so it can't import api.ts back).
// Never persisted: a fresh launch re-learns it via login or /api/auth/me.
let token: string | null = null;
export function setDesktopCsrfToken(value: string | null): void {
token = value;
}
export function getDesktopCsrfToken(): string | null {
return token;
}