Refatoring : Working state
This commit is contained in:
67
src/Auth/Infrastructure/PdoLoginAttemptRepository.php
Normal file
67
src/Auth/Infrastructure/PdoLoginAttemptRepository.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Auth\Infrastructure;
|
||||
|
||||
use App\Auth\LoginAttemptRepositoryInterface;
|
||||
use PDO;
|
||||
|
||||
class PdoLoginAttemptRepository implements LoginAttemptRepositoryInterface
|
||||
{
|
||||
public function __construct(private readonly PDO $db)
|
||||
{
|
||||
}
|
||||
|
||||
public function findByIp(string $ip): ?array
|
||||
{
|
||||
$stmt = $this->db->prepare('SELECT * FROM login_attempts WHERE ip = :ip');
|
||||
$stmt->execute([':ip' => $ip]);
|
||||
|
||||
/** @var array{ip: string, attempts: int, locked_until: string|null, updated_at: string}|false $row */
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
public function recordFailure(string $ip, int $maxAttempts, int $lockMinutes): void
|
||||
{
|
||||
$now = (new \DateTime())->format('Y-m-d H:i:s');
|
||||
$lockUntil = (new \DateTime())->modify("+{$lockMinutes} minutes")->format('Y-m-d H:i:s');
|
||||
|
||||
$stmt = $this->db->prepare(
|
||||
'INSERT INTO login_attempts (ip, attempts, locked_until, updated_at)
|
||||
VALUES (:ip, 1, CASE WHEN 1 >= :max1 THEN :lock1 ELSE NULL END, :now1)
|
||||
ON CONFLICT(ip) DO UPDATE SET
|
||||
attempts = login_attempts.attempts + 1,
|
||||
locked_until = CASE WHEN login_attempts.attempts + 1 >= :max2
|
||||
THEN :lock2
|
||||
ELSE NULL END,
|
||||
updated_at = :now2'
|
||||
);
|
||||
|
||||
$stmt->execute([
|
||||
':ip' => $ip,
|
||||
':max1' => $maxAttempts,
|
||||
':lock1' => $lockUntil,
|
||||
':now1' => $now,
|
||||
':max2' => $maxAttempts,
|
||||
':lock2' => $lockUntil,
|
||||
':now2' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
public function resetForIp(string $ip): void
|
||||
{
|
||||
$stmt = $this->db->prepare('DELETE FROM login_attempts WHERE ip = :ip');
|
||||
$stmt->execute([':ip' => $ip]);
|
||||
}
|
||||
|
||||
public function deleteExpired(): void
|
||||
{
|
||||
$now = (new \DateTime())->format('Y-m-d H:i:s');
|
||||
$stmt = $this->db->prepare(
|
||||
'DELETE FROM login_attempts WHERE locked_until IS NOT NULL AND locked_until < :now'
|
||||
);
|
||||
$stmt->execute([':now' => $now]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user