mailwolt/app/Console/Commands/WizardDomains.php

117 lines
4.0 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\Setting;
use Illuminate\Console\Command;
class WizardDomains extends Command
{
protected $signature = 'mailwolt:wizard-domains
{--ui= : UI-Domain}
{--mail= : Mail-Domain}
{--webmail= : Webmail-Domain}
{--ssl=1 : SSL automatisch (1/0)}';
protected $description = 'Wizard: Domains einrichten mit Status-Dateien';
private const STATE_DIR = '/var/lib/mailwolt/wizard';
public function handle(): int
{
$ui = $this->option('ui');
$mail = $this->option('mail');
$webmail = $this->option('webmail');
$ssl = (bool)(int)$this->option('ssl');
@mkdir(self::STATE_DIR, 0755, true);
foreach (['ui', 'mail', 'webmail'] as $key) {
file_put_contents(self::STATE_DIR . "/{$key}", 'pending');
}
$domains = ['ui' => $ui, 'mail' => $mail, 'webmail' => $webmail];
$allOk = true;
// DNS prüfen
foreach ($domains as $key => $domain) {
if (!$domain) {
file_put_contents(self::STATE_DIR . "/{$key}", 'skip');
continue;
}
file_put_contents(self::STATE_DIR . "/{$key}", 'running');
$hasDns = checkdnsrr($domain, 'A') || checkdnsrr($domain, 'AAAA');
if (!$hasDns) {
file_put_contents(self::STATE_DIR . "/{$key}", 'nodns');
$allOk = false;
}
}
if (!$allOk) {
file_put_contents(self::STATE_DIR . '/done', '0');
Setting::set('ssl_configured', '0');
return self::SUCCESS;
}
// Nginx-Vhosts + optionales SSL via mailwolt-apply-domains
// Das Script erstellt erst die Vhosts (mit ACME-Location), dann certbot --webroot
$helper = '/usr/local/sbin/mailwolt-apply-domains';
$out = shell_exec(sprintf(
'sudo -n %s --ui-host %s --webmail-host %s --mail-host %s --ssl-auto %d 2>&1',
escapeshellarg($helper),
escapeshellarg($ui),
escapeshellarg($webmail),
escapeshellarg($mail),
$ssl ? 1 : 0,
));
$outStr = (string) $out;
$helperOk = $out !== null
&& !str_contains($outStr, '[x]')
&& !str_contains($outStr, 'command not found')
&& !str_contains($outStr, 'No such file')
&& trim($outStr) !== '';
foreach (['ui', 'mail', 'webmail'] as $key) {
$status = file_get_contents(self::STATE_DIR . "/{$key}");
if ($status === 'running' || $status === 'pending') {
$domain = $domains[$key] ?? '';
if ($domain && str_contains($outStr, "[!] {$domain}:")) {
file_put_contents(self::STATE_DIR . "/{$key}", 'noipv6');
} else {
file_put_contents(self::STATE_DIR . "/{$key}", $helperOk ? 'done' : 'error');
}
}
}
// Shell-Script schreibt done bereits vor dem nginx-Switch — nicht überschreiben
$alreadyDone = trim((string) @file_get_contents(self::STATE_DIR . '/done')) === '1';
if (!$alreadyDone) {
file_put_contents(self::STATE_DIR . '/done', $helperOk ? '1' : '0');
}
Setting::set('ssl_configured', ($helperOk || $alreadyDone) ? '1' : '0');
// SESSION_SECURE_COOKIE wird nicht automatisch gesetzt —
// nginx leitet HTTP→HTTPS weiter, Secure-Flag wird im Admin gesetzt
return self::SUCCESS;
}
private function updateEnv(string $path, string $key, string $value): void
{
$content = @file_get_contents($path) ?: '';
$pattern = '/^' . preg_quote($key, '/') . '=[^\r\n]*/m';
$line = $key . '=' . $value;
if (preg_match($pattern, $content)) {
$content = preg_replace($pattern, $line, $content);
} else {
$content .= "\n{$line}";
}
file_put_contents($path, $content);
}
}