Kyrux
Back

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.