From 9732d01a9ed828880422df0648823d01e37154b3 Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 16 Jun 2016 21:55:50 -0700 Subject: [PATCH 1/9] relay: default DB to {} so it doesn't flip out on 'load relay' (cherry picked from commit db56513ac7ff76b21f4907d4608f2a1e24a4c961) --- plugins/relay.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/relay.py b/plugins/relay.py index 5d76327..d112bef 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -21,6 +21,7 @@ spawnlocks_servers = defaultdict(threading.RLock) exportdb_timer = None +db = {} dbname = utils.getDatabaseName('pylinkrelay') ### INTERNAL FUNCTIONS From 9132bfcb3a3c7c9578ca5a344c3d0f5a56a3a886 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 12:12:17 -0700 Subject: [PATCH 2/9] pylink-opers: mention DESTROY, DELINK --- docs/pylink-opers.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/pylink-opers.md b/docs/pylink-opers.md index 31d93ba..b204c78 100644 --- a/docs/pylink-opers.md +++ b/docs/pylink-opers.md @@ -27,6 +27,12 @@ You can also link remote channels to take a different name on your network. (Thi Also, to list the available channels: - `/msg PyLink linked` +To remove a relay channel that you've created: +- `/msg PyLink destroy #channelname` + +To delink a channel linked to another network: +- `/msg PyLink delink #channelname` + ### Claiming channels PyLink offers channel claims similarly to Janus, except that it is on by default when you create a channel on any network. Unless the claimed network list of a channel is EMPTY, oper override (MODE, KICK, TOPIC) will only be allowed from networks on that list. From e47738c27fbea94e2aaefa439f36efbda82f3620 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 12:13:56 -0700 Subject: [PATCH 3/9] relay: forbid linking two channels on the same network --- plugins/relay.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/relay.py b/plugins/relay.py index d112bef..07f9a27 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -1405,25 +1405,36 @@ def link(irc, source, args): except IndexError: irc.reply("Error: Not enough arguments. Needs 2-3: remote netname, channel, local channel name (optional).") return + try: localchan = irc.toLower(args[2]) except IndexError: localchan = channel + for c in (channel, localchan): if not utils.isChannel(c): irc.reply('Error: Invalid channel %r.' % c) return + + if remotenet == irc.name: + irc.reply('Error: Cannot link two channels on the same network.') + return + if source not in irc.channels[localchan].users: irc.reply('Error: You must be in %r to complete this operation.' % localchan) return + irc.checkAuthenticated(source) + if remotenet not in world.networkobjects: irc.reply('Error: No network named %r exists.' % remotenet) return localentry = getRelay((irc.name, localchan)) + if localentry: irc.reply('Error: Channel %r is already part of a relay.' % localchan) return + try: entry = db[(remotenet, channel)] except KeyError: From bcc754cf0b050e204c5e53eff49127b1b5819c9e Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 12:30:34 -0700 Subject: [PATCH 4/9] relay: allow forcing slashes on unsupported IRCds This adds an undocumented option "relay_force_slashes" to allow slashes in nicks anyways, for IRCds that are, for example, TS6 or P10 variations that don't validate remote nicks. --- plugins/relay.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/relay.py b/plugins/relay.py index 07f9a27..2c64c15 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -103,11 +103,17 @@ def normalizeNick(irc, netname, nick, separator=None, uid=''): orig_nick = nick protoname = irc.protoname maxnicklen = irc.maxnicklen - if '/' not in separator or not protoname.startswith(('insp', 'unreal')): - # Charybdis doesn't allow / in usernames, and will SQUIT with - # a protocol violation if it sees one. + + # Charybdis, IRCu, etc. don't allow / in nicks, and will SQUIT with a protocol + # violation if it sees one. Or it might just ignore the client introduction and + # cause bad desyncs. + protocol_allows_slashes = protoname.startswith(('insp', 'unreal')) or \ + irc.serverdata.get('relay_force_slashes') + + if '/' not in separator or not protocol_allows_slashes: separator = separator.replace('/', '|') nick = nick.replace('/', '|') + if nick.startswith(tuple(string.digits)): # On TS6 IRCds, nicks that start with 0-9 are only allowed if # they match the UID of the originating server. Otherwise, you'll From d3e207d653fcdad5fee8e59c0d2544f36bbb35f0 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 12:32:12 -0700 Subject: [PATCH 5/9] relay: axe unused variable --- plugins/relay.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/relay.py b/plugins/relay.py index 2c64c15..59c3a3c 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -119,7 +119,6 @@ def normalizeNick(irc, netname, nick, separator=None, uid=''): # they match the UID of the originating server. Otherwise, you'll # get nasty protocol violation SQUITs! nick = '_' + nick - tagnicks = True suffix = separator + netname nick = nick[:maxnicklen] From 87cbbc9c57f621ce308d1fde77167e1c157845f3 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 12:32:27 -0700 Subject: [PATCH 6/9] relay: clearer error message when DESTROY'ing a channel you didn't create --- plugins/relay.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/relay.py b/plugins/relay.py index 59c3a3c..c22c87e 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -1395,7 +1395,8 @@ def destroy(irc, source, args): channel, irc.getHostmask(source)) irc.reply('Done.') else: - irc.reply('Error: No such relay %r exists.' % channel) + irc.reply("Error: No such channel %r exists. If you're trying to delink a channel from " + "another network, use the DESTROY command." % channel) return @utils.add_cmd From 26df48c26d663b130b9bf2738ce5348fe7420fb5 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 21:13:14 -0700 Subject: [PATCH 7/9] ts6: add missing definition for cmode +i --- protocols/ts6.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/ts6.py b/protocols/ts6.py index bed80c7..8dc3619 100644 --- a/protocols/ts6.py +++ b/protocols/ts6.py @@ -259,7 +259,7 @@ class TS6Protocol(TS6BaseProtocol): chary_cmodes = { # TS6 generic modes (note that +p is noknock instead of private): 'op': 'o', 'voice': 'v', 'ban': 'b', 'key': 'k', 'limit': 'l', 'moderated': 'm', 'noextmsg': 'n', 'noknock': 'p', - 'secret': 's', 'topiclock': 't', + 'secret': 's', 'topiclock': 't', 'inviteonly': 'i', # charybdis-specific modes: 'quiet': 'q', 'redirect': 'f', 'freetarget': 'F', 'joinflood': 'j', 'largebanlist': 'L', 'permanent': 'P', From e057df2ae9814e325a64c5e6a5f5684986bf55e5 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 21:14:10 -0700 Subject: [PATCH 8/9] channel-modes: fix definition for private (+p) Charybdis and Elemental-IRCd implement +p as noknock, not the RFC1459-style private. --- docs/technical/channel-modes.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/technical/channel-modes.csv b/docs/technical/channel-modes.csv index c309663..f39280f 100644 --- a/docs/technical/channel-modes.csv +++ b/docs/technical/channel-modes.csv @@ -45,7 +45,7 @@ oplevel_upass,,,,,,U opmoderated,U (extras/m_opmoderated),z,z,,, owner,q (m_customprefix/m_chanprotect),,y (when enabled),q,, permanent,P (m_permchannels),P,P,P,,z -private,p,p,p,p,,p +private,p,,,p,,p quiet,,q,q,,, redirect,L (m_redirect),f,f,L,,L registered,r (m_services_account),,,r,r,R From 3e19e9c3f1b92b166328225d737c459b4ad9e13b Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 19 Jun 2016 21:18:35 -0700 Subject: [PATCH 9/9] unreal: add missing inviteonly (+i) definition --- protocols/unreal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/unreal.py b/protocols/unreal.py index 9155a93..9a1a38d 100644 --- a/protocols/unreal.py +++ b/protocols/unreal.py @@ -482,7 +482,7 @@ class UnrealProtocol(TS6BaseProtocol): 'nokick': 'Q', 'private': 'p', 'stripcolor': 'S', 'key': 'k', 'op': 'o', 'voice': 'v', 'regonly': 'R', 'noinvite': 'V', 'banexception': 'e', 'nonick': 'N', 'issecure': 'Z', 'topiclock': 't', - 'nonotice': 'T', 'delayjoin': 'D'} + 'nonotice': 'T', 'delayjoin': 'D', 'inviteonly': 'i'} # Make a list of all our capability names. self.caps += [arg.split('=')[0] for arg in args]