xmtp / libxmtp

MIT License
33 stars 13 forks source link

Conversation History - New installations only see one 1to1 conversation (Large) #696

Open nplasterer opened 2 months ago

nplasterer commented 2 months ago

Conversation History

The biggest difference between 1:1 and Groups is that users will expect that for any pair of inboxes there is only one conversation. With Groups, you can have an unlimited number of conversations with identical membership.

Enforcing this constraint is a bit tricky. Imagine Alix and Bo each have one app and are chatting in a 1:1 conversation.

Now, Alix installs a second app using the same inbox. There are two ways that Alix’s second app can get added to the existing conversation.

  1. Either Alix or Bo send a message on the original apps used in the convo. Their clients detect the new installation and add Alix’s second app to the convo.
  2. Alix restores from a message history backup and as part of that process, Alix’s old app adds Alix’s new app to all existing conversations.

But it’s possible that neither of those two things happen at first. Message history restoration is optional from the protocol level. In that case, when Alix wants to send Bo a message from their second app they will be unaware of the existing conversation and create a new one.

One way to solve this problem would be to have 1:1 be treated as an aggregation of one or more groups. The message list would be merged in that scenario, and each client would send new messages to the oldest (or newest) group it was aware of. When reading new messages you would need to sync all groups. The membership between all the groups would become the same over time, so it feels awkward to require this just for the edge case of brand new installations with no history.

richardhuaaa commented 1 month ago

I think there's two questions here - whether v2 and v3 1:1 conversations can exist simultaneously, and whether there can be multiple duplicate v3 1:1 conversations.

I think the answer to the first question should be yes, as we need to support dual send/receive as a migration path. And ideally the answer to the second question would be no, but it depends on technical feasibility.

I think in order to answer the second question, we need to iron out exactly how we are going to support personal preferences in v3 (which is needed for consent, for example, even if we don't support message history). It's possible we could piggy-back on however that works.

Another avenue for exploration would be whether we can have a deterministic group_id or other dedupe_key that is derived from the two addresses involved in the conversation. Then a client could always detect that a 1:1 conversation is already in progress for a given sender/receiver pair. If we went with this approach, in order to not leak anything, we'd have to provide cryptographic protection to prevent parties other than the two people involved in the conversation from performing the same detection.

richardhuaaa commented 3 weeks ago

Ideas from discussion:

  1. Stitch conversations
  2. Use consent lists + external join
  3. Use deterministic topic ID (with per-user DH keys in personal prefs) + external join
  4. Make message history sync mandatory for at least the conversation list
nplasterer commented 3 weeks ago
  1. Stitch conversations

Complexity on our side. Tracking all these conversations and tracking them together. We all agree this is not ideal.

  1. We already track consent

We may be able to derive the whole conversation from that consent list. Could check the consent list to see if you already have a conversation. Knowing you have a conversation doesn't allow you to send message. Add an installation to that conversation. MLS feature called external joins. We would need to implement.

  1. Use deterministic topic ID (with per-user DH keys in personal prefs) + external join

2 doesnt handle race conditions. This is similar to 2. There could be a large window for this race condition. Lets make sure for any two participants they will always end up on the same topic id. We generate a diff helmen key pair and hash the results for the topic. (kind of how we do it in V2 for deterministic topics) This is a little complicated because we have to generate new keys and sync it. All devices have the same key in V2 but all devices have different keys in V3. We're trying to get away from this for security reasons. Similar to the HMAC key we would use the same mechanism

  1. Make message history sync mandatory for at least the conversation list

Message history sync is optional. But make the conversation list of it as required. Simple. But if lost in a river the list is gone.
V2 does not require a live device but it has a security trade off. And a UX trade off because of the wallet signature.

nplasterer commented 3 weeks ago

Default on for message history with the option to turn off. But you can't turn off personal preference syncing.

New device is still going to make duplicate conversations if it doesn't do the message history because the device isn't active. Stitching will query both conversations but only write to the latest. Latest will be come the same for both users after a message is sent there. 1to1 does not have special permission policies so shouldn't be an issue for two group chats to get out of sync.

Conversation identifier is a concat of the two inboxIds and then we query that.

Sub feature of 1on1 not modifying anything about groups.

Dual Sending: Just show V2 conversations for a period then cut over to just showing V3