Files
global-autoresponder/exec/lib/Settings.php
T
2026-06-02 20:07:17 +02:00

167 lines
5.1 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_REPLY_EVERY_MESSAGE' => 'false',
'GLOBAL_AUTORESPONDER_REPEAT_MINUTES' => '1440',
'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 replyEveryMessage(): bool
{
return $this->getBool('GLOBAL_AUTORESPONDER_REPLY_EVERY_MESSAGE', false);
}
public function repeatMinutes(): int
{
return $this->getInt('GLOBAL_AUTORESPONDER_REPEAT_MINUTES', 1440);
}
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->repeatMinutes() < 0) {
throw new InvalidArgumentException('Invalid repeat minutes');
}
if ($this->maxSubjectBytes() < 1 || $this->maxBodyBytes() < 1) {
throw new InvalidArgumentException('Invalid size limits');
}
}
}