From 723c2491bc8cef4d2b7a9448dd2cf2bfc010eea0 Mon Sep 17 00:00:00 2001 From: nick evans Date: Tue, 5 May 2026 09:30:15 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=8D=20Add=20more=20detail=20to=20`Net:?= =?UTF-8?q?:IMAP#inspect`=20TLS=20info?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the existance of `ssl_ctx` would cause `TLS (NOT VERIFIED)` to be printed. But that isn't quite right: `ssl_ctx` is assigned immediately, before sending the `STARTTLS` command, before calling `start_tls_session`, and before `start_tls_session` returns. And those intermediate states are important distinctions for debugging TLS issues. So this updates `Net::IMAP#inspect` with two new TLS/PLAINTEXT states: * `PLAINTEXT (TLS NOT STARTED)`, when: * `#starttls` has been called (`@ssl_ctx` has been set), * but `#start_tls_session` hasn't (`@sock` is a `TCPSocket`). * `TLS (NOT ESTABLISHED)`, when: * `#start_tls_session` was called (`@sock` is an `SSLSocket`), * but hasn't returned successfully (`@sock.session` isn't available). --- lib/net/imap.rb | 21 +++++++++++++++++---- test/net/imap/test_imap.rb | 5 ++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 6607f786..242a1d98 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -1160,16 +1160,29 @@ def initialize(host, port: nil, ssl: nil, response_handlers: nil, # imap.logout # imap.inspect #=> "#" # + # imap = Net::IMAP.new(hostname, ssl: false) + # imap.inspect #=> "#" + # + # imap.starttls verify_mode: OpenSSL::SSL::VERIFY_NONE + # imap.inspect #=> "#" + # def inspect - tls_state = tls_verified? ? "TLS" : - ssl_ctx ? "TLS (NOT VERIFIED)" : - "PLAINTEXT" conn_state = disconnected? ? "disconnected" : connection_state.to_sym "#<%s:0x%08x %s:%s %s %s>" % [ - self.class.name, __id__, host, port, tls_state, conn_state + self.class.name, __id__, host, port, inspect_tls_state, conn_state ] end + private def inspect_tls_state + if tls_verified? + "TLS" + elsif ssl_ctx && @sock.kind_of?(OpenSSL::SSL::SSLSocket) + "TLS (#{@sock.session ? "NOT VERIFIED" : "NOT ESTABLISHED"})" + else + "PLAINTEXT#{" (TLS NOT STARTED)" if ssl_ctx}" + end + end + # Returns true after the TLS negotiation has completed and the remote # hostname has been verified. Returns false when TLS has been established # but peer verification was disabled. diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb index a9745fc3..11e9fc32 100644 --- a/test/net/imap/test_imap.rb +++ b/test/net/imap/test_imap.rb @@ -128,7 +128,8 @@ def test_starttls assert_equal false, initial_verified assert_equal false, initial_params assert_equal nil, initial_ctx - assert_equal true, imap.tls_verified? + assert_equal true, imap.tls_verified? + assert_include imap.inspect, " TLS disconnected" assert_equal({ca_file: CA_FILE}, imap.ssl_ctx_params) rescue SystemCallError skip $! @@ -164,6 +165,7 @@ def test_starttls_stripping_not_ok end assert_equal false, imap.tls_verified? + assert_include imap.inspect, " PLAINTEXT (TLS NOT STARTED) " assert_equal({ca_file: CA_FILE}, imap.ssl_ctx_params) assert_equal(CA_FILE, imap.ssl_ctx.ca_file) assert_equal(OpenSSL::SSL::VERIFY_PEER, imap.ssl_ctx.verify_mode) @@ -201,6 +203,7 @@ def test_starttls_stripping_ok_sent_before_response imap.disconnect if imap && !imap.disconnected? end assert_equal false, imap.tls_verified? + assert_include imap.inspect, " PLAINTEXT (TLS NOT STARTED) " assert_equal({ca_file: CA_FILE}, imap.ssl_ctx_params) assert_equal(CA_FILE, imap.ssl_ctx.ca_file) assert_equal(OpenSSL::SSL::VERIFY_PEER, imap.ssl_ctx.verify_mode)