152 lines
4.6 KiB
PHP
152 lines
4.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
final class Settings
|
|
{
|
|
public const BASE_DIR = '/usr/local/hitme_plugins/global-autoresponders';
|
|
public const CONFIG_DIR = self::BASE_DIR . '/config';
|
|
public const DATA_DIR = self::BASE_DIR . '/data';
|
|
public const STATE_DIR = self::BASE_DIR . '/state';
|
|
public const LOG_DIR = self::BASE_DIR . '/logs';
|
|
public const AUDIT_LOG = self::LOG_DIR . '/audit.log';
|
|
public const EXTERNAL_SETTINGS = self::CONFIG_DIR . '/plugin-settings.conf';
|
|
|
|
/** @var array<string,string> */
|
|
private array $values;
|
|
|
|
/**
|
|
* @param array<string,string> $values
|
|
*/
|
|
private function __construct(array $values)
|
|
{
|
|
$this->values = $values;
|
|
$this->validate();
|
|
}
|
|
|
|
public static function load(string $path): self
|
|
{
|
|
$values = self::defaults();
|
|
if (is_file($path)) {
|
|
$lines = file($path, FILE_IGNORE_NEW_LINES);
|
|
if ($lines !== false) {
|
|
foreach ($lines as $line) {
|
|
$line = trim($line);
|
|
if ($line === '' || str_starts_with($line, '#') || !str_contains($line, '=')) {
|
|
continue;
|
|
}
|
|
[$key, $value] = explode('=', $line, 2);
|
|
$values[trim($key)] = trim($value);
|
|
}
|
|
}
|
|
}
|
|
return new self($values);
|
|
}
|
|
|
|
/**
|
|
* @return array<string,string>
|
|
*/
|
|
public static function defaults(): array
|
|
{
|
|
return [
|
|
'DEFAULT_PLUGIN_LANGUAGE' => 'pl',
|
|
'DEFAULT_ENABLE' => 'true',
|
|
'GLOBAL_AUTORESPONDER_TIMEZONE' => 'Europe/Warsaw',
|
|
'GLOBAL_AUTORESPONDER_BACKEND' => 'da',
|
|
'GLOBAL_AUTORESPONDER_DYNAMIC_MAILBOX_SCOPE' => 'true',
|
|
'GLOBAL_AUTORESPONDER_MAX_SUBJECT_BYTES' => '255',
|
|
'GLOBAL_AUTORESPONDER_MAX_BODY_BYTES' => '20000',
|
|
];
|
|
}
|
|
|
|
public function getString(string $key, string $default = ''): string
|
|
{
|
|
return $this->values[$key] ?? $default;
|
|
}
|
|
|
|
public function getBool(string $key, bool $default = false): bool
|
|
{
|
|
$raw = strtolower($this->getString($key, $default ? 'true' : 'false'));
|
|
return in_array($raw, ['1', 'true', 'yes', 'on'], true);
|
|
}
|
|
|
|
public function getInt(string $key, int $default): int
|
|
{
|
|
$raw = $this->getString($key, (string)$default);
|
|
return preg_match('/^-?[0-9]+$/', $raw) ? (int)$raw : $default;
|
|
}
|
|
|
|
public function defaultLanguage(): string
|
|
{
|
|
$lang = strtolower($this->getString('DEFAULT_PLUGIN_LANGUAGE', 'pl'));
|
|
return preg_match('/^[a-z]{2}$/', $lang) ? $lang : 'pl';
|
|
}
|
|
|
|
public function defaultEnable(): bool
|
|
{
|
|
return $this->getBool('DEFAULT_ENABLE', true);
|
|
}
|
|
|
|
public function timezone(): string
|
|
{
|
|
return $this->getString('GLOBAL_AUTORESPONDER_TIMEZONE', 'Europe/Warsaw');
|
|
}
|
|
|
|
public function backendMode(): string
|
|
{
|
|
return $this->getString('GLOBAL_AUTORESPONDER_BACKEND', 'da');
|
|
}
|
|
|
|
public function scheduleMode(): string
|
|
{
|
|
return $this->backendMode() === 'da' ? 'directadmin_period' : 'exact_hour';
|
|
}
|
|
|
|
public function dynamicMailboxScope(): bool
|
|
{
|
|
return $this->getBool('GLOBAL_AUTORESPONDER_DYNAMIC_MAILBOX_SCOPE', true);
|
|
}
|
|
|
|
public function maxSubjectBytes(): int
|
|
{
|
|
return $this->getInt('GLOBAL_AUTORESPONDER_MAX_SUBJECT_BYTES', 255);
|
|
}
|
|
|
|
public function maxBodyBytes(): int
|
|
{
|
|
return $this->getInt('GLOBAL_AUTORESPONDER_MAX_BODY_BYTES', 20000);
|
|
}
|
|
|
|
public function loadOrCreateSecret(string $path = self::CONFIG_DIR . '/secret.key'): string
|
|
{
|
|
if (is_file($path)) {
|
|
$secret = trim((string)file_get_contents($path));
|
|
if ($secret !== '') {
|
|
return $secret;
|
|
}
|
|
}
|
|
$dir = dirname($path);
|
|
if (!is_dir($dir)) {
|
|
mkdir($dir, 0700, true);
|
|
}
|
|
$secret = bin2hex(random_bytes(32));
|
|
file_put_contents($path, $secret . "\n", LOCK_EX);
|
|
@chmod($path, 0600);
|
|
return $secret;
|
|
}
|
|
|
|
private function validate(): void
|
|
{
|
|
try {
|
|
new DateTimeZone($this->timezone());
|
|
} catch (Throwable) {
|
|
throw new InvalidArgumentException('Invalid timezone: ' . $this->timezone());
|
|
}
|
|
if (!in_array($this->backendMode(), ['da', 'exim'], true)) {
|
|
throw new InvalidArgumentException('Invalid backend mode: ' . $this->backendMode());
|
|
}
|
|
if ($this->maxSubjectBytes() < 1 || $this->maxBodyBytes() < 1) {
|
|
throw new InvalidArgumentException('Invalid size limits');
|
|
}
|
|
}
|
|
}
|