3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-24 03:29:28 +01:00

relay: add a working KICK handler

This should block kicks from non-opped remote users, and handle kicks across the relay properly by mapping our pseudoclients to the real targets.
This commit is contained in:
James Lu 2015-07-14 18:20:20 -07:00
parent 79a1ac9006
commit 28f1d4ba19

View File

@ -188,6 +188,78 @@ def handle_part(irc, numeric, command, args):
remoteirc.proto.partClient(remoteirc, user, remotechan, text)
utils.add_hook(handle_part, 'PART')
def handle_kick(irc, source, command, args):
channel = args['channel']
target = args['target']
text = args['text']
kicker = source
kicker_modes = getPrefixModes(irc, irc, channel, kicker)
relay = findRelay((irc.name, channel))
if relay is None:
return
for name, remoteirc in utils.networkobjects.items():
if irc.name == name:
continue
remotechan = findRemoteChan(irc, remoteirc, channel)
log.debug('(%s) Relay kick: remotechan for %s on %s is %s', irc.name, channel, name, remotechan)
if remotechan is None:
continue
real_kicker = getRemoteUser(irc, remoteirc, kicker)
log.debug('(%s) Relay kick: real kicker for %s on %s is %s', irc.name, kicker, name, real_kicker)
if not utils.isInternalClient(irc, target):
log.debug('(%s) Relay kick: target %s is NOT an internal client', irc.name, target)
# Both the target and kicker are external clients; i.e.
# they originate from the same network. We shouldn't have
# to process this any further, because the uplink IRCd
# will handle this appropriately, and we'll just follow.
real_target = getRemoteUser(irc, remoteirc, target)
log.debug('(%s) Relay kick: real target for %s is %s', irc.name, target, real_target)
remoteirc.proto.kickClient(remoteirc, real_kicker,
remotechan, real_target, args['text'])
else:
log.debug('(%s) Relay kick: target %s is an internal client, going to look up the real user', irc.name, target)
# Our target is an internal client, which means someone
# is kicking a remote user over the relay.
# We have to find the real target for the KICK. This is like
# findRemoteUser, but in reverse.
# First, iterate over everyone!
for k, v in relayusers.items():
log.debug('(%s) Relay kick: processing %s, %s in relayusers', irc.name, k, v)
if k[0] == irc.name:
# We don't need to do anything if the target users is on
# the same network as us.
log.debug('(%s) Relay kick: skipping %s since the target network matches the source network.', irc.name, k)
continue
if v[irc.name] == target:
# If the stored pseudoclient UID for the kicked user on
# this network matches the target we have, set that user
# as the one we're kicking! It's a handful, but remember
# we're mapping (home network, UID) pairs to their
# respective relay pseudoclients on other networks.
real_target = k[1]
log.debug('(%s) Relay kick: found %s to correspond to %s.', irc.name, v, k)
break
log.debug('(%s) Relay kick: kicker_modes are %r', irc.name, kicker_modes)
if irc.name not in db[relay]['links'] and not \
any([mode in kicker_modes for mode in ('q', 'a', 'o', 'h')]):
log.debug('(%s) Relay 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 = getPrefixModes(remoteirc, irc, remotechan, real_target)
# Join the kicked client back with its respective modes.
irc.proto.sjoinServer(irc, irc.sid, remotechan, [(modes, target)])
utils.msg(irc, kicker, "This channel is claimed; your kick has "
"to %s been blocked because you are not "
"(half)opped." % channel, notice=True)
else:
# Propogate the kick!
log.debug('(%s) Relay kick: Kicking %s from channel %s via %s on behalf of %s/%s', irc.name, real_target, remotechan, real_kicker, kicker, irc.name)
remoteirc.proto.kickClient(remoteirc, real_kicker,
remotechan, real_target, args['text'])
utils.add_hook(handle_kick, 'KICK')
def relayJoins(irc, channel, users, ts, modes):
queued_users = []
for user in users:
@ -209,7 +281,7 @@ def relayJoins(irc, channel, users, ts, modes):
continue
u = getRemoteUser(irc, remoteirc, user)
remotechan = findRemoteChan(irc, remoteirc, channel)
if remotechan is None:
if remotechan is None or u is None:
continue
ts = irc.channels[channel].ts
# TODO: join users in batches with SJOIN, not one by one.