Cockatrice 2026-10-19-Development-3.1.2-beta.2
A virtual tabletop for multiplayer card games
Loading...
Searching...
No Matches
RateLimiter Class Reference

Thread-safe per-key attempt limiter used to throttle abusive requests. More...

#include <ratelimiter.h>

Collaboration diagram for RateLimiter:
[legend]

Classes

struct  AttemptHistory

Public Member Functions

bool recordAttempt (const QString &key, int maxAttempts, int windowSeconds)
 Record an attempt for key and report whether the key is now blocked.
bool recordAttemptAt (const QString &key, int maxAttempts, int windowSeconds, qint64 now)
 Record an attempt as seen at epoch second now.
bool isBlocked (const QString &key, int maxAttempts, int windowSeconds) const
 True if key already has at least maxAttempts attempts within windowSeconds.
bool isBlockedAt (const QString &key, int maxAttempts, int windowSeconds, qint64 now) const
 Whether key is blocked as measured at epoch second now.
void clearAttempts (const QString &key)
 Drop all recorded attempts for the key, e.g. after a successful login.
int retryAfterSeconds (const QString &key, int maxAttempts, int windowSeconds) const
 Get the retry-after window in seconds for key.
int retryAfterSecondsAt (const QString &key, int maxAttempts, int windowSeconds, qint64 now) const
 Get the retry-after window in seconds for key as measured at now.

Private Member Functions

void pruneLocked (qint64 now)
 Drops keys whose last attempts have fully aged out of their window.

Private Attributes

QMutex mutex
QMap< QString, AttemptHistory > attempts
qint64 lastPruneSecs = 0

Static Private Attributes

static constexpr int PruneIntervalSeconds = 60

Detailed Description

Thread-safe per-key attempt limiter used to throttle abusive requests.

Member Function Documentation

◆ clearAttempts()

void RateLimiter::clearAttempts ( const QString & key)

Drop all recorded attempts for the key, e.g. after a successful login.

Here is the caller graph for this function:

◆ isBlocked()

bool RateLimiter::isBlocked ( const QString & key,
int maxAttempts,
int windowSeconds ) const

True if key already has at least maxAttempts attempts within windowSeconds.

Reads only; records nothing. Returns false when maxAttempts <= 0 or windowSeconds <= 0. Delegates to isBlockedAt().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isBlockedAt()

bool RateLimiter::isBlockedAt ( const QString & key,
int maxAttempts,
int windowSeconds,
qint64 now ) const

Whether key is blocked as measured at epoch second now.

Exposed for deterministic tests; production callers should use isBlocked().

Here is the caller graph for this function:

◆ pruneLocked()

void RateLimiter::pruneLocked ( qint64 now)
private

Drops keys whose last attempts have fully aged out of their window.

Runs at most every PruneIntervalSeconds to stop the map from growing without bound when attackers rotate source addresses.

Here is the caller graph for this function:

◆ recordAttempt()

bool RateLimiter::recordAttempt ( const QString & key,
int maxAttempts,
int windowSeconds )

Record an attempt for key and report whether the key is now blocked.

A key that is already at its limit is not extended: the attempt is rejected without appending, so the lockout lifts once the recorded attempts age out of the window. Returns false immediately when maxAttempts <= 0 or windowSeconds <= 0 (rate limiting disabled), recording nothing.

Delegates to recordAttemptAt() with the current wall-clock time.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ recordAttemptAt()

bool RateLimiter::recordAttemptAt ( const QString & key,
int maxAttempts,
int windowSeconds,
qint64 now )

Record an attempt as seen at epoch second now.

Exposed for deterministic tests; production callers should use recordAttempt().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ retryAfterSeconds()

int RateLimiter::retryAfterSeconds ( const QString & key,
int maxAttempts,
int windowSeconds ) const

Get the retry-after window in seconds for key.

Returns the number of seconds from now until the oldest attempt exits windowSeconds and the key is no longer blocked. If the key is not blocked, returns 0. Returns 0 if maxAttempts <= 0 or windowSeconds <= 0.

Delegates to retryAfterSecondsAt().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ retryAfterSecondsAt()

int RateLimiter::retryAfterSecondsAt ( const QString & key,
int maxAttempts,
int windowSeconds,
qint64 now ) const

Get the retry-after window in seconds for key as measured at now.

Exposed for deterministic tests.

Here is the caller graph for this function:

Member Data Documentation

◆ attempts

QMap<QString, AttemptHistory> RateLimiter::attempts
private

◆ lastPruneSecs

qint64 RateLimiter::lastPruneSecs = 0
private

◆ mutex

QMutex RateLimiter::mutex
mutableprivate

◆ PruneIntervalSeconds

int RateLimiter::PruneIntervalSeconds = 60
staticconstexprprivate

The documentation for this class was generated from the following files: