Distinguish 'client' from 'federation' events (#3658)

Fixes #3305 
Fixes #3380
 
The idea here is to better distinguish between a 'raw' event (as we send over the wire), and the 
'serialised' format, as sent in responses to the C-S api and in `PUT /_matrix/app/v1/transactions/{txnId}`.

It's made more complicated by the fact that there are _two_ serialisation formats, one used by `/sync`
and `/notifications`, and one by everything else (the difference being whether `room_id` is included).

In an ideal world, we wouldn't repeat `SerialisedEvent` every time it's used, and instead just link to the
first reference, but that's a job for another day.

Another job for another day is to get rid of things like `sync_state_event.yaml` (which is now used
only in one place, so should be inlined.)
pull/977/head
Richard van der Hoff 3 years ago committed by GitHub
parent d4c74d37a9
commit 36b02edfc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1 @@
Distinguish between "federation" event format as exchanged by the Federation API, and the "client" event formats as used in the client-server and AS APIs.

@ -0,0 +1 @@
Distinguish between "federation" event format as exchanged by the Federation API, and the "client" event formats as used in the client-server and AS APIs.

@ -1440,32 +1440,6 @@ any given point in time:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5] [E0]->[E1]->[E2]->[E3]->[E4]->[E5]
{{% boxes/warning %}}
The format of events can change depending on room version. Check the
[room version specification](/rooms) for specific
details on what to expect for event formats. Examples contained within
the client-server specification are expected to be compatible with all
specified room versions, however some differences may still apply.
For this version of the specification, clients only need to worry about
the event ID format being different depending on room version. Clients
should not be parsing the event ID, and instead be treating it as an
opaque string. No changes should be required to support the currently
available room versions.
{{% /boxes/warning %}}
{{% boxes/warning %}}
Event bodies are considered untrusted data. This means that any application using
Matrix must validate that the event body is of the expected shape/schema
before using the contents verbatim.
**It is not safe to assume that an event body will have all the expected
fields of the expected types.**
See [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801) for more
detail on why this assumption is unsafe.
{{% /boxes/warning %}}
### Types of room events ### Types of room events
Room events are split into two categories: Room events are split into two categories:
@ -1496,25 +1470,31 @@ sent by clients and other clients would receive it through Matrix,
assuming the client has access to the `com.example` namespace. assuming the client has access to the `com.example` namespace.
{{% /boxes/note %}} {{% /boxes/note %}}
Note that the structure of these events may be different than those in ### Room event format
the server-server API.
#### Event fields
{{% event-fields event_type="event" %}} The "federation" format of a room event, which is used internally by homeservers
and between homeservers via the Server-Server API, depends on the ["room
version"](/rooms) in use by the room. See, for example, the definitions
in [room version 1](/rooms/v1#event-format) and [room version
3](/rooms/v3#event-format).
#### Room event fields However, it is unusual that a Matrix client would encounter this event
format. Instead, homeservers are responsible for converting events into the
format shown below so that they can be easily parsed by clients.
{{% event-fields event_type="room_event" %}} {{% boxes/warning %}}
Event bodies are considered untrusted data. This means that any application using
Matrix must validate that the event body is of the expected shape/schema
before using the contents verbatim.
#### State event fields **It is not safe to assume that an event body will have all the expected
fields of the expected types.**
In addition to the fields of a Room Event, State Events have the See [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801) for more
following field: detail on why this assumption is unsafe.
{{% /boxes/warning %}}
| Key | Type | Description | {{% definition path="api/client-server/definitions/client_event" %}}
|--------------|--------------|--------------------------------------------------------------------------------------------------------------|
| state_key | string | **Required.** A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. State keys starting with an `@` are reserved for referencing user IDs, such as room members. With the exception of a few events, state events set with a given user's ID as the state key MUST only be set by that user. |
### Stripped state ### Stripped state
@ -1580,8 +1560,7 @@ updates not being sent.
### Size limits ### Size limits
The complete event MUST NOT be larger than 65536 bytes, when formatted The complete event MUST NOT be larger than 65536 bytes, when formatted
as a [PDU for the Server-Server with the [federation event format](#room-event-format), including any
protocol](/server-server-api/#pdus), including any
signatures, and encoded as [Canonical signatures, and encoded as [Canonical
JSON](/appendices#canonical-json). JSON](/appendices#canonical-json).

@ -65,8 +65,7 @@ paths:
description: |- description: |-
A list of events, formatted as per the Client-Server API. A list of events, formatted as per the Client-Server API.
items: items:
type: object $ref: "../client-server/definitions/client_event.yaml"
title: Event
required: ["events"] required: ["events"]
responses: responses:
200: 200:

@ -0,0 +1,47 @@
# Copyright 2022 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: ClientEvent
description: |-
The format used for events when they are returned from a homeserver to a client
via the Client-Server API, or sent to an Application Service via the Application Services API.
type: object
allOf:
- $ref: "client_event_without_room_id.yaml"
- properties:
room_id:
description: The ID of the room associated with this event.
type: string
example: '!jEsUZKDJdhlrceRyVU:example.org'
unsigned:
properties:
redacted_because:
title: ClientEvent
example: {
"type": "m.room.redaction",
"sender": "@moderator:example.org",
"content": {
"reason": "spam"
},
"redacts": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
"event_id": "$Nhl3rsgHMjk-DjMJANawr9HHAhLg4GcoTYrSiYYGqEE",
"origin_server_ts": 1632491098485,
"room_id": '!jEsUZKDJdhlrceRyVU:example.org',
"unsigned": {
"age": 1257,
}
}
required:
- room_id

@ -0,0 +1,110 @@
# Copyright 2022 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: ClientEventWithoutRoomID
description: |-
The format used for events when they are returned from
API endpoints such as `/sync`, where the `room_id` is implied elsewhere
in the response.
type: object
required:
- event_id
- type
- sender
- origin_server_ts
- content
properties:
event_id:
description: The globally unique identifier for this event.
type: string
example: '$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45'
type:
description: The type of the event.
type: string
example: 'm.room.member'
state_key:
description: |-
Present if, and only if, this event is a *state* event. The key making
this piece of state unique in the room. Note that it is often an empty
string.
type: string
example: '@user:example.org'
sender:
description: Contains the fully-qualified ID of the user who sent this event.
type: string
example: "@example:example.org"
origin_server_ts:
description: |-
Timestamp (in milliseconds since the unix epoch) on originating homeserver
when this event was sent.
type: integer
format: int64
example: 1632489532305
content:
description: |-
The body of this event, as created by the client which sent it.
type: object
example: {
"membership": "join"
}
unsigned:
title: UnsignedData
type: object
description: Contains optional extra information about the event.
properties:
age:
description: The time in milliseconds that has elapsed since the event was
sent. This field is generated by the local homeserver, and may be incorrect
if the local time on at least one of the two servers is out of sync, which can
cause the age to either be negative or greater than it actually is.
type: integer
format: int64
example: 1567437
redacted_because:
description: The event that redacted this event, if any.
type: object
title: ClientEventWithoutRoomID
example: {
"type": "m.room.redaction",
"sender": "@moderator:example.org",
"content": {
"reason": "spam"
},
"redacts": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
"event_id": "$Nhl3rsgHMjk-DjMJANawr9HHAhLg4GcoTYrSiYYGqEE",
"origin_server_ts": 1632491098485,
"unsigned": {
"age": 1257,
}
}
transaction_id:
description: |
The client-supplied transaction ID, for example, provided via
`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`,
if the client being given the event is the same one which sent it.
type: string
prev_content:
description: |
The previous `content` for this event. This field is generated
by the local homeserver, and is only returned if the event is a state event,
and the client has permission to see the previous content.
x-changedInMatrixVersion:
1.2: |
Previously, this field was specified at the top level of returned
events rather than in `unsigned` (with the exception of the [`GET
.../notifications`](/client-server-api/#get_matrixclientv3notifications)
endpoint), though in practice no known server implementations honoured
this.
title: EventContent
type: object

@ -1,28 +0,0 @@
# Copyright 2018 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
properties:
events:
description: List of events.
items:
allOf:
- $ref: ../../../event-schemas/schema/core-event-schema/sync_room_event.yaml
type: object
required:
- event_id
#- room_id - Not in /sync
- sender
- origin_server_ts
type: array
type: object
title: RoomEventBatch

@ -15,15 +15,7 @@ properties:
events: events:
description: List of events. description: List of events.
items: items:
allOf: $ref: client_event_without_room_id.yaml
- $ref: ../../../event-schemas/schema/core-event-schema/sync_state_event.yaml
type: object
required:
- event_id
#- room_id - Not in /sync
- sender
- origin_server_ts
- state_key
type: array type: array
type: object type: object
title: StateEventBatch title: StateEventBatch

@ -12,8 +12,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
allOf:
- $ref: room_event_batch.yaml
properties: properties:
limited: limited:
description: True if the number of events returned was limited by the `limit` description: True if the number of events returned was limited by the `limit`
@ -27,5 +25,12 @@ properties:
If no earlier events are available, this property may be omitted from If no earlier events are available, this property may be omitted from
the response. the response.
type: string type: string
events:
description: List of events.
type: array
items:
$ref: "client_event_without_room_id.yaml"
type: object type: object
title: TimelineBatch title: TimelineBatch
required:
- events

@ -92,28 +92,25 @@ paths:
A list of room events that happened just before the A list of room events that happened just before the
requested event, in reverse-chronological order. requested event, in reverse-chronological order.
items: items:
allOf: $ref: "definitions/client_event.yaml"
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
event: event:
description: |- description: |-
Details of the requested event. Details of the requested event.
allOf: allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" - $ref: "definitions/client_event.yaml"
events_after: events_after:
type: array type: array
description: |- description: |-
A list of room events that happened just after the A list of room events that happened just after the
requested event, in chronological order. requested event, in chronological order.
items: items:
allOf: $ref: "definitions/client_event.yaml"
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
state: state:
type: array type: array
description: |- description: |-
The state of the room at the last event returned. The state of the room at the last event returned.
items: items:
allOf: $ref: "definitions/client_event.yaml"
- "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml"
examples: examples:
application/json: { application/json: {
"end": "t29-57_2_0_2", "end": "t29-57_2_0_2",

@ -125,7 +125,7 @@ paths:
are available. Clients should continue to paginate until no `end` property are available. Clients should continue to paginate until no `end` property
is returned. is returned.
items: items:
"$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" "$ref": "definitions/client_event.yaml"
state: state:
type: array type: array
description: |- description: |-
@ -138,7 +138,7 @@ paths:
sent to the client in prior calls to this endpoint, assuming sent to the client in prior calls to this endpoint, assuming
the membership of those members has not changed. the membership of those members has not changed.
items: items:
$ref: "../../event-schemas/schema/core-event-schema/state_event.yaml" $ref: "definitions/client_event.yaml"
required: [start, chunk] required: [start, chunk]
examples: examples:
application/json: { application/json: {

@ -112,8 +112,7 @@ paths:
type: object type: object
title: Event title: Event
description: The Event object for the event that triggered the notification. description: The Event object for the event that triggered the notification.
allOf: "$ref": "definitions/client_event_without_room_id.yaml"
- $ref: ../../event-schemas/schema/core-event-schema/sync_room_event.yaml
profile_tag: profile_tag:
type: string type: string
description: The profile tag of the rule that matched this event. description: The profile tag of the rule that matched this event.

@ -84,10 +84,7 @@ paths:
type: array type: array
description: "An array of events." description: "An array of events."
items: items:
type: object $ref: "definitions/client_event.yaml"
title: Event
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
400: 400:
description: "Bad pagination `from` parameter." description: "Bad pagination `from` parameter."
tags: tags:
@ -206,10 +203,7 @@ paths:
type: array type: array
description: A list of presence events. description: A list of presence events.
items: items:
type: object $ref: "definitions/client_event.yaml"
title: Event
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
rooms: rooms:
type: array type: array
items: items:
@ -227,8 +221,7 @@ paths:
type: object type: object
title: "InviteEvent" title: "InviteEvent"
description: "The invite event if `membership` is `invite`" description: "The invite event if `membership` is `invite`"
allOf: $ref: "definitions/client_event.yaml"
- "$ref": "../../event-schemas/schema/m.room.member.yaml"
messages: messages:
type: object type: object
title: PaginationChunk title: PaginationChunk
@ -260,10 +253,7 @@ paths:
messages that preceded them leaving. This array messages that preceded them leaving. This array
will consist of at most `limit` elements. will consist of at most `limit` elements.
items: items:
type: object $ref: "definitions/client_event.yaml"
title: RoomEvent
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
required: ["end", "chunk"] required: ["end", "chunk"]
state: state:
type: array type: array
@ -273,10 +263,7 @@ paths:
user has left the room this will be the state of the user has left the room this will be the state of the
room when they left it. room when they left it.
items: items:
title: StateEvent $ref: "definitions/client_event.yaml"
type: object
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml"
visibility: visibility:
type: string type: string
enum: ["private", "public"] enum: ["private", "public"]
@ -289,10 +276,7 @@ paths:
The private data that this user has attached to The private data that this user has attached to
this room. this room.
items: items:
title: Event $ref: "definitions/client_event.yaml"
type: object
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
required: ["room_id", "membership"] required: ["room_id", "membership"]
account_data: account_data:
type: array type: array
@ -336,8 +320,7 @@ paths:
examples: examples:
application/json: {"$ref": "../../event-schemas/examples/m.room.message$m.text.yaml"} application/json: {"$ref": "../../event-schemas/examples/m.room.message$m.text.yaml"}
schema: schema:
allOf: $ref: "definitions/client_event.yaml"
- "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
404: 404:
description: The event was not found or you do not have permission to read this event. description: The event was not found or you do not have permission to read this event.
tags: tags:

@ -102,7 +102,7 @@ paths:
type: object type: object
title: Event title: Event
allOf: allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" - "$ref": "definitions/client_event.yaml"
400: 400:
description: "Bad pagination `from` parameter." description: "Bad pagination `from` parameter."
tags: tags:

@ -119,10 +119,7 @@ paths:
messages that preceded them leaving. This array messages that preceded them leaving. This array
will consist of at most `limit` elements. will consist of at most `limit` elements.
items: items:
type: object "$ref": "definitions/client_event.yaml"
title: RoomEvent
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
required: ["end", "chunk"] required: ["end", "chunk"]
state: state:
type: array type: array
@ -132,10 +129,7 @@ paths:
user has left the room this will be the state of the user has left the room this will be the state of the
room when they left it. room when they left it.
items: items:
title: StateEvent "$ref": "definitions/client_event.yaml"
type: object
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml"
visibility: visibility:
type: string type: string
enum: ["private", "public"] enum: ["private", "public"]

@ -58,8 +58,7 @@ paths:
"$ref": "../../event-schemas/examples/m.room.message$m.text.yaml" "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml"
} }
schema: schema:
allOf: "$ref": "definitions/client_event.yaml"
- "$ref": "../../event-schemas/schema/core-event-schema/event.yaml"
404: 404:
description: The event was not found or you do not have permission to read this event. description: The event was not found or you do not have permission to read this event.
examples: examples:
@ -165,10 +164,7 @@ paths:
has left the room then this will be the state of the room has left the room then this will be the state of the room
when they left as a list of events. when they left as a list of events.
items: items:
title: StateEvent $ref: "definitions/client_event.yaml"
type: object
allOf:
- "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml"
403: 403:
description: > description: >
You aren't a member of the room and weren't previously a You aren't a member of the room and weren't previously a
@ -251,10 +247,7 @@ paths:
chunk: chunk:
type: array type: array
items: items:
title: MemberEvent $ref: "definitions/client_event.yaml"
type: object
allOf:
- "$ref": "../../event-schemas/schema/m.room.member.yaml"
403: 403:
description: > description: >
You aren't a member of the room and weren't previously a You aren't a member of the room and weren't previously a

@ -204,7 +204,7 @@ paths:
type: object type: object
title: Event title: Event
description: The event that matched. description: The event that matched.
"$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" "$ref": "definitions/client_event.yaml"
context: context:
type: object type: object
title: Event Context title: Event Context
@ -247,7 +247,7 @@ paths:
items: items:
title: Event title: Event
type: object type: object
"$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" "$ref": "definitions/client_event.yaml"
events_after: events_after:
type: array type: array
title: Events After title: Events After
@ -255,7 +255,7 @@ paths:
items: items:
title: Event title: Event
type: object type: object
"$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" "$ref": "definitions/client_event.yaml"
state: state:
type: object type: object
title: Current state title: Current state
@ -271,7 +271,7 @@ paths:
title: Room State title: Room State
items: items:
type: object type: object
"$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml" "$ref": "definitions/client_event.yaml"
groups: groups:
type: object type: object
title: Groups title: Groups

@ -18,31 +18,5 @@ description: Contains optional extra information about the event.
properties: properties:
age: age:
description: The time in milliseconds that has elapsed since the event was description: The time in milliseconds that has elapsed since the event was
sent. This field is generated by the local homeserver, and may be incorrect sent.
if the local time on at least one of the two servers is out of sync, which can
cause the age to either be negative or greater than it actually is.
type: integer type: integer
redacted_because:
description: The event that redacted this event, if any.
title: Event
type: object
transaction_id:
description: |
The client-supplied transaction ID, for example, provided via
`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`,
if the client being given the event is the same one which sent it.
type: string
prev_content:
description: |
The previous `content` for this event. This field is generated
by the local homeserver, and is only returned if the event is a state event,
and the client has permission to see the previous content.
x-changedInMatrixVersion:
1.2: |
Previously, this field was specified at the top level of returned
events rather than in `unsigned` (with the exception of the [`GET
.../notifications`](/client-server-api/#get_matrixclientv3notifications)
endpoint), though in practice no known server implementations honoured
this.
title: EventContent
type: object

Loading…
Cancel
Save