diff --git a/hcaptcha/README.md b/hcaptcha/README.md index 952956e0..14542031 100644 --- a/hcaptcha/README.md +++ b/hcaptcha/README.md @@ -39,11 +39,12 @@ hcaptcha.New(config hcaptcha.Config) fiber.Handler ## Config -| Property | Type | Description | Default | -|:----------------|:----------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------| -| SecretKey | `string` | The secret key you obtained from the HCaptcha admin panel. This field must not be empty. | `""` | -| ResponseKeyFunc | `func(fiber.Ctx) (string, error)` | ResponseKeyFunc should return the token that captcha provides upon successful solving. By default, it gets the token from the body by parsing a JSON request and returns the `hcaptcha_token` field. | `hcaptcha.DefaultResponseKeyFunc` | -| SiteVerifyURL | `string` | This property specifies the API resource used for token authentication. | `https://api.hcaptcha.com/siteverify` | +| Property | Type | Description | Default | +|:-----------------|:----------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------| +| SecretKey | `string` | The secret key you obtained from the HCaptcha admin panel. This field must not be empty. | `""` | +| ResponseKeyFunc | `func(fiber.Ctx) (string, error)`| ResponseKeyFunc should return the token that captcha provides upon successful solving. By default, it gets the token from the body by parsing a JSON request and returns the `hcaptcha_token` field. | `hcaptcha.DefaultResponseKeyFunc` | +| SiteVerifyURL | `string` | This property specifies the API resource used for token authentication. | `https://api.hcaptcha.com/siteverify` | +| ValidateFunc | `func(bool, fiber.Ctx) error` | A custom validation function that allows you to define the behavior upon validation success or failure. If set, it will be called with the validation result and the context. | `nil` | ## Example @@ -51,6 +52,7 @@ hcaptcha.New(config hcaptcha.Config) fiber.Handler package main import ( + "errors" "github.com/gofiber/contrib/hcaptcha" "github.com/gofiber/fiber/v3" "log" @@ -63,9 +65,22 @@ const ( func main() { app := fiber.New() + + // Create HCaptcha middleware captcha := hcaptcha.New(hcaptcha.Config{ // Must set the secret key SecretKey: TestSecretKey, + // Custom validation function (optional) + ValidateFunc: func(success bool, c fiber.Ctx) error { + if !success { + c.Status(fiber.StatusForbidden).JSON(fiber.Map{ + "error": "Custom error: validation failed, please try again", + "details": "The HCaptcha validation was unsuccessful.", + }) + return errors.New("custom error: validation failed") + } + return nil + }, }) app.Get("/api/", func(c fiber.Ctx) error { @@ -74,9 +89,9 @@ func main() { }) }) - app.Post("/api/robots-excluded", func(c fiber.Ctx) error { + app.Post("/api/submit", captcha, func(c fiber.Ctx) error { return c.SendString("You are not a robot") - }, captcha) + }) log.Fatal(app.Listen(":3000")) } diff --git a/hcaptcha/config.go b/hcaptcha/config.go index 91bff4ed..3f5af07f 100644 --- a/hcaptcha/config.go +++ b/hcaptcha/config.go @@ -19,6 +19,8 @@ type Config struct { // SiteVerifyURL is the endpoint URL where the program should verify the given token // default value is: "https://api.hcaptcha.com/siteverify" SiteVerifyURL string + // ValidateFunc allows custom validation logic based on the HCaptcha validation result and the context + ValidateFunc func(success bool, c fiber.Ctx) error } // DefaultResponseKeyFunc is the default function to get the HCaptcha token from the request body diff --git a/hcaptcha/hcaptcha.go b/hcaptcha/hcaptcha.go index 2a1218ba..220fa3e2 100644 --- a/hcaptcha/hcaptcha.go +++ b/hcaptcha/hcaptcha.go @@ -69,9 +69,18 @@ func (h *HCaptcha) Validate(c fiber.Ctx) error { return fmt.Errorf("error decoding HCaptcha API response: %w", err) } - if !o.Success { - c.Status(fiber.StatusForbidden) - return errors.New("unable to check that you are not a robot") + // Use custom ValidateFunc if defined, otherwise default behavior + if h.ValidateFunc != nil { + if err := h.ValidateFunc(o.Success, c); err != nil { + // If the custom ValidateFunc returns an error, set the response status code accordingly + c.Status(fiber.StatusForbidden) + return err + } + } else { + if !o.Success { + c.Status(fiber.StatusForbidden) + return errors.New("unable to check that you are not a robot") + } } return c.Next()