From dcaefbdcf588cc2bae6f45f727168ffef49a93a5 Mon Sep 17 00:00:00 2001 From: nyuszika7h Date: Tue, 13 Sep 2011 11:07:52 +0200 Subject: [PATCH 1/5] Add SASL support to core. --- src/conf.py | 11 ++++++++++- src/irclib.py | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/conf.py b/src/conf.py index f38dfba33..fb90e17b1 100644 --- a/src/conf.py +++ b/src/conf.py @@ -258,7 +258,7 @@ class SpaceSeparatedSetOfChannels(registry.SpaceSeparatedListOf): else: return ircmsgs.join(channel) -def registerNetwork(name, password='', ssl=False): +def registerNetwork(name, username='', password='', ssl=False): network = registerGroup(supybot.networks, name) registerGlobalValue(network, 'password', registry.String(password, _("""Determines what password will be used on %s. Yes, we know that @@ -277,6 +277,15 @@ def registerNetwork(name, password='', ssl=False): registerChannelValue(network.channels, 'key', registry.String('', _("""Determines what key (if any) will be used to join the channel."""))) + sasl = registerGroup(network, 'sasl') + registerGlobalValue(sasl, 'username', registry.String(username, + _("""Determines what SASL username will be used on %s. This should + be the bot's account name. Due to the way SASL works, you can't use + any grouped nick.""") % name, private=False)) + registerGlobalValue(sasl, 'password', registry.String(password, + _("""Determines what SASL password will be used on %s. Yes, we know + that technically passwords are server-specific and not network-specific, + but this is the best we can do right now.""") % name, private=True)) return network # Let's fill our networks. diff --git a/src/irclib.py b/src/irclib.py index 0efa1abc8..b7dc0f648 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -31,6 +31,7 @@ import re import copy import time import random +import base64 import supybot.log as log import supybot.conf as conf @@ -862,6 +863,8 @@ class Irc(IrcCommandDispatcher): self.ident = conf.supybot.ident() self.alternateNicks = conf.supybot.nick.alternates()[:] self.password = conf.supybot.networks.get(self.network).password() + self.sasl_username = conf.supybot.networks.get(self.network).sasl.username() + self.sasl_password = conf.supybot.networks.get(self.network).sasl.password() self.prefix = '%s!%s@%s' % (self.nick, self.ident, 'unset.domain') # The rest. self.lastTake = 0 @@ -875,6 +878,18 @@ class Irc(IrcCommandDispatcher): self.driver.die() self._reallyDie() else: + if self.sasl_password: + if not self.sasl_username: + log.error('SASL username is not set, unable to identify.') + else: + auth_string = base64.b64encode('%s\x00%s\x00%s' % (self.sasl_username, + self.sasl_username, self.sasl_password)) + log.debug('Sending CAP REQ command, requesting capability \'sasl\'.') + self.queueMsg(ircmsgs.IrcMsg(command="CAP", args=('REQ', 'sasl'))) + log.debug('Sending AUTHENTICATE command, using mechanism PLAIN.') + self.queueMsg(ircmsgs.IrcMsg(command="AUTHENTICATE", args=('PLAIN',))) + log.info('Sending AUTHENTICATE command, not logging the password.') + self.queueMsg(ircmsgs.IrcMsg(command="AUTHENTICATE", args=(auth_string,))) if self.password: log.info('Sending PASS command, not logging the password.') self.queueMsg(ircmsgs.password(self.password)) @@ -884,6 +899,17 @@ class Irc(IrcCommandDispatcher): self.ident, self.user) self.queueMsg(ircmsgs.user(self.ident, self.user)) + def do903(self, msg): + log.info('SASL authentication successful') + log.debug('Sending CAP END command.') + self.queueMsg(ircmsgs.IrcMsg(command="CAP", args=('END',))) + + def do904(self, msg): + log.warning('SASL authentication failed') + log.debug('Aborting authentication.') + log.debug('Sending CAP END command.') + self.queueMsg(ircmsgs.IrcMsg(command="CAP", args=('END',))) + def _getNextNick(self): if self.alternateNicks: nick = self.alternateNicks.pop(0) From c8c2f125a18d3dad8ed1b9ef7515dde95f201e63 Mon Sep 17 00:00:00 2001 From: nyuszika7h Date: Tue, 13 Sep 2011 17:01:18 +0200 Subject: [PATCH 2/5] conf.py: remove part about server-specific password for supybot.networks..sasl.password. --- src/conf.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/conf.py b/src/conf.py index fb90e17b1..d0169b7dc 100644 --- a/src/conf.py +++ b/src/conf.py @@ -283,9 +283,8 @@ def registerNetwork(name, username='', password='', ssl=False): be the bot's account name. Due to the way SASL works, you can't use any grouped nick.""") % name, private=False)) registerGlobalValue(sasl, 'password', registry.String(password, - _("""Determines what SASL password will be used on %s. Yes, we know - that technically passwords are server-specific and not network-specific, - but this is the best we can do right now.""") % name, private=True)) + _("""Determines what SASL password will be used on %s.""") \ + % name, private=True)) return network # Let's fill our networks. From ca502c6814fb39331ab8644b4673ae6365fa7953 Mon Sep 17 00:00:00 2001 From: nyuszika7h Date: Tue, 13 Sep 2011 19:55:01 +0200 Subject: [PATCH 3/5] irclib.py: Added network name to SASL authentication success/fail. --- src/irclib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/irclib.py b/src/irclib.py index b7dc0f648..174758699 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -900,12 +900,12 @@ class Irc(IrcCommandDispatcher): self.queueMsg(ircmsgs.user(self.ident, self.user)) def do903(self, msg): - log.info('SASL authentication successful') + log.info('%s: SASL authentication successful' % self.network) log.debug('Sending CAP END command.') self.queueMsg(ircmsgs.IrcMsg(command="CAP", args=('END',))) def do904(self, msg): - log.warning('SASL authentication failed') + log.warning('%s: SASL authentication failed' % self.network) log.debug('Aborting authentication.') log.debug('Sending CAP END command.') self.queueMsg(ircmsgs.IrcMsg(command="CAP", args=('END',))) From e140fc76f599c9d3636719ffce728c52f9485e6e Mon Sep 17 00:00:00 2001 From: nyuszika7h Date: Tue, 13 Sep 2011 19:55:31 +0200 Subject: [PATCH 4/5] conf.py: Change username to sasl_username and add it as last argument. --- src/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conf.py b/src/conf.py index d0169b7dc..6dd8692ce 100644 --- a/src/conf.py +++ b/src/conf.py @@ -258,7 +258,7 @@ class SpaceSeparatedSetOfChannels(registry.SpaceSeparatedListOf): else: return ircmsgs.join(channel) -def registerNetwork(name, username='', password='', ssl=False): +def registerNetwork(name, password='', ssl=False, sasl_username = ''): network = registerGroup(supybot.networks, name) registerGlobalValue(network, 'password', registry.String(password, _("""Determines what password will be used on %s. Yes, we know that @@ -278,7 +278,7 @@ def registerNetwork(name, username='', password='', ssl=False): _("""Determines what key (if any) will be used to join the channel."""))) sasl = registerGroup(network, 'sasl') - registerGlobalValue(sasl, 'username', registry.String(username, + registerGlobalValue(sasl, 'username', registry.String(sasl_username, _("""Determines what SASL username will be used on %s. This should be the bot's account name. Due to the way SASL works, you can't use any grouped nick.""") % name, private=False)) From 25dcadfe68b933608351bc896dbcc79fb48d055a Mon Sep 17 00:00:00 2001 From: nyuszika7h Date: Wed, 14 Sep 2011 11:39:00 +0200 Subject: [PATCH 5/5] conf.py: remove surrounding spaces around '=' for sasl_username. --- src/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf.py b/src/conf.py index 6dd8692ce..81a47dd7a 100644 --- a/src/conf.py +++ b/src/conf.py @@ -258,7 +258,7 @@ class SpaceSeparatedSetOfChannels(registry.SpaceSeparatedListOf): else: return ircmsgs.join(channel) -def registerNetwork(name, password='', ssl=False, sasl_username = ''): +def registerNetwork(name, password='', ssl=False, sasl_username=''): network = registerGroup(supybot.networks, name) registerGlobalValue(network, 'password', registry.String(password, _("""Determines what password will be used on %s. Yes, we know that