From f00ecdeaefbaf5b6cca2c29ed98d72319090418f Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Fri, 26 May 2023 21:15:12 +0200 Subject: [PATCH] BadWords: Add the option to redact messages containing bad words instead of or in addition to kicking --- plugins/BadWords/config.py | 5 +++ plugins/BadWords/plugin.py | 63 ++++++++++++++++++++++++++------------ plugins/BadWords/test.py | 47 ++++++++++++++++++++++++++-- 3 files changed, 94 insertions(+), 21 deletions(-) diff --git a/plugins/BadWords/config.py b/plugins/BadWords/config.py index 9c9fb31ee..de908cc46 100644 --- a/plugins/BadWords/config.py +++ b/plugins/BadWords/config.py @@ -119,6 +119,11 @@ conf.registerChannelValue(BadWords, 'selfCensor', conf.registerChannelValue(BadWords, 'kick', registry.Boolean(False, _("""Determines whether the bot will kick people with a warning when they use bad words."""))) +conf.registerChannelValue(BadWords, 'redact', + registry.Boolean(False, _("""Determines whether the bot will redact + messages containing bad words (only on servers supporting IRCv3 + draft/message-redaction; requires supybot.protocols.irc.experimentalExtensions). + """))) conf.registerChannelValue(BadWords.kick, 'message', registry.NormalizedString(_("""You have been kicked for using a word prohibited in the presence of this bot. Please use more appropriate diff --git a/plugins/BadWords/plugin.py b/plugins/BadWords/plugin.py index a98e59320..c28c7cd35 100644 --- a/plugins/BadWords/plugin.py +++ b/plugins/BadWords/plugin.py @@ -1,7 +1,7 @@ ### # Copyright (c) 2002-2004, Jeremiah Fincher # Copyright (c) 2009, James McCoy -# Copyright (c) 2010-2021, Valentin Lorentz +# Copyright (c) 2010-2023, Valentin Lorentz # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -77,24 +77,49 @@ class BadWords(callbacks.Privmsg): channel = msg.channel self.updateRegexp(channel, irc.network) s = ircutils.stripFormatting(msg.args[1]) - if irc.isChannel(channel) \ - and self.registryValue('kick', channel, irc.network): - if self.regexp.search(s): - c = irc.state.channels[channel] - cap = ircdb.makeChannelCapability(channel, 'op') - if c.isHalfopPlus(irc.nick): - if c.isHalfopPlus(msg.nick) or \ - ircdb.checkCapability(msg.prefix, cap): - self.log.debug("Not kicking %s from %s, because " - "they are halfop+ or can't be " - "kicked.", msg.nick, channel) - else: - message = self.registryValue('kick.message', - channel, irc.network) - irc.queueMsg(ircmsgs.kick(channel, msg.nick, message)) - else: - self.log.warning('Should kick %s from %s, but not opped.', - msg.nick, channel) + if not irc.isChannel(channel): + # not a channel, don't bother checking + return msg + + may_kick = self.registryValue('kick', channel, irc.network) + msgid = msg.server_tags.get("msgid") + may_redact = ( + "draft/message-redaction" in irc.state.capabilities_ack + and msgid + and conf.supybot.protocols.irc.experimentalExtensions() + and self.registryValue('redact', channel, irc.network) + ) + + if not may_kick and not may_redact: + # no configured action, don't bother checking + return msg + + if not self.regexp.search(s): + # message does not contain a bad word + return msg + + c = irc.state.channels[channel] + cap = ircdb.makeChannelCapability(channel, 'op') + if not c.isHalfopPlus(irc.nick): + self.log.warning( + 'Should kick and/or redact %s from %s, but not opped.', + msg.nick, channel) + return msg + + if may_redact: + irc.queueMsg(ircmsgs.IrcMsg( + command="REDACT", args=(channel, msgid))) + + if may_kick: + if c.isHalfopPlus(msg.nick) or \ + ircdb.checkCapability(msg.prefix, cap): + self.log.debug("Not kicking %s from %s, because " + "they are halfop+ or can't be " + "kicked.", msg.nick, channel) + else: + message = self.registryValue('kick.message', + channel, irc.network) + irc.queueMsg(ircmsgs.kick(channel, msg.nick, message)) return msg def updateRegexp(self, channel, network): diff --git a/plugins/BadWords/test.py b/plugins/BadWords/test.py index fa337ec6f..6ba9c1821 100644 --- a/plugins/BadWords/test.py +++ b/plugins/BadWords/test.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2002-2004, Jeremiah Fincher -# Copyright (c) 2010-2021, Valentin Lorentz +# Copyright (c) 2010-2023, Valentin Lorentz # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ import supybot.conf as conf from supybot.test import * -class BadWordsTestCase(PluginTestCase): +class BadWordsOutfilterTestCase(PluginTestCase): plugins = ('BadWords', 'Utilities', 'Format', 'Filter') badwords = ('shit', 'ass', 'fuck') def tearDown(self): @@ -80,5 +80,48 @@ class BadWordsTestCase(PluginTestCase): self.assertNotError('badwords add "fuck you"') self.assertResponse('badwords list', 'ass, fuck you, and shit') + +class BadWordsInfilterTestCase(ChannelPluginTestCase): + plugins = ('BadWords',) + badwords = ('shit', 'ass', 'fuck') + def tearDown(self): + # .default() doesn't seem to be working for BadWords.words + #default = conf.supybot.plugins.BadWords.words.default() + #conf.supybot.plugins.BadWords.words.setValue(default) + conf.supybot.plugins.BadWords.words.setValue([]) + + def testKick(self): + self.irc.feedMsg(ircmsgs.op(self.channel, self.nick)) + self.assertNotError('badwords add shit') + + with conf.supybot.plugins.BadWords.kick \ + .getSpecific(self.irc.network, self.channel).context(True): + self.irc.feedMsg(ircmsgs.privmsg(self.channel, + 'oh shit', + prefix='foobar!user@__no_testcap__')) + m = self.getMsg(' ') + self.assertIsNotNone(m) + self.assertEqual(m.command, 'KICK', m) + self.assertEqual(m.args[0], self.channel, m) + self.assertEqual(m.args[1], 'foobar', m) + + def testRedact(self): + self.irc.feedMsg(ircmsgs.op(self.channel, self.nick)) + self.irc.state.capabilities_ack.add('draft/message-redaction') + self.assertNotError('badwords add shit') + + with conf.supybot.plugins.BadWords.redact \ + .getSpecific(self.irc.network, self.channel).context(True): + with conf.supybot.protocols.irc.experimentalExtensions.context(True): + self.irc.feedMsg(ircmsgs.IrcMsg( + command='PRIVMSG', + args=(self.channel, 'oh shit'), + prefix='foobar!user@__no_testcap__', + server_tags={'msgid': 'abcde'})) + m = self.getMsg(' ', timeout=0.5) + self.assertIsNotNone(m) + self.assertEqual(m.command, 'REDACT', m) + self.assertEqual(m.args, (self.channel, 'abcde'), m) + # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: