eleven / messenger Public

server: fetch service sends Access-Control-Allow-Origin: * (#1251)

Every caller is a browser on some other origin (each space is its own), so
without CORS headers fetch() could never read a response — every client
silently fell back to its instance path and the whole client flip was a
no-op in real browsers (curl checks hid it; <img> loads aren't CORS-gated,
which is why proxied images looked fine). '*' is the honest scope: the
service is anonymous by design — no cookies, no credentials, nothing
origin-scoped to protect.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell cb77f1f01fc1fa4378357a5e132238212dc88be1 parent e585830
2 files changed, +15 −1
  • fetch.go +9 −1
  • fetch_test.go +6 −0
diff --git a/fetch.go b/fetch.go
index ad67897..f4bb433 100644
--- a/fetch.go
+++ b/fetch.go
@@ -170,7 +170,15 @@ func (g *fetchServer) handler() http.Handler {
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "https://elevenmessenger.com", http.StatusFound)
})
- return mux
+ // Every caller is a browser on some OTHER origin (each space is its own
+ // origin; the service serves them all), so without CORS headers fetch()
+ // can never read a response and every client silently falls back to its
+ // instance path. `*` is the honest scope: the service is anonymous by
+ // design — no cookies, no credentials, nothing origin-scoped to protect.
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ mux.ServeHTTP(w, r)
+ })
}
// fetchCallerKey is the rate-limit bucket key. Mirrors linkscmd.go — behind
diff --git a/fetch_test.go b/fetch_test.go
index ce2c047..38a91b6 100644
--- a/fetch_test.go
+++ b/fetch_test.go
@@ -48,6 +48,12 @@ func TestFetchUnfurlAndImageProxy(t *testing.T) {
if err != nil {
t.Fatalf("unfurl: %v", err)
}
+ // Callers are browsers on OTHER origins (every space is one): without
+ // this header fetch() can't read the response and clients silently fall
+ // back to their instance path — the bug that made the client flip a no-op.
+ if r.Header.Get("Access-Control-Allow-Origin") != "*" {
+ t.Fatal("missing Access-Control-Allow-Origin — cross-origin clients can't read the service")
+ }
var pv LinkPreview
json.NewDecoder(r.Body).Decode(&pv)
r.Body.Close()