docs: what actually gates access, now that there is a deployment
The internal deployment exists (deployments repo, `mirror/`: quadlet, nginx edge, certbot, route53, VM SOP), so the docs that said "the real fix is HTTPS" were describing a future that has arrived from a different direction — TLS terminates in nginx on the service VM, not in this process, and there is no `--https` flag here. SECURITY.md's trust model said "trusted: anyone who can open a TCP connection". With an allow list in production that sentence was simply no longer true, so the table now names the address space, and a new section says what the list is and what it is not: one wall (network/nginx) and one belt (the app, for the path that bypasses nginx at 127.0.0.1:8080), plus the thing neither can do — once two browsers are in the room their media never asks the server again, and it can never tell you *who*, only *where from*. Saying "defence in depth" about that would have been the dishonest version. PLAN.md gains A19 (TLS + admission in production, LOCKED) and A18 becomes deprioritised rather than deleted — standalone `mirror serve --https` is still worth having for offline/ad-hoc use, it just stopped being the thing blocking cross-device sharing, and candidate phase 1 is now share-page resilience. AGENTS.md gains the two rules most likely to be broken by a well-meaning edit: trust XFF only from a trusted proxy, and change the nginx and app lists in the same commit. LLM-Generated: true
This commit is contained in:
@@ -12,9 +12,11 @@ your network:
|
||||
| **Index** | `/` | Signpost + live count of mirrors. |
|
||||
|
||||
Any number of people can mirror at the same time and any number of people can
|
||||
watch. There is **no authentication** — this is built for a trusted local
|
||||
network, and that assumption is deliberate and documented in
|
||||
[SECURITY.md](SECURITY.md).
|
||||
watch. There are **no accounts and no passwords** — this is built for a trusted
|
||||
local network, and that assumption is deliberate and documented in
|
||||
[SECURITY.md](SECURITY.md). What *does* decide who gets in is the source address:
|
||||
by default any address is welcome, and `--allow-cidr` / `MIRROR_ALLOW_CIDRS`
|
||||
narrows that to the networks you name.
|
||||
|
||||
## Quickstart
|
||||
|
||||
@@ -60,6 +62,8 @@ Environment variables (all optional; a `.env` file is loaded if present):
|
||||
| `MIRROR_PORT` | `8055` | Bind port. |
|
||||
| `MIRROR_ICE_SERVERS` | `[]` | JSON array of RTCIceServer objects, if peers cannot reach each other directly. |
|
||||
| `MIRROR_MAX_MIRRORS` | `0` | Cap on concurrent mirrors (`0` = unlimited). |
|
||||
| `MIRROR_ALLOW_CIDRS` | *(unset)* | Comma-separated source networks allowed to connect, e.g. `10.2.0.0/22,fd00::/64`. Unset means unrestricted. |
|
||||
| `MIRROR_TRUSTED_PROXIES` | `127.0.0.0/8, ::1/128` | Which peers may speak for a client via `X-Forwarded-For`. Only a proxy that overwrites the header belongs here. |
|
||||
| `DEBUGPY` | `0` | `1` opens a debugpy listener on `DEBUGPY_PORT`. |
|
||||
| `DEBUGPY_PORT` | `5678` | debugpy port. |
|
||||
|
||||
@@ -71,6 +75,11 @@ Environment variables (all optional; a `.env` file is loaded if present):
|
||||
three ways forward (share from localhost, serve HTTPS, or mark that one origin as
|
||||
secure on the sharing device). Watching never needs permission.
|
||||
|
||||
This is why the fleet deployment terminates TLS in nginx rather than exposing
|
||||
`mirror serve` directly — over `https://`, every device on the network can share
|
||||
and none of this applies. A bare `mirror serve` is for the machine it runs on and
|
||||
for testing.
|
||||
|
||||
**Linux.** On X11/Xorg Chromium uses its native capturer — the picker appears and
|
||||
that is the end of it. On Wayland (GNOME/KDE) Chromium goes through
|
||||
`xdg-desktop-portal`, so the compositor shows its **own permission dialog for
|
||||
@@ -78,6 +87,24 @@ each share**, which mirror neither controls nor tries to bypass. Chrome's picker
|
||||
offers whole screens and individual windows; on Wayland what the portal will
|
||||
agree to depends on the compositor.
|
||||
|
||||
## Deployment
|
||||
|
||||
The internal deployment is `https://mirror.reeseapps.com`, described and automated
|
||||
in the deployments repo under `mirror/` (`app/` quadlet, `nginx/` edge, `certbot/`,
|
||||
`route53/`, and a README with the VM SOP). Three things about it are worth knowing
|
||||
from this side:
|
||||
|
||||
- **TLS ends at nginx on the service VM**, not in this process, so there is no
|
||||
`--https` flag here. That is what makes `getDisplayMedia()` available on every
|
||||
device, and it means an `Upgrade` header and a long idle timeout on `/ws` are
|
||||
load-bearing.
|
||||
- **The address list is enforced twice** — nginx `allow`/`deny`, and
|
||||
`MIRROR_ALLOW_CIDRS` in the container for the path that bypasses nginx. Change
|
||||
both in one commit.
|
||||
- **The container has no internet egress.** Media goes browser-to-browser and the
|
||||
server only relays JSON, so it dials nothing; `Internal=true` is what makes
|
||||
that a fact rather than an intention.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user