5c6a21e2c3
The desktop shell is one generic .deb/.AppImage distributed via mca/public_releases, not built per-booth, but the backend origin was baked in at build time (VITE_API_BASE, hardcoded to http://127.0.0.1:3000) — the same installer could never point at a different appliance without a rebuild. Adds ConnectScreen (shown before Login in Tauri when no backend is saved), backed by tauri-plugin-store persisting the operator-entered URL across restarts. CSP's connect-src tightens to 'self' only — all backend traffic already routes through tauri-plugin-http/websocket, which run Rust-side and are outside connect-src's reach anyway — and the real access boundary moves to capabilities/default.json's http:default scope, wildcarded so an operator-chosen host is actually reachable. Adds a "Change server" control in Setup (desktop-only) to repoint an already-configured install. While tracing the desktop auth path for this: tauri-plugin-http's fetch() runs through Rust's reqwest, which keeps its own cookie jar separate from the webview, so document.cookie on tauri://localhost never sees the parking_csrf cookie the server sets (open upstream bug, tauri-apps/tauri#13045/#11518). This means the desktop app has likely been silently sending no CSRF header on every mutation since the shell was first built — pre-existing, independent of this change. Fixed by having sessionView() (routes/auth.ts) also echo the CSRF value in the login/me JSON body; the desktop client stashes it in memory and echoes that instead of reading document.cookie. assertCsrf() itself is untouched. Verified end-to-end against a real LAN-bound dev server: login returns a csrfToken matching the cookie, a mutation using the body-sourced token in X-CSRF-Token succeeds (200), and the same mutation without it still correctly 403s.
44 lines
1.7 KiB
TOML
44 lines
1.7 KiB
TOML
[package]
|
|
name = "parking-desktop"
|
|
version = "0.0.0"
|
|
description = "Parking System — desktop kiosk shell"
|
|
edition = "2021"
|
|
rust-version = "1.77"
|
|
|
|
# Thin Tauri v2 shell. Deliberately holds NO business logic — it loads the
|
|
# @parking/web SPA and lets it talk to the local Fastify server. Device/auth/
|
|
# ledger stay server-side. See wiki/decisions/desktop-shell-tauri.md.
|
|
|
|
[lib]
|
|
name = "parking_desktop_lib"
|
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
|
|
[build-dependencies]
|
|
tauri-build = { version = "2", features = [] }
|
|
|
|
[dependencies]
|
|
tauri = { version = "2", features = [] }
|
|
serde_json = "1"
|
|
# Auto-update: prompt the operator, download a signed update, relaunch.
|
|
tauri-plugin-updater = "2"
|
|
tauri-plugin-process = "2"
|
|
# HTTP client for the SPA's API/WS calls to the local Fastify server. The window
|
|
# runs at tauri://localhost, which WebKitGTK treats as a secure origin — a plain
|
|
# http://127.0.0.1:3000 fetch() from inside it is blocked as mixed content (a
|
|
# long-standing WebKit limitation, not fixable via CSP). Routing through this
|
|
# plugin sends the request via Tauri's Rust side instead of the webview's own
|
|
# fetch, sidestepping the browser mixed-content check entirely.
|
|
tauri-plugin-http = "2"
|
|
# Same mixed-content problem as above, but for the live-feed WebSocket
|
|
# (ws://127.0.0.1:3000 from the secure tauri://localhost origin) — HTTP and WS
|
|
# are separate browser checks, so this needs its own plugin.
|
|
tauri-plugin-websocket = "2"
|
|
# Persists the operator-configured backend URL (host:port of the Fastify
|
|
# server this install talks to) across restarts. Read before any API call —
|
|
# see apps/web/src/lib/backend-config.ts.
|
|
tauri-plugin-store = "2"
|
|
|
|
[features]
|
|
# Used by `tauri dev`/CLI for hot-reload of the Rust side.
|
|
custom-protocol = ["tauri/custom-protocol"]
|