4.2 KiB
joule-moq-room
A room service for WAI live rooms (wai/extensions/live-rooms.md) over
joule-moq-relay. It holds one room's authority and clock keys and:
- issues grants. A visitor's page makes an Ed25519 key and asks for a grant for it
(
POST /grant). The service signs a short-livedWRG1grant: a publisher's (its own audio and video, one of the room's places) or a viewer's (the room to watch). A grant is public, so it is useless without its key: the relay, configured with the authority's key ([[auth.authorities]]), honours it only beside a proof of possession over the relay's own challenge (§10.5), which only the page that holds the key can make. Grants are bounded per client address and overall, and publishers per room. Every role, and so every grant, holds the seek power (live-rooms §3.3, bit 4): a visitor may fetch a track below its live edge (§10.6), from the relay's cache or its DVR window, as a late joiner does for the groups before it joined. A relay refuses such a fetch to a grant without it. - authors the lifecycle (§7.2). The service's clock is a session on the relay. It
watches each publisher's video track (a SUBSCRIBE that asks for no objects): when the
track appears the clock signs
joinandpublishfor the publisher on its events track (live-events §8.1), and when the relay ends the track (the publisher's session closed) it signsleave. Pages author none of it. - serves the room.
GET /roomgives the signed descriptor, the composition descriptor and the publishers' grants, which a page verifies the room with (live-rooms §9).
A room lasts while anyone publishes in it. When the last publisher has left, the next one
starts a new room: a new descriptor at a new t0, under the same authority and clock, so
each room's grants and chain hold one stretch of company.
Running it
joule-moq-room keygen <keys.toml> new keys (mode 0600, never over a file); prints the
relay configuration lines that trust them
joule-moq-room relay-lines <keys.toml> those lines again
joule-moq-room --config <room.toml> serve (room.example.toml shows every field)
The keys file must be readable by its owner alone; the service refuses it otherwise.
Keys has no Debug, so that no log prints a seed.
The relay needs, beside its listener and limits, the lines relay-lines prints:
[[auth.authorities]]
key = "<authority>"
[[auth.grants]] # the clock's events track, in any room
prefix = ["*", "<clock>", "events"]
token_sha256 = "<SHA-256 of the clock's token>"
publish = true
unlimited = true # no session or ingress limit for the clock's session
[[auth.grants]] # the clock watches the publishers
prefix = []
token_sha256 = "<SHA-256 of the clock's token>"
subscribe = true
and a door that holds each publisher's media to its own key:
[[receipts.door]]
prefix = ["*", "*", "video"]
trust_field = 1
HTTP
| Request | Answer |
|---|---|
GET /, GET /health |
{"ok", "relay": the clock's session is open, "room"} |
GET /room |
the room: room, t0_us, descriptor, compose, grants (hex), present, publishers, max_publishers |
POST /grant {"principal": <64 hex>, "role": "publisher" | "viewer"} |
{"grant", "digest", "exp", "role", "room": <as GET /room>}; 409 full or busy; 429 rate with retry_after_s; 503 relay while the clock has no session |
Every answer is JSON with Cache-Control: no-store. The client's address is
CF-Connecting-IP, else the first X-Forwarded-For, else the connection's: the service
listens on loopback behind the front that sets them.
Tests
cargo test (this crate is a workspace of its own, with its own lock file, since it builds
on wai-rs): the keys file, the grants checked against the descriptor and read by the
relay's reader, the places, the limiter, and tests/room_service.rs, the service against a
relay on loopback: a grant and its proof open a session and the clock announces the
publisher, the grant alone opens none, the room verifies, a third publisher is refused,
clients are bounded, and a new room starts when the last publisher has left.
Licence
Apache-2.0.