Replies: 1 comment
|
I think this is the right place to separate three concepts that are currently close together but should stay distinct: request-authority trust, browser authentication, and client privileges. I checked current master after the browser-token authentication work landed. The missing primitive seems narrower than "make trusted hosts privileged": a server-issued authenticated-client grant, with an optional authenticated reverse-proxy bootstrap path. A possible direction:
Security properties I would keep explicit:
This also gives #5430 a safer fix than broadening We have downstream evidence for this deployment shape in DSH Orbit ( Reference: https://github.com/IkariKr/dsh-orbit/tree/v0.3.0-rc.1 If maintainers agree with the direction, I would be happy to help reduce this to the smallest service/interface change once external PRs are accepted again. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
When the DSH web UI is served over any non-loopback origin — a declared
--trusted-host(e.g. a MagicDNS*.ts.netdomain behind Tailscale Serve), a LAN hostname, or a reverse proxy — changes made in Settings → Appearance (theme light/dark/system, font size) are lost on page refresh. They do not persist to the Host settings document.This is caused by a loopback-only hard gate in the client settings persistence path (
ui-settings), which is inconsistent with the/apitrust fence that already honors declared--trusted-hostauthorities.Environment
dsh-v0.1.2-alpha.4dsh web --port 3081 --no-open --trusted-host <host>.taile<xxxx>.ts.nethttps://<host>.taile<xxxx>.ts.net(Tailscale Serve, tailnet-only, Let's Encrypt)./apirequests work correctly (the--trusted-hostfence lets them through).http://127.0.0.1:3081does persist correctly.Steps to reproduce
https://<host>.ts.net/or any LAN hostname).Expected behavior
A host the operator has explicitly trusted via
--trusted-host(and that passes browser-session authentication) should be able to persist UI/appearance settings, consistent with the fact that the same authority is already trusted for/apiaccess. At minimum this behavior should be clearly documented, because today it silently looks like a bug.Root cause
Persistence mode is chosen per page origin and is
'host'only on loopback:packages/client/ui-settings/src/client/index.ts(~line 58):isLoopbackis computed client-side purely from the page hostname:packages/client/connection/src/client/index.ts(~line 228):packages/client/connection/src/loopback-hostname.ts— matches onlylocalhost/127.*/[::1]. A.ts.netMagicDNS name is not loopback.packages/api/gateway/src/client/index.ts—interface RemoteHostFacts { readonly home: string | undefined; readonly isLoopback: boolean }.--trusted-hostlist lives only server-side (packages/client/connection/src/api-request-trust.ts,rpc-host.ts) and is never shipped to the browser, so the client cannot tell whether its current origin is one of the trusted authorities.Inconsistency worth highlighting
The
/apirequest fence already accepts a declared trusted authority:packages/client/connection/src/api-request-trust.ts(~line 103):So the same remote origin that is trusted for
/apiis not trusted for settings persistence. This asymmetry is the core of the bug report.Blast radius of
isLoopbackctx.remote.$host.isLoopbackis currently reused as a coarse "privileged page" flag by at least three consumers:packages/client/ui-settings/src/client/index.ts:58hostvsmemory)packages/client/ui-settings-general/src/client/index.ts:76packages/client/ui-deliverables/src/client/ProducedFiles.tsxThe security rationale for restricting durable writes to the Host settings document is clear. But gating UI appearance persistence (a per-user, low-risk preference) behind the exact same boolean as "open a file on the host OS" is too coarse.
Why this is not a one-line allowlist
--trusted-hostis currently server-private. To let the client evaluate "is my origin trusted", the server would have to ship the trusted-host list to the browser, making it a publicly readable fact on any page that can reach the UI. That partially weakens the original "trust only loopback, never reveal the trust list" posture. Any proposal should therefore be designed as a narrow, session-scoped persistence grant, not a blanket relaxation ofisLoopback.Proposed directions for discussion
Decouple persistence from
isLoopback. Introduce a narrower, server-issued capability (e.g. tied to the existing 30-day browser-session cookie / JWT grant rather than to the page hostname), so a browser that has already authenticated against a--trusted-hostauthority may persist its own UI preferences — while higher-risk surfaces ("open file on host") remain loopback-only.Scoped settings document. Persist remote UI preferences into a per-session / per-cookie settings namespace instead of the shared Host settings document, so a remote trusted user personalizes their own view without mutating the operator's global configuration.
At minimum, document the limitation. If loopback-only persistence is intentional, surface it in the UI ("Changes won't persist on this host") and in
dsh web --help, because today it behaves like a silent data-loss bug.Expected follow-up
All reactions