Skip to content

Instantly share code, notes, and snippets.

@DMRobertson
Last active September 1, 2021 16:22
Show Gist options
  • Save DMRobertson/2a6b2a0453daec29831d0e99156e1e3f to your computer and use it in GitHub Desktop.
Save DMRobertson/2a6b2a0453daec29831d0e99156e1e3f to your computer and use it in GitHub Desktop.
Plan for matrix-org/synapse#5677 part 2

Scenario

Aiming to solve matrix-org/synapse#5677.

Follows on from matrix-org/synapse#10695.

We're running our own homeserver with users Bob and Eve. A remote user Alice is already in a public room on her own homeserver. Bob on our homeserver joins it. Alice and Bob then make a private room. Within it, Alice changes her name to Delia.

Eve should be able to see Alice in the directory, but only by searching for Alice's public identifiers: her mxid and her username. Synapse today will populate the directory with the last displayname and avatar it sees for that user. In particular, if Eve searches for Alice's mxid, the returned displayname will be "Delia". That's a leak of information that Eve isn't privy to.

The problem is that we (the homeserver hosting Bob and Eve) has absolutely no idea what Alice's "public" identifiers are. There are no guarantees that the first join event sets the display name and avatar to match Alice's "public" one. (By public I mean the thing returned by GET /profile/userid.)

So short of protocol changes (e.g. "profiles as rooms") we need to contact Alice's homeserver to ask what her "public" profile is.

Plan

When someone remote joins a room, or when they send an event changing their displayname or avatar:

  1. if we've never seen this person before, add a user_directory entry with displayname set to their mxid

  2. if their displayname in the event doesn't match what we have in the user_directory, then queue up a request to their homeserver to retrieve their profile

  • on success, update their user_directory entry based on the response
  • on failure, requeue up to $RETRY_ATTEMPTS with $DELAY and exp. backoff
  • if all retries fail, give up

Note: Erik says the federation http client has some retry handling and "this server is well dead" handling built-in.

When someone remote leaves a room:

  1. if they're no longer in any rooms that we can see, remove their user_directory entry

When this homeserver leaves a room:

  1. Check all remote members in that room. If they're no longer in a room we can see, remove their user_directory entry.

Deduplication

If I change my name in N rooms shared by an average of M homeservers, I'm going to send out NM events altogether, which will trigger NM profile requests to us from M homeservers. This is sad. We want each homesrver to be able to spot multiple room displayname updates occurring in quick succession, and only send out one GET /profile request each.

To do this:

  • for each mxid in the queue, remember the last displayname we saw them change to
  • only enqueue another request if an event comes in with a different displayname
  • use a "lineariser" (???) to do... stuff?

Races?

It's possible we receive the response to GET /profile/@user:remote after they have left all rooms we see (or after we've left all rooms they're in). Then we'll have removed their entry from the user_directory. In this situation, discard the response. (Suggest doing a SQL UPDATE ... WHERE which updates either 0 or 1 rows.)

Persistence and Resliience

DEFER TO LATER. Worst case we have out-of-date info in the directory.

If the server restarts after it's fired off a request but before it's received a response, then we'll not see the latest profile for the remote user. We could augment or add a table to track which remote users need their profiles retrieving/confirming. Use this to pre-populate the request queue at startup. On a successful request, remove them from this table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment