package surf import ( "net/http" "net/http/httptest" "os" "path/filepath" "testing" "git.golem15.com/golem15/summercms/backpack" "git.golem15.com/golem15/summercms/compass" "git.golem15.com/golem15/summercms/party" ) func TestCORSLaravelGlobMatchesNestedPaths(t *testing.T) { re := compileLaravelGlob("api/*") if re == nil || !re.MatchString("api/v1/acme/genres") { t.Fatal("api/* must match api/v1/acme/genres (Laravel Str::is, not Go path.Match)") } if re.MatchString("_acme/api/v1/genres") { t.Fatal("api/* must not match _acme/api/v1/genres") } mcp := compileLaravelGlob("oauth/mcp/*") if mcp == nil || !mcp.MatchString("oauth/mcp/token") { t.Fatal("oauth/mcp/* must match oauth/mcp/token") } } func TestCORSPathScopedHeaders(t *testing.T) { cfg := CORSConfig{ Paths: []string{"api/*", "oauth/mcp/*"}, AllowedMethods: []string{"*"}, AllowedOrigins: []string{"*"}, AllowedHeaders: []string{"*"}, } mux := http.NewServeMux() mux.HandleFunc("GET /api/v1/acme/genres", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) mux.HandleFunc("GET /_acme/api/v1/genres", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) h := pathScopedCORS(cfg, mux) rec := httptest.NewRecorder() h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/v1/acme/genres", nil)) if rec.Header().Get("Access-Control-Allow-Origin") != "*" { t.Fatalf("token group ACAO = %q", rec.Header().Get("Access-Control-Allow-Origin")) } rec = httptest.NewRecorder() h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/_acme/api/v1/genres", nil)) if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "" { t.Fatalf("JWT group ACAO = %q, want empty", got) } } func TestCORSConfigLoadedFromHTTPSection(t *testing.T) { cfg := writeHTTPConfig(t, ` cors: paths: ["api/*"] allowed_methods: ["*"] allowed_origins: ["*"] allowed_origins_patterns: [] allowed_headers: ["*"] exposed_headers: [] max_age: 0 supports_credentials: false `) got, err := LoadCORSConfig(cfg) if err != nil { t.Fatal(err) } if len(got.Paths) != 1 || got.Paths[0] != "api/*" { t.Fatalf("paths = %v", got.Paths) } if !containsStar(got.AllowedOrigins) { t.Fatalf("origins = %v", got.AllowedOrigins) } } func writeHTTPConfig(t *testing.T, httpYAML string) *compass.Config { t.Helper() dir := t.TempDir() if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: cors-test\n"), 0o644); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "http.yaml"), []byte(httpYAML), 0o644); err != nil { t.Fatal(err) } cfg, err := compass.Open(compass.Options{ Dir: dir, Environ: []string{"SUMMER_ENV=development"}, }) if err != nil { t.Fatal(err) } return cfg } func TestCORSAssembleUsesConfig(t *testing.T) { cfg := writeHTTPConfig(t, ` body_limits: default_bytes: 1048576 upload_bytes: 1048576 cors: paths: ["api/*"] allowed_methods: ["*"] allowed_origins: ["*"] allowed_headers: ["*"] `) p := assemblePlugin{id: "golem15.demo", path: "/genres"} h, err := Assemble(backpack.New(cfg), []party.Plugin{p}) if err != nil { t.Fatal(err) } rec := httptest.NewRecorder() h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/genres", nil)) if rec.Header().Get("Access-Control-Allow-Origin") != "*" { t.Fatalf("ACAO = %q", rec.Header().Get("Access-Control-Allow-Origin")) } }