Fix: Mailbox Stats über Dovecot mit config/mailpool.php

main v1.0.97
boban 2025-10-29 04:23:41 +01:00
parent 3c1093311c
commit aaae226c8d
2 changed files with 107 additions and 55 deletions

View File

@ -25,7 +25,7 @@ class DnsHealthCard extends Component
public function refresh(): void public function refresh(): void
{ {
$this->load(true); $this->load();
} }
public function openDnsModal(int $domainId): void public function openDnsModal(int $domainId): void
@ -33,62 +33,108 @@ class DnsHealthCard extends Component
$this->dispatch('openModal', component: 'ui.domain.modal.domain-dns-modal', arguments: ['domainId' => $domainId]); $this->dispatch('openModal', component: 'ui.domain.modal.domain-dns-modal', arguments: ['domainId' => $domainId]);
} }
protected function load(bool $force = false): void // protected function load(bool $force = false): void
// {
// [$this->mtaHost, $this->tlsa, $this->rows] = Cache::remember('dash.dnshealth.v2', $force ? 1 : 600, function () {
//
// $base = trim((string) env('BASE_DOMAIN', ''));
// $mtaSub = trim((string) env('MTA_SUB', 'mx'));
// $mtaHost = $base !== '' ? "{$mtaSub}.{$base}" : $mtaSub; // z.B. mx.nexlab.at
//
// // ▼ gewünschter Filter:
// $domains = Domain::query()
// ->where('is_active', true)
// ->where('is_server', false) // <<< Server-Domain sauber ausschließen
// ->orderBy('domain')
// ->get(['id', 'domain']);
//
// $rows = [];
// foreach ($domains as $d) {
// $dom = $d->domain;
//
// // DKIM-Selector ermitteln: .env > DB > Fallback null
// $selector = trim((string) env('DKIM_SELECTOR', ''));
// if ($selector === '') {
// $selector = (string) DB::table('dkim_keys')
// ->where('domain_id', $d->id)
// ->where('is_active', 1)
// ->orderByDesc('id')
// ->value('selector') ?? '';
// }
//
// $missing = [];
//
// if (!$this->mxPointsTo($dom, [$mtaHost])) $missing[] = 'MX';
// if (!$this->hasSpf($dom)) $missing[] = 'SPF';
// if (!$this->hasDkim($dom, $selector)) $missing[] = 'DKIM';
// if (!$this->hasTxt("_dmarc.$dom")) $missing[] = 'DMARC';
//
// $rows[] = [
// 'id' => (int) $d->id,
// 'name' => $dom,
// 'ok' => empty($missing),
// 'missing' => $missing,
// ];
// }
//
// // Hostweites TLSA (nur Hinweis)
// $tlsa = $this->hasTlsa("_25._tcp.$mtaHost") || $this->hasTlsa("_465._tcp.$mtaHost") || $this->hasTlsa("_587._tcp.$mtaHost");
//
// return [$mtaHost, $tlsa, $rows];
// });
// }
protected function load(): void
{ {
[$this->mtaHost, $this->tlsa, $this->rows] = Cache::remember('dash.dnshealth.v2', $force ? 1 : 600, function () { $base = trim((string) env('BASE_DOMAIN', ''));
$mtaSub = trim((string) env('MTA_SUB', 'mx'));
$mtaHost = $base !== '' ? "{$mtaSub}.{$base}" : $mtaSub; // z.B. mx.nexlab.at
$base = trim((string) env('BASE_DOMAIN', '')); // nur aktive, NICHT-Server-Domains (System + Custom, solange is_server = false)
$mtaSub = trim((string) env('MTA_SUB', 'mx')); $domains = Domain::query()
$mtaHost = $base !== '' ? "{$mtaSub}.{$base}" : $mtaSub; // z.B. mx.nexlab.at ->where('is_active', true)
->where('is_server', false)
->orderBy('domain')
->get(['id','domain']);
// ▼ gewünschter Filter: $rows = [];
$domains = Domain::query()
->where('is_active', true)
->where(function ($q) {
$q->where('is_system', false)
->orWhere(function ($q2) {
$q2->where('is_system', true)->where('is_server', false);
});
})
->orderBy('domain')
->get(['id', 'domain']);
$rows = []; foreach ($domains as $d) {
foreach ($domains as $d) { $dom = $d->domain;
$dom = $d->domain;
// DKIM-Selector ermitteln: .env > DB > Fallback null // DKIM-Selector: .env > DB > leer
$selector = trim((string) env('DKIM_SELECTOR', '')); $selector = trim((string) env('DKIM_SELECTOR', ''));
if ($selector === '') { if ($selector === '') {
$selector = (string) DB::table('dkim_keys') $selector = (string) DB::table('dkim_keys')
->where('domain_id', $d->id) ->where('domain_id', $d->id)
->where('is_active', 1) ->where('is_active', 1)
->orderByDesc('id') ->orderByDesc('id')
->value('selector') ?? ''; ->value('selector') ?? '';
}
$missing = [];
if (!$this->mxPointsTo($dom, [$mtaHost])) $missing[] = 'MX';
if (!$this->hasSpf($dom)) $missing[] = 'SPF';
if (!$this->hasDkim($dom, $selector)) $missing[] = 'DKIM';
if (!$this->hasTxt("_dmarc.$dom")) $missing[] = 'DMARC';
$rows[] = [
'id' => (int) $d->id,
'name' => $dom,
'ok' => empty($missing),
'missing' => $missing,
];
} }
// Hostweites TLSA (nur Hinweis) $missing = [];
$tlsa = $this->hasTlsa("_25._tcp.$mtaHost") || $this->hasTlsa("_465._tcp.$mtaHost") || $this->hasTlsa("_587._tcp.$mtaHost"); if (!$this->mxPointsTo($dom, [$mtaHost])) $missing[] = 'MX';
if (!$this->hasSpf($dom)) $missing[] = 'SPF';
if (!$this->hasDkim($dom, $selector)) $missing[] = 'DKIM';
if (!$this->hasTxt("_dmarc.$dom")) $missing[] = 'DMARC';
return [$mtaHost, $tlsa, $rows]; $rows[] = [
}); 'id' => (int) $d->id,
'name' => $dom,
'ok' => empty($missing),
'missing' => $missing,
];
}
// Hostweites TLSA (nur Info)
$tlsa = $this->hasTlsa("_25._tcp.$mtaHost")
|| $this->hasTlsa("_465._tcp.$mtaHost")
|| $this->hasTlsa("_587._tcp.$mtaHost");
$this->mtaHost = $mtaHost;
$this->tlsa = $tlsa;
$this->rows = $rows;
} }
/* ── DNS Helpers ───────────────────────────────────────────────────── */ /* ── DNS Helpers ───────────────────────────────────────────────────── */
protected function digShort(string $type, string $name): string protected function digShort(string $type, string $name): string
@ -119,13 +165,22 @@ class DnsHealthCard extends Component
// ▼ DKIM: bevorzugt konkreten Selector prüfen; wenn leer, versuche Policy (_domainkey) // ▼ DKIM: bevorzugt konkreten Selector prüfen; wenn leer, versuche Policy (_domainkey)
protected function hasDkim(string $domain, string $selector = ''): bool protected function hasDkim(string $domain, string $selector = ''): bool
{ {
if ($selector !== '') { if ($selector !== '' && $this->hasTxt("{$selector}._domainkey.$domain")) {
return $this->hasTxt("{$selector}._domainkey.$domain"); return true;
} }
// Manche Betreiber veröffentlichen eine Policy auf _domainkey.<dom> // Fallback: irgendein _domainkey-TXT vorhanden
return $this->hasTxt("_domainkey.$domain"); return $this->hasTxt("_domainkey.$domain");
} }
// protected function hasDkim(string $domain, string $selector = ''): bool
// {
// if ($selector !== '') {
// return $this->hasTxt("{$selector}._domainkey.$domain");
// }
// // Manche Betreiber veröffentlichen eine Policy auf _domainkey.<dom>
// return $this->hasTxt("_domainkey.$domain");
// }
protected function mxPointsTo(string $domain, array $allowedHosts): bool protected function mxPointsTo(string $domain, array $allowedHosts): bool
{ {
$out = $this->digShort('MX', $domain); $out = $this->digShort('MX', $domain);

View File

@ -6,10 +6,7 @@
</div> </div>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<button wire:click="refresh" <button wire:click="refresh"
class="inline-flex items-center gap-1.5 rounded-full text-[12px] px-3 py-1.5 class="px-3 py-1.5 text-[12px] rounded-lg bg-white/5 border border-white/10 hover:bg-white/10">
text-white/80 bg-white/10 border border-white/15
hover:bg-white/15 hover:text-white transition">
<i class="ph ph-arrows-clockwise text-[13px]"></i>
Neu prüfen Neu prüfen
</button> </button>
</div> </div>