feat(web): harden server for public exposure

- hard per-traversal deadline (EXPLOREDNS_JOB_TIMEOUT, default 5m) so
  every job reaches a terminal state; timed-out jobs report error with
  any partial results instead of masquerading as complete
- cap concurrent traversals (EXPLOREDNS_MAX_JOBS, default 8) returning
  429 when saturated
- CORS off by default (the embedded SPA is same-origin); opt in via
  EXPLOREDNS_CORS_ORIGIN

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Gary Hansen
2026-07-07 21:50:29 +10:00
co-authored by Claude Fable 5
parent d71c7fbef2
commit 111b8bf48e
4 changed files with 178 additions and 9 deletions
+10 -2
View File
@@ -18,6 +18,7 @@ import (
"log"
"net"
"net/http"
"os"
"time"
)
@@ -93,10 +94,17 @@ func (s *Server) Shutdown(timeout time.Duration) error {
return s.srv.Shutdown(ctx)
}
// corsMiddleware adds CORS headers for cross-origin SPA access.
// corsMiddleware adds CORS headers for cross-origin API access. The
// embedded SPA is served same-origin and needs none, so CORS is off
// unless EXPLOREDNS_CORS_ORIGIN names an allowed origin (use "*" to
// restore the old allow-all behaviour for development).
func corsMiddleware(next http.Handler) http.Handler {
origin := os.Getenv("EXPLOREDNS_CORS_ORIGIN")
if origin == "" {
return next
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")