92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
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()
|
|
}()
|
|
}
|