From 4312983ca5c93e46ec0d2b1a114c9db38b93eee5 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 31 Mar 2017 22:52:40 -0700 Subject: [PATCH 1/3] relay: initial modedelta implementation --- plugins/relay.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/plugins/relay.py b/plugins/relay.py index 1c0b42d..4589a20 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -2095,3 +2095,91 @@ def claim(irc, source, args): db[relay]["claim"] = claimed irc.reply('CLAIM for channel \x02%s\x02 set to: %s' % (channel, ', '.join(claimed) or '\x1D(none)\x1D')) + +@utils.add_cmd +def modedelta(irc, source, args): + """ [] + + Sets the relay mode delta for the given channel: a list of named mode pairs to apply on leaf + channels, but not the host network. This may be helpful in fighting spam if leaf networks + don't police it as well as your own (e.g. you can set +R with this). + + Mode names are defined using PyLink named modes, and not IRC mode characters: you can find a + list of channel named modes and the characters they map to on different IRCds at + https://github.com/GLolol/PyLink/blob/master/docs/technical/channel-modes.csv + + Examples of setting modes: + modedelta #channel regonly + modedelta #channel regonly inviteonly + modedelta #channel key,supersecret sslonly + modedelta #channel - + + If no modes are given, this shows the mode delta for the channel. + A single hyphen (-) can also be given as a list of modes to disable the mode delta + and remove any mode deltas from relay leaves. + """ + try: + channel = irc.toLower(args[0]) + except IndexError: + irc.error("Not enough arguments. Needs 1-2: channel, list of modes (optional).") + return + + permissions.checkPermissions(irc, source, ['relay.modedelta']) + + # We override get_relay() here to limit the search to the current network. + relay = (irc.name, channel) + with db_lock: + if relay not in db: + irc.error('No relay %r exists on this network (this command must be run on the ' + 'network this channel was created on).' % channel) + return + + target_modes = [] + old_modes = [] + if '-' in args[1:]: # - given to clear the list + try: + # Keep track of the + old_modes = db[relay]['modedelta'] + del db[relay]['modedelta'] + except KeyError: + irc.error('No mode delta exists for %r.' % channel) + return + else: + irc.reply('Cleared the mode delta for %r.' % channel) + else: + modes = [] + for modepair in map(str.lower, args[1:]): + # Construct mode pairs given the initial query. + m = modepair.split(',', 1) + if len(m) == 1: + m.append(None) + modes.append(m) + + if modes: + old_modes = db[relay].get('modedelta', []) + db[relay]['modedelta'] = target_modes = modes + log.debug('channel: %s', str(channel)) + irc.reply('Set the mode delta for \x02%s\x02 to: %s' % (channel, modes)) + else: # No modes given, so show the list. + irc.reply('Mode delta for channel \x02%s\x02 is set to: %s' % + (channel, db[relay].get('modedelta') or '\x1D(none)\x1D')) + + target_modes += [('-%s' % modepair[0], modepair[1]) for modepair in old_modes] + for chanpair in db[relay]['links']: + remotenet, remotechan = chanpair + remoteirc = world.networkobjects.get(remotenet) + + remote_modes = [] + # For each leaf channel, unset the old mode delta and set the new one + # if applicable. + for modepair in target_modes: + modeprefix = modepair[0][0] + if modeprefix not in '+-': # Assume + if no prefix was given. + modeprefix = '+' + modename = modepair[0].lstrip('+-') + mchar = remoteirc.cmodes.get(modename) + if mchar: + remote_modes.append(('%s%s' % (modeprefix, mchar), modepair[1])) + if remote_modes: + log.debug('(%s) Sending modedelta modes %s to %s/%s', irc.name, remote_modes, remotenet, remotechan) + remoteirc.proto.mode(remoteirc.pseudoclient.uid, remotechan, remote_modes) From 13be8ff6d08f191ce74e020f2f79ee23941dd8f0 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 31 Mar 2017 23:20:27 -0700 Subject: [PATCH 2/3] relay: apply modedelta rules on SJOIN as well --- plugins/relay.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/plugins/relay.py b/plugins/relay.py index 4589a20..d9f54e7 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -665,6 +665,28 @@ def relay_joins(irc, channel, users, ts, burst=True): # to be set on the joining user. if burst or len(queued_users) > 1 or queued_users[0][0]: modes = get_supported_cmodes(irc, remoteirc, channel, irc.channels[channel].modes) + + # Subtract any mode delta modes from this burst + relay = db[get_relay((irc.name, channel))] + modedelta_modes = relay.get('modedelta') + if modedelta_modes: + # Check if the target is a leaf channel: if so, add the mode delta modes to the target mode set. + # Otherwise, subtract this mode set (otherwise, leaf channel modes will apply onto + # the original channel. + adding = (name, remotechan) in relay['links'] + + # Add this to the SJOIN mode list. + for mode in modedelta_modes: + modechar = remoteirc.cmodes.get(mode[0]) + if modechar: + modedelta_mode = ('+%s' % modechar, mode[1]) + if adding: + log.debug('(%s) relay.relay_joins: adding %r on %s/%s (modedelta)', irc.name, str(modedelta_mode), name, remotechan) + modes.append(modedelta_mode) + elif modedelta_mode in modes: + log.debug('(%s) relay.relay_joins: removing %r on %s/%s (modedelta)', irc.name, str(modedelta_mode), name, remotechan) + modes.remove(modedelta_mode) + rsid = get_remote_sid(remoteirc, irc) if rsid: remoteirc.proto.sjoin(rsid, remotechan, queued_users, ts=ts, modes=modes) @@ -2168,6 +2190,8 @@ def modedelta(irc, source, args): for chanpair in db[relay]['links']: remotenet, remotechan = chanpair remoteirc = world.networkobjects.get(remotenet) + if not remoteirc: + continue remote_modes = [] # For each leaf channel, unset the old mode delta and set the new one From 2e5cccc3813fd6b696ffd2664fb2d55d22d1e294 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 31 Mar 2017 23:38:24 -0700 Subject: [PATCH 3/3] relay: fix incrementing changes to modedelta --- plugins/relay.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/relay.py b/plugins/relay.py index d9f54e7..57e71d4 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -2186,7 +2186,12 @@ def modedelta(irc, source, args): irc.reply('Mode delta for channel \x02%s\x02 is set to: %s' % (channel, db[relay].get('modedelta') or '\x1D(none)\x1D')) - target_modes += [('-%s' % modepair[0], modepair[1]) for modepair in old_modes] + # Add to target_modes all former modedelta modes that don't have a positive equivalent + # Note: We only check for (modechar, modedata) and not for (+modechar, modedata) here + # internally, but the actual filtering below checks for both? + modedelta_diff = [('-%s' % modepair[0], modepair[1]) for modepair in old_modes if + modepair not in target_modes] + target_modes += modedelta_diff for chanpair in db[relay]['links']: remotenet, remotechan = chanpair remoteirc = world.networkobjects.get(remotenet) @@ -2196,6 +2201,7 @@ def modedelta(irc, source, args): remote_modes = [] # For each leaf channel, unset the old mode delta and set the new one # if applicable. + log.debug('(%s) modedelta target modes for %s/%s: %s', irc.name, remotenet, remotechan, target_modes) for modepair in target_modes: modeprefix = modepair[0][0] if modeprefix not in '+-': # Assume + if no prefix was given.