RateLimitService::blockIp()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Jidaikobo\Kontiki\Services;
4
5
use Illuminate\Database\Connection;
6
use Jidaikobo\Kontiki\Core\Database;
7
8
class RateLimitService
9
{
10
    private Connection $db;
11
    private int $blockDuration = 900; // 15 minutes
12
    private int $limitDuration = 180; // 3 minutes
13
    private int $maxAttempts = 5;     // Max 5 attempts
14
15
    public function __construct(Database $db)
16
    {
17
        $this->db = $db->getConnection();
18
    }
19
20
    public function recordFailedLogin(string $ip): void
21
    {
22
        $now = time();
23
        $record = $this->getRateLimitRecord($ip);
24
25
        if ($record) {
26
            $this->db->table('rate_limit')
27
                ->where('ip_address', $ip)
28
                ->update([
29
                    'attempt_count' => $record->attempt_count + 1,
30
                    'last_attempt' => $now,
31
                ]);
32
        } else {
33
            $this->db->table('rate_limit')->insert([
34
                'ip_address' => $ip,
35
                'attempt_count' => 1,
36
                'first_attempt' => $now,
37
                'last_attempt' => $now,
38
            ]);
39
        }
40
    }
41
42
    public function isIpBlocked(string $ip): bool
43
    {
44
        $record = $this->getRateLimitRecord($ip);
45
        if (!$record) {
46
            return false;
47
        }
48
49
        if ($this->isCurrentlyBlocked($record)) {
50
            return true;
51
        }
52
        if ($this->shouldBlockIp($record)) {
53
            $this->blockIp($ip);
54
            return true;
55
        }
56
        return false;
57
    }
58
59
    public function resetRateLimit(string $ip): void
60
    {
61
        $this->db->table('rate_limit')
62
            ->where('ip_address', $ip)
63
            ->delete();
64
    }
65
66
    public function cleanOldRateLimitData(): void
67
    {
68
        $threshold = time() - (7 * 24 * 60 * 60); // 7 days
69
        $this->db->table('rate_limit')
70
            ->where('last_attempt', '<', $threshold)
71
            ->delete();
72
    }
73
74
    private function getRateLimitRecord(string $ip)
75
    {
76
        return $this->db->table('rate_limit')
77
            ->where('ip_address', $ip)
78
            ->first();
79
    }
80
81
    private function isCurrentlyBlocked($record): bool
82
    {
83
        return !is_null($record->blocked_until) && $record->blocked_until > time();
84
    }
85
86
    private function shouldBlockIp($record): bool
87
    {
88
        return $record->attempt_count >= $this->maxAttempts &&
89
               (time() - $record->first_attempt) <= $this->limitDuration;
90
    }
91
92
    private function blockIp(string $ip): void
93
    {
94
        $this->db->table('rate_limit')
95
            ->where('ip_address', $ip)
96
            ->update(['blocked_until' => time() + $this->blockDuration]);
97
    }
98
}
99