-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
hCaptcha: add custom error handling and fix documentation #1191
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -39,18 +39,20 @@ 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 | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
```go | ||||||||||||||||||||||||
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) | ||||||||||||||||||||||||
}) | ||||||||||||||||||||||||
Comment on lines
+92
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add example of accessing validation results in the handler. Consider showing how to access validation results in the handler for more complex use cases. app.Post("/api/submit", captcha, func(c fiber.Ctx) error {
- return c.SendString("You are not a robot")
+ return c.JSON(fiber.Map{
+ "success": true,
+ "message": "HCaptcha validation successful",
+ // Add any additional processing here
+ })
}) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
log.Fatal(app.Listen(":3000")) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+74
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider wrapping custom validation errors for security. Custom validation functions might return errors containing sensitive information. Consider wrapping these errors with a generic message before returning them to clients. Apply this change: if err := h.ValidateFunc(o.Success, c); err != nil {
c.Status(fiber.StatusForbidden)
- return err
+ return fmt.Errorf("hCaptcha validation failed: %w", err)
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if !o.Success { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c.Status(fiber.StatusForbidden) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return errors.New("unable to check that you are not a robot") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+72
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor duplicate status code setting. The status code setting is duplicated in both branches. Consider setting it once after the validation check. Refactor the code to reduce duplication: // Use custom ValidateFunc if defined, otherwise default behavior
+var validationErr error
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
- }
+ validationErr = h.ValidateFunc(o.Success, c)
} else {
if !o.Success {
- c.Status(fiber.StatusForbidden)
- return errors.New("unable to check that you are not a robot")
+ validationErr = errors.New("unable to check that you are not a robot")
}
}
+
+if validationErr != nil {
+ c.Status(fiber.StatusForbidden)
+ return fmt.Errorf("hCaptcha validation failed: %w", validationErr)
+} 📝 Committable suggestion
Suggested change
Comment on lines
+72
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider allowing custom status codes for validation failures The current implementation forces HTTP 403 Forbidden status for all validation failures. Consider allowing the custom ValidateFunc to set its own status code for more flexibility. 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
}
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return c.Next() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance ValidateFunc example with more specific error handling.
The current error handling could be more informative by including the specific validation failure reason.
📝 Committable suggestion