ircv3-specifications
ircv3-specifications copied to clipboard
Add draft relaymsg spec
This PR submits the relaymsg
extension that I developed for my network as a draft. It allows relay bots to spoof usernames in a stateless fashion, similarly to webhooks in Discord and Slack. I originally posted this idea in https://github.com/ircv3/ircv3-ideas/issues/63 - but ultimately, I wanted to try implementing it anyways, after seeing plenty of stability/scalability concerns with my previous services-based relayer.
(dan- helped me edit this initial draft, so I've added him as a co-author)
Why not just use a tag for the relaynick and normal PRIVMSGs?
This is something I did consider early on, ie. using @+relaymsg with a client-supplied value. However, it seemed like that would be more work for a bot to check whether the feature is supported: it would depend on message-tags being available, as well as some other signal that relaymsg is supported by the server (ISUPPORT key or a separate tag?). The fallback if the relaymsg context simply gets dropped would be quite confusing IMO.
I really like the idea, but I have a few questions/concerns:
- What is the meaning of nickname separators? Where should a separator be in the spoofed nickname?
- It should mention there should be a fallback for receiving clients which don't support
relaymsg
. - It's a security issue for bots receiving these relayed messages if the relay bot has any kind of privilege over them (it's a bad idea to do that, but it happens, eg. if the relay bot has the same hostmask or NickServ account as a real user).
- It's also a security issue for bots receiving these relayed messages; if they use only nicks for authenticating senders, then the relay bot can impersonate them (again, it's a bad idea, but it happens too)
@jlu5 even if the server is involved and there’s a CAP you can still have the client send a normal privmsg with the relay nick as a tag and it can then only send the tagged message to clients that support it, adding the fallback in for other clients.
I don’t see the need for a separate RELAYMSG verb or for the spoofed nick to appear in the source.
I think I confused the @relaymsg sender tag with a potential spoofed nick tag - my bad. (This is what happens when I comment at 2am I guess..)
The spoofed nick trick is really to ensure backwards compatibility, and not having to patch every single client to support virtual senders. Given the breadth of clients and platforms IRC supports, having this be handled client side just wasn't feasible for my network.
But, I suppose server side translation could still be possible using a client side tag? e.g. client sends @+relaynick=me/net2 PRIVMSG #channel :abcd
, which gets translated on supported servers as me/net2 PRIVMSG #channel :abcd
. This could also add room for specifying an ident & host to send from, though the allowed hosts should use some sort of whitelist for security reasons. (e.g. @+relaynick=me/net2 @+relayhost=relay.example.com/net2-1234 PRIVMSG #channel :abcd
)
As for fallback, I'm not quite sure what's needed? relaymsg source spoofing makes the sender look like any client that happens to be sending an external message. If relaymsg isn't supported, the command fails and nothing is forwarded. I have seen some bots not working well with nicks that contain invalid nick characters, but current relay implementations already use some of these (e.g. / and ~), and I haven't heard any user complaints about broken clients. Though, full UTF-8 support is another question, so that's why I've left that as optional for consideration.
Having this as a tag on PRIVMSG would look a bit different. If the relaynick context gets dropped and the message gets sent as PRIVMSG #channel :abcd
, that would be no good. It'd look like the bot was speaking to itself without any other context. I can imagine something like @+relaynick=me/net2 @+relaymsg-strip=10 PRIVMSG #channel :<me/net2> abcd
to chop off the first X characters if relaymsg is supported? But this seems quite like a hack to me..
Replying more specifically to https://github.com/ircv3/ircv3-specifications/pull/417#issuecomment-640178893:
I really like the idea, but I have a few questions/concerns:
1. What is the meaning of nickname separators? Where should a separator be in the spoofed nickname?
Spoofed nicks look something like jlu5/mynet
or jlu5~d
- in these cases the /
or ~
would be the separator. In terms of implementations, PyLink uses the first format (though the separator char is configurable) and go-discord-irc uses the latter by default.
2. It should mention there should be a fallback for receiving clients which don't support `relaymsg`.
See above.
3. It's a security issue for bots receiving these relayed messages if the relay bot has any kind of privilege over them (it's a bad idea to do that, but it happens, eg. if the relay bot has the same hostmask or NickServ account as a real user). 4. It's also a security issue for bots receiving these relayed messages; if they use only nicks for authenticating senders, then the relay bot can impersonate them (again, it's a bad idea, but it happens too)
I suppose an ideal implementation of this would have to allow relaying from a bot-specified hostmask. I agree that verifying by nick only is useless, especially considering that other platforms (eg Discord) don't necessarily guarantee that nicks are unique.
I’m not comfortable at all with the relay nick being fully spoofed into the source. Clients seeing messages from nicks that aren’t actually on the network would be an issue, not to mention that you can’t even express many relayed nicks in the irc protocol (spaces, special characters).
Putting it in angle brackets at the start of the message is preferable as a fallback.
You’re saying relying on clients to add support for this isn’t feasible, but they will need to add support for the CAP you’re proposing anyway.
I’m not comfortable at all with the relay nick being fully spoofed into the source. Clients seeing messages from nicks that aren’t actually on the network would be an issue, not to mention that you can’t even express many relayed nicks in the irc protocol (spaces, special characters).
I feel this is fundamentally a limitation of IRC in that we don't have widespread support for display names (yet). These issues have to be worked around by any implementation that wants spoofed sources, regardless of which method they use to do it. In my matterbridge fork I replace disallowed characters with a -
before sending the message, for example.
There was some talk when I first drafted this about giving the option for bots to register a relayed-nick namespace as a target for commands; this could open up the possibility of things like cross-network PMs for example, and alleviate the confusion of nicks that appear but don't exist. But, it still faces the same issues of other platforms allowing more liberal display names than IRC or duplicate nicks. Nick rewriting is the best I can do in the first case, but the second is way more ambiguous.
Putting it in angle brackets at the start of the message is preferable as a fallback.
This is just what regular relay bots do, but my experience is that a lot of people dislike this syntax precisely because it doesn't integrate well with the rest of IRC.
You’re saying relying on clients to add support for this isn’t feasible, but they will need to add support for the CAP you’re proposing anyway.
Only the relay bot needs to handle the relaymsg capability to use the feature - everyone else just sees it as a regular PRIVMSG. They could request the relaymsg cap to verify that spoofed messages are in fact spoofed, but it's not a requirement for the basic design to work.
Oh so regular clients don’t even have to opt in to seeing spoofed nicks? That sounds even worse.
I get that you’re trying to improve the landscape but just punting on getting clients to implement this properly isn’t really the way forward. Doing stuff like this might work for niche networks where people are on board with the idea. But I don’t see it getting traction as a sanctioned ircv3 extension.
I’ll let others comment if they think this has legs though.
I'm very sympathetic to this proposal. Here's how I see it: if you want to do protocol bridging using the IRC client-to-server protocol, with separate nicknames for each identity on the other side of the bridge, the network operator currently needs to set up IP limit whitelisting and the bridge needs to create a separate TCP connection for each bridged client. I see this proposal as a way of streamlining and optimizing that. What's salient is that RELAYMSG will typically be restricted to a privileged user of some kind; in many cases, the privileges will be comparable to those associated with a server-to-server connection. So I'm not that concerned about the potential security or user rights issues here. (I'm not saying this as an unqualified endorsement of the proposal in its current form: in particular, I would be interested in having a better story about direct messages.)
Philosophically, I want to object to the characterization of small networks as "niche networks"; they may be niche individually but the use case is not niche. I think a lot of the future of IRCv3 is in the long tail of small networks.
No shade intended whatsoever. It just seems much better suited to a vendor prefix.
I think the implication of leaving this as a vendor prefix is that mainstream software projects --- clients, servers, and bridges --- shouldn't need to implement this, or shouldn't prioritize implementing it. But that doesn't follow from the claim (which I accept) that this will primarily be useful on small networks, or private networks.
Just at a concrete level, I imagine it would be considerably easier to get this into upstream Matterbridge if it were an official IRCv3 draft. So the question is, is this useful enough to the IRCv3 ecosystem as a whole (even if not to any large networks within it) to warrant being an IRCv3 draft? I think it is.
I know that spoofed nicks aren't standards compliant, but I'd just like to point out that reserved nick characters are something I've used in production for 5+ years now, and I've never seen a single client actually explode when parsing them. (The only issues I've seen are from other bots ironically, such as matrix-appservice-irc iirc). This similarly never was opt in because those virtual clients just show up in the user list, and clients just had to adapt to it. In fact, my implementation wasn't even the first to use the nick separator trick; the predecessor that inspired it (Janus) had been around for years before that.
From all I've seen, client parsers are more liberal than the original IRC spec when it comes to parsing nicks. I don't know if this is because of all the server-side relayers using this, or if it just happened naturally.
As for whether the idea is niche, I've heard that sentiment a dozen times by now. I get that large networks don't have much demand for relayers because they already have a large established community. But for smaller / hobbyist networks, it's very much an uphill battle to get any traction these days...
For a bit more context: PyLink's goal was really to give small to mid size networks the option of forming larger communities without losing their autonomy. It does this by doing server-side relays between channels on an opt-in basis. For the most part, the UX for IRC<->IRC relays work well and you could easily say, kickban a user connected on another network.
Later on, we added Discord support based on this bridging framework and it sort of became a PoC gone wild... Some of the core concepts that originally worked well on IRC starting breaking down: kicks/bans for example could not be synced in any non-hacky way. Duplicate nicks also did weird things and never really got resolved in a consistent manner. Similarly, I had to run unidecode to flatten UTF-8 nicks into IRC compatible ASCII - a lossy process that really is a bandaid fix for a lack of UTF-8 support. But more broadly there were design concerns: IRC bridges require prepopulating a list of all users to work properly, but this would never scale well onto platforms with giant servers. User lists are paginated on platforms like Discord and Slack - and even if you could get past API limits, the amount of join/quit spam on a cycle would be awful UX on most IRC clients.
So all in all, this is the story of what really made me want to approach stateless bridging.
To be clear, I don't think this idea is niche, just this implementation of it. I think for something that's after all largely a display issue, clients should be involved in a proper implementation. I'd be more than happy to support an IRCv3 spec that allows for this, but the proposal here feels like a workaround/bypass rather than a solution.
Is "clients should be involved" an objection to any specification that would relay spoofed nicks to legacy clients without an opt-in? Because I think that's exactly what I'm hoping for: something that achieves parity with the multiple-clients-over-C2S implementation of bridging, but without actually requiring multiple clients.
If I'm understanding your comment properly, no, that's not my objection. I'd be very happy for a solution that uses a single bridging bot client and "spoofing" using a message tag, rather than directly replacing the nick/user/host source prefix.
"Clients should be involved" means that clients should have to implement support for displaying the "spoofed" nick somehow, and not just be fooled into thinking a message is coming from a different user that doesn't exist on the network.
Right --- "fooling" the clients, i.e., transmitting the spoofed nickmask directly as the message source, without an opt-in, is exactly what I want to do. (Again, I want parity with the multiple-clients-over-C2S implementation. It seems academic to me whether the clients "really exist" on the network on the network or not; in the multiple-clients-over-C2S case, they're still special-cased by the server (for rate limiting purposes) and not able to participate in DMs.)
"Clients should be involved" means that clients should have to implement support for displaying the "spoofed" nick somehow, and not just be fooled into thinking a message is coming from a different user that doesn't exist on the network.
What's the motivation for this? Is this a user rights issue? Is core functionality being broken?
It's not academic at all. Non-existent users can't be interacted with in the same way. kicks, bans, dms, whois, etc. It breaks fundamental expectations of IRC presence. This may be something you want to do, but I wouldn't describe it as mainstream IRC functionality (hence niche).
Clients should be involved because this is about how clients display messages. Asking the server to pretend for a bot just seems to be the wrong approach. I want to spend effort on specifying a robust proposal for clients to display these messages in a more user friendly way. I don't want to spend effort on ratifying a workaround.
That makes sense. DMs and WHOIS are broken anyway, but I hadn't considered the impact on moderation (kicks and bans).
The point isn't whether they're broken already, it's that with source spoofing they look like they aren't broken.
We have two competing views here, but I think we can unify them both:
- we could add a tag for PRIVMSG that contains the spoofed nick (@jwheare 's proposal), and senders use it
- recommend that server implementations pass it to other clients (still @jwheare 's proposal), but they are allowed to rewrite messages however they want (covers @jlu5 's use case)
- have the separator thing as an official (but optional) or vendored tag?
@jwheare: leaving aside the issue of sanctioning bad behavior by servers, would this proposal be feature-complete from your perspective?
I’d be happy with a “display name” or “relay name” client tag spec.
Whether servers use this as a hint to rewrite the source nick would be out of scope and left up to the implementation I think.
I don’t fully get the separators thing or why it has to be specified.
I thought about it and I don't see much possibility of a viable compromise specification. The objective of this specification is to enable nick spoofing. If spoofing becomes an unspecified or implementation-defined behavior, it largely defeats the purpose and also makes the specification confusing on its own terms. (An example is the question of separators: the purpose of separators is to establish a disjoint namespace for spoofed nicks. If nick spoofing is optional or peripheral to the specification, then it is indeed unclear why they should be specified.)
I'm OK with what seems to be the status quo: leaving this open as draft/relaymsg
, and then keeping the bridging use case in mind for any future display name proposals.
I think there should also be a RELAYNOTICE
or RELAYBOT
or similar command for the usecase of bridging NOTICE
use by automatons. Two scenarios where this could be encountered:
- Bridging multiple IRC networks where bots are using NOTICEs together.
- Bridging Matrix to IRC as they have
m.notice
that is used for bots.
I have been using Matterbridge's relaymsg since it was released with Oragono and loving it, so I hope it will become an officially approved spec. My favourite thing is that receiving it just works with any client and thus will reduce complaints of relaying looking ugly.
This spec will probably live here as an open PR forever.
If we really wanted to @jlu5 we could make it a finalised vendor spec under either overdrivenetworks.com
or oragono.io
... but I'm also totally okay (probably more okay) just leaving this as a PR and using /draft
forever (or until some grand c2ctag future where we replace this with a displayname c2c tag or something).
I don't think draft/
should be used forever, it's supposed to be only temporary, and for somewhat experimental implementations. Vendoring is perfect for this.
We'll see what @jlu5 thinks about vendoring, because there's no way the spec is fundamentally changing going forward.
I support maintaining the status quo.