Filter list of SASL mechanisms when provided (908 or IRCv3.2-style CAP LS).

This commit is contained in:
Valentin Lorentz 2015-12-11 23:30:57 +01:00
parent 932345fa48
commit 8aff8170e4
2 changed files with 55 additions and 13 deletions

View File

@ -966,13 +966,6 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
self.ident = get_value('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.sasl_ecdsa_key = \
conf.supybot.networks.get(self.network).sasl.ecdsa_key()
self.authenticate_decoder = None
self.prefix = '%s!%s@%s' % (self.nick, self.ident, 'unset.domain')
# The rest.
self.lastTake = 0
@ -981,8 +974,14 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
self.startedAt = time.time()
self.lastping = time.time()
self.outstandingPing = False
self.resetSasl()
def resetSasl(self):
network_config = conf.supybot.networks.get(self.network)
self.sasl_username = network_config.sasl.username()
self.sasl_password = network_config.sasl.password()
self.sasl_ecdsa_key = network_config.sasl.ecdsa_key()
self.authenticate_decoder = None
self.sasl_next_mechanisms = []
self.sasl_current_mechanism = None
@ -1049,6 +1048,11 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
self.sasl_current_mechanism = None
self.sendMsg(ircmsgs.IrcMsg(command='CAP', args=('END',)))
def filterSaslMechanisms(self, available):
self.sasl_next_mechanisms = [
x for x in self.sasl_next_mechanisms
if x in available]
def doAuthenticate(self, msg):
if not self.authenticate_decoder:
self.authenticate_decoder = ircutils.AuthenticateDecoder()
@ -1107,7 +1111,7 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
def do908(self, msg):
log.info('%s: Supported SASL mechanisms: %s',
self.network, msg.args[1])
# TODO: filter self.sasl_next_mechanisms
self.filterSaslMechanisms(set(msg.args[1].split(',')))
def doCap(self, msg):
subcommand = msg.args[1]
@ -1153,7 +1157,6 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
else:
self.state.capabilities_ls[item] = None
def doCapLs(self, msg):
# TODO: filter self.sasl_next_mechanisms
if len(msg.args) == 4:
# Multi-line LS
if msg.args[2] != '*':
@ -1164,6 +1167,10 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
self._addCapabilities(msg.args[2])
common_supported_capabilities = set(self.state.capabilities_ls) & \
self.REQUEST_CAPABILITIES
if 'sasl' in self.state.capabilities_ls:
s = self.state.capabilities_ls['sasl']
if s is not None:
self.filterSaslMechanisms(set(s.split(',')))
# NOTE: Capabilities are requested in alphabetic order, because
# sets are unordered, and their "order" is nondeterministic.
# This is needed for the tests.

View File

@ -531,7 +531,7 @@ class SaslTestCase(SupyTestCase):
def setUp(self):
pass
def startCapNegociation(self):
def startCapNegociation(self, sasl_attributes=None):
m = self.irc.takeMsg()
self.failUnless(m.command == 'CAP', 'Expected CAP, got %r.' % m)
self.failUnless(m.args == ('LS', '302'), 'Expected CAP LS 302, got %r.' % m)
@ -541,9 +541,13 @@ class SaslTestCase(SupyTestCase):
m = self.irc.takeMsg()
self.failUnless(m.command == 'USER', 'Expected USER, got %r.' % m)
# TODO
self.irc.feedMsg(ircmsgs.IrcMsg(command='CAP',
args=('*', 'LS', 'sasl')))
if sasl_attributes:
self.irc.feedMsg(ircmsgs.IrcMsg(command='CAP',
args=('*', 'LS', 'sasl=%s' % sasl_attributes)))
else:
self.irc.feedMsg(ircmsgs.IrcMsg(command='CAP',
args=('*', 'LS', 'sasl')))
m = self.irc.takeMsg()
self.failUnless(m.command == 'CAP', 'Expected CAP, got %r.' % m)
@ -624,6 +628,37 @@ class SaslTestCase(SupyTestCase):
self.endCapNegociation()
def testFilter(self):
try:
conf.supybot.networks.test.sasl.username.setValue('jilles')
conf.supybot.networks.test.sasl.password.setValue('sesame')
conf.supybot.networks.test.certfile.setValue('foo')
self.irc = irclib.Irc('test')
finally:
conf.supybot.networks.test.sasl.username.setValue('')
conf.supybot.networks.test.sasl.password.setValue('')
conf.supybot.networks.test.certfile.setValue('')
self.assertEqual(self.irc.sasl_current_mechanism, None)
self.assertEqual(self.irc.sasl_next_mechanisms,
['external', 'plain'])
self.startCapNegociation(sasl_attributes='foo,plain,bar')
m = self.irc.takeMsg()
self.assertEqual(m, ircmsgs.IrcMsg(command='AUTHENTICATE',
args=('PLAIN',)))
self.irc.feedMsg(ircmsgs.IrcMsg(command='AUTHENTICATE', args=('+',)))
m = self.irc.takeMsg()
self.assertEqual(m, ircmsgs.IrcMsg(command='AUTHENTICATE',
args=('amlsbGVzAGppbGxlcwBzZXNhbWU=',)))
self.irc.feedMsg(ircmsgs.IrcMsg(command='900', args=('jilles',)))
self.irc.feedMsg(ircmsgs.IrcMsg(command='903', args=('jilles',)))
self.endCapNegociation()
class IrcCallbackTestCase(SupyTestCase):