From ab75d45867ce62aa2ab71e2dc8077cabd0010e45 Mon Sep 17 00:00:00 2001 From: Pratyush Desai Date: Fri, 20 Aug 2021 14:05:26 +0530 Subject: [PATCH] WIP quiet and ban --- outline.rst | 22 +++--- plugin.py | 213 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 186 insertions(+), 49 deletions(-) diff --git a/outline.rst b/outline.rst index 0506ec2..db4c8cb 100644 --- a/outline.rst +++ b/outline.rst @@ -7,27 +7,27 @@ The permissions are inherited in descending order. Tier 1 inherits Tier 2 ... |Commands |Description | Tier | Channel | Status | | | | | Restrictions| | +===========+=============+============+=============+==========+ -| DEFCON | | Admins/Ops | column 3 | DONE | +| DEFCON | | Admins/Ops | public | DONE | +-----------+-------------+------------+-------------+----------+ -| SAJOIN | | Admins/Ops | | DONE | +| SAJOIN | | Admins/Ops | public | DONE | +-----------+-------------+------------+-------------+----------+ -| SANICK | | Admins/Ops | column 3 | column 4 | +| SANICK | | Admins/Ops | column 3 | DONE | +-----------+-------------+------------+-------------+----------+ -| KILL | | Admins/Ops | | | +| KILL | | Admins/Ops | public | DONE | +-----------+-------------+------------+-------------+----------+ -| UBAN | | Moderators | column 3 | column 4 | +| UBAN | | Moderators | public | WIP | +-----------+-------------+------------+-------------+----------+ -| NBAN | | Moderators | | | +| NBAN | | Moderators | public | WIP | +-----------+-------------+------------+-------------+----------+ -| KBAN | | Moderators | column 3 | column 4 | +| KBAN | | Moderators | public | EXISTS | +-----------+-------------+------------+-------------+----------+ -| SUSTATUS | | Moderators | | | +| SUSTATUS | | Moderators | staff, pm | TBD | +-----------+-------------+------------+-------------+----------+ -| WARN | | Tripsitters| column 3 | column 4 | +| WARN | | Tripsitters| public | TBD | +-----------+-------------+------------+-------------+----------+ -| ADDNOTE | | Tripsitters| | | +| ADDNOTE | | Tripsitters| staff, pm | TBD | +-----------+-------------+------------+-------------+----------+ -| STATUS | | Tripsitters| column 3 | column 4 | +| STATUS | | Tripsitters| staff, pm | TBD | +-----------+-------------+------------+-------------+----------+ | QUIET | | Tripsitters| | | +-----------+-------------+------------+-------------+----------+ diff --git a/plugin.py b/plugin.py index a40a029..ea537df 100644 --- a/plugin.py +++ b/plugin.py @@ -28,7 +28,12 @@ ### -from supybot import utils, plugins, ircutils, callbacks, irclib, ircmsgs, conf, world, log +# My Imports + + + +from supybot import utils, plugins, ircutils, callbacks, irclib, ircmsgs, +from supybot import conf, world, log, ircdb, registry, schedule from supybot.commands import * try: from supybot.i18n import PluginInternationalization @@ -44,6 +49,69 @@ except ImportError: # filename = conf.supybot.directories.data.dirize("EgoServ.db") +# Perms Decorator +def ensure_permissions(min_permission_group): + "Ensures user belongs to a least permission group" + def decorator(function): + def wrapper(*args,**kwargs): + print(args) + print(kwargs) + return function(*args, **kwargs) + return wrapper + return decorator + +# Taken from plugins.Time.seconds +def getTs(irc, msg, args, state): + """[y] [w] [d] [h] [m] [s] + Returns the number of seconds in the number of , , + , , , and given. An example usage is + "seconds 2h 30m", which would return 9000, which is '3600*2 + 30*60'. + Useful for scheduling events at a given number of seconds in the + future. + """ + # here there is some glitch / ugly hack to allow any('getTs'), with rest('test') after... + # TODO: check that bot can't kill itself with loop + seconds = -1 + items = list(args) + for arg in items: + if not (arg and arg[-1] in 'ywdhms'): + try: + n = int(arg) + state.args.append(n) + except: + state.args.append(float(seconds)) + raise callbacks.ArgumentError + (s, kind) = arg[:-1], arg[-1] + try: + i = int(s) + except ValueError: + state.args.append(float(seconds)) + raise callbacks.ArgumentError + if kind == 'y': + seconds += i*31536000 + elif kind == 'w': + seconds += i*604800 + elif kind == 'd': + seconds += i*86400 + elif kind == 'h': + seconds += i*3600 + elif kind == 'm': + seconds += i*60 + elif kind == 's': + if i == 0: + i = 1 + seconds += i + elif kind == '-': + state.args.append(float(seconds)) + raise callbacks.ArgumentError + args.pop(0) + state.args.append(float(seconds)) + + +addConverter('getTs', getTs) + + + class EgoServ(callbacks.Plugin): """Suite of tools to help Network Operators run their ErgoIRCd nets""" threaded = True @@ -100,6 +168,7 @@ class EgoServ(callbacks.Plugin): # KILL + @ensure_permissions(5) @wrap(['nick', optional('something')]) def kill(self, irc, msg, args, nick, reason): """ [] @@ -162,48 +231,115 @@ class EgoServ(callbacks.Plugin): # Channel Administration ###### - # Only Talking to CS isn't enough because - # CS doesn't handle expiring bans mutes - - - # Use mute Extban - - - # @wrap(['nick', 'channel', optional('expiry', 0), 'something']) - # def mute(self, irc, msg, args, nick, channel, duration, reason): - # @wrap(['nick', 'channel']) - # def mute(self, irc, msg, args, nick, channel): - # """ [] + def _ban(self, irc, msg, args, + channel, optlist, target, getTs, reason, kick): + # Check that they're not trying to make us kickban ourself. + if irc.isNick(target): + bannedNick = target + try: + bannedHostmask = irc.state.nickToHostmask(target) + banmaskstyle = conf.supybot.protocols.irc.banmask + banmask = banmaskstyle.makeBanmask(bannedHostmask, [o[0] for o in optlist]) + except KeyError: + ## WTF IS THIS + if not conf.supybot.protocols.irc.strictRfc() and \ + target.startswith('$'): + # Select the last part, or the whole target: + bannedNick = target.split(':')[-1] + banmask = bannedHostmask = target + else: + irc.error(format(_('I haven\'t seen %s.'), bannedNick), Raise=True) + else: + bannedNick = ircutils.nickFromHostmask(target) + banmask = bannedHostmask = target + if not irc.isNick(bannedNick): + self.log.warning('%q tried to kban a non nick: %q', + msg.prefix, bannedNick) + raise callbacks.ArgumentError + elif bannedNick == irc.nick: + self.log.warning('%q tried to make me kban myself.', msg.prefix) + irc.error(_('I cowardly refuse to kickban myself.')) + return + if not reason: + reason = msg.nick - # Issues an extban which mutes the hostmask associated with the - # - # """ - # # add --all flag for muting the hostmask/account in all channels - # # on the current network + capability = ircdb.makeChannelCapability(channel, 'op') + # Check (again) that they're not trying to make us kickban ourself. + if ircutils.hostmaskPatternEqual(banmask, irc.prefix): + if ircutils.hostmaskPatternEqual(bannedHostmask, irc.prefix): + self.log.warning('%q tried to make me kban myself.',msg.prefix) + irc.error(_('I cowardly refuse to ban myself.')) + return + else: + self.log.warning('Using exact hostmask since banmask would ' + 'ban myself.') + banmask = bannedHostmask + # Now, let's actually get to it. Check to make sure they have + # #channel,op and the bannee doesn't have #channel,op; or that the + # bannee and the banner are both the same person. + def doBan(): + if irc.state.channels[channel].isOp(bannedNick): + irc.queueMsg(ircmsgs.deop(channel, bannedNick)) + irc.queueMsg(ircmsgs.ban(channel, banmask)) + if kick: + irc.queueMsg(ircmsgs.kick(channel, bannedNick, reason)) + if getTs > 0: + def f(): + if channel in irc.state.channels and \ + banmask in irc.state.channels[channel].bans: + irc.queueMsg(ircmsgs.unban(channel, banmask)) + schedule.addEvent(f, ) + if bannedNick == msg.nick: + doBan() + elif ircdb.checkCapability(msg.prefix, capability): + if ircdb.checkCapability(bannedHostmask, capability) and \ + not ircdb.checkCapability(msg.prefix, 'owner'): + self.log.warning('%s tried to ban %q, but both have %s', + msg.prefix, bannedHostmask, capability) + irc.error(format(_('%s has %s too, you can\'t ban ' + 'them.'), bannedNick, capability)) + else: + doBan() + else: + self.log.warning('%q attempted kban without %s', + msg.prefix, capability) + irc.errorNoCapability(capability) - # # Seconds needs to be human readable i.e. 5w 3d 2h + def nban(self, irc, msg, args, + bannedNick, getTs, reason): + """ [] [] + If you have the #channel,op capability, this will kickban 's banmask from + for + the time period specified. Not specifying the time period it will ban the user + indefinitely. is optional but recommended. + """ + self._ban(irc, msg, args, bannedNick, reason, True) + nban = wrap(nban, + ['haveOp', + + ('haveHalfop+', _('kick or ban someone')), + 'nickInChannel', + optional('', 0), + additional('text')]) - # # Do we care about adding quiets/mutes for accounts not online - # # via --host specification or even an --account - # # Fuck 'duration' and 'reason' for now - # # What I'm doing is very filthy - # # Refer to how the core channel plugin deals with this. - # # https://github.com/ProgVal/Limnoria/blob/master/plugins/Channel/plugin.py#L358 - # try: - # (nick, ident, host) = ircutils.splitHostmask(irc.state.nickToHostmask(nick)) - # except KeyError: - # irc.error( - # "No such nick", - # Raise=True, - # ) - # if nick == irc.nick: - # self.log.warning(f'{msg.prefix} tried to make me mute myself.', ) - # irc.error(_('No, I would like to preserve my right to speech!')) - # return - - # irc.queueMsg() + + @wrap(['nick', 'channel', optional('getTs'), 'something']) + def quiet(self, irc, msg, args, nick, channel, duration, reason="Fuck Knows!"): + """ [] [] [] + + Quiets the banmask associated with for the time period specified + . If not specified, it will quiet the user indefinitely. + is optional but recommended! is only necessary if + the command is not sent in the channel itself. + """ + try: + (nick, ident, host) = \ + ircutils.splitHostmask(irc.state.nickToHostmask(nick)) + except KeyError: + irc.error(format("No such nick"), Raise=True) + @wrap(['channel', 'something', many('nick')]) def amode(self, irc, msg, args, channel, mode, nicks): @@ -245,6 +381,7 @@ class EgoServ(callbacks.Plugin): @wrap([many('channel')]) def chanreg(self, irc, msg, args, channels): """[].. [..] + Registered the given channel/s by the bot """