323 lines
11 KiB
PHP
323 lines
11 KiB
PHP
<?php
|
||
|
||
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.<BASE_DOMAIN>) 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;
|
||
}
|
||
|
||
// 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 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/<host>.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;
|
||
// }
|
||
}
|
||
|
||
|
||
//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;
|
||
//
|
||
//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;
|
||
// }
|
||
//}
|