Compare commits
5 Commits
ee920d8e66
...
a076c28a30
Author | SHA1 | Date |
---|---|---|
|
a076c28a30 | |
|
f4c008c65f | |
|
13947e2099 | |
|
0a17b947d7 | |
|
528f4829af |
|
@ -86,7 +86,6 @@ class RateLimiter {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if IP is whitelisted
|
|
||||||
private function isIpWhitelisted($ip) {
|
private function isIpWhitelisted($ip) {
|
||||||
// Check exact IP match and CIDR ranges
|
// Check exact IP match and CIDR ranges
|
||||||
$stmt = $this->db->prepare("SELECT ip_address, is_network FROM {$this->whitelistTable}");
|
$stmt = $this->db->prepare("SELECT ip_address, is_network FROM {$this->whitelistTable}");
|
||||||
|
@ -107,6 +106,31 @@ class RateLimiter {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function isIpBlacklisted($ip) {
|
||||||
|
// First check if IP is explicitly blacklisted or in a blacklisted range
|
||||||
|
$stmt = $this->db->prepare("SELECT ip_address, is_network, expiry_time FROM {$this->blacklistTable}");
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
// Skip expired entries
|
||||||
|
if ($row['expiry_time'] !== null && strtotime($row['expiry_time']) < time()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($row['is_network']) {
|
||||||
|
if ($this->ipInRange($ip, $row['ip_address'])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($ip === $row['ip_address']) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private function ipInRange($ip, $cidr) {
|
private function ipInRange($ip, $cidr) {
|
||||||
list($subnet, $bits) = explode('/', $cidr);
|
list($subnet, $bits) = explode('/', $cidr);
|
||||||
|
|
||||||
|
@ -121,6 +145,15 @@ class RateLimiter {
|
||||||
// Add to whitelist
|
// Add to whitelist
|
||||||
public function addToWhitelist($ip, $isNetwork = false, $description = '', $createdBy = 'system', $userId = null) {
|
public function addToWhitelist($ip, $isNetwork = false, $description = '', $createdBy = 'system', $userId = null) {
|
||||||
try {
|
try {
|
||||||
|
// Check if IP is blacklisted first
|
||||||
|
if ($this->isIpBlacklisted($ip)) {
|
||||||
|
$message = "Cannot whitelist {$ip} - IP is currently blacklisted";
|
||||||
|
if ($userId) {
|
||||||
|
$this->log->insertLog($userId, "IP Whitelist: {$message}", 'system');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$stmt = $this->db->prepare("INSERT INTO {$this->whitelistTable}
|
$stmt = $this->db->prepare("INSERT INTO {$this->whitelistTable}
|
||||||
(ip_address, is_network, description, created_by)
|
(ip_address, is_network, description, created_by)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?, ?)
|
||||||
|
@ -186,6 +219,83 @@ class RateLimiter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addToBlacklist($ip, $isNetwork = false, $reason = '', $createdBy = 'system', $userId = null, $expiryHours = null) {
|
||||||
|
try {
|
||||||
|
// Check if IP is whitelisted first
|
||||||
|
if ($this->isIpWhitelisted($ip)) {
|
||||||
|
$message = "Cannot blacklist {$ip} - IP is currently whitelisted";
|
||||||
|
if ($userId) {
|
||||||
|
$this->log->insertLog($userId, "IP Blacklist: {$message}", 'system');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expiryTime = $expiryHours ? date('Y-m-d H:i:s', strtotime("+{$expiryHours} hours")) : null;
|
||||||
|
|
||||||
|
$stmt = $this->db->prepare("INSERT INTO {$this->blacklistTable}
|
||||||
|
(ip_address, is_network, reason, expiry_time, created_by)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
is_network = VALUES(is_network),
|
||||||
|
reason = VALUES(reason),
|
||||||
|
expiry_time = VALUES(expiry_time),
|
||||||
|
created_by = VALUES(created_by)");
|
||||||
|
|
||||||
|
$result = $stmt->execute([$ip, $isNetwork, $reason, $expiryTime, $createdBy]);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$logMessage = sprintf(
|
||||||
|
'IP Blacklist: Added %s "%s" by %s. Reason: %s. Expires: %s',
|
||||||
|
$isNetwork ? 'network' : 'IP',
|
||||||
|
$ip,
|
||||||
|
$createdBy,
|
||||||
|
$reason,
|
||||||
|
$expiryTime ?? 'never'
|
||||||
|
);
|
||||||
|
$this->log->insertLog($userId ?? 0, $logMessage, 'system');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if ($userId) {
|
||||||
|
$this->log->insertLog($userId, "IP Blacklist: Failed to add {$ip}: " . $e->getMessage(), 'system');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeFromBlacklist($ip, $userId = null, $removedBy = 'system') {
|
||||||
|
try {
|
||||||
|
// Get IP details before removal for logging
|
||||||
|
$stmt = $this->db->prepare("SELECT * FROM {$this->blacklistTable} WHERE ip_address = ?");
|
||||||
|
$stmt->execute([$ip]);
|
||||||
|
$ipDetails = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Remove the IP
|
||||||
|
$stmt = $this->db->prepare("DELETE FROM {$this->blacklistTable} WHERE ip_address = ?");
|
||||||
|
$result = $stmt->execute([$ip]);
|
||||||
|
|
||||||
|
if ($result && $ipDetails) {
|
||||||
|
$logMessage = sprintf(
|
||||||
|
'IP Blacklist: Removed %s "%s" by %s. Was added by: %s. Reason was: %s',
|
||||||
|
$ipDetails['is_network'] ? 'network' : 'IP',
|
||||||
|
$ip,
|
||||||
|
$removedBy,
|
||||||
|
$ipDetails['created_by'],
|
||||||
|
$ipDetails['reason']
|
||||||
|
);
|
||||||
|
$this->log->insertLog($userId ?? 0, $logMessage, 'system');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if ($userId) {
|
||||||
|
$this->log->insertLog($userId, "IP Blacklist: Failed to remove {$ip}: " . $e->getMessage(), 'system');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getWhitelistedIps() {
|
public function getWhitelistedIps() {
|
||||||
$stmt = $this->db->prepare("SELECT * FROM {$this->whitelistTable} ORDER BY created_at DESC");
|
$stmt = $this->db->prepare("SELECT * FROM {$this->whitelistTable} ORDER BY created_at DESC");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
@ -193,6 +303,32 @@ class RateLimiter {
|
||||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBlacklistedIps() {
|
||||||
|
$stmt = $this->db->prepare("SELECT * FROM {$this->blacklistTable} ORDER BY created_at DESC");
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cleanupExpiredEntries() {
|
||||||
|
try {
|
||||||
|
// Remove expired blacklist entries
|
||||||
|
$stmt = $this->db->prepare("DELETE FROM {$this->blacklistTable}
|
||||||
|
WHERE expiry_time IS NOT NULL AND expiry_time < NOW()");
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
// Clean old login attempts
|
||||||
|
$stmt = $this->db->prepare("DELETE FROM {$this->tableName}
|
||||||
|
WHERE attempted_at < DATE_SUB(NOW(), INTERVAL ? MINUTE)");
|
||||||
|
$stmt->execute([$this->decayMinutes]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->log->insertLog(0, "Failed to cleanup expired entries: " . $e->getMessage(), 'system');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function attempt($username, $ipAddress) {
|
public function attempt($username, $ipAddress) {
|
||||||
// Skip rate limiting for whitelisted IPs
|
// Skip rate limiting for whitelisted IPs
|
||||||
if ($this->isIpWhitelisted($ipAddress)) {
|
if ($this->isIpWhitelisted($ipAddress)) {
|
||||||
|
|
Loading…
Reference in New Issue