mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-30 14:49:28 +01:00
automode: support remote channel manipulation in the form netname#channel
Closes #352.
This commit is contained in:
parent
691a8178b2
commit
8ff292bd1f
@ -53,7 +53,7 @@ def die(sourceirc):
|
|||||||
def checkAccess(irc, uid, channel, command):
|
def checkAccess(irc, uid, channel, command):
|
||||||
"""Checks the caller's access to Automode."""
|
"""Checks the caller's access to Automode."""
|
||||||
# Automode defines the following permissions, where <command> is either "manage", "list",
|
# Automode defines the following permissions, where <command> is either "manage", "list",
|
||||||
# "sync", or "clear":
|
# "sync", "clear", "remotemanage", "remotelist", "remotesync", "remoteclear":
|
||||||
# - automode.<command> OR automode.<command>.*: ability to <command> automode on all channels.
|
# - automode.<command> OR automode.<command>.*: ability to <command> automode on all channels.
|
||||||
# - automode.<command>.relay_owned: ability to <command> automode on channels owned via Relay.
|
# - automode.<command>.relay_owned: ability to <command> automode on channels owned via Relay.
|
||||||
# If Relay isn't loaded, this permission check FAILS.
|
# If Relay isn't loaded, this permission check FAILS.
|
||||||
@ -68,6 +68,8 @@ def checkAccess(irc, uid, channel, command):
|
|||||||
perms = [baseperm, baseperm+'.*', '%s.%s' % (baseperm, channel)]
|
perms = [baseperm, baseperm+'.*', '%s.%s' % (baseperm, channel)]
|
||||||
return permissions.checkPermissions(irc, uid, perms)
|
return permissions.checkPermissions(irc, uid, perms)
|
||||||
except utils.NotAuthorizedError:
|
except utils.NotAuthorizedError:
|
||||||
|
if not command.startswith('remote'):
|
||||||
|
# Relay-based ACL checking only works with local calls.
|
||||||
log.debug('(%s) Automode: falling back to automode.%s.relay_owned', irc.name, command)
|
log.debug('(%s) Automode: falling back to automode.%s.relay_owned', irc.name, command)
|
||||||
permissions.checkPermissions(irc, uid, [baseperm+'.relay_owned'], also_show=perms)
|
permissions.checkPermissions(irc, uid, [baseperm+'.relay_owned'], also_show=perms)
|
||||||
|
|
||||||
@ -79,6 +81,7 @@ def checkAccess(irc, uid, channel, command):
|
|||||||
elif (irc.name, channel) not in relay.db:
|
elif (irc.name, channel) not in relay.db:
|
||||||
raise utils.NotAuthorizedError("The network you are on does not own the relay channel %s." % channel)
|
raise utils.NotAuthorizedError("The network you are on does not own the relay channel %s." % channel)
|
||||||
return True
|
return True
|
||||||
|
raise
|
||||||
|
|
||||||
def match(irc, channel, uids=None):
|
def match(irc, channel, uids=None):
|
||||||
"""
|
"""
|
||||||
@ -141,65 +144,90 @@ def handle_services_login(irc, source, command, args):
|
|||||||
utils.add_hook(handle_services_login, 'CLIENT_SERVICES_LOGIN')
|
utils.add_hook(handle_services_login, 'CLIENT_SERVICES_LOGIN')
|
||||||
utils.add_hook(handle_services_login, 'PYLINK_RELAY_SERVICES_LOGIN')
|
utils.add_hook(handle_services_login, 'PYLINK_RELAY_SERVICES_LOGIN')
|
||||||
|
|
||||||
|
def getChannelPair(irc, source, chanpair, perm=None):
|
||||||
|
"""
|
||||||
|
Fetches the network and channel given a channel pair,
|
||||||
|
also optionally checking the caller's permissions.
|
||||||
|
"""
|
||||||
|
log.debug('(%s) Looking up chanpair %s', irc.name, chanpair)
|
||||||
|
try:
|
||||||
|
network, channel = chanpair.split('#')
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError("Invalid channel pair %r" % chanpair)
|
||||||
|
channel = '#' + channel
|
||||||
|
channel = irc.toLower(channel)
|
||||||
|
|
||||||
|
assert utils.isChannel(channel), "Invalid channel name %s." % channel
|
||||||
|
|
||||||
|
if network:
|
||||||
|
ircobj = world.networkobjects.get(network)
|
||||||
|
else:
|
||||||
|
ircobj = irc
|
||||||
|
|
||||||
|
assert ircobj, "Unknown network %s" % network
|
||||||
|
|
||||||
|
if perm is not None:
|
||||||
|
# Only check for permissions if we're told to and the irc object exists.
|
||||||
|
if ircobj.name != irc.name:
|
||||||
|
perm = 'remote' + perm
|
||||||
|
|
||||||
|
checkAccess(irc, source, channel, perm)
|
||||||
|
|
||||||
|
return (ircobj, channel)
|
||||||
|
|
||||||
def setacc(irc, source, args):
|
def setacc(irc, source, args):
|
||||||
"""<channel> <mask> <mode list>
|
"""<channel/chanpair> <mask> <mode list>
|
||||||
|
|
||||||
Assigns the given prefix mode characters to the given mask for the channel given. Extended targets are supported for masks - use this to your advantage!
|
Assigns the given prefix mode characters to the given mask for the channel given. Extended targets are supported for masks - use this to your advantage!
|
||||||
|
|
||||||
|
Channel pairs are also supported (for operations on remote channels), using the form "network#channel".
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
SET #channel *!*@localhost ohv
|
SET #channel *!*@localhost ohv
|
||||||
SET #channel $account v
|
SET #channel $account v
|
||||||
SET #channel $oper:Network?Administrator qo
|
SET othernet#channel $oper:Network?Administrator qo
|
||||||
SET #staffchan $channel:#mainchan:op o
|
SET #staffchan $channel:#mainchan:op o
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
channel, mask, modes = args
|
chanpair, mask, modes = args
|
||||||
except ValueError:
|
except ValueError:
|
||||||
reply(irc, "Error: Invalid arguments given. Needs 3: channel, mask, mode list.")
|
reply(irc, "Error: Invalid arguments given. Needs 3: channel, mask, mode list.")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if not utils.isChannel(channel):
|
ircobj, channel = getChannelPair(irc, source, chanpair, perm='manage')
|
||||||
reply(irc, "Error: Invalid channel name %s." % channel)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Store channels case insensitively
|
|
||||||
channel = irc.toLower(channel)
|
|
||||||
|
|
||||||
checkAccess(irc, source, channel, 'manage')
|
|
||||||
|
|
||||||
# Database entries for any network+channel pair are automatically created using
|
# Database entries for any network+channel pair are automatically created using
|
||||||
# defaultdict. Note: string keys are used here instead of tuples so they can be
|
# defaultdict. Note: string keys are used here instead of tuples so they can be
|
||||||
# exported easily as JSON.
|
# exported easily as JSON.
|
||||||
dbentry = db[irc.name+channel]
|
dbentry = db[ircobj.name+channel]
|
||||||
|
|
||||||
# Otherwise, update the modes as is.
|
# Otherwise, update the modes as is.
|
||||||
dbentry[mask] = modes
|
dbentry[mask] = modes
|
||||||
log.info('(%s) %s set modes +%s for %s on %s', irc.name, irc.getHostmask(source), modes, mask, channel)
|
log.info('(%s) %s set modes +%s for %s on %s', ircobj.name, irc.getHostmask(source), modes, mask, channel)
|
||||||
reply(irc, "Done. \x02%s\x02 now has modes \x02%s\x02 in \x02%s\x02." % (mask, modes, channel))
|
reply(irc, "Done. \x02%s\x02 now has modes \x02%s\x02 in \x02%s\x02." % (mask, modes, channel))
|
||||||
|
|
||||||
# Join the Automode bot to the channel if not explicitly told to.
|
# Join the Automode bot to the channel if not explicitly told to.
|
||||||
modebot.join(irc, channel)
|
modebot.join(ircobj, channel)
|
||||||
|
|
||||||
modebot.add_cmd(setacc, 'setaccess')
|
modebot.add_cmd(setacc, 'setaccess')
|
||||||
modebot.add_cmd(setacc, 'set')
|
modebot.add_cmd(setacc, 'set')
|
||||||
modebot.add_cmd(setacc, featured=True)
|
modebot.add_cmd(setacc, featured=True)
|
||||||
|
|
||||||
def delacc(irc, source, args):
|
def delacc(irc, source, args):
|
||||||
"""<channel> <mask>
|
"""<channel/chanpair> <mask>
|
||||||
|
|
||||||
Removes the Automode entry for the given mask on the given channel, if one exists.
|
Removes the Automode entry for the given mask on the given channel, if one exists.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
channel, mask = args
|
chanpair, mask = args
|
||||||
channel = irc.toLower(channel)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
reply(irc, "Error: Invalid arguments given. Needs 2: channel, mask")
|
reply(irc, "Error: Invalid arguments given. Needs 2: channel, mask")
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
ircobj, channel = getChannelPair(irc, source, chanpair, perm='manage')
|
||||||
|
|
||||||
checkAccess(irc, source, channel, 'manage')
|
dbentry = db.get(ircobj.name+channel)
|
||||||
|
|
||||||
dbentry = db.get(irc.name+channel)
|
|
||||||
|
|
||||||
if dbentry is None:
|
if dbentry is None:
|
||||||
reply(irc, "Error: no Automode access entries exist for \x02%s\x02." % channel)
|
reply(irc, "Error: no Automode access entries exist for \x02%s\x02." % channel)
|
||||||
@ -207,34 +235,33 @@ def delacc(irc, source, args):
|
|||||||
|
|
||||||
if mask in dbentry:
|
if mask in dbentry:
|
||||||
del dbentry[mask]
|
del dbentry[mask]
|
||||||
log.info('(%s) %s removed modes for %s on %s', irc.name, irc.getHostmask(source), mask, channel)
|
log.info('(%s) %s removed modes for %s on %s', ircobj.name, irc.getHostmask(source), mask, channel)
|
||||||
reply(irc, "Done. Removed the Automode access entry for \x02%s\x02 in \x02%s\x02." % (mask, channel))
|
reply(irc, "Done. Removed the Automode access entry for \x02%s\x02 in \x02%s\x02." % (mask, channel))
|
||||||
else:
|
else:
|
||||||
reply(irc, "Error: No Automode access entry for \x02%s\x02 exists in \x02%s\x02." % (mask, channel))
|
reply(irc, "Error: No Automode access entry for \x02%s\x02 exists in \x02%s\x02." % (mask, channel))
|
||||||
|
|
||||||
# Remove channels if no more entries are left.
|
# Remove channels if no more entries are left.
|
||||||
if not dbentry:
|
if not dbentry:
|
||||||
log.debug("Automode: purging empty channel pair %s/%s", irc.name, channel)
|
log.debug("Automode: purging empty channel pair %s/%s", ircobj.name, channel)
|
||||||
del db[irc.name+channel]
|
del db[ircobj.name+channel]
|
||||||
|
|
||||||
return
|
|
||||||
modebot.add_cmd(delacc, 'delaccess')
|
modebot.add_cmd(delacc, 'delaccess')
|
||||||
modebot.add_cmd(delacc, 'del')
|
modebot.add_cmd(delacc, 'del')
|
||||||
modebot.add_cmd(delacc, featured=True)
|
modebot.add_cmd(delacc, featured=True)
|
||||||
|
|
||||||
def listacc(irc, source, args):
|
def listacc(irc, source, args):
|
||||||
"""<channel>
|
"""<channel/chanpair>
|
||||||
|
|
||||||
Lists all Automode entries for the given channel."""
|
Lists all Automode entries for the given channel."""
|
||||||
try:
|
try:
|
||||||
channel = irc.toLower(args[0])
|
chanpair = args[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
reply(irc, "Error: Invalid arguments given. Needs 1: channel.")
|
reply(irc, "Error: Invalid arguments given. Needs 1: channel.")
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
ircobj, channel = getChannelPair(irc, source, chanpair, perm='list')
|
||||||
|
|
||||||
checkAccess(irc, source, channel, 'list')
|
dbentry = db.get(ircobj.name+channel)
|
||||||
|
|
||||||
dbentry = db.get(irc.name+channel)
|
|
||||||
if not dbentry:
|
if not dbentry:
|
||||||
reply(irc, "Error: No Automode access entries exist for \x02%s\x02." % channel)
|
reply(irc, "Error: No Automode access entries exist for \x02%s\x02." % channel)
|
||||||
return
|
return
|
||||||
@ -247,6 +274,7 @@ def listacc(irc, source, args):
|
|||||||
mask, modes = entry
|
mask, modes = entry
|
||||||
reply(irc, "[%s] \x02%s\x02 has modes +\x02%s\x02" % (entrynum, mask, modes), private=True)
|
reply(irc, "[%s] \x02%s\x02 has modes +\x02%s\x02" % (entrynum, mask, modes), private=True)
|
||||||
reply(irc, "End of Automode entries list.", private=True)
|
reply(irc, "End of Automode entries list.", private=True)
|
||||||
|
|
||||||
modebot.add_cmd(listacc, featured=True)
|
modebot.add_cmd(listacc, featured=True)
|
||||||
modebot.add_cmd(listacc, 'listaccess')
|
modebot.add_cmd(listacc, 'listaccess')
|
||||||
|
|
||||||
@ -261,19 +289,20 @@ def save(irc, source, args):
|
|||||||
modebot.add_cmd(save)
|
modebot.add_cmd(save)
|
||||||
|
|
||||||
def syncacc(irc, source, args):
|
def syncacc(irc, source, args):
|
||||||
"""<channel>
|
"""<channel/chanpair>
|
||||||
|
|
||||||
Syncs Automode access lists to the channel.
|
Syncs Automode access lists to the channel.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
channel = irc.toLower(args[0])
|
chanpair = args[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
reply(irc, "Error: Invalid arguments given. Needs 1: channel.")
|
reply(irc, "Error: Invalid arguments given. Needs 1: channel.")
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
ircobj, channel = getChannelPair(irc, source, chanpair, perm='sync')
|
||||||
|
|
||||||
checkAccess(irc, source, channel, 'sync')
|
log.info('(%s) %s synced modes on %s', ircobj.name, irc.getHostmask(source), channel)
|
||||||
log.info('(%s) %s synced modes on %s', irc.name, irc.getHostmask(source), channel)
|
match(ircobj, channel)
|
||||||
match(irc, channel)
|
|
||||||
|
|
||||||
reply(irc, 'Done.')
|
reply(irc, 'Done.')
|
||||||
|
|
||||||
@ -288,17 +317,16 @@ def clearacc(irc, source, args):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
channel = irc.toLower(args[0])
|
chanpair = args[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
reply(irc, "Error: Invalid arguments given. Needs 1: channel.")
|
reply(irc, "Error: Invalid arguments given. Needs 1: channel.")
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
ircobj, channel = getChannelPair(irc, source, chanpair, perm='clear')
|
||||||
|
|
||||||
checkAccess(irc, source, channel, 'clear')
|
if db.get(ircobj.name+channel):
|
||||||
|
del db[ircobj.name+channel]
|
||||||
if db.get(irc.name+channel):
|
log.info('(%s) %s cleared modes on %s', ircobj.name, irc.getHostmask(source), channel)
|
||||||
log.debug("Automode: purging channel pair %s/%s", irc.name, channel)
|
|
||||||
del db[irc.name+channel]
|
|
||||||
log.info('(%s) %s cleared modes on %s', irc.name, irc.getHostmask(source), channel)
|
|
||||||
reply(irc, "Done. Removed all Automode access entries for \x02%s\x02." % channel)
|
reply(irc, "Done. Removed all Automode access entries for \x02%s\x02." % channel)
|
||||||
else:
|
else:
|
||||||
reply(irc, "Error: No Automode access entries exist for \x02%s\x02." % channel)
|
reply(irc, "Error: No Automode access entries exist for \x02%s\x02." % channel)
|
||||||
|
Loading…
Reference in New Issue
Block a user