package web import ( "net/http" "net/http/httptest" "path/filepath" "testing" "pete/internal/config" "pete/internal/storage" ) // A sibling parodia.dev host is the same *site* as Pete, so SameSite=Lax lets // the session cookie ride along on its forms. The server has to refuse those // itself, and must still let a same-origin page and a headerless server-to-server // call (gogobee, with its bearer token) through. func TestCrossOriginWritesAreRefused(t *testing.T) { storage.Close() if err := storage.Init(filepath.Join(t.TempDir(), "csrf.db")); err != nil { t.Fatal(err) } t.Cleanup(func() { storage.Close() }) s, err := New(config.WebConfig{SiteTitle: "Pete", ListenAddr: ":0"}, nil, true, config.AdventureConfig{}, nil) if err != nil { t.Fatal(err) } post := func(hdr map[string]string) int { req := httptest.NewRequest("POST", "https://news.parodia.dev/api/state/read", nil) for k, v := range hdr { req.Header.Set(k, v) } rec := httptest.NewRecorder() s.srv.Handler.ServeHTTP(rec, req) return rec.Code } if code := post(map[string]string{"Sec-Fetch-Site": "cross-site"}); code != http.StatusForbidden { t.Errorf("cross-site POST = %d, want 403", code) } if code := post(map[string]string{"Sec-Fetch-Site": "same-site", "Origin": "https://evil.parodia.dev"}); code != http.StatusForbidden { t.Errorf("sibling-subdomain POST = %d, want 403", code) } if code := post(map[string]string{"Sec-Fetch-Site": "same-origin"}); code == http.StatusForbidden { t.Error("same-origin POST was refused") } if code := post(nil); code == http.StatusForbidden { t.Error("headerless server-to-server POST was refused") } }