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 .= '' . AppContext::e($dbName) . ' ';
}
$roleOptions = '-- wybierz użytkownika -- ';
foreach ($roleNames as $roleName) {
$sel = ($roleName === $selectedRole) ? ' selected' : '';
$roleOptions .= '' . AppContext::e($roleName) . ' ';
}
$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 .= ' usuń ';
$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 .= '';
$ctx->renderPage('Hosty Zdalne Użytkownika', $body, $ok, $errors);
};