fix(proxmox): harden console sessions and firewall rollout safety
Reduce security and reliability risk across the Proxmox extension by removing password exposure from Livewire state, hardening console auth/cookie handling, and improving sanitized error paths. Improve firewall and router performance by adding safer lazy loading, bounded pagination, cross-server compatibility guards, and lower-overhead API workflows. Made-with: Cursor
This commit is contained in:
@@ -24,6 +24,13 @@ class Component extends BaseComponent
|
||||
*/
|
||||
public bool $fastPolling = false;
|
||||
|
||||
/**
|
||||
* Cached Proxmox storage content lookups keyed by storage name.
|
||||
*
|
||||
* @var array<string, array<int, array<string, mixed>>>
|
||||
*/
|
||||
protected array $storageContentCache = [];
|
||||
|
||||
/**
|
||||
* Mount the component with the server.
|
||||
*/
|
||||
@@ -71,7 +78,8 @@ class Component extends BaseComponent
|
||||
$this->fastPolling = true;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->notify('Action failed: ' . $e->getMessage(), 'error');
|
||||
report($e);
|
||||
$this->notify('Action failed. Please try again in a moment.', 'error');
|
||||
} finally {
|
||||
$this->loadVmStatus();
|
||||
}
|
||||
@@ -113,8 +121,8 @@ class Component extends BaseComponent
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
// If check fails, allow the action (fail open)
|
||||
return true;
|
||||
report($e);
|
||||
return 'Unable to validate storage quota at this time. Please try again in a moment.';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +147,13 @@ class Component extends BaseComponent
|
||||
}
|
||||
$totalSize += $this->extractDiskSize($value);
|
||||
}
|
||||
// LXC root filesystem and mount points
|
||||
elseif ($key === 'rootfs' || preg_match('/^mp(\d+)$/', $key)) {
|
||||
if ($this->isExcludedDisk($value)) {
|
||||
continue;
|
||||
}
|
||||
$totalSize += $this->extractDiskSize($value);
|
||||
}
|
||||
// Check for unused/detached drives
|
||||
elseif (preg_match('/^unused(\d+)$/', $key)) {
|
||||
if ($this->isExcludedDisk($value)) {
|
||||
@@ -215,9 +230,31 @@ class Component extends BaseComponent
|
||||
$volume = trim($value);
|
||||
|
||||
// Extract storage name from volume (format: storage:volume-name)
|
||||
$storageName = 'cephpool';
|
||||
if (str_contains($volume, ':')) {
|
||||
[$storageName, ] = explode(':', $volume, 2);
|
||||
$volumeParts = explode(':', $volume, 2);
|
||||
$storageName = trim($volumeParts[0] ?? '');
|
||||
if ($storageName === '') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$storageRows = $this->getStorageContentRows($storageName);
|
||||
foreach ($storageRows as $item) {
|
||||
if (isset($item['volid']) && $item['volid'] === $volume && isset($item['size'])) {
|
||||
return round(((float) $item['size']) / (1024 * 1024 * 1024), 2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and memoize storage contents for the active VM.
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
protected function getStorageContentRows(string $storageName): array
|
||||
{
|
||||
if (array_key_exists($storageName, $this->storageContentCache)) {
|
||||
return $this->storageContentCache[$storageName];
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -226,24 +263,13 @@ class Component extends BaseComponent
|
||||
'/nodes/' . $this->server->node->name . '/storage/' . $storageName . '/content',
|
||||
data: ['vmid' => $this->server->vm_id]
|
||||
);
|
||||
|
||||
$data = $storageContent->json()['data'] ?? [];
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $item) {
|
||||
if (isset($item['volid']) && $item['volid'] === $volume) {
|
||||
// Size is in bytes
|
||||
if (isset($item['size'])) {
|
||||
return round($item['size'] / (1024 * 1024 * 1024), 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$rows = $storageContent->json()['data'] ?? [];
|
||||
$this->storageContentCache[$storageName] = is_array($rows) ? $rows : [];
|
||||
} catch (\Throwable $e) {
|
||||
// If we can't fetch size, return 0
|
||||
$this->storageContentCache[$storageName] = [];
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return $this->storageContentCache[$storageName];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user