package gateway import ( "encoding/json" "net/http" "strings" "time" "github.com/DeBrosOfficial/network/pkg/client" "github.com/DeBrosOfficial/network/pkg/logging" "go.uber.org/zap" ) // Build info (set via -ldflags at build time; defaults for dev) var ( BuildVersion = "dev" BuildCommit = "" BuildTime = "" ) // healthResponse is the JSON structure used by healthHandler type healthResponse struct { Status string `json:"status"` StartedAt time.Time `json:"started_at"` Uptime string `json:"uptime"` } func (g *Gateway) healthHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") server := healthResponse{ Status: "ok", StartedAt: g.startedAt, Uptime: time.Since(g.startedAt).String(), } var clientHealth *client.HealthStatus if g.client != nil { if h, err := g.client.Health(); err == nil { clientHealth = h } else { g.logger.ComponentWarn(logging.ComponentClient, "failed to fetch client health", zap.Error(err)) } } resp := struct { Status string `json:"status"` Server healthResponse `json:"server"` Client *client.HealthStatus `json:"client"` }{ Status: "ok", Server: server, Client: clientHealth, } _ = json.NewEncoder(w).Encode(resp) } // statusHandler aggregates server uptime and network status func (g *Gateway) statusHandler(w http.ResponseWriter, r *http.Request) { if g.client == nil { writeError(w, http.StatusServiceUnavailable, "client not initialized") return } // Use internal auth context to bypass client credential requirements ctx := client.WithInternalAuth(r.Context()) status, err := g.client.Network().GetStatus(ctx) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{ "server": map[string]any{ "started_at": g.startedAt, "uptime": time.Since(g.startedAt).String(), }, "network": status, }) } // versionHandler returns gateway build/runtime information func (g *Gateway) versionHandler(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{ "version": BuildVersion, "commit": BuildCommit, "build_time": BuildTime, "started_at": g.startedAt, "uptime": time.Since(g.startedAt).String(), }) } // tlsCheckHandler validates if a domain should receive a TLS certificate // Used by Caddy's on-demand TLS feature to prevent abuse func (g *Gateway) tlsCheckHandler(w http.ResponseWriter, r *http.Request) { domain := r.URL.Query().Get("domain") if domain == "" { http.Error(w, "domain parameter required", http.StatusBadRequest) return } // Get base domain from config baseDomain := "dbrs.space" if g.cfg != nil && g.cfg.BaseDomain != "" { baseDomain = g.cfg.BaseDomain } // Allow any subdomain of our base domain if strings.HasSuffix(domain, "."+baseDomain) || domain == baseDomain { w.WriteHeader(http.StatusOK) return } // Domain not allowed - only allow subdomains of our base domain // Custom domains would need to be verified separately http.Error(w, "domain not allowed", http.StatusForbidden) }