From fee64ece045ad9dc49a07d1b438caa019c90a778 Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 7 Jun 2018 13:34:52 -0700 Subject: [PATCH 1/6] relay: fix clientbot op requirement not being checked if the sender is in the target channel Also, show a slightly different error when using the command with 'remote', since the clientbot client gets overridden to be the message sender. This mirrors the fix in 1.x: commit 9578fd5ac306866f3535ee1cf9c5a7e241fc4511 --- plugins/relay.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/relay.py b/plugins/relay.py index c7f44e5..fe5d870 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -2269,14 +2269,17 @@ def link(irc, source, args): irc.join(irc.pseudoclient.uid, localchan) irc.reply('Joining %r now to check for op status; please run this command again after I join.' % localchan) return - elif not irc.channels[localchan].is_op_plus(source): - irc.error('You must be opped in %r to complete this operation.' % localchan) - return - else: irc.error('You must be in %r to complete this operation.' % localchan) return + elif not irc.channels[localchan].is_op_plus(source): + if irc.pseudoclient and source == irc.pseudoclient.uid: + irc.error('Please op the bot in %r to complete this operation.' % localchan) + else: + irc.error('You must be opped in %r to complete this operation.' % localchan) + return + permissions.check_permissions(irc, source, ['relay.link']) if remotenet not in world.networkobjects: From b202954be471eef28ca1fd0cd87c1a1e57cdfc49 Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 7 Jun 2018 13:38:01 -0700 Subject: [PATCH 2/6] relay: check permissions before clientbot op status to prevent arbitrary join triggering This mirrors the fix in 1.x: commit 141e941fcddaffc93906b0b5e7cb632f21dde464 --- plugins/relay.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/relay.py b/plugins/relay.py index fe5d870..20fcb6c 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -2243,6 +2243,7 @@ def link(irc, source, args): If the --force option is given, this command will bypass checks for TS and whether the target network is alive, and link the channel anyways.""" + args = link_parser.parse_args(args) # Normalize channel case @@ -2259,6 +2260,8 @@ def link(irc, source, args): irc.error('Cannot link two channels on the same network.') return + permissions.check_permissions(irc, source, ['relay.link']) + if localchan not in irc.channels or source not in irc.channels[localchan].users: # Caller is not in the requested channel. log.debug('(%s) Source not in channel %s; protoname=%s', irc.name, localchan, irc.protoname) @@ -2280,8 +2283,6 @@ def link(irc, source, args): irc.error('You must be opped in %r to complete this operation.' % localchan) return - permissions.check_permissions(irc, source, ['relay.link']) - if remotenet not in world.networkobjects: irc.error('No network named %r exists.' % remotenet) return From d4bf407c5d891edad4ab7cd2ca4f6dc71a9f353c Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 7 Jun 2018 13:44:06 -0700 Subject: [PATCH 3/6] relay: oops, the op check in 'link' should be specific to clientbot --- plugins/relay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/relay.py b/plugins/relay.py index 20fcb6c..3649063 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -2276,7 +2276,7 @@ def link(irc, source, args): irc.error('You must be in %r to complete this operation.' % localchan) return - elif not irc.channels[localchan].is_op_plus(source): + elif irc.protoname == 'clientbot' and not irc.channels[localchan].is_op_plus(source): if irc.pseudoclient and source == irc.pseudoclient.uid: irc.error('Please op the bot in %r to complete this operation.' % localchan) else: From 06d57a5b28658cc8ae3780449092250dc298ed73 Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 7 Jun 2018 13:44:45 -0700 Subject: [PATCH 4/6] relay: rename 'link --force' to 'link --force-ts' to better reflect its purpose Also mention explicitly that this option does not bypass LINKACL and other channel restrictions (e.g. the Clientbot one) --- plugins/relay.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/relay.py b/plugins/relay.py index 3649063..ff6269c 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -2234,15 +2234,16 @@ link_parser = utils.IRCParser() link_parser.add_argument('remotenet') link_parser.add_argument('channel') link_parser.add_argument('localchannel', nargs='?') -link_parser.add_argument("-f", "--force", action='store_true') +link_parser.add_argument("-f", "--force-ts", action='store_true') def link(irc, source, args): - """ [] [-f/--force] + """ [] [-f/--force-ts] Links the specified channel on \x02remotenet\x02 over PyLink Relay as \x02local channel\x02. If \x02local channel\x02 is not specified, it defaults to the same name as \x02channel\x02. - If the --force option is given, this command will bypass checks for TS and whether the target - network is alive, and link the channel anyways.""" + If the --force-ts option is given, this command will bypass checks for TS and whether the target + network is alive, and link the channel anyways. It will not bypass other link restrictions like + those imposed by LINKACL.""" args = link_parser.parse_args(args) @@ -2312,7 +2313,7 @@ def link(irc, source, args): "as %r." % (remotenet, args.channel, link[1])) return - if args.force: + if args.force_ts: permissions.check_permissions(irc, source, ['relay.link.force']) log.info("(%s) relay: Forcing link %s%s -> %s%s", irc.name, irc.name, localchan, remotenet, args.channel) From 6f3813d3a4f755af95cc9e9657addb9fd16e9505 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 8 Jun 2018 15:54:06 -0700 Subject: [PATCH 5/6] UserMapping: add in missing reference to the parent irc instance --- classes.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/classes.py b/classes.py index 7a1c0d1..f289a03 100644 --- a/classes.py +++ b/classes.py @@ -174,13 +174,14 @@ class UserMapping(collections.abc.MutableMapping, structures.CopyWrapper): A mapping storing User objects by UID, as well as UIDs by nick via the 'bynick' attribute """ - def __init__(self, *, data=None): + def __init__(self, irc, data=None): if data is not None: assert isinstance(data, dict) self._data = data else: self._data = {} self.bynick = collections.defaultdict(list) + self._irc = irc def __getitem__(self, key): return self._data[key] @@ -188,7 +189,7 @@ class UserMapping(collections.abc.MutableMapping, structures.CopyWrapper): def __setitem__(self, key, userobj): assert hasattr(userobj, 'lower_nick'), "Cannot add object without lower_nick attribute to UserMapping" if key in self._data: - log.warning('(%s) Attempting to replace User object for %r: %r -> %r', self.name, + log.warning('(%s) Attempting to replace User object for %r: %r -> %r', self._irc.name, key, self._data.get(key), userobj) self._data[key] = userobj @@ -310,7 +311,7 @@ class PyLinkNetworkCore(structures.CamelCaseToSnakeCase): # Intialize the server, channel, and user indexes to be populated by # our protocol module. self.servers = {} - self.users = UserMapping() + self.users = UserMapping(self) # Two versions of the channels index exist in PyLink 2.0, and they are joined together # - irc._channels which implicitly creates channels on access (mostly used From 8cc838e5cad5612a73b83ff145a0eade4c81ab9e Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 8 Jun 2018 15:56:42 -0700 Subject: [PATCH 6/6] relay: allow "relay.link.force_ts" as an alternate permission to 'link --force' --- plugins/relay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/relay.py b/plugins/relay.py index ff6269c..a8f47fb 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -2314,7 +2314,7 @@ def link(irc, source, args): return if args.force_ts: - permissions.check_permissions(irc, source, ['relay.link.force']) + permissions.check_permissions(irc, source, ['relay.link.force_ts', 'relay.link.force']) log.info("(%s) relay: Forcing link %s%s -> %s%s", irc.name, irc.name, localchan, remotenet, args.channel) else: