Captcha (core/security/captcha)
A simple visual challenge (distorted numeric code, rendered as PNG) for public forms — with no dependency on any external service (Google reCAPTCHA, hCaptcha, etc). Zero account setup, zero API key, zero network call for the visitor's browser to block or slow down.
Ready-to-use — captcha.Store
import "kyrux/core/security/captcha"
captchaStore := captcha.NewStore(fw.Sessions)
router.Path("GET", "/captcha/image", captchaStore.ImageHandler(), "captcha_image"),
// in the form's POST handler:
if !captchaStore.Verify(ctx, ctx.Request.FormValue("captcha_answer")) {
// wrong code — show an error and don't process the form
}
In the template:
<img src="{{ url "captcha_image" }}" alt="Verification code" id="captchaImg">
<input type="text" name="captcha_answer" maxlength="5" inputmode="numeric" required>
ImageHandler generates a new code on every request (useful for a "get a
new one" link in the front end — swap the image's src with a
cache-buster, e.g. ?t=Date.now()) and stores it in the visitor's
session, replacing the previous one. Verify checks the answer against
the session's code and consumes it (single use) regardless of the
outcome — a fresh image is always needed for a new attempt.
Low-level primitives
To store the code somewhere other than a session (e.g. a database, in a cookie-less flow):
code, err := captcha.New() // random code of captcha.CodeLength digits
png, err := captcha.PNG(code) // distorted PNG image of the code
How the image works
A custom 5x7 bitmap font (digits 0-9 only, avoiding visual ambiguity like
0/O or 1/I/l), drawn with the stdlib's image/image/png — no
golang.org/x/image, no third-party dependency at all. Background noise
(random lines and dots) and a slight per-character slant make simple
automated OCR harder.