Skip to content

Commit

Permalink
Merge pull request #250 from carverauto/249-security-add-support-for-…
Browse files Browse the repository at this point in the history
…api-key

adding api key
  • Loading branch information
mfreeman451 authored Feb 26, 2025
2 parents 3aaca71 + 4435527 commit fc0ce96
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 4 deletions.
10 changes: 8 additions & 2 deletions pkg/cloud/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,14 @@ func (s *APIServer) setupStaticFileServing() {
}

func (s *APIServer) setupRoutes() {
// Add CORS middleware
s.router.Use(srHttp.CommonMiddleware)
// Create a middleware chain
middlewareChain := func(next http.Handler) http.Handler {
// Order matters: first API key check, then CORS headers
return srHttp.CommonMiddleware(srHttp.APIKeyMiddleware(next))
}

// Add middleware to router
s.router.Use(middlewareChain)

// Basic endpoints
s.router.HandleFunc("/api/nodes", s.getNodes).Methods("GET")
Expand Down
63 changes: 61 additions & 2 deletions pkg/http/middleware.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// Package httpx provides HTTP utilities for the application
package httpx

import (
"log"
"net/http"
"os"
"strings"
)

// CommonMiddleware returns an http.Handler that sets up typical
Expand All @@ -10,10 +14,10 @@ func CommonMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization,X-API-Key")

if r.Method == http.MethodOptions {
// Possibly respond 200 here
// Preflight request response
w.WriteHeader(http.StatusOK)
return
}
Expand All @@ -25,3 +29,58 @@ func CommonMiddleware(next http.Handler) http.Handler {
next.ServeHTTP(w, r)
})
}

// APIKeyMiddleware creates middleware that validates API keys.
func APIKeyMiddleware(next http.Handler) http.Handler {
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
log.Printf("WARNING: API_KEY environment variable not set, API endpoints are unprotected!")
}

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Skip API key check for static file requests
if isStaticFileRequest(r.URL.Path) {
next.ServeHTTP(w, r)

return
}

// Skip API key check if it's not configured (development mode)
if apiKey == "" {
next.ServeHTTP(w, r)

return
}

// Check API key in header or query parameter
requestKey := r.Header.Get("X-API-Key")
if requestKey == "" {
requestKey = r.URL.Query().Get("api_key")
}

// Validate API key
if requestKey == "" || requestKey != apiKey {
log.Printf("Unauthorized API access attempt: %s %s", r.Method, r.URL.Path)
http.Error(w, "Unauthorized", http.StatusUnauthorized)

return
}

next.ServeHTTP(w, r)
})
}

// isStaticFileRequest returns true if the request is for static content.
func isStaticFileRequest(path string) bool {
// Skip API key check for static files (adjust as needed)
staticExtensions := []string{".js", ".css", ".html", ".png", ".jpg", ".svg", ".ico", ".woff", ".woff2"}

for _, ext := range staticExtensions {
if strings.HasSuffix(path, ext) {
return true
}
}

// Also skip for the root path (which serves index.html)
return path == "/"
}

0 comments on commit fc0ce96

Please sign in to comment.