219 lines
16 KiB
PHP
219 lines
16 KiB
PHP
<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>
|