From dc9a5fdd482f079c040359d044477527d44f1c2b Mon Sep 17 00:00:00 2001 From: boban Date: Fri, 17 Oct 2025 19:04:47 +0200 Subject: [PATCH] Domain Create Modal anpassen Fehler auf Null --- app/Services/TlsaService.php | 675 ++++++++++++++++++++--------------- 1 file changed, 395 insertions(+), 280 deletions(-) diff --git a/app/Services/TlsaService.php b/app/Services/TlsaService.php index e196c74..b82f484 100644 --- a/app/Services/TlsaService.php +++ b/app/Services/TlsaService.php @@ -1,4 +1,5 @@ /dev/null') ?? ''; - $out = trim($out); + $out = trim(shell_exec($cmd . ' 2>/dev/null') ?? ''); if ($out === '') return null; - // Variationen entfernen: "SHA256(stdin)= x", "SHA2-256(stdin)= x" - $hash = preg_replace('/^SHA2?56\(stdin\)=\s*/i', '', $out); - $hash = preg_replace('/^SHA2?-256\(stdin\)=\s*/i', '', $hash); // falls "SHA2-256" + // Akzeptiere "SHA256(stdin)= x" und "SHA2-256(stdin)= x" + $hash = preg_replace('/^SHA2?-?256\(stdin\)=\s*/i', '', $out); $hash = trim($hash); - return $hash !== '' ? $hash : null; + return $hash !== '' ? strtolower($hash) : null; } - /** Holt is_server-Domain und schreibt/aktualisiert TLSA (3 1 1) */ + /** Erzeugt/aktualisiert TLSA (3 1 1) für den aktuellen MX-Host (is_server-Domain). */ public function refreshForMx(string $service = '_25._tcp'): ?TlsaRecord { $host = $this->resolveMxHost(); - // 1) Server-Domain ermitteln (es darf genau eine mit is_server=true geben) $serverDomain = Domain::where('is_server', true) - ->where('domain', $host) // doppelt absichern: passt zur ENV + ->where('domain', $host) // Absicherung ->first(); - if (!$serverDomain) { - // Kein is_server Eintrag -> nichts zu tun - return null; - } + if (!$serverDomain) return null; - // 2) Zertifikat finden/lesen $certPath = $this->firstReadableCert($host); if (!$certPath) return null; - // 3) Hash berechnen $hash = $this->computeHashFromCertPath($certPath); if (!$hash) return null; - // 4) DB schreiben (idempotent) $rec = TlsaRecord::updateOrCreate( ['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service], [ @@ -81,17 +73,20 @@ class TlsaService ] ); - // 5) optionale Export-Datei @mkdir('/etc/mailwolt/dns', 0755, true); $line = 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"); return $rec; } + + /** 🔧 Alias für Seeder-Kompatibilität */ + public function prefreshForServerDomain(?Domain $unused = null): ?TlsaRecord + { + return $this->refreshForMx('_25._tcp'); + } } - - //namespace App\Services; // //use App\Models\Domain; @@ -99,316 +94,436 @@ class TlsaService // //class TlsaService //{ +// public function refreshForServerDomain(Domain $serverDomain): ?TlsaRecord +// { +// // Falls du bereits eine Methode hast, die den Server-TLSA erzeugt: +// if (method_exists($this, 'refreshForServer')) { +// return $this->refreshForServer(); +// } +// +// // Minimal-Implementierung (TLSA 3 1 1 aus aktuellem Mail-Zertifikat) +// $host = env('MTA_HOST', $serverDomain->mx_host ?? ("mx.".$serverDomain->domain)); +// $service = '_25._tcp'; +// $cert = env('MAIL_CERT', "/etc/ssl/mail/fullchain.pem"); +// $pubkeyDer = trim(shell_exec( +// "openssl x509 -in ".escapeshellarg($cert)." -pubkey -noout | ". +// "openssl pkey -pubin -outform DER 2>/dev/null | ". +// "openssl dgst -sha256 -r | awk '{print \$1}'" +// ) ?? ''); +// +// if ($pubkeyDer === '') { +// return null; +// } +// +// return TlsaRecord::updateOrCreate( +// ['service' => $service, 'host' => $host], +// ['usage' => 3, 'selector' => 1, 'matching' => 1, 'hash' => strtolower($pubkeyDer)] +// ); +// } +// // public function resolveMxHost(): string // { // $base = env('BASE_DOMAIN', 'example.com'); -// $sub = env('MTA_SUB', 'mx') ?: 'mx'; +// $sub = env('MTA_SUB', 'mx') ?: 'mx'; // return "{$sub}.{$base}"; // } // // private function certCandidates(string $host): array // { -// // bevorzugt die vom Deploy-Hook gesetzten, lesbaren Symlinks -// $candidates = [ -// '/etc/ssl/mail/fullchain.pem', // MX -// "/etc/letsencrypt/live/{$host}/fullchain.pem", // Fallback +// return [ +// '/etc/ssl/mail/fullchain.pem', // vom Deploy-Wrapper kopiert (lesbar) +// "/etc/letsencrypt/live/{$host}/fullchain.pem", // Fallback (meist nicht lesbar) // ]; -// return $candidates; -// } -// -// public function refreshForMx(string $service = '_25._tcp'): ?\App\Models\TlsaRecord -// { -// $host = $this->resolveMxHost(); -// -// // bevorzugt die als Server markierte Domain -// $serverDomain = \App\Models\Domain::where('is_server', true)->first(); -// -// // Fallback: Domain über FQDN (mx.) finden -// if (!$serverDomain) { -// $serverDomain = \App\Models\Domain::where('domain', $host)->first(); -// } -// -// if (!$serverDomain) { -// // Keine passende Domain in der DB → nichts tun -// return null; -// } -// -// return $this->refreshForServerDomain($serverDomain, $service); // } // // private function firstReadableCert(string $host): ?string // { -// foreach ($this->certCandidates($host) as $path) { -// if (is_file($path) && is_readable($path)) { -// return $path; -// } +// foreach ($this->certCandidates($host) as $p) { +// if (is_file($p) && is_readable($p)) return $p; // } // return null; // } // -// public function computeHashFromCert(string $host): ?string +// public function computeHashFromCertPath(string $certPath): ?string // { -// $certPath = $this->firstReadableCert($host); -// if (!$certPath) return null; -// -// $cmd = "openssl x509 -in ".escapeshellarg($certPath)." -noout -pubkey" +// $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)); +// $out = shell_exec($cmd . ' 2>/dev/null') ?? ''; +// $out = trim($out); +// if ($out === '') return null; +// +// // Variationen entfernen: "SHA256(stdin)= x", "SHA2-256(stdin)= x" +// $hash = preg_replace('/^SHA2?56\(stdin\)=\s*/i', '', $out); +// $hash = preg_replace('/^SHA2?-256\(stdin\)=\s*/i', '', $hash); // falls "SHA2-256" +// $hash = trim($hash); +// // return $hash !== '' ? $hash : null; // } // -// public function refreshForServerDomain(Domain $serverDomain, string $service = '_25._tcp'): ?TlsaRecord +// /** Holt is_server-Domain und schreibt/aktualisiert TLSA (3 1 1) */ +// public function refreshForMx(string $service = '_25._tcp'): ?TlsaRecord // { // $host = $this->resolveMxHost(); -// $hash = $this->computeHashFromCert($host); -// if (!$hash) return null; // -// $certPath = $this->firstReadableCert($host) ?? ''; +// // 1) Server-Domain ermitteln (es darf genau eine mit is_server=true geben) +// $serverDomain = Domain::where('is_server', true) +// ->where('domain', $host) // doppelt absichern: passt zur ENV +// ->first(); // -// $rec = TlsaRecord::updateOrCreate( -// ['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service], -// [ -// 'usage' => 3, -// 'selector' => 1, -// 'matching' => 1, -// 'hash' => $hash, -// 'cert_path' => $certPath, -// ] -// ); -// -// @mkdir('/etc/mailwolt/dns', 0755, true); -// $line = 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"); -// -// return $rec; -// } - -// public function computeHashFromCert(string $host): ?string -// { -// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem"; -// if (!is_file($certPath)) { -// // optional: Log für Debug -// logger()->warning("TLSA: Zertifikat nicht gefunden", ['path' => $certPath]); +// if (!$serverDomain) { +// // Kein is_server Eintrag -> nichts zu tun // 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; -// } +// // 2) Zertifikat finden/lesen +// $certPath = $this->firstReadableCert($host); +// if (!$certPath) return null; // -// /** -// * TLSA (3 1 1) für den MX-Host der übergebenen Domain erzeugen/aktualisieren. -// * Host kommt DIREKT aus $serverDomain->domain, nicht aus ENV. -// */ -// public function refreshForServerDomain(Domain $serverDomain, string $service = '_25._tcp'): ?TlsaRecord -// { -// $host = $serverDomain->domain; // <— wichtig: Domain-Objekt statt ENV -// $hash = $this->computeHashFromCert($host); -// if (!$hash) { -// return null; // Zert (noch) nicht vorhanden -// } -// -// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem"; +// // 3) Hash berechnen +// $hash = $this->computeHashFromCertPath($certPath); +// if (!$hash) return null; // +// // 4) DB schreiben (idempotent) // $rec = TlsaRecord::updateOrCreate( // ['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service], // [ -// 'usage' => 3, // DANE-EE -// 'selector' => 1, // SPKI -// 'matching' => 1, // SHA-256 -// 'hash' => $hash, +// 'usage' => 3, +// 'selector' => 1, +// 'matching' => 1, +// 'hash' => $hash, // 'cert_path' => $certPath, // ] // ); // -// // optional: Datei für Export/Debug -// @mkdir('/etc/mailwolt/dns', 0755, true); -// @file_put_contents("/etc/mailwolt/dns/{$host}.tlsa.txt", sprintf('%s.%s IN TLSA 3 1 1 %s', $service, $host, $hash)."\n"); -// -// return $rec; -// } - -// public function resolveMxHost(): 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; -// } -// -// /** -// * Schreibt/aktualisiert TLSA (3 1 1) für den MX-Host in DB -// * und legt zusätzlich /etc/mailwolt/dns/.tlsa.txt ab. -// */ -// public function refreshForServerDomain(Domain $serverDomain, string $service = '_25._tcp'): ?TlsaRecord -// { -// $host = $this->resolveMxHost(); -// $hash = $this->computeHashFromCert($host); -// if (!$hash) { -// return null; // Zert (noch) nicht vorhanden -// } -// -// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem"; -// -// $rec = TlsaRecord::updateOrCreate( -// ['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service], -// [ -// 'usage' => 3, // DANE-EE -// 'selector' => 1, // SPKI -// 'matching' => 1, // SHA-256 -// 'hash' => $hash, -// 'cert_path' => $certPath, -// ] -// ); -// -// // Optional: TXT-Datei für Export/Debug +// // 5) optionale Export-Datei // @mkdir('/etc/mailwolt/dns', 0755, true); // $line = 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"); -// -// 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"); -// } +// @file_put_contents("/etc/mailwolt/dns/{$host}.tlsa.txt", $line . "\n"); // // return $rec; // } //} // -//---- - - // -//namespace App\Services; // -//use App\Models\TlsaRecord; +////namespace App\Services; +//// +////use App\Models\Domain; +////use App\Models\TlsaRecord; +//// +////class TlsaService +////{ +//// public function resolveMxHost(): string +//// { +//// $base = env('BASE_DOMAIN', 'example.com'); +//// $sub = env('MTA_SUB', 'mx') ?: 'mx'; +//// return "{$sub}.{$base}"; +//// } +//// +//// private function certCandidates(string $host): array +//// { +//// // bevorzugt die vom Deploy-Hook gesetzten, lesbaren Symlinks +//// $candidates = [ +//// '/etc/ssl/mail/fullchain.pem', // MX +//// "/etc/letsencrypt/live/{$host}/fullchain.pem", // Fallback +//// ]; +//// return $candidates; +//// } +//// +//// public function refreshForMx(string $service = '_25._tcp'): ?\App\Models\TlsaRecord +//// { +//// $host = $this->resolveMxHost(); +//// +//// // bevorzugt die als Server markierte Domain +//// $serverDomain = \App\Models\Domain::where('is_server', true)->first(); +//// +//// // Fallback: Domain über FQDN (mx.) finden +//// if (!$serverDomain) { +//// $serverDomain = \App\Models\Domain::where('domain', $host)->first(); +//// } +//// +//// if (!$serverDomain) { +//// // Keine passende Domain in der DB → nichts tun +//// return null; +//// } +//// +//// return $this->refreshForServerDomain($serverDomain, $service); +//// } +//// +//// private function firstReadableCert(string $host): ?string +//// { +//// foreach ($this->certCandidates($host) as $path) { +//// if (is_file($path) && is_readable($path)) { +//// return $path; +//// } +//// } +//// return null; +//// } +//// +//// public function computeHashFromCert(string $host): ?string +//// { +//// $certPath = $this->firstReadableCert($host); +//// if (!$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 refreshForServerDomain(Domain $serverDomain, string $service = '_25._tcp'): ?TlsaRecord +//// { +//// $host = $this->resolveMxHost(); +//// $hash = $this->computeHashFromCert($host); +//// if (!$hash) return null; +//// +//// $certPath = $this->firstReadableCert($host) ?? ''; +//// +//// $rec = TlsaRecord::updateOrCreate( +//// ['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service], +//// [ +//// 'usage' => 3, +//// 'selector' => 1, +//// 'matching' => 1, +//// 'hash' => $hash, +//// 'cert_path' => $certPath, +//// ] +//// ); +//// +//// @mkdir('/etc/mailwolt/dns', 0755, true); +//// $line = 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"); +//// +//// 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)) { +//// // optional: Log für Debug +//// logger()->warning("TLSA: Zertifikat nicht gefunden", ['path' => $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; +//// } +//// +//// /** +//// * TLSA (3 1 1) für den MX-Host der übergebenen Domain erzeugen/aktualisieren. +//// * Host kommt DIREKT aus $serverDomain->domain, nicht aus ENV. +//// */ +//// public function refreshForServerDomain(Domain $serverDomain, string $service = '_25._tcp'): ?TlsaRecord +//// { +//// $host = $serverDomain->domain; // <— wichtig: Domain-Objekt statt ENV +//// $hash = $this->computeHashFromCert($host); +//// if (!$hash) { +//// return null; // Zert (noch) nicht vorhanden +//// } +//// +//// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem"; +//// +//// $rec = TlsaRecord::updateOrCreate( +//// ['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service], +//// [ +//// 'usage' => 3, // DANE-EE +//// 'selector' => 1, // SPKI +//// 'matching' => 1, // SHA-256 +//// 'hash' => $hash, +//// 'cert_path' => $certPath, +//// ] +//// ); +//// +//// // optional: Datei für Export/Debug +//// @mkdir('/etc/mailwolt/dns', 0755, true); +//// @file_put_contents("/etc/mailwolt/dns/{$host}.tlsa.txt", sprintf('%s.%s IN TLSA 3 1 1 %s', $service, $host, $hash)."\n"); +//// +//// return $rec; +//// } // -// public function computeHashFromCert(string $host): ?string -// { -// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem"; -// if (!is_file($certPath)) return null; +//// public function resolveMxHost(): 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; +//// } +//// +//// /** +//// * Schreibt/aktualisiert TLSA (3 1 1) für den MX-Host in DB +//// * und legt zusätzlich /etc/mailwolt/dns/.tlsa.txt ab. +//// */ +//// public function refreshForServerDomain(Domain $serverDomain, string $service = '_25._tcp'): ?TlsaRecord +//// { +//// $host = $this->resolveMxHost(); +//// $hash = $this->computeHashFromCert($host); +//// if (!$hash) { +//// return null; // Zert (noch) nicht vorhanden +//// } +//// +//// $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem"; +//// +//// $rec = TlsaRecord::updateOrCreate( +//// ['domain_id' => $serverDomain->id, 'host' => $host, 'service' => $service], +//// [ +//// 'usage' => 3, // DANE-EE +//// 'selector' => 1, // SPKI +//// 'matching' => 1, // SHA-256 +//// 'hash' => $hash, +//// 'cert_path' => $certPath, +//// ] +//// ); +//// +//// // Optional: TXT-Datei für Export/Debug +//// @mkdir('/etc/mailwolt/dns', 0755, true); +//// $line = 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"); +//// +//// return $rec; +//// } +////} // -// $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; -// } // -// /** -// * Schreibt/aktualisiert TLSA in DB (global) + Datei unter /etc/mailwolt/dns/. -// * Wir speichern ohne domain_id (global, nur pro Host/Service). -// */ -// 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; +////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; +//// } +////} +//// +////---- // -// // DB upsert (domain_id = null → globaler Eintrag) -// $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 schreiben (für externen DNS-Export etc.) -// @mkdir('/etc/mailwolt/dns', 0755, true); -// $line = 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"); -// -// return $rec; -// } -//} +//// +////namespace App\Services; +//// +////use App\Models\TlsaRecord; +//// +////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; +//// } +//// +//// /** +//// * Schreibt/aktualisiert TLSA in DB (global) + Datei unter /etc/mailwolt/dns/. +//// * Wir speichern ohne domain_id (global, nur pro Host/Service). +//// */ +//// 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 (domain_id = null → globaler Eintrag) +//// $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 schreiben (für externen DNS-Export etc.) +//// @mkdir('/etc/mailwolt/dns', 0755, true); +//// $line = 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"); +//// +//// return $rec; +//// } +////}