Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
6c5c9a989f | |||
83438a522d |
@ -1,3 +1 @@
|
|||||||
# EgoServ - Limnoria Plugin
|
|
||||||
|
|
||||||
Suite of tools to help Network Operators run their ErgoIRCd nets
|
Suite of tools to help Network Operators run their ErgoIRCd nets
|
||||||
|
@ -37,10 +37,14 @@ import supybot
|
|||||||
from supybot import world
|
from supybot import world
|
||||||
|
|
||||||
# Use this for the version of this plugin.
|
# Use this for the version of this plugin.
|
||||||
__version__ = ""
|
__version__ = "0.1.1"
|
||||||
|
|
||||||
# XXX Replace this with an appropriate author or supybot.Author instance.
|
# 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
|
# This is a dictionary mapping supybot.Author instances to lists of
|
||||||
# contributions.
|
# contributions.
|
||||||
|
71
outline.rst
71
outline.rst
@ -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
218
plugin.py
@ -28,12 +28,7 @@
|
|||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
# My Imports
|
from supybot import utils, plugins, ircutils, callbacks, irclib, ircmsgs, conf, world, log
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from supybot import utils, plugins, ircutils, callbacks, irclib, ircmsgs,
|
|
||||||
from supybot import conf, world, log, ircdb, registry, schedule
|
|
||||||
from supybot.commands import *
|
from supybot.commands import *
|
||||||
try:
|
try:
|
||||||
from supybot.i18n import PluginInternationalization
|
from supybot.i18n import PluginInternationalization
|
||||||
@ -49,69 +44,6 @@ except ImportError:
|
|||||||
|
|
||||||
# filename = conf.supybot.directories.data.dirize("EgoServ.db")
|
# 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):
|
class EgoServ(callbacks.Plugin):
|
||||||
"""Suite of tools to help Network Operators run their ErgoIRCd nets"""
|
"""Suite of tools to help Network Operators run their ErgoIRCd nets"""
|
||||||
threaded = True
|
threaded = True
|
||||||
@ -168,7 +100,6 @@ class EgoServ(callbacks.Plugin):
|
|||||||
|
|
||||||
|
|
||||||
# KILL
|
# KILL
|
||||||
@ensure_permissions(5)
|
|
||||||
@wrap(['nick', optional('something')])
|
@wrap(['nick', optional('something')])
|
||||||
def kill(self, irc, msg, args, nick, reason):
|
def kill(self, irc, msg, args, nick, reason):
|
||||||
"""<nick> [<reason>]
|
"""<nick> [<reason>]
|
||||||
@ -231,115 +162,48 @@ class EgoServ(callbacks.Plugin):
|
|||||||
# Channel Administration
|
# Channel Administration
|
||||||
######
|
######
|
||||||
|
|
||||||
def _ban(self, irc, msg, args,
|
# Only Talking to CS isn't enough because
|
||||||
channel, optlist, target, getTs, reason, kick):
|
# CS doesn't handle expiring bans mutes
|
||||||
# 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')])
|
|
||||||
|
|
||||||
|
|
||||||
|
# Use mute Extban
|
||||||
|
|
||||||
|
|
||||||
@wrap(['nick', 'channel', optional('getTs'), 'something'])
|
# @wrap(['nick', 'channel', optional('expiry', 0), 'something'])
|
||||||
def quiet(self, irc, msg, args, nick, channel, duration, reason="Fuck Knows!"):
|
# def mute(self, irc, msg, args, nick, channel, duration, reason):
|
||||||
"""<nick> [<channel>] [<seconds>] [<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
|
# Issues an extban which mutes the hostmask associated with the
|
||||||
<seconds>. If not specified, it will quiet the user indefinitely.
|
# <nick>
|
||||||
<reason> is optional but recommended! <channel> is only necessary if
|
# """
|
||||||
the command is not sent in the channel itself.
|
# # add --all flag for muting the hostmask/account in all channels
|
||||||
"""
|
# # on the current network
|
||||||
try:
|
|
||||||
(nick, ident, host) = \
|
|
||||||
ircutils.splitHostmask(irc.state.nickToHostmask(nick))
|
|
||||||
except KeyError:
|
|
||||||
irc.error(format("No such nick"), Raise=True)
|
|
||||||
|
|
||||||
|
# # 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')])
|
@wrap(['channel', 'something', many('nick')])
|
||||||
def amode(self, irc, msg, args, channel, mode, nicks):
|
def amode(self, irc, msg, args, channel, mode, nicks):
|
||||||
@ -367,21 +231,19 @@ class EgoServ(callbacks.Plugin):
|
|||||||
flag = '-a'
|
flag = '-a'
|
||||||
elif mode == 'deop':
|
elif mode == 'deop':
|
||||||
flag = '-o'
|
flag = '-o'
|
||||||
|
else:
|
||||||
|
irc.error(f'Supplied mode {mode} is not allowed/valid')
|
||||||
|
|
||||||
for nick in nicks:
|
for nick in nicks:
|
||||||
irc.queueMsg(msg=ircmsgs.IrcMsg(command='PRIVMSG',
|
irc.queueMsg(msg=ircmsgs.IrcMsg(command='PRIVMSG',
|
||||||
args=('chanserv', f'amode {channel} {flag} {nick}')))
|
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,
|
# Would love to handle responses for when it's not an account,
|
||||||
# https://github.com/ergochat/ergo/issues/1515 Waiting for this.
|
# 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')])
|
@wrap([many('channel')])
|
||||||
def chanreg(self, irc, msg, args, channels):
|
def chanreg(self, irc, msg, args, channels):
|
||||||
"""[<channel>].. [<channel>..]
|
"""[<channel>].. [<channel>..]
|
||||||
|
|
||||||
Registered the given channel/s by the bot
|
Registered the given channel/s by the bot
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user