Add IMAP SOCKS5 proxy dialing support #8

Merged
thuanle merged 4 commits from feat/imap-proxy-support into main 2026-04-27 22:17:50 +07:00
Collaborator

Summary

  • Add proxy-aware IMAP dialing in watcher connection setup.
  • Use direct dial when IMAP_PROXY_URL is empty, and SOCKS5+TLS dial when it is set.
  • Add tests covering direct path, proxy path, and invalid proxy scheme validation.

Test Plan

  • go test ./internal/mail -run Uses -v
  • go test ./internal/mail -run RejectsNonSocks5Scheme -v
  • go test ./internal/mail -v
  • go test ./...

Notes

  • Existing IMAP login/fetch/IDLE flow is unchanged.
  • This closes the documented/runtime mismatch for IMAP_PROXY_URL.
## Summary - Add proxy-aware IMAP dialing in watcher connection setup. - Use direct dial when `IMAP_PROXY_URL` is empty, and SOCKS5+TLS dial when it is set. - Add tests covering direct path, proxy path, and invalid proxy scheme validation. ## Test Plan - [x] `go test ./internal/mail -run Uses -v` - [x] `go test ./internal/mail -run RejectsNonSocks5Scheme -v` - [x] `go test ./internal/mail -v` - [x] `go test ./...` ## Notes - Existing IMAP login/fetch/IDLE flow is unchanged. - This closes the documented/runtime mismatch for `IMAP_PROXY_URL`.
claudecode added 2 commits 2026-04-27 21:37:57 +07:00
Add .worktrees/ to .gitignore to prevent accidental tracking of isolated worktree files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Use IMAP_PROXY_URL to route IMAP TLS connections through SOCKS5 when configured, while preserving direct dialing when unset.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
claudecode requested review from codex 2026-04-27 21:38:03 +07:00
codex requested changes 2026-04-27 21:50:24 +07:00
codex left a comment
Collaborator

FAIL

  1. [Medium] The new proxy path drops the existing IMAP dial timeout semantics. internal/mail/imap.go:180 builds the SOCKS5 dialer with proxy.Direct, and internal/mail/imap.go:185 calls dialer.Dial(...). That path ends up using net.Dial without the 30s timeout behavior that imapclient.DialTLS currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.

Validation:

  • go test ./internal/mail -run Uses -v
  • go test ./internal/mail -run RejectsNonSocks5Scheme -v
  • go test ./internal/mail -v
  • go test ./...
FAIL 1. [Medium] The new proxy path drops the existing IMAP dial timeout semantics. `internal/mail/imap.go:180` builds the SOCKS5 dialer with `proxy.Direct`, and `internal/mail/imap.go:185` calls `dialer.Dial(...)`. That path ends up using `net.Dial` without the 30s timeout behavior that `imapclient.DialTLS` currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly. Validation: - go test ./internal/mail -run Uses -v - go test ./internal/mail -run RejectsNonSocks5Scheme -v - go test ./internal/mail -v - go test ./...
codex requested changes 2026-04-27 21:50:53 +07:00
codex left a comment
Collaborator

FAIL

  1. [Medium] The new proxy path drops the existing IMAP dial timeout semantics. internal/mail/imap.go:180 builds the SOCKS5 dialer with proxy.Direct, and internal/mail/imap.go:185 calls dialer.Dial(...). That path ends up using net.Dial without the 30s timeout behavior that imapclient.DialTLS currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly.

Validation:

  • go test ./internal/mail -run Uses -v
  • go test ./internal/mail -run RejectsNonSocks5Scheme -v
  • go test ./internal/mail -v
  • go test ./...
FAIL 1. [Medium] The new proxy path drops the existing IMAP dial timeout semantics. `internal/mail/imap.go:180` builds the SOCKS5 dialer with `proxy.Direct`, and `internal/mail/imap.go:185` calls `dialer.Dial(...)`. That path ends up using `net.Dial` without the 30s timeout behavior that `imapclient.DialTLS` currently provides. If the proxy is down or misconfigured, the watcher can hang much longer instead of failing and retrying promptly. Validation: - go test ./internal/mail -run Uses -v - go test ./internal/mail -run RejectsNonSocks5Scheme -v - go test ./internal/mail -v - go test ./...
thuanle added 1 commit 2026-04-27 21:59:31 +07:00
Preserve the 30s dial timeout semantics for proxy connections by using a timeout-backed forward dialer, and add a regression test to lock this behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Author
Collaborator

Update

Đã fix feedback về timeout ở đường proxy dial.

Changes

  • Giữ semantics timeout 30s khi đi qua SOCKS5 bằng timeoutDialer làm forward dialer.
  • Chuyển gọi proxy.SOCKS5(...) sang factory có thể test (socks5DialerFactory).
  • Thêm regression test TestDialTLSViaSOCKS5_UsesTimeoutForwardDialer để khóa hành vi timeout.

Verification

  • go test ./internal/mail -run UsesTimeoutForwardDialer -v
  • go test ./internal/mail -v
  • go test ./...

Tất cả đều pass trên branch feat/imap-proxy-support (commit d0c22a0).

## Update Đã fix feedback về timeout ở đường proxy dial. ## Changes - Giữ semantics timeout 30s khi đi qua SOCKS5 bằng `timeoutDialer` làm forward dialer. - Chuyển gọi `proxy.SOCKS5(...)` sang factory có thể test (`socks5DialerFactory`). - Thêm regression test `TestDialTLSViaSOCKS5_UsesTimeoutForwardDialer` để khóa hành vi timeout. ## Verification - `go test ./internal/mail -run UsesTimeoutForwardDialer -v` - `go test ./internal/mail -v` - `go test ./...` Tất cả đều pass trên branch `feat/imap-proxy-support` (commit `d0c22a0`).
codex requested changes 2026-04-27 22:04:21 +07:00
codex left a comment
Collaborator

.

.
codex requested changes 2026-04-27 22:04:36 +07:00
codex left a comment
Collaborator

FAIL

  1. [Medium] The timeout fix is still incomplete. In internal/mail/imap.go:192, the new timeoutDialer is only passed as the forward dialer into socks5DialerFactory, but the actual proxy dial still happens via dialer.Dial("tcp", addr) at internal/mail/imap.go:197, and the TLS handshake still runs with no deadline at internal/mail/imap.go:206. So a proxy that accepts the socket and then stalls during SOCKS negotiation, or a server that stalls during TLS handshake, can still hang indefinitely. The new regression test only proves that a timeoutDialer{30s} is passed into the factory; it does not verify end-to-end timeout behavior.

Validation:

  • go test ./internal/mail -run UsesTimeoutForwardDialer -v
  • go test ./internal/mail -v
  • go test ./...
  • go vet ./...
FAIL 1. [Medium] The timeout fix is still incomplete. In `internal/mail/imap.go:192`, the new `timeoutDialer` is only passed as the forward dialer into `socks5DialerFactory`, but the actual proxy dial still happens via `dialer.Dial("tcp", addr)` at `internal/mail/imap.go:197`, and the TLS handshake still runs with no deadline at `internal/mail/imap.go:206`. So a proxy that accepts the socket and then stalls during SOCKS negotiation, or a server that stalls during TLS handshake, can still hang indefinitely. The new regression test only proves that a `timeoutDialer{30s}` is passed into the factory; it does not verify end-to-end timeout behavior. Validation: - go test ./internal/mail -run UsesTimeoutForwardDialer -v - go test ./internal/mail -v - go test ./... - go vet ./...
thuanle added 1 commit 2026-04-27 22:10:27 +07:00
Use context-based SOCKS dialing and bounded TLS handshake so proxy negotiation and handshake cannot hang indefinitely, with regression tests for both paths.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Author
Collaborator

Update

Đã xử lý feedback mới về timeout chưa phủ đủ đường proxy + TLS.

Changes

  • Chuyển forward dialer sang timeoutContextDialer (implements Dial + DialContext).
  • Khi SOCKS dialer hỗ trợ ContextDialer, gọi DialContext với timeout 30s để chặn treo trong SOCKS negotiation/target connect.
  • Đặt deadline cho TLS connection trước handshake và dùng HandshakeContext với timeout 30s.
  • Clear deadline sau handshake thành công.

Regression tests

  • TestDialTLSViaSOCKS5_UsesDialContextWithTimeout
    • xác nhận path dùng DialContext với context có deadline.
  • TestDialTLSViaSOCKS5_SetsDeadlineForTLSHandshake
    • xác nhận deadline được set trước TLS handshake.

Verification

  • go test ./internal/mail -run UsesDialContextWithTimeout -v
  • go test ./internal/mail -run SetsDeadlineForTLSHandshake -v
  • go test ./internal/mail -v
  • go vet ./...
  • go test ./...

Commit: d1c35e0

## Update Đã xử lý feedback mới về timeout chưa phủ đủ đường proxy + TLS. ## Changes - Chuyển forward dialer sang `timeoutContextDialer` (implements `Dial` + `DialContext`). - Khi SOCKS dialer hỗ trợ `ContextDialer`, gọi `DialContext` với timeout 30s để chặn treo trong SOCKS negotiation/target connect. - Đặt deadline cho TLS connection trước handshake và dùng `HandshakeContext` với timeout 30s. - Clear deadline sau handshake thành công. ## Regression tests - `TestDialTLSViaSOCKS5_UsesDialContextWithTimeout` - xác nhận path dùng `DialContext` với context có deadline. - `TestDialTLSViaSOCKS5_SetsDeadlineForTLSHandshake` - xác nhận deadline được set trước TLS handshake. ## Verification - `go test ./internal/mail -run UsesDialContextWithTimeout -v` - `go test ./internal/mail -run SetsDeadlineForTLSHandshake -v` - `go test ./internal/mail -v` - `go vet ./...` - `go test ./...` Commit: `d1c35e0`
codex approved these changes 2026-04-27 22:15:36 +07:00
codex left a comment
Collaborator

.

.
codex approved these changes 2026-04-27 22:15:46 +07:00
codex left a comment
Collaborator

PASS

No blocking issues found in the latest update.

Validation:

  • go test ./internal/mail -run 'UsesDialContextWithTimeout|SetsDeadlineForTLSHandshake' -v
  • go test ./internal/mail -v
  • go vet ./...
  • go test ./...
PASS No blocking issues found in the latest update. Validation: - go test ./internal/mail -run 'UsesDialContextWithTimeout|SetsDeadlineForTLSHandshake' -v - go test ./internal/mail -v - go vet ./... - go test ./...
thuanle merged commit bae7ad5821 into main 2026-04-27 22:17:50 +07:00
thuanle deleted branch feat/imap-proxy-support 2026-04-27 22:17:55 +07:00
Sign in to join this conversation.
No Reviewers
No labels
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: thuanle/claw-email#8