3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-27 21:19:31 +01:00

relay: move claim enforcement routines outside the mode/kick loops

This prevents claim responses from being sent multiple times.
This commit is contained in:
James Lu 2017-12-14 12:15:19 -08:00
parent 59c12ff354
commit b2270ca3eb

View File

@ -1483,30 +1483,6 @@ def handle_kick(irc, source, command, args):
log.debug('(%s) relay.handle_kick: target %s is an internal client, going to look up the real user', irc.name, target) log.debug('(%s) relay.handle_kick: target %s is an internal client, going to look up the real user', irc.name, target)
real_target = get_orig_user(irc, target, targetirc=remoteirc) real_target = get_orig_user(irc, target, targetirc=remoteirc)
if not check_claim(irc, channel, kicker):
log.debug('(%s) relay.handle_kick: kicker %s is not opped... We should rejoin the target user %s', irc.name, kicker, real_target)
# Home network is not in the channel's claim AND the kicker is not
# opped. We won't propograte the kick then.
# TODO: make the check slightly more advanced: i.e. halfops can't
# kick ops, admins can't kick owners, etc.
modes = get_prefix_modes(remoteirc, irc, remotechan, real_target)
# Join the kicked client back with its respective modes.
irc.sjoin(irc.sid, channel, [(modes, target)])
if kicker in irc.users:
log.info('(%s) relay: Blocked KICK (reason %r) from %s/%s to relay client %s on %s.',
irc.name, args['text'], irc.users[source].nick, irc.name,
remoteirc.users[real_target].nick, channel)
irc.msg(kicker, "This channel is claimed; your kick to "
"%s has been blocked because you are not "
"(half)opped." % channel, notice=True)
else:
log.info('(%s) relay: Blocked KICK (reason %r) from server %s to relay client %s/%s on %s.',
irc.name, args['text'], irc.servers[source].name,
remoteirc.users[real_target].nick, remoteirc.name, channel)
return
if not real_target: if not real_target:
return return
@ -1541,6 +1517,35 @@ def handle_kick(irc, source, command, args):
del relayusers[(irc.name, target)][remoteirc.name] del relayusers[(irc.name, target)][remoteirc.name]
remoteirc.quit(real_target, 'Left all shared channels.') remoteirc.quit(real_target, 'Left all shared channels.')
if not check_claim(irc, channel, kicker):
homenet, real_target = get_orig_user(irc, target)
homeirc = world.networkobjects.get(homenet)
homenick = homeirc.users[real_target].nick if homeirc else '<ghost user>'
homechan = get_remote_channel(irc, homeirc, channel)
log.debug('(%s) relay.handle_kick: kicker %s is not opped... We should rejoin the target user %s', irc.name, kicker, real_target)
# Home network is not in the channel's claim AND the kicker is not
# opped. We won't propograte the kick then.
# TODO: make the check slightly more advanced: i.e. halfops can't
# kick ops, admins can't kick owners, etc.
modes = get_prefix_modes(homeirc, irc, homechan, real_target)
# Join the kicked client back with its respective modes.
irc.sjoin(irc.sid, channel, [(modes, target)])
if kicker in irc.users:
log.info('(%s) relay: Blocked KICK (reason %r) from %s/%s to %s/%s on %s.',
irc.name, args['text'], irc.users[source].nick, irc.name,
homenick, homenet, channel)
irc.msg(kicker, "This channel is claimed; your kick to "
"%s has been blocked because you are not "
"(half)opped." % channel, notice=True)
else:
log.info('(%s) relay: Blocked KICK (reason %r) from server %s to %s/%s on %s.',
irc.name, args['text'], irc.servers[source].name ,
homenick, homenet, channel)
return
iterate_all(irc, _handle_kick_loop, extra_args=(source, command, args)) iterate_all(irc, _handle_kick_loop, extra_args=(source, command, args))
if origuser and not irc.users[target].channels: if origuser and not irc.users[target].channels:
@ -1582,72 +1587,47 @@ def _is_uline(irc, client):
return irc.get_friendly_name(irc.get_server(client)) in irc.serverdata.get('ulines', []) return irc.get_friendly_name(irc.get_server(client)) in irc.serverdata.get('ulines', [])
def handle_mode(irc, numeric, command, args): def handle_mode(irc, numeric, command, args):
target = args['target']
modes = args['modes']
def _handle_mode_loop(irc, remoteirc, numeric, command, args): def _handle_mode_loop(irc, remoteirc, numeric, command, args):
target = args['target']
modes = args['modes']
if irc.is_channel(target): if irc.is_channel(target):
# Use the old state of the channel to check for CLAIM access. remotechan = get_remote_channel(irc, remoteirc, target)
oldchan = args.get('channeldata') if not remotechan:
if check_claim(irc, target, numeric, chanobj=oldchan):
remotechan = get_remote_channel(irc, remoteirc, target)
if not remotechan:
return
supported_modes = get_supported_cmodes(irc, remoteirc, target, modes)
# Check if the sender is a user with a relay client; otherwise relay the mode
# from the corresponding server.
remotesender = get_remote_user(irc, remoteirc, numeric, spawn_if_missing=False) or \
get_relay_server_sid(remoteirc, irc) or remoteirc.sid
if not remoteirc.has_cap('can-spawn-clients'):
friendly_modes = []
for modepair in modes:
if modepair[0][-1] in irc.prefixmodes:
orig_user = get_orig_user(irc, modepair[1])
if orig_user and orig_user[0] == remoteirc.name:
# Don't display prefix mode changes for someone on the target clientbot
# link; this will either be relayed via modesync or ignored.
continue
# Convert UIDs to nicks when relaying this to clientbot.
modepair = (modepair[0], irc.get_friendly_name(modepair[1]))
elif modepair[0][-1] in irc.cmodes['*A'] and irc.is_hostmask(modepair[1]) and \
conf.conf.get('relay', {}).get('clientbot_modesync', 'none').lower() != 'none':
# Don't show bans if the ban is a simple n!u@h and modesync is enabled
continue
friendly_modes.append(modepair)
if friendly_modes:
# Call hooks, this is used for clientbot relay.
remoteirc.call_hooks([remotesender, 'RELAY_RAW_MODE', {'channel': remotechan, 'modes': friendly_modes}])
if supported_modes:
remoteirc.mode(remotesender, remotechan, supported_modes)
else: # Mode change blocked by CLAIM.
reversed_modes = irc.reverse_modes(target, modes, oldobj=oldchan)
if _is_uline(irc, numeric):
# Special hack for "U-lined" servers - ignore changes to SIMPLE modes and
# attempts to op u-lined clients (trying to change status for others
# SHOULD be reverted).
# This is for compatibility with Anope's DEFCON for the most part, as well as
# silly people who try to register a channel multiple times via relay.
reversed_modes = [modepair for modepair in reversed_modes if
# Mode is a prefix mode but target isn't ulined, revert
((modepair[0][-1] in irc.prefixmodes and not
_is_uline(irc, modepair[1]))
# Tried to set a list mode, revert
or modepair[0][-1] in irc.cmodes['*A'])
]
if reversed_modes:
log.debug('(%s) relay.handle_mode: Reversing mode changes of %r with %r (CLAIM).',
irc.name, modes, reversed_modes)
irc.mode(irc.sid, target, reversed_modes)
return return
supported_modes = get_supported_cmodes(irc, remoteirc, target, modes)
# Check if the sender is a user with a relay client; otherwise relay the mode
# from the corresponding server.
remotesender = get_remote_user(irc, remoteirc, numeric, spawn_if_missing=False) or \
get_relay_server_sid(remoteirc, irc) or remoteirc.sid
if not remoteirc.has_cap('can-spawn-clients'):
friendly_modes = []
for modepair in modes:
modechar = modepair[0][-1]
if modechar in irc.prefixmodes:
orig_user = get_orig_user(irc, modepair[1])
if orig_user and orig_user[0] == remoteirc.name:
# Don't display prefix mode changes for someone on the target clientbot
# link; this will either be relayed via modesync or ignored.
continue
# Convert UIDs to nicks when relaying this to clientbot.
modepair = (modepair[0], irc.get_friendly_name(modepair[1]))
elif modechar in irc.cmodes['*A'] and irc.is_hostmask(modepair[1]) and \
conf.conf.get('relay', {}).get('clientbot_modesync', 'none').lower() != 'none':
# Don't show bans if the ban is a simple n!u@h and modesync is enabled
continue
friendly_modes.append(modepair)
if friendly_modes:
# Call hooks, this is used for clientbot relay.
remoteirc.call_hooks([remotesender, 'RELAY_RAW_MODE', {'channel': remotechan, 'modes': friendly_modes}])
if supported_modes:
remoteirc.mode(remotesender, remotechan, supported_modes)
else: else:
# Set hideoper on remote opers, to prevent inflating # Set hideoper on remote opers, to prevent inflating
@ -1665,6 +1645,35 @@ def handle_mode(irc, numeric, command, args):
if remoteuser and modes: if remoteuser and modes:
remoteirc.mode(remoteuser, remoteuser, modes) remoteirc.mode(remoteuser, remoteuser, modes)
if irc.is_channel(target):
# Use the old state of the channel to check for CLAIM access.
oldchan = args.get('channeldata')
if not check_claim(irc, target, numeric, chanobj=oldchan):
# Mode change blocked by CLAIM.
reversed_modes = irc.reverse_modes(target, modes, oldobj=oldchan)
if _is_uline(irc, numeric):
# Special hack for "U-lined" servers - ignore changes to SIMPLE modes and
# attempts to op u-lined clients (trying to change status for others
# SHOULD be reverted).
# This is for compatibility with Anope's DEFCON for the most part, as well as
# silly people who try to register a channel multiple times via relay.
reversed_modes = [modepair for modepair in reversed_modes if
# Mode is a prefix mode but target isn't ulined, revert
((modepair[0][-1] in irc.prefixmodes and not
_is_uline(irc, modepair[1]))
# Tried to set a list mode, revert
or modepair[0][-1] in irc.cmodes['*A'])
]
if reversed_modes:
log.debug('(%s) relay.handle_mode: Reversing mode changes of %r with %r (CLAIM).',
irc.name, modes, reversed_modes)
irc.mode(irc.sid, target, reversed_modes)
return
iterate_all(irc, _handle_mode_loop, extra_args=(numeric, command, args)) iterate_all(irc, _handle_mode_loop, extra_args=(numeric, command, args))
utils.add_hook(handle_mode, 'MODE') utils.add_hook(handle_mode, 'MODE')