From c2f1c6e78d4d92aa77e9df131dfc9234a5a3e614 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 18 Jul 2018 16:21:48 -0600 Subject: [PATCH 1/6] Improve the joining rooms handshake documentation There isn't a whole lot to this section that needed work. The section overall lost the table schema in favour of having the endpoints close by. The directory query is improved in https://github.com/matrix-org/matrix-doc/pull/1443 --- api/server-server/joins.yaml | 29 +++++--- specification/server_server_api.rst | 100 ++++++---------------------- 2 files changed, 39 insertions(+), 90 deletions(-) diff --git a/api/server-server/joins.yaml b/api/server-server/joins.yaml index eaf14e717..472d63bf4 100644 --- a/api/server-server/joins.yaml +++ b/api/server-server/joins.yaml @@ -29,7 +29,6 @@ paths: description: |- Asks the receiving server to return information that the sending server will need to prepare a join event to get into the room. - This is part of the `Joining Rooms`_ handshake. operationId: makeJoin parameters: - in: path @@ -95,7 +94,9 @@ paths: type: array description: |- An event reference list containing the authorization events that would - allow the member to join the room. + allow the member to join the room. This should normally be the + ``m.room.create``, ``m.room.power_levels``, and ``m.room.join_rules`` + events. items: type: array maxItems: 2 @@ -128,7 +129,12 @@ paths: "state_key": "@someone:example.org", "content": { "membership": "join" - } + }, + "auth_events": [ + ["$room_cre4te_3vent:matrix.org", {"sha256": "abase64encodedsha256hashshouldbe43byteslong"}], + ["$room_j0in_rul3s_3vent:matrix.org", {"sha256": "abase64encodedsha256hashshouldbe43byteslong"}], + ["$room_p0wer_l3vels_3vent:matrix.org", {"sha256": "abase64encodedsha256hashshouldbe43byteslong"}] + ] } "/send_join/{roomId}/{eventId}": put: @@ -250,27 +256,30 @@ paths: title: Room State description: The state for the room. properties: + origin: + type: string + description: The resident server's DNS name. auth_chain: type: array description: The auth chain. items: type: object - properties: {} - # TODO: Verify schema + schema: + $ref: "definitions/pdu.yaml" state: type: array description: The room state. items: type: object - properties: {} - # TODO: Verify schema + schema: + $ref: "definitions/pdu.yaml" required: ["auth_chain", "state"] examples: application/json: [ 200, { - # TODO: Use the appropriate refs (see TODOs in schema) - "auth_chain": [], - "state": [] + "origin": "matrix.org", + "auth_chain": [{"$ref": "examples/pdu.json"}], + "state": [{"$ref": "examples/pdu.json"}] } ] diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index f1825f270..d819b0723 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -688,9 +688,6 @@ All these URLs are name-spaced within a prefix of:: {{query_general_ss_http_api}} - -{{joins_ss_http_api}} - Joining Rooms ------------- @@ -742,94 +739,34 @@ homeservers, though most in practice will use just two. <---------- join response The first part of the handshake usually involves using the directory server to -request the room ID and join candidates. This is covered in more detail on the -directory server documentation, below. In the case of a new user joining a -room as a result of a received invite, the joining user's homeserver could -optimise this step away by picking the origin server of that invite message as -the join candidate. However, the joining server should be aware that the origin -server of the invite might since have left the room, so should be prepared to -fall back on the regular join flow if this optimisation fails. +request the room ID and join candidates through the |/query/directory|_ +API endpoint. In the case of a new user joining a room as a result of a received +invite, the joining user's homeserver could optimise this step away by picking +the origin server of that invite message as the join candidate. However, the +joining server should be aware that the origin server of the invite might since +have left the room, so should be prepared to fall back on the regular join flow +if this optimisation fails. Once the joining server has the room ID and the join candidates, it then needs to obtain enough information about the room to fill in the required fields of the ``m.room.member`` event. It obtains this by selecting a resident from the -candidate list, and requesting the ``make_join`` endpoint using a ``GET`` -request, specifying the room ID and the user ID of the new member who is -attempting to join. - -The resident server replies to this request with a JSON-encoded object having a -single key called ``event``; within this is an object whose fields contain some -of the information that the joining server will need. Despite its name, this -object is not a full event; notably it does not need to be hashed or signed by -the resident homeserver. The required fields are: - -======================== ============ ========================================= - Key Type Description -======================== ============ ========================================= -``type`` String The value ``m.room.member``. -``auth_events`` List An event-reference list containing the - authorization events that would allow - this member to join. -``content`` Object The event content. -``depth`` Integer (this field must be present but is - ignored; it may be 0) -``origin`` String The name of the resident homeserver. -``origin_server_ts`` Integer A timestamp added by the resident - homeserver. -``prev_events`` List An event-reference list containing the - immediate predecessor events. -``room_id`` String The room ID of the room. -``sender`` String The user ID of the joining member. -``state_key`` String The user ID of the joining member. -======================== ============ ========================================= - -The ``content`` field itself must be an object, containing: - -======================== ============ ========================================= - Key Type Description -======================== ============ ========================================= -``membership`` String The value ``join``. -======================== ============ ========================================= - -The joining server now has sufficient information to construct the real join -event from these protoevent fields. It copies the values of most of them, -adding (or replacing) the following fields: - -======================== ============ ========================================= - Key Type Description -======================== ============ ========================================= -``event_id`` String A new event ID specified by the joining - homeserver. -``origin`` String The name of the joining homeserver. -``origin_server_ts`` Integer A timestamp added by the joining - homeserver. -======================== ============ ========================================= +candidate list, and using the ``GET /make_join`` endpoint. The resident server +will then reply with enough information for the joining server to fill in the +event. -This will be a true event, so the joining server should apply the event-signing -algorithm to it, resulting in the addition of the ``hashes`` and ``signatures`` -fields. +The joining server is expected to add or replace the ``origin``, ``origin_server_ts``, +and ``event_id`` on the templated event received by the resident server. This +event is then signed by the joining server. To complete the join handshake, the joining server must now submit this new -event to an resident homeserver, by using the ``send_join`` endpoint. This is -invoked using the room ID and the event ID of the new member event. +event to an resident homeserver, by using the ``PUT /send_join`` endpoint. The resident homeserver then accepts this event into the room's event graph, and responds to the joining server with the full set of state for the -newly-joined room. This is returned as a two-element list, whose first element -is the integer 200, and whose second element is an object which contains the -following keys: +newly-joined room. The resident server must also send the event to other servers +participating in the room. -======================== ============ ========================================= - Key Type Description -======================== ============ ========================================= -``auth_chain`` List A list of events giving all of the events - in the auth chains for the join event and - the events in ``state``. -``state`` List A complete list of the prevailing state - events at the instant just before - accepting the new ``m.room.member`` - event. -======================== ============ ========================================= +{{joins_ss_http_api}} .. TODO-spec - (paul) I don't really understand why the full auth_chain events are given @@ -1306,6 +1243,9 @@ that are too long. [[TODO(markjh) We might want to allow the server to omit the output of well known hash functions like SHA-256 when none of the keys have been redacted]] +.. |/query/directory| replace:: ``/query/directory`` +.. _/query/directory: #get-matrix-federation-v1-query-directory + .. _`Invitation storage`: ../identity_service/unstable.html#invitation-storage .. _`Identity Service API`: ../identity_service/unstable.html .. _`Client-Server API`: ../client_server/unstable.html#m-room-member From 9fdd8a6f964c70689bd7451d746e96164ce8ab5f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 26 Jul 2018 14:59:43 -0600 Subject: [PATCH 2/6] Document how leaving rooms/rejecting invites over federation works Fixes https://github.com/matrix-org/matrix-doc/issues/1401 This is very similar to the joining rooms handshake, and much of it is a near copy/paste of the make_join and send_join API. The major difference is the send_leave API doesn't return anything. References: * Handling of make_leave: https://github.com/matrix-org/synapse/blob/d69decd5c78c72abef50b597a689e2bc55a39702/synapse/handlers/federation.py#L1285-L1310 * send_leave route: https://github.com/matrix-org/synapse/blob/d69decd5c78c72abef50b597a689e2bc55a39702/synapse/federation/transport/client.py#L267 * make_leave route: https://github.com/matrix-org/synapse/blob/d69decd5c78c72abef50b597a689e2bc55a39702/synapse/federation/transport/server.py#L396 * send_leave returning nothing: https://github.com/matrix-org/synapse/blob/d69decd5c78c72abef50b597a689e2bc55a39702/synapse/handlers/federation.py#L1346 --- api/server-server/leaving.yaml | 266 ++++++++++++++++++++++++++++ specification/server_server_api.rst | 20 +++ 2 files changed, 286 insertions(+) create mode 100644 api/server-server/leaving.yaml diff --git a/api/server-server/leaving.yaml b/api/server-server/leaving.yaml new file mode 100644 index 000000000..11b0e01d1 --- /dev/null +++ b/api/server-server/leaving.yaml @@ -0,0 +1,266 @@ +# 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. + +swagger: '2.0' +info: + title: "Matrix Federation Leave Room API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/federation/v1 +produces: + - application/json +paths: + "/make_leave/{roomId}/{userId}": + get: + summary: Get information required to make a join event for a room + description: |- + Asks the receiving server to return information that the sending + server will need to prepare a leave event to get out of the room. + operationId: makeLeave + parameters: + - in: path + name: roomId + type: string + description: The room ID that is about to be left. + required: true + x-example: "!abc123:matrix.org" + - in: path + name: userId + type: string + description: The user ID the leave event will be for. + required: true + x-example: "@someone:example.org" + responses: + 200: + description: |- + An unsigned event that the sending server may use as a template + for when it calls ``/send_leave``. + schema: + allOf: + - $ref: "definitions/unsigned_pdu.yaml" + - type: object + properties: + # Note: we override a bunch of parameters to change their descriptions + sender: + type: string + description: The user ID of the leaving member. + example: "@someone:example.org" + origin: + type: string + description: The name of the resident homeserver. + example: "matrix.org" + origin_server_ts: + type: integer + format: int64 + description: A timestamp added by the resident homeserver. + example: 1234567890 + type: + type: string + description: The value ``m.room.member``. + example: "m.room.member" + state_key: + type: string + description: The user ID of the leaving member. + example: "@someone:example.org" + content: + type: object + title: Membership Event Content + description: The content of the event. + example: {"membership": "leave"} + properties: + membership: + type: string + description: The value ``leave``. + example: "leave" + required: ['membership'] + auth_events: + type: array + description: |- + An event reference list containing the authorization events that would + allow the member to leave the room. This should normally be the + ``m.room.create``, ``m.room.power_levels``, and ``m.room.join_rules`` + events. + items: + type: array + maxItems: 2 + minItems: 2 + items: + - type: string + title: Event ID + example: "$abc123:matrix.org" + - type: object + title: Event Hash + example: { + "sha256": "abase64encodedsha256hashshouldbe43byteslong" + } + properties: + sha256: + type: string + description: The event hash. + example: abase64encodedsha256hashshouldbe43byteslong + required: ['sha256'] + redacts: + type: string + description: Not used. + required: + # Every other field is already flagged as required by the $ref + - state_key + examples: + application/json: { + "$ref": "examples/unsigned_pdu.json", + "type": "m.room.member", + "state_key": "@someone:example.org", + "content": { + "membership": "leave" + }, + "auth_events": [ + ["$room_cre4te_3vent:matrix.org", {"sha256": "abase64encodedsha256hashshouldbe43byteslong"}], + ["$room_j0in_rul3s_3vent:matrix.org", {"sha256": "abase64encodedsha256hashshouldbe43byteslong"}], + ["$room_p0wer_l3vels_3vent:matrix.org", {"sha256": "abase64encodedsha256hashshouldbe43byteslong"}] + ] + } + 403: + description: |- + The request is not authorized. This could mean that the user is not in the room. + schema: + $ref: "../client-server/definitions/errors/error.yaml" + examples: + application/json: { + "errcode": "M_FORBIDDEN", + "error": "User is not in the room." + } + "/send_leave/{roomId}/{eventId}": + put: + summary: Submit a signed leave event to a resident server + description: |- + Submits a signed leave event to the resident server for it + to accept it into the room's graph. + operationId: sendLeave + parameters: + - in: path + name: roomId + type: string + description: The room ID that is about to be left. + required: true + x-example: "!abc123:matrix.org" + - in: path + name: eventId + type: string + description: The event ID for the leave event. + required: true + x-example: "$abc123:example.org" + - in: body + name: body + type: object + required: true + schema: + allOf: + - $ref: "definitions/pdu.yaml" + - type: object + properties: + # Note: we override a bunch of parameters to change their descriptions + sender: + type: string + description: The user ID of the leaving member. + example: "@someone:example.org" + origin: + type: string + description: The name of the leaving homeserver. + example: "matrix.org" + origin_server_ts: + type: integer + format: int64 + description: A timestamp added by the leaving homeserver. + example: 1234567890 + type: + type: string + description: The value ``m.room.member``. + example: "m.room.member" + state_key: + type: string + description: The user ID of the leaving member. + example: "@someone:example.org" + content: + type: object + title: Membership Event Content + description: The content of the event. + example: {"membership": "leave"} + properties: + membership: + type: string + description: The value ``leave``. + example: "leave" + required: ['membership'] + depth: + type: integer + description: This field must be present but is ignored; it may be 0. + example: 12 + auth_events: + type: array + description: |- + An event reference list containing the authorization events that would + allow the member to leave the room. + items: + type: array + maxItems: 2 + minItems: 2 + items: + - type: string + title: Event ID + example: "$abc123:matrix.org" + - type: object + title: Event Hash + example: { + "sha256": "abase64encodedsha256hashshouldbe43byteslong" + } + properties: + sha256: + type: string + description: The event hash. + example: abase64encodedsha256hashshouldbe43byteslong + required: ['sha256'] + redacts: + type: string + description: Not used. + required: + # Every other field is already flagged as required by the $ref + - state_key + example: { + "$ref": "examples/pdu.json", + "type": "m.room.member", + "state_key": "@someone:example.org", + "content": { + "membership": "leave" + } + } + responses: + 200: + description: |- + An empty response to indicate the event was accepted into the graph by + the receiving homeserver. + schema: + type: array + minItems: 2 + maxItems: 2 + items: + - type: integer + description: The value ``200``. + example: 200 + - type: object + title: Empty Object + description: An empty object. + examples: + application/json: [200, {}] diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index f1825f270..32b6486fc 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -881,6 +881,26 @@ Inviting to a room {{invites_ss_http_api}} +Leaving Rooms (Rejecting Invites) +--------------------------------- + +Normally homeservers can send appropriate ``m.room.member`` events to have users +leave the room, or to reject local invites. Remote invites from other homeservers +do not involve the server in the graph and therefore need another approach to +reject the invite. Joining the room and promptly leaving is not recommended as +clients and servers will interpret that as accepting the invite, then leaving the +room rather than rejecting the invite. + +Similar to the `Joining Rooms`_ handshake, the server which wishes to leave the +room starts with sending a ``/make_leave`` request to a resident server. In the +case of rejecting invites, the resident server may be the server which sent the +invite. After receiving a template event from ``/make_leave``, the leaving server +signs the event and replaces the ``event_id`` with it's own. This is then sent to +the resident server via ``/send_leave``. The resident server will then send the +event to other servers in the room. + +{{leaving_ss_http_api}} + Third-party invites ------------------- From 7679b4f1d168e4f5ab7c2e94d34923079782f234 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Jul 2018 16:58:13 -0600 Subject: [PATCH 3/6] Improve documentation on how Transactions work The response is based upon various sections of the Synapse code in how it generates a response. There are no new fields added to the transaction. Originally, `previous_ids` and `pdu_failures` were to be documented however neither of these are used in the real world. --- .../definitions/transaction.yaml | 8 ++- api/server-server/transactions.yaml | 58 +++++++++++++++++-- specification/server_server_api.rst | 38 +----------- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/api/server-server/definitions/transaction.yaml b/api/server-server/definitions/transaction.yaml index 930ddec1a..7df8b6464 100644 --- a/api/server-server/definitions/transaction.yaml +++ b/api/server-server/definitions/transaction.yaml @@ -25,11 +25,13 @@ properties: origin_server_ts: type: integer format: int64 - description: Timestamp in milliseconds on originating homeserver when this transaction started. - example: 1234567890 + description: |- + POSIX timestamp in milliseconds on originating homeserver when this + transaction started. + example: 1532991320875 pdus: type: array description: List of persistent updates to rooms. items: $ref: "pdu.yaml" -required: ['origin', 'origin_server_ts', 'pdus'] \ No newline at end of file +required: ['origin', 'origin_server_ts', 'pdus'] diff --git a/api/server-server/transactions.yaml b/api/server-server/transactions.yaml index 13ba6826b..2a9180a19 100644 --- a/api/server-server/transactions.yaml +++ b/api/server-server/transactions.yaml @@ -30,16 +30,18 @@ paths: Push messages representing live activity to another server. The destination name will be set to that of the receiving server itself. Each embedded PDU in the transaction body will be processed. + + The sending server must wait and retry for a 200 OK response before sending a + transaction with a different ``txnId`` to the receiving server. operationId: sendTransaction parameters: - in: path name: txnId type: string - # TODO: "Overrides any ID given in the JSON body" - What does this mean? description: |- - The transaction ID. Overrides any ID given in the JSON body. + The transaction ID. required: true - x-example: TODO # No examples in the spec so far + x-example: S0meTransacti0nId - in: body name: body type: object @@ -51,7 +53,9 @@ paths: properties: edus: type: array - description: List of ephemeral messages. May be omitted if there are no ephemeral messages to be sent. + description: |- + List of ephemeral messages. May be omitted if there are no ephemeral + messages to be sent. items: $ref: "definitions/edu.yaml" example: { @@ -60,5 +64,47 @@ paths: } responses: 200: - # TODO: Spec this (and figure out what it is) - description: TODO + description: |- + The result of processing the transaction. The server is to use this response even in + the event of one or more PDUs failing to be processed. + schema: + type: array + minItems: 2 + maxItems: 2 + items: + - type: integer + description: The value ``200``. + example: 200 + - type: object + title: PDU Processing Results + description: The results for the processing of each PDU in the transaction. + properties: + pdus: + type: object + description: |- + The PDUs from the original transaction. The string key represents the ID of the + PDU (event) that was processed. + additionalProperties: + type: object + title: PDU Processing Result + description: Information about how the PDU was handled. + properties: + error: + type: string + description: |- + A human readable description about what went wrong in processing this PDU. + If no error is present, the PDU can be considered successfully handled. + example: "You are not allowed to send a message to this room." + required: ['pdus'] + examples: + application/json: [ + 200, + { + "pdus": { + "$successful_event:domain.com": {}, + "$failed_event:example.org": { + "error": "You are not allowed to send a message to this room." + } + } + } + ] diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index f1825f270..a190d9d2f 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -242,41 +242,7 @@ of Transaction messages, which are encoded as JSON objects, passed over an HTTP PUT request. A Transaction is meaningful only to the pair of homeservers that exchanged it; they are not globally-meaningful. -Each transaction has: - - An opaque transaction ID, unique among transactions from the same origin. - - A timestamp (UNIX epoch time in milliseconds) generated by its origin - server. - - An origin and destination server name. - - A list of PDUs and EDUs - the actual message payload that the Transaction - carries. - -Transaction Fields -~~~~~~~~~~~~~~~~~~ - -==================== =================== ====================================== - Key Type Description -==================== =================== ====================================== -``origin`` String **Required**. ``server_name`` of homeserver sending - this transaction. -``origin_server_ts`` Integer **Required**. Timestamp in milliseconds on - originating homeserver when this - transaction started. -``pdus`` List of Objects **Required**. List of persistent updates to rooms. -``edus`` List of Objects List of ephemeral messages. May be omitted - if there are no ephemeral messages to - be sent. -==================== =================== ====================================== - -Example: - -.. code:: json - - { - "origin_server_ts": 1404835423000, - "origin": "matrix.org", - "pdus": [...], - "edus": [...] - } +{{transactions_ss_http_api}} PDUs ---- @@ -682,8 +648,6 @@ All these URLs are name-spaced within a prefix of:: /_matrix/federation/v1/... -{{transactions_ss_http_api}} - {{events_ss_http_api}} {{query_general_ss_http_api}} From 5596243add762c0ee2ede0a5ca592f4437ee3ce2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 2 Aug 2018 16:43:24 -0600 Subject: [PATCH 4/6] origin is required --- api/server-server/joins.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/server-server/joins.yaml b/api/server-server/joins.yaml index 472d63bf4..759361b71 100644 --- a/api/server-server/joins.yaml +++ b/api/server-server/joins.yaml @@ -273,7 +273,7 @@ paths: type: object schema: $ref: "definitions/pdu.yaml" - required: ["auth_chain", "state"] + required: ["auth_chain", "state", "origin"] examples: application/json: [ 200, From a9258ed1951d55e19f4ede02b7708e692a1bb1f0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 2 Aug 2018 16:43:29 -0600 Subject: [PATCH 5/6] an -> a --- specification/server_server_api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index d819b0723..8c3d85ea2 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -759,7 +759,7 @@ and ``event_id`` on the templated event received by the resident server. This event is then signed by the joining server. To complete the join handshake, the joining server must now submit this new -event to an resident homeserver, by using the ``PUT /send_join`` endpoint. +event to a resident homeserver, by using the ``PUT /send_join`` endpoint. The resident homeserver then accepts this event into the room's event graph, and responds to the joining server with the full set of state for the From e766606f24820f75820b1ae45c7b1a729d64ddfb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 2 Aug 2018 18:54:12 -0600 Subject: [PATCH 6/6] join -> leave --- api/server-server/leaving.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/server-server/leaving.yaml b/api/server-server/leaving.yaml index 11b0e01d1..e287bf586 100644 --- a/api/server-server/leaving.yaml +++ b/api/server-server/leaving.yaml @@ -25,7 +25,7 @@ produces: paths: "/make_leave/{roomId}/{userId}": get: - summary: Get information required to make a join event for a room + summary: Get information required to make a leave event for a room description: |- Asks the receiving server to return information that the sending server will need to prepare a leave event to get out of the room.