package server import ( "fmt" "net/http" "time" "wolsol-agent/auth" "wolsol-agent/system" "git.secnex.io/secnex/masterlog" ) // APIServer handles HTTP API requests type APIServer struct { port int authenticator *auth.Authenticator } // NewAPIServer creates a new API server func NewAPIServer(port int, authenticator *auth.Authenticator) *APIServer { return &APIServer{ port: port, authenticator: authenticator, } } // Start starts the API server func (s *APIServer) Start(done chan bool) { mux := http.NewServeMux() mux.HandleFunc("/shutdown", s.handleShutdown) server := &http.Server{ Addr: fmt.Sprintf(":%d", s.port), Handler: mux, } masterlog.Info("API server listening on port", map[string]interface{}{ "port": s.port, }) // Start server in goroutine go func() { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { masterlog.Error("API server error", map[string]interface{}{ "error": err, }) } }() // Wait for shutdown signal <-done server.Close() } func (s *APIServer) handleShutdown(w http.ResponseWriter, r *http.Request) { // Check authentication username, password, ok := r.BasicAuth() if !ok { w.Header().Set("WWW-Authenticate", `Basic realm="SOL Agent"`) http.Error(w, "Unauthorized", http.StatusUnauthorized) masterlog.Error("Unauthorized API request", map[string]interface{}{ "address": r.RemoteAddr, "error": "no auth", }) return } // Verify credentials if !s.authenticator.Verify(username, password) { w.Header().Set("WWW-Authenticate", `Basic realm="SOL Agent"`) http.Error(w, "Unauthorized", http.StatusUnauthorized) masterlog.Error("Unauthorized API request", map[string]interface{}{ "address": r.RemoteAddr, "error": "invalid credentials", }) return } masterlog.Info("Authenticated shutdown request", map[string]interface{}{ "address": r.RemoteAddr, }) w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "Shutting down system...\n") // Shutdown in a goroutine to allow response to be sent go func() { time.Sleep(500 * time.Millisecond) system.Shutdown() }() }