e2f56b8cc8
Flask WebUI behind nginx reverse proxy with zone-based firewall, DHCP, WireGuard, and ACME certificate management.
77 lines
3.3 KiB
HTML
77 lines
3.3 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Certificates - Vacuum Wall{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="page-header">
|
|
<div>
|
|
<h1>Certificates</h1>
|
|
<div class="subtitle">SSL/TLS certificate management</div>
|
|
</div>
|
|
<button class="btn btn-primary" onclick="openModal('issue-cert-modal')">+ Issue New Certificate</button>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Domain</th>
|
|
<th>Issuer</th>
|
|
<th>Expiry Date</th>
|
|
<th>Days Left</th>
|
|
<th style="width:120px;">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for cert in (certs or []) %}
|
|
<tr>
|
|
<td><strong>{{ cert.get('domain', 'unknown') }}</strong></td>
|
|
<td class="text-sm">{{ cert.get('issuer', '-') }}</td>
|
|
<td>{{ cert.get('expiry', 'N/A') }}</td>
|
|
<td>
|
|
{% set days = cert.get('days_remaining') %}
|
|
{% if cert.get('expired') or (days is not none and days <= 0) %}
|
|
<span class="badge badge-danger">Expired{% if days %} ({{ days }}d ago){% endif %}</span>
|
|
{% elif days is not none and days <= 30 %}
|
|
<span class="badge badge-warning">{{ days }} days</span>
|
|
{% else %}
|
|
<span class="badge badge-success">{{ days }} days</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<form hx-post="/api/certs/renew/{{ cert.get('domain', '') }}" hx-swap="none" class="htmx-on-success" data-success="Renewal started for {{ cert.domain }}" onsuccess="setTimeout(function(){ location.reload(); }, 2000);">
|
|
<button type="submit" class="btn btn-sm btn-outline">Renew</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% if not (certs or []) %}
|
|
<tr>
|
|
<td colspan="5" class="text-muted text-sm">No certificates found. Issue a certificate to get started.</td>
|
|
</tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Issue Certificate Modal -->
|
|
<div class="modal-overlay" id="issue-cert-modal" onclick="if(event.target===this) closeModal('issue-cert-modal')">
|
|
<div class="modal">
|
|
<h2>Issue New Certificate</h2>
|
|
<form hx-post="/api/certs/issue" hx-swap="none" class="htmx-on-success" data-success="Certificate issuance started" onsuccess="setTimeout(function(){closeModal('issue-cert-modal'); location.reload();}, 500);">
|
|
<div class="form-group">
|
|
<label for="cert-domain">Domain</label>
|
|
<input type="text" id="cert-domain" name="domain" placeholder="example.com" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="cert-email">Contact Email</label>
|
|
<input type="email" id="cert-email" name="email" placeholder="admin@example.com" value="{{ (email or '') | e }}">
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" class="btn btn-outline" onclick="closeModal('issue-cert-modal')">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Issue</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|