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.
pass
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.kick(channel, msg.nick))

View File

@ -368,7 +368,9 @@ class Channel(callbacks.Plugin):
try:
bannedHostmask = irc.state.nickToHostmask(target)
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:
if not conf.supybot.protocols.irc.strictRfc() and \
target.startswith('$'):
@ -606,7 +608,9 @@ class Channel(callbacks.Plugin):
c.addBan(banmask, expires)
ircdb.channels.setChannel(channel, c)
irc.replySuccess()
add = wrap(add, ['op', first('hostmask', 'banmask'), additional('expiry', 0)])
add = wrap(add, ['op',
first('hostmask', 'extbanmask'),
additional('expiry', 0)])
@internationalizeDocstring
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'))
join()
self.irc.feedMsg(ircmsgs.op(self.channel, self.irc.nick))
self.assertKban('kban --account --exact foobar',
'~a:account1')
join()
self.assertKban('kban --account foobar',
'~a:account1')
join()
self.assertKban('kban --account --host foobar',
'~a:account1')
for style in (['exact'], ['account', 'exact']):
with conf.supybot.protocols.irc.banmask.context(style):
self.assertKban('kban --account --exact foobar',
'~a:account1')
join()
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):
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)
banmaskstyle = conf.supybot.protocols.irc.banmask
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):
try:
@ -806,6 +813,7 @@ wrappers = ircutils.IrcDict({
'commandName': getCommandName,
'email': getEmail,
'expiry': getExpiry,
'extbanmask': getExtBanmask,
'filename': getSomething, # XXX Check for validity.
'float': getFloat,
'glob': getGlob,

View File

@ -1181,7 +1181,7 @@ registerGroup(supybot.protocols, 'irc')
class Banmask(registry.SpaceSeparatedSetOfStrings):
__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):
assert self.validStrings, 'There must be some valid strings. ' \
'This is a bug.'
@ -1215,6 +1215,31 @@ class Banmask(registry.SpaceSeparatedSetOfStrings):
isn't specified via options, the value of
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
explicitly be matched: nick, user, host. If 'exact' is given, then
only the exact hostmask will be used.
@ -1224,8 +1249,6 @@ class Banmask(registry.SpaceSeparatedSetOfStrings):
"""
if not channel:
channel = dynamic.channel
if not network:
network = dynamic.irc.network
(nick, user, host) = ircutils.splitHostmask(hostmask)
bnick = '*'
buser = '*'