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

MSC4201: Profiles as Rooms v2 #4201

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
264 changes: 264 additions & 0 deletions proposals/4201-profiles-as-rooms-v2.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:

  • Server
  • Client

Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
# MSC4201: Profiles as Rooms v2

- [MSC4201: Profiles as Rooms v2](#msc4201-profiles-as-rooms-v2)
- [Introduction](#introduction)
- [Proposal](#proposal)
- [Profile Rooms](#profile-rooms)
- [Using and Accessing Profiles](#using-and-accessing-profiles)
- [Limitations](#limitations)
- [Trust and Safety](#trust-and-safety)
- [Field Name Rules](#field-name-rules)
- [Potential issues](#potential-issues)
- [Alternatives](#alternatives)
- [Security considerations](#security-considerations)
- [Unstable prefix](#unstable-prefix)
- [Dependencies](#dependencies)
- [Acknowledgements](#acknowledgements)

## Introduction

Profiles as rooms is a long established dream in the matrix ecosystem that has been declared as the solution
to a whole bunch of our problems. This MSC aims to realise that dream via packaging up a idea that has been circulating
in the spec room. Just abuse /profile and the nature of profiles to bypass the Peeking problems.
Comment on lines +20 to +22
Copy link
Member

Choose a reason for hiding this comment

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

This fails to answer "Why?" -- it being a desire isn't enough. Why is this helpful?


This proposal uses profile rooms and state events to define profile information. Profile information
is defined via a `m.profile` state event in your profile room that uses state keys to differentiate values.

To get around the fact that we do not have federated peeking yet this proposal will use the /profile federation API
to simply ask the users homeserver about their profiles. This proposal supports per room profiles and viewing
restricted profiles.

Public profiles without viewing restrictions are also considered valid as you want to be able to present
a profile before you share a room if your privacy settings allow for this.

## Proposal

### Profile Rooms

Profile rooms are special rooms with the dedicated purpose of storing profiles. These rooms will be created
with the `type` being `m.profile` in line with [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772)
established precedent on that specialised rooms like these are what room types are for.
Comment on lines +38 to +40
Copy link
Member

Choose a reason for hiding this comment

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

Please link to the spec for merged features.


They are plain old normal matrix rooms except for that they store profile information as their defined
purpose and server implementations or future MSCs are free to provide powerlevel templates that reflect this purpose.
Comment on lines +42 to +43
Copy link
Member

Choose a reason for hiding this comment

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

What happens if other events are sent in this room? I'm confused at who is expected to be joined to this room.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Its not clarified properly but the parties expected to be present in ones profile room is traditionally only the user them self and optionally bots that can update their profile if that isnt handled via scoped access tokens.

Copy link

Choose a reason for hiding this comment

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

Its not clarified properly but the parties expected to be present in ones profile room is traditionally only the user them self and optionally bots that can update their profile if that isnt handled via scoped access tokens.

Without reading this comment, it's not clear that the room should be joined only by the user and bots. Maybe that should be explicitly specified in the MSC?


These rooms contain `m.profile` state events to store profile data as the state key determines
the profile field this data is for.
Comment on lines +45 to +46
Copy link
Member

Choose a reason for hiding this comment

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

An example of this event would be useful!


The `m.profile.privacy` event controls the privacy rules for the profile in question. This state event
with a blank state key contains a `visibility` value as its initial contents but future proposals
are welcome to elaborate.

This `visibility` value accepts the values of `public` and `restricted`.

Example of the `m.profile.privacy` event.

```json
{
"content": {
"visibility": "restricted"
},
"sender": "@alice:example.com",
"state_key": "",
"type": "m.profile.privacy",
"event_id": "exampleid",
"room_id": "!alice_profile:example.com"
}
```

`visibility` of `public` means that anyone is allowed to look up this profile. This value is primarily intended for
your global profile for when you do not yet share a room with the subject. Like when they are doing a lookup in
the user directory when starting a DM.

`visibility` of `restricted` restricts who can look up a profile to users who are
in a room that has a `m.profile` value set to this profile.
For this value to be legal it must be sent by the creator of the profile.
Copy link
Member

Choose a reason for hiding this comment

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

I was confused that this is referring to the sender of the m.room.member as opposed to in the m.profile.privacy event.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes this is a bit confusing i can agree.

The intent is essentially that only the profile owner can create valid pointers for non public profiles.

This means that invites can only set `public` profiles without causing the server to 404 the request.

`m.profile` events abide by normal event size rules but clients are allowed to enforce whatever
limits they find reasonable on data that they will render.

### Using and Accessing Profiles

To use a profile you set `m.profile` to the room ID of a profile room in your `m.room.member` event in that room.

<details>
<summary>Example membership event with profile set.</summary>

```json
{
"content": {
"avatar_url": "Avatar URL",
"displayname": "Cat",
"membership": "join",
"m.profile" : "!cats_public_profile:feline.support"
},
"origin_server_ts": 2147483648000,
"sender": "@cat:cat:feline.support",
"state_key": "@cat:cat:feline.support",
"type": "m.room.member",
"event_id": "example_event_id",
"room_id": "example_room_id"
}
```

</details>

To access a profile you issue a request to `GET /_matrix/client/v1/profile/{roomID}` and provide the following parameters.

Query Parameter of `auth_event` pointing to a `m.room.member` that has a `m.profile` field that matches the profile
being requested. If the profile is public like in a use case where your presenting profile information before
a room is shared `auth_event` must to be omitted.

The user making the request must have history visibility for the `auth_event`

A subset of the profile fields can be requested using the `filter` query parameter type being `string`.

The response to a `GET /_matrix/client/v1/profile/{roomID}` is a set of Stripped state events responsive to the query.
Comment on lines +115 to +117
Copy link
Member

Choose a reason for hiding this comment

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

I assume this is something like filter is the state keys of events in the profile room? This isn't clear though. The response is the stripped m.profile state events?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup you filter based on the state keys you care about and the response is stripped m.profile events responsive to the query.


To Access a profile over federation you use `GET /_matrix/federation/v1/profile/{roomID}`.

The result of a profile inquiry may be cached for a reasonable period of time not exceeding 24 hours.

The federation version of this endpoint mirrors its behaviour mostly with the client server API version of this endpoint.
The federation version of the endpoint adds the `requesting_user` query parameter. This parameter is required when
the `auth_event` parameter is present. Its used to indicate on whose behalf the request is made as this changes if
a profile lookup fails or succeeds, due to that the `requesting_user` must have history visibility for `auth_event`.

The history visibility check is done from the perspective of the resident server for the profile owner.

Profile rooms that have `m.federate` = `false` are not allowed to be requested over federation and `m.room.server_acl`
is to be honoured for all profile requests based on profile room.

Any profile field that is empty is omitted from profile lookups.

### Limitations

The completely freeform nature of this proposal raises Trust and Safety Concerns. To mitigate at least
one of these concerns servers are completely welcome to run allow and deny lists on state keys for profiles.

Profiles have no size caps set in stone in this proposal as of version 1 of the proposal. This is seen as
acceptable because rooms are currently also unbound and servers are happy with requests like /state on the
matrix.org coc policy list. The policy list in question is of a decent size.

### Trust and Safety

To continue to allow for moderation of profiles that are not aligned with policy in a given room, this MSC
keeps the behaviour of that redacting someone's membership event stops profile information from rendering.

Homeserver administrators are welcome to redact or modify user profiles to comply with server policy, in accordance
with server policies.

Its preferred if homeserver moderators / administrators redact state events that are not aligned with server policy.

The omit empty fields policy for the endpoint is to mitigate this specific T&S concern and privacy concern.

### Field Name Rules

Homeservers should be very careful about how they enforce profile field rules as to balance their T&S concerns and
the ability for users to access the full power of this proposal and future extensions.

Spec defined profile fields come with state keys that carry the reserved `m.` prefix.

User defined profile fields come with the `u.` prefix copied from tags.

Lastly Clients and Servers and MSCs are ofc allowed to use custom prefixes that follow the Java naming
conventions that we follow in matrix. An example could be `support.feline.cat`.

Spec defined fields and fields that follow the java naming conventions can have specified validation
rules that go beyond the general rules that this MSC imposes. For example if
[MSC4175](https://github.com/matrix-org/matrix-spec-proposals/pull/4175) is used with this proposal that MSC
could define that the `m.tz / us.cloke.msc4175.tz` field it defines has a maximum size of 50 characters.

## Potential issues

This MSC has the problem of that its adding freeform fields and attempting to guarantee wide ecosystem
support for all of them is well hard. But this challenge I think is warranted as this MSC represents
a faithful hopefully version of the vision that
the community had for [MSC1769](https://github.com/matrix-org/matrix-spec-proposals/pull/1769).

This MSC is intentionally more complex to allow for a single proposal to do everything that was
dreamed about for [MSC1769](https://github.com/matrix-org/matrix-spec-proposals/pull/1769) over the years.

This MSC on its own is very weakly useful as it needs proposals that build upon it to achieve full potential.

This MSC is intentionally leaving all the possible fields out of scope as that's not important. The
desire is proven for years in the ecosystem so this proposals job is not to prove that the people want this,
just to provide it.

This MSC also has no way to broadcast changes to users but that could easily be added in a future proposal.

Mechanisms to indicate this change include EDUs or timeline events but state events are considered too heavy
for this purpose at this time.

## Alternatives

The primary alternative to this MSC is [MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133).

This MSC sees it self as the better alternative if perfected because it brings Per room and private profiles
and a path to the original vision of Profiles as Rooms that use Federated peeking. This proposal brings
Trust and Safety as a Nr 1 priority but ofc this is a very hard thing to deal with as we are essentially
bringing something akin to a steam profile with this MSC. That's very intentional as Steam profiles are a
inspiration for this MSC UX wise.
Comment on lines +198 to +202
Copy link
Member

Choose a reason for hiding this comment

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

I don't really see how this helps T&S concerns TBH. Why is it easier to redact events in a room than to update a profile?

Choose a reason for hiding this comment

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

I, as a user on homeserver A, cannot update the profile of a user on homeserver B.


## Security considerations
Copy link
Member

Choose a reason for hiding this comment

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

Having all historical data via state events sounds like a big privacy violation that would be surprising to users?


This MSC has covered its various security related aspects throughout the whole MSC but lets boil it down to one
place.

Privacy of profiles is only loosely enforceable over federation. But so is all of matrix. We simply can not guarantee
that someone is who they claim to be outside of E2EE. This also applies with our profile lookups. But
we do mitigate the abuse aspect by requiring that you not only know the event ID of a event that points
to a profile but have all the validation be done by the server who controls said user.

Public profiles are a risk that users need to be informed of but its seen as an acceptable risk as its simply
paramount to offer this option. Users are not expected to be happy when told you can not see any profile what so
ever for someone you don't share a room with when trying to invite them. Especially local users on private servers.

A public profile is not mandatory under this proposal very much on purpose. This is one of the details of this
MSC informed by Steam. They also have rich profile visibility settings and they are very popular, while we are
not copying all of their settings in this proposal with the right use of this proposal you can achieve mostly similar
results.

There is the concern that users can ACL ban the mods from their profile and this concern is lessened if moderators are
informed of this situation and simply disallow such profiles in their rooms.

The Problems related to that this MSC allows you to essentially ask to be vomited data at are hopefully explained
away to an acceptable degree.

No further Security considerations not covered elsewhere in this MSC
or in this Section are known to the author at this time.

## Unstable prefix

While this proposal is unstable the following substitutions are to be made.

`m.profile.privacy` becomes `support.feline.msc4201.profile.privacy.v1`
`m.profile` state event becomes `support.feline.msc4201.profile.v1`
`m.profile` room type becomes `support.feline.msc4201.profile`
`m.profile` value in `m.room.member` becomes `support.feline.msc4201.profile.v1`

`GET /_matrix/client/v1/profile/{roomID}` becomes `GET /_matrix/client/unstable/support.feline.msc4201.v1/profile/{roomID}`
`GET /_matrix/federation/v1/profile/{roomID}` becomes `GET /_matrix/federation/unstable/support.feline.msc4201.v1/profile/{roomID}`

## Dependencies

This MSC does not have any unstable dependencies known to the author but does build on the
work in [MSC1769](https://github.com/matrix-org/matrix-spec-proposals/pull/1769)

## Acknowledgements

This MSC exists to realise the vision that was set out in
[MSC1769](https://github.com/matrix-org/matrix-spec-proposals/pull/1769)
this vision has served to guide the ecosystem for a long time but its time to finally realise it.

This proposal aims to provide a pathway to take us from the limitations of today that shaped the competing proposal
[MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133) to the future where we have fed peeking
fully working in the hopeful event that said future happens.

A thanks has to be issued to everyone who gave feedback on
[MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133)
as this feedback has helped shape this competing proposal.
Also thanks to Tom for the proposal it self as it has inspired parts of this proposal.

Thanks to Gnuxie for being the source of the peeking bypass idea as far as Cat remembers.