feat: add whitelist management endpoints to CrowdsecHandler

This commit is contained in:
GitHub Actions
2026-04-15 19:51:46 +00:00
parent 5642a37c44
commit 741a59c333

View File

@@ -63,6 +63,7 @@ type CrowdsecHandler struct {
Hub *crowdsec.HubService
Console *crowdsec.ConsoleEnrollmentService
Security *services.SecurityService
WhitelistSvc *services.CrowdSecWhitelistService
CaddyManager *caddy.Manager // For config reload after bouncer registration
LAPIMaxWait time.Duration // For testing; 0 means 60s default
LAPIPollInterval time.Duration // For testing; 0 means 500ms default
@@ -392,6 +393,7 @@ func NewCrowdsecHandler(db *gorm.DB, executor CrowdsecExecutor, binPath, dataDir
Hub: hubSvc,
Console: consoleSvc,
Security: securitySvc,
WhitelistSvc: services.NewCrowdSecWhitelistService(db, dataDir),
dashCache: newDashboardCache(),
validateLAPIURL: validateCrowdsecLAPIBaseURLDefault,
}
@@ -2700,6 +2702,75 @@ func fileExists(path string) bool {
return err == nil
}
// ListWhitelists returns all CrowdSec IP/CIDR whitelist entries.
func (h *CrowdsecHandler) ListWhitelists(c *gin.Context) {
entries, err := h.WhitelistSvc.List(c.Request.Context())
if err != nil {
logger.Log().WithError(err).Error("failed to list whitelist entries")
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list whitelist entries"})
return
}
c.JSON(http.StatusOK, gin.H{"entries": entries})
}
// AddWhitelist adds a new IP or CIDR to the CrowdSec whitelist.
func (h *CrowdsecHandler) AddWhitelist(c *gin.Context) {
var req struct {
IPOrCIDR string `json:"ip_or_cidr" binding:"required"`
Reason string `json:"reason"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
entry, err := h.WhitelistSvc.Add(c.Request.Context(), req.IPOrCIDR, req.Reason)
if err != nil {
switch {
case errors.Is(err, services.ErrInvalidIPOrCIDR):
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid IP address or CIDR notation"})
case errors.Is(err, services.ErrDuplicateEntry):
c.JSON(http.StatusConflict, gin.H{"error": "entry already exists in whitelist"})
default:
logger.Log().WithError(err).Error("failed to add whitelist entry")
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to add whitelist entry"})
}
return
}
if _, execErr := h.CmdExec.Execute(c.Request.Context(), "cscli", "hub", "reload"); execErr != nil {
logger.Log().WithError(execErr).Warn("cscli hub reload failed after whitelist add (non-fatal)")
}
c.JSON(http.StatusCreated, entry)
}
// DeleteWhitelist removes a whitelist entry by UUID.
func (h *CrowdsecHandler) DeleteWhitelist(c *gin.Context) {
id := c.Param("uuid")
if id == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "uuid is required"})
return
}
if err := h.WhitelistSvc.Delete(c.Request.Context(), id); err != nil {
switch {
case errors.Is(err, services.ErrWhitelistNotFound):
c.JSON(http.StatusNotFound, gin.H{"error": "whitelist entry not found"})
default:
logger.Log().WithError(err).Error("failed to delete whitelist entry")
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete whitelist entry"})
}
return
}
if _, execErr := h.CmdExec.Execute(c.Request.Context(), "cscli", "hub", "reload"); execErr != nil {
logger.Log().WithError(execErr).Warn("cscli hub reload failed after whitelist delete (non-fatal)")
}
c.Status(http.StatusNoContent)
}
// RegisterRoutes registers crowdsec admin routes under protected group
func (h *CrowdsecHandler) RegisterRoutes(rg *gin.RouterGroup) {
rg.POST("/admin/crowdsec/start", h.Start)
@@ -2742,4 +2813,8 @@ func (h *CrowdsecHandler) RegisterRoutes(rg *gin.RouterGroup) {
rg.GET("/admin/crowdsec/dashboard/scenarios", h.DashboardScenarios)
rg.GET("/admin/crowdsec/alerts", h.ListAlerts)
rg.GET("/admin/crowdsec/decisions/export", h.ExportDecisions)
// Whitelist management endpoints (Issue #939)
rg.GET("/admin/crowdsec/whitelist", h.ListWhitelists)
rg.POST("/admin/crowdsec/whitelist", h.AddWhitelist)
rg.DELETE("/admin/crowdsec/whitelist/:uuid", h.DeleteWhitelist)
}