Fix missing imports and restore CORS middleware for tests

After conflict resolution from rebase, some imports were accidentally
removed and the CORS middleware function was eliminated but still
referenced by tests. This commit:
- Adds fmt import to api/rest/keys.go (used for error messages)
- Adds gorilla/mux import to cmd/server/main.go (used for router type)
- Restores newCORSMiddleware function to api/rest/router.go for test compatibility
- Formats code with gofmt
This commit is contained in:
2025-10-30 23:47:27 -07:00
parent 81d11e01bb
commit 56bfcb59d3
5 changed files with 68 additions and 11 deletions
+10 -10
View File
@@ -23,13 +23,13 @@ func TestCORSMiddleware_AllowedOrigin(t *testing.T) {
})) }))
tests := []struct { tests := []struct {
name string name string
origin string origin string
expectOrigin string expectOrigin string
expectMethods string expectMethods string
expectHeaders string expectHeaders string
expectMaxAge string expectMaxAge string
expectCreds string expectCreds string
}{ }{
{ {
name: "allowed origin - example.com", name: "allowed origin - example.com",
@@ -323,9 +323,9 @@ func TestDefaultCORSConfig(t *testing.T) {
// TestCORSMiddleware_MaxAge tests custom max age values // TestCORSMiddleware_MaxAge tests custom max age values
func TestCORSMiddleware_MaxAge(t *testing.T) { func TestCORSMiddleware_MaxAge(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
maxAge int maxAge int
expectMaxAge string expectMaxAge string
}{ }{
{ {
name: "zero max age", name: "zero max age",
+1
View File
@@ -2,6 +2,7 @@ package rest
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
+55
View File
@@ -2,6 +2,8 @@ package rest
import ( import (
"net/http" "net/http"
"strconv"
"strings"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/igodwin/notifier/internal/auth" "github.com/igodwin/notifier/internal/auth"
@@ -105,3 +107,56 @@ func loggingMiddleware(next http.Handler) http.Handler {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }
// newCORSMiddleware creates a CORS middleware with origin whitelist validation
func newCORSMiddleware(config *CORSConfig) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
// Check if the origin is in the allowed list
allowed := false
for _, allowedOrigin := range config.AllowedOrigins {
if origin == allowedOrigin {
allowed = true
break
}
}
// Only set CORS headers if the origin is allowed
if allowed {
// Set the exact origin (never use wildcard)
w.Header().Set("Access-Control-Allow-Origin", origin)
// Set allowed methods
if len(config.AllowedMethods) > 0 {
w.Header().Set("Access-Control-Allow-Methods", strings.Join(config.AllowedMethods, ", "))
}
// Set allowed headers
if len(config.AllowedHeaders) > 0 {
w.Header().Set("Access-Control-Allow-Headers", strings.Join(config.AllowedHeaders, ", "))
}
// Set credentials header if enabled
if config.AllowCredentials {
w.Header().Set("Access-Control-Allow-Credentials", "true")
}
// Set max age for preflight caching
if config.MaxAge > 0 {
w.Header().Set("Access-Control-Max-Age", strconv.FormatInt(int64(config.MaxAge), 10))
}
}
// Handle preflight OPTIONS requests
if r.Method == http.MethodOptions {
// Return 200 OK for preflight requests
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
}
+1
View File
@@ -12,6 +12,7 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/gorilla/mux"
grpcapi "github.com/igodwin/notifier/api/grpc" grpcapi "github.com/igodwin/notifier/api/grpc"
pb "github.com/igodwin/notifier/api/grpc/pb" pb "github.com/igodwin/notifier/api/grpc/pb"
"github.com/igodwin/notifier/api/rest" "github.com/igodwin/notifier/api/rest"
+1 -1
View File
@@ -224,7 +224,7 @@ func setDefaults(v *viper.Viper) {
v.SetDefault("auth.bootstrap.kubernetes_secret_key", "admin-key") // Default secret key v.SetDefault("auth.bootstrap.kubernetes_secret_key", "admin-key") // Default secret key
// CORS defaults - secure by default (no origins allowed) // CORS defaults - secure by default (no origins allowed)
v.SetDefault("cors.allowed_origins", []string{}) // Empty by default - must be explicitly configured v.SetDefault("cors.allowed_origins", []string{}) // Empty by default - must be explicitly configured
v.SetDefault("cors.allowed_methods", []string{"GET", "POST", "OPTIONS", "DELETE"}) // Standard REST methods v.SetDefault("cors.allowed_methods", []string{"GET", "POST", "OPTIONS", "DELETE"}) // Standard REST methods
v.SetDefault("cors.allowed_headers", []string{"Content-Type", "Authorization"}) // Common headers v.SetDefault("cors.allowed_headers", []string{"Content-Type", "Authorization"}) // Common headers
v.SetDefault("cors.allow_credentials", false) // Credentials disabled by default v.SetDefault("cors.allow_credentials", false) // Credentials disabled by default