add custom selfhosted captcha (#259)

*  Add wicketkeeper captcha

*  Anom config

* 🍱 fix readme

* 🍱 fix lint

* 🍱 fix lint

* 🍱 normalize

* 🍱 fix lint

* 🍱 fix lint

*  Add env for RemediationStatusCode (#250)

*  Add env for defaultStatusCode

* 📝 doc

* change name of the parameter

* 🔧 Add config check

* fix lint

* 📈 Report traffic dropped metrics to LAPI (#223)

* Initial implementation

* fix

* fixes

* Fixes

* xx

* progress

* xx

* xx

* xx

* fix linter

* Progress

* Fixes

* xx

* xx

* Remove trace logger

* Last fix

* fix lint

* fix lint

* fix lint

---------

Co-authored-by: Max Lerebourg <maxlerebourg@gmail.com>

*  Anom config

* 🍱 fix readme

* 🍱 fix lint

* 🍱 normalize

* 🍱 fix lint

* 📝 Add documentation

* 📝 Fix example and makefile and doc for wicketkeeper

* 🍱 fix last things

* 🍱 add disclaimer to use maxlerebourg docker image

* 🍱 Use official wicketpeeker image

* 🍱 revert unnecessary code

* 🍱 fix

---------

Co-authored-by: David <deivid.garcia.garcia@gmail.com>
Co-authored-by: max.lerebourg <max.lerebourg@monisnap.com>
Co-authored-by: mhx <mathieu@hanotaux.fr>
This commit is contained in:
maxlerebourg
2025-09-01 19:41:45 +02:00
committed by GitHub
co-authored by David max.lerebourg mhx
parent 734975c206
commit 7c4f5163e9
13 changed files with 649 additions and 46 deletions
+34 -6
View File
@@ -34,6 +34,7 @@ const (
HcaptchaProvider = "hcaptcha"
RecaptchaProvider = "recaptcha"
TurnstileProvider = "turnstile"
CustomProvider = "custom"
)
// Config the plugin configuration.
@@ -84,6 +85,10 @@ type Config struct {
BanHTMLFilePath string `json:"banHtmlFilePath,omitempty"`
CaptchaHTMLFilePath string `json:"captchaHtmlFilePath,omitempty"`
CaptchaProvider string `json:"captchaProvider,omitempty"`
CaptchaCustomJsURL string `json:"captchaCustomJsUrl,omitempty"`
CaptchaCustomValidateURL string `json:"captchaCustomValidateUrl,omitempty"`
CaptchaCustomKey string `json:"captchaCustomKey,omitempty"`
CaptchaCustomResponse string `json:"captchaCustomResponse,omitempty"`
CaptchaSiteKey string `json:"captchaSiteKey,omitempty"`
CaptchaSiteKeyFile string `json:"captchaSiteKeyFile,omitempty"`
CaptchaSecretKey string `json:"captchaSecretKey,omitempty"`
@@ -125,6 +130,10 @@ func New() *Config {
RemediationStatusCode: http.StatusForbidden,
HTTPTimeoutSeconds: 10,
CaptchaProvider: "",
CaptchaCustomJsURL: "",
CaptchaCustomValidateURL: "",
CaptchaCustomKey: "",
CaptchaCustomResponse: "",
CaptchaSiteKey: "",
CaptchaSecretKey: "",
CaptchaGracePeriodSeconds: 1800,
@@ -196,6 +205,10 @@ func ValidateParams(config *Config) error {
return err
}
if err := validateCaptcha(config); err != nil {
return err
}
if err := validateParamsIPs(config.ForwardedHeadersTrustedIPs, "ForwardedHeadersTrustedIPs"); err != nil {
return err
}
@@ -331,6 +344,24 @@ func validateParamsIPs(listIP []string, key string) error {
return nil
}
func validateCaptcha(config *Config) error {
if !contains([]string{"", HcaptchaProvider, RecaptchaProvider, TurnstileProvider, CustomProvider}, config.CaptchaProvider) {
return fmt.Errorf("CaptchaProvider: must be one of '%s', '%s', '%s' or '%s'", HcaptchaProvider, RecaptchaProvider, TurnstileProvider, CustomProvider)
}
if config.CaptchaProvider == CustomProvider {
if config.CaptchaCustomKey == "" || config.CaptchaCustomResponse == "" || config.CaptchaCustomValidateURL == "" || config.CaptchaCustomJsURL == "" {
return fmt.Errorf(
"CaptchaProvider: provider is custom, captchaCustom variables must be filled: CaptchaCustomKey:%s, CaptchaCustomResponse:%s, CaptchaCustomValidateURL:%s, CaptchaCustomJsURL:%s",
config.CaptchaCustomKey,
config.CaptchaCustomResponse,
config.CaptchaCustomValidateURL,
config.CaptchaCustomJsURL,
)
}
}
return nil
}
func validateParamsRequired(config *Config) error {
requiredStrings := map[string]string{
"CrowdsecLapiScheme": config.CrowdsecLapiScheme,
@@ -339,7 +370,7 @@ func validateParamsRequired(config *Config) error {
}
for key, val := range requiredStrings {
if len(val) == 0 {
return fmt.Errorf("%v: cannot be empty", key)
return errors.New(key + ": cannot be empty")
}
}
requiredInt0 := map[string]int64{
@@ -348,7 +379,7 @@ func validateParamsRequired(config *Config) error {
}
for key, val := range requiredInt0 {
if val < 0 {
return fmt.Errorf("%v: cannot be less than 0", key)
return errors.New(key + ": cannot be less than 0")
}
}
requiredInt1 := map[string]int64{
@@ -359,7 +390,7 @@ func validateParamsRequired(config *Config) error {
}
for key, val := range requiredInt1 {
if val < 1 {
return fmt.Errorf("%v: cannot be less than 1", key)
return errors.New(key + ": cannot be less than 1")
}
}
if config.UpdateMaxFailure < -1 {
@@ -378,9 +409,6 @@ func validateParamsRequired(config *Config) error {
if !contains([]string{HTTP, HTTPS}, config.CrowdsecLapiScheme) {
return errors.New("CrowdsecLapiScheme: must be one of 'http' or 'https'")
}
if !contains([]string{"", HcaptchaProvider, RecaptchaProvider, TurnstileProvider}, config.CaptchaProvider) {
return errors.New("CaptchaProvider: must be one of 'hcaptcha', 'recaptcha' or 'turnstile'")
}
return nil
}