ircutils: Improve robustness when faced with invalid hostmasks

eg. @ in nicks, which happened on pissnet earlier today.
This commit is contained in:
Valentin Lorentz 2021-07-14 23:25:11 +02:00
parent 0af4af16d3
commit 5baf87ddba
3 changed files with 28 additions and 4 deletions

View File

@ -60,7 +60,11 @@ def debug(s, *args):
"""Prints a debug string. Most likely replaced by our logging debug."""
print('***', s % args)
userHostmaskRe = re.compile(r'^\S+!\S+@\S+$')
def warning(s, *args):
"""Prints a debug string. Most likely replaced by our logging debug."""
print('###', s % args)
userHostmaskRe = re.compile(r'^(?P<nick>\S+?)!(?P<user>\S+?)@(?P<host>\S+)$')
def isUserHostmask(s):
"""Returns whether or not the string s is a valid User hostmask."""
return userHostmaskRe.match(s) is not None
@ -91,9 +95,17 @@ def hostFromHostmask(hostmask):
def splitHostmask(hostmask):
"""hostmask => (nick, user, host)
Returns the nick, user, host of a user hostmask."""
assert isUserHostmask(hostmask)
nick, rest = hostmask.rsplit('!', 1)
user, host = rest.rsplit('@', 1)
m = userHostmaskRe.match(hostmask)
assert m is not None, hostmask
nick = m.group("nick")
user = m.group("user")
host = m.group("host")
if set("!@") & set(nick+user+host):
# There should never be either of these characters in the part.
# As far as I know it never happens in practice aside from networks
# broken by design.
warning("Invalid hostmask format: %s", hostmask)
# TODO: error if strictRfc is True
return (minisix.intern(nick), minisix.intern(user), minisix.intern(host))
def joinHostmask(nick, ident, host):

View File

@ -329,6 +329,7 @@ atexit.register(logging.shutdown)
# ircutils will work without this, but it's useful.
ircutils.debug = debug
ircutils.warning = warning
def getPluginLogger(name):
if not conf.supybot.log.plugins.individualLogfiles():

View File

@ -113,6 +113,17 @@ class FunctionsTestCase(SupyTestCase):
self.assertFalse(ircutils.isUserHostmask('@'))
self.assertFalse(ircutils.isUserHostmask('!bar@baz'))
def testSplitHostmask(self):
# This is the only valid case:
self.assertEqual(ircutils.splitHostmask('foo!bar@baz'),
('foo', 'bar', 'baz'))
# Extravagant cases that never happen on real networks:
self.assertEqual(ircutils.splitHostmask('foo!bar@baz!qux'),
('foo', 'bar', 'baz!qux'))
self.assertEqual(ircutils.splitHostmask('foo!bar@baz!qux@quux'),
('foo', 'bar', 'baz!qux@quux'))
def testIsChannel(self):
self.assertTrue(ircutils.isChannel('#'))
self.assertTrue(ircutils.isChannel('&'))