CreaCaptcha

code-challenge.php

Code-Challenge library layer: trigger decision, transient-backed token codec, and random code generator. REST handlers and route registration live at the bottom of this file (added in Task 10).

Table of Contents

Functions

creationell_captcha_should_issue_code_challenge()  : bool
Decides whether the current /challenge request should attach a code-challenge instruction. Returns true iff:
creationell_captcha_code_charset()  : string
Returns the active charset string for the configured option.
creationell_captcha_generate_code()  : string
Generates a fresh random code from the configured charset.
creationell_captcha_code_token_issue()  : string
Issues a token backed by a server-side WP transient that stores the expected code for at most $expiry_seconds. Returns the opaque ID that `/code-image` and `/code-verify` use to look the code up again.
creationell_captcha_code_token_verify()  : string|null
Looks up the code for a token and returns it, or null on: - malformed token (not 32 hex chars) - missing transient (expired or unknown)
creationell_captcha_code_fail_key()  : string
Transient name of the per-token failed-attempt counter (CM-3).
creationell_captcha_code_token_fail()  : void
Records one wrong image-code submission for a token and invalidates the token once its attempt budget is spent.
creationell_captcha_rest_code_image()  : WP_REST_Response
Handles GET /code-image?t=<token>. Looks up the code from the token (server-side transient), renders the PNG, returns 410 on token failure.
creationell_captcha_rest_code_verify()  : WP_REST_Response
Handles POST /code-verify. Two body shapes:
creationell_captcha_register_code_challenge_routes()  : void
Registers the two code-challenge REST routes. The /challenge handler itself stays in includes/rest.php; Task 11 extends it with the codeChallenge field and the data.ccode embed.

Functions

creationell_captcha_should_issue_code_challenge()

Decides whether the current /challenge request should attach a code-challenge instruction. Returns true iff:

creationell_captcha_should_issue_code_challenge() : bool
  1. the master toggle is on, AND
  2. PHP-GD is available, AND
  3. at least one of the three trigger conditions matches (under-attack, ratelimit threshold, watch-list).
Return values
bool

creationell_captcha_code_charset()

Returns the active charset string for the configured option.

creationell_captcha_code_charset(string $charset_key) : string
Parameters
$charset_key : string

One of: digits / alphanumeric / alphanumeric-no-confusing.

Return values
string

creationell_captcha_generate_code()

Generates a fresh random code from the configured charset.

creationell_captcha_generate_code() : string
Return values
string

creationell_captcha_code_token_issue()

Issues a token backed by a server-side WP transient that stores the expected code for at most $expiry_seconds. Returns the opaque ID that `/code-image` and `/code-verify` use to look the code up again.

creationell_captcha_code_token_issue(string $code, int $expiry_seconds) : string

The code is intentionally NOT encoded into the token itself — a base64 round-trip would leak the code to anyone who can read the network response (defeats the OCR-resistant captcha goal). Server state via WP transients is the accepted trade-off.

Parameters
$code : string

The expected code (already from generator).

$expiry_seconds : int

Seconds until the token expires.

Return values
string

creationell_captcha_code_token_verify()

Looks up the code for a token and returns it, or null on: - malformed token (not 32 hex chars) - missing transient (expired or unknown)

creationell_captcha_code_token_verify(string $token[, bool $consume = false ]) : string|null
Parameters
$token : string

The 32-hex-char ID from code_token_issue.

$consume : bool = false

Delete the transient after successful lookup (single-use semantics). The /code-image handler passes false; /code-verify passes true ONLY after a successful code match so retries on wrong input still work.

Return values
string|null

creationell_captcha_code_fail_key()

Transient name of the per-token failed-attempt counter (CM-3).

creationell_captcha_code_fail_key(string $token) : string
Parameters
$token : string

The 32-hex-char ID from code_token_issue.

Return values
string

creationell_captcha_code_token_fail()

Records one wrong image-code submission for a token and invalidates the token once its attempt budget is spent.

creationell_captcha_code_token_fail(string $token) : void

Before this existed, a wrong code was completely free: /code-verify returned 401 before the consume, nothing was counted, and the REST route is not covered by the default rate-limit scopes (core/forms). A client could therefore walk a token through the entire code space. The counter lives exactly as long as the token it belongs to, so it cannot be reset by waiting — only by fetching a fresh challenge, which also means a fresh PoW.

Parameters
$token : string

The 32-hex-char ID from code_token_issue.

creationell_captcha_rest_code_image()

Handles GET /code-image?t=<token>. Looks up the code from the token (server-side transient), renders the PNG, returns 410 on token failure.

creationell_captcha_rest_code_image(WP_REST_Request $request) : WP_REST_Response

Idempotent — the transient is NOT consumed here so the browser may reload the image.

Parameters
$request : WP_REST_Request

The REST request. Required query parameter t (opaque server-issued token).

Return values
WP_REST_Response —

200 with image/png body on success; 410 when the token is unknown/expired or PHP-GD is unavailable.

creationell_captcha_rest_code_verify()

Handles POST /code-verify. Two body shapes:

creationell_captcha_rest_code_verify(WP_REST_Request $request) : WP_REST_Response
  • Code-Challenge mode: { "code": "", "payload": "" } The widget rendered a code-image because the /challenge response embedded data.ccode. Token lookup → case-insensitive match → single-use consume → "code stage passed" marker for this challenge.

    • Plain server-verify mode: { "payload": "" } (no code) ALTCHA's widget posts here unconditionally whenever verifyUrl is set (see widget.js logic: verifyUrl ? _e() : verified()). Structural verify only — nothing is consumed, because there is nothing to protect: the endpoint hands back exactly what it was given.

Neither mode mints a payload any more (CM-5, Wurzel 3.1). The old handler ended in Engine::issue_signed_payload(), which made the SERVER solve a fresh PoW (solveChallenge()) and returned a ready-to-use payload — one client-side solve was enough to drive an endless loop of server-side key derivations. The response now echoes the SUBMITTED payload back verbatim, so a caller never gains anything it did not already have.

Parameters
$request : WP_REST_Request

The REST request with JSON body {payload: string, code?: string}.

Return values
WP_REST_Response —

200 on success ({payload, verified: true}); 400 on malformed body; 401 on wrong code; 410 on missing/expired/unsigned payload or token.

creationell_captcha_register_code_challenge_routes()

Registers the two code-challenge REST routes. The /challenge handler itself stays in includes/rest.php; Task 11 extends it with the codeChallenge field and the data.ccode embed.

creationell_captcha_register_code_challenge_routes() : void

        
On this page

Search results