Import postgresql plugin

This commit is contained in:
Marek Miklewicz
2026-07-04 16:00:04 +02:00
commit ddc971567f
74 changed files with 18735 additions and 0 deletions
+704
View File
@@ -0,0 +1,704 @@
#!/bin/bash
# =============================================================================
# adminer_install.sh
# Instalacja i integracja Adminera z pluginem da-postgresql (DirectAdmin)
#
# Założenia bezpieczeństwa:
# - Adminer dostępny przez alias /adminer
# - Tryb public/private odczytywany runtime z /var/www/html/adminer/runtime/config.json
# - Tryb publiczny (ADMINER_PUBLIC=true) pozwala na ręczne logowanie do PostgreSQL
# - Tryb prywatny (ADMINER_PUBLIC=false) wymaga ticketu SSO z pluginu
# - Ticket SSO ma krótki TTL i jest przypięty do User-Agent
# - Logowanie odbywa się tymczasową rolą PostgreSQL tworzoną przez plugin
# =============================================================================
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
sekcja() { echo -e "\n${BOLD}${CYAN}=== $* ===${NC}\n"; }
die() { echo -e "${RED}[BŁĄD]${NC} $*" >&2; exit 1; }
[[ $EUID -eq 0 ]] || die "Skrypt musi być uruchomiony jako root."
LOGFILE="/var/log/adminer_install_$(date +%Y%m%d_%H%M%S).log"
exec 1> >(tee >(sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' >> "$LOGFILE")) 2>&1
info "Pełny log zapisany w: $LOGFILE"
ADMINER_URL_PATH="/adminer"
ADMINER_VERSION="5.4.2"
ADMINER_FLAVOR="pgsql"
ADMINER_INSTALL_DIR="/var/www/html/adminer"
ADMINER_RUNTIME_DIR="${ADMINER_INSTALL_DIR}/runtime"
ADMINER_TICKETS_DIR="${ADMINER_RUNTIME_DIR}/tickets"
ADMINER_RUNTIME_CONFIG_FILE="${ADMINER_RUNTIME_DIR}/config.json"
ADMINER_CORE_FILE="${ADMINER_INSTALL_DIR}/adminer-core.php"
ADMINER_EXTENSION_FILE="${ADMINER_INSTALL_DIR}/adminer-extension.php"
ADMINER_INDEX_FILE="${ADMINER_INSTALL_DIR}/index.php"
PLUGIN_BUNDLED_ADMINER="/usr/local/directadmin/plugins/da-postgresql/assets/adminer/adminer-${ADMINER_VERSION}-${ADMINER_FLAVOR}.php"
PLUGIN_BUNDLED_ADMINER_SHA256="059505abc2b56487d78bbfbeb9485ed8c6a10fe357f4ddec9fc69b1043bff4af"
PLUGIN_BUNDLED_EXTENSION="/usr/local/directadmin/plugins/da-postgresql/assets/adminer/adminer-extension.php"
PLUGIN_BUNDLED_EXTENSION_SHA256="6e2f098b172838ccb3736506867396dc0954a6383fdd7b7c5e7739ab21baafeb"
CB_DIR="/usr/local/directadmin/custombuild"
CB_BUILD="${CB_DIR}/build"
APACHE_ALIAS_CUSTOM="${CB_DIR}/custom/ap2/conf/extra/httpd-alias.conf"
APACHE_ALIAS_SOURCE="/etc/httpd/conf/extra/httpd-alias.conf"
APACHE_ALIAS_CONFIGURE="${CB_DIR}/configure/ap2/conf/extra/httpd-alias.conf"
PLUGIN_SETTINGS="/usr/local/directadmin/plugins/da-postgresql/plugin-settings.conf"
PLUGIN_OWNER="diradmin:diradmin"
ADMINER_PUBLIC_DEFAULT="false"
ADMINER_PUBLIC_MODE="0"
detect_apache_group() {
local group_name=""
if [[ -f /etc/httpd/conf/httpd.conf ]]; then
group_name="$(awk 'tolower($1)=="group" {print $2; exit}' /etc/httpd/conf/httpd.conf | tr -d '[:space:]')"
fi
if [[ -z "$group_name" && -f /etc/apache2/apache2.conf ]]; then
group_name="$(awk 'tolower($1)=="group" {print $2; exit}' /etc/apache2/apache2.conf | tr -d '[:space:]')"
fi
if [[ -z "$group_name" ]]; then
for candidate in apache www-data nobody; do
if getent group "$candidate" >/dev/null 2>&1; then
group_name="$candidate"
break
fi
done
fi
[[ -n "$group_name" ]] || die "Nie można wykryć grupy użytkownika Apache."
echo "$group_name"
}
set_setting() {
local key="$1"
local value="$2"
local file="$3"
[[ -f "$file" ]] || return 0
sed -i "/^${key}=/d" "$file" || true
echo "${key}=${value}" >> "$file"
}
set_setting_if_missing() {
local key="$1"
local value="$2"
local file="$3"
[[ -f "$file" ]] || return 0
if grep -q "^${key}=" "$file"; then
return 0
fi
echo "${key}=${value}" >> "$file"
}
bool_is_true() {
local v
v="$(echo "${1:-}" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')"
case "$v" in
1|true|yes|y|on|tak|t) return 0 ;;
*) return 1 ;;
esac
}
read_adminer_public_mode() {
local raw="$ADMINER_PUBLIC_DEFAULT"
if [[ -f "$PLUGIN_SETTINGS" ]]; then
local found
found="$(awk -F= '/^ADMINER_PUBLIC=/{print $2; exit}' "$PLUGIN_SETTINGS" | tr -d '[:space:]')"
if [[ -n "$found" ]]; then
raw="$found"
fi
fi
if bool_is_true "$raw"; then
ADMINER_PUBLIC_MODE="1"
else
ADMINER_PUBLIC_MODE="0"
fi
}
write_runtime_public_config() {
local public_json="false"
if [[ "$ADMINER_PUBLIC_MODE" == "1" ]]; then
public_json="true"
fi
cat > "$ADMINER_RUNTIME_CONFIG_FILE" <<EOF
{"version":1,"adminer_public":${public_json},"updated_at":$(date +%s)}
EOF
}
sha256_file() {
local path="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$path" | awk '{print $1}'
return 0
fi
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$path" | awk '{print $1}'
return 0
fi
if command -v openssl >/dev/null 2>&1; then
openssl dgst -sha256 "$path" | awk '{print $NF}'
return 0
fi
return 1
}
render_adminer_wrapper() {
cat > "$ADMINER_INDEX_FILE" <<'PHPEOF'
<?php
declare(strict_types=1);
const DA_ADMINER_RUNTIME_DIR = '/var/www/html/adminer/runtime';
const DA_ADMINER_TICKETS_DIR = DA_ADMINER_RUNTIME_DIR . '/tickets';
const DA_ADMINER_CONFIG_FILE = DA_ADMINER_RUNTIME_DIR . '/config.json';
const DA_ADMINER_CORE_FILE = __DIR__ . '/adminer-core.php';
const DA_ADMINER_EXTENSION_FILE = __DIR__ . '/adminer-extension.php';
const DA_ADMINER_SESSION_KEY = 'da_adminer_auth';
const DA_ADMINER_SESSION_NAME = 'DA_POSTGRESQL_ADMINER';
const DA_ADMINER_PUBLIC_DEFAULT = __ADMINER_PUBLIC_MODE__;
header('X-Frame-Options: SAMEORIGIN');
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: no-referrer');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
session_name(DA_ADMINER_SESSION_NAME);
session_set_cookie_params([
'lifetime' => 0,
'path' => '/adminer',
'secure' => (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'),
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
$now = time();
$adminerPublic = load_public_mode();
if (isset($_GET['logout'])) {
clear_session();
if (!$adminerPublic) {
render_placeholder('Sesja Adminera zostala zamknieta. Otworz Adminera ponownie z panelu DirectAdmin.');
}
}
$auth = null;
$ticketId = ticket_id_from_request();
if ($ticketId !== '') {
$ticketAccepted = false;
$ticketRejectReason = '';
$ticketBinding = '';
$ticket = load_ticket($ticketId);
if ($ticket !== null) {
$ticketBinding = isset($ticket['user_binding']) && is_string($ticket['user_binding']) ? $ticket['user_binding'] : '';
}
if ($ticket === null) {
$ticketRejectReason = 'ticket_missing_or_unreadable';
} elseif (validate_ticket($ticket, $now, $adminerPublic, $ticketRejectReason)) {
$auth = [
'host' => 'localhost',
'port' => (int)($ticket['port'] ?? 5432),
'user' => (string)($ticket['role'] ?? ''),
'password' => (string)($ticket['password'] ?? ''),
'database' => (string)($ticket['database'] ?? ''),
'expires_at' => (int)($ticket['session_expires_at'] ?? ($now + 900)),
];
$_SESSION[DA_ADMINER_SESSION_KEY] = $auth;
@unlink(ticket_path($ticketId));
clear_ticket_from_request();
$ticketAccepted = true;
}
debug_ticket_event($ticketId, $ticketAccepted, $ticketRejectReason, $ticketBinding, current_user_binding());
if (!$ticketAccepted && !$adminerPublic) {
render_placeholder('Nieprawidlowy lub wygasly link logowania. Otworz Adminera z poziomu pluginu.');
}
}
if ($auth === null) {
$auth = $_SESSION[DA_ADMINER_SESSION_KEY] ?? null;
}
if (!is_array($auth) || empty($auth['user']) || empty($auth['password'])) {
$auth = null;
if (!$adminerPublic) {
render_placeholder();
}
}
if ($auth !== null) {
$expiresAt = (int)($auth['expires_at'] ?? 0);
if ($expiresAt <= 0 || $expiresAt < $now) {
clear_session();
$auth = null;
if (!$adminerPublic) {
render_placeholder('Sesja Adminera wygasla. Otworz Adminera ponownie z poziomu pluginu.');
}
}
}
if (has_forbidden_driver_params()) {
clear_session();
http_response_code(403);
render_placeholder('Dozwolony jest tylko sterownik PostgreSQL.');
}
$_GET['pgsql'] = 'localhost';
if ($auth !== null) {
bootstrap_adminer_session($auth);
unset($_POST['auth']);
} else {
normalize_post_auth();
}
$GLOBALS['da_adminer_sso_auth'] = $auth;
require DA_ADMINER_EXTENSION_FILE;
require DA_ADMINER_CORE_FILE;
exit;
function ticket_id_from_request(): string
{
$ticket = $_GET['ticket'] ?? '';
if (!is_string($ticket)) {
return '';
}
$ticket = trim($ticket);
if ($ticket === '' || !preg_match('/^[A-Za-z0-9_-]{20,128}$/', $ticket)) {
return '';
}
return $ticket;
}
function ticket_path(string $ticketId): string
{
return DA_ADMINER_TICKETS_DIR . '/' . $ticketId . '.json';
}
function clear_ticket_from_request(): void
{
unset($_GET['ticket']);
$uri = $_SERVER['REQUEST_URI'] ?? '';
if (!is_string($uri) || $uri === '') {
return;
}
$parts = parse_url($uri);
if (!is_array($parts)) {
return;
}
$path = isset($parts['path']) && is_string($parts['path']) ? $parts['path'] : '/adminer';
$query = [];
if (isset($parts['query']) && is_string($parts['query']) && $parts['query'] !== '') {
parse_str($parts['query'], $query);
if (is_array($query)) {
unset($query['ticket']);
} else {
$query = [];
}
}
$newQuery = http_build_query($query);
$_SERVER['REQUEST_URI'] = $path . ($newQuery !== '' ? ('?' . $newQuery) : '');
}
function load_ticket(string $ticketId): ?array
{
$path = ticket_path($ticketId);
if (!is_file($path) || !is_readable($path)) {
return null;
}
$raw = @file_get_contents($path);
if (!is_string($raw) || $raw === '') {
return null;
}
$decoded = json_decode($raw, true);
return is_array($decoded) ? $decoded : null;
}
function load_public_mode(): bool
{
$default = (DA_ADMINER_PUBLIC_DEFAULT === 1);
if (!is_file(DA_ADMINER_CONFIG_FILE) || !is_readable(DA_ADMINER_CONFIG_FILE)) {
return $default;
}
$raw = @file_get_contents(DA_ADMINER_CONFIG_FILE);
if (!is_string($raw) || $raw === '') {
return $default;
}
$decoded = json_decode($raw, true);
if (!is_array($decoded) || !array_key_exists('adminer_public', $decoded)) {
return $default;
}
return parse_bool_value($decoded['adminer_public'], $default);
}
function parse_bool_value($value, bool $default = false): bool
{
if (is_bool($value)) {
return $value;
}
if (is_int($value) || is_float($value)) {
return ((int)$value) !== 0;
}
if (!is_string($value)) {
return $default;
}
$normalized = strtolower(trim($value));
if (in_array($normalized, ['1', 'true', 'yes', 'y', 'on', 'tak', 't'], true)) {
return true;
}
if (in_array($normalized, ['0', 'false', 'no', 'n', 'off', 'nie'], true)) {
return false;
}
return $default;
}
function validate_ticket(array $ticket, int $now, bool $adminerPublic, string &$reason = ''): bool
{
$required = ['role', 'password', 'database', 'host', 'port', 'expires_at', 'session_expires_at', 'user_binding'];
foreach ($required as $key) {
if (!array_key_exists($key, $ticket)) {
$reason = 'missing_key:' . $key;
return false;
}
}
$expiresAt = is_numeric($ticket['expires_at']) ? (int)$ticket['expires_at'] : 0;
if ($expiresAt < $now) {
$reason = 'ticket_expired';
return false;
}
$sessionExpiresAt = is_numeric($ticket['session_expires_at']) ? (int)$ticket['session_expires_at'] : 0;
if ($sessionExpiresAt < $now) {
$reason = 'session_expired';
return false;
}
$role = (string)$ticket['role'];
if ($role === '' || !preg_match('/^[a-z0-9_]{1,63}$/', $role)) {
$reason = 'invalid_role';
return false;
}
$binding = (string)$ticket['user_binding'];
if (!is_binding_valid($binding, current_user_binding(), $adminerPublic)) {
$reason = 'binding_mismatch';
return false;
}
$reason = 'ok';
return true;
}
function current_user_binding(): string
{
$ua = (string)($_SERVER['HTTP_USER_AGENT'] ?? '');
return hash('sha256', $ua);
}
function is_binding_valid(string $ticketBinding, string $currentBinding, bool $adminerPublic): bool
{
if ($adminerPublic) {
return true;
}
if ($ticketBinding === '') {
return false;
}
if (hash_equals($ticketBinding, $currentBinding)) {
return true;
}
// Kompatybilność: starsze ticket-y mogły być wystawione bez HTTP_USER_AGENT po stronie DA.
$legacyNoUaBinding = hash('sha256', '');
if (hash_equals($ticketBinding, $legacyNoUaBinding)) {
return true;
}
return false;
}
function debug_ticket_event(
string $ticketId,
bool $accepted,
string $reason,
string $ticketBinding,
string $currentBinding
): void {
$line = sprintf(
"[%s] ticket=%s accepted=%s reason=%s ticket_binding=%s current_binding=%s remote=%s ua=%s\n",
date('c'),
$ticketId,
$accepted ? '1' : '0',
$reason !== '' ? $reason : 'n/a',
$ticketBinding !== '' ? $ticketBinding : '-',
$currentBinding !== '' ? $currentBinding : '-',
(string)($_SERVER['REMOTE_ADDR'] ?? '-'),
(string)($_SERVER['HTTP_USER_AGENT'] ?? '-')
);
@error_log($line, 3, '/tmp/da_adminer_wrapper_debug.log');
}
function has_forbidden_driver_params(): bool
{
$forbidden = ['server', 'sqlite', 'mongo', 'mssql', 'oracle', 'elastic', 'clickhouse'];
foreach ($forbidden as $key) {
if (isset($_GET[$key])) {
return true;
}
}
return false;
}
function bootstrap_adminer_session(array $auth): void
{
$driver = 'pgsql';
$server = 'localhost';
$user = trim((string)($auth['user'] ?? ''));
$password = (string)($auth['password'] ?? '');
$database = trim((string)($auth['database'] ?? ''));
if ($user === '' || $password === '') {
return;
}
$_GET[$driver] = $server;
$_GET['username'] = $user;
if ($database !== '' && (!isset($_GET['db']) || !is_string($_GET['db']) || $_GET['db'] === '')) {
$_GET['db'] = $database;
}
$_SESSION['pwds'][$driver][$server][$user] = $password;
if ($database !== '') {
$_SESSION['db'][$driver][$server][$user][$database] = true;
}
}
function normalize_post_auth(): void
{
if (!isset($_POST['auth']) || !is_array($_POST['auth'])) {
return;
}
$_POST['auth']['driver'] = 'pgsql';
$_POST['auth']['server'] = 'localhost';
}
function clear_session(): void
{
$_SESSION = [];
if (session_status() === PHP_SESSION_ACTIVE) {
session_unset();
session_destroy();
}
}
function render_placeholder(string $extra = ''): void
{
http_response_code(200);
$message = 'Dostep do Adminera jest mozliwy wylacznie z poziomu panelu DirectAdmin.';
echo '<!doctype html><html lang="pl"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">';
echo '<title>Adminer - DirectAdmin</title>';
echo '<style>body{margin:0;background:#f5f7fb;color:#1f2937;font:16px/1.5 -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}';
echo '.wrap{max-width:760px;margin:10vh auto;padding:24px}';
echo '.card{background:#fff;border:1px solid #d7dfeb;border-radius:12px;padding:26px;box-shadow:0 6px 22px rgba(18,38,63,.08)}';
echo 'h1{margin:0 0 12px;font-size:24px}p{margin:0 0 10px}.muted{color:#52607a;font-size:14px}</style></head><body>';
echo '<div class="wrap"><div class="card"><h1>Adminer</h1><p>' . htmlspecialchars($message, ENT_QUOTES, 'UTF-8') . '</p>';
if ($extra !== '') {
echo '<p class="muted">' . htmlspecialchars($extra, ENT_QUOTES, 'UTF-8') . '</p>';
}
echo '<p class="muted">W panelu pluginu PostgreSQL kliknij przycisk "Adminer", aby otworzyc sesje SSO.</p></div></div></body></html>';
exit;
}
PHPEOF
sed -i "s/__ADMINER_PUBLIC_MODE__/${ADMINER_PUBLIC_MODE}/g" "$ADMINER_INDEX_FILE"
}
configure_apache_alias() {
[[ -d "$CB_DIR" ]] || die "Brak katalogu CustomBuild: ${CB_DIR}"
mkdir -p "$(dirname "$APACHE_ALIAS_CUSTOM")"
if [[ ! -f "$APACHE_ALIAS_CUSTOM" ]]; then
if [[ -f "$APACHE_ALIAS_SOURCE" ]]; then
cp -p "$APACHE_ALIAS_SOURCE" "$APACHE_ALIAS_CUSTOM"
elif [[ -f "$APACHE_ALIAS_CONFIGURE" ]]; then
cp -p "$APACHE_ALIAS_CONFIGURE" "$APACHE_ALIAS_CUSTOM"
else
warn "Nie znaleziono źródłowego httpd-alias.conf tworzę pusty custom template."
: > "$APACHE_ALIAS_CUSTOM"
fi
fi
local tmp_file
tmp_file="$(mktemp)"
awk '
BEGIN { skip = 0 }
/^# BEGIN DA_POSTGRESQL_ADMINER$/ { skip = 1; next }
/^# END DA_POSTGRESQL_ADMINER$/ { skip = 0; next }
skip == 0 { print }
' "$APACHE_ALIAS_CUSTOM" > "$tmp_file"
cat >> "$tmp_file" <<EOF
# BEGIN DA_POSTGRESQL_ADMINER
Alias ${ADMINER_URL_PATH} ${ADMINER_INSTALL_DIR}/index.php
Alias ${ADMINER_URL_PATH}/ ${ADMINER_INSTALL_DIR}/index.php
<Directory "${ADMINER_INSTALL_DIR}">
AllowOverride None
Options -Indexes
Require all granted
<FilesMatch "^adminer-(core|extension)\.php$">
Require all denied
</FilesMatch>
</Directory>
<Directory "${ADMINER_RUNTIME_DIR}">
AllowOverride None
Options -Indexes
Require all denied
</Directory>
# END DA_POSTGRESQL_ADMINER
EOF
mv "$tmp_file" "$APACHE_ALIAS_CUSTOM"
chmod 644 "$APACHE_ALIAS_CUSTOM"
}
sekcja "Weryfikacja środowiska"
command -v php >/dev/null 2>&1 || die "Brak polecenia php."
id diradmin >/dev/null 2>&1 || die "Brak użytkownika diradmin."
APACHE_GROUP="$(detect_apache_group)"
info "Wykryta grupa Apache: ${APACHE_GROUP}"
read_adminer_public_mode
if [[ "$ADMINER_PUBLIC_MODE" == "1" ]]; then
info "Tryb ADMINER_PUBLIC: true (bezpośredni dostęp do /adminer bez SSO)."
else
info "Tryb ADMINER_PUBLIC: false (dostęp wyłącznie przez SSO z pluginu)."
fi
sekcja "Instalacja z bundla Adminera ${ADMINER_VERSION}-${ADMINER_FLAVOR}"
mkdir -p "$ADMINER_INSTALL_DIR"
[[ -f "$PLUGIN_BUNDLED_ADMINER" ]] || die "Brak zbundlowanego pliku Adminera: ${PLUGIN_BUNDLED_ADMINER}"
[[ -f "$PLUGIN_BUNDLED_EXTENSION" ]] || die "Brak zbundlowanego rozszerzenia Adminera: ${PLUGIN_BUNDLED_EXTENSION}"
EXPECTED_SUM="$PLUGIN_BUNDLED_ADMINER_SHA256"
ACTUAL_SUM="$(sha256_file "$PLUGIN_BUNDLED_ADMINER" || true)"
[[ -n "$ACTUAL_SUM" ]] || die "Nie można policzyć SHA256 dla ${PLUGIN_BUNDLED_ADMINER}."
[[ "$ACTUAL_SUM" == "$EXPECTED_SUM" ]] \
|| die "Niezgodna suma SHA256 dla zbundlowanego Adminera. Oczekiwano: ${EXPECTED_SUM}, otrzymano: ${ACTUAL_SUM}"
cp -f "$PLUGIN_BUNDLED_ADMINER" "$ADMINER_CORE_FILE"
info "Adminer ${ADMINER_VERSION}-${ADMINER_FLAVOR} skopiowany do: ${ADMINER_CORE_FILE}"
EXPECTED_EXTENSION_SUM="$PLUGIN_BUNDLED_EXTENSION_SHA256"
ACTUAL_EXTENSION_SUM="$(sha256_file "$PLUGIN_BUNDLED_EXTENSION" || true)"
[[ -n "$ACTUAL_EXTENSION_SUM" ]] || die "Nie można policzyć SHA256 dla ${PLUGIN_BUNDLED_EXTENSION}."
[[ "$ACTUAL_EXTENSION_SUM" == "$EXPECTED_EXTENSION_SUM" ]] \
|| die "Niezgodna suma SHA256 dla zbundlowanego rozszerzenia Adminera. Oczekiwano: ${EXPECTED_EXTENSION_SUM}, otrzymano: ${ACTUAL_EXTENSION_SUM}"
cp -f "$PLUGIN_BUNDLED_EXTENSION" "$ADMINER_EXTENSION_FILE"
info "Rozszerzenie Adminera skopiowane do: ${ADMINER_EXTENSION_FILE}"
sekcja "Konfiguracja wrappera bezpieczeństwa"
mkdir -p "$ADMINER_RUNTIME_DIR" "$ADMINER_TICKETS_DIR"
render_adminer_wrapper
chown root:root "$ADMINER_INSTALL_DIR"
chmod 755 "$ADMINER_INSTALL_DIR"
chown root:root "$ADMINER_CORE_FILE" "$ADMINER_EXTENSION_FILE" "$ADMINER_INDEX_FILE"
chmod 644 "$ADMINER_CORE_FILE" "$ADMINER_EXTENSION_FILE" "$ADMINER_INDEX_FILE"
chown diradmin:"$APACHE_GROUP" "$ADMINER_RUNTIME_DIR" "$ADMINER_TICKETS_DIR"
chmod 711 "$ADMINER_RUNTIME_DIR"
chmod 2733 "$ADMINER_TICKETS_DIR"
write_runtime_public_config
chown diradmin:"$APACHE_GROUP" "$ADMINER_RUNTIME_CONFIG_FILE"
chmod 644 "$ADMINER_RUNTIME_CONFIG_FILE"
if command -v selinuxenabled >/dev/null 2>&1 && selinuxenabled; then
warn "Wykryto SELinux: ustawiam kontekst zapisu runtime dla Apache."
if command -v chcon >/dev/null 2>&1; then
chcon -R -t httpd_sys_rw_content_t "$ADMINER_RUNTIME_DIR" || warn "Nie udało się ustawić kontekstu SELinux dla runtime."
chcon -t httpd_sys_content_t "$ADMINER_CORE_FILE" "$ADMINER_EXTENSION_FILE" "$ADMINER_INDEX_FILE" || warn "Nie udało się ustawić kontekstu SELinux dla plików PHP."
else
warn "Brak chcon - ustaw kontekst SELinux ręcznie."
fi
fi
sekcja "Konfiguracja aliasu /adminer (DirectAdmin CustomBuild)"
configure_apache_alias
if [[ -x "$CB_BUILD" ]]; then
(cd "$CB_DIR" && ./build rewrite_confs) \
|| die "rewrite_confs zakończył się błędem."
info "rewrite_confs wykonane pomyślnie."
else
warn "Brak ${CB_BUILD} - uruchom ręcznie: cd ${CB_DIR} && ./build rewrite_confs"
fi
if systemctl is-active --quiet httpd 2>/dev/null; then
systemctl reload httpd || warn "Nie udało się przeładować httpd."
fi
sekcja "Aktualizacja ustawień pluginu"
if [[ -f "$PLUGIN_SETTINGS" ]]; then
set_setting "ENABLE_ADMINER" "true" "$PLUGIN_SETTINGS"
set_setting_if_missing "ADMINER_PUBLIC" "false" "$PLUGIN_SETTINGS"
set_setting_if_missing "ADMINER_PUBLIC_BASE_URL" "" "$PLUGIN_SETTINGS"
set_setting "ADMINER_URL_PATH" "$ADMINER_URL_PATH" "$PLUGIN_SETTINGS"
set_setting "ADMINER_SSO_DIR" "$ADMINER_RUNTIME_DIR" "$PLUGIN_SETTINGS"
set_setting "ADMINER_TICKET_TTL" "120" "$PLUGIN_SETTINGS"
set_setting "ADMINER_SESSION_TTL" "900" "$PLUGIN_SETTINGS"
set_setting "ADMINER_ROLE_TTL" "1200" "$PLUGIN_SETTINGS"
chown "$PLUGIN_OWNER" "$PLUGIN_SETTINGS" 2>/dev/null || true
chmod 640 "$PLUGIN_SETTINGS" 2>/dev/null || true
info "Zaktualizowano: ${PLUGIN_SETTINGS}"
else
warn "Nie znaleziono pliku ${PLUGIN_SETTINGS} - ustawienia pluginu pominięte."
fi
sekcja "Instalacja zakończona"
echo "Adminer URL: ${ADMINER_URL_PATH}"
echo "Katalog: ${ADMINER_INSTALL_DIR}"
echo "Runtime ticketów: ${ADMINER_TICKETS_DIR}"
echo "Runtime config: ${ADMINER_RUNTIME_CONFIG_FILE}"
echo "Alias template: ${APACHE_ALIAS_CUSTOM}"
echo "Log: ${LOGFILE}"