Perform a dummy LDAP bind when SearchDN fails so that the response time
is indistinguishable between unknown users and wrong passwords.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Style altcha widget to match theme using CSS variables (border, background, colors, dark mode)
- Make buttons in .btn-group stretch full width to align with inputs
- Center altcha widget with max-width: 100%
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace violet/indigo accent colors with #2fa700 green, and update the
background from a flat color to a diagonal gradient evoking a sky over
green landscape (light: sky blue → meadow green; dark: midnight → forest).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add self-hosted style.css replacing Bootstrap CDN dependency
- Add profile.html with tabbed view (account info, emails/aliases, API token)
- Refactor login handler to pass structured data to template instead of building HTML strings
- Add brand-name and brand-logo flags/env vars for UI customization
- Update CSP to allow brand logo domain and remove CDN references
- Update all templates to pass template vars to header/footer and use new CSS classes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace map[string]interface{} with map[string]any, ioutil.ReadAll with
io.ReadAll, and simplify redundant fmt.Sprintf/w.Write calls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In development mode (-dev):
- HSTS header is omitted (prevents browser caching HTTPS-only requirement)
- CSRF cookie Secure flag is cleared (allows cookies over plain HTTP)
- A warning is logged on startup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Integrate go-altcha to protect login, change password, lost password,
and reset password forms against automated submissions. Serves the
altcha widget JS from the embedded library, exposes a challenge
endpoint, validates responses server-side with replay prevention, and
updates the CSP to allow self-hosted scripts and WebAssembly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Increase minimum password length from 8 to 12 characters and require
at least one uppercase letter, one lowercase letter, and one digit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace math/rand.Intn with crypto/rand for generating random alias
prefixes. While aliases are not security tokens, using a CSPRNG ensures
consistent use of cryptographically secure randomness throughout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add ALIAS_ALLOWED_DOMAINS env var (comma-separated) that restricts which
domains users may create aliases under. Alias creation is disabled when
the env var is not set. Prevents users from creating aliases with arbitrary
domains (e.g. for phishing/spoofing).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set X-Frame-Options, X-Content-Type-Options, Referrer-Policy, CSP,
and Strict-Transport-Security on all responses to mitigate clickjacking,
MIME sniffing, XSS, and downgrade attacks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded "docker-registry" check with a configurable secret via
DOCKER_REGISTRY_SECRET env var. When the env var is unset, the anonymous
docker registry bypass is disabled entirely, closing the unauthenticated
access path if the service is accidentally exposed directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement sliding window rate limiter to prevent brute-force attacks:
- /auth and /login: 20 requests/minute per IP
- /change: 10 POST requests/minute per IP
- /lost: 5 POST requests/minute per IP (prevents email spam and user enumeration)
- /reset: 10 POST requests/minute per IP
- /api/v1/aliases: 30 requests/minute per IP
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use html.EscapeString for attribute names and values when building HTML.
Move dynamic data (alias URL, API token) to data-* attributes and use
a self-contained onclick function to read them, eliminating JS string
injection via LDAP-controlled values.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace SHA512-based deterministic token with 32-byte crypto/rand token
- Store tokens server-side with 1-hour expiry and single-use semantics
- Remove genToken (previously broken due to time.Add immutability bug)
- Add CSRF double-submit cookie protection to change/lost/reset forms
- Remove token from form action URL (use hidden fields only, POST body)
- Add MailFrom field and SMTP_FROM env var for configurable sender address
- Add SMTP_PASSWORD_FILE env var for secure SMTP password loading
- Add PUBLIC_URL env var and --public-url flag for configurable reset link domain
- Use generic error messages in handlers to avoid information disclosure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
http.Redirect only sets response headers; without return, handler execution
continued with empty login/token strings, potentially causing unexpected
LDAP queries and information leakage.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use ldap.EscapeFilter() on all user-controlled inputs before interpolating
them into LDAP search filter strings in SearchDN and SearchMailAlias.
Prevents authentication bypass via filter manipulation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>