CreaCaptcha

RateLimiter
in package

Counts requests per client IP in a fixed time window and blocks with HTTP 429 once the configured limit is exceeded. See the module-4 design spec §6.

Table of Contents

Constants

CHALLENGE_ROUTE  = '/creationell-captcha/v1/challenge'
The plugin's own challenge route — the only route exempt from counting.

Methods

run()  : void
Runs the rate limiter for the current request. Registered on `init` at priority 0. Terminates the request with 429 once the limit is exceeded.
context()  : array{ip: string, path: string, path_raw: string, method: string, script: string, action: string, is_ajax: bool}
Builds the request context array.
is_challenge_endpoint()  : bool
Whether the request is actually served by the plugin's own challenge endpoint — the one route that must stay reachable without being counted, because the widget fetches a challenge for every protected form.
should_count()  : bool
Whether the current request counts toward the rate limit.

Constants

CHALLENGE_ROUTE

The plugin's own challenge route — the only route exempt from counting.

private mixed CHALLENGE_ROUTE = '/creationell-captcha/v1/challenge'

Compared for EQUALITY against the route the request actually addresses (CM-7); the previous str_contains() matched any path or rest_route value that merely contained this string.

Methods

run()

Runs the rate limiter for the current request. Registered on `init` at priority 0. Terminates the request with 429 once the limit is exceeded.

public run() : void

context()

Builds the request context array.

private context(string $ip) : array{ip: string, path: string, path_raw: string, method: string, script: string, action: string, is_ajax: bool}
Parameters
$ip : string
Return values
array{ip: string, path: string, path_raw: string, method: string, script: string, action: string, is_ajax: bool}

is_challenge_endpoint()

Whether the request is actually served by the plugin's own challenge endpoint — the one route that must stay reachable without being counted, because the widget fetches a challenge for every protected form.

private is_challenge_endpoint() : bool

BK-2 / CM-7: the previous implementation ran str_contains() over the request path AND over the raw $_GET['rest_route'] value. Both are client-controlled, and neither says anything about what WordPress will actually serve: POST /wp-login.php?rest_route=creationell-captcha/v1/challenge is an ordinary login POST — wp-login.php never calls parse_request(), so rest_api_loaded() never runs — yet it turned the rate limiter off and made the login brute-force limit unenforceable.

The route now comes from creationell_captcha_current_rest_route(), which only reports a route when core would really dispatch one, and it is compared for equality instead of by substring.

Return values
bool

should_count()

Whether the current request counts toward the rate limit.

private should_count(array{ip: string, path: string, path_raw: string, method: string, script: string, action: string, is_ajax: bool} $context, string $scope) : bool
Parameters
$context : array{ip: string, path: string, path_raw: string, method: string, script: string, action: string, is_ajax: bool}

Request context.

$scope : string

The configured scope.

Return values
bool

        
On this page

Search results