Files
selfpost/internal/web/view/templates/settings.html
T
mix 00e36df553 rate limit: domain ceiling for all IPs, trusted app override
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>
2026-08-12 23:19:51 +03:00

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&nbsp;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&nbsp;1 applies. Must be ≤ level&nbsp;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&nbsp;1). Those IPs
skip the domain check; everyone else stays under the domain (or level&nbsp;1).</p>
</div>
{{end}}