diff --git a/extensions/Servers/Proxmox/Livewire/Firewall.php b/extensions/Servers/Proxmox/Livewire/Firewall.php index 46699001a..562990ef4 100644 --- a/extensions/Servers/Proxmox/Livewire/Firewall.php +++ b/extensions/Servers/Proxmox/Livewire/Firewall.php @@ -795,7 +795,9 @@ class Firewall extends Component { $this->logError = ''; try { - // Try the firewall log endpoint - Proxmox returns logs as text/plain, not JSON + // Proxmox API: GET /api2/json/nodes/{node}/qemu/{vmid}/firewall/log + // Documentation: https://pve.proxmox.com/pve-docs/api-viewer/#/nodes/{node}/qemu/{vmid}/firewall/log + // Returns: text/plain format with log entries, one per line $response = $this->firewallRequest( '/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/firewall/log', 'get', @@ -803,12 +805,17 @@ class Firewall extends Component ); if (!$response->successful()) { - $errorData = $response->json(); + $errorData = []; + try { + $errorData = $response->json(); + } catch (\Exception $e) { + // Response might not be JSON + } $errorMsg = $errorData['message'] ?? 'HTTP ' . $response->status(); $this->logError = 'Failed to fetch logs: ' . $errorMsg; \Log::warning('Firewall log API request failed', [ 'status' => $response->status(), - 'body' => $response->body(), + 'body' => substr($response->body(), 0, 500), 'server_id' => $this->server->id, 'vm_id' => $this->server->vm_id ]); @@ -816,7 +823,8 @@ class Firewall extends Component return; } - // Proxmox firewall log endpoint returns plain text, not JSON + // Proxmox firewall log endpoint returns text/plain format + // Each log entry is on a new line $body = $response->body(); $rawLogs = []; @@ -828,50 +836,19 @@ class Firewall extends Component }); } - // If we got JSON instead, try to parse it - if (empty($rawLogs)) { - try { - $responseData = $response->json(); - if (isset($responseData['data']) && is_array($responseData['data'])) { - $rawLogs = $responseData['data']; - } elseif (is_array($responseData) && !isset($responseData['data'])) { - $rawLogs = $responseData; - } - } catch (\Exception $jsonError) { - // Not JSON, that's fine - we already tried plain text - } - } - - \Log::debug('Firewall logs fetched', [ + \Log::debug('Firewall logs fetched from Proxmox API', [ 'raw_count' => count($rawLogs), 'body_length' => strlen($body), 'content_type' => $response->header('Content-Type'), - 'sample' => !empty($rawLogs) ? (is_array($rawLogs[0]) ? json_encode($rawLogs[0]) : substr($rawLogs[0], 0, 200)) : null + 'sample' => !empty($rawLogs) ? substr($rawLogs[0], 0, 200) : null ]); $this->firewallLogs = []; - // Store raw log entries without parsing + // Store raw log entries exactly as received from Proxmox (no parsing/sanitization) foreach ($rawLogs as $logEntry) { if (is_string($logEntry)) { $logText = trim($logEntry); - if (!empty($logText)) { - $this->firewallLogs[] = ['raw' => $logText]; - } - } elseif (is_array($logEntry)) { - // If it's an array, try to get the log text - $logText = $logEntry['n'] ?? $logEntry['t'] ?? $logEntry['text'] ?? $logEntry['log'] ?? $logEntry['message'] ?? $logEntry['line'] ?? ''; - - if (empty($logText)) { - // Try to get the first string value - foreach ($logEntry as $key => $value) { - if (is_string($value) && !empty(trim($value))) { - $logText = trim($value); - break; - } - } - } - if (!empty($logText)) { $this->firewallLogs[] = ['raw' => $logText]; } @@ -883,16 +860,16 @@ class Firewall extends Component } elseif (empty($this->firewallLogs)) { $this->logError = 'No firewall logs available. Ensure firewall logging is enabled in Proxmox (Datacenter > Firewall > Options).'; } - - \Log::debug('Firewall logs parsed', [ - 'parsed_count' => count($this->firewallLogs) - ]); } catch (\Exception $e) { $errorMessage = $e->getMessage(); if (method_exists($e, 'response') && $e->response()) { - $errorData = $e->response()->json(); - if (isset($errorData['message'])) { - $errorMessage = $errorData['message']; + try { + $errorData = $e->response()->json(); + if (isset($errorData['message'])) { + $errorMessage = $errorData['message']; + } + } catch (\Exception $jsonError) { + // Response might not be JSON } } $this->logError = 'Error loading logs: ' . $errorMessage;