mirror of
https://github.com/OfflineIMAP/offlineimap3.git
synced 2026-07-07 18:06:29 +02:00
Robustly handle dead sockets during authentication by retrying the connection
This commit addresses issues where certain IMAP servers (like Protonmail Bridge) abruptly close the socket during the authentication phase. Following a simplified approach: 1. Updated __authn_helper to initiate STARTTLS unconditionally at the beginning of the loop. 2. Modified acquireconnection to catch OfflineImapError. If the socket is detected as dead during authentication, it now logs a warning and retries the entire connection process from scratch (up to 3 attempts). 3. This ensures each retry starts with a fresh connection and all configured authentication methods available, avoiding permanent list modification.
This commit is contained in:
+24
-10
@@ -461,20 +461,20 @@ class IMAPServer:
|
||||
# Stack stores pairs of (method name, exception)
|
||||
exc_stack = []
|
||||
tried_to_authn = False
|
||||
tried_tls = False
|
||||
# Authentication routines, hash keyed by method name
|
||||
# with value that is a tuple with
|
||||
# - authentication function,
|
||||
# - tryTLS flag,
|
||||
# - check IMAP capability flag.
|
||||
auth_methods = {
|
||||
"GSSAPI": (self.__authn_gssapi, False, True),
|
||||
"XOAUTH2": (self.__authn_xoauth2, True, True),
|
||||
"CRAM-MD5": (self.__authn_cram_md5, True, True),
|
||||
"PLAIN": (self.__authn_plain, True, True),
|
||||
"LOGIN": (self.__authn_login, True, False),
|
||||
"GSSAPI": (self.__authn_gssapi, True),
|
||||
"XOAUTH2": (self.__authn_xoauth2, True),
|
||||
"CRAM-MD5": (self.__authn_cram_md5, True),
|
||||
"PLAIN": (self.__authn_plain, True),
|
||||
"LOGIN": (self.__authn_login, False),
|
||||
}
|
||||
|
||||
did_starttls = False
|
||||
# GSSAPI is tried first by default: we will probably go TLS after it and
|
||||
# GSSAPI mustn't be tunneled over TLS.
|
||||
for m in self.authmechs:
|
||||
@@ -482,12 +482,12 @@ class IMAPServer:
|
||||
raise Exception("Bad authentication method %s, "
|
||||
"please, file OfflineIMAP bug" % m)
|
||||
|
||||
func, tryTLS, check_cap = auth_methods[m]
|
||||
func, check_cap = auth_methods[m]
|
||||
|
||||
# TLS must be initiated before checking capabilities:
|
||||
# they could have been changed after STARTTLS.
|
||||
if tryTLS and self.starttls and not tried_tls:
|
||||
tried_tls = True
|
||||
if self.starttls and not did_starttls:
|
||||
did_starttls = True
|
||||
self.__start_tls(imapobj)
|
||||
|
||||
if check_cap:
|
||||
@@ -624,7 +624,8 @@ class IMAPServer:
|
||||
# and release locks / threads so that the next attempt can try...
|
||||
success = False
|
||||
try:
|
||||
while success is not True:
|
||||
retries = 0
|
||||
while success is not True and retries < 3:
|
||||
# Generate a new connection.
|
||||
if self.tunnel:
|
||||
self.ui.connecting(
|
||||
@@ -678,6 +679,19 @@ class IMAPServer:
|
||||
self.goodpassword = self.password
|
||||
success = True
|
||||
except OfflineImapError as e:
|
||||
if not _is_socket_alive(imapobj):
|
||||
retries += 1
|
||||
if retries >= 3:
|
||||
self.ui.warn("Authentication failed after 3 attempts due to dead sockets.")
|
||||
raise
|
||||
self.ui.warn("Connection lost during authentication. "
|
||||
"Retrying from scratch (%d/3)..." % retries)
|
||||
if imapobj is not None:
|
||||
try:
|
||||
imapobj.shutdown()
|
||||
except:
|
||||
pass
|
||||
continue
|
||||
self.passworderror = str(e)
|
||||
raise
|
||||
|
||||
|
||||
Reference in New Issue
Block a user