diff --git a/docs/operations.md b/docs/operations.md index 1d9b0f0..8b3976b 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -24,6 +24,8 @@ The service always runs from the app: `/Applications/Byre.app/Contents/Helpers/b byre runs its own tailnet node with `tsnet`; it doesn't use the Tailscale app. The API is served only there, at the root of the node's `ts.net` name on 443, not under a path: the API uses absolute paths and the app takes an origin with no path. There is no way to call the API other than as a tailnet user; a tagged node gets 403. +Tailscale identifies the connecting Mac, including requests from a web page opened there; network identity alone doesn't establish the user's intent. Cross-origin browser requests must not be allowed to change state through that identity. Native app and CLI access remains intentional. + A new node needs signing in: `curl /api/tailnet` (`byre check` prints the loopback address) shows `NeedsLogin` and the `auth_url`, and the app on the same Mac shows it as **Sign in to Tailscale**. The tailnet must have MagicDNS and HTTPS certificates turned on (the DNS page of Tailscale's admin console); without certificates byre logs `tailnet has no https certificates` and serves only the loopback address until it is restarted. Each preview gets its own port on byre's node rather than a path under byre's origin, since path-prefix proxying breaks apps that use absolute paths. diff --git a/internal/server/server.go b/internal/server/server.go index 3d09943..7513768 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -121,7 +121,7 @@ func (s *Server) Handler() http.Handler { writeError(w, http.StatusBadRequest, err) }, }) - return mux + return http.NewCrossOriginProtection().Handler(mux) } func (s *Server) LoopbackHandler() http.Handler {