PFS and missing contact information


PFS relies on a piece of data to be exchanged between the users to allow a “secure channel” to be established (any messages exchanged through a secure channel have pfs properties).

A secure channel can be established currently in a few ways:

  1. Through public chats
  2. Through contact codes

Which means that if you send a direct message to a user who you added through a contact code (we changed the format), or you have received a message from the user in any public chat, the app works exactly as before.

In a few cases though that is not the case:

  1. You add the user through a public key
  2. You use ENS (ENS support might come but not in the initial version)

In those cases a secure channel cannot be established until the receiving user replies to our message.

Until more solid options are available (IPFS, Swarm), we need to consider the possibility of this happening and we need to find a way to handle it, until then we will add more ways to establish a secure channel.

To handle this there are a couple of options available:

Force all users to exchange a contact request before sending message

This is basically the same as Facebook, whereby if you want to communicate with user B you would first send them a contact request, which need to be accepted before any communication takes place.

Only require users to establish a secure channel when that cannot be done

This would only apply to the cases mentioned above, which should be the minority:

  • adding by public key will be replaced by contact codes
  • ENS is not live yet as I understand, and by the time it goes live we might be able to cover this scenario as well.

To give a concrete example of what a user flow might look like in this scenario:

  1. Users A adds user B public key, when they open a chat they see a message: “We could not establish a secure channel, a request has been sent, we need to wait for a reply from blah until any message can be securely sent” (this can be signaled by an icon of an open lock pad or similar)
  2. User B sees a chat with a message “User B wants to establish a secure channel with you, would you like to do so?”
  3. Once user B accept, adds the user to contact or replies with a message a secure channel is established.

As a last option we could still allow the user to send messages, and find a way to warn/explain that until a user replies to them those messages have different security properties, but I would discard this as not desirable.

I personally feel that 2 sounds the most reasonable given that it should impact only a few cases and can be improved incrementally by adding more ways to establish a secure channel without user interaction.

What do you all think?

1 Like

Hey @cammellos thanks for exploring this.

I like the approach but just had some concerns for User B in your scenario. User B will receive a contact request but will have no context of the sender, so it removes any option of informed consent or context. This may force users to either get into the habit of accepting all, or rejecting all contact requests.

Instead, how about if User A could include a welcome message so that User B can decide whether to accept/reject/block? Skype used to have something like this to help deal with unknown contacts and spam, and gave the recipient solid next steps.

(forgive the google-images-found example, but it nicely illustrates that this contact request is clearly spam, and shows the context needed for the recipient)


@Chad I like the suggestion, we could do this for any contact request sent before that any message has been exchanged.

In this way is much clearer that the user is actually sending one, at the moment Add to contacts is not really clear that your are actually sending data, UX does this sound like a plan?

Agree, many thanks @cammellos for exploring and raising the discuss post.

Generally, I agree with @Chad’s point + example but would also ask if it’s possible to allow User A’s first message to be included as part of the “User A wants to establish a secure channel with you, would you like to do so?” connection request?

I’m making a bit of an assumption that the first message from A should establish context for who is trying to contact you. Maybe this is what you’re kind of referring to in your “last option” example though?

@patrick I think it depends on how we present this to the user.

Basically in such cases it’s ok to include a “introduction message”, but it needs to be clear to the user that it is not a “message” and it’s a “contact request”, so it’s easier to explain that we guarantee PFS for messages but not for contact requests.
If the user is concerned about privacy they can always send it blank, or with the pre-filled message “Hi, i would like to connect…” or something, in the same way as linkedin.

We can warn the user not to disclose any sensitive information in a contact request, and reinforce the message by a visual indicator, but I know nothing about UX :slight_smile:

This would be a nice place to tell the user B how user A found him (public chat, QR code, etc), and what type of address it used (contact code, public key, ENS).

1 Like

+1, I think we should keep the scenarios as simple and secure as possible, especially given that we have further avenues to explore in the future to reduce the possibilities for X3DH bundles to be missing.

RE: Basically in such cases it’s ok to include a “introduction message”, but it needs to be clear to the user that it is not a “message” and it’s a “contact request”, so it’s easier to explain that we guarantee PFS for messages but not for contact requests.

I was thinking something like below where we could have the initial message from A included in the connection request but the modal clearly asks for User B to accept of deny the request. There are a lot of caveats here - e.g. should we use a system modal or if this request should take place somewhere else but this is one possibility.

In such cases we could also use the Add to contacts snackbar in the same as we have now (basically on user B no changes are required to the flow)

Ok seems like there is some consensus, the plan would be then:

  1. When a user wants to send a contact request to someone who they haven’t messaged before, they will be shown a new screen, inviting them to send a single message (potentially pre-filled with some default text). We can add two buttons Cancel and Send. There will be a disclaimer not to disclose any information etc.

  2. If a secure channel has been established there will be some lock icon/ visual indicator in the chat and the user will be able to send messages at will

  3. If a secure channel has not been established, there will be some lock icon/visual indicator in the chat and the input box will be disable/replaced with a prompt to send/re-send a contact request instead

  4. On the receiving end everything could work as now (we would add the lock icons/visual indicators), and we could change/polish at later stages. Contact request messages will be displayed in the chat, possibly with a different text/font so it’s clear it’s a contact request message.

What do you all think? Let me know and I can get the ball rolling

Regarding 4, I would prefer replacing the snackbar with a couple of buttons inside a contact request message bubble (Accept/Reject). wdyt?

@pedro I thought about this, the only thing that is tricky is the fact that user can delaying accepting the contact request, and maybe send x messages, at that point the contact request will only be shown at the top of the chat, making it difficult for the user to accept at a later stage.

Has anyone tried to write a message to someone who is not in your contact list on Linkedin? (Facebook has changed this logic btw, you can write to anyone and your message will pop up in the receiver’s list)
It’s tough! You have to include a welcome message, how do you know this person and something else. From my point of view it creates a big friction. Can it work like this? Is it possible to send a message through unsecure channel?

Is it possible to send a message trough unsecure channel?

It is, it would be the same as now, but I think we should not allow users to do so, otherwise we can’t really guarantee PFS for all messages and would give a user a false sense of security.

If we use an introduction message, than it’s much easier to explain to the user. “We guarantee pfs on all messages, we don’t guarantee pfs on contact requests”.

Mind that this scenario is only required when user does not have a contact code and use a public key (which we will actively discourage), or ENS (in which case we will eventually cover this scenario as well, at least for stateofus.eth)

I actually like the idea of including the buttons inside the message, I’d go with it. Even if the message is scrolled away it’s because of user action so it’s not like he won’t know about it.


Thanks @maciej looks good to me,
@Chad are we ok with this? If so I will start working on it.

I can’t get rid of the snackbar though, as otherwise there would be no way to add a contact back if you haven’t received the contact request, that’s maybe something to think about in the future.

Yes looks good!

@hester and @Patrick might have some thoughts?

Here’s the design file I use, you can also leave your comments directly there

looks good! My question would be: what does Chad see as long as the contact request has not been accepted.

Aside from this, I think this approach could help clarify the distinction between Start new chat and Invite friends, which is very vague.

Agree that these look good, thanks Maciej!

Maybe to play devil’s advocate and suggest considering some final points before getting too deep in implementation. If we accept that the best the UI is no UI and @cammellos you mention in your first post

I personally feel that 2 sounds the most reasonable given that it should impact only a few cases and can be improved incrementally by adding more ways to establish a secure channel without user interaction.

Should we consider waiting for ENS to go live? And what would be the next phase/steps for those incremental improvements to establish secure channels without interactions? Do we need to go through these steps of establishing a secure connection via modal dialogues to get to a point we where don’t need them - i.e. will we always have the case where you can be contacted via public key?

I’m basically just double-checking that we aren’t signing up for building a UX that might not need to be there 6-12 months from now.

Final point, can we build in some time here to user test some different versions of the flow (if necessary) such that @cammellos has time to adjust if needed.