Add Certificates page and Traefik API frontend client
This commit is contained in:
parent
9e4c612dcb
commit
7fc90524b5
40 changed files with 6585 additions and 359 deletions
|
|
@ -165,11 +165,16 @@ func RequireRole(allowedRoles ...string) gin.HandlerFunc {
|
|||
}
|
||||
|
||||
func CORSMiddleware(allowedOrigin string) gin.HandlerFunc {
|
||||
// Reject wildcard when credentials are enabled — browsers will block it anyway.
|
||||
// Only the explicitly configured origin is allowed.
|
||||
isWildcard := allowedOrigin == "*"
|
||||
return func(c *gin.Context) {
|
||||
origin := c.Request.Header.Get("Origin")
|
||||
if origin == allowedOrigin || allowedOrigin == "*" {
|
||||
if !isWildcard && origin != "" && origin == allowedOrigin {
|
||||
c.Header("Access-Control-Allow-Origin", origin)
|
||||
c.Header("Vary", "Origin")
|
||||
}
|
||||
// Explicitly do not set Access-Control-Allow-Origin to "*" when credentials are true
|
||||
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
|
||||
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-CSRF-Token")
|
||||
c.Header("Access-Control-Allow-Credentials", "true")
|
||||
|
|
|
|||
76
backend/internal/api/middleware/cors_test.go
Normal file
76
backend/internal/api/middleware/cors_test.go
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestCORSMiddleware_AllowedOrigin(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
r := gin.New()
|
||||
r.Use(CORSMiddleware("http://localhost:5173"))
|
||||
r.GET("/test", func(c *gin.Context) { c.String(200, "ok") })
|
||||
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
req.Header.Set("Origin", "http://localhost:5173")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
if w.Header().Get("Access-Control-Allow-Origin") != "http://localhost:5173" {
|
||||
t.Fatalf("expected allowed origin header, got %q", w.Header().Get("Access-Control-Allow-Origin"))
|
||||
}
|
||||
if w.Header().Get("Access-Control-Allow-Credentials") != "true" {
|
||||
t.Fatalf("should have credentials true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCORSMiddleware_DisallowedOrigin(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
r := gin.New()
|
||||
r.Use(CORSMiddleware("http://localhost:5173"))
|
||||
r.GET("/test", func(c *gin.Context) { c.String(200, "ok") })
|
||||
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
req.Header.Set("Origin", "http://evil.com")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
if w.Header().Get("Access-Control-Allow-Origin") != "" {
|
||||
t.Fatalf("disallowed origin should not set header, got %q", w.Header().Get("Access-Control-Allow-Origin"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCORSMiddleware_WildcardRejectedWithCredentials(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
r := gin.New()
|
||||
r.Use(CORSMiddleware("*"))
|
||||
r.GET("/test", func(c *gin.Context) { c.String(200, "ok") })
|
||||
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
req.Header.Set("Origin", "http://anything.com")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
got := w.Header().Get("Access-Control-Allow-Origin")
|
||||
if got == "*" {
|
||||
t.Fatalf("must never return * when credentials true, got *")
|
||||
}
|
||||
if got != "" {
|
||||
t.Fatalf("wildcard with credentials should not set allow origin, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCORSMiddleware_Preflight(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
r := gin.New()
|
||||
r.Use(CORSMiddleware("http://localhost:5173"))
|
||||
r.GET("/test", func(c *gin.Context) { c.String(200, "ok") })
|
||||
req := httptest.NewRequest("OPTIONS", "/test", nil)
|
||||
req.Header.Set("Origin", "http://localhost:5173")
|
||||
req.Header.Set("Access-Control-Request-Method", "POST")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusNoContent {
|
||||
t.Fatalf("preflight should be 204, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue