Compare commits

..

2 Commits

Author SHA1 Message Date
6c5c9a989f add metadata 2021-07-16 22:34:15 +05:30
83438a522d Merge pull request 'setup.py' (#1) from devel into master
Reviewed-on: #1
2021-07-16 18:15:45 +02:00
4 changed files with 47 additions and 254 deletions

View File

@ -1,3 +1 @@
# EgoServ - Limnoria Plugin
Suite of tools to help Network Operators run their ErgoIRCd nets

View File

@ -37,10 +37,14 @@ import supybot
from supybot import world
# Use this for the version of this plugin.
__version__ = ""
__version__ = "0.1.1"
# XXX Replace this with an appropriate author or supybot.Author instance.
__author__ = supybot.authors.unknown
if not hasattr(supybot.authors, 'mogad0n'):
supybot.authors.mogad0n =supybot.Author('Pratyush Desai', 'mogad0n',
'pratyushndesai@gmail.com')
__author__ = supybot.authors.mogad0n
# This is a dictionary mapping supybot.Author instances to lists of
# contributions.

View File

@ -1,71 +0,0 @@
WIP Outline of Commands and Functionality
=========================================
The permissions are inherited in descending order. Tier 1 inherits Tier 2 ...
+-----------+-------------+------------+-------------+----------+
|Commands |Description | Tier | Channel | Status |
| | | | Restrictions| |
+===========+=============+============+=============+==========+
| DEFCON | | Admins/Ops | public | DONE |
+-----------+-------------+------------+-------------+----------+
| SAJOIN | | Admins/Ops | public | DONE |
+-----------+-------------+------------+-------------+----------+
| SANICK | | Admins/Ops | column 3 | DONE |
+-----------+-------------+------------+-------------+----------+
| KILL | | Admins/Ops | public | DONE |
+-----------+-------------+------------+-------------+----------+
| UBAN | | Moderators | public | WIP |
+-----------+-------------+------------+-------------+----------+
| NBAN | | Moderators | public | WIP |
+-----------+-------------+------------+-------------+----------+
| KBAN | | Moderators | public | EXISTS |
+-----------+-------------+------------+-------------+----------+
| SUSTATUS | | Moderators | staff, pm | TBD |
+-----------+-------------+------------+-------------+----------+
| WARN | | Tripsitters| public | TBD |
+-----------+-------------+------------+-------------+----------+
| ADDNOTE | | Tripsitters| staff, pm | TBD |
+-----------+-------------+------------+-------------+----------+
| STATUS | | Tripsitters| staff, pm | TBD |
+-----------+-------------+------------+-------------+----------+
| QUIET | | Tripsitters| | |
+-----------+-------------+------------+-------------+----------+
| NOTES | | Tripsitters| | |
+-----------+-------------+------------+-------------+----------+
Tier 1 : Administrator/Operator only
------------------------------------
1. DEFCON
2. SANICK
3. SAJOIN
4. KILL
5. UBAN - Variations. This can be considered akin to a KLINE in tripbot.
Tier 2 : Moderators
-------------------
1. NBAN - this will behave as current ``nban`` minus the kline aspect
2. KBAN - Single channel bans (exists)
3. WARN
4. SUSTATUS
Tier 3 : Tripsitters
--------------------
1. QUIET - should allow for --all flag to quiet accross channels similar to NBAN
1. This will require the use of the mute extban ``MODE +b #channel m:nick!user@host``
2. Refer to ``@kban`` and ``@iban`` code in the ``Channel`` plugin
2. STATUS
3. ADDNOTE
4. NOTES
---
- All commands targetting a user (infractions) should be logged in a database. sqlite3 for now.
- decide upon the schema for these tables.
- Besides the user permissions, there should be channel restrictions for certain commands.
- Ensure that the bot itself cannot be targetted and is immune

218
plugin.py
View File

@ -28,12 +28,7 @@
###
# My Imports
from supybot import utils, plugins, ircutils, callbacks, irclib, ircmsgs,
from supybot import conf, world, log, ircdb, registry, schedule
from supybot import utils, plugins, ircutils, callbacks, irclib, ircmsgs, conf, world, log
from supybot.commands import *
try:
from supybot.i18n import PluginInternationalization
@ -49,69 +44,6 @@ 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):
"""[<years>y] [<weeks>w] [<days>d] [<hours>h] [<minutes>m] [<seconds>s]
Returns the number of seconds in the number of <years>, <weeks>,
<days>, <hours>, <minutes>, and <seconds> 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
@ -168,7 +100,6 @@ class EgoServ(callbacks.Plugin):
# KILL
@ensure_permissions(5)
@wrap(['nick', optional('something')])
def kill(self, irc, msg, args, nick, reason):
"""<nick> [<reason>]
@ -231,115 +162,48 @@ class EgoServ(callbacks.Plugin):
# Channel Administration
######
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
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)
def nban(self, irc, msg, args,
bannedNick, getTs, reason):
""" <nick> [<seconds>] [<reason>]
If you have the #channel,op capability, this will kickban <nick>'s banmask from
for
the time period specified. Not specifying the time period it will ban the user
indefinitely. <reason> 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')])
# Only Talking to CS isn't enough because
# CS doesn't handle expiring bans mutes
# Use mute Extban
@wrap(['nick', 'channel', optional('getTs'), 'something'])
def quiet(self, irc, msg, args, nick, channel, duration, reason="Fuck Knows!"):
"""<nick> [<channel>] [<seconds>] [<reason>]
# @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):
# """<nick> [<channel>]
Quiets the banmask associated with <nick> for the time period specified
<seconds>. If not specified, it will quiet the user indefinitely.
<reason> is optional but recommended! <channel> 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)
# Issues an extban which mutes the hostmask associated with the
# <nick>
# """
# # add --all flag for muting the hostmask/account in all channels
# # on the current network
# # Seconds needs to be human readable i.e. 5w 3d 2h
# # 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(['channel', 'something', many('nick')])
def amode(self, irc, msg, args, channel, mode, nicks):
@ -367,21 +231,19 @@ class EgoServ(callbacks.Plugin):
flag = '-a'
elif mode == 'deop':
flag = '-o'
else:
irc.error(f'Supplied mode {mode} is not allowed/valid')
for nick in nicks:
irc.queueMsg(msg=ircmsgs.IrcMsg(command='PRIVMSG',
args=('chanserv', f'amode {channel} {flag} {nick}')))
else:
irc.error(f'Supplied mode {mode} is BAD INPUT!')
# Would love to handle responses for when it's not an account,
# https://github.com/ergochat/ergo/issues/1515 Waiting for this.
irc.replySuccess(f'= Auto {flag} applied to \x02registered\x0F nicks!')
irc.replySuccess(f'Setting mode {flag} on given nick(s), if nick(s) weren\'t given the {flag} mode it/they is/are unregistered')
@wrap([many('channel')])
def chanreg(self, irc, msg, args, channels):
"""[<channel>].. [<channel>..]
Registered the given channel/s by the bot
"""