diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/DECISIONS.md | 14 | ||||
| -rw-r--r-- | docs/DEPLOY.md | 60 | ||||
| -rw-r--r-- | docs/PROTOCOL.md | 13 | ||||
| -rw-r--r-- | docs/STATE.md | 10 | ||||
| -rw-r--r-- | docs/TUI-GUIDELINES.md | 7 |
5 files changed, 101 insertions, 3 deletions
diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index c18f49b..e317758 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -275,6 +275,20 @@ kept verbatim from the STATE.md they were pruned from (2026-09-21). the key parts of #11 and #28; `make check` rejects F-keys, `^N` and `^Enter` in `clients/`. +30. **Web frontend (2026-09-23)**: bokftui runs in the browser through + ttyd in its own container (`bokf-web`), behind a login gate in C + (`bokfweb`) that authenticates with bokfd's `session.open` — no second + password store — and one login: the gate hands the bokfd session to + the TUI through a terminal handle that only works with the login's + cookie. Caddy in the container does the routing and `forward_auth`; + TLS stays with the host's existing Caddy (port 443 was taken), which + proxies `bokf.makandra.eu` to `127.0.0.1:8790`. Every terminal is an + isolated process (private HOME, limits, `BOKF_WEB=1`: no local files or + programs). bokfd's login limiter became per user name (it was one + global counter, so any 5 wrong guesses locked out everybody) and the + gate limits per client address. Audience: the owner and Petter first, + prepared for more users. + ## Completed work formerly listed under "Pending decisions" - Attachments are complete: download (voucher detail `f`, Underlag `Enter`, diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 6fe6a53..99b7661 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -224,6 +224,66 @@ Agents use `token.create` instead of a password; tokens are scoped and revocable. Only the TLS port is forwarded, and every command still requires authentication (`meta` and `health` excepted). +## Web frontend (`https://bokf.makandra.eu/web`) + +The `web` service (image `bokf-web`, built from the `web` target of the +same Dockerfile and shipped by `scripts/deploy.sh` with the daemon) serves +bokftui in the browser: + +``` +browser ──443──▶ host Caddy (TLS) ──▶ 127.0.0.1:8790 bokf-web container + Caddy: routing + forward_auth + ├─ /web, /web/login, /web/logout ─▶ bokfweb (login gate) + └─ /web/tty/* (gate OK only) ────▶ ttyd ─▶ bokftui-web ─▶ bokftui + │ + bokfd ◀── unix socket ┘ +``` + +- **Login gate** (`bokfweb`, `clients/bokfweb.c`): the login page checks + the credentials with bokfd's own `session.open` — there is no second + password store, and bokfd's audit and per-user lockout apply. The gate + limits failed logins per client address (5 per 15 min) before bokfd's + limit is reached. A login sets a cookie (`HttpOnly`, `Secure`, + `SameSite=Strict`, 12 h) and redirects to `/web/tty/?arg=<handle>`. +- **One login**: the terminal wrapper (`deploy/bokftui-web`) trades the + handle for the bokfd session on the gate's internal `/redeem` (never + routed by Caddy) and starts `bokftui` with `BOKFD_SESSION`, so the TUI + opens logged in. Caddy's `forward_auth` lets a request reach ttyd only + with a live cookie whose session owns the handle in the URL; a leaked + URL is useless without the cookie. Quitting the TUI (or `/web/logout`) + closes the bokfd session and with it the web session. +- **Isolation**: every browser terminal is its own bokftui process with a + private throwaway `HOME` (config, drafts, log), memory/CPU/file limits, + and `BOKF_WEB=1`: the TUI refuses everything that would read or write + files or start programs on the frontend (file browser, save prompts, + downloads, the PDF viewer). No shell is ever offered. The container runs + as uid 10001, read-only root, `/tmp` tmpfs, all capabilities dropped, + `no-new-privileges`, pids/memory limits, and it sees bokfd only through + the protocol socket (no database, no secrets, no certificates). +- **TLS** is the host's reverse proxy. On the NAS, add to the existing + Caddy (`/mnt/data/caddy/Caddyfile`) a site block like the others and + reload it: + + ``` + bokf.makandra.eu { + tls { + dns inwx { ... } # as for the other sites + } + reverse_proxy 127.0.0.1:8790 + } + ``` + + Port 443 is already forwarded for the other sites. The container + publishes 8790 on the host's loopback only, so it is unreachable until + that block exists. +- `BOKF_WEB_MAX_SESSIONS` (default 20) caps concurrent terminals. + `docker compose logs web` shows logins, logouts and failed attempts + (never passwords). + +Not yet in the web version: uploading and downloading files (attachments, +bank files, SRU/eSKD/årsredovisning files, PDFs). The TUI says so where it +applies; use bokftui on a computer for those. + ## Mock company ```sh diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md index 709a475..3c8ba54 100644 --- a/docs/PROTOCOL.md +++ b/docs/PROTOCOL.md @@ -85,7 +85,11 @@ and returns an opaque, high-entropy session id: intentional. API tokens survive restarts. - Sliding TTL, `session_ttl` default 8 h. `session.close` ends one explicitly. - Passwords are stored as Argon2id hashes. Failed logins are rate limited per - peer (default: 5 failures per 15 minutes, then `RATE_LIMITED`). + user name (5 failures per 15 minutes, then `RATE_LIMITED` for that name + only): guessing one account never locks out the others. The table of + counters replaces expired or least-failed entries when full, so flooding + it with names neither disables the limiter nor lifts a block. The web + gate (`bokfweb`) adds its own limit per client address in front of this. - A user changes their own password with `user.set_password` from a password session (a token session gets `FORBIDDEN`). The current password is required — 5 wrong ones per 15 minutes give `RATE_LIMITED` — and the @@ -946,7 +950,10 @@ commands. Implemented screens (0.1.0-dev): - **Inloggning** — server, user, password; org picker when several exist. **Byt bolag** in the main menu reopens the picker during the session; - **Byt lösenord** calls `user.set_password`. + **Byt lösenord** calls `user.set_password`. The same TUI runs in the + browser at `/web` (DEPLOY.md "Web frontend"): the login page opens the + session with `session.open` and the TUI reuses it; file features are + off there. - **Dashboard** — status line with org, fiscal year, role and user. - **Verifikat** — list and detail view (rows with column headers, an underlag section separated by a rule, hash, link to corrected voucher); `c` @@ -1122,7 +1129,7 @@ beyond the session and calls nothing but public commands. | `session_ttl` | `8h` | sliding session lifetime | | `max_line_bytes` | `1048576` | NDJSON line limit | | `max_attachment_bytes` | `10485760` (10 MiB) | decoded attachment limit | -| `auth_fail_limit` | `5/15m` | login rate limit per peer | +| `auth_fail_limit` | `5/15m` | login rate limit per user name (fixed in the code) | | `synchronous` | `FULL` | SQLite durability (`FULL`/`NORMAL`) | | `audit_reads` | `false` | log read commands too | | `allow_org_create` | `true` | any user may create an org | diff --git a/docs/STATE.md b/docs/STATE.md index 77ef9a4..93ade1e 100644 --- a/docs/STATE.md +++ b/docs/STATE.md @@ -14,6 +14,16 @@ unit tests and the docs consistency check. ## Resume here (2026-09-23) +- **Web frontend (2026-09-23, branch `feat/web-frontend`, not deployed)**: + image `bokf-web` (Caddy routing + `bokfweb` login gate + ttyd + + bokftui in web mode) as compose service `web` on `127.0.0.1:8790`; see + DEPLOY.md "Web frontend" and decision #30. Tested end to end locally + (login, one-login handoff, foreign handle 403, logout, per-address + limit) and the aarch64 static build. **To go live**: deploy, then add + the `bokf.makandra.eu` block to the NAS Caddy + (`/mnt/data/caddy/Caddyfile`) and reload it. bokfd's login limiter is + now per user name (was global: 5 wrong guesses locked out everyone). + Next: file upload/download through the browser for the web mode. - **Context menu and web-safe keys (2026-09-23, branch `eff/context-menu`)**: `→` (or `^O`, also in table cells) opens "Åtgärder", a box at the right edge with every action of the view and diff --git a/docs/TUI-GUIDELINES.md b/docs/TUI-GUIDELINES.md index 650f026..c223514 100644 --- a/docs/TUI-GUIDELINES.md +++ b/docs/TUI-GUIDELINES.md @@ -145,6 +145,13 @@ terminal and browser delivers (checked by `make check`): reload — `^R` is a developer convenience and never the only way). - Every action is reachable with arrows + `Enter` through the menu; a letter accelerator is a shortcut, never the only path. +- **Web mode** (`BOKF_WEB=1`, set by the browser-terminal wrapper): the TUI + runs on the web frontend, not on the user's machine, so a screen never + reads or writes a local file or starts a program there. Every such path + goes through `ui_web_block(title)` (`clients/ui.c`), which shows why and + returns 1: the file browser, `save_cache_and_open` (PDF viewer), the + attachment download and the SRU/eSKD/årsredovisning save prompts. New + file features must call it too (pty scenario `web-mode`). ### Implementation status |
