feat(email): add ImapProvider (generic IMAP for unsupported providers) #12

Merged
cesnimda merged 1 commits from feat/imap-provider into main 2026-07-11 19:47:31 +02:00
Owner

b3 of the multi-provider email roadmap. Generic IMAP via MailKit for mailboxes with no dedicated OAuth provider: ImapConnection model/table, ImapService (connect/search/thread/message-detail), ImapProvider implementing IEmailProvider, ImapController (credential connect, no OAuth). Scoped to INBOX with References/In-Reply-To-based thread approximation (documented inline).

Security: ran the security-audit skill per the standing gate. Found + fixed a real SSRF (arbitrary host:port connect target, no internal-range check, distinguishable connect-vs-auth failure = network-probing oracle). Fixed with DNS-resolve + internal-range rejection re-checked on every reconnect, plus a single generic failure message. 7 regression tests. 168/168 total green.

b3 of the multi-provider email roadmap. Generic IMAP via MailKit for mailboxes with no dedicated OAuth provider: ImapConnection model/table, ImapService (connect/search/thread/message-detail), ImapProvider implementing IEmailProvider, ImapController (credential connect, no OAuth). Scoped to INBOX with References/In-Reply-To-based thread approximation (documented inline). Security: ran the security-audit skill per the standing gate. Found + fixed a real SSRF (arbitrary host:port connect target, no internal-range check, distinguishable connect-vs-auth failure = network-probing oracle). Fixed with DNS-resolve + internal-range rejection re-checked on every reconnect, plus a single generic failure message. 7 regression tests. 168/168 total green.
cesnimda added 1 commit 2026-07-11 19:41:45 +02:00
feat(email): add ImapProvider (generic IMAP for unsupported providers)
CI and Deploy / test (pull_request) Successful in 2m2s
CI and Deploy / deploy (pull_request) Has been skipped
a8e2f4dc4a
b3 of the multi-provider email roadmap. Adds ImapConnection model + table
(reconciler pattern, SQLite+MySQL), ImapService (MailKit-backed IMAP client),
ImapProvider implementing the existing IEmailProvider contract unchanged,
and ImapController for credential-based connect (no OAuth — user supplies
host/username/password directly, verified by a live connect before storage).

Scope, documented inline with ponytail: comments:
- INBOX only, no multi-folder support.
- Thread grouping approximates the References/In-Reply-To chain root rather
  than the IMAP THREAD extension, which not every server implements.
- External message ids are IMAP UIDs, scoped to the connection's current
  UIDVALIDITY.

Security: ran the security-audit skill against this diff (credential
handling + arbitrary-host connect is exactly the class of change the
standing security gate exists for). Found and fixed a real SSRF: the
connect endpoint let an authenticated user point the server at an
arbitrary host:port with no internal-range check, and connect-vs-auth
failure was distinguishable to the caller -- together a working oracle to
fingerprint internal services (loopback/RFC1918/link-local/cloud metadata)
from the server's network position. Fixed with EnsureHostIsExternalAsync
(DNS-resolve + reject internal ranges, re-checked on every reconnect to
close the DNS-rebinding gap) and a single generic failure message that no
longer distinguishes connect vs auth failure. 7 regression tests added.

Dependency: MailKit 4.17.0 (MIT license) on JobTrackerBackend.csproj --
stdlib has no IMAP client; hand-rolling IMAP4rev1 (TLS, SASL, MIME parsing)
would be a large, security-sensitive protocol implementation nobody asked
for, so this is the correct dependency, not a stdlib substitute.

168/168 green (161 existing + 7 new SSRF regression tests; the earlier
14 IMAP feature tests are included in the 161).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cesnimda force-pushed feat/imap-provider from 3849c16666 to a8e2f4dc4a 2026-07-11 19:41:45 +02:00 Compare
cesnimda merged commit d308f1d5d4 into main 2026-07-11 19:47:31 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: cesnimda/jobtrackingapp#12