Domain Create Modal anpassen Fehler auf Null

main
boban 2025-10-18 10:12:31 +02:00
parent 33abdc7c7f
commit 0730f53a72
7 changed files with 174 additions and 4 deletions

View File

@ -0,0 +1,52 @@
<?php
namespace App\Jobs;
use App\Models\Domain;
use App\Models\DkimKey;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class InstallDkimKey implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
public int $domainId,
public int $dkimKeyId,
public string $privPath,
public string $dnsTxtContent,
) {}
public function handle(): void
{
$domain = Domain::findOrFail($this->domainId);
$dk = DkimKey::findOrFail($this->dkimKeyId);
$domainName = $domain->domain; // z.B. example.com
$selector = $dk->selector; // z.B. mwl1
// TXT temporär für Helper speichern (optional, damit /etc/mailwolt/dns gefüllt wird)
$tmpTxt = tempnam(sys_get_temp_dir(), 'dkim_txt_');
file_put_contents($tmpTxt, $this->dnsTxtContent);
// Root-Helper aufrufen (sudoers hast du im Installer angelegt)
$cmd = sprintf(
'sudo /usr/local/sbin/mailwolt-install-dkim %s %s %s %s',
escapeshellarg($domainName),
escapeshellarg($selector),
escapeshellarg($this->privPath),
escapeshellarg($tmpTxt)
);
exec($cmd, $out, $rc);
@unlink($tmpTxt);
if ($rc !== 0) {
throw new \RuntimeException("mailwolt-install-dkim failed (rc={$rc})");
}
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Jobs;
use App\Models\Domain;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class RemoveDkimKey implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
public int $domainId,
public string $selector
) {}
public function handle(): void
{
$domain = Domain::withTrashed()->findOrFail($this->domainId);
$cmd = sprintf(
'sudo /usr/local/sbin/mailwolt-remove-dkim %s %s',
escapeshellarg($domain->domain),
escapeshellarg($this->selector)
);
exec($cmd, $out, $rc);
if ($rc !== 0) {
throw new \RuntimeException("mailwolt-remove-dkim failed (rc={$rc})");
}
}
}

View File

@ -3,6 +3,7 @@
namespace App\Livewire\Ui\Domain\Modal;
use App\Jobs\InstallDkimKey;
use App\Models\DkimKey;
use App\Models\Domain;
use App\Models\Setting;
@ -271,7 +272,7 @@ class DomainCreateModal extends ModalComponent
// DKIM + DNS
$dkim = app(DkimService::class)->generateForDomain($domain, $this->dkim_bits, $this->dkim_selector);
DkimKey::create([
$dk = DkimKey::create([
'domain_id' => $domain->id,
'selector' => $dkim['selector'],
'private_key_pem' => $dkim['private_pem'],
@ -279,6 +280,13 @@ class DomainCreateModal extends ModalComponent
'is_active' => true,
]);
dispatch(new InstallDkimKey(
domainId: $domain->id,
dkimKeyId: $dk->id,
privPath: $dkim['priv_path'],
dnsTxtContent: $dkim['dns_txt']
));
app(DnsRecordService::class)->provision(
$domain,
$dkim['selector'] ?? null,

View File

@ -0,0 +1,66 @@
<?php
namespace App\Observers;
use App\Jobs\InstallDkimKey;
use App\Jobs\RemoveDkimKey;
use App\Models\DkimKey;
use App\Models\Domain;
use App\Services\DkimService;
class DomainObserver
{
/**
* DKIM bei neuen Domains erzeugen + in OpenDKIM installieren.
* Läuft NUR, wenn die Domain aktiv ist (anpassbar).
*/
public function created(Domain $domain): void
{
// Standardwerte aus Config oder .env
$selector = config('mailwolt.dkim.selector', 'mwl1');
$bits = (int) config('mailwolt.dkim.bits', 2048);
// Keypair erzeugen
$res = app(DkimService::class)->generateForDomain(
domainId: $domain,
bits: $bits,
selector: $selector
);
// In dkim_keys speichern
$dk = DkimKey::create([
'domain_id' => $domain->id,
'selector' => $res['selector'],
'private_key_pem' => $res['private_pem'],
'public_key_txt' => preg_replace('/^v=DKIM1; k=rsa; p=/', '', $res['dns_txt']),
'is_active' => true,
]);
// Helper-Job zum Installieren starten
InstallDkimKey::dispatch(
domainId: $domain->id,
dkimKeyId: $dk->id,
privPath: $res['priv_path'],
dnsTxtContent: $res['dns_txt']
)->afterCommit();
}
/**
* Beim Löschen alle DKIM-Selector dieser Domain aus OpenDKIM entfernen.
*/
public function deleted(Domain $domain): void
{
// Falls SoftDeletes im Spiel, willst du evtl. forceDeleted spiegeln (s.u.)
foreach ($domain->dkimKeys()->get() as $dk) {
RemoveDkimKey::dispatch(
domainId: $domain->id,
selector: $dk->selector
)->afterCommit();
}
}
public function forceDeleted(Domain $domain): void
{
$this->deleted($domain);
}
}

View File

@ -2,6 +2,8 @@
namespace App\Providers;
use App\Models\Domain;
use App\Observers\DomainObserver;
use App\Support\SettingsRepository;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
@ -21,6 +23,9 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(\App\Support\SettingsRepository $settings): void
{
Domain::observe(DomainObserver::class);
try {
$S = app(\App\Support\SettingsRepository::class);

View File

@ -54,9 +54,6 @@ class DkimService
throw new \RuntimeException("DKIM: Public-Key schreiben fehlgeschlagen: {$pubRel}");
}
// 4) DNS-Record bauen
// $p = preg_replace('/-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\s+/', '', $publicKeyPem);
// $dnsTxt = "v=DKIM1; k=rsa; p={$p}";
$publicKeyBase64 = self::extractPublicKeyBase64($publicKeyPem);
Log::debug('dkim.p.len', ['len' => strlen($publicKeyBase64)]);

View File

@ -4,4 +4,10 @@ return [
'base_domain' => env('BASE_DOMAIN', 'example.com'),
'sysmail_sub' => env('SYSMAIL_SUB', 'sysmail'),
'dkim_selector' => env('DKIM_SELECTOR', 'mwl1'),
'dkim' => [
'selector' => env('DKIM_SELECTOR', 'mwl1'),
'bits' => (int) env('DKIM_BITS', 2048),
],
];