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

WIPish: MSC1769: Extensible profiles as rooms #1769

Draft
wants to merge 5 commits into
base: old_master
Choose a base branch
from
Draft
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
152 changes: 152 additions & 0 deletions proposals/1769-extensible-profiles-as-rooms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Proposal for extensible profiles as rooms
Copy link
Member Author

Choose a reason for hiding this comment

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

@remram44 downvoted this, so i asked for clarification via Matrix on the rationale:

It probably simplifies some of the machinery but is very awkward from a API user stand point. I would have to treat that room differently anyway. It also makes it impossible to ask the server to return some of that info directly, I'd always have to peek that special room.
but the ACLs also make it too easy to break all of this. What if the room alias already exists? What if it's not readable to me? What if it's writable?
Most of the room machinery don't apply
I don't know what the situation is like for server implementors though.

To respond to this:

I would have to treat that room differently anyway

Not necessarily. If the room is used as the social feed for that user (as proposed in the Client Behaviour section below), clients could fell treat it as a real "Remram's Wall" style room - as well as it providing the additional profile state events about him. Even if that doesn't happen, it's just a simple filter to hide the room from the roomlist, and one which we are already doing trivially for things like VoIP conference rooms. There are also enough other cases where entities can be modelled elegantly as rooms without reinventing the wheel (e.g. groups; #1772) that the idea that we have rooms flying around which aren't normal chatrooms is probably inevitable. Likewise as more IOTish rooms start appearing which you may not want to see in your IM client's roomlist.

It also makes it impossible to ask the server to return some of that info directly, I'd always have to peek that special room.

This much is true. It's a trade-off between implementing a custom API specifically for querying profiles, versus (ab)using the peek API.

but the ACLs also make it too easy to break all of this

Not so sure about that. ACLs are a feature here. If you don't want someone to see your profile, then lock down who can access that room. It's very much a feature rather than a bug.

What if the room alias already exists?

We already have the ability to reserve chunks of alias namespace for stuff like that, and the spec already says that anything that begins with #_ should be preserved for magic rooms (i think/hope).

What if it's not readable to me?

Then that user has hidden their profile from you.

What if it's writable?

Then that user lets people respond to stuff written on their wall.

Most of the room machinery don't apply

I'd argue that the sync mechanisms, peeking mechanisms, ACLs, extensible key/value storage, and conversation history all apply.

I don't know what the situation is like for server implementors though.

With my server implementor hat on, i would be overjoyed that this proposal opens up a path to hosting extensible profiles without having to write a single line of server code (other than making peeking work over federation, which is desired anyway).

Copy link
Contributor

Choose a reason for hiding this comment

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

As this MSC should be blocked by #1840 unless we want clients to have to have hacky work-arounds / fixes forever, either this MSC should be changed to kind:feature or that MSC to kind:core

Copy link
Member

Choose a reason for hiding this comment

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

A potential problem with this MSC is disclosing the age of an account: servers would likely have to create this nearly at the time of registration, making it easy to determine when an account was created.

I don't believe there's anything particularly wrong with disclosing this information, though it does feel wrong to have it advertised. On the other hand, it could also help power features like Stack Overflow's "this person is new, be nice" warning bar.

Choose a reason for hiding this comment

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

No. Profile rooms should be created on client request, and it should be allowed to have profile-less users (or users with multiple profile rooms).

Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure if I am just not finding it in the MSC or if it is missing, but what are the Powerlevels of these rooms supposed to be? Admin only for everything? Since the profile room I guess should only get changed by the creator of the room or am I wrong on that assumption?


## Problem

Profiles are currently limited to display names and avatars. We'd like users to
be able to publish arbitrary data about themselves instead (in a relatively
vcard-compatible fashion).

## Solution

Rather than creating a whole new set of APIs for defining and synchronising
profiles, the proposal is to simply put the data as state events in a room and
leverage all the existing infrastructure we have for sending and receiving state
events.

Clients should construct the default alias of the profile room is constructed as
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure this sentence came out the way it was supposed to

Copy link
Member

Choose a reason for hiding this comment

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

indeed

Suggested change
Clients should construct the default alias of the profile room is constructed as
Clients should construct the default alias of the profile room as

`#@userid:<server>` (assuming aliases allow @; if not, `#_profile_userid:<server>`.

Choose a reason for hiding this comment

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

Suggested change
`#@userid:<server>` (assuming aliases allow @; if not, `#_profile_userid:<server>`.
`#@<userid>:<server>` (assuming aliases allow @; if not, `#_profile_<userid>:<server>`.

to better capture that userid here is not a literal.

The server in the alias is that of the user whose profile is being considered.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like that format, it looks more like a typo IMO.

Copy link

@gleachkr gleachkr Apr 15, 2021

Choose a reason for hiding this comment

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

Here's another worry about the default alias scheme, from a discussion on #matrix-spec.

So, as I read this, a user with a userid @<mylocalpart>:<myserver> is supposed to have a default room profile alias of #@<mylocalpart>:<myserver> or #_profile_<mylocalpart>:<myserver>.

But userids are limited to 255 characters (in a subset of us-ascii, so assuming utf-8, 1 byte per character), while room aliases are limited to 255 bytes. So a 255 character userid, prefixed with # and utf-8 encoded will produce an invalid room profile alias.

Perhaps this could be avoided by only exposing room profiles via the profile field in m.room.member?


This may be overridden per-room by setting a `profile` field in the
`m.room.member` for the user. (Once we remove MXIDs from rooms in
[MSC1228](https://github.com/matrix-org/matrix-doc/issues/1228) then this
becomes irrelevant, as each user will get its own profile room alias for each
room it is in. That user would typically choose to point all those aliases at
the same underlying profile room).
jcgruenhage marked this conversation as resolved.
Show resolved Hide resolved

This does not replace the current `displayname` and `avatar_url` field behaviour
on `m.room.membership` events which we have today.

This proposal is an alternative to [MSC489](https://github.com/matrix-org/matrix-doc/issues/489).

## Client behaviour

When a client loads a membership info page for a given user, it peeks into that
user's profile room in order to inspect their current profile state events.

N.B. This requires the peeking API to be improved from the legacy stopgap of using
/events. One solution could be to pass /sync a list of additional rooms to attempt
to sync data for (somewhat as per the paginated /sync API did in
https://github.com/matrix-org/synapse/pull/893). Defining this is left as a
separate MSC ([MSC1776](https://github.com/matrix-org/matrix-doc/issues/1776))

N.B. This also requires peeking to work over federation. One simple solution to
this could be to require servers to join remote rooms they need to peek into
usinga null user - e.g. @:server or @null:server. This would avoid having to
Copy link

Choose a reason for hiding this comment

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

Suggested change
usinga null user - e.g. @:server or @null:server. This would avoid having to
using a null user - e.g. @:server or @null:server. This would avoid having to

create a new membership event type for servers and complicate state auth/res
rules. Again, defining this is left as a separate MSC.
([MSC1777](https://github.com/matrix-org/matrix-doc/issues/1777))

The same peeking could also be used to display message events in the user's
Copy link
Contributor

@Half-Shot Half-Shot Jan 29, 2019

Choose a reason for hiding this comment

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

It's not clear to me if we are dropping the /profile endpoints, or simply making them helpers?

The endpoint will update all the member states in all the rooms for a user if they update their profile, so presumably that has to still be triggered when updating this room? Unless we are dropping profiles in member events, in which case I'd like to know how we plan to keep support for custom nicks per rooms as they are extremely useful for bridging things like discord.

Choose a reason for hiding this comment

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

It's not clear to me if we are dropping the /profile endpoints, or simply making them helpers?

How to make /profile work with zero or multiple profile rooms?

profile room - the equivalent of their social network profile wall.

## Events

### m.profile

This would store a vCard-style profile of the user.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the rationale of blobbing all the profile in one state event rather than splitting out the types?

If I have a large profile, surely updating my displayname requires me to pull the whole event, change a value, then push it again which is going to be a rather large load in terms of the whole network. If the intention was to keep displayname and avatar as their own types, can that be added as an example?

Copy link
Member

Choose a reason for hiding this comment

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

Tbh I thought this proposal reused existing state events where it made sense. Not really a fan of vcards-as-state.

Copy link
Contributor

Choose a reason for hiding this comment

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

Given we have a rich typing system already, I am failing to see the advantage of doing a single event inside content. The only advantage I can see is a single request to pull the state, but surely the calling client knows what types it wants, and should just ask for what it needs. Alternative it can call /state and find out what types are supported.

Copy link

Choose a reason for hiding this comment

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

On the other hand profiles probably change relatively rarely. So bunching up a lot of data into a single event may be beneficial for memory usage and retrieval overhead. It makes the updates more expensive but the steady-state cheaper.

There is also an advantage of using a standard format that probably already has clients in numerous languages and allows interop. For example imagine that a client wants to implement "Add user to your address book" feature. Now this client is going to implement this Matrix -> vCard conversion mostly correctly for a subset of fields. If we natively support some sort of vCard, or well-known vCard conversion (like jsContact) this can be delegated to a dedicated library which hopefully has quite good support.

Furthermore if we are concerned about updates to big events maybe we can specify a general patch event in the future. However for just contact data (with the image broken out into the regular avatar) I don't think we need it anyways.

I was originally on the side of breaking it up but eventually I decided that the benefits of a standardized format is probably worth it.

Copy link

@erkinalp erkinalp May 24, 2021

Choose a reason for hiding this comment

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

Suggested change
This would store a vCard-style profile of the user.
This would store a vCard-style profile of the user, optionally including a user alias, as specified by
the `user_alias` field under `name`. A user alias shall function similarly to the user display names
we currently have and replace them, except it shall be optional, meaning each user and each profile
shall have zero or more user aliases.

Copy link
Contributor

Choose a reason for hiding this comment

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

I do think it's reasonable to do it this way (replacing the display names from the member events), but I think we should stick to the already standardised names for vCards, which would make these nicknames, and not user aliases.

Choose a reason for hiding this comment

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

The difference lies within details. Usernames are 1:1, nicknames are 1:N, and user aliases will be M:N. Meaning, multiple (1+) users will be able to share the same profile and alias; and a user will be able to have multiple (0+) aliases.

Copy link
Member

Choose a reason for hiding this comment

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

Uhm, nicknames are not 1:N. There are multiple people who share the same nickname, and people can have more than one nickname, so nicknames are M:N.


In the absence of a jsCalendar style format for expressing vCards as idiomatic
Copy link
Contributor

Choose a reason for hiding this comment

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

There actually is a JSCalendar style RFC for an idiomatic JSON representation of vCards now: JSContact, by the same authors. Not yet as far as JSCalendar already is, but seems like the way to go.

JSON (rather than as a parse tree of the vCard data, as jCard does (RFC7095)),
it could be something like this:

```json
{
"type": "m.profile",
"content": {
"m.profile": {
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the need of "m.profile" inside "content"?

Copy link
Member Author

Choose a reason for hiding this comment

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

"name": {
"family": "Gump",
"given": "Forrest",
"additional": "",
"prefixes": "Mr.",
"suffixes": ""
},
Comment on lines +68 to +74

Choose a reason for hiding this comment

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

Suggested change
"name": {
"family": "Gump",
"given": "Forrest",
"additional": "",
"prefixes": "Mr.",
"suffixes": ""
},
"name": {
"family": "Gump",
"given": "Forrest",
"additional": "",
"prefixes": "Mr.",
"suffixes": "",
"user_alias": "mrgumpforest"
},

Copy link
Member

Choose a reason for hiding this comment

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

What is a user_alias? This is not defined anywhere in Matrix or in this MSC. Again, you are making a suggestion without providing sufficient context, and making us try to figure out what you're talking about.

Choose a reason for hiding this comment

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

Added the definition for user alias, as a suggested change.

"fn": "Forrest Gump",
"org": "Bubba Gump Shrimp Co.",
"title": "Shrimp Man",
"tel": [
{
"type": [
"work", "voice"
],
"uri": "tel:+1-111-555-1212"
},
{
"type": [
"home", "voice"
],
"uri": "tel:+1-404-555-1212"
}
],
"address": [
{
"type": [
"work"
],
"pref": 1,
"label": "100 Waters Edge\nBaytown, LA 30314\nUnited States of America",
"pobox": "",
"extended": "",
"street": "100 Waters Edge",
"locality": "Baytown",
"region": "LA",
"postcode": "30314",
"country": "United States of America"
},
{
"type": [
"home"
],
"label": "42 Plantation St.\nBaytown, LA 30314\nUnited States of America",
"pobox": "",
"extended": "",
"street": "42 Plantation St.",
"locality": "Baytown",
"region": "LA",
"postcode": "30314",
"country": "United States of America"
}
],
"email": "[email protected]",
"rev": "20080424T195243Z"
}
}
}
```

Representing:

```vcard
N:Gump;Forrest;;Mr.;
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
PHOTO;MEDIATYPE=image/gif:http://www.example.com/dir_photos/my_photo.gif
TEL;TYPE=work,voice;VALUE=uri:tel:+1-111-555-1212
TEL;TYPE=home,voice;VALUE=uri:tel:+1-404-555-1212
ADR;TYPE=WORK;PREF=1;LABEL="100 Waters Edge\nBaytown\, LA 30314\nUnited States of America":;;100 Waters Edge;Baytown;LA;30314;United States of America
ADR;TYPE=HOME;LABEL="42 Plantation St.\nBaytown\, LA 30314\nUnited States of America":;;42 Plantation St.;Baytown;LA;30314;United States of America
EMAIL:[email protected]
REV:20080424T195243Z
```
Comment on lines +130 to +142
Copy link

Choose a reason for hiding this comment

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

Why not just this? Is the intention just avoiding clients from needing a vCard parser? Either way it probably makes sense to list this in an "Alternatives" section with some pros and cons.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think going with jCard (standardised json variant of vCard) instead of vCards would be a slightly better fit, but other than that I agree that we shouldn't replicate this into our own data structure


The avatar would be split out into a normal Matrix avatar (or perhaps an `m.avatar`
room profile event).

Internationalisation could be done using "lang" keys, as per MSC1767.

Copy link
Member

Choose a reason for hiding this comment

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

One potential issue with profiles as rooms is that you lose the ability to display old profile information in the timeline. No longer would a change to a field in your profile room directly correspond to a point in the timeline of another room.

Thus if you had a "job title" field in your profile room, and your client was configured to show that field's value next to messages from users in rooms, you wouldn't be able to definitely decide for a given message whether to use the old or new value.

That may not be that big a deal though. You could just make it loosely work by comparing origin_server_ts between events across rooms.

Choose a reason for hiding this comment

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

users may also not necesarrily want old profile information in the timeline

Choose a reason for hiding this comment

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

Good points. They only way is to capture causality between your profile events and "interaction" (e.g., message) events.

Also, given you sign messages with a key managed in your profile, "anchoring" the message into profile is what proves it's authentic, persistent across key rotations.

### Other events

Other events could be custom data, using the normal fallback representations from
MSC1767 to determine fallbacks (m.text, m.html, m.message, m.thumbnail etc).