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

MSC4144: Per-message profiles #4144

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
145 changes: 145 additions & 0 deletions proposals/4144-per-message-profile.md
Copy link
Member

Choose a reason for hiding this comment

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

Implementation requirements:

  • Client sending avatars
  • Client using avatars

Choose a reason for hiding this comment

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

Implemented in Honoroit - helpdesk bot will send an unstable MSC4144 profile for each message in operators' room by default

Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# MSC4144: Per-message profiles
Currently profiles in Matrix are defined by `m.room.member` state events, and
there is no easy way to have different profiles per message.

## Proposal
The proposed solution is a new field called `m.per_message_profile`, which
contains a displayname and/or avatar URL to override the default profile,
Copy link

@bkil bkil Nov 24, 2024

Choose a reason for hiding this comment

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

We should provide guidance about the maximal length of each new field such as id and displayname.

Copy link

Choose a reason for hiding this comment

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

It would align with the present spec to state that

  • the size of id MUST NOT exceed 255 bytes
  • the size of displayname MUST NOT exceed 255 bytes

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah for ids 255 bytes sounds right. Not entirely sure about the character set as user ids are quite messy currently (and it'd be nice to allow anything that can be in a matrix user id). Displaynames don't currently have any byte limits though

Copy link

Choose a reason for hiding this comment

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

Both of them could be any arbitrary UTF-8 string. Why would you want to restrict it if you already state that id is opaque? Clients are already expected to properly sanitize and wrap it for their own rendering.

Including a 64kB displayname in each reply sounds excessive. I'd rather we had a recommendation for how to shorten it (i.e., cut it properly on a UTF-8 boundary before reaching 256 bytes and ideally trimming whitespace at its edges).

Copy link

Choose a reason for hiding this comment

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

I would mention a suggestion that if the protocol and router discriminant, delimiter and the remote user ID together would exceed 255 bytes so it can't fit in the
id, hashing should be used (and the discriminant should be adjusted to specify this in this case). You can always find a protocol that allows just a little longer IDs than you have anticipated, or there's the simple case of cascading such relays by independent parties, increasing the length of each ID by just a little bit on every hop. 256 bits of entropy is usually considered good enough for a UUID and that fits within 43 characters of unpadded base64 or 64 characters of hex, so it should still leave plenty for further metadata. E.g.,

  • For the user @nick42:matrix.example, the id could be mx1-mxid:@nick42:matrix.example
  • For a user with an excessive remote ID (@too_long_name@matrix.example), this could be mx1-hash:04b9becd1c9306453d9aa80033a8a70fe9bd4c64989a06b470bc46ef6b8154c7

plus an ID to identify different profiles within the same Matrix user.
tulir marked this conversation as resolved.
Show resolved Hide resolved

Copy link

Choose a reason for hiding this comment

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

I would like to propose a new field to forward the remote username or nickname in.

  • The id can be either randomly generated or a decimal sequence number, but it is definitely not something that I would expect to be prominently displayed in a client. Incidentally, the mxid serves this purpose on Matrix internally.
  • The nickname is a short word that is quick to type in when we want to @-mention another member. Usually the localpart of the mxid acts as a poor substitute on matrix right now.
  • Not all platforms support a display name, but where they do, it may contain the full, long personal name including spaces, pronouns, affiliations, position, emoji, etc. Many platforms also autocomplete for this when @-mentioning another user.

Copy link
Member Author

Choose a reason for hiding this comment

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

There's currently no mention support here, but that might make sense if mention support is added. Not entirely sure if it should be in this MSC or a separate one (the feature can be neatly separated from the rest of the MSC and it requires modifying the matrix.to/matrix: URI spec)

Copy link
Member Author

Choose a reason for hiding this comment

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

Leaning towards defining mentions to be out of scope here

Copy link

Choose a reason for hiding this comment

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

It can still be useful without support for mentions. For example, extant Matrix clients fall back to also showing the mxid (that can not clash) in case of a display name clash in a given room. Similarly they may want to fallback to the remote account name (remote nickname) when the remote display name clashes.

```json
{
"msgtype": "m.text",
"body": "Hello, World!",
"m.per_message_profile": {
"id": "meow",
"displayname": "cat",
"avatar_url": "mxc://maunium.net/hgXsKqlmRfpKvCZdUoWDkFQo"
}
}
```

The `id` field is required and is an opaque string. Clients may use it to group
messages with the same ID like they would group messages from the same sender.
For example, bridges would likely set it to the immutable remote user ID.
clokep marked this conversation as resolved.
Show resolved Hide resolved
tulir marked this conversation as resolved.
Show resolved Hide resolved
tulir marked this conversation as resolved.
Show resolved Hide resolved

### Encrypted avatars
Because the profile is inside the ciphertext in encrypted events, the entire
profile can be hidden the server, as long as the avatar is also encrypted.
tulir marked this conversation as resolved.
Show resolved Hide resolved
Encrypted avatars are placed under `avatar_file` instead of `avatar_url`.
The `avatar_file` field has the same schema as the `file` field in
`m.room.message` events.

<details>
<summary>Encrypted avatar example</summary>

```json
{
"msgtype": "m.text",
"body": "Hello, World!",
"m.per_message_profile": {
"id": "meow",
"displayname": "cat",
"avatar_file": {
"v": "v2",
"key": {
"alg": "A256CTR",
"ext": true,
"k": "8dXeBMBMthuXGY5zmUh9Mi0aqC1kndMZ4NCa-0RhELc",
"key_ops": [
"encrypt",
"decrypt"
],
"kty": "oct"
},
"iv": "L6zup2cR570AAAAAAAAAAA",
"hashes": {
"sha256": "/cTs+PajUcznbV3h1w5gh1AHnLjrKQVl2jU3xLCqoBI"
},
"url": "mxc://maunium.net/eKLhozQduElYSgBkWjtwSXoi"
}
}
}
```

</details>

### Behavior of omitted and empty fields
If the `displayname` field is omitted, null, or an empty string, the
displayname from the member event should be used instead. Setting an empty
displayname using a per-message profile is not supported, as there aren't any
clear use cases for it.

However, there are use cases for setting an empty avatar, so `avatar_url` being
an empty string should be treated as clearing the avatar and falling back to
the client's default blank avatar behavior (e.g. generating one based on the
displayname). If both `avatar_url` and `avatar_file` are omitted or null, the
avatar from the member event should be used instead.
tulir marked this conversation as resolved.
Show resolved Hide resolved

### Extensible profiles
This MSC is not related to extensible profiles and does not attempt to
implement them. However, in case extensible profiles are implemented as
something that can be referenced (e.g. room IDs), the MSC adding them could
allow per-message profiles to specify which extensible profile is used.

## Use cases

### Bridging
Per-message profiles will allow making "lighter-weight" bridges that don't need
appservice access. Currently the only option for such bridges is to prepend the
displayname to the message, which is extremely ugly. Even though they're ugly,
there are still rooms that use bot-based bridges like matterbridge, which shows
there's demand for bridging without requiring server admin access.

Such bridges would obviously have downsides, like not being able to start chats
via standard mechanisms, and not being able to see the member list on Matrix.
However, those may be acceptable compromises for non-puppeting bridges that
only operate in specific predetermined rooms.
tulir marked this conversation as resolved.
Show resolved Hide resolved

tulir marked this conversation as resolved.
Show resolved Hide resolved
This method also allows encrypting profile info, which reduces metadata leaked
by bridging.

### Feature-parity with other platforms
Other chat applications such as Slack and Discord have "webhooks" which allow
per-message profile overrides. This MSC effectively enables the same on Matrix.
clokep marked this conversation as resolved.
Show resolved Hide resolved

For example, Discord's [execute webhook](https://discord.com/developers/docs/resources/webhook#execute-webhook)
API takes `username` and `avatar_url` as optional parameters.

### Roleplaying, plural users, etc
Some users want to be able to switch between profiles quickly, which would be
much easier using this MSC. Currently easiest way is to have multiple accounts,
which has other benefits, but is much more cumbersome to manage.

## Potential issues
Implementing encrypted avatars could cause difficulty for clients that assume
that avatars are always unencrypted mxc URIs.

tulir marked this conversation as resolved.
Show resolved Hide resolved
tulir marked this conversation as resolved.
Show resolved Hide resolved
## Alternatives
tulir marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

Reminds me of MSC3464. This is more general than that MSC, though.

### New state events
Per-message profiles could be transmitted more compactly by defining the profile
in a new state event and only referencing the state key in the message event.
However, that approach wouldn't enable encrypting per-message profiles without
inventing encrypted state events. Additionally, even with encrypted state
events, some kind of sender identifiers would be leaked via state keys.

### Appservices
Appservices work perfectly fine for bridging already now, but they require
admin access to a server, which is not available for everyone. Additionally,
they have similar metadata issues as the "New state events" alternative above.

For use cases involving a single human user, having multiple mxids (regardless
of whether they're registered manually or via an appservice) complicates things
unnecessarily.

## Security considerations

### Preventing impersonation
To prevent impersonation using per-message profiles, clients should somehow
indicate to the user that the message has a per-message profile with an easy
way to see the user's MXID or default profile. For example, a client could have
a small `via @user:example.com` text next to the per-message displayname.

Copy link

Choose a reason for hiding this comment

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

User experience could be greatly improved in a room with mostly remote messages if this source disclaimer could be hidden (or only shown when clicking on the avatar) if all of the following conditions are met:

  • The event sender is a moderator (e.g., has permission level for redaction or a new level)
  • The impersonated user is not a member in the room

Copy link
Member Author

Choose a reason for hiding this comment

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

I've added that now, but there's also 2 new todos to figure out the power level to use and whether anything needs to be done about multiple bridges where the remote users have conflicting displaynames

## Unstable prefix
`com.beeper.per_message_profile` should be used instead of `m.per_message_profile`
until this MSC is accepted.