fc53ae1314
Phase 12 (UI/UX). The navigation bar now renders once from layout.html instead of being copied into each content template, so it is present on every authenticated page — including the domain page and its delete confirmation, which had no links at all — and the current page is highlighted via .Active rather than quietly dropping out of the list. New /account page changes the administrator's username and/or password: the current password is required and the attempt is throttled on the same limiter as the login form, so this route cannot be used to brute-force past that limit. A password change invalidates every other session while keeping the one performing it; a rename carries that session over. Backup and domain import move from a card in the middle of the domain list to their own /backup page, one card each; the handlers themselves are unchanged, only the page the import form renders its errors on. The domain page gains a "Sending server settings" card (server, port, encryption) so a client can be configured without reading the docs; 587 is listed only when SUBMISSION_ENABLE is true for this deployment, which is a deploy-time flag the panel cannot verify at runtime. Client-side (static/panel.js, no libraries): Copy buttons on the values that get carried elsewhere (DKIM record, new application credentials, server name), and the Addresses field is hidden while the address mode is wildcard, where the server ignores it. Verified in a container on the dev server: setup, login, every page's nav and active item, domain and application creation, all account-form paths including cross-session invalidation, import errors, full backup download. gofmt/vet/test/docker build green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
65 lines
3.7 KiB
Markdown
65 lines
3.7 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to this project are documented here.
|
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [SemVer](https://semver.org/).
|
|
|
|
## [Unreleased]
|
|
|
|
- panel: navigation bar is now rendered once from the shared layout, so every
|
|
authenticated page has it — including the domain page and the delete
|
|
confirmation, which had no navigation links at all — and the current page is
|
|
highlighted instead of silently missing from the list.
|
|
- panel: new *Account* page to change the administrator's username and/or
|
|
password (the current password is required, throttled on the same limiter as
|
|
the login form). Changing the password invalidates all other sessions.
|
|
- panel: *Backup & migration* moved off the domain list onto its own *Backup*
|
|
page, with the full backup and the domain import as two separate cards.
|
|
- panel: the domain page now shows the *Sending server settings* (server,
|
|
port and encryption) needed to configure a mail client; port 587 is listed
|
|
only when `SUBMISSION_ENABLE=true` for this deployment.
|
|
- panel: *Copy* buttons on the DKIM record, on a newly issued application
|
|
login/password and on the sending server name.
|
|
- panel: the *Addresses* field is hidden while an application's address mode is
|
|
*Any address of the domain*, where the server ignores it.
|
|
- ci: disable provenance attestation on release image push, so the ghcr.io
|
|
manifest list shows only `linux/amd64`/`linux/arm64` (no `unknown/unknown`).
|
|
- security: optionally honour `X-Forwarded-For` for login/setup rate-limiting
|
|
when the request's direct peer is in the new `TRUSTED_PROXY_CIDR` list,
|
|
giving real per-client limits behind a reverse proxy instead of one global
|
|
bucket. Unset by default (unchanged `RemoteAddr`-only behaviour).
|
|
|
|
## [0.1.0] - 2026-07-15
|
|
|
|
Initial feature-complete implementation of the v1.0 specification (phases 0-11
|
|
of `docs/implementation-plan.md`).
|
|
|
|
### Added
|
|
|
|
- Panel (Go, single static binary) with SQLite persistence, one-time
|
|
crypto-random setup link, bcrypt admin auth, session cookies.
|
|
- Domain management with per-domain DKIM (RSA-2048, generated in pure Go) and
|
|
OpenDKIM KeyTable/SigningTable regeneration + privilege-safe reload.
|
|
- Application (sender identity) management: SASL credentials via `sasldb2`,
|
|
`smtpd_sender_login_maps` enforcing sender/domain ownership, no open relay.
|
|
- Full Postfix relay config generated from env at container start: SMTPS 465,
|
|
optional STARTTLS submission 587, SASL auth, TLS for outbound delivery,
|
|
anvil-based rate limiting (level 1).
|
|
- Journal milter (pure Go, `go-milter`) recording every send to `send_log`;
|
|
fail-open by design so a milter fault never blocks mail.
|
|
- Monitoring UI: send log, Postfix queue, and mail.log tail, all
|
|
HTMX-polling, HTML-escaped.
|
|
- Per-domain/per-application sending rate limit (level 2), enforced in the
|
|
journal milter at `MAIL FROM`, fail-open on the limiter's own errors.
|
|
- Full backup/restore (`tar.gz` of `/data`, consistent SQLite snapshot via
|
|
`VACUUM INTO`) with a version guard that refuses to start on a
|
|
manifest/binary version mismatch. Per-domain export/import for moving a
|
|
single domain between hosts without re-issuing DNS records.
|
|
- Deployment: Docker image + compose, reverse-proxy fragments for Apache
|
|
(default), nginx, Caddy, and Traefik; CI workflow publishing tagged,
|
|
multi-arch images to `ghcr.io` on `vX.Y.Z` tags.
|
|
- Security pass against spec 7.6 (exec safety, config-write sanitization,
|
|
server-side validation, rate limiting, session/cookie hardening, output
|
|
escaping, non-root panel) — full compliance, no code changes required.
|
|
- Live production deployment on `selfpost.example.com` with a real Let's
|
|
Encrypt certificate; end-to-end delivery confirmed (DKIM pass, SPF pass).
|