package discriminator // The heuristic crowdsec. It reads SWW_WAF_CROWDSEC_LAPI_URL, and the decisions // through the reputation lists. import ( "context" "time" "sneak.berlin/go/smallwebwaf/internal/bans" "sneak.berlin/go/smallwebwaf/internal/config" "sneak.berlin/go/smallwebwaf/internal/reputation" "sneak.berlin/go/smallwebwaf/internal/requestlog" ) // crowdSec refuses a request when a decision of the CrowdSec decision list on // the client is in force at now. It then adds the tag crowdsec, notes the // list, as noteHit does, and bans the client until that decision ends. Its // figures are the decision's scenario and when it ends. type crowdSec struct{} func (crowdSec) name() string { return "crowdsec" } func (crowdSec) check(_ context.Context, rq *request, now time.Time) *verdict { decision, listed := rq.crowdSecDecisionInForce(now) if !listed { return nil } rq.addTag(config.CrowdSecTag) rq.noteHit(bans.ReputationHit{Source: rq.h.config.CrowdSecDecisionsURL}, "listed by the CrowdSec decision list") return &verdict{ action: rq.banForCrowdSec(now, decision), figures: map[string]any{ "scenario": decision.Scenario, "expires": requestlog.FormatTime(decision.Expires), }, } } // crowdSecDecisionInForce returns the decision of the CrowdSec decision list on // the client that is in force at now, and reports whether there is one, which // the heuristic crowdsec refuses the request for. func (rq *request) crowdSecDecisionInForce( now time.Time, ) (reputation.Decision, bool) { return rq.h.lists.CrowdSecDecision(rq.client, now) }