305 lines
19 KiB
HTML
305 lines
19 KiB
HTML
{{define "webmail_certs.html"}}
|
|
<!DOCTYPE html>
|
|
<html lang="en" data-bs-theme="dark">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Settings - Webmail</title>
|
|
<link href="/webmail/static/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="/webmail/static/vendor/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
|
|
<link href="/webmail/static/vendor/quill/quill.snow.css" rel="stylesheet">
|
|
<style>
|
|
body { background-color: #1a1a1a; color: #e0e0e0; }
|
|
.table-dark { --bs-table-bg: #2d2d2d; --bs-table-border-color: #404040; }
|
|
</style>
|
|
{{template "webmail_settings_style" .}}
|
|
</head>
|
|
<body>
|
|
{{template "csrf_script" .}}
|
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
<div class="container-fluid">
|
|
<span class="navbar-brand mb-0 h1"><i class="bi bi-inbox-fill me-2"></i>Webmail <small class="text-muted">{{.mailbox.Email}}</small></span>
|
|
<div class="navbar-nav flex-row gap-2 ms-auto">
|
|
<a href="/webmail/mail/INBOX" class="btn btn-outline-light btn-sm"><i class="bi bi-envelope me-1"></i>Mail</a>
|
|
<button type="button" onclick="openCompose('/webmail/mail/compose')" class="btn btn-outline-light btn-sm"><i class="bi bi-pencil-square me-1"></i>Compose</button>
|
|
<form method="post" action="/webmail/logout" class="d-inline">
|
|
<button type="submit" class="btn btn-outline-light btn-sm"><i class="bi bi-box-arrow-right me-1"></i>Sign out</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 1090;">
|
|
{{range .flashes}}
|
|
<div class="toast align-items-center text-bg-{{if eq .Category "error"}}danger{{else}}{{.Category}}{{end}} border-0" role="alert" aria-live="assertive" aria-atomic="true">
|
|
<div class="d-flex">
|
|
<div class="toast-body">
|
|
<i class="bi bi-{{if eq .Category "error"}}exclamation-triangle{{else if eq .Category "success"}}check-circle{{else}}info-circle{{end}} me-2"></i>
|
|
{{.Message}}
|
|
</div>
|
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div id="settingsPanelRoot">
|
|
<div class="settings-card" id="settingsPanel">
|
|
<div class="settings-card-header">
|
|
<h5 class="mb-0"><i class="bi bi-sliders me-2"></i>Settings</h5>
|
|
<button type="button" class="btn-close btn-close-white" onclick="closeSettings()" aria-label="Close"></button>
|
|
</div>
|
|
<div class="settings-card-body">
|
|
{{template "webmail_settings_nav" .}}
|
|
<div class="settings-body">
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle me-2"></i>Two separate systems live here, each doing one job: <strong>S/MIME certificates sign</strong> outgoing mail (proves it came from you and wasn't altered) — <strong>PGP keys encrypt</strong> it (only the recipient can read it). They're different standards with different key formats; a message can use either, both, or neither. PGP private keys are protected by their own passphrase (never stored anywhere), so you'll be asked for it the first time you use one each session.
|
|
</div>
|
|
|
|
<h6 class="text-uppercase text-muted mb-2"><i class="bi bi-pen me-1"></i>S/MIME Certificates <small>— for signing</small></h6>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header"><h6 class="mb-0"><i class="bi bi-person-badge me-2"></i>Your Certificates</h6></div>
|
|
<div class="card-body">
|
|
{{if .identities}}
|
|
<div class="table-responsive mb-3">
|
|
<table class="table table-dark table-hover mb-0">
|
|
<thead><tr><th>Expires</th><th>Actions</th></tr></thead>
|
|
<tbody>
|
|
{{range .identities}}
|
|
<tr>
|
|
<td>{{.NotAfter.Format "2006-01-02"}}</td>
|
|
<td class="d-flex gap-2">
|
|
<a href="/webmail/smime/identity/{{.ID}}/download" class="btn btn-outline-light btn-sm"><i class="bi bi-download me-1"></i>Download</a>
|
|
<form method="post" action="/webmail/smime/identity/{{.ID}}/remove" class="d-inline">
|
|
<button type="submit" class="btn btn-outline-danger btn-sm" data-confirm="Remove this S/MIME certificate? Mail signed with it will no longer verify."><i class="bi bi-trash me-1"></i>Remove</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{else}}
|
|
<p class="text-muted">No S/MIME certificates yet. Generate a free self-signed certificate, or import one you already have (.p12/.pfx).</p>
|
|
{{end}}
|
|
|
|
<hr class="my-3">
|
|
|
|
<div class="row g-4">
|
|
<div class="col-md-6">
|
|
<h6>Generate New</h6>
|
|
<form method="post" action="/webmail/smime/identity/generate" class="row g-2">
|
|
<div class="col-12">
|
|
<button type="submit" class="btn btn-primary btn-sm"><i class="bi bi-magic me-1"></i>Generate Self-Signed Certificate</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Import Existing (.p12 / .pfx)</h6>
|
|
<form method="post" action="/webmail/smime/identity/import" enctype="multipart/form-data" class="row g-2">
|
|
<div class="col-12">
|
|
<input type="file" class="form-control form-control-sm" name="p12_file" accept=".p12,.pfx" required>
|
|
</div>
|
|
<div class="col-12">
|
|
<input type="password" class="form-control form-control-sm" name="p12_password" placeholder=".p12 export password (if any)">
|
|
</div>
|
|
<div class="col-12">
|
|
<button type="submit" class="btn btn-secondary btn-sm">Import</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header"><h6 class="mb-0"><i class="bi bi-people me-2"></i>S/MIME Contact Certificates</h6></div>
|
|
<div class="card-body">
|
|
<form method="post" action="/webmail/smime/contacts/add" enctype="multipart/form-data" class="row g-2 align-items-end mb-3">
|
|
<div class="col-auto">
|
|
<label class="form-label">Email</label>
|
|
<input type="email" class="form-control form-control-sm" name="email" placeholder="someone@example.com" required>
|
|
</div>
|
|
<div class="col-auto">
|
|
<label class="form-label">Certificate (.pem/.crt/.cer)</label>
|
|
<input type="file" class="form-control form-control-sm" name="cert_file" accept=".pem,.crt,.cer" required>
|
|
</div>
|
|
<div class="col-auto">
|
|
<button type="submit" class="btn btn-success btn-sm"><i class="bi bi-plus-circle me-1"></i>Add Contact</button>
|
|
</div>
|
|
</form>
|
|
|
|
{{if .contacts}}
|
|
<div class="table-responsive">
|
|
<table class="table table-dark table-hover mb-0">
|
|
<thead><tr><th>Email</th><th>Added</th><th>Actions</th></tr></thead>
|
|
<tbody>
|
|
{{range .contacts}}
|
|
<tr>
|
|
<td>{{.Email}}</td>
|
|
<td>{{.CreatedAt.Format "2006-01-02"}}</td>
|
|
<td>
|
|
<form method="post" action="/webmail/smime/contacts/{{.ID}}/remove" class="d-inline">
|
|
<button type="submit" class="btn btn-outline-danger btn-sm" title="Remove" data-confirm="Remove this contact's certificate?"><i class="bi bi-trash"></i></button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{else}}
|
|
<p class="text-muted mb-0">No contact certificates yet. They're also captured automatically when you open a validly signed email from someone new.</p>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<h6 class="text-uppercase text-muted mb-2"><i class="bi bi-lock me-1"></i>PGP Keys <small>— for encryption</small></h6>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header"><h6 class="mb-0"><i class="bi bi-key me-2"></i>Your Keys</h6></div>
|
|
<div class="card-body">
|
|
{{if .pgp_identities}}
|
|
<div class="table-responsive mb-3">
|
|
<table class="table table-dark table-hover mb-0">
|
|
<thead><tr><th>Label</th><th>Fingerprint</th><th>Status</th><th>Actions</th></tr></thead>
|
|
<tbody>
|
|
{{range .pgp_identities}}
|
|
<tr>
|
|
<td>{{if .Label}}{{.Label}}{{else}}<span class="text-muted">(no label)</span>{{end}}</td>
|
|
<td><code class="small">{{.Fingerprint}}</code></td>
|
|
<td>{{if index $.pgp_unlocked .ID}}<span class="badge bg-success">Unlocked this session</span>{{else}}<span class="badge bg-secondary">Locked</span>{{end}}</td>
|
|
<td class="d-flex gap-2">
|
|
<a href="/webmail/pgp/identity/{{.ID}}/download" class="btn btn-outline-light btn-sm"><i class="bi bi-download me-1"></i>Download Public Key</a>
|
|
<form method="post" action="/webmail/pgp/identity/{{.ID}}/remove" class="d-inline">
|
|
<button type="submit" class="btn btn-outline-danger btn-sm" data-confirm="Remove this PGP key? Mail encrypted to it will no longer decrypt."><i class="bi bi-trash me-1"></i>Remove</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{else}}
|
|
<p class="text-muted">No PGP keys yet. Generate a new keypair, or import one you already have (an ASCII-armored .asc export from e.g. GnuPG).</p>
|
|
{{end}}
|
|
|
|
<hr class="my-3">
|
|
|
|
<div class="row g-4">
|
|
<div class="col-md-6">
|
|
<h6>Generate New</h6>
|
|
<form method="post" action="/webmail/pgp/identity/generate" class="row g-2">
|
|
<div class="col-12">
|
|
<input type="text" class="form-control form-control-sm" name="label" placeholder="Label (e.g. "Work") — optional, helps tell keys apart">
|
|
</div>
|
|
<div class="col-12">
|
|
<input type="password" class="form-control form-control-sm" name="passphrase" placeholder="Choose a passphrase (min 8 chars)" required minlength="8">
|
|
</div>
|
|
<div class="col-12">
|
|
<input type="password" class="form-control form-control-sm" name="passphrase_confirm" placeholder="Confirm passphrase" required minlength="8">
|
|
</div>
|
|
<div class="col-12">
|
|
<button type="submit" class="btn btn-primary btn-sm"><i class="bi bi-magic me-1"></i>Generate PGP Key</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Import Existing (.asc)</h6>
|
|
<form method="post" action="/webmail/pgp/identity/import" enctype="multipart/form-data" class="row g-2">
|
|
<div class="col-12">
|
|
<input type="text" class="form-control form-control-sm" name="label" placeholder="Label — optional">
|
|
</div>
|
|
<div class="col-12">
|
|
<input type="file" class="form-control form-control-sm" name="key_file" accept=".asc,.pem,.gpg" required>
|
|
</div>
|
|
<div class="col-12">
|
|
<input type="password" class="form-control form-control-sm" name="passphrase" placeholder="The key's passphrase (its own, or a new one if it has none)" required>
|
|
</div>
|
|
<div class="col-12">
|
|
<button type="submit" class="btn btn-secondary btn-sm">Import</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header"><h6 class="mb-0"><i class="bi bi-people me-2"></i>PGP Contact Keys</h6></div>
|
|
<div class="card-body">
|
|
<form method="post" action="/webmail/pgp/contacts/add" enctype="multipart/form-data" class="row g-2 align-items-end mb-3">
|
|
<div class="col-auto">
|
|
<label class="form-label">Email</label>
|
|
<input type="email" class="form-control form-control-sm" name="email" placeholder="someone@example.com" required>
|
|
</div>
|
|
<div class="col-auto">
|
|
<label class="form-label">Label</label>
|
|
<input type="text" class="form-control form-control-sm" name="label" placeholder="optional">
|
|
</div>
|
|
<div class="col-auto">
|
|
<label class="form-label">Public Key (.asc)</label>
|
|
<input type="file" class="form-control form-control-sm" name="key_file" accept=".asc,.pem,.gpg" required>
|
|
</div>
|
|
<div class="col-auto">
|
|
<button type="submit" class="btn btn-success btn-sm"><i class="bi bi-plus-circle me-1"></i>Add Contact</button>
|
|
</div>
|
|
</form>
|
|
|
|
{{if .pgp_contacts}}
|
|
<div class="table-responsive">
|
|
<table class="table table-dark table-hover mb-0">
|
|
<thead><tr><th>Email</th><th>Label</th><th>Fingerprint</th><th>Added</th><th>Actions</th></tr></thead>
|
|
<tbody>
|
|
{{range .pgp_contacts}}
|
|
<tr>
|
|
<td>{{.Email}}</td>
|
|
<td>{{.Label}}</td>
|
|
<td><code class="small">{{.Fingerprint}}</code></td>
|
|
<td>{{.CreatedAt.Format "2006-01-02"}}</td>
|
|
<td>
|
|
<form method="post" action="/webmail/pgp/contacts/{{.ID}}/remove" class="d-inline">
|
|
<button type="submit" class="btn btn-outline-danger btn-sm" title="Remove" data-confirm="Remove this contact's PGP key?"><i class="bi bi-trash"></i></button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{else}}
|
|
<p class="text-muted mb-0">No contact keys yet. Ask a sender for their public key export, or grab it from a keyserver, and add it here before you can encrypt mail to them.</p>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal fade" id="confirmationModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="bi bi-question-circle me-2"></i>Confirm Action</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body" id="confirmationModalBody">Are you sure you want to proceed?</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-danger" id="confirmationModalConfirm">Confirm</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{template "compose_widget" .}}
|
|
|
|
<script src="/webmail/static/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
|
<script src="/webmail/static/vendor/quill/quill.js"></script>
|
|
{{template "webmail_settings_script" .}}
|
|
</body>
|
|
</html>
|
|
{{end}}
|