00e36df553
Invert level-2 semantics so domain limits apply to every client IP and application limits with trusted IPs raise the ceiling above the domain (still capped by level 1). Panel shows L1, validates maxima, and documents the model on Settings. Co-authored-by: Cursor <cursoragent@cursor.com>
128 lines
5.4 KiB
HTML
128 lines
5.4 KiB
HTML
{{/* Wide enough for credentials and DMARC settings side by side (see .split
|
|
in panel.css, as on a delivery's page). */}}
|
|
{{define "wide"}}wide{{end}}
|
|
|
|
{{define "content"}}
|
|
<h1>Settings</h1>
|
|
|
|
{{if .Flash}}<div class="flash">{{.Flash}}</div>{{end}}
|
|
{{if .Error}}<p class="error">{{.Error}}</p>{{end}}
|
|
|
|
{{if .ShowDMARC}}
|
|
<form method="post" action="/settings">
|
|
<div class="split">
|
|
<div class="card">
|
|
<h2>Panel credentials</h2>
|
|
<p class="muted">These are the credentials for this control panel only.
|
|
Applications keep their own logins and passwords, which are not affected.</p>
|
|
|
|
<label for="username">Username</label>
|
|
<input id="username" name="username" autocomplete="username"
|
|
autocapitalize="none" spellcheck="false" value="{{.FormUsername}}" required>
|
|
|
|
<label for="current_password">Current password</label>
|
|
<input id="current_password" name="current_password" type="password"
|
|
autocomplete="current-password" required>
|
|
|
|
<label for="new_password">New password</label>
|
|
<input id="new_password" name="new_password" type="password" autocomplete="new-password">
|
|
|
|
<label for="new_password_confirm">Confirm new password</label>
|
|
<input id="new_password_confirm" name="new_password_confirm" type="password" autocomplete="new-password">
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>DMARC aggregate reports</h2>
|
|
<p class="muted">Optional default <code>rua=</code> address for every sending
|
|
domain (can be overridden per domain). Use a mailbox on a domain that
|
|
receives inbound mail. SelfPost is send-only today; a future release will
|
|
be able to receive reports in the panel itself.</p>
|
|
|
|
<label for="dmarc_report_email">Default report address</label>
|
|
<input id="dmarc_report_email" name="dmarc_report_email" type="email"
|
|
autocomplete="email" autocapitalize="none" spellcheck="false"
|
|
value="{{.FormDMARCEmail}}" placeholder="reports@your-mail-domain.com">
|
|
|
|
{{if .FormDMARCEmail}}
|
|
<p class="muted">When <code>rua=</code> points at another domain, that hub
|
|
domain must publish a report-authorisation record so receivers will deliver
|
|
the XML aggregates.</p>
|
|
|
|
<label>Report authorization — host / name</label>
|
|
<div class="code-row">
|
|
<span class="code">{{.ReportAuthName}}</span>
|
|
<button type="button" class="copy">Copy</button>
|
|
</div>
|
|
|
|
<label>Report authorization — value</label>
|
|
<div class="code-row">
|
|
<span class="code">{{.ReportAuthExample}}</span>
|
|
<button type="button" class="copy">Copy</button>
|
|
</div>
|
|
|
|
{{if .ReportAuthDNS.Status}}
|
|
<label>Report authorization DNS <span class="st st-{{.ReportAuthDNS.Status}}">{{.ReportAuthDNS.Status}}</span></label>
|
|
<p class="{{if eq .ReportAuthDNS.Status "ok"}}muted{{else}}error{{end}}">{{.ReportAuthDNS.Detail}}</p>
|
|
{{if .ReportAuthDNS.Records}}<span class="code">{{range .ReportAuthDNS.Records}}{{.}}
|
|
{{end}}</span>{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit">Save changes</button>
|
|
<p class="muted">Leave both new-password fields empty to change the username
|
|
or DMARC address only. Changing the password signs out every other session;
|
|
this one stays signed in.</p>
|
|
</form>
|
|
{{else}}
|
|
<div class="card narrow">
|
|
<h2>Panel credentials</h2>
|
|
<p class="muted">These are the credentials for this control panel only.
|
|
Applications keep their own logins and passwords, which are not affected.</p>
|
|
<form method="post" action="/settings">
|
|
<label for="username">Username</label>
|
|
<input id="username" name="username" autocomplete="username"
|
|
autocapitalize="none" spellcheck="false" value="{{.FormUsername}}" required>
|
|
|
|
<label for="current_password">Current password</label>
|
|
<input id="current_password" name="current_password" type="password"
|
|
autocomplete="current-password" required>
|
|
|
|
<label for="new_password">New password</label>
|
|
<input id="new_password" name="new_password" type="password" autocomplete="new-password">
|
|
|
|
<label for="new_password_confirm">Confirm new password</label>
|
|
<input id="new_password_confirm" name="new_password_confirm" type="password" autocomplete="new-password">
|
|
|
|
<button type="submit">Save changes</button>
|
|
</form>
|
|
<p class="muted">Leave both new-password fields empty to change the username
|
|
only. Changing the password signs out every other session;
|
|
this one stays signed in.</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="card" id="rate-limits">
|
|
<h2>Sending rate limits</h2>
|
|
<p class="muted">Configured in <code>.env</code> / Compose; restart the
|
|
container to change level 1. Domain and application ceilings are set on
|
|
each domain's page.</p>
|
|
|
|
<label>Level 1 — per client IP (Postfix)</label>
|
|
<p><strong>{{.L1Messages}}</strong> messages per <strong>{{.L1Window}}</strong>
|
|
seconds (<code>RATE_LIMIT_MESSAGES_PER_IP</code> /
|
|
<code>RATE_LIMIT_WINDOW_SECONDS</code>). Hard ceiling for every connecting IP;
|
|
the panel cannot raise a domain or application limit above this.</p>
|
|
|
|
<label>Level 2 — domain</label>
|
|
<p class="muted">Optional ceiling for <em>all</em> senders on a domain. When
|
|
unset, only level 1 applies. Must be ≤ level 1.</p>
|
|
|
|
<label>Level 2 — application (trusted IPs)</label>
|
|
<p class="muted">Optional override: list client IPs and a ceiling
|
|
<em>strictly above</em> the domain limit (still ≤ level 1). Those IPs
|
|
skip the domain check; everyone else stays under the domain (or level 1).</p>
|
|
</div>
|
|
{{end}}
|