isupports: _UpdatingDict
nickname_confirmed: bool
user_modes: str
+ sasl_auth_state: str
_completable_motd: _CompletableStringsList
_channels: dict[str, _ChannelDb]
self.conn = None
self._db.isupports.clear()
self._db.nickname_confirmed = False
+ self._db.sasl_auth_state = ''
def on_handled_loop_exception(self, e: IrcConnAbortException) -> None:
'Gracefully handle broken connection.'
# '@'-split because <https://defs.ircdocs.horse/defs/numerics>
# claims: "<hostname> can also be in the form <user@hostname>"
self._db.client_host = msg.params[1].split('@')[-1]
- elif msg.match('903', 2): # RPL_SASLSUCESS
- self._log('SASL auth succeeded')
- self._caps.end_negotiation()
- elif msg.match('904', 2): # ERR_SASLFAIL
- self._log('SASL auth failed', alert=True)
- self._caps.end_negotiation()
+ elif msg.match('903', 2) or msg.match('904', 2): # RPL_SUCESS, or …
+ self._db.sasl_auth_state = 'WIN' if msg.verb == '903' else 'FAIL'
+ self._caps.end_negotiation() # … ERR_SASLFAIL
elif msg.match('AUTHENTICATE') and msg.params[0] == '+':
auth = b64encode((self._db.nickname + '\0'
+ self._db.nickname + '\0'
+ self._db.password
).encode('utf-8')).decode('utf-8')
self.send(IrcMessage('AUTHENTICATE', (auth,)))
- elif msg.match('CAP', len_is_min=True)\
- and self._caps.process_msg(msg.params[1:])\
- and self._db.caps.has('sasl')\
- and 'PLAIN' in self._db.caps['sasl'].data.split(','):
- if self._db.password:
- self._log('trying to authenticate via SASL/plain')
- self.send(IrcMessage('AUTHENTICATE', ('PLAIN',)))
- else:
- self._caps.end_negotiation()
+ elif msg.match('CAP', len_is_min=True):
+ if (self._caps.process_msg(msg.params[1:])
+ and self._db.caps.has('sasl')
+ and 'PLAIN' in self._db.caps['sasl'].data.split(',')):
+ if self._db.password:
+ self._db.sasl_auth_state = 'attempting'
+ self.send(IrcMessage('AUTHENTICATE', ('PLAIN',)))
+ else:
+ self._caps.end_negotiation()
elif msg.match('ERROR'):
self.close()
elif msg.match('MODE', 2) and msg.params[0] == self._db.nickname: