9856c04b75
ci / rust (push) Has been cancelled
Single-user, LAN-reachable-but-gated. The web server is a backend-for-frontend:
- Login: POST /_auth/login {password} checks PUNKTFUNK_UI_PASSWORD (constant-time) and
sets a SEALED session cookie (h3 useSession / AES-GCM). server/middleware/auth.ts gates
every request — pages 302 → /login, /api → 401 — and FAILS CLOSED (503) when
PUNKTFUNK_UI_PASSWORD is unset, so a misconfigured LAN-exposed server admits no one.
- The management API stays loopback-only + token (never LAN-exposed). The proxy
(server/routes/api/[...].ts) injects PUNKTFUNK_MGMT_TOKEN server-side and drops the
browser's cookie before forwarding — the token never reaches the browser, which only
holds the session cookie.
Nitro doesn't auto-scan a server/ dir, so the Nitro plugin gets an explicit scanDirs to
pick up middleware + routes. Client: removed the localStorage token (server injects it);
the fetcher bounces to /login on 401; new /login page (bare, no shell); Settings drops the
token field and gains a Sign-out button; en/de strings.
Validated live end to end: unauth /→302, /api→401; wrong pw→401; right pw→200+cookie;
authed /api/v1/status→200 (proxied, mgmt token injected — the host required it); logout→
session cleared→401. tsc + build green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
66 lines
2.4 KiB
JSON
66 lines
2.4 KiB
JSON
{
|
|
"$schema": "https://inlang.com/schema/inlang-message-format",
|
|
"app_name": "punktfunk",
|
|
"app_tagline": "management console",
|
|
"nav_dashboard": "Dashboard",
|
|
"nav_host": "Host",
|
|
"nav_clients": "Paired clients",
|
|
"nav_pairing": "Pairing",
|
|
"nav_settings": "Settings",
|
|
"status_title": "Live status",
|
|
"status_video": "Video",
|
|
"status_audio": "Audio",
|
|
"status_streaming": "Streaming",
|
|
"status_idle": "Idle",
|
|
"status_session": "Session",
|
|
"status_no_session": "No active session",
|
|
"status_paired_count": "Paired clients",
|
|
"status_pin_pending": "Pairing PIN pending",
|
|
"stream_codec": "Codec",
|
|
"stream_resolution": "Resolution",
|
|
"stream_fps": "Frame rate",
|
|
"stream_bitrate": "Bitrate",
|
|
"action_stop_session": "Stop session",
|
|
"action_request_idr": "Request keyframe",
|
|
"action_unpair": "Unpair",
|
|
"host_identity": "Identity",
|
|
"host_hostname": "Hostname",
|
|
"host_local_ip": "Local IP",
|
|
"host_version": "Version",
|
|
"host_abi": "ABI version",
|
|
"host_codecs": "Codecs",
|
|
"host_ports": "Ports",
|
|
"host_uniqueid": "Unique ID",
|
|
"clients_title": "Paired clients",
|
|
"clients_empty": "No paired clients yet.",
|
|
"clients_name": "Name",
|
|
"clients_fingerprint": "Fingerprint",
|
|
"clients_unpair_confirm": "Unpair this client? It will need to pair again to connect.",
|
|
"pairing_title": "Pairing",
|
|
"pairing_idle": "No pairing in progress. Start pairing from a Moonlight client, then enter its PIN here.",
|
|
"pairing_waiting": "A client is waiting to pair. Enter the PIN it shows:",
|
|
"pairing_pin_label": "PIN",
|
|
"pairing_submit": "Submit PIN",
|
|
"pairing_success": "Paired successfully.",
|
|
"pairing_failed": "Pairing failed — check the PIN and try again.",
|
|
"settings_title": "Settings",
|
|
"settings_token_label": "API token",
|
|
"settings_token_help": "Bearer token for the management API. Leave empty for a loopback host with no token.",
|
|
"settings_language": "Language",
|
|
"settings_save": "Save",
|
|
"settings_saved": "Saved.",
|
|
"common_loading": "Loading…",
|
|
"common_error": "Something went wrong.",
|
|
"common_retry": "Retry",
|
|
"common_yes": "Yes",
|
|
"common_cancel": "Cancel",
|
|
"common_unauthorized": "Session expired — redirecting to sign in…",
|
|
"login_title": "Sign in",
|
|
"login_subtitle": "Enter the management password to continue.",
|
|
"login_password": "Password",
|
|
"login_submit": "Sign in",
|
|
"login_error": "Wrong password.",
|
|
"login_signing_in": "Signing in…",
|
|
"action_logout": "Sign out"
|
|
}
|