Anpassen der Tlsa Record erstellung
parent
44a3056de9
commit
93c541e3e7
|
|
@ -9,7 +9,7 @@ class Domain extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'domain','description','tags',
|
'domain','description','tags',
|
||||||
'is_active','is_system',
|
'is_active','is_system','is_server',
|
||||||
'max_aliases','max_mailboxes',
|
'max_aliases','max_mailboxes',
|
||||||
'default_quota_mb','max_quota_per_mailbox_mb','total_quota_mb',
|
'default_quota_mb','max_quota_per_mailbox_mb','total_quota_mb',
|
||||||
'rate_limit_per_hour','rate_limit_override',
|
'rate_limit_per_hour','rate_limit_override',
|
||||||
|
|
@ -19,6 +19,7 @@ class Domain extends Model
|
||||||
'tags' => 'array',
|
'tags' => 'array',
|
||||||
'is_active' => 'bool',
|
'is_active' => 'bool',
|
||||||
'is_system' => 'bool',
|
'is_system' => 'bool',
|
||||||
|
'is_server' => 'boolean',
|
||||||
'max_aliases' => 'int',
|
'max_aliases' => 'int',
|
||||||
'max_mailboxes' => 'int',
|
'max_mailboxes' => 'int',
|
||||||
'default_quota_mb' => 'int',
|
'default_quota_mb' => 'int',
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Domain;
|
||||||
use App\Models\TlsaRecord;
|
use App\Models\TlsaRecord;
|
||||||
|
|
||||||
class TlsaService
|
class TlsaService
|
||||||
{
|
{
|
||||||
public function resolveMtaHost(): string
|
public function resolveMxHost(): string
|
||||||
{
|
{
|
||||||
$base = env('BASE_DOMAIN', 'example.com');
|
$base = env('BASE_DOMAIN', 'example.com');
|
||||||
$sub = env('MTA_SUB', 'mx') ?: 'mx';
|
$sub = env('MTA_SUB', 'mx') ?: 'mx';
|
||||||
|
|
@ -25,44 +27,105 @@ class TlsaService
|
||||||
return $hash !== '' ? $hash : null;
|
return $hash !== '' ? $hash : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function refreshForMx(string $service = '_25._tcp'): ?TlsaRecord
|
/**
|
||||||
|
* Schreibt/aktualisiert TLSA (3 1 1) für den MX-Host in DB
|
||||||
|
* und legt zusätzlich /etc/mailwolt/dns/<host>.tlsa.txt ab.
|
||||||
|
*/
|
||||||
|
public function refreshForServerDomain(Domain $serverDomain, string $service = '_25._tcp'): ?TlsaRecord
|
||||||
{
|
{
|
||||||
$host = $this->resolveMtaHost();
|
$host = $this->resolveMxHost();
|
||||||
$certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem";
|
|
||||||
$hash = $this->computeHashFromCert($host);
|
$hash = $this->computeHashFromCert($host);
|
||||||
if (!$hash) return null;
|
if (!$hash) {
|
||||||
|
return null; // Zert (noch) nicht vorhanden
|
||||||
|
}
|
||||||
|
|
||||||
|
$certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem";
|
||||||
|
|
||||||
// DB upsert (global, domain_id = null)
|
|
||||||
$rec = TlsaRecord::updateOrCreate(
|
$rec = TlsaRecord::updateOrCreate(
|
||||||
['domain_id' => null, 'host' => $host, 'service' => $service],
|
['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service],
|
||||||
[
|
[
|
||||||
'usage' => 3, // DANE-EE
|
'usage' => 3, // DANE-EE
|
||||||
'selector' => 1, // SPKI
|
'selector' => 1, // SPKI
|
||||||
'matching' => 1, // SHA-256
|
'matching' => 1, // SHA-256
|
||||||
'hash' => $hash,
|
'hash' => $hash,
|
||||||
'cert_path' => $certPath,
|
'cert_path' => $certPath,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Datei – nur aktualisieren, wenn sich der Hash ändert
|
// Optional: TXT-Datei für Export/Debug
|
||||||
@mkdir('/etc/mailwolt/dns', 0755, true);
|
@mkdir('/etc/mailwolt/dns', 0755, true);
|
||||||
$file = "/etc/mailwolt/dns/{$host}.tlsa.txt";
|
$line = sprintf('%s.%s IN TLSA %d %d %d %s', $service, $host, 3, 1, 1, $hash);
|
||||||
$newLine = sprintf('%s.%s IN TLSA %d %d %d %s', $service, $host, 3, 1, 1, $hash);
|
@file_put_contents("/etc/mailwolt/dns/{$host}.tlsa.txt", $line."\n");
|
||||||
|
|
||||||
$needWrite = true;
|
|
||||||
if (is_file($file)) {
|
|
||||||
$current = trim((string)file_get_contents($file));
|
|
||||||
if ($current === $newLine) {
|
|
||||||
$needWrite = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($needWrite) {
|
|
||||||
file_put_contents($file, $newLine."\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rec;
|
return $rec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//class TlsaService
|
||||||
|
//{
|
||||||
|
// public function resolveMtaHost(): string
|
||||||
|
// {
|
||||||
|
// $base = env('BASE_DOMAIN', 'example.com');
|
||||||
|
// $sub = env('MTA_SUB', 'mx') ?: 'mx';
|
||||||
|
// return "{$sub}.{$base}";
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function computeHashFromCert(string $host): ?string
|
||||||
|
// {
|
||||||
|
// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem";
|
||||||
|
// if (!is_file($certPath)) return null;
|
||||||
|
//
|
||||||
|
// $cmd = "openssl x509 -in ".escapeshellarg($certPath)." -noout -pubkey"
|
||||||
|
// . " | openssl pkey -pubin -outform DER"
|
||||||
|
// . " | openssl dgst -sha256";
|
||||||
|
// $out = shell_exec($cmd.' 2>/dev/null') ?? '';
|
||||||
|
// $hash = preg_replace('/^SHA256\(stdin\)=\s*/', '', trim($out));
|
||||||
|
// return $hash !== '' ? $hash : null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function refreshForMx(string $service = '_25._tcp'): ?TlsaRecord
|
||||||
|
// {
|
||||||
|
// $host = $this->resolveMtaHost();
|
||||||
|
// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem";
|
||||||
|
// $hash = $this->computeHashFromCert($host);
|
||||||
|
// if (!$hash) return null;
|
||||||
|
//
|
||||||
|
// // DB upsert (global, domain_id = null)
|
||||||
|
// $rec = TlsaRecord::updateOrCreate(
|
||||||
|
// ['domain_id' => null, 'host' => $host, 'service' => $service],
|
||||||
|
// [
|
||||||
|
// 'usage' => 3, // DANE-EE
|
||||||
|
// 'selector' => 1, // SPKI
|
||||||
|
// 'matching' => 1, // SHA-256
|
||||||
|
// 'hash' => $hash,
|
||||||
|
// 'cert_path' => $certPath,
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // Datei – nur aktualisieren, wenn sich der Hash ändert
|
||||||
|
// @mkdir('/etc/mailwolt/dns', 0755, true);
|
||||||
|
// $file = "/etc/mailwolt/dns/{$host}.tlsa.txt";
|
||||||
|
// $newLine = sprintf('%s.%s IN TLSA %d %d %d %s', $service, $host, 3, 1, 1, $hash);
|
||||||
|
//
|
||||||
|
// $needWrite = true;
|
||||||
|
// if (is_file($file)) {
|
||||||
|
// $current = trim((string)file_get_contents($file));
|
||||||
|
// if ($current === $newLine) {
|
||||||
|
// $needWrite = false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if ($needWrite) {
|
||||||
|
// file_put_contents($file, $newLine."\n");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return $rec;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//----
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//namespace App\Services;
|
//namespace App\Services;
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ return new class extends Migration
|
||||||
$table->string('tags', 500)->nullable();
|
$table->string('tags', 500)->nullable();
|
||||||
$table->boolean('is_active')->default(true)->index();
|
$table->boolean('is_active')->default(true)->index();
|
||||||
$table->boolean('is_system')->default(false);
|
$table->boolean('is_system')->default(false);
|
||||||
|
$table->boolean('is_server')->default(false)->index();
|
||||||
$table->unsignedInteger('max_aliases')->default(400);
|
$table->unsignedInteger('max_aliases')->default(400);
|
||||||
$table->unsignedInteger('max_mailboxes')->default(10);
|
$table->unsignedInteger('max_mailboxes')->default(10);
|
||||||
$table->unsignedInteger('default_quota_mb')->default(3072);
|
$table->unsignedInteger('default_quota_mb')->default(3072);
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,71 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\DkimKey;
|
use App\Models\DkimKey;
|
||||||
use App\Models\Domain;
|
use App\Models\Domain;
|
||||||
use App\Models\MailUser;
|
use App\Models\MailUser;
|
||||||
use App\Services\DnsRecordService;
|
use App\Services\DnsRecordService;
|
||||||
|
use App\Services\TlsaService;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
class SystemDomainSeeder extends Seeder
|
class SystemDomainSeeder extends Seeder
|
||||||
{
|
{
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
$base = config('mailpool.platform_zone', 'example.com');
|
// --- Basiswerte aus Config/ENV ---
|
||||||
if (!$base || $base === 'example.com') {
|
$platformBase = config('mailpool.platform_zone', env('BASE_DOMAIN', 'example.com')); // z.B. nexlab.at
|
||||||
|
if (!$platformBase || $platformBase === 'example.com') {
|
||||||
$this->command->warn("BASE_DOMAIN ist 'example.com' – Seeder überspringt produktive Einträge.");
|
$this->command->warn("BASE_DOMAIN ist 'example.com' – Seeder überspringt produktive Einträge.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$systemSub = config('mailpool.platform_system_zone');
|
$mtaSub = env('MTA_SUB', 'mx') ?: 'mx'; // z.B. mx
|
||||||
$base = "{$systemSub}.{$base}";
|
$serverFqdn = "{$mtaSub}.{$platformBase}"; // z.B. mx.nexlab.at
|
||||||
|
|
||||||
// Domain anlegen/holen
|
$systemSub = config('mailpool.platform_system_zone') ?: 'sysmail'; // z.B. sysmail
|
||||||
$domain = Domain::firstOrCreate(
|
$systemFqdn = "{$systemSub}.{$platformBase}"; // z.B. sysmail.nexlab.at
|
||||||
['domain' => $base],
|
|
||||||
|
// =========================================================================
|
||||||
|
// 1) MAILSERVER-DOMAIN zuerst (mx.<BASE_DOMAIN>), is_server = true
|
||||||
|
// =========================================================================
|
||||||
|
$serverDomain = Domain::firstOrCreate(
|
||||||
|
['domain' => $serverFqdn],
|
||||||
|
['is_active' => true, 'is_system' => false, 'is_server' => true]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$serverDomain->is_server) {
|
||||||
|
$serverDomain->is_server = true;
|
||||||
|
$serverDomain->save();
|
||||||
|
$this->command->info("Server-Host markiert: {$serverDomain->domain}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSA (3 1 1) nur in Laravel erzeugen/aktualisieren (falls LE-Zert bereits da ist)
|
||||||
|
if (! $serverDomain->tlsa()->exists()) {
|
||||||
|
$tlsa = app(\App\Services\TlsaService::class)->refreshForServerDomain($serverDomain);
|
||||||
|
if ($tlsa) {
|
||||||
|
$this->command->info("TLSA erstellt: _25._tcp.{$tlsa->host} 3 1 1 {$tlsa->hash}");
|
||||||
|
} else {
|
||||||
|
$this->command->warn("TLSA übersprungen: LE-Zertifikat (noch) nicht vorhanden – später erneut seeden.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->command->line("TLSA bereits vorhanden, übersprungen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// 2) SYSTEM-DOMAIN danach (sysmail.<BASE_DOMAIN>), is_system = true
|
||||||
|
// =========================================================================
|
||||||
|
$systemDomain = Domain::firstOrCreate(
|
||||||
|
['domain' => $systemFqdn],
|
||||||
['is_active' => true, 'is_system' => true]
|
['is_active' => true, 'is_system' => true]
|
||||||
);
|
);
|
||||||
|
|
||||||
// System Absender (no-reply) – ohne Passwort (kein Login)
|
// System-Absender (no-reply) – ohne Passwort (kein Login)
|
||||||
MailUser::firstOrCreate(
|
MailUser::firstOrCreate(
|
||||||
['email' => "no-reply@{$base}"],
|
['email' => "no-reply@{$systemFqdn}"],
|
||||||
[
|
[
|
||||||
'domain_id' => $domain->id,
|
'domain_id' => $systemDomain->id,
|
||||||
'localpart' => 'no-reply',
|
'localpart' => 'no-reply',
|
||||||
'password_hash' => null,
|
'password_hash' => null,
|
||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
|
|
@ -42,26 +76,26 @@ class SystemDomainSeeder extends Seeder
|
||||||
);
|
);
|
||||||
|
|
||||||
// DKIM – Key erzeugen, falls keiner aktiv existiert
|
// DKIM – Key erzeugen, falls keiner aktiv existiert
|
||||||
if (! $domain->dkimKeys()->where('is_active', true)->exists()) {
|
if (!$systemDomain->dkimKeys()->where('is_active', true)->exists()) {
|
||||||
[$privPem, $pubTxt] = $this->generateDkimKeyPair();
|
[$privPem, $pubTxt] = $this->generateDkimKeyPair();
|
||||||
$selector = 'mwl1'; // frei wählbar, z. B. rotierend später
|
$selector = 'mwl1'; // frei wählbar, später rotieren
|
||||||
|
|
||||||
DkimKey::create([
|
DkimKey::create([
|
||||||
'domain_id' => $domain->id,
|
'domain_id' => $systemDomain->id,
|
||||||
'selector' => $selector,
|
'selector' => $selector,
|
||||||
'private_key_pem'=> $privPem,
|
'private_key_pem' => $privPem,
|
||||||
'public_key_txt' => $pubTxt,
|
'public_key_txt' => $pubTxt,
|
||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->command->info("DKIM angelegt: Host = {$selector}._domainkey.{$base}");
|
$this->command->info("DKIM angelegt: Host = {$selector}._domainkey.{$systemFqdn}");
|
||||||
}
|
}
|
||||||
|
|
||||||
$dk = $domain->dkimKeys()->where('is_active', true)->latest()->first();
|
$dk = $systemDomain->dkimKeys()->where('is_active', true)->latest()->first();
|
||||||
$dkimTxt = $dk ? "v=DKIM1; k=rsa; p={$dk->public_key_txt}" : null;
|
$dkimTxt = $dk ? "v=DKIM1; k=rsa; p={$dk->public_key_txt}" : null;
|
||||||
|
|
||||||
app(DnsRecordService::class)->provision(
|
app(DnsRecordService::class)->provision(
|
||||||
$domain,
|
$systemDomain,
|
||||||
dkimSelector: $dk?->selector,
|
dkimSelector: $dk?->selector,
|
||||||
dkimTxt: $dkimTxt,
|
dkimTxt: $dkimTxt,
|
||||||
opts: [
|
opts: [
|
||||||
|
|
@ -71,8 +105,8 @@ class SystemDomainSeeder extends Seeder
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->command->info("System-Domain '{$base}' fertig. SPF/DMARC/DKIM & DNS-Empfehlungen eingetragen.");
|
$this->command->info("System-Domain '{$systemFqdn}' fertig. SPF/DMARC/DKIM & DNS-Empfehlungen eingetragen.");
|
||||||
$this->printDnsHints($domain);
|
$this->printDnsHints($systemDomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{0:string privatePem,1:string publicTxt} */
|
/** @return array{0:string privatePem,1:string publicTxt} */
|
||||||
|
|
@ -84,17 +118,16 @@ class SystemDomainSeeder extends Seeder
|
||||||
]);
|
]);
|
||||||
openssl_pkey_export($res, $privateKeyPem);
|
openssl_pkey_export($res, $privateKeyPem);
|
||||||
$details = openssl_pkey_get_details($res);
|
$details = openssl_pkey_get_details($res);
|
||||||
// $details['key'] ist PEM, wir brauchen Base64 ohne Header/Footers
|
|
||||||
$pubDer = $details['key'];
|
$pubDer = $details['key'];
|
||||||
// Public PEM zu "p=" Wert (reines Base64) normalisieren
|
// Public PEM zu "p=" (reines Base64) normalisieren
|
||||||
$pubTxt = trim(preg_replace('/-----(BEGIN|END) PUBLIC KEY-----|\s+/', '', $pubDer));
|
$publicTxt = trim(preg_replace('/-----(BEGIN|END) PUBLIC KEY-----|\s+/', '', $pubDer));
|
||||||
|
return [$privateKeyPem, $publicTxt];
|
||||||
return [$privateKeyPem, $pubTxt];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function printDnsHints(Domain $domain): void
|
private function printDnsHints(Domain $domain): void
|
||||||
{
|
{
|
||||||
$base = $domain->domain;
|
$base = $domain->domain;
|
||||||
|
|
||||||
$dkim = $domain->dkimKeys()->where('is_active', true)->latest()->first();
|
$dkim = $domain->dkimKeys()->where('is_active', true)->latest()->first();
|
||||||
if ($dkim) {
|
if ($dkim) {
|
||||||
$this->command->line(" • DKIM TXT @ {$dkim->selector}._domainkey.{$base}");
|
$this->command->line(" • DKIM TXT @ {$dkim->selector}._domainkey.{$base}");
|
||||||
|
|
@ -114,3 +147,141 @@ class SystemDomainSeeder extends Seeder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//namespace Database\Seeders;
|
||||||
|
//
|
||||||
|
//use App\Models\DkimKey;
|
||||||
|
//use App\Models\Domain;
|
||||||
|
//use App\Models\MailUser;
|
||||||
|
//use App\Services\DnsRecordService;
|
||||||
|
//use Illuminate\Database\Seeder;
|
||||||
|
//
|
||||||
|
//class SystemDomainSeeder extends Seeder
|
||||||
|
//{
|
||||||
|
// public function run(): void
|
||||||
|
// {
|
||||||
|
// $base = config('mailpool.platform_zone', 'example.com');
|
||||||
|
// if (!$base || $base === 'example.com') {
|
||||||
|
// $this->command->warn("BASE_DOMAIN ist 'example.com' – Seeder überspringt produktive Einträge.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $systemSub = config('mailpool.platform_system_zone');
|
||||||
|
// $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}");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $dk = $domain->dkimKeys()->where('is_active', true)->latest()->first();
|
||||||
|
// $dkimTxt = $dk ? "v=DKIM1; k=rsa; p={$dk->public_key_txt}" : null;
|
||||||
|
//
|
||||||
|
// app(DnsRecordService::class)->provision(
|
||||||
|
// $domain,
|
||||||
|
// dkimSelector: $dk?->selector,
|
||||||
|
// dkimTxt: $dkimTxt,
|
||||||
|
// opts: [
|
||||||
|
// 'dmarc_policy' => 'none',
|
||||||
|
// 'spf_tail' => '-all',
|
||||||
|
// // optional: 'ipv4' => $serverIp, 'ipv6' => ...
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// $base = config('mailpool.platform_zone', env('BASE_DOMAIN', 'example.com')); // z.B. nexlab.at
|
||||||
|
// $mta = env('MTA_SUB', 'mx') ?: 'mx';
|
||||||
|
// $serverHostFqdn = "{$mta}.{$base}";
|
||||||
|
//
|
||||||
|
// $serverHostDomain = \App\Models\Domain::firstOrCreate(
|
||||||
|
// ['domain' => $serverHostFqdn],
|
||||||
|
// ['is_active' => true, 'is_system' => false, 'is_server' => true]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// if (!$serverHostDomain->is_server) {
|
||||||
|
// $serverHostDomain->is_server = true;
|
||||||
|
// $serverHostDomain->save();
|
||||||
|
// $this->command->info("Server-Host markiert: {$serverHostDomain->domain}");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $tlsa = app(\App\Services\TlsaService::class)->refreshForServerDomain($serverHostDomain);
|
||||||
|
// if ($tlsa) {
|
||||||
|
// $this->command->info("TLSA gespeichert: _25._tcp.{$tlsa->host} 3 1 1 {$tlsa->hash}");
|
||||||
|
// } else {
|
||||||
|
// $this->command->warn("TLSA übersprungen: LE-Zertifikat (noch) nicht vorhanden – später erneut seeden.");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $this->command->info("System-Domain '{$base}' fertig. SPF/DMARC/DKIM & DNS-Empfehlungen eingetragen.");
|
||||||
|
// $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()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue