Add ban html template (#142)

*  Add ban html template

* 📝 Add doc for custom ban page

* 🍱 fix Mathieu work

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

---------

Co-authored-by: Max Lerebourg <maxlerebourg@gmail.com>
This commit is contained in:
mathieuHa
2024-04-03 17:58:18 +02:00
committed by GitHub
co-authored by Max Lerebourg
parent 6059f23dc3
commit 615e7ccf69
13 changed files with 865 additions and 50 deletions
+27 -10
View File
@@ -8,6 +8,7 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
htmlTemplate "html/template"
"io"
"net/http"
"net/url"
@@ -72,6 +73,7 @@ type Bouncer struct {
customHeader string
crowdsecStreamRoute string
crowdsecHeader string
banTemplate *htmlTemplate.Template
clientPoolStrategy *ip.PoolStrategy
serverPoolStrategy *ip.PoolStrategy
httpClient *http.Client
@@ -118,6 +120,10 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
}
config.CrowdsecLapiKey = apiKey
}
var banTemplate *htmlTemplate.Template
if config.BanHTMLFilePath != "" {
banTemplate, _ = configuration.GetHTMLTemplate(config.BanHTMLFilePath)
}
bouncer := &Bouncer{
next: next,
@@ -141,6 +147,7 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
crowdsecStreamRoute: crowdsecStreamRoute,
crowdsecHeader: crowdsecHeader,
log: log,
banTemplate: banTemplate,
serverPoolStrategy: &ip.PoolStrategy{
Checker: serverChecker,
},
@@ -219,13 +226,13 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
remoteIP, err := ip.GetRemoteIP(req, bouncer.serverPoolStrategy, bouncer.customHeader)
if err != nil {
bouncer.log.Error(fmt.Sprintf("ServeHTTP:getRemoteIp ip:%s %s", remoteIP, err.Error()))
rw.WriteHeader(http.StatusForbidden)
handleBanServeHTTP(bouncer, rw)
return
}
isTrusted, err := bouncer.clientPoolStrategy.Checker.Contains(remoteIP)
if err != nil {
bouncer.log.Error(fmt.Sprintf("ServeHTTP:checkerContains ip:%s %s", remoteIP, err.Error()))
rw.WriteHeader(http.StatusForbidden)
handleBanServeHTTP(bouncer, rw)
return
}
// if our IP is in the trusted list we bypass the next checks
@@ -248,7 +255,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
bouncer.log.Debug(fmt.Sprintf("ServeHTTP:Get ip:%s isBanned:false %s", remoteIP, cacheErrString))
if cacheErrString != cache.CacheMiss {
bouncer.log.Error(fmt.Sprintf("ServeHTTP:Get ip:%s %s", remoteIP, cacheErrString))
rw.WriteHeader(http.StatusForbidden)
handleBanServeHTTP(bouncer, rw)
return
}
} else {
@@ -256,7 +263,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if value == cache.NoBannedValue {
handleNextServeHTTP(bouncer, remoteIP, rw, req)
} else {
handleErrorServeHTTP(bouncer, remoteIP, value, rw, req)
handleRemediationServeHTTP(bouncer, remoteIP, value, rw, req)
}
return
}
@@ -268,7 +275,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
handleNextServeHTTP(bouncer, remoteIP, rw, req)
} else {
bouncer.log.Debug(fmt.Sprintf("ServeHTTP isCrowdsecStreamHealthy:false ip:%s", remoteIP))
rw.WriteHeader(http.StatusForbidden)
handleBanServeHTTP(bouncer, rw)
}
} else {
value, err := handleNoStreamCache(bouncer, remoteIP)
@@ -276,7 +283,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
handleNextServeHTTP(bouncer, remoteIP, rw, req)
} else {
bouncer.log.Debug(fmt.Sprintf("ServeHTTP:handleNoStreamCache ip:%s isBanned:%v %s", remoteIP, value, err.Error()))
handleErrorServeHTTP(bouncer, remoteIP, value, rw, req)
handleRemediationServeHTTP(bouncer, remoteIP, value, rw, req)
}
}
}
@@ -309,8 +316,18 @@ type Login struct {
Expire string `json:"expire"`
}
func handleErrorServeHTTP(bouncer *Bouncer, remoteIP, remediation string, rw http.ResponseWriter, req *http.Request) {
bouncer.log.Debug(fmt.Sprintf("handleErrorServeHTTP ip:%s remediation:%s", remoteIP, remediation))
func handleBanServeHTTP(bouncer *Bouncer, rw http.ResponseWriter) {
rw.WriteHeader(http.StatusForbidden)
if bouncer.banTemplate != nil {
err := bouncer.banTemplate.Execute(rw, map[string]string{"caca": "caca"})
if err != nil {
bouncer.log.Info(fmt.Sprintf("handleBanServeHTTP banTemplateServe %s", err.Error()))
}
}
}
func handleRemediationServeHTTP(bouncer *Bouncer, remoteIP, remediation string, rw http.ResponseWriter, req *http.Request) {
bouncer.log.Debug(fmt.Sprintf("handleRemediationServeHTTP ip:%s remediation:%s", remoteIP, remediation))
if bouncer.captchaClient.Valid && remediation == cache.CaptchaValue {
if bouncer.captchaClient.Check(remoteIP) {
handleNextServeHTTP(bouncer, remoteIP, rw, req)
@@ -319,14 +336,14 @@ func handleErrorServeHTTP(bouncer *Bouncer, remoteIP, remediation string, rw htt
bouncer.captchaClient.ServeHTTP(rw, req, remoteIP)
return
}
rw.WriteHeader(http.StatusForbidden)
handleBanServeHTTP(bouncer, rw)
}
func handleNextServeHTTP(bouncer *Bouncer, remoteIP string, rw http.ResponseWriter, req *http.Request) {
if bouncer.appsecEnabled {
if err := appsecQuery(bouncer, remoteIP, req); err != nil {
bouncer.log.Debug(fmt.Sprintf("handleNextServeHTTP ip:%s isWaf:true %s", remoteIP, err.Error()))
rw.WriteHeader(http.StatusForbidden)
handleBanServeHTTP(bouncer, rw)
return
}
}