From b14ea4f051ad7ea2c5fd0951a5d005c0827ae27c Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 3 Mar 2017 15:39:28 -0800 Subject: [PATCH 1/5] clientbot: send CAP LS before NICK/USER so that it consistently gets a response before connect Previously, SASL was failing on networks like freenode, as the connection completed before a CAP response was received. (cherry picked from commit 9420f21680058e50a8134eed7a050bb4abb9ae73) --- protocols/clientbot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocols/clientbot.py b/protocols/clientbot.py index 4516d79..17212c6 100644 --- a/protocols/clientbot.py +++ b/protocols/clientbot.py @@ -73,6 +73,8 @@ class ClientbotWrapperProtocol(Protocol): if sendpass: f('PASS %s' % sendpass) + f('CAP LS 302') + # This is a really gross hack to get the defined NICK/IDENT/HOST/GECOS. # But this connection stuff is done before any of the spawnClient stuff in # services_support fires. @@ -82,8 +84,6 @@ class ClientbotWrapperProtocol(Protocol): f('USER %s 8 * :%s' % (ident, # TODO: per net realnames or hostnames aren't implemented yet. conf.conf["bot"].get("realname", "PyLink Clientbot"))) - f('CAP LS 302') - # Note: clientbot clients are initialized with umode +i by default def spawnClient(self, nick, ident='unknown', host='unknown.host', realhost=None, modes={('i', None)}, server=None, ip='0.0.0.0', realname='', ts=None, opertype=None, From 84448e9803c8eaedb4aadfe1da9db16e9cbd0eb9 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sat, 4 Mar 2017 23:54:16 -0800 Subject: [PATCH 2/5] clientbot: time out CAP/SASL after 5 seconds Closes #424. (cherry picked from commit 47f0b7626f8d17b99fa4dd8cfd93a89f81bb7753) --- protocols/clientbot.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/protocols/clientbot.py b/protocols/clientbot.py index 17212c6..aa2de52 100644 --- a/protocols/clientbot.py +++ b/protocols/clientbot.py @@ -75,6 +75,15 @@ class ClientbotWrapperProtocol(Protocol): f('CAP LS 302') + # Start a timer to call CAP END if registration freezes (e.g. if AUTHENTICATE for SASL is + # never replied to). + def capEnd(): + log.info('(%s) Skipping SASL due to timeout; are the IRCd and services configured ' + 'properly?', self.irc.name) + self.capEnd() + self._cap_timer = threading.Timer(5, capEnd) + self._cap_timer.start() + # This is a really gross hack to get the defined NICK/IDENT/HOST/GECOS. # But this connection stuff is done before any of the spawnClient stuff in # services_support fires. @@ -413,6 +422,14 @@ class ClientbotWrapperProtocol(Protocol): parsed_args['tags'] = tags # Add message tags to this dict. return [idsource, command, parsed_args] + def capEnd(self): + """ + Abort SASL login by sending CAP END. + """ + self.irc.send('CAP END') + log.debug("(%s) Stopping CAP END timer.", self.irc.name) + self._cap_timer.cancel() + def saslAuth(self): """ Starts an authentication attempt via SASL. This returns True if SASL @@ -483,7 +500,7 @@ class ClientbotWrapperProtocol(Protocol): logfunc = log.info if command == '903' else log.warning logfunc('(%s) %s', self.irc.name, args[-1]) if not self.has_eob: - self.irc.send('CAP END') + self.capEnd() handle_903 = handle_902 = handle_905 = handle_906 = handle_907 = handle_904 def requestNewCaps(self): @@ -521,12 +538,12 @@ class ClientbotWrapperProtocol(Protocol): # to do so. if not self.saslAuth(): if not self.has_eob: - self.irc.send('CAP END') + self.capEnd() elif subcmd == 'NAK': log.warning('(%s) Got NAK for IRCv3 capabilities %s, even though they were supposedly available', self.irc.name, args[-1]) if not self.has_eob: - self.irc.send('CAP END') + self.capEnd() elif subcmd == 'NEW': # :irc.example.com CAP modernclient NEW :batch # :irc.example.com CAP tester NEW :away-notify extended-join From 22ceb3f6995bf3709680582a5d11325093c47d02 Mon Sep 17 00:00:00 2001 From: James Lu Date: Wed, 5 Apr 2017 23:08:17 -0700 Subject: [PATCH 3/5] clientbot: make SASL timeout configurable & raise default to 15 secs (cherry picked from commit 9d50a4363be5ed2ca17b9bdf563017220ffba1bd) --- example-conf.yml | 3 +++ protocols/clientbot.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/example-conf.yml b/example-conf.yml index 80eeaa4..011db49 100644 --- a/example-conf.yml +++ b/example-conf.yml @@ -305,6 +305,9 @@ servers: #sasl_username: "mIRCsKripterz" #sasl_password: "DownLoaditn00b!!!" + # Defines the SASL timeout - this defaults to 15 seconds. + #sasl_timeout: 15 + # If this option is enabled, the bot will attempt SASL authentication even after it's # connected, as services become available throughout netsplits and reconnects. # Note: This requires an IRC server capable of IRCv3.2 cap-notify and sasl: diff --git a/protocols/clientbot.py b/protocols/clientbot.py index aa2de52..c227fea 100644 --- a/protocols/clientbot.py +++ b/protocols/clientbot.py @@ -81,7 +81,7 @@ class ClientbotWrapperProtocol(Protocol): log.info('(%s) Skipping SASL due to timeout; are the IRCd and services configured ' 'properly?', self.irc.name) self.capEnd() - self._cap_timer = threading.Timer(5, capEnd) + self._cap_timer = threading.Timer(self.irc.serverdata.get('sasl_timeout') or 15, capEnd) self._cap_timer.start() # This is a really gross hack to get the defined NICK/IDENT/HOST/GECOS. From e2ae0917235ea08350791c69634b2d906b4da5bc Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 6 Apr 2017 15:30:46 -0700 Subject: [PATCH 4/5] .travis.yml: bring PyPI deployment to production --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a33c92f..cc875b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,8 @@ addons: deploy: provider: pypi - server: https://testpypi.python.org/pypi +# Enable this to use test mode +# server: https://testpypi.python.org/pypi user: secure: Ql6ihu5MDgWuAvT9NYfriGUYGhHpsqwXfZHWDQT+DfRjOqHo9QT7PnfexeBoe6L6cYUkEnIrnAXKtBXGy6UmyvfrnvBl68877dLVuoC8PfQ4J0ej7TVnCJmT/LwRqFvzZXkeg4CIlJsVJ6pvrPHXQBDPH1rj/rWCucchrofmps8= password: From 539ad668cf7f3999af6ad3638a68995ac73a6478 Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 6 Apr 2017 15:33:28 -0700 Subject: [PATCH 5/5] PyLink 1.1.2 --- RELNOTES.md | 20 ++++++++++++++++++++ VERSION | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/RELNOTES.md b/RELNOTES.md index 8bdf0e2..95d84b5 100644 --- a/RELNOTES.md +++ b/RELNOTES.md @@ -1,3 +1,23 @@ +# PyLink 1.1.2 + +The "Calamari" release. + +#### Bug fixes +- Multiple fixes for the `unreal` protocol module when using UnrealIRCd 3.2 links: + - fccec3a Fix crashes on processing SJOIN when a user behind a 3.2 server has a nick starting with a symbol + - 8465edd Fix kicks to Unreal 3.2 users (PUIDs) not updating the internal state - this would've caused odd prefix mode desyncs if a user was kicked and rejoined. + - df4acbf Fix prefix modes not being set on Unreal 3.2 users (affects Automode, etc.) +- Backported SASL fixes from 1.2-dev: + - b14ea4f Send CAP LS before NICK/USER so that we consistently get a SASL response before connect - this fixes SASL on networks like freenode, where connections can often complete before a SASL response from services is ever received. + - 84448e9 22ceb3f The above commit rewrites SASL to depend on a timely response from the server, so a configurable timeout for SASL/CAP is also introduced. (#424) + +#### Feature changes +- 22ceb3f Added the `sasl_timeout` option for Clientbot networks (this defaults to 15 seconds if not set). + +#### Internal improvements +- Backported stability improvements from 1.2-dev: + - d70ca9f Rewrite connection error handling to include `RuntimeError` and `SystemExit` (#438) + # PyLink 1.1.1 The "Crush" release. Changes from 1.1.0: diff --git a/VERSION b/VERSION index 524cb55..45a1b3f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.1 +1.1.2