Documentation
¶
Overview ¶
Package captcha verifies proof-of-work CAPTCHA tokens against a self-hosted Cap server (https://capjs.js.org, docker image tiago2/cap). The CMS uses it to protect the admin login form; host applications may reuse the client for their own forms.
Cap has two halves: a browser side that solves the challenge and puts the resulting token in a hidden cap-token form field — either the visible <cap-widget> checkbox or, by default here, the invisible programmatic mode (see Config.Visible) — and a server that issues challenges and verifies solutions. The browser script itself is served by the Cap server, so no third-party CDN is involved.
Index ¶
Constants ¶
const FieldName = "cap-token"
FieldName is the hidden form field the Cap widget stores its token in.
const PakoPath = "/static/pako_inflate.min.js"
PakoPath is the admin-relative path of the vendored pako library, which the widget's instrumentation step decompresses with.
Like the WASM binary, the widget defaults to a public CDN for this; the admin CSP allows scripts only from the app and the Cap server, so the fetch would be blocked and the solver would stall at the final step with "Instrumentation timed out". Pointing window.CAP_PAKO_URL at our own copy keeps it inside the policy.
Variables ¶
var ErrBadResponse = errors.New("captcha: siteverify did not return a verdict")
ErrBadResponse means no verdict was obtained even though something answered: the body was not JSON, or was JSON without the "success" field a Cap verdict carries. Almost always a deployment pointed at the wrong place — a URL typo, a proxy's error page, some other service on the port — rather than a passing fault.
It is kept apart from ErrUnavailable because the two want different things from an operator: one waits, the other fixes a setting. Both are the absence of a verdict, so a caller that fails open on one usually fails open on both.
ErrUnavailable means no verdict was obtained because the Cap server could not be consulted: the request never completed, or it answered 5xx. This is the outage the fail-open path exists for.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client verifies Cap tokens and produces the URLs the login page needs to embed the widget.
func (*Client) Origin ¶
Origin is the browser-facing origin of the Cap server, for building a Content-Security-Policy that admits the widget.
func (*Client) Verify ¶
Verify checks a widget token with the Cap server.
It returns (true, nil) when the token is good and (false, nil) when the server rejects it — both are verdicts. Every error means the opposite: no verdict was reached, and the caller has to decide what to do about that. See ErrUnavailable and ErrBadResponse for the two ways it happens; errors.Is distinguishes them.
Note what is *not* an error. Cap answers a bad token with a 4xx status and {"success": false}, so a 4xx is a verdict and comes back as one. A body with no "success" field, on the other hand, is not a rejection however well-formed it is — nothing said no, something merely failed to say yes — so it is ErrBadResponse rather than a quiet false.
func (*Client) Visible ¶
Visible reports whether the login form should show Cap's interactive checkbox widget rather than solving the challenge invisibly.
func (*Client) WasmURL ¶
WasmURL is the solver's WebAssembly binary, served by the Cap server. The widget defaults to fetching it from a public CDN; pointing window.CAP_CUSTOM_WASM_URL here keeps everything self-hosted (and inside the CSP) — without it the widget falls back to a many-times-slower pure-JS solver.
func (*Client) WidgetEndpoint ¶
WidgetEndpoint is the value for the widget's data-cap-api-endpoint attribute.
type Config ¶
type Config struct {
// URL is the browser-facing base URL of the Cap server, e.g.
// "https://cap.example.com" or "http://localhost:3000". The widget
// script and challenge API are loaded from here. Required.
URL string
// InternalURL is the base URL the application server uses for
// server-to-server token verification, when that differs from URL —
// e.g. "http://cap:3000" inside a Docker network. Defaults to URL.
InternalURL string
// SiteKey identifies the site to the Cap server. Required.
SiteKey string
// Secret authorizes siteverify calls for the site key. Required.
Secret string
// Visible renders Cap's interactive checkbox widget on the login
// form. The default (false) uses Cap's programmatic mode instead:
// the login page solves the challenge invisibly in the background
// and submits the token with the form, so users never see a
// CAPTCHA at all.
Visible bool
}
Config locates the Cap server and identifies the site to it. Create site keys in the Cap dashboard (log in with the server's ADMIN_KEY).