Skip to content

feat: admin-controlled policy for self-hosted mail server connections - #5

Merged
saiththerobo merged 3 commits into
mainfrom
feat/allow-private-host
Jun 3, 2026
Merged

feat: admin-controlled policy for self-hosted mail server connections#5
saiththerobo merged 3 commits into
mainfrom
feat/allow-private-host

Conversation

@saiththerobo

@saiththerobo saiththerobo commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds three admin-only toggles in Settings → Security → Mail Server Connection Policy:
    • Allow private / local hosts — permits connecting to IMAP/SMTP at private or local addresses (127.x, 192.168.x, 10.x, etc.)
    • Allow insecure TLS — allows skipping TLS certificate verification per account; when off, plain-text (non-TLS) connections are also rejected
    • Allow non-standard ports — permits any IMAP/SMTP port, not just 993/143/465/587
  • Policy is enforced at both validation time (account save) and connection time (makeClientCfg, send.js)
  • Plain-text IMAP/SMTP is treated as insecure: blocked when "Allow insecure TLS" is off
  • Policy errors are surfaced to the UI via sync_error / account_error WebSocket broadcast
  • Toggles auto-save on click (no separate Save button), matching existing admin UI patterns
  • DNS rebinding protection (resolveForConnection) is preserved even when private hosts are allowed

Changes

  • backend/migrations/0013_account_allow_private_host.sql — adds allow_private_hosts, allow_insecure_tls, allow_nonstandard_ports to system_settings
  • backend/src/services/connectionPolicy.js — new module; reads all three flags from DB
  • backend/src/services/hostValidation.js — all three exports accept { allowPrivate } option
  • backend/src/services/imapManager.js — reads policy on every connect; enforces TLS requirement in makeClientCfg
  • backend/src/routes/accounts.js — validates host/port against policy on account create/update
  • backend/src/routes/admin.js — PATCH /settings persists the three policy flags
  • backend/src/routes/send.js — enforces policy for SMTP connections
  • frontend/src/components/AdminPanel.jsx — Security tab: policy toggles; account form: conditional skip-TLS toggle and port input mode
  • frontend/src/locales/{en,de,es,fr,it,ru,zhCN}.json — i18n keys for new UI strings

Testing

  • All existing tests pass (npm test — 165 tests)
  • New tests for makeClientCfg TLS enforcement and rejectUnauthorized under all policy combinations
  • New allowPrivate option tests for hostValidation functions
  • Manually verified against GreenMail (local IMAP server): private host + non-standard port connect when policy allows, fail when revoked
  • Plain-text IMAP correctly blocked when "Allow insecure TLS" is off; error surfaces in UI
  • IMAPS with self-signed cert: fails when policy off, succeeds when on

CLA

  • I have read the CLA and agree to its terms

Replaces the per-account allow_private_host toggle with three
server-level policy flags set by admins in Settings → Security:

- allow_private_hosts: permits IMAP/SMTP on private/local addresses
- allow_insecure_tls: exposes per-account TLS verify skip toggle
- allow_nonstandard_ports: unlocks free-form port input

Migration 0013 seeds the three keys in system_settings (default false)
and drops the account-level column added in the earlier draft.
A new connectionPolicy service reads the flags for use in validation
and connection code. The account form shows TLS and port options only
when the admin has enabled them.
- makeClientCfg throws when imap_tls=false and allowInsecureTls policy is off,
  ensuring plain-text IMAP is rejected when admin requires secure connections
- Move makeClientCfg call inside try/catch so policy errors set sync_error
  and broadcast account_error to the UI instead of being silently swallowed
- Block plain-text SMTP when allowInsecureTls is off (STARTTLS and SSL pass)
- Replace Save button on mail policy toggles with auto-save on click,
  matching the existing pattern used by other boolean admin settings
- Export makeClientCfg and add tests covering TLS enforcement and
  rejectUnauthorized behaviour under all policy combinations
@saiththerobo
saiththerobo merged commit b1bc576 into main Jun 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant