superseded by the full set from 09-23, #17–#37
description:
Review set for lichen.page.review, 0b92cb61 (reviewed) → eb5a1653 (stack). PR 10 of 16. 16 files, +2629/−467. One commit, 33c1d1346eea, which sets these files to their content at eb5a1653. Targets #9 (oct/09-iroh). #11 stacks on this one. Tests and generated files are not in any PR; they are in main.
The front server's sign-in, sessions and routing, after the admin/edit host split and the security-table conformance fixes.
Hosts and roles (ADMIN-EDIT-HOST-SPLIT). A server with a dashboard now answers three kinds of host: the dashboard (dash.<domain>, admin), each site's edit host (<site>.edit.<domain>, or edit.<custom domain>; the editor only), and the site's published host, where /cms editing is also allowed (operator note N10). An edit host has its own session cookie, bound to that host and its one site; the owner signed in on the dashboard reaches it through a one-time handoff code. Each role sets its own framing headers (frame-ancestors, X-Frame-Options, Origin-Agent-Cluster). server.rs dispatches by host to these roles, every route in its permission group (#2); clients' git routes go to the hub (#5).
Fixes from the security-table conformance review, each named in the code:
- STC-CSRF1: a browser's state-changing request must come from a page of this host; the session cookie is shared with sibling sites on a dashboard domain.
- Password sign-ins are rate-limited per client and account, on account login, token login and the share-password login;
trusted_proxiessays whoseX-Forwarded-Forto believe. - STC-ATPROTO1: the CLI's atproto login is verified (the handle against the DID, a loopback client id, the grant as the server refreshed it), and atproto discovery follows no redirect to a private address.
- TOKEN-SESSION1: a bearer token's identity is that request's only; it no longer leaks into the session cookie.
- STC-GUEST1 / STC-FIXATION1: a share guest is let go when the share password changes; every login cycles the session id.
- STC-FWDCRED1: the session cookie is taken off what is forwarded to a site process.
info:
Plans: ADMIN-EDIT-HOST-SPLIT-2026-10-13.md (H1 host roles, H1e guests' admin acts, H2a handoff, H3 request checks and framing; the operator's answers Q1–Q4 in its header), OPERATOR-REVIEW-NOTES-2026-10-13.md N10, SECURITY-TABLE-CONFORMANCE-2026-10-11.md (S2 fixes) and its findings list SECURITY-TABLE-CONFORMANCE-2-2026-10-13.md.
Files (crates/lichen-server/src/)
host_roles.rs— new: which host is which role; the edit-host name rules (one label, injective). Read first.server.rs(+520/−166) — host dispatch, the edit host's router and cookie, role headers, the hub's git routes, permission groups on every router, the React dashboard's files and no-JS forms mounted.handoff.rs— new: the dashboard-to-edit-host sign-in code (H2a).same_origin.rs— new: STC-CSRF1.session_scope.rs— the cookie's name and scope; refusals in the dashboard API's error shape on/api.auth.rs—not_signed_in(401 for the API, redirect otherwise), the share guest's session bound to the password hash, session-id cycling.auth/login_limit.rs— new: the rate limit.auth/token.rs— TOKEN-SESSION1; the CLI's grant stored as the server refreshed it.auth/atproto/cli_login.rs— new: what the CLI's login must prove (STC-ATPROTO1).auth/atproto/client.rs— a no-redirect client; handles a DID names; discovery checked public.auth/atproto/handlers.rs,auth/atproto.rs,auth/oidc/handlers.rs,auth/atproto/discovery.rs— routes into groups; the loopback client id; a moved type path.credentials.rs— the owner's atproto session as the front server's own work uses it (push topds://, records); no site process holds one.users.rs—read_ownedfor blocking workers; small.
Moved in: auth/atproto/* (the starting map's iroh/sync bucket matched them on atproto) and handoff.rs (its Site area bucket matched handoff).
Lives elsewhere
access.rs, the front server's permission policy: #2.- The sign-in pages themselves, now React drawn on the server (
sign_in_render.rs): #12. server_settings.rs(trusted_proxies, single-site state): #11.docs/HOSTS.md, which describes the hosts for operators: #16.- Tests (
auth/tests/,tests/same_origin.rs,host_roles.rs,handoff.rs,server.rs,router_group_semantics.rs, e2e) are inmain.