feat(kiosk): companion remote drives app iframes via trusted CDP input
Demo images / Build & push demo images (push) Successful in 3m11s

Companion tap/scroll/type now works INSIDE cross-origin app iframes and
kiosk tabs. The web relay synthesizes untrusted DOM events in the top
document, which can never cross an origin boundary — so apps served
through the appgate were dead to the remote. The kiosk Chromium now
exposes a loopback-only CDP port (default origin check intact, no
--remote-allow-origins) and a backend bridge (api/handler/cdp.rs)
dispatches validated companion input as Input.dispatchKeyEvent /
dispatchMouseEvent / mouseWheel — trusted events that hit-test through
any frame, move real focus, and insert text like a physical device.

- Session keeper self-heals across kiosk Chromium restarts; inert on
  nodes without a kiosk unit (falls back to the existing relay path).
- The kiosk relay subscriber self-tags (?kiosk=1) and the backend mutes
  its key/click/scroll messages while the bridge is live, so input never
  applies twice; cursor moves still flow for the on-screen cursor.
- While companion input is active the native OS pointer is hidden
  (cursor:none, auto-restores 30s after the last event) so the dead
  physical-mouse cursor doesn't sit next to the virtual one.
- docs/tv-input-iframe-apps.md scope note updated: gamepad keys stay on
  uinput; CDP is for companion pointer/typing only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-16 05:28:53 -04:00
co-authored by Claude Fable 5
parent 876ecc4bdf
commit 3a3077529b
8 changed files with 517 additions and 7 deletions
+10 -3
View File
@@ -66,9 +66,16 @@ packaging docs; never required for an app to be usable.
## What NOT to do
- ❌ CDP (`--remote-debugging-port` + Input.dispatchKeyEvent): works but adds
a privileged debug port to the kiosk and a daemon↔browser coupling; the
uinput route gets the same result at kernel level with no attack surface.
- ⚠️ **Scope update 2026-08-16:** the "no CDP" rule below still holds for
*gamepad keys* (uinput remains their path). But companion **pointer input**
(tap at coordinates, scroll, focus-then-type inside cross-origin app
iframes) has no uinput equivalent that survives hit-testing across frames,
so the kiosk now runs `--remote-debugging-port=9222` (loopback-only, default
origin check intact) feeding the backend CDP bridge in
`core/archipelago/src/api/handler/cdp.rs`.
- ❌ CDP for gamepad keys (`Input.dispatchKeyEvent` for the NES pad): the
uinput route gets the same result at kernel level with no daemon↔browser
coupling; keep gamepads on uinput.
- ❌ Per-app nav scripts injected into iframes: cross-origin makes this
impossible for most apps, and it's exactly the per-app hack the requirement
rules out.