Add Certificates page and Traefik API frontend client

This commit is contained in:
backup 2026-09-02 12:42:52 -05:00
commit 7fc90524b5
40 changed files with 6585 additions and 359 deletions

View file

@ -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")

View 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)
}
}