Files
2026-07-04 16:00:04 +02:00

705 lines
22 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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}"