mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-02 16:09:24 +01:00
Better implementation of relay detecting/punishing.
This commit is contained in:
parent
019a53cdae
commit
b9d109222a
119
plugins/Relay.py
119
plugins/Relay.py
@ -53,7 +53,7 @@ import supybot.ircmsgs as ircmsgs
|
|||||||
import supybot.ircutils as ircutils
|
import supybot.ircutils as ircutils
|
||||||
import supybot.registry as registry
|
import supybot.registry as registry
|
||||||
import supybot.callbacks as callbacks
|
import supybot.callbacks as callbacks
|
||||||
from supybot.structures import RingBuffer, MultiSet
|
from supybot.structures import MultiSet, TimeoutQueue
|
||||||
|
|
||||||
def configure(advanced):
|
def configure(advanced):
|
||||||
from supybot.questions import output, expect, anything, something, yn
|
from supybot.questions import output, expect, anything, something, yn
|
||||||
@ -87,12 +87,16 @@ conf.registerChannelValue(conf.supybot.plugins.Relay, 'includeNetwork',
|
|||||||
registry.Boolean(True, """Determines whether the bot will include the
|
registry.Boolean(True, """Determines whether the bot will include the
|
||||||
network in relayed PRIVMSGs; if you're only relaying between two networks,
|
network in relayed PRIVMSGs; if you're only relaying between two networks,
|
||||||
it's somewhat redundant, and you may wish to save the space."""))
|
it's somewhat redundant, and you may wish to save the space."""))
|
||||||
conf.registerChannelValue(conf.supybot.plugins.Relay, 'detectOtherRelayBots',
|
conf.registerChannelValue(conf.supybot.plugins.Relay, 'punishOtherRelayBots',
|
||||||
registry.Boolean(False, """Determines whether the bot will detect other
|
registry.Boolean(False, """Determines whether the bot will detect other
|
||||||
bots relaying and respond by kickbanning them."""))
|
bots relaying and respond by kickbanning them."""))
|
||||||
conf.registerGlobalValue(conf.supybot.plugins.Relay, 'channels',
|
conf.registerGlobalValue(conf.supybot.plugins.Relay, 'channels',
|
||||||
conf.SpaceSeparatedSetOfChannels([], """Determines which channels the bot
|
conf.SpaceSeparatedSetOfChannels([], """Determines which channels the bot
|
||||||
will relay in."""))
|
will relay in."""))
|
||||||
|
conf.registerChannelValue(conf.supybot.plugins.Relay.channels,
|
||||||
|
'joinOnAllNetworks', registry.Boolean(True, """Determines whether the bot
|
||||||
|
will always join the channel(s) it relays for on all networks the bot is
|
||||||
|
connected to."""))
|
||||||
|
|
||||||
class Relay(callbacks.Privmsg):
|
class Relay(callbacks.Privmsg):
|
||||||
noIgnore = True
|
noIgnore = True
|
||||||
@ -103,7 +107,7 @@ class Relay(callbacks.Privmsg):
|
|||||||
self.lastmsg = {}
|
self.lastmsg = {}
|
||||||
self.ircstates = {}
|
self.ircstates = {}
|
||||||
self.queuedTopics = MultiSet()
|
self.queuedTopics = MultiSet()
|
||||||
self.last20Privmsgs = ircutils.IrcDict()
|
self.lastRelayMsgs = ircutils.IrcDict()
|
||||||
|
|
||||||
def __call__(self, irc, msg):
|
def __call__(self, irc, msg):
|
||||||
try:
|
try:
|
||||||
@ -118,8 +122,9 @@ class Relay(callbacks.Privmsg):
|
|||||||
def do376(self, irc, msg):
|
def do376(self, irc, msg):
|
||||||
L = []
|
L = []
|
||||||
for channel in self.registryValue('channels'):
|
for channel in self.registryValue('channels'):
|
||||||
if channel not in irc.state.channels:
|
if self.registryValue('channels.joinOnAllNetworks', channel):
|
||||||
L.append(channel)
|
if channel not in irc.state.channels:
|
||||||
|
L.append(channel)
|
||||||
if L:
|
if L:
|
||||||
irc.queueMsg(ircmsgs.joins(L))
|
irc.queueMsg(ircmsgs.joins(L))
|
||||||
do377 = do422 = do376
|
do377 = do422 = do376
|
||||||
@ -360,50 +365,37 @@ class Relay(callbacks.Privmsg):
|
|||||||
msg.tag('relayedMsg')
|
msg.tag('relayedMsg')
|
||||||
otherIrc.queueMsg(msg)
|
otherIrc.queueMsg(msg)
|
||||||
|
|
||||||
def _detectRelays(self, irc, msg, channel):
|
def _checkRelayMsg(self, msg):
|
||||||
def isRelayPrefix(s):
|
channel = msg.args[0]
|
||||||
return s and s[0] == '<' and s[-1] == '>'
|
if channel in self.lastRelayMsgs:
|
||||||
def punish():
|
q = self.lastRelayMsgs[channel]
|
||||||
punished = False
|
unformatted = ircutils.stripFormatting(msg.args[1])
|
||||||
for irc in world.ircs:
|
normalized = utils.normalizeWhitespace(unformatted)
|
||||||
if channel in irc.state.channels:
|
for s in q:
|
||||||
if irc.nick in irc.state.channels[channel].ops:
|
if s in normalized:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _punishRelayers(self, msg):
|
||||||
|
assert self._checkRelayMsg(msg), 'Punishing without checking.'
|
||||||
|
who = msg.prefix
|
||||||
|
channel = msg.args[0]
|
||||||
|
def notPunishing(irc, s, *args):
|
||||||
|
self.log.info('Not punishing %s in %s on %s: %s.',
|
||||||
|
msg.prefix, channel, irc.network, s, *args)
|
||||||
|
for irc in world.ircs:
|
||||||
|
if channel in irc.state.channels:
|
||||||
|
if irc.nick in irc.state.channels[channel].ops:
|
||||||
|
if who in irc.state.channels[channel].bans:
|
||||||
|
notPunishing(irc, 'already banned')
|
||||||
|
else:
|
||||||
self.log.info('Punishing %s in %s on %s for relaying.',
|
self.log.info('Punishing %s in %s on %s for relaying.',
|
||||||
msg.prefix, channel, irc.network)
|
who, channel, irc.network)
|
||||||
irc.sendMsg(ircmsgs.ban(channel, msg.prefix))
|
irc.sendMsg(ircmsgs.ban(channel, who))
|
||||||
kmsg = 'You seem to be relaying, punk.'
|
kmsg = 'You seem to be relaying, punk.'
|
||||||
irc.sendMsg(ircmsgs.kick(channel, msg.nick, kmsg))
|
irc.sendMsg(ircmsgs.kick(channel, msg.nick, kmsg))
|
||||||
punished = True
|
else:
|
||||||
else:
|
notPunishing(irc, 'not opped')
|
||||||
self.log.warning('Can\'t punish %s in %s on %s; '
|
|
||||||
'I\'m not opped.',
|
|
||||||
msg.prefix, channel, irc.network)
|
|
||||||
return punished
|
|
||||||
if channel not in self.last20Privmsgs:
|
|
||||||
self.last20Privmsgs[channel] = RingBuffer(20)
|
|
||||||
s = ircutils.stripFormatting(msg.args[1])
|
|
||||||
s = utils.normalizeWhitespace(s)
|
|
||||||
try:
|
|
||||||
(prefix, suffix) = s.split(None, 1)
|
|
||||||
except ValueError, e:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if isRelayPrefix(prefix):
|
|
||||||
parts = suffix.split()
|
|
||||||
while parts and isRelayPrefix(parts[0]):
|
|
||||||
parts.pop(0)
|
|
||||||
suffix = ' '.join(parts)
|
|
||||||
for m in self.last20Privmsgs[channel]:
|
|
||||||
if suffix in m:
|
|
||||||
who = msg.prefix
|
|
||||||
self.log.info('%s seems to be relaying too.', who)
|
|
||||||
if punish():
|
|
||||||
self.log.info('Successfully punished %s.', who)
|
|
||||||
else:
|
|
||||||
self.log.info('Unsuccessfully attempted to '
|
|
||||||
'punish %s.', who)
|
|
||||||
break
|
|
||||||
self.last20Privmsgs[channel].append(s)
|
|
||||||
|
|
||||||
def doPrivmsg(self, irc, msg):
|
def doPrivmsg(self, irc, msg):
|
||||||
(channel, text) = msg.args
|
(channel, text) = msg.args
|
||||||
@ -415,12 +407,19 @@ class Relay(callbacks.Privmsg):
|
|||||||
'AWAY' not in text and 'ACTION' not in text:
|
'AWAY' not in text and 'ACTION' not in text:
|
||||||
return
|
return
|
||||||
# Let's try to detect other relay bots.
|
# Let's try to detect other relay bots.
|
||||||
if self.registryValue('detectOtherRelayBots', channel):
|
if self._checkRelayMsg(msg):
|
||||||
self._detectRelays(irc, msg, channel)
|
if self.registryValue('punishOtherRelayBots', channel):
|
||||||
network = self._getIrcName(irc)
|
self._punishRelayers(msg)
|
||||||
s = self._formatPrivmsg(msg.nick, network, msg)
|
# Either way, we don't relay the message.
|
||||||
m = ircmsgs.privmsg(channel, s)
|
else:
|
||||||
self._sendToOthers(irc, m)
|
self.log.warning('Refusing to relay message from %s, '
|
||||||
|
'it appears to be a relay message.',
|
||||||
|
msg.prefix)
|
||||||
|
else:
|
||||||
|
network = self._getIrcName(irc)
|
||||||
|
s = self._formatPrivmsg(msg.nick, network, msg)
|
||||||
|
m = ircmsgs.privmsg(channel, s)
|
||||||
|
self._sendToOthers(irc, m)
|
||||||
|
|
||||||
def doJoin(self, irc, msg):
|
def doJoin(self, irc, msg):
|
||||||
irc = self._getRealIrc(irc)
|
irc = self._getRealIrc(irc)
|
||||||
@ -530,7 +529,9 @@ class Relay(callbacks.Privmsg):
|
|||||||
def outFilter(self, irc, msg):
|
def outFilter(self, irc, msg):
|
||||||
irc = self._getRealIrc(irc)
|
irc = self._getRealIrc(irc)
|
||||||
if msg.command == 'PRIVMSG':
|
if msg.command == 'PRIVMSG':
|
||||||
if not msg.relayedMsg:
|
if msg.relayedMsg:
|
||||||
|
self._addRelayMsg(msg)
|
||||||
|
else:
|
||||||
channel = msg.args[0]
|
channel = msg.args[0]
|
||||||
if channel in self.registryValue('channels'):
|
if channel in self.registryValue('channels'):
|
||||||
network = self._getIrcName(irc)
|
network = self._getIrcName(irc)
|
||||||
@ -539,6 +540,18 @@ class Relay(callbacks.Privmsg):
|
|||||||
self._sendToOthers(irc, relayMsg)
|
self._sendToOthers(irc, relayMsg)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
def _addRelayMsg(self, msg):
|
||||||
|
channel = msg.args[0]
|
||||||
|
if channel in self.lastRelayMsgs:
|
||||||
|
q = self.lastRelayMsgs[channel]
|
||||||
|
else:
|
||||||
|
q = TimeoutQueue(60) # XXX Make this configurable.
|
||||||
|
self.lastRelayMsgs[channel] = q
|
||||||
|
unformatted = ircutils.stripFormatting(msg.args[1])
|
||||||
|
normalized = utils.normalizeWhitespace(unformatted)
|
||||||
|
q.enqueue(normalized)
|
||||||
|
|
||||||
|
|
||||||
Class = Relay
|
Class = Relay
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
Loading…
Reference in New Issue
Block a user