CON-46: ask before connecting to a relay a link picked - #91
Merged
Merged
Conversation
A space carries its relay in its own address, so a link decides on its author's behalf which host the reader's browser opens a WebSocket to, fetches a NIP-11 document from, and — while signed in — answers a NIP-42 challenge from with an event signed by the reader's key. Following a link is not consent to any of that. An unfamiliar host is asked about once, before anything is sent, and the answer is remembered per host in `localStorage`. Both the connection and the AUTH happen inside effects in `useRelay`, so "do not connect" cannot mean calling the hook and ignoring it — the hook must not be called. The shell is split for that: `Shell` decides, `SpaceShell` holds every relay-consuming hook including the `<Outlet>`, and either mounts or does not. Two reasons reach that one mechanism and stay apart as two screens, because a broken link and an undecided one are different things to be told. An address that does not parse no longer falls back to `DEFAULT_RELAY_URL`: until now it connected to the deployment's own relay purely so the view above could draw "Invalid group address." on top of it. Loopback and the host of `VITE_RELAY_URL` are trusted by construction — the first asks `isLocalRelayHost` rather than keeping a second copy of that rule (CON-45 is what one costs), the second is operator configuration, and prompting for a reader's own deployment would only teach them to click through. `/settings/spaces/<host>'<group>` stays outside the gate on purpose: that route calls no `useRelay`, so nothing holds the connection and `SpaceStore.start()` returns at its readiness check. `AppShell.trust.test.tsx` pins that, so wiring a relay through the settings route fails a test rather than quietly connecting. Revoking a remembered relay still means clearing the site's data; the "Trusted relays" list under /settings/profile is deliberately not in this ticket and is written down as residual risk in docs/09.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes CON-46. From the CON-43 security audit. Stacked on
con-45-group-address-host— merge CON-45 first.A space carries its relay in its own address (
/s/<host>'<group>), so a link decides, on its author's behalf, which host the reader's browser opens a WebSocket to, fetches a NIP-11 document from over HTTPS, and — while signed in — answers a NIP-42 challenge from with an event signed by the reader's key. Following a link is not consent to any of that.What is in it
localStorage. Unchecked it still connects, for this visit only — asking again on every reload would train the reader to click through.useRelay, so "do not connect" cannot mean calling the hook and ignoring it. The shell is split:Shelldecides,SpaceShellholds every relay-consuming hook (including the<Outlet>) and either mounts or does not.DEFAULT_RELAY_URL— until now an unreadable link opened a connection to the deployment's relay purely so the view above could draw "Invalid group address." on top of it.VITE_RELAY_URLare trusted by construction: the first throughisLocalRelayHost(CON-45, not a second copy of the rule), the second because operator configuration is not link input./settings/spaces/<host>'<group>stays outside the gate on purpose — that route calls nouseRelay, so nothing holds the connection andSpaceStore.start()returns at its readiness check.AppShell.trust.test.tsxpins it, so wiring a relay through the settings route fails a test rather than quietly connecting.How to test
VITE_RELAY_URL(e.g./s/relay.example'engineering). Before clicking anything, check DevTools → Network: no WebSocket, no NIP-11 request to that host./s/not-an-addressshows the "This link is not a space address" screen, and no relay connection is made at all./settings/spaces/<unknown host>'groupshows the settings nav without a prompt — and still opens no socket (check Network).Known gap
Taking an approval back means clearing the site's data. A "Trusted relays" list under
/settings/profileis deliberately not in this ticket and is written down as residual risk in docs/09.