Documentation
¶
Overview ¶
Package challenge stops bots on form routes (signup, login, contact) with a challenge the browser solves: Cloudflare Turnstile and hCaptcha through SiteVerify, or any Verifier of your own.
Middleware verifies unsafe requests only. A missing or rejected answer is a validation error on the "challenge" field (422, or a redirect back with errors for HTML forms); a provider that cannot be reached denies with 503 (fail closed). Both log a security event. Pass When to ask only suspicious clients, for example after a soft rate limit trips.
verify := challenge.Turnstile(cfg.TurnstileSecret) g.Use(challenge.Middleware(verify, nil)) // on the group holding POST /register
See https://github.com/AlexGalhardo/vukem/blob/main/docs/subsystems.md#bot-challenge.
Index ¶
Examples ¶
Constants ¶
const Field = "challenge"
Field is the validation-error field of a failed challenge.
const Header = "X-Challenge-Token"
Header carries the answer for JSON and Inertia requests, which do not post the widget's hidden form field.
Variables ¶
var ErrRejected = errors.New("challenge: rejected")
ErrRejected is returned by a Verifier when the answer is missing or wrong. Any other error means the check could not run.
Functions ¶
func Middleware ¶
Middleware verifies the challenge on POST, PUT, PATCH and DELETE requests for which when returns true (nil: all of them); safe methods pass, so the page that renders the widget is not challenged.
Example ¶
package main
import (
"net/http"
"github.com/AlexGalhardo/vukem/challenge"
"github.com/AlexGalhardo/vukem/config"
"github.com/AlexGalhardo/vukem/router"
"github.com/AlexGalhardo/vukem/web"
)
func main() {
verify := challenge.Turnstile(config.NewSecret("turnstile-secret"))
verify.Hostname = "example.com"
r := router.New(&web.Services{})
r.Group("", func(g *router.Group) {
g.Use(challenge.Middleware(verify, nil))
g.Post("/register", func(c *web.Ctx) error { return c.String(http.StatusCreated, "welcome") })
})
}
Output:
Types ¶
type SiteVerify ¶
type SiteVerify struct {
// URL is the siteverify endpoint.
URL string
// Secret is the server-side secret key.
Secret config.Secret
// FormField is the form field the widget fills in (the Header is also
// read, for JSON requests).
FormField string
// Hostname, when set, must equal the hostname the provider reports the
// widget was solved on, so a token solved on another site is refused.
Hostname string
// Client sends the request; nil uses httpclient.Safe with a 5s timeout.
Client *http.Client
}
SiteVerify verifies tokens with a siteverify endpoint, the protocol of Cloudflare Turnstile and hCaptcha: the secret, the token and the client IP are posted, and the JSON answer must say success.
func HCaptcha ¶
func HCaptcha(secret config.Secret) *SiteVerify
HCaptcha returns an hCaptcha verifier.
func Turnstile ¶
func Turnstile(secret config.Secret) *SiteVerify
Turnstile returns a Cloudflare Turnstile verifier.