Files
Webka/README.md
2026-09-06 16:47:05 +05:00

98 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Webka
A private camera and screen streaming app for your local network. Nuxt 3 / Vue 3 / TypeScript, Pinia, English/Russian/Spanish, and an Axum/Rust service with SQLite and browser-to-browser WebRTC.
## One-command start
Install Node **22.12+** (npm included) and stable Rust/Cargo once. Then, from the repository root:
```sh
npm run dev:all
```
This starts **http://127.0.0.1:3000**. To listen on all network interfaces at port 3002:
```sh
npm run dev:all -- --host 0.0.0.0 --port 3002
```
The `--` after `dev:all` passes the options to the launcher. Use ordinary double hyphens. `npm start -- --host 0.0.0.0 --port 3002` is an alias. `--help` shows usage.
The launcher installs frontend dependencies automatically on the first run, builds Nuxt, builds Rust, and runs one server serving both the frontend and API on the chosen port. First startup needs internet and can take several minutes. Subsequent runs reuse unchanged dependencies/frontend output; Cargo builds incrementally. Restart the command after code changes to rebuild. This convenience command does not provide hot reload.
The terminal prints the local URL, LAN URLs when available, and the setup-token file location. Open the local URL on the server computer for camera capture; use a printed LAN URL on other devices to watch. The QR code uses the detected LAN address when listening on all interfaces. Local and detected private IPv4 origins are explicitly allowed; arbitrary origins remain blocked. If the selected port is busy, startup stops with an actionable message.
Press **Ctrl+C** to stop the app and any build subprocesses. Accounts remain in `data/`. The first login page creates the administrator account using the token from `data/setup-token`. The administrator cannot be deleted; resetting its password ends its sessions.
For HTTPS behind a reverse proxy, set `WEBKA_ORIGIN` to the exact public origin before launching. This override disables automatic HTTP aliases; optional `WEBKA_ALLOWED_ORIGINS` is a comma-separated list of additional trusted exact origins. Browser capture on another LAN device still requires trusted HTTPS; plain LAN HTTP permits viewing only.
For frontend hot reload, the separate development workflow remains available: run `cargo run --manifest-path backend/Cargo.toml` and `npm --prefix frontend run dev` in separate terminals, then open `http://localhost:3000`.
## Use on your LAN
A webpage **cannot launch a Rust server** on the device running its browser. Start the Rust service once on a computer on your LAN. A phone, tablet, or computer can then sign in as the administrator and act as the capturing host. This repository does not include a native iOS/Android service wrapper. Each service instance owns its account database.
Browser camera/screen APIs require a **secure context**: localhost on the service machine, or trusted HTTPS on a LAN device. LAN HTTP IP addresses cannot capture camera/screen. For LAN use, use the included `Caddyfile.example` with a trusted local certificate:
1. Point `webka.local` at the service computer, through mDNS (`WEBKA_MDNS=1`), your router, or a hosts entry. `.local` resolution and multicast support vary by network/device; a local DNS name or IP with a matching trusted certificate also works.
2. Configure Caddy with the example below, and install/trust Caddy’s local CA on **every** client device. Keep this CA private.
3. Start Webka with its exact public origin:
```sh
WEBKA_ORIGIN=https://webka.local WEBKA_MDNS=1 \
WEBKA_PUBLIC_PORT=443 WEBKA_BIND=127.0.0.1:3001 \
cargo run --release --manifest-path backend/Cargo.toml
```
4. Open `https://webka.local`, create the admin account, add viewer accounts in **Accounts**, enable preview, and choose **Go live**. Share the QR code/local address. Each viewer signs in with an account created on this service.
Caddy terminates HTTPS and proxies to the loopback Rust server. Cookies gain `Secure` automatically when `WEBKA_ORIGIN` starts with `https://`. WebSocket handshakes and all mutations validate an explicitly configured Origin. No CORS wildcard or trusted forwarded-IP headers are used. The login throttle sees the reverse proxy as one IP, so its ten-attempts-per-minute limit is shared behind that proxy.
Use a private LAN and firewall; do not expose the service through public port forwarding. The app uses **no cloud accounts, public STUN/TURN, telemetry, CDNs, or external fonts**. WebRTC connects peers directly with local ICE candidates. Client isolation, VLANs, and firewalls that block peer UDP can prevent streams; no cloud relay fallback is provided. The one active host sends a separate peer stream to each viewer (32 signaling connections total, including the host). Capacity depends on the host device and Wi-Fi.
## Configuration
| Variable | Default | Purpose |
|---|---|---|
| `WEBKA_BIND` | `127.0.0.1:3001` | Rust listener |
| `WEBKA_ORIGIN` | `http://localhost:3000` | Exact public origin; used for CSRF checks, QR and secure cookies |
| `WEBKA_ALLOWED_ORIGINS` | none | Additional trusted exact origins; launcher configures local/LAN aliases |
| `WEBKA_DATA` | `data` | Local database and persistent secrets |
| `WEBKA_ASSETS` | `frontend/.output/public` | Generated frontend; paths are relative to the current directory |
| `WEBKA_MDNS` | off | Set `1` to advertise `_webka._tcp.local.` and `webka.local` |
| `WEBKA_PUBLIC_PORT` | `443` for HTTPS, otherwise `3000` | Advertised public port |
Back up `WEBKA_DATA` securely. On Unix the data directory is owner-only and secret files are created with mode 0600. On Windows configure equivalent directory ACLs. Session tokens are random, HMAC-signed, stored only as SHA-256 digests in SQLite, and sent in HttpOnly/SameSite=Strict cookies. Argon2id stores salted passwords. Sessions expire after 30 minutes without activity and always after 12 hours. Visible authenticated pages send a heartbeat; hidden pages do not. Revocation closes signaling and tells the host to close the affected peer. A recipient may still retain media already received.
## Features and implementation
- `/login`: protected first-run setup and local sign-in.
- `/host`: camera preview, front/back/screen selection, start/stop, uptime, bitrate presets, QR link and viewer disconnection.
- `/watch`: live video, connection/resolution indicator, fullscreen, logout and automatic reconnect with backoff.
- `/settings/accounts`: viewer creation/deletion, password reset, last login and active session revocation.
- `/settings/general`: light/dark glass, accent, locale and security information.
- Shared `GlassCard`, `GlassButton`, `GlassNavBar`, `GlassModal` and `LanguageSwitcher` with layered rim highlights, pointer-responsive specular light, rounded geometry, reduced-motion support, native keyboard focus and dialog focus containment.
- Content panels stay opaque. Glass is used for navigation, source/share controls and dialogs. CSS edge layers approximate refraction; they do not implement physically accurate optical lensing.
Quality presets control the host’s per-peer send bitrate; the viewer shows actual received resolution. Capture is video-only. Closing/navigating away from the host tab stops capture; a browser may also suspend hosting when the device locks or the tab is backgrounded. Screen share support varies, particularly on mobile. Back-camera discovery becomes reliable after granting camera permission. Physical-device tests are documented in `docs/MANUAL_TEST_PLAN.md`.
Nuxt 3 is retained to match the requested stack. Its upstream documentation now marks it end-of-life; plan a Nuxt 4 upgrade before broader distribution. Reference: https://nuxt.com/docs/3.x/getting-started/installation.
## Validation
```sh
npm run test:launcher
cargo fmt --manifest-path backend/Cargo.toml --check
cargo test --manifest-path backend/Cargo.toml
cargo clippy --manifest-path backend/Cargo.toml --all-targets -- -D warnings
npm --prefix frontend run typecheck
npm --prefix frontend run build
node frontend/scripts/check-locales.mjs
cargo build --manifest-path backend/Cargo.toml
python3 scripts/smoke.py
# Optional POSIX integration test: reserves port 3002, tests startup/restart/stop.
python3 scripts/test-launcher.py
```
See `docs/API.md` for REST/signaling contracts and `docs/MANUAL_TEST_PLAN.md` for real-device checks. Design references: [Apple’s introduction](https://www.apple.com/uk/newsroom/2025/06/apple-introduces-a-delightful-and-elegant-new-software-design/) and [Meet Liquid Glass](https://developer.apple.com/videos/play/wwdc2025/219/). No Apple assets are included. Nothing is published by the build commands.