settings->allowRemoteHosts()) { $ctx->renderFatal('Zarządzanie hostami zdalnymi jest wyłączone (`allow_remote_hosts=0`).', 403); return; } $ok = []; $errors = []; $lastSyncOutput = ''; $daUser = $ctx->daUser->username(); $prefix = $ctx->daUser->prefix(); $postgresPort = $ctx->pg->serverPort(); $dbNames = array_map(static fn(array $db): string => $db['name'], $ctx->pg->listDatabasesForUser($daUser)); if (empty($dbNames)) { $ctx->renderPage('Hosty Zdalne Użytkownika', '

Brak baz danych do zarządzania hostami.

', $ok, $errors); return; } $selectedDb = $ctx->postString('db_name'); if ($selectedDb === '') { $selectedDb = $ctx->queryString('db'); } if ($selectedDb === '') { $selectedDb = $dbNames[0]; } try { $selectedDb = NamePolicy::normalizeDatabaseName($selectedDb, $prefix); } catch (Throwable $e) { $selectedDb = $dbNames[0]; } if (!in_array($selectedDb, $dbNames, true)) { $selectedDb = $dbNames[0]; } $roleNames = $ctx->pg->listDatabaseUsers($daUser, $selectedDb); $selectedRole = $ctx->queryString('role'); if ($ctx->isPost()) { $selectedRole = $ctx->postString('role_name'); try { $ctx->requireCsrf('manage_hosts_submit'); $selectedDb = NamePolicy::normalizeDatabaseName($ctx->postString('db_name', $selectedDb), $prefix); if (!in_array($selectedDb, $dbNames, true)) { throw new RuntimeException('Baza nie należy do konta DA: ' . $selectedDb); } $roleNames = $ctx->pg->listDatabaseUsers($daUser, $selectedDb); $selectedRole = NamePolicy::normalizeRoleName($selectedRole, $prefix); if (!in_array($selectedRole, $roleNames, true)) { throw new RuntimeException('Użytkownik PostgreSQL nie ma dostępu do wybranej bazy: ' . $selectedRole); } $currentEntries = $ctx->pg->getRoleHostEntries($daUser, $selectedRole, $selectedDb); $hostMap = []; foreach ($currentEntries as $entry) { $hostMap[$entry['host']] = $entry['note']; } $removeHosts = $ctx->postArray('remove_hosts'); $removeHosts = array_values(array_unique($removeHosts)); foreach ($removeHosts as $rawHost) { $host = trim($rawHost); if ($host === '') { continue; } if (array_key_exists($host, $hostMap)) { unset($hostMap[$host]); } } $addHostRaw = trim($ctx->postString('add_host')); if ($addHostRaw !== '') { $addHost = NamePolicy::normalizeRemoteIpv4AccessPattern($addHostRaw); $addComment = NamePolicy::normalizeHostComment($ctx->postString('add_comment')); $hostMap[$addHost] = $addComment; } $allowAllHosts = $ctx->postString('allow_all_hosts') === '1'; if ($allowAllHosts) { $allHostsComment = NamePolicy::normalizeHostComment($ctx->postString('allow_all_comment')); $hostMap[NamePolicy::ALL_IPV4_HOST_PATTERN] = $allHostsComment !== '' ? $allHostsComment : 'Dostęp z każdego adresu IPv4'; } else { unset($hostMap[NamePolicy::ALL_IPV4_HOST_PATTERN]); } if (count($hostMap) > $ctx->settings->maxHostsPerUser()) { throw new RuntimeException('Przekroczono limit hostów dla wybranej bazy i użytkownika PostgreSQL.'); } $finalEntries = []; foreach ($hostMap as $host => $note) { $finalEntries[] = ['host' => $host, 'note' => $note]; } $ctx->pg->replaceRoleHostsWithNotes($daUser, $selectedRole, $finalEntries, $selectedDb); $restartPostgresql = $ctx->postString('restart_postgresql') === '1'; $sync = $ctx->pg->syncHbaRules($restartPostgresql); $lastSyncOutput = trim((string)($sync['output'] ?? '')); if (!$sync['ok']) { $errors[] = 'Hosty zapisane, ale synchronizacja konfiguracji hostów zdalnych nie powiodła się: ' . $sync['output']; } elseif ($restartPostgresql) { $ok[] = 'Synchronizacja konfiguracji PostgreSQL zakończona i usługa PostgreSQL została zrestartowana.'; } elseif (array_key_exists(NamePolicy::ALL_IPV4_HOST_PATTERN, $hostMap)) { $ok[] = 'Synchronizacja PostgreSQL zakończona. Dla dostępu z każdego hosta port PostgreSQL do otwarcia w CSF: ' . $postgresPort . '.'; } else { $ok[] = 'Synchronizacja konfiguracji PostgreSQL i CSF zakończona.'; } $ok[] = 'Zaktualizowano hosty dostępu dla użytkownika ' . $selectedRole . '.'; } catch (Throwable $e) { $errors[] = $e->getMessage(); } } $roleNames = $ctx->pg->listDatabaseUsers($daUser, $selectedDb); if ($selectedRole !== '') { try { $selectedRole = NamePolicy::normalizeRoleName($selectedRole, $prefix); } catch (Throwable $e) { $selectedRole = ''; } } if ($selectedRole === '' && !empty($roleNames)) { $selectedRole = $roleNames[0]; } $currentEntries = []; if ($selectedRole !== '') { $currentEntries = $ctx->pg->getRoleHostEntries($daUser, $selectedRole, $selectedDb); } $allHostsEnabled = false; $allHostsComment = ''; foreach ($currentEntries as $entry) { if ($entry['host'] === NamePolicy::ALL_IPV4_HOST_PATTERN) { $allHostsEnabled = true; $allHostsComment = $entry['note']; break; } } $dbOptions = ''; foreach ($dbNames as $dbName) { $sel = ($dbName === $selectedDb) ? ' selected' : ''; $dbOptions .= ''; } $roleOptions = ''; foreach ($roleNames as $roleName) { $sel = ($roleName === $selectedRole) ? ' selected' : ''; $roleOptions .= ''; } $hostRows = ''; if (empty($currentEntries)) { $hostRows = 'Brak zapisanych hostów.'; } else { foreach ($currentEntries as $entry) { $host = $entry['host']; $note = $entry['note']; $hostRows .= ''; $hostRows .= '' . AppContext::e($host) . ''; $hostRows .= '' . AppContext::e($note) . ''; $hostRows .= ''; $hostRows .= ''; } } $body = ''; if ($allHostsEnabled) { $body .= '
'; $body .= 'Uwaga: dla bazy ' . AppContext::e($selectedDb) . ' i użytkownika ' . AppContext::e($selectedRole) . ' włączono dostęp z każdego adresu IPv4. Plugin nie otwiera portu PostgreSQL w CSF dla tego trybu. Port PostgreSQL do otwarcia w CSF: ' . AppContext::e((string)$postgresPort) . '.'; $body .= '
'; } $body .= '
'; $body .= '

Status konfiguracji hostów zdalnych

'; $body .= '

Hosty zdalne są włączone przez allow_remote_hosts=1. Zapis hostów uruchamia synchronizację pg_hba, postgresql.conf oraz CSF.

'; if ($lastSyncOutput !== '') { $body .= '

Ostatni wynik synchronizacji:

'; $body .= '
' . AppContext::e($lastSyncOutput) . '
'; } else { $body .= '

Ostatni wynik synchronizacji będzie widoczny po zapisaniu zmian hostów.

'; } $body .= '
'; $body .= '
'; $body .= $ctx->csrfField('manage_hosts_submit'); $body .= '
'; $body .= '
'; $body .= '
'; $body .= '
'; $body .= '
'; $body .= '
'; $body .= '
'; $body .= '
'; $body .= '
'; $body .= '
'; $body .= ''; $body .= ''; $body .= '
'; $body .= '

Ta opcja dotyczy tylko wybranej bazy i użytkownika. Plugin skonfiguruje PostgreSQL, ale nie otworzy portu PostgreSQL w CSF. Port PostgreSQL do otwarcia w CSF: ' . AppContext::e((string)$postgresPort) . '.

'; $body .= ''; $body .= '
'; $body .= '

Aktualne hosty dla wybranej bazy

'; $body .= '' . $hostRows . '
Host/CIDRKomentarzAkcja
'; $body .= '
'; $body .= '
'; $body .= '
'; $ctx->renderPage('Hosty Zdalne Użytkownika', $body, $ok, $errors); };