Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 43 additions & 19 deletions sopel/modules/adminchannel.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,28 +117,37 @@ def kick(bot, trigger):


def configureHostMask(mask):
if mask == '*!*@*':
return mask
if re.match('^[^.@!/]+$', mask) is not None:
# shortcut for nick!*@*
if re.match(r'^[^.@!/\s]+$', mask) is not None:
return '%s!*@*' % mask
if re.match('^[^@!]+$', mask) is not None:

# shortcut for *!*@host
# won't work for local names w/o dot, but does support cloaks/with/slashes
if re.match(r'^[^@!\s]+$', mask) is not None:
return '*!*@%s' % mask

m = re.match('^([^!@]+)@$', mask)
# shortcut for *!user@*
# requires trailing @ to be recognized as a username instead of a nick
m = re.match(r'^([^!@\s]+)@$', mask)
if m is not None:
return '*!%s@*' % m.group(1)

m = re.match('^([^!@]+)@([^@!]+)$', mask)
# shortcut for *!user@host
m = re.match(r'^([^!@\s]+)@([^@!\s]+)$', mask)
if m is not None:
return '*!%s@%s' % (m.group(1), m.group(2))

m = re.match('^([^!@]+)!(^[!@]+)@?$', mask)
# shortcut for nick!user@*
m = re.match(r'^([^!@\s]+)!([^!@\s]+)@?$', mask)
if m is not None:
return '%s!%s@*' % (m.group(1), m.group(2))

if re.match(r'^\S+[!]\S+[@]\S+$', mask) is not None:
# not a shortcut; validate full NUH format
if re.match(r'^[^!@\s]+![^!@\s]+@[^!@\s]+$', mask) is not None:
return mask
return ''

# not a shortcut nor a valid hostmask
raise ValueError('Invalid hostmask format or unsupported shorthand')


@plugin.require_chanmsg
Expand All @@ -163,9 +172,12 @@ def ban(bot, trigger):
return
channel = opt
banmask = text[2]
banmask = configureHostMask(banmask)
if banmask == '':

try:
banmask = configureHostMask(banmask)
except ValueError:
return

bot.write(['MODE', channel, '+b', banmask])


Expand All @@ -190,9 +202,12 @@ def unban(bot, trigger):
return
channel = opt
banmask = text[2]
banmask = configureHostMask(banmask)
if banmask == '':

try:
banmask = configureHostMask(banmask)
except ValueError:
return

bot.write(['MODE', channel, '-b', banmask])


Expand All @@ -217,9 +232,12 @@ def quiet(bot, trigger):
return
quietmask = text[2]
channel = opt
quietmask = configureHostMask(quietmask)
if quietmask == '':

try:
quietmask = configureHostMask(quietmask)
except ValueError:
return

bot.write(['MODE', channel, '+q', quietmask])


Expand All @@ -244,9 +262,12 @@ def unquiet(bot, trigger):
return
quietmask = text[2]
channel = opt
quietmask = configureHostMask(quietmask)
if quietmask == '':

try:
quietmask = configureHostMask(quietmask)
except ValueError:
return

bot.write(['MODE', channel, '-q', quietmask])


Expand Down Expand Up @@ -278,9 +299,12 @@ def kickban(bot, trigger):
mask = text[3]
reasonidx = 4
reason = ' '.join(text[reasonidx:])
mask = configureHostMask(mask)
if mask == '':

try:
mask = configureHostMask(mask)
except ValueError:
return

bot.write(['MODE', channel, '+b', mask])
bot.kick(nick, channel, reason)

Expand Down
43 changes: 43 additions & 0 deletions test/modules/test_modules_adminchannel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Tests for Sopel's ``adminchannel`` plugin"""
from __future__ import generator_stop

import pytest

from sopel.modules import adminchannel


VALID_INPUTS = (
('justanick', 'justanick!*@*'),
('just-a.host', '*!*@just-a.host'),
('justauser@', '*!justauser@*'),
('[email protected]', '*[email protected]'),
('someuser@dotlesshost', '*!someuser@dotlesshost'),
('somenick!someuser', 'somenick!someuser@*'),
('somenick!someuser@', 'somenick!someuser@*'),
('somenick!someuser@', 'somenick!someuser@*'),
('full!host@mask', 'full!host@mask'),
('[email protected]', '[email protected]'),
('libera/style/cloak', '*!*@libera/style/cloak'),
)

INVALID_INPUTS = (
'mask with whitespace',
'cloak/with whitespace',
'nick!auser@something with whitespace',
'nick with spaces!user@host',
'nick!user with spaces@host',
'two!user!names@host',
'two!user@host@names',
)


@pytest.mark.parametrize('raw, checked', VALID_INPUTS)
def test_configureHostMask(raw, checked):
"""Test the `configureHostMask` helper for functionality and compatibility."""
assert adminchannel.configureHostMask(raw) == checked


@pytest.mark.parametrize('raw', INVALID_INPUTS)
def test_configureHostMask_invalid(raw):
with pytest.raises(ValueError):
adminchannel.configureHostMask(raw)