125 lines
4.4 KiB
PHP
125 lines
4.4 KiB
PHP
<?php
|
||
|
||
namespace Database\Seeders;
|
||
|
||
use App\Models\DkimKey;
|
||
use App\Models\DmarcRecord;
|
||
use App\Models\Domain;
|
||
use App\Models\MailUser;
|
||
use App\Models\SpfRecord;
|
||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||
use Illuminate\Database\Seeder;
|
||
|
||
class SystemDomainSeeder extends Seeder
|
||
{
|
||
public function run(): void
|
||
{
|
||
$base = config('app.base_domain', env('BASE_DOMAIN', 'example.com'));
|
||
if (!$base || $base === 'example.com') {
|
||
$this->command->warn("BASE_DOMAIN ist 'example.com' – Seeder überspringt produktive Einträge.");
|
||
return;
|
||
}
|
||
|
||
$systemSub = env('SYSTEM_SUB', 'system');
|
||
$base = "{$systemSub}.{$base}";
|
||
|
||
// Domain anlegen/holen
|
||
$domain = Domain::firstOrCreate(
|
||
['domain' => $base],
|
||
['is_active' => true, 'is_system' => true]
|
||
);
|
||
|
||
// System Absender (no-reply) – ohne Passwort (kein Login)
|
||
MailUser::firstOrCreate(
|
||
['email' => "no-reply@{$base}"],
|
||
[
|
||
'domain_id' => $domain->id,
|
||
'localpart' => 'no-reply',
|
||
'password_hash' => null,
|
||
'is_active' => true,
|
||
'is_system' => true,
|
||
'must_change_pw' => false,
|
||
'quota_mb' => 0,
|
||
]
|
||
);
|
||
|
||
// DKIM – Key erzeugen, falls keiner aktiv existiert
|
||
if (! $domain->dkimKeys()->where('is_active', true)->exists()) {
|
||
[$privPem, $pubTxt] = $this->generateDkimKeyPair();
|
||
$selector = 'mwl1'; // frei wählbar, z. B. rotierend später
|
||
|
||
DkimKey::create([
|
||
'domain_id' => $domain->id,
|
||
'selector' => $selector,
|
||
'private_key_pem'=> $privPem,
|
||
'public_key_txt' => $pubTxt,
|
||
'is_active' => true,
|
||
]);
|
||
|
||
$this->command->info("DKIM angelegt: Host = {$selector}._domainkey.{$base}");
|
||
}
|
||
|
||
// SPF – einfachen Default bauen
|
||
$serverIp = env('SERVER_IP'); // optional vom Installer rein schreiben
|
||
$parts = ['v=spf1','mx','a'];
|
||
if ($serverIp) $parts[] = "ip4:{$serverIp}";
|
||
$parts[] = '-all';
|
||
$spf = implode(' ', $parts);
|
||
|
||
SpfRecord::firstOrCreate(
|
||
['domain_id' => $domain->id, 'record_txt' => $spf],
|
||
['is_active' => true]
|
||
);
|
||
|
||
// DMARC – vorsichtig starten (p=none)
|
||
$rua = "mailto:dmarc@{$base}";
|
||
$dmarc = DmarcRecord::firstOrCreate(
|
||
['domain_id' => $domain->id, 'policy' => 'none'],
|
||
['rua' => $rua, 'pct' => 100, 'record_txt' => "v=DMARC1; p=none; rua={$rua}; pct=100", 'is_active' => true]
|
||
);
|
||
|
||
$this->command->info("System-Domain '{$base}' fertig. SPF/DMARC/DKIM eingetragen.");
|
||
$this->command->line("DNS-Hinweise:");
|
||
$this->printDnsHints($domain);
|
||
}
|
||
|
||
/** @return array{0:string privatePem,1:string publicTxt} */
|
||
private function generateDkimKeyPair(): array
|
||
{
|
||
$res = openssl_pkey_new([
|
||
'private_key_bits' => 2048,
|
||
'private_key_type' => OPENSSL_KEYTYPE_RSA,
|
||
]);
|
||
openssl_pkey_export($res, $privateKeyPem);
|
||
$details = openssl_pkey_get_details($res);
|
||
// $details['key'] ist PEM, wir brauchen Base64 ohne Header/Footers
|
||
$pubDer = $details['key'];
|
||
// Public PEM zu "p=" Wert (reines Base64) normalisieren
|
||
$pubTxt = trim(preg_replace('/-----(BEGIN|END) PUBLIC KEY-----|\s+/', '', $pubDer));
|
||
|
||
return [$privateKeyPem, $pubTxt];
|
||
}
|
||
|
||
private function printDnsHints(Domain $domain): void
|
||
{
|
||
$base = $domain->domain;
|
||
$dkim = $domain->dkimKeys()->where('is_active', true)->latest()->first();
|
||
if ($dkim) {
|
||
$this->command->line(" • DKIM TXT @ {$dkim->selector}._domainkey.{$base}");
|
||
$this->command->line(" v=DKIM1; k=rsa; p={$dkim->public_key_txt}");
|
||
}
|
||
|
||
$spf = $domain->spf()->where('is_active', true)->latest()->first();
|
||
if ($spf) {
|
||
$this->command->line(" • SPF TXT @ {$base}");
|
||
$this->command->line(" {$spf->record_txt}");
|
||
}
|
||
|
||
$dmarc = $domain->dmarc()->where('is_active', true)->latest()->first();
|
||
if ($dmarc) {
|
||
$this->command->line(" • DMARC TXT @ _dmarc.{$base}");
|
||
$this->command->line(" " . ($dmarc->record_txt ?? $dmarc->renderTxt()));
|
||
}
|
||
}
|
||
}
|