Add support for 'account' in supybot.protocols.irc.banmask

And a new method .makeExtBanmask() as an alternative to .makeBanmask(),
so plugins can opt-in to extended banmasks when they support it.

'ignore' commands in Channel and anti-flood in Owner and Misc will
keep using .makeBanmask() because they use them as ignore masks in
ircdb.
This commit is contained in:
Valentin Lorentz 2022-11-23 19:22:45 +01:00
parent 5056f2e6ef
commit fc49d17faa
5 changed files with 61 additions and 15 deletions

View File

@ -163,7 +163,8 @@ class AutoMode(callbacks.Plugin):
# We're not in the channel anymore. # We're not in the channel anymore.
pass pass
schedule.addEvent(unban, time.time()+period) schedule.addEvent(unban, time.time()+period)
banmask =conf.supybot.protocols.irc.banmask.makeBanmask(msg.prefix) banmask = conf.supybot.protocols.irc.banmask.makeExtBanmask(
msg.prefix, channel=channel, network=irc.network)
irc.queueMsg(ircmsgs.ban(channel, banmask)) irc.queueMsg(ircmsgs.ban(channel, banmask))
irc.queueMsg(ircmsgs.kick(channel, msg.nick)) irc.queueMsg(ircmsgs.kick(channel, msg.nick))

View File

@ -368,7 +368,9 @@ class Channel(callbacks.Plugin):
try: try:
bannedHostmask = irc.state.nickToHostmask(target) bannedHostmask = irc.state.nickToHostmask(target)
banmaskstyle = conf.supybot.protocols.irc.banmask banmaskstyle = conf.supybot.protocols.irc.banmask
banmask = banmaskstyle.makeBanmask(bannedHostmask, [o[0] for o in optlist]) banmask = banmaskstyle.makeExtBanmask(
bannedHostmask, [o[0] for o in optlist],
channel=channel, network=irc.network)
except KeyError: except KeyError:
if not conf.supybot.protocols.irc.strictRfc() and \ if not conf.supybot.protocols.irc.strictRfc() and \
target.startswith('$'): target.startswith('$'):
@ -606,7 +608,9 @@ class Channel(callbacks.Plugin):
c.addBan(banmask, expires) c.addBan(banmask, expires)
ircdb.channels.setChannel(channel, c) ircdb.channels.setChannel(channel, c)
irc.replySuccess() irc.replySuccess()
add = wrap(add, ['op', first('hostmask', 'banmask'), additional('expiry', 0)]) add = wrap(add, ['op',
first('hostmask', 'extbanmask'),
additional('expiry', 0)])
@internationalizeDocstring @internationalizeDocstring
def remove(self, irc, msg, args, channel, banmask): def remove(self, irc, msg, args, channel, banmask):

View File

@ -273,14 +273,24 @@ class ChannelTestCase(ChannelPluginTestCase):
self.channel, prefix='foobar!user@host.domain.tld')) self.channel, prefix='foobar!user@host.domain.tld'))
join() join()
self.irc.feedMsg(ircmsgs.op(self.channel, self.irc.nick)) self.irc.feedMsg(ircmsgs.op(self.channel, self.irc.nick))
self.assertKban('kban --account --exact foobar',
'~a:account1')
join() for style in (['exact'], ['account', 'exact']):
self.assertKban('kban --account foobar', with conf.supybot.protocols.irc.banmask.context(style):
'~a:account1') self.assertKban('kban --account --exact foobar',
join() '~a:account1')
self.assertKban('kban --account --host foobar', join()
'~a:account1') self.assertKban('kban --account foobar',
'~a:account1')
join()
self.assertKban('kban --account --host foobar',
'~a:account1')
join()
with conf.supybot.protocols.irc.banmask.context(['account', 'exact']):
self.assertKban('kban foobar',
'~a:account1')
join()
def testBan(self): def testBan(self):
with conf.supybot.protocols.irc.banmask.context(['exact']): with conf.supybot.protocols.irc.banmask.context(['exact']):

View File

@ -435,7 +435,14 @@ def getBanmask(irc, msg, args, state):
getChannel(irc, msg, args, state) getChannel(irc, msg, args, state)
banmaskstyle = conf.supybot.protocols.irc.banmask banmaskstyle = conf.supybot.protocols.irc.banmask
state.args[-1] = banmaskstyle.makeBanmask(state.args[-1], state.args[-1] = banmaskstyle.makeBanmask(state.args[-1],
channel=state.channel) channel=state.channel, network=irc.network)
def getExtBanmask(irc, msg, args, state):
getHostmask(irc, msg, args, state)
getChannel(irc, msg, args, state)
banmaskstyle = conf.supybot.protocols.irc.extbanmask
state.args[-1] = banmaskstyle.makeExtBanmask(state.args[-1],
channel=state.channel, network=irc.network)
def getUser(irc, msg, args, state): def getUser(irc, msg, args, state):
try: try:
@ -806,6 +813,7 @@ wrappers = ircutils.IrcDict({
'commandName': getCommandName, 'commandName': getCommandName,
'email': getEmail, 'email': getEmail,
'expiry': getExpiry, 'expiry': getExpiry,
'extbanmask': getExtBanmask,
'filename': getSomething, # XXX Check for validity. 'filename': getSomething, # XXX Check for validity.
'float': getFloat, 'float': getFloat,
'glob': getGlob, 'glob': getGlob,

View File

@ -1181,7 +1181,7 @@ registerGroup(supybot.protocols, 'irc')
class Banmask(registry.SpaceSeparatedSetOfStrings): class Banmask(registry.SpaceSeparatedSetOfStrings):
__slots__ = ('__parent', '__dict__') # __dict__ is needed to set __doc__ __slots__ = ('__parent', '__dict__') # __dict__ is needed to set __doc__
validStrings = ('exact', 'nick', 'user', 'host') validStrings = ('exact', 'nick', 'user', 'host', 'account')
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
assert self.validStrings, 'There must be some valid strings. ' \ assert self.validStrings, 'There must be some valid strings. ' \
'This is a bug.' 'This is a bug.'
@ -1215,6 +1215,31 @@ class Banmask(registry.SpaceSeparatedSetOfStrings):
isn't specified via options, the value of isn't specified via options, the value of
conf.supybot.protocols.irc.banmask is used. conf.supybot.protocols.irc.banmask is used.
Unlike :meth:`makeExtBanmask`, this is guaranteed to return an
RFC1459-like mask, suitable for ircdb's ignore lists.
options - A list specifying which parts of the hostmask should
explicitly be matched: nick, user, host. If 'exact' is given, then
only the exact hostmask will be used.
"""
if not network:
network = dynamic.irc.network
if not options:
options = supybot.protocols.irc.banmask.getSpecific(
network, channel)()
options = [option for option in options if option != 'account']
return self.makeExtBanmask(hostmask, options, channel, network=network)
def makeExtBanmask(self, hostmask, options=None, channel=None, *, network):
"""Create a banmask from the given hostmask. If a style of banmask
isn't specified via options, the value of
conf.supybot.protocols.irc.banmask is used.
Depending on the options and configuration, this may return a mask
in the format of an extban (eg. "~account:foobar" on UnrealIRCd).
If this is unwanted (eg. to pass to ircdb's ignore lists, use
:meth:`makeBanmask` instead)
options - A list specifying which parts of the hostmask should options - A list specifying which parts of the hostmask should
explicitly be matched: nick, user, host. If 'exact' is given, then explicitly be matched: nick, user, host. If 'exact' is given, then
only the exact hostmask will be used. only the exact hostmask will be used.
@ -1224,8 +1249,6 @@ class Banmask(registry.SpaceSeparatedSetOfStrings):
""" """
if not channel: if not channel:
channel = dynamic.channel channel = dynamic.channel
if not network:
network = dynamic.irc.network
(nick, user, host) = ircutils.splitHostmask(hostmask) (nick, user, host) = ircutils.splitHostmask(hostmask)
bnick = '*' bnick = '*'
buser = '*' buser = '*'