Import postgresql plugin
This commit is contained in:
Executable
+704
@@ -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}"
|
||||
Reference in New Issue
Block a user