mailwolt/app/Livewire/Ui/Domain/Modal/DomainDnsModal.php

233 lines
8.6 KiB
PHP

<?php
namespace App\Livewire\Ui\Domain\Modal;
use App\Models\DkimKey;
use App\Models\Domain;
use App\Services\DnsRecordService;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
use LivewireUI\Modal\ModalComponent;
class DomainDnsModal extends ModalComponent
{
public int $domainId;
public string $domainName = '';
public string $base = '';
public string $ttl = '3600';
public array $recordColors = [];
/** @var array<int,array<string,string|int|null>> */
public array $static = [];
/** @var array<int,array<string,string|int|null>> */
public array $dynamic = [];
public static function modalMaxWidth(): string { return '6xl'; }
public function mount(int $domainId): void
{
$this->recordColors = [
'A' => 'bg-cyan-500/20 text-cyan-300',
'AAAA' => 'bg-blue-500/20 text-blue-300',
'MX' => 'bg-emerald-500/20 text-emerald-300',
'CNAME' => 'bg-indigo-500/20 text-indigo-300',
'PTR' => 'bg-amber-500/20 text-amber-300',
'TXT' => 'bg-violet-500/20 text-violet-300',
'SRV' => 'bg-rose-500/20 text-rose-300',
'TLSA' => 'bg-red-500/20 text-red-300',
];
$d = Domain::findOrFail($domainId);
$this->domainName = $d->domain;
$ipv4 = $this->detectIPv4();
$ipv6 = $this->detectIPv6(); // kann null sein
$this->base = env('BASE_DOMAIN', 'example.com');
$mta = env('MTA_SUB', 'mx').'.'.$this->base; // mx.example.com
// --- Statische Infrastruktur (für alle Domains gleich) ---
$this->static = [
['type'=>'A','name'=>$mta,'value'=>$ipv4],
['type'=>'PTR','name'=>$this->ptrFromIPv4($ipv4),'value'=>$mta],
];
if ($ipv6) {
$this->static[] = ['type'=>'AAAA','name'=>$mta,'value'=>$ipv6];
$this->static[] = ['type'=>'PTR', 'name'=>$this->ptrFromIPv6($ipv6),'value'=>$mta];
}
if ($tlsa = config('mailwolt.tlsa')) {
$this->static[] = ['type'=>'TLSA','name'=>"_25._tcp.$mta",'value'=>$tlsa];
}
$this->static[] = ['type'=>'MX','name'=>$this->domainName,'value'=>"10 $mta."];
// --- Domain-spezifisch ---
$spf = 'v=spf1 mx a -all';
$dmarc = "v=DMARC1; p=none; rua=mailto:dmarc@{$this->domainName}; pct=100";
$dkim = DB::table('dkim_keys')
->where('domain_id', $d->id)->where('is_active', 1)->orderByDesc('id')->first();
$selector = $dkim ? $dkim->selector : 'mwl1';
$dkimHost = "{$selector}._domainkey.{$this->domainName}";
$dkimTxt = $dkim && !str_starts_with(trim($dkim->public_key_txt),'v=')
? 'v=DKIM1; k=rsa; p='.$dkim->public_key_txt
: ($dkim->public_key_txt ?? 'v=DKIM1; k=rsa; p=');
$this->dynamic = [
['type'=>'TXT','name'=>$this->domainName, 'value'=>$spf, 'helpLabel'=>'SPF Record Syntax','helpUrl'=>'http://www.open-spf.org/SPF_Record_Syntax/'],
['type'=>'TXT','name'=>"_dmarc.{$this->domainName}", 'value'=>$dmarc, 'helpLabel'=>'DMARC Assistant','helpUrl'=>'https://www.kitterman.com/dmarc/assistant.html'],
['type'=>'TXT','name'=>$dkimHost, 'value'=>$dkimTxt, 'helpLabel'=>'DKIM Inspector','helpUrl'=>'https://dkimvalidator.com/'],
];
}
private function detectIPv4(): string
{
// robust & ohne env
$out = @shell_exec("ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'");
$ip = trim((string)$out);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) return $ip;
$ip = trim($_SERVER['SERVER_ADDR'] ?? '');
return $ip ?: '203.0.113.10'; // Fallback Demo
}
private function detectIPv6(): ?string
{
$out = @shell_exec("ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'");
$ip = trim((string)$out);
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $ip : null;
}
private function ptrFromIPv4(string $ip): string
{
$p = array_reverse(explode('.', $ip));
return implode('.', $p).'.in-addr.arpa';
}
private function ptrFromIPv6(string $ip): string
{
$expanded = strtolower(inet_ntop(inet_pton($ip)));
$hex = str_replace(':', '', $expanded);
return implode('.', array_reverse(str_split($hex))).'.ip6.arpa';
}
public function render()
{
return view('livewire.ui.domain.modal.domain-dns-modal');
}
// public int $domainId;
// public Domain $domain;
//
// public array $records = [];
//
// public function mount(int $domainId): void
// {
// $this->domainId = $domainId;
// $this->domain = Domain::findOrFail($domainId);
//
// // Placeholder-Werte, sofern du sie anderswo speicherst gern ersetzen:
// $serverIp = config('app.server_ip', 'DEINE.SERVER.IP');
// $mxHost = config('mailwolt.mx_fqdn', 'mx.' . $this->domain->domain);
// $selector = optional(
// DkimKey::where('domain_id', $this->domain->id)->where('is_active', true)->first()
// )->selector ?? 'mwl1';
//
// $dkimTxt = optional(
// DkimKey::where('domain_id', $this->domain->id)->where('is_active', true)->first()
// )->public_key_txt ?? 'DKIM_PUBLIC_KEY';
//
// $this->records = [
// [
// 'type' => 'A',
// 'host' => $this->domain->domain,
// 'value' => $serverIp,
// 'ttl' => 3600,
// ],
// [
// 'type' => 'MX',
// 'host' => $this->domain->domain,
// 'value' => "10 {$mxHost}.",
// 'ttl' => 3600,
// ],
// [
// 'type' => 'TXT',
// 'host' => $this->domain->domain,
// 'value' => 'v=spf1 mx a -all',
// 'ttl' => 3600,
// ],
// [
// 'type' => 'TXT',
// 'host' => "{$selector}._domainkey." . $this->domain->domain,
// // komplette, fertige TXT-Payload (aus deiner dkim_keys.public_key_txt Spalte)
// 'value' => "v=DKIM1; k=rsa; p={$dkimTxt}",
// 'ttl' => 3600,
// ],
// [
// 'type' => 'TXT',
// 'host' => "_dmarc." . $this->domain->domain,
// 'value' => "v=DMARC1; p=none; rua=mailto:dmarc@" . $this->domain->domain . "; pct=100",
// 'ttl' => 3600,
// ],
// ];
// }
//
// public static function modalMaxWidth(): string
// {
// return '4xl'; // schön breit
// }
//
// public function render()
// {
// return view('livewire.ui.domain.modal.domain-dns-modal');
// }
// public Domain $domain;
//
// public static function modalMaxWidth(): string
// {
// return '3xl';
// }
//
// public function mount(int $domainId): void
// {
// $this->domain = Domain::with(['dkimKeys' /* falls Relationen existieren */])->findOrFail($domainId);
// }
//
// public function render()
// {
// // Hier kannst du die Records vorbereiten (SPF/DMARC/DKIM)
// $records = [
// [
// 'type' => 'TXT',
// 'host' => $this->domain->domain,
// 'value'=> $this->domain->spf_record ?? 'v=spf1 mx a -all',
// 'ttl' => 3600,
// ],
// [
// 'type' => 'TXT',
// 'host' => '_dmarc.' . $this->domain->domain,
// 'value'=> $this->domain->dmarc_record ?? 'v=DMARC1; p=none; rua=mailto:dmarc@' . $this->domain->domain . '; pct=100',
// 'ttl' => 3600,
// ],
// // DKIM (falls vorhanden)
// // Beispiel: nimm den aktiven Key oder den ersten
// ];
//
// $dkim = optional($this->domain->dkimKeys()->where('is_active', true)->first() ?? $this->domain->dkimKeys()->first());
// if ($dkim && $dkim->selector) {
// $records[] = [
// 'type' => 'TXT',
// 'host' => "{$dkim->selector}._domainkey." . $this->domain->domain,
// 'value'=> "v=DKIM1; k=rsa; p={$dkim->public_key_txt}",
// 'ttl' => 3600,
// ];
// }
//
// return view('livewire.ui.domain.modal.domain-dns-modal', [
// 'records' => $records,
// ]);
// }
// public function render()
// {
// return view('livewire.ui.domain.modal.domain-dns-modal');
// }
}