mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-02 17:29:22 +01:00
Merge pull request #976 from maxteufel/feature/sasl-ecdsa-nist256p-challenge
irclib: add support for SASL ECDSA-NIST256P-CHALLENGE
This commit is contained in:
commit
fca473c043
@ -6,3 +6,4 @@ feedparser
|
|||||||
sqlalchemy
|
sqlalchemy
|
||||||
SocksiPy-branch
|
SocksiPy-branch
|
||||||
mock
|
mock
|
||||||
|
ecdsa
|
||||||
|
@ -344,6 +344,10 @@ def registerNetwork(name, password='', ssl=False, sasl_username='',
|
|||||||
registerGlobalValue(sasl, 'password', registry.String(sasl_password,
|
registerGlobalValue(sasl, 'password', registry.String(sasl_password,
|
||||||
_("""Determines what SASL password will be used on %s.""") \
|
_("""Determines what SASL password will be used on %s.""") \
|
||||||
% name, private=True))
|
% name, private=True))
|
||||||
|
registerGlobalValue(sasl, 'ecdsa_key', registry.String('',
|
||||||
|
_("""Determines what SASL ECDSA key (if any) will be used on %s.
|
||||||
|
The public key must be registered with NickServ for SASL
|
||||||
|
ECDSA-NIST256P-CHALLENGE to work.""") % name, private=False))
|
||||||
registerGlobalValue(network, 'socksproxy', registry.String('',
|
registerGlobalValue(network, 'socksproxy', registry.String('',
|
||||||
_("""If not empty, determines the hostname of the socks proxy that
|
_("""If not empty, determines the hostname of the socks proxy that
|
||||||
will be used to connect to this network.""")))
|
will be used to connect to this network.""")))
|
||||||
|
@ -33,6 +33,12 @@ import time
|
|||||||
import random
|
import random
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
try:
|
||||||
|
from ecdsa import SigningKey, BadDigestError
|
||||||
|
ecdsa = True
|
||||||
|
except ImportError:
|
||||||
|
ecdsa = False
|
||||||
|
|
||||||
from . import conf, ircdb, ircmsgs, ircutils, log, utils, world
|
from . import conf, ircdb, ircmsgs, ircutils, log, utils, world
|
||||||
from .utils.str import rsplit
|
from .utils.str import rsplit
|
||||||
from .utils.iter import imap, chain, cycle
|
from .utils.iter import imap, chain, cycle
|
||||||
@ -924,6 +930,11 @@ class Irc(IrcCommandDispatcher):
|
|||||||
# TODO Find a better way to fix this
|
# TODO Find a better way to fix this
|
||||||
if hasattr(self.sasl_password, 'decode'):
|
if hasattr(self.sasl_password, 'decode'):
|
||||||
self.sasl_password = self.sasl_password.decode('utf-8')
|
self.sasl_password = self.sasl_password.decode('utf-8')
|
||||||
|
self.sasl_ecdsa_key = \
|
||||||
|
conf.supybot.networks.get(self.network).sasl.ecdsa_key()
|
||||||
|
# TODO Find a better way to fix this
|
||||||
|
if hasattr(self.sasl_ecdsa_key, 'decode'):
|
||||||
|
self.sasl_ecdsa_key = self.sasl_ecdsa_key.decode('utf-8')
|
||||||
self.prefix = '%s!%s@%s' % (self.nick, self.ident, 'unset.domain')
|
self.prefix = '%s!%s@%s' % (self.nick, self.ident, 'unset.domain')
|
||||||
# The rest.
|
# The rest.
|
||||||
self.lastTake = 0
|
self.lastTake = 0
|
||||||
@ -943,7 +954,9 @@ class Irc(IrcCommandDispatcher):
|
|||||||
|
|
||||||
self.sasl = None
|
self.sasl = None
|
||||||
|
|
||||||
if (conf.supybot.networks.get(self.network).certfile() or
|
if ecdsa and self.sasl_username and self.sasl_ecdsa_key:
|
||||||
|
self.sasl = 'ecdsa-nist256p-challenge'
|
||||||
|
elif (conf.supybot.networks.get(self.network).certfile() or
|
||||||
conf.supybot.protocols.irc.certfile()):
|
conf.supybot.protocols.irc.certfile()):
|
||||||
self.sasl = 'external'
|
self.sasl = 'external'
|
||||||
elif self.sasl_username and self.sasl_password:
|
elif self.sasl_username and self.sasl_password:
|
||||||
@ -980,6 +993,9 @@ class Irc(IrcCommandDispatcher):
|
|||||||
|
|
||||||
if self.sasl == 'external':
|
if self.sasl == 'external':
|
||||||
authstring = '+'
|
authstring = '+'
|
||||||
|
elif self.sasl == 'ecdsa-nist256p-challenge':
|
||||||
|
authstring = base64.b64encode(
|
||||||
|
self.sasl_username.encode('utf-8')).decode('utf-8')
|
||||||
elif self.sasl == 'plain':
|
elif self.sasl == 'plain':
|
||||||
authstring = base64.b64encode('\0'.join([
|
authstring = base64.b64encode('\0'.join([
|
||||||
self.sasl_username,
|
self.sasl_username,
|
||||||
@ -988,6 +1004,17 @@ class Irc(IrcCommandDispatcher):
|
|||||||
]).encode('utf-8')).decode('utf-8')
|
]).encode('utf-8')).decode('utf-8')
|
||||||
|
|
||||||
self.queueMsg(ircmsgs.IrcMsg(command='AUTHENTICATE', args=(authstring,)))
|
self.queueMsg(ircmsgs.IrcMsg(command='AUTHENTICATE', args=(authstring,)))
|
||||||
|
elif (len(msg.args) == 1 and msg.args[0] != '+' and
|
||||||
|
self.sasl == 'ecdsa-nist256p-challenge'):
|
||||||
|
try:
|
||||||
|
private_key = SigningKey.from_pem(open(self.sasl_ecdsa_key).
|
||||||
|
read())
|
||||||
|
authstring = base64.b64encode(
|
||||||
|
private_key.sign(base64.b64decode(msg.args[0]))).decode('utf-8')
|
||||||
|
except (BadDigestError, OSError, ValueError) as e:
|
||||||
|
authstring = "*"
|
||||||
|
|
||||||
|
self.queueMsg(ircmsgs.IrcMsg(command='AUTHENTICATE', args=(authstring,)))
|
||||||
|
|
||||||
def doCap(self, msg):
|
def doCap(self, msg):
|
||||||
if len(msg.args) == 3:
|
if len(msg.args) == 3:
|
||||||
@ -1009,9 +1036,10 @@ class Irc(IrcCommandDispatcher):
|
|||||||
self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('END',)))
|
self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('END',)))
|
||||||
|
|
||||||
def do904(self, msg):
|
def do904(self, msg):
|
||||||
if (self.sasl == 'external' and self.sasl_username and
|
if (self.sasl != 'plain' and self.sasl_username and
|
||||||
self.sasl_password):
|
self.sasl_password):
|
||||||
log.info('%s: SASL EXTERNAL failed, trying PLAIN.', self.network)
|
log.info('%s: SASL %s failed, trying PLAIN.', self.network,
|
||||||
|
self.sasl.upper())
|
||||||
|
|
||||||
self.sasl = 'plain'
|
self.sasl = 'plain'
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user