//! The host-side, token-gated front door for one project's Playwright viewer. //! //! ## Why this is not `PortForward` on its own //! //! [`crate::auth_bridge::tunnel::PortForward`] mirrors a container loopback port //! onto the *same* host loopback port with **no authentication at all**. That is //! the right trade for the auth bridge — the things it exposes are short-lived //! OAuth callback listeners whose whole purpose is to receive one unauthenticated //! request — but it is the wrong trade here. The Playwright viewer is full mouse //! and keyboard control of a browser running inside a container that has //! passwordless sudo and, very often, the host's Docker socket bind-mounted. A //! bare loopback port is reachable by: //! //! * any other local user on a multi-user host, and //! * **any web page the user happens to have open**, via localhost port scanning //! or DNS rebinding. //! //! So this module keeps the tunnel half of the auth bridge (a per-connection //! `socat` exec through the Docker API — see //! [`crate::auth_bridge::tunnel::tunnel_connection_with_prelude`]) and replaces //! the listener half with one that authenticates before a single byte reaches //! the container. There is therefore exactly **one** host-bound socket per //! session, and it is gated. //! //! ## The gate //! //! Gating happens on the first HTTP request head of every accepted TCP //! connection, before anything is forwarded. To get a connection through you //! must satisfy all of: //! //! 1. `Host` is `127.0.0.1:` or `localhost:` — this is the //! anti-DNS-rebinding check. A page on `evil.com` that rebinds its name to //! 127.0.0.1 still sends `Host: evil.com`. //! 2. Either //! * the request carries the session token (in `?token=`, in a `Cookie`, or //! in the query of a same-origin `Referer`), **or** //! * `Origin` / `Referer` is exactly this proxy's own origin — i.e. the //! request was issued by a document that we already served, which itself //! had to present the token. This is what lets the viewer's own //! sub-resource and WebSocket requests through: a browser will not let a //! hostile page forge either header, and requests that carry neither (a //! cross-site `