Files
vojta 2b9a673912 Initial commit: AzerothCore registration site
PHP registration page for AzerothCore with SRP6 salt/verifier generation,
Cloudflare Turnstile + honeypot + rate limiting anti-spam, and a WoW-themed
landing page with client setup instructions.
2026-08-05 11:41:24 +02:00

66 lines
1.9 KiB
PHP

<?php
declare(strict_types=1);
/**
* File-based (SQLite) rate limiter keyed by IP. Kept separate from the
* AzerothCore auth database on purpose — this is purely a web-layer
* anti-spam guard, not game data.
*/
final class RateLimiter
{
private PDO $db;
private int $maxAttempts;
private int $windowSeconds;
public function __construct(string $storagePath, int $maxAttempts, int $windowSeconds)
{
$this->maxAttempts = $maxAttempts;
$this->windowSeconds = $windowSeconds;
$isNew = !is_file($storagePath);
$this->db = new PDO('sqlite:' . $storagePath);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($isNew) {
$this->db->exec(
'CREATE TABLE attempts (
ip TEXT NOT NULL,
created_at INTEGER NOT NULL
)'
);
$this->db->exec('CREATE INDEX idx_attempts_ip ON attempts (ip, created_at)');
}
}
public function tooManyAttempts(string $ip): bool
{
$this->cleanup($ip);
$stmt = $this->db->prepare('SELECT COUNT(*) FROM attempts WHERE ip = :ip AND created_at > :since');
$stmt->execute([
':ip' => $ip,
':since' => time() - $this->windowSeconds,
]);
return (int) $stmt->fetchColumn() >= $this->maxAttempts;
}
public function recordAttempt(string $ip): void
{
$stmt = $this->db->prepare('INSERT INTO attempts (ip, created_at) VALUES (:ip, :now)');
$stmt->execute([
':ip' => $ip,
':now' => time(),
]);
}
private function cleanup(string $ip): void
{
$stmt = $this->db->prepare('DELETE FROM attempts WHERE ip = :ip AND created_at <= :since');
$stmt->execute([
':ip' => $ip,
':since' => time() - $this->windowSeconds,
]);
}
}