Files
crowdsec-dashy/internal/handlers/machines.go
T

118 lines
3.0 KiB
Go

package handlers
import (
"context"
"fmt"
"net/http"
"regexp"
"time"
"crowdsec-dashy/internal/crowdsec"
)
// MachinesHandler manages the machines page and its POST actions.
type MachinesHandler struct {
deps Deps
}
func NewMachinesHandler(deps Deps) *MachinesHandler {
return &MachinesHandler{deps: deps}
}
// MachinesData is passed to the machines template.
type MachinesData struct {
PageData
Machines []crowdsec.Machine
}
var validMachineID = regexp.MustCompile(`^[a-zA-Z0-9_.\-]{1,128}$`)
// List renders the machines list.
func (h *MachinesHandler) List(w http.ResponseWriter, r *http.Request) {
pd := NewPageData(r, "Machines", h.deps.CLIAvailable, h.deps.PollInterval)
if f := readFlash(r); f.Message != "" {
pd.Flash = f
}
var machines []crowdsec.Machine
if h.deps.CLIAvailable {
ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second)
defer cancel()
var err error
machines, err = h.deps.CLI.ListMachines(ctx)
if err != nil {
pd.Flash = FlashMessage{Type: "error", Message: fmt.Sprintf("cscli error: %v", err)}
}
}
h.deps.Renderer.Render(w, "machines", MachinesData{PageData: pd, Machines: machines})
}
// Delete removes a machine by ID.
func (h *MachinesHandler) Delete(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 4096)
if err := r.ParseForm(); err != nil {
flashRedirect(w, r, "/machines", "error", "invalid form data")
return
}
if !checkCSRF(r) {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
if !h.deps.CLIAvailable {
flashRedirect(w, r, "/machines", "error", "cscli not available")
return
}
id := r.FormValue("id")
if !validMachineID.MatchString(id) {
flashRedirect(w, r, "/machines", "error", "invalid machine id")
return
}
ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second)
defer cancel()
if err := h.deps.CLI.DeleteMachine(ctx, id); err != nil {
flashRedirect(w, r, "/machines", "error", fmt.Sprintf("failed to delete machine: %v", err))
return
}
flashRedirect(w, r, "/machines", "success", fmt.Sprintf("Machine %q deleted", id))
}
// Validate approves a pending machine registration.
func (h *MachinesHandler) Validate(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 4096)
if err := r.ParseForm(); err != nil {
flashRedirect(w, r, "/machines", "error", "invalid form data")
return
}
if !checkCSRF(r) {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
if !h.deps.CLIAvailable {
flashRedirect(w, r, "/machines", "error", "cscli not available")
return
}
id := r.FormValue("id")
if !validMachineID.MatchString(id) {
flashRedirect(w, r, "/machines", "error", "invalid machine id")
return
}
ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second)
defer cancel()
if err := h.deps.CLI.ValidateMachine(ctx, id); err != nil {
flashRedirect(w, r, "/machines", "error", fmt.Sprintf("failed to validate machine: %v", err))
return
}
flashRedirect(w, r, "/machines", "success", fmt.Sprintf("Machine %q validated", id))
}