From dfa9e88f5bbea17df97a4d4c54d219711ec32bfe Mon Sep 17 00:00:00 2001 From: Mitchell-Johnson Date: Thu, 24 Sep 2026 12:41:58 -0700 Subject: [PATCH] PLAN: the KVM tab, as simply as it can actually be built Co-Authored-By: Claude Opus 5 --- PLAN.md | 60 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/PLAN.md b/PLAN.md index 4b9cde2..39cccca 100644 --- a/PLAN.md +++ b/PLAN.md @@ -553,37 +553,39 @@ something long in one, switch away and back, refresh — it's all still there. item names the heavier pieces (multi-select and bulk actions, folder download, resumable uploads, a gallery, search) — worth doing the two together, since they are the same tab. -- **A KVM tab** — asked for 2026-09-24, not started. A tab that shows the **IP-KVM's own web - page** inside Ham Lab, so a machine's screen, keyboard and mouse are one click away. **This +- **A KVM tab** — asked for 2026-09-24, not started. **Dead simple is the brief**: paste one + HTTP link, the tab shows whatever UI that KVM serves, and the keyboard goes to it. **This is KVM the keyboard-video-mouse switch, not KVM the hypervisor** — the Virtualization item - above means the other one, and the two must not be confused when either is built. - - **The device**: a **Sipeed NanoKVM**, attached to `grid`, at **`10.0.0.217`** (MAC - `48:da:35:6f:d0:31`), serving a web UI on port 80. The only one in the lab so far, so the - tab must be built for a list of them, not hard-wired to one. - - **Framing works.** Probed 2026-09-24: the NanoKVM sends **no `X-Frame-Options` and no - `frame-ancestors`**, so unlike most of its competitors it does not refuse to be embedded. - An iframe is a real option and the fallback of "just link out" is not needed. - - **Mixed content is the actual blocker.** The NanoKVM is **HTTP only** — there is no - HTTPS listener at all — and Ham Lab is served over TLS, so a browser will refuse the - iframe outright. Something must give it HTTPS. Two routes: - - **Proxy it through the daemon**, which is the better one. Ham Lab already - reverse-proxies nodes over WebSockets (`proxyNode`), which is exactly what the KVM's - video and input streams need, and it puts the KVM behind **Ham Lab's own login** rather - than a second one. `/api/vm/info` answers **401**, so the device has its own auth; the - hub could hold that credential once instead of prompting per person. - - **Or an NPM proxy host** (`scripts/npm-proxy-host.sh`), which is two minutes of work — - but note what it means: `*.bigham.dev` is a wildcard to the public IP, so that would put - **BIOS-level keyboard and screen access to `grid` on the public internet** behind - whatever the KVM's own login is worth. If that route is taken it wants an NPM access - list or a LAN/WireGuard-only binding, decided deliberately. - - **Where the entry lives is still the design decision.** A KVM earns its keep when the + above means the other one. + - **The device**: a **Sipeed NanoKVM** attached to `grid` at **`10.0.0.217`** (MAC + `48:da:35:6f:d0:31`), web UI on port 80. The only one so far, so store a list, not one URL. + - **Framing works.** Probed 2026-09-24: it sends **no `X-Frame-Options` and no + `frame-ancestors`**, so it does not refuse to be embedded. No fallback needed. + - **Proxy it through the daemon — that is what makes the simple version possible.** The + KVM is **HTTP only**, and Ham Lab is served over TLS, so a bare `http://…` iframe is + blocked as mixed content and the "just paste a link" idea dies there. Serving it from Ham + Lab's own origin (`/api/kvm//…`, on the `proxyNode` machinery, which already carries + WebSockets — exactly what the video and input streams are) fixes three things at once: + no mixed content, the KVM sits behind **Ham Lab's** login rather than a second one + (`/api/vm/info` answers 401, so it has its own, which the hub can hold once), and the + iframe becomes **same-origin**, which matters for the keyboard below. + - **The keyboard needs less than it sounds.** A parent page *cannot* capture keys and + forward them into a **cross-origin** iframe — the browser forbids synthetic events across + origins — but it does not need to: an iframe with focus receives keystrokes directly, and + the NanoKVM's own page already handles them. So "capture and give it to the iframe" is + really: click-to-focus, keep focus there, and stop the console's own shortcuts from + eating keys while it is focused. What is genuinely worth adding is **fullscreen** plus + `navigator.keyboard.lock()`, which is what stops the *browser* swallowing Escape, Tab and + Ctrl-W so they reach the guest — note it is Chromium-only, so Firefox and iOS Safari get + the plain version. Proxying makes the iframe same-origin anyway, so real forwarding stays + available if some KVM ever needs it. + - **Where the list lives is the one real design decision.** A KVM earns its keep when the machine is *down* — no OS, a bad kernel, a BIOS screen — which is when that host's Ham Lab - cannot answer. So the list has to be **hub-side** and must work for machines running no - Ham Lab at all. A `kvm_url` inside each node's own `config.json` would fail in precisely - the case it exists for. - - Worth settling too: whether the KVM shows on its machine's page or on one page listing - every KVM; and whether a machine with no Ham Lab deserves a first-class entry on the - Machines page, which today only knows hosts that answer. + cannot answer. So it is **hub-side** and must work for machines running no Ham Lab at all. + A `kvm_url` in each node's own `config.json` would fail in exactly the case it is for. + - **Do not give it an NPM host** without deciding to: `*.bigham.dev` is a wildcard to the + public IP, so that would put BIOS-level control of `grid` on the internet behind only the + KVM's own login. Behind Ham Lab's proxy it inherits Ham Lab's auth instead. ## Open questions