{
"tool_response": {
"filePath": "\/tmp\/BotDetectionService-groupC.php",
"oldString": " \/**\n * UFW-Regel hinzufügen\n *\/\n private function addUfwRule(string $ip, string $reason): void\n {\n try {\n \/\/ Validiere IP-Format\n if (!filter_var($ip, FILTER_VALIDATE_IP)) {\n $this->logger->error(\"Invalid IP for UFW blocking: $ip\");\n return;\n }\n \n \/\/ Prüfe ob Regel bereits existiert\n $checkCmd = \"sudo ufw status numbered | grep '$ip'\";\n $output = shell_exec($checkCmd);\n \n if (!empty($output)) {\n $this->logger->info(\"UFW rule already exists for IP: $ip\");\n return;\n }\n \n \/\/ Füge UFW-Regel hinzu\n $blockDuration = $this->config['settings']['block_duration_minutes'];\n $comment = \"Bot blocked: $reason - \" . date('Y-m-d H:i:s');\n \n $ufwCmd = \"sudo ufw deny from $ip comment '$comment'\";\n $result = shell_exec($ufwCmd . ' 2>&1');\n \n $this->logger->info(\"UFW rule added for IP: $ip | Reason: $reason | Command: $ufwCmd\");\n \n \/\/ Schedule removal after block duration (via cron or background job)\n $this->scheduleUfwRuleRemoval($ip, $blockDuration);\n \n } catch (\\Exception $e) {\n $this->logger->error(\"Failed to add UFW rule for $ip: \" . $e->getMessage());\n }\n }\n \n \/**\n * UFW-Regel zeitgesteuerte Entfernung planen\n *\/\n private function scheduleUfwRuleRemoval(string $ip, int $minutes): void\n {\n $removeTime = time() + ($minutes * 60);\n $removalFile = $this->getConfigLoader()->get('paths.root') . '\/cache\/ufw_removals.json';\n \n $removals = [];\n if (file_exists($removalFile)) {\n $removals = json_decode(file_get_contents($removalFile), true) ?? [];\n }\n \n $removals[] = [\n 'ip' => $ip,\n 'remove_at' => $removeTime,\n 'added_at' => time()\n ];\n \n file_put_contents($removalFile, json_encode($removals, JSON_PRETTY_PRINT));\n }\n \n \/**\n * Hilfsfunktionen",
"newString": " \/**\n * Hilfsfunktionen",
"originalFile": "<?php\n\nnamespace App\\Services;\n\nuse SystemAdmin\\Helpers\\ConfigLoader;\nuse App\\Services\\Traits\\BotDetectionTrait;\nuse App\\Services\\Logger;\nuse App\\Services\\RateLimitingService;\n\n\/**\n * Bot Detection Service mit fail2ban\/nftables-Integration\n * Blockiert unerwünschte Bots basierend auf JSON-Konfiguration\n *\/\nclass BotDetectionService\n{\n use BotDetectionTrait;\n private array $config;\n private Logger $logger;\n private string $blockedIpsFile;\n private array $requestCounts = [];\n private RateLimitingService $rateLimiter;\n \n public function __construct()\n {\n $configLoader = ConfigLoader::getInstance();\n $configPath = $configLoader->get('paths.root') . '\/src\/Config\/bot-management.json';\n \n if (!file_exists($configPath)) {\n throw new \\Exception(\"Bot management config not found: $configPath\");\n }\n \n $this->config = json_decode(file_get_contents($configPath), true);\n if (json_last_error() !== JSON_ERROR_NONE) {\n throw new \\Exception(\"Invalid bot management config JSON: \" . json_last_error_msg());\n }\n \n $this->logger = new Logger();\n $this->blockedIpsFile = $configLoader->get('paths.root') . '\/cache\/blocked_ips.json';\n \n \/\/ Initialize advanced rate limiting\n $this->rateLimiter = new RateLimitingService($this->config['rate_limiting']);\n \n \/\/ Lade bestehende blockierte IPs\n $this->loadBlockedIps();\n }\n \n \/**\n * Hauptfunktion: Prüft ob Request blockiert werden soll\n *\/\n public function shouldBlockRequest(): bool\n {\n if (!$this->config['settings']['enabled']) {\n return $this->returnBotDetectionResult(false, 'service_disabled');\n }\n \n $clientIp = $this->getClientIp();\n $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';\n \n \/\/ 1. Whitelist-Prüfung (höchste Priorität)\n if ($this->isWhitelisted($clientIp, $userAgent)) {\n $this->logDetectionEvent('whitelist_match', $clientIp, $userAgent);\n return $this->returnBotDetectionResult(false, 'whitelisted');\n }\n \n \/\/ 2. Blacklist-Prüfung\n if ($this->isBlacklisted($clientIp, $userAgent)) {\n $this->blockRequest($clientIp, $userAgent, 'blacklist_match');\n return $this->returnBotDetectionResult(true, 'blacklisted');\n }\n \n \/\/ 3. Advanced Rate Limiting\n $isAuthenticated = $this->isUserAuthenticated();\n $rateLimitResult = $this->rateLimiter->isRateLimited($clientIp, $userAgent, $isAuthenticated);\n \n if ($rateLimitResult['limited']) {\n $this->handleRateLimitViolation($clientIp, $userAgent, $rateLimitResult);\n return $this->returnBotDetectionResult(true, 'rate_limited');\n }\n \n return $this->returnBotDetectionResult(false, 'allowed');\n }\n \n \/**\n * Whitelist-Prüfung\n *\/\n private function isWhitelisted(string $ip, string $userAgent): bool\n {\n $whitelist = $this->config['whitelist'];\n \n \/\/ Exakte User-Agent Matches\n if (in_array($userAgent, $whitelist['user_agents'] ?? [])) {\n return true;\n }\n \n \/\/ User-Agent Pattern Matches\n if ($this->checkUserAgentRegexPatterns($userAgent, $whitelist['user_agent_patterns'] ?? [])) {\n return true;\n }\n \n \/\/ IP-Ranges\n if ($this->checkIpInRanges($ip, $whitelist['ips'] ?? [])) {\n return true;\n }\n \n return $this->checkAndReturnResult(false);\n }\n \n \/**\n * Blacklist-Prüfung\n *\/\n private function isBlacklisted(string $ip, string $userAgent): bool\n {\n $blacklist = $this->config['blacklist'];\n \n \/\/ Exakte User-Agent Matches\n if (in_array($userAgent, $blacklist['exact_user_agents'] ?? [])) {\n return true;\n }\n \n \/\/ Einzelne User-Agent Keywords\n if ($this->checkUserAgentPattern($userAgent, $blacklist['user_agents'] ?? [])) {\n return true;\n }\n \n \/\/ User-Agent Pattern Matches\n if ($this->checkUserAgentRegexPatterns($userAgent, $blacklist['user_agent_patterns'] ?? [])) {\n return true;\n }\n \n \/\/ IP-Ranges\n if ($this->checkIpInRanges($ip, $blacklist['ips'] ?? [])) {\n return true;\n }\n \n return $this->checkAndReturnResult(false);\n }\n \n \/**\n * Prüft ob User authentifiziert ist\n *\/\n private function isUserAuthenticated(): bool\n {\n if (session_status() === PHP_SESSION_NONE) {\n session_start();\n }\n \n \/\/ Check verschiedene Session-Indikatoren\n return isset($_SESSION['admin_authenticated']) ||\n isset($_SESSION['user_authenticated']) ||\n isset($_SESSION['crm_contact_id']) ||\n !empty($_COOKIE['crm_session']);\n }\n \n \/**\n * Behandelt Rate Limit Verletzungen basierend auf Level\n *\/\n private function handleRateLimitViolation(string $ip, string $userAgent, array $rateLimitResult): void\n {\n $level = $rateLimitResult['level'];\n $action = $rateLimitResult['action'];\n $remainingSeconds = $rateLimitResult['remaining_seconds'] ?? 0;\n \n \/\/ Logging\n $this->logger->warning(\"Rate limit violation: $level | IP: $ip | Action: $action | Remaining: {$remainingSeconds}s\");\n \n switch ($action) {\n case 'log_warning':\n \/\/ Nur loggen, kein Blocking\n break;\n \n case 'temporary_delay':\n \/\/ 2-Sekunden Delay\n sleep(2);\n break;\n \n case 'temporary_block':\n \/\/ Temporärer Block mit HTTP Response\n $this->sendRateLimitResponse($remainingSeconds, $level);\n break;\n \n case 'block':\n $this->sendRateLimitResponse($remainingSeconds, $level);\n break;\n }\n }\n \n \/**\n * Sendet Rate Limit Response\n *\/\n private function sendRateLimitResponse(int $remainingSeconds, string $level): void\n {\n http_response_code(429); \/\/ Too Many Requests\n header('Retry-After: ' . $remainingSeconds);\n header('Content-Type: text\/plain');\n \n $message = \"Rate limit exceeded ($level). \";\n if ($remainingSeconds > 0) {\n $message .= \"Try again in $remainingSeconds seconds.\";\n } else {\n $message .= \"Please slow down your requests.\";\n }\n \n echo $message;\n exit;\n }\n \n \/**\n * Request blockieren\n *\/\n private function blockRequest(string $ip, string $userAgent, string $reason): void\n {\n \/\/ Logging\n if ($this->config['logging']['blocked_attempts']) {\n $this->logger->warning(\"Bot blocked: $reason | IP: $ip | UA: \" . substr($userAgent, 0, 100));\n }\n\n \/\/ IP zu blockierten IPs hinzufügen\n $this->addToBlockedIps($ip, $reason);\n \n \/\/ HTTP Response senden\n if ($this->config['actions']['return_403']) {\n http_response_code(403);\n header('Content-Type: text\/plain');\n echo \"Access denied. Automated traffic not permitted.\";\n exit;\n } elseif ($this->config['actions']['return_404']) {\n http_response_code(404);\n header('Content-Type: text\/plain');\n echo \"Not Found\";\n exit;\n }\n }\n \n \/**\n * UFW-Regel hinzufügen\n *\/\n private function addUfwRule(string $ip, string $reason): void\n {\n try {\n \/\/ Validiere IP-Format\n if (!filter_var($ip, FILTER_VALIDATE_IP)) {\n $this->logger->error(\"Invalid IP for UFW blocking: $ip\");\n return;\n }\n \n \/\/ Prüfe ob Regel bereits existiert\n $checkCmd = \"sudo ufw status numbered | grep '$ip'\";\n $output = shell_exec($checkCmd);\n \n if (!empty($output)) {\n $this->logger->info(\"UFW rule already exists for IP: $ip\");\n return;\n }\n \n \/\/ Füge UFW-Regel hinzu\n $blockDuration = $this->config['settings']['block_duration_minutes'];\n $comment = \"Bot blocked: $reason - \" . date('Y-m-d H:i:s');\n \n $ufwCmd = \"sudo ufw deny from $ip comment '$comment'\";\n $result = shell_exec($ufwCmd . ' 2>&1');\n \n $this->logger->info(\"UFW rule added for IP: $ip | Reason: $reason | Command: $ufwCmd\");\n \n \/\/ Schedule removal after block duration (via cron or background job)\n $this->scheduleUfwRuleRemoval($ip, $blockDuration);\n \n } catch (\\Exception $e) {\n $this->logger->error(\"Failed to add UFW rule for $ip: \" . $e->getMessage());\n }\n }\n \n \/**\n * UFW-Regel zeitgesteuerte Entfernung planen\n *\/\n private function scheduleUfwRuleRemoval(string $ip, int $minutes): void\n {\n $removeTime = time() + ($minutes * 60);\n $removalFile = $this->getConfigLoader()->get('paths.root') . '\/cache\/ufw_removals.json';\n \n $removals = [];\n if (file_exists($removalFile)) {\n $removals = json_decode(file_get_contents($removalFile), true) ?? [];\n }\n \n $removals[] = [\n 'ip' => $ip,\n 'remove_at' => $removeTime,\n 'added_at' => time()\n ];\n \n file_put_contents($removalFile, json_encode($removals, JSON_PRETTY_PRINT));\n }\n \n \/**\n * Hilfsfunktionen\n *\/\n private function getClientIp(): string\n {\n $headers = [\n 'HTTP_CF_CONNECTING_IP', \/\/ Cloudflare\n 'HTTP_X_FORWARDED_FOR', \/\/... [TRUNCATED-e41fca502509281c]",
"structuredPatch": [
{
"oldStart": 232,
"oldLines": 66,
"newStart": 232,
"newLines": 6,
"lines": [
" }",
" ",
" \/**",
"- * UFW-Regel hinzufügen",
"- *\/",
"- private function addUfwRule(string $ip, string $reason): void",
"- {",
"- try {",
"- \/\/ Validiere IP-Format",
"- if (!filter_var($ip, FILTER_VALIDATE_IP)) {",
"- $this->logger->error(\"Invalid IP for UFW blocking: $ip\");",
"- return;",
"- }",
"- ",
"- \/\/ Prüfe ob Regel bereits existiert",
"- $checkCmd = \"sudo ufw status numbered | grep '$ip'\";",
"- $output = shell_exec($checkCmd);",
"- ",
"- if (!empty($output)) {",
"- $this->logger->info(\"UFW rule already exists for IP: $ip\");",
"- return;",
"- }",
"- ",
"- \/\/ Füge UFW-Regel hinzu",
"- $blockDuration = $this->config['settings']['block_duration_minutes'];",
"- $comment = \"Bot blocked: $reason - \" . date('Y-m-d H:i:s');",
"- ",
"- $ufwCmd = \"sudo ufw deny from $ip comment '$comment'\";",
"- $result = shell_exec($ufwCmd . ' 2>&1');",
"- ",
"- $this->logger->info(\"UFW rule added for IP: $ip | Reason: $reason | Command: $ufwCmd\");",
"- ",
"- \/\/ Schedule removal after block duration (via cron or background job)",
"- $this->scheduleUfwRuleRemoval($ip, $blockDuration);",
"- ",
"- } catch (\\Exception $e) {",
"- $this->logger->error(\"Failed to add UFW rule for $ip: \" . $e->getMessage());",
"- }",
"- }",
"- ",
"- \/**",
"- * UFW-Regel zeitgesteuerte Entfernung planen",
"- *\/",
"- private function scheduleUfwRuleRemoval(string $ip, int $minutes): void",
"- {",
"- $removeTime = time() + ($minutes * 60);",
"- $removalFile = $this->getConfigLoader()->get('paths.root') . '\/cache\/ufw_removals.json';",
"- ",
"- $removals = [];",
"- if (file_exists($removalFile)) {",
"- $removals = json_decode(file_get_contents($removalFile), true) ?? [];",
"- }",
"- ",
"- $removals[] = [",
"- 'ip' => $ip,",
"- 'remove_at' => $removeTime,",
"- 'added_at' => time()",
"- ];",
"- ",
"- file_put_contents($removalFile, json_encode($removals, JSON_PRETTY_PRINT));",
"- }",
"- ",
"- \/**",
" * Hilfsfunktionen",
" *\/",
" private function getClientIp(): string"
]
}
],
"userModified": false,
"replaceAll": false
}
}