Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions proposals/4529-profile-overrides.md

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation requirements:

  • Client (setting)
  • Client (showing)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

So, I need implementation in a client before this proposal has the possibility of being merged?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@nvnvnvnvnvnvnv yes:

This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP.

Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# MSC4529: Client-side profile overrides

People are often known by names they don't choose for themselves. A user may want to see "Mum"
rather than "Sarah", to tell apart two colleagues who both call themselves "Alex", or to keep a
familiar name for a contact who has renamed themselves to something unrecognisable. Pictures matter
for the same reason. A user is often picked out of a timeline by their avatar before their name is
read, but many people set no avatar at all, leaving rows of identical placeholders, and others use
an image shared with a dozen people or one that changes every week. Giving somebody a picture, as an
address book does with a contact photo, is as useful as giving them a name, and it survives their
next change.

Address books and other chat apps let their user relabel a contact privately. Matrix has no
equivalent. A user can change their own profile, but not how somebody else appears to them. Clients
offering this feature today must store the labels locally, so they are lost on reinstall and never
reach the user's other devices.

This proposal introduces an account data event in which a user records the profile fields they wish
to see in place of the real ones, facilitating the usage of private labels between the user's clients.

## Proposal

A new global account data event `m.profile_overrides` is introduced. In `content`, it maps user IDs
to objects of profile field names and the values to display for them:

```json5
{
"type": "m.profile_overrides",
"content": {
"@sarah:example.org": {
"displayname": "Mum"
},
"@alex:example.com": {
"displayname": "Alex (accounting)",
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
// Fields set to null are displayed as though absent
"m.tz": null
}
}
}
```

The field names are those of the [profile](https://spec.matrix.org/v1.18/client-server-api/#profiles):
`displayname`, `avatar_url`, `m.tz`, and any other extended profile field. A value MUST have the
type that field would have in a real profile, except that `null` means the user has no value for
that field. Clients MUST ignore entries whose key is not a valid
[user ID](https://spec.matrix.org/v1.18/appendices/#user-identifiers) and fields whose value is of
the wrong type, which leaves room to extend the event later. To remove an override, remove its key.
Clients SHOULD drop a user's entry rather than leave an empty object behind.

The [`m.profile_fields`](https://spec.matrix.org/v1.18/client-server-api/#mprofile_fields-capability)
capability restricts which fields a user may change in their own profile. It does not constrain
overrides. An override is never sent to the server as profile data, so a client MAY override any
field, including one the server manages on the overridden user's behalf.

Where a client displays a profile field for which an override exists, it SHOULD display the override
in place of the value it would otherwise use, whether that came from the user's profile or from an
`m.room.member` event. This applies in every room and everywhere a profile is shown, including
[room names and avatars](https://spec.matrix.org/v1.18/client-server-api/#calculating-the-display-name-for-a-room)
derived from members.

A user may set a different display name and avatar in each room, and an override replaces all of
them. This is intended. Overriding a user's profile is a choice to see them the same way wherever
they appear, and that uniformity is the point of the feature.

Overrides MUST NOT affect anything the client sends. The text of a
[mention](https://spec.matrix.org/v1.18/client-server-api/#user-and-room-mentions) or reply
fallback, and all other outgoing content, MUST use the real profile, so that a private label is
never revealed to the room.

Clients [disambiguate](https://spec.matrix.org/v1.18/client-server-api/#calculating-the-display-name-for-a-user)
colliding display names by appending the user ID. A client MAY treat an overridden name as
unambiguous, since the user chose it themselves, provided the real user ID remains discoverable
elsewhere, such as on the user's profile view.

This is a client-to-client mechanism carried over the existing
[account data](https://spec.matrix.org/v1.18/client-server-api/#client-config) endpoints; servers
need no knowledge of this proposal.

## Potential issues

The event is rewritten in full for every change, so simultaneous edits from two clients can lose one
of them. This is the same race [`m.direct`](https://spec.matrix.org/v1.18/client-server-api/#mdirect)
has, and is tolerable for the same reasons: such writes are rare and user-initiated. A user with
many overrides also ends up with a large event. Each entry is bounded by the limits the
specification already places on a profile, 255 bytes per key and 64 KiB for the profile as a whole,
so the event grows with the number of users overridden rather than without limit. In practice the
feature is used for a handful of users at a few dozen bytes each.

An override is a snapshot and does not track later changes to the real profile. That is largely the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Considering for names, pfps and per-room colors, a user would likely see them still as most clients show m.room.member changes by default so this would likely be less of a potential issue than this would anticipate

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, they would be shown in timeline, but would be less obvious to you I suppose. I don't see it as a meaningful problem either.

point, but it does mean a user will not notice when the underlying name changes.

Clients that do not implement this proposal display real profiles, which is a safe degradation,
though a user running two clients may then see different names in each.

## Alternatives

Clients could continue to store overrides locally, as they do today. This needs no specification,
but the labels are lost on reinstall and do not reach the user's other devices, which is the problem
being solved.

One event type per overridden user, such as `m.profile_override.@alice:example.org`, would avoid the
read-modify-write race and allow a single override to be updated in isolation. It also embeds a user
ID in an event type, which is unlike anything else in the specification, and gives up the ability to
enumerate overrides. The race does not seem serious enough to justify that.

[MSC3015] and [MSC4431] apply the same idea to room state, storing personal overrides as room
account data whose content mirrors the state event being overridden. [MSC3015] is generic, keying
the account data on `override.` followed by the state event type, so any state event could in
principle be overridden; it proposes to gate this behind an allowlist of `m.room.name`,
`m.room.avatar`, `m.room.topic` and perhaps `m.room.pinned_events`. [MSC4431] covers room names
alone, as `m.room.name.private`. They personalise *rooms*, where this proposal personalises *users*,
and neither supersedes the other. A client may implement any of them alone or all of them together,
and a user may reasonably want a private name for a room and a private name for a user at the same
time. [MSC3015] even lists `m.room.member` among the state types its allowlist could
admit, but defers it pending the extensible profiles of [MSC1769], so the two fit together directly.

This proposal does not extend either to `m.room.member`, because a profile is not room state. A room
has a natural per-user container in its room account data; a user has none. Per-room storage would
therefore repeat each override in every room shared with that user, need a further write on joining
another, and leave the same user labelled inconsistently wherever a copy was missed. `displayname`
and `avatar_url` belong to the user rather than to any room, and extended profile fields such as
`m.tz` have no room state to mirror at all. A single global map keyed by user ID
follows the shape of the thing being overridden, and leaves room-level personalisation to the
proposals above.

Finally, servers could rewrite profiles before serving them, which would extend the feature to
clients that do not implement it. That would require every server to participate. It would also hide
the real profile from clients that need it, such as when composing a mention, and put a
presentational concern in the server.

## Security considerations

The user's homeserver can read their account data, so the labels they choose are visible to a server
administrator, and a label like "therapist" or "work" gives away plenty. Clients SHOULD NOT present
the feature as private from the homeserver. The overridden user learns nothing: nothing is sent to
them and no room state changes.

## Unstable prefix

While this MSC is not considered stable, `m.profile_overrides` should be referred to as
`org.matrix.msc4529.profile_overrides`. Clients SHOULD prefer the stable event type where both are
present, and may use it as soon as this proposal is accepted, since no feature negotiation is
involved.

## Dependencies

None.

[MSC1769]: https://github.com/matrix-org/matrix-spec-proposals/pull/1769
[MSC3015]: https://github.com/matrix-org/matrix-spec-proposals/pull/3015
[MSC4431]: https://github.com/matrix-org/matrix-spec-proposals/pull/4431
Loading