Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Murmur: forward text message to linked channels #3457

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

davidebeatrici
Copy link
Member

@davidebeatrici davidebeatrici commented Jul 8, 2018

@davidebeatrici davidebeatrici added server feature-request This issue or PR deals with a new feature labels Jul 8, 2018
@davidebeatrici davidebeatrici requested review from mkrautz, Kissaki, a user, hacst and Natenom July 8, 2018 03:46
@ghost
Copy link

ghost commented Jul 8, 2018

After this patch, text messages will not fail if the user sends a message to a channel and the channel has a linked channel on which the user does not have text message permission.
But text messages will fail if the user sends a message to a channel tree and the channel has a linked channel on which the user does not have text message permission.
Is this the correct behaviour?

I didn't test it, but, is an infinite loop possible when resolving the tree links, if there is a bidirectional channel link?

@Krzmbrzl
Copy link
Member

I didn't test it, but, is an infinite loop possible when resolving the tree links, if there is a bidirectional channel link?

From a quick glance at the code, I think that could happen, as there is no check as to which channels have been visited before...

@davidebeatrici davidebeatrici changed the title Murmur: forward text message to linked channels WIP: Murmur: forward text message to linked channels Jan 22, 2020
Copy link
Member

@Krzmbrzl Krzmbrzl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I see it, if messages are sent to the tree, the immediate links are being accounted for. However if a channel that gets added to q due to being linked to another channel in the tree the message is originally sent to, then that channel won't be checked for additional links.

That is if we have 3 channels: A, B and C and A is linked to B and B is linked to C. Now we send a message to tree so that A receives it. The code checks A's links and finds B and adds B to q. However as I see it, the message will not reach C.

Now this could of course also be a feature / wanted bhavior. Just wanted to point it out.

As to the potential endless loop: I Don't see a chance for this happening as long as this fuction doesn't call itself somehow (which I don't see happening). We might get some duplicates in q though but as soon as we process q to add the contained users to the set, the duplication is removed by using a St of users instead of a list.


// Forward text message to linked channels
if (c->qhLinks.count() > 0) {
foreach(Channel *l, c->qhLinks.keys()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
foreach(Channel *l, c->qhLinks.keys()) {
// First check if the sender has the permission to write a text-msg to the linked chanel
if (! ChanACL::hasPermission(uSource, l, ChanACL::TextMessage, &acCache)) {
continue;
}
foreach(Channel *l, c->qhLinks.keys()) {

// Forward text message to linked channels
if (c->qhLinks.count() > 0) {
foreach(Channel *l, c->qhLinks.keys()) {
q.enqueue(l);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
q.enqueue(l);
// Permission is checked later, so we don't have to worry about it here
q.enqueue(l);

@Krzmbrzl
Copy link
Member

@kripton you said that you wanted to work on this feature. I just found this PR again and wanted to make sure you know about it. I think you can pick up where it was left, if you want to :)

@kripton
Copy link
Contributor

kripton commented Oct 27, 2020

@Krzmbrzl: Thanks, I'm aware. Might take some days to think through on how I'd want this to work exactly. But I'll have a look what's here and what the comments are 👍

@kripton
Copy link
Contributor

kripton commented Nov 1, 2020

Well, I've started working on this.
Just as a general understanding: The protocol definition of TextMessage would allow a message to be sent to 0 or more users PLUS 0 or more channels PLUS 0 or more trees. However, the UI only allows messages to be sent to one user OR one channel OR one tree. Is there any chance in the UI to send to multiple users? Or multiple channels? Or multiple trees? Or to a mixture to any of those?

And can we take the "limitations" of the current UI into account when checking permissions?

Because this check already leads to unintended rejections if a message would go to a channel (where the sender has the permission to send a message to) PLUS several users (where just one of them is in a channel where the sender does NOT have the permission to send messages to):

PERM_DENIED(uSource, u->cChannel, ChanACL::TextMessage);

@Krzmbrzl
Copy link
Member

Krzmbrzl commented Nov 1, 2020

Is there any chance in the UI to send to multiple users? Or multiple channels? Or multiple trees? Or to a mixture to any of those?

I don't think so, but I am also not super familiar with the code parts for text messaging...
I think however that the server's implementation should be able to handle all possible combinations of the possibilities, as (in theory) unofficial client-implementations might exist that expose all of the protocol's capabilities to the user. Or in fact we could decide at some point that we want to do so 🤷

Because this check already leads to unintended rejections if a message would go to a channel (where the sender has the permission to send a message to) PLUS several users (where just one of them is in a channel where the sender does NOT have the permission to send messages to):

Yes indeed. The fact that a single rejected message effectively cancels all other (potentially valid) messages is (imo) a shortcoming of the current implementation

@kripton
Copy link
Contributor

kripton commented Nov 1, 2020

Just noticed that I've continued the discussion in the PR instead of #1719 where it actually belongs :-/

I am fully in line that the server should support all cases supported by the protocol, even if the official client cannot trigger some cases.

The question when a message is counted as "failed" is pretty complex since we only have "success" or "failure" (permission denied) as responses. Of course we could introduce a third one ("partially failed") but I feel that it might be a bad idea.
I think we agree that if the permission for an "indirect" recipient (linked channel, user listening to a channel) is not given, the message shall not fail.
So, what do we do if a message targets 5 channels and 2 trees and the permission for 3 directly targeted channels (not targeted via the tree) is missing? Fail the whole message but tell the user? Deliver it to where it's allowed and don't tell the user it failed for 3 channels? Do something else?

Sorry if I'm asking so many question but I would like the design to be same so it can be "easily" explained to the users

@Krzmbrzl
Copy link
Member

Krzmbrzl commented Nov 2, 2020

Just noticed that I've continued the discussion in the PR instead of #1719 where it actually belongs :-/

In the end it doesn't really matter :)

I think we agree that if the permission for an "indirect" recipient (linked channel, user listening to a channel) is not given, the message shall not fail.

yes

So, what do we do if a message targets 5 channels and 2 trees and the permission for 3 directly targeted channels (not targeted via the tree) is missing? Fail the whole message but tell the user? Deliver it to where it's allowed and don't tell the user it failed for 3 channels? Do something else?

I thin the problem that we are facing is that we can't tell the user that it failed for multiple targets. Therefore I think we have to make the best out of it and tell the user about the first direct target that failed.
Imo though the message should still be sent to all other targets that it is allowed to even though to some it wasn't allowed to.

The way I imagine this to work is to process all targets, put the ones that aren't allowed into a list/set and when actually sending the messages, ignore targets that the user may not send messages to.
Then after having sent the message to all valid targets, check if there were denied targets and if so, report permission denied for the first one.
Ideally we would expand the permission denied message to take a list of targets so that we can inform the user about all targets the (s)he couldn't send the message to...

Sorry if I'm asking so many question but I would like the design to be same so it can be "easily" explained to the users

Absolutely no problem. In fact I think it is important to discuss issues like this in order to arrive at the best possible end result 👍

@kripton
Copy link
Contributor

kripton commented Dec 17, 2020

Mh, didn't have time for this for too long, sorry. So, here we go :)

Terms:

  • Primary target: A message target (user, channel tree root), that the sender specified explicitly when sending the TextMessage
  • Secondary target: A message target (user, channel) that the sender did not specify explicitly. Results of subchannels in a tree, channel linking and users listening to channels

I've thought a bit about expanding the PermissionDenied message to include targets that did not get a message because of a lacking permission and I feel that it should only be used for "hard" errors. Here's my counter-proposal:

  • When the message cannot be delivered to a primary target, the server generates a PermissionDenied message and delivery is stopped. This resembles more or less the current situation, keeping in mind that the current client sends messages to either a user OR a channel OR a tree but not to a mix of them
  • In all other cases (all primary and secondary targets got the message OR some secondary targets failed), the server will send a TextMessageDeliveryReport back to the actor

I've drafted the TextMessageDeliveryReport in the Mumble.proto file like this:

// Sent by the server to the user who just sent a TextMessage to indicate the 
// targets the message has (or not) been delivered to.
// If the actor is not allowed to send a message to a user, channel or tree
// that was directly requested as a target in the TextMessage command
// (= primary target), a PermissionDenied message is sent back instead of the
// TextMessageDeliveryReport
message TextMessageDeliveryReport {
	// The message sender, identified by its session.
	required uint32 actor = 1;
	// The UTF-8 encoded message as sent to the other users
	// Might differ from the message the sender sent if it was too long or
	// contained HTML and the server doesn't allow HTML messages
	required string message = 2;
	// The primary users (identified by their session) the message has been
	// delivered to.
	// Basically the same users that the sender requested but we copy the
	// information for the convenience of the sender to not need to keep track
	repeated uint32 primary_users_delivered = 3;
	// The primary channel IDs the message has been delivered to.
	// Basically the same channels that the sender requested but we copy the
	// information for the convenience of the sender to not need to keep track
	repeated uint32 primary_channels_delivered = 4;
	// The primary root channel IDs the message has been delivered to,
	// Only the roots. For all channels the message went to, see
	// secondary_channels_delivered
	// Basically the same root channels that the sender requested but we copy
	// the information for the convenience of the sender to not need to keep
	// track.
	repeated uint32 primary_tree_root_delivered = 5;
	// The secondary users (identified by their session) the message has been
	// delivered to.
	// Secondary users are users in:
	//   * channels OR
	//   * channels below a tree root OR
	//   * channels linked to channels
	// the message was being sent to OR
	//   * users that listened to channels the message was being sent to 
	// Those are all the users that got the message minus the ones listed
	// in primary_users_delivered.
	repeated uint32 secondary_users_delivered = 6;
	// The secondary channel IDs the message has been delivered to.
	// This includes channels that were part of a channel tree or channels
	// that were linked to ones the message has been targeted at.
	// Those are all the channels the message has been delivered to minus the
	// ones listed in primary_channels_delivered and primary_tree_root_delivered
	repeated uint32 secondary_channels_delivered = 7;
	// The secondary channel IDs the message could not be delivered to.
	// Those are the channels that the message should be sent to but the
	// actor was lacking the required permissions. In those cases, no
	// PermissionDenied-Message is being generated but the client can find
	// the information here.
	repeated uint32 secondary_channels_failed = 8;
}

I've thought about adding a secondary_users_failed-field but couldn't find a case where we would list a user there. If a user is listening to a channel that gets a message, the user will get the message. We won't be checking if the message sender has the permission to send text messages to the channel the listening-user resides in. That would contradict the listening to function quite a bit.

Does that make sense? Shall I go ahead implementing it like that, including defining the new message type in the proto and sending it to the client?
Are the comments of the TextMessageDeliveryReport definition too verbose for the proto file?
Not sure how we want the Mumble client to behave if a TextMessageDeliveryReport is returned by the server but protocol-wise it would be the cleanest solution.

@Krzmbrzl
Copy link
Member

Creating a new message gives us more flexibility but we should also keep in mind that this way for older clients, we'll have to fall-back to the current solution as they don't know about the new message.

In all other cases (all primary and secondary targets got the message OR some secondary targets failed), the server will send a TextMessageDeliveryReport back to the actor

I think we only need this message in case the delivery failed at some point. If all went fine, I don't see the point in sending it.

Are the comments of the TextMessageDeliveryReport definition too verbose for the proto file?

Nah, they're great. This way one does not need any implicit knowledge to understand the message's purpose 👍

The message itself seems to contain way more information than it actually needs to though. 👀

Not sure how we want the Mumble client to behave if a TextMessageDeliveryReport is returned by the server but protocol-wise it would be the cleanest solution.

We should probably figure this out first, so that we can then tune the report to contain just the necessary information. No need to send unneeded info back and forth. That only uses up bandwidth ☝️

@Krzmbrzl Krzmbrzl marked this pull request as draft January 1, 2024 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request This issue or PR deals with a new feature server
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Linked channels with text message
3 participants