element-hq / element-hq/synapse

Inconsistent behavior for client profile endpoints for legacy fields

Open
#19,466 0 comments 1 reaction 0 assignees View on GitHub
A-Profiles
Dominant language
Python
Stars
4.6k
Forks
600
Avg merge
5d 22h
Merged PRs (30d)
51

Description

### Description

The behavior is inconsistent for the `displayname` and `avatar_url` profile fields between the `GET /_matrix/client/v3/profile/{userId}`, `PUT /_matrix/client/v3/profile/{userId}/{keyName}` endpoints on one side, and the `GET /_matrix/client/v3/profile/{userId}/{keyName}` endpoint on the other side. The latter also doesn't seem to be spec compliant.

This is what I observed, using the `displayname` field as an example and comparing with the [Matrix 1.17 spec](https://spec.matrix.org/v1.17/client-server-api/#profiles):

1. `GET /_matrix/client/v3/profile/{userId}` returns an `HTTP 200` response when at least one field is set and an `HTTP 404` response with an `M_NOT_FOUND` error code when none of the fields are set, which matches the definition in the spec.
2. `PUT /_matrix/client/v3/profile/{userId}/displayname` requires the `displayname` field to be present and a string, which matches the definition in the spec. Setting the value to an empty string appears to unset the field, which seems like an opinionated behavior, since it is not defined in the spec.
3. `GET /_matrix/client/v3/profile/{userId}/displayname` always returns an `HTTP 200` response, whether the `displayname` is set or not. If it is not set, the value of the field is `null`, which is inconsistent with the two other endpoints. If it is not possible to set a `null` value with the `PUT` endpoint, how can it be possible to receive it? According to the spec, a missing field should return an `HTTP 404` response like the `GET /_matrix/client/v3/profile/{userId}` endpoint.

Note that this doesn't apply to other profile fields like `m.tz`: those are allowed to be set to `null` or an empty string, and those "invalid" values appear in the responses of both `GET` endpoints. Only using the `DELETE` endpoint actually unsets the field, and when the field is unset both `GET` endpoints return an `HTTP 404` response.

### Steps to reproduce

The following commands can be used to test this behavior on a local deployment listening on port `8008`, using an existing `@user1:matrix.local` account with a valid access token set into the `MATRIX_ACCESS_TOKEN` environment variable, and starting with an empty profile.

#### 1. Set a non-empty display name

```sh
$ curl -i -X PUT "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local/displayname" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"displayname":"Alice"}'

HTTP/1.1 200 OK
[… other headers]

{}
```

Check that the field is set:

```sh
$ curl -i -X GET "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local/displayname" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN"

HTTP/1.1 200 OK
[… other headers]

{"displayname":"Alice"}
```

Check that the profile is not empty:

```sh
$ curl -i -X GET "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN"

HTTP/1.1 200 OK
[… other headers]

{"displayname":"Alice"}
```

#### 2. Unsuccessful attempts to unset the display name

Try to omit the field:

```sh
$ curl -i -X PUT "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local/displayname" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{}'

HTTP/1.1 400 Bad Request
[… other headers]

{"errcode":"M_MISSING_PARAM","error":"Missing key 'displayname'"}
```

Try to set the value to `null`:

```sh
$ curl -i -X PUT "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local/displayname" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"displayname":null}'

HTTP/1.1 400 Bad Request
[… other headers]

{"errcode":"M_INVALID_PARAM","error":"'displayname' must be a string"}
```

#### 2. Successful attempts to unset the display name

Send an empty string:

```sh
$ curl -i -X PUT "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local/displayname" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"displayname":""}'

HTTP/1.1 200 OK
[… other headers]

{}
```

or use the `DELETE` endpoint:

```sh
$ curl -i -X DELETE "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local/displayname" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN"

HTTP/1.1 200 OK
[… other headers]

{}
```

Check that the field is unset:

```sh
$ curl -i -X GET "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local/displayname" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN"

HTTP/1.1 200 OK
[… other headers]

{"displayname":null}
```

Check that the profile is empty:

```sh
$ curl -i -X GET "http://localhost:8008/_matrix/client/v3/profile/%40user1%3Amatrix.local" -H "Accept: application/json" -H "Authorization: Bearer $MATRIX_ACCESS_TOKEN"

HTTP/1.1 404 Not Found
[… other headers]

{"errcode":"M_NOT_FOUND","error":"Profile was not found"}
```

### Homeserver

Local deployment / any Synapse homeserver

### Synapse Version

1.147.1

### Installation Method

Docker (matrixdotorg/synapse)

### Database

SQLite

### Workers

Single process

### Platform

N/A

### Configuration

_No response_

### Relevant log output

```shell
N/A
```

### Anything else that would be useful to know?

_No response_

Contributor guide

Open the contributing guide

Research direction

Reproduce the behavior with the listed curl commands against the profile endpoints, starting with GET /_matrix/client/v3/profile/{userId}/{keyName} for an unset displayname. Compare its response with GET /_matrix/client/v3/profile/{userId} and the Matrix 1.17 profiles specification; done means the legacy field endpoints agree on unset-field behavior and match the specification.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.