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
+296
View File
@@ -0,0 +1,296 @@
<?php
declare(strict_types=1);
final class DirectAdminUser
{
private string $username;
private string $prefix;
/** @var array<string,string> */
private array $userConf;
/** @var array<string,string> */
private array $packageConf;
private Settings $settings;
private function __construct(string $username, array $userConf, array $packageConf, Settings $settings)
{
$this->username = $username;
$this->prefix = $username . '_';
$this->userConf = $userConf;
$this->packageConf = $packageConf;
$this->settings = $settings;
}
public static function fromEnvironment(Settings $settings): self
{
$username = Http::server('USER');
if ($username === '') {
$username = Http::server('USERNAME');
}
if ($username === '' || !preg_match('/^[A-Za-z0-9._-]+$/', $username)) {
throw new RuntimeException('Nie można ustalić użytkownika DirectAdmin.');
}
$userConfPath = '/usr/local/directadmin/data/users/' . $username . '/user.conf';
$userConf = self::loadSimpleConf($userConfPath);
$packageConf = self::loadPackageConf($username, $userConf);
return new self($username, $userConf, $packageConf, $settings);
}
public function username(): string
{
return $this->username;
}
public function prefix(): string
{
return $this->prefix;
}
public function language(): string
{
$lang = strtolower(trim((string)($this->userConf['language'] ?? $this->userConf['lang'] ?? 'en')));
if ($lang === '' || strpos($lang, 'en') === 0) {
return 'en';
}
if (strpos($lang, 'pl') === 0) {
return 'pl';
}
return 'en';
}
public function skin(): string
{
$skin = strtolower(trim((string)($this->userConf['skin'] ?? 'enhanced')));
if (strpos($skin, 'evolution') !== false) {
return 'evolution';
}
if (strpos($skin, 'enhanced') !== false) {
return 'enhanced';
}
return 'enhanced';
}
public function hasPluginAccess(): bool
{
return $this->isPluginEnabledByCustomItem() && $this->isDatabaseQuotaEnabled() && $this->isPluginAllowedByPluginRules();
}
public function pluginAccessErrorMessage(): string
{
if (!$this->isPluginEnabledByCustomItem()) {
return 'Plugin PostgreSQL jest wyłączony dla tego konta lub pakietu.';
}
if (!$this->isDatabaseQuotaEnabled()) {
return 'Plugin PostgreSQL jest wyłączony: limit baz danych PostgreSQL ustawiono na 0 i nie zaznaczono opcji Bez Ograniczeń.';
}
if (!$this->isPluginAllowedByPluginRules()) {
return 'Plugin PostgreSQL jest zablokowany przez reguły plugins_allow/plugins_deny.';
}
return 'Brak dostępu do pluginu PostgreSQL.';
}
public function maxDatabases(): int
{
if ($this->isUnlimitedDatabasesByCustomItem()) {
return 0;
}
$rawValue = $this->rawDatabasesLimitValue();
if ($rawValue === null || trim($rawValue) === '') {
$default = $this->settings->defaultDatabasesLimit();
return $default < 0 ? 0 : $default;
}
$raw = trim($rawValue);
$normalized = strtolower(trim($raw));
if ($normalized === 'unlimited') {
return 0;
}
if (!preg_match('/^[0-9]+$/', trim($raw))) {
$default = $this->settings->defaultDatabasesLimit();
return $default < 0 ? 0 : $default;
}
$limit = (int)trim($raw);
return $limit < 0 ? 0 : $limit;
}
private function isPluginEnabledByCustomItem(): bool
{
$raw = $this->readScopedValue('postgresql_enabled');
if ($raw === null) {
return false;
}
return Settings::toBool($raw, false);
}
private function isUnlimitedDatabasesByCustomItem(): bool
{
$unlimitedFlags = [
$this->readScopedValue('upostgresql'),
$this->readScopedValue('upostgresql_max_databases'),
$this->readScopedValue('postgresql_unlimited'), // backward compatibility
];
foreach ($unlimitedFlags as $raw) {
if ($raw !== null && Settings::toBool($raw, false)) {
return true;
}
}
$rawLimit = $this->rawDatabasesLimitValue();
if ($rawLimit !== null && strtolower(trim($rawLimit)) === 'unlimited') {
return true;
}
return false;
}
private function isDatabaseQuotaEnabled(): bool
{
if ($this->isUnlimitedDatabasesByCustomItem()) {
return true;
}
return $this->maxDatabases() > 0;
}
private function rawDatabasesLimitValue(): ?string
{
$raw = $this->readScopedValue('postgresql_max_databases');
if ($raw === null || trim($raw) === '') {
$raw = $this->readScopedValue('postgresql');
}
return $raw;
}
private function isPluginAllowedByPluginRules(): bool
{
$pluginId = 'da-postgresql';
foreach ([$this->packageConf, $this->userConf] as $conf) {
if (!empty($conf['plugins_allow'])) {
$allow = self::parsePluginsList($conf['plugins_allow']);
return in_array($pluginId, $allow, true);
}
}
foreach ([$this->packageConf, $this->userConf] as $conf) {
if (!empty($conf['plugins_deny'])) {
$deny = self::parsePluginsList($conf['plugins_deny']);
return !in_array($pluginId, $deny, true);
}
}
return true;
}
private function readScopedValue(string $key): ?string
{
if (array_key_exists($key, $this->userConf)) {
return $this->userConf[$key];
}
if (array_key_exists($key, $this->packageConf)) {
return $this->packageConf[$key];
}
return null;
}
/**
* @return array<string,string>
*/
private static function loadSimpleConf(string $path): array
{
$data = [];
if (!is_readable($path)) {
return $data;
}
$lines = file($path, FILE_IGNORE_NEW_LINES);
if ($lines === false) {
return $data;
}
foreach ($lines as $line) {
$line = trim($line);
if ($line === '' || $line[0] === '#') {
continue;
}
if (!preg_match('/^([A-Za-z0-9_]+)=(.*)$/', $line, $m)) {
continue;
}
$data[strtolower($m[1])] = trim((string)$m[2]);
}
return $data;
}
/**
* @param array<string,string> $userConf
* @return array<string,string>
*/
private static function loadPackageConf(string $username, array $userConf): array
{
$package = trim((string)($userConf['package'] ?? $userConf['user_package'] ?? ''));
if ($package === '' || !preg_match('/^[A-Za-z0-9._-]+$/', $package)) {
return [];
}
$candidates = [];
$owners = [];
foreach (['creator', 'owner', 'reseller', 'username'] as $k) {
if (!empty($userConf[$k]) && preg_match('/^[A-Za-z0-9._-]+$/', $userConf[$k])) {
$owners[] = $userConf[$k];
}
}
$owners[] = $username;
$owners[] = 'admin';
$owners = array_values(array_unique($owners));
foreach ($owners as $owner) {
$candidates[] = '/usr/local/directadmin/data/users/' . $owner . '/packages/' . $package;
$candidates[] = '/usr/local/directadmin/data/users/' . $owner . '/packages/' . $package . '.conf';
}
foreach ($candidates as $path) {
$conf = self::loadSimpleConf($path);
if (!empty($conf)) {
return $conf;
}
}
return [];
}
/**
* @return string[]
*/
private static function parsePluginsList(string $value): array
{
$value = trim($value);
if ($value === '') {
return [];
}
$items = [];
foreach (explode(':', strtolower($value)) as $item) {
$item = trim($item);
if ($item !== '') {
$items[] = $item;
}
}
return array_values(array_unique($items));
}
}