mailwolt/resources/views/livewire/ui/security/ssl-certificates-table.blad...

219 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<x-slot:breadcrumbParent>Sicherheit</x-slot:breadcrumbParent>
<x-slot:breadcrumb>SSL/TLS</x-slot:breadcrumb>
<div>
@if($sslProvisioning)
<div wire:poll.2s="pollSsl"></div>
@endif
<div class="mbx-page-header">
<div class="mbx-page-title">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<rect x="1.5" y="6" width="13" height="8.5" rx="1.8" stroke="currentColor" stroke-width="1.3"/>
<path d="M5 6V4.5a3 3 0 0 1 6 0V6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>
<circle cx="8" cy="10.5" r="1" fill="currentColor"/>
</svg>
SSL/TLS
@php $realCerts = array_filter($certs, fn($c) => !isset($c['_error'])); @endphp
<span class="mbx-total-badge">{{ count($realCerts) }}</span>
</div>
<div class="mbx-page-actions">
<button wire:click="refresh" class="mbx-act-btn" title="Aktualisieren">
<svg width="13" height="13" viewBox="0 0 14 14" fill="none">
<path d="M12 7A5 5 0 1 1 9 2.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
<path d="M9 .5l2.5 2L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</div>
<div class="sec-layout">
{{-- ═══ Links (breit): Ausgestellte Zertifikate ═══ --}}
<div style="min-width:0">
<div class="mbx-sections">
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Ausgestellte Zertifikate</span>
</div>
</div>
@php $unavailable = !empty($certs) && isset($certs[0]['_error']); @endphp
@if($unavailable)
<div style="padding:24px 16px;text-align:center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" style="color:rgba(239,68,68,.5);margin:0 auto 8px;display:block"><rect x="2" y="8" width="20" height="13" rx="2.5" stroke="currentColor" stroke-width="1.4"/><path d="M7 8V6a5 5 0 0 1 10 0v2" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
<div style="font-size:12.5px;color:var(--mw-t3)">certbot nicht erreichbar</div>
<div style="font-size:11px;color:var(--mw-t4);margin-top:4px">sudo-Recht für <code style="font-size:10px">/usr/bin/certbot</code> fehlt</div>
</div>
@elseif(empty($realCerts))
<div style="padding:28px 16px;text-align:center">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" style="color:var(--mw-t4);margin:0 auto 10px;display:block"><rect x="2" y="8" width="20" height="13" rx="2.5" stroke="currentColor" stroke-width="1.4"/><path d="M7 8V6a5 5 0 0 1 10 0v2" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
<div style="font-size:12.5px;color:var(--mw-t3)">Noch keine Zertifikate</div>
<div style="font-size:11px;color:var(--mw-t4);margin-top:4px">Rechts auf "Einrichten" klicken</div>
</div>
@else
<div class="mbx-table-wrap">
<table class="mbx-table">
<thead>
<tr>
<th class="mbx-th">Name / Pfad</th>
<th class="mbx-th">Domains</th>
<th class="mbx-th" style="width:120px">Gültig bis</th>
<th class="mbx-th" style="width:90px">Status</th>
<th class="mbx-th mbx-th-right" style="width:50px"></th>
</tr>
</thead>
<tbody>
@foreach($realCerts as $cert)
<tr class="mbx-tr">
<td class="mbx-td">
<span class="dom-name">{{ $cert['name'] }}</span>
@if($cert['cert_path'])
<div style="font-size:10px;color:var(--mw-t4);margin-top:2px;font-family:monospace">{{ $cert['cert_path'] }}</div>
@endif
</td>
<td class="mbx-td">
<div class="ssl-domains">
@foreach($cert['domains'] as $d)
<span class="ssl-domain-pill">{{ $d }}</span>
@endforeach
</div>
</td>
<td class="mbx-td">
@if($cert['expiry_date'])
<span style="font-size:12px;color:var(--mw-t2)">{{ $cert['expiry_date'] }}</span>
@if($cert['days_left'] !== null)
<div style="font-size:10.5px;color:var(--mw-t4);margin-top:1px">{{ $cert['days_left'] }} Tage</div>
@endif
@elseif($cert['days_left'] !== null)
<span style="color:var(--mw-t3)">{{ $cert['days_left'] }} Tage</span>
@else
<span style="color:var(--mw-t4)"></span>
@endif
</td>
<td class="mbx-td">
@if($cert['expired'])
<span class="mbx-badge-warn">Abgelaufen</span>
@elseif($cert['days_left'] !== null && $cert['days_left'] < 14)
<span class="mbx-badge-warn">Bald fällig</span>
@else
<span class="mbx-badge-ok">Gültig</span>
@endif
</td>
<td class="mbx-td">
<div class="mbx-actions">
<button wire:click="renew('{{ $cert['name'] }}')"
class="mbx-act-btn" title="Zertifikat erneuern"
wire:confirm="Zertifikat {{ $cert['name'] }} jetzt erneuern?">
<svg width="13" height="13" viewBox="0 0 14 14" fill="none"><path d="M12 7A5 5 0 1 1 9 2.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><path d="M9 .5l2.5 2L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
</div>
</div>
{{-- ═══ Rechts (schmal): Let's Encrypt einrichten ═══ --}}
<div style="min-width:0">
<div class="mbx-sections">
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Let's Encrypt einrichten</span>
</div>
</div>
<div style="padding:12px 14px;display:flex;flex-direction:column;gap:10px">
{{-- Nur Schloss + Domain --}}
@php
$domainMap = [
['domain' => $uiDomain],
['domain' => $webmailDomain],
['domain' => $mailDomain],
];
@endphp
<div style="display:flex;flex-direction:column;gap:5px">
@foreach($domainMap as $info)
@php
$d = $info['domain'];
$certOk = $d && (file_exists("/etc/letsencrypt/renewal/{$d}.conf") || is_dir("/etc/letsencrypt/live/{$d}"));
@endphp
<div style="display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;background:var(--mw-bg3);border:1px solid var(--mw-b2)">
@if($certOk)
<svg width="13" height="13" viewBox="0 0 14 14" fill="none" style="flex-shrink:0;color:#22c55e"><rect x="1.5" y="6" width="11" height="7.5" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M4.5 6V4.5a2.5 2.5 0 0 1 5 0V6" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><path d="M5 9.5l1.3 1.3 2.7-2.7" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
@elseif($d)
<svg width="13" height="13" viewBox="0 0 14 14" fill="none" style="flex-shrink:0;color:#f87171"><rect x="1.5" y="6" width="11" height="7.5" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M4.5 6V4.5a2.5 2.5 0 0 1 5 0V6" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
@else
<svg width="13" height="13" viewBox="0 0 14 14" fill="none" style="flex-shrink:0;color:var(--mw-t4)"><rect x="1.5" y="6" width="11" height="7.5" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M4.5 6V4.5a2.5 2.5 0 0 1 5 0V6" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
@endif
<span style="font-size:11px;color:var(--mw-t3);font-family:monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ $d ?: '—' }}</span>
</div>
@endforeach
</div>
{{-- Fortschritt --}}
@if($sslProvisioning || $sslDone)
<div style="display:flex;flex-direction:column;gap:5px;padding:9px 11px;border-radius:7px;background:rgba(99,102,241,.06);border:1px solid rgba(99,102,241,.2)">
<div style="font-size:11px;font-weight:600;color:var(--mw-t2);margin-bottom:1px">
{{ $sslProvisioning ? 'Läuft…' : 'Abgeschlossen' }}
</div>
@foreach(['ui' => 'UI', 'webmail' => 'Webmail', 'mail' => 'Mailserver'] as $key => $label)
@php $st = $sslProgress[$key] ?? 'pending'; @endphp
<div style="display:flex;align-items:center;gap:7px">
@if($st === 'done')
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" style="flex-shrink:0;color:#22c55e"><circle cx="6" cy="6" r="5" stroke="currentColor" stroke-width="1.1"/><path d="M3.5 6l1.8 1.8 3.2-3.2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
@elseif($st === 'error' || $st === 'nodns')
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" style="flex-shrink:0;color:#f87171"><circle cx="6" cy="6" r="5" stroke="currentColor" stroke-width="1.1"/><path d="M4 4l4 4M8 4l-4 4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
@elseif($st === 'running')
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" style="flex-shrink:0;color:#818cf8;animation:spin 1s linear infinite"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.3" stroke-dasharray="14 7" stroke-linecap="round"/></svg>
@else
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" style="flex-shrink:0;color:var(--mw-t4)"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.1" stroke-dasharray="3 3"/></svg>
@endif
@php
$stSuffix = $st==='nodns' ? ' kein DNS' : ($st==='error' ? ' Fehler' : '');
$stColor = in_array($st,['error','nodns']) ? '#f87171' : ($st==='done' ? '#22c55e' : 'var(--mw-t4)');
@endphp
<span style="font-size:10.5px;color:{{ $stColor }}">{{ $label }}{{ $stSuffix }}</span>
</div>
@endforeach
</div>
@endif
{{-- Button --}}
@if(!$uiDomain || !$webmailDomain || !$mailDomain)
<p style="font-size:11px;color:var(--mw-t4);margin:0">
Erst alle Domains unter <a href="{{ route('ui.system.settings') }}" style="color:var(--mw-v)">Einstellungen</a> speichern.
</p>
@else
<button wire:click="startSslProvisioning"
wire:loading.attr="disabled"
wire:target="startSslProvisioning"
@disabled($sslProvisioning)
class="{{ $sslDone ? 'mw-btn-secondary' : 'mw-btn-primary' }}"
style="width:100%;justify-content:center">
<svg width="12" height="12" viewBox="0 0 14 14" fill="none"><rect x="1.5" y="6" width="11" height="7.5" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M4.5 6V4.5a2.5 2.5 0 0 1 5 0V6" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
<span wire:loading.remove wire:target="startSslProvisioning">
@if($sslProvisioning) Läuft…
@elseif($sslDone) Erneut einrichten
@else Zertifikate einrichten
@endif
</span>
<span wire:loading wire:target="startSslProvisioning">Startet…</span>
</button>
@endif
</div>
</div>
</div>
</div>
</div>
</div>