diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml new file mode 100644 index 000000000..6e5951207 --- /dev/null +++ b/.buildkite/pipeline.yaml @@ -0,0 +1,16 @@ +steps: + - label: ":books: Build spec" + command: + - python3 -m venv env + - env/bin/pip install -r scripts/requirements.txt + - ". env/bin/activate; scripts/generate-matrix-org-assets" + artifact_paths: + - assets.tar.gz + plugins: + - docker#v3.0.1: + image: "python:3.6" + + - label: "rebuild matrix.org" + trigger: "matrix-dot-org" + async: true + branches: "master" diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 7a6c6be20..0b814fb92 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -26,10 +26,11 @@ For this to be effective, the APIs need to be present and working correctly in a server before they can be documented in the specification. This process can take some time to complete. -For this reason, we have not found the github pull-request model effective for -discussing changes to the specification. Instead, we have adopted the workflow -as described at https://matrix.org/docs/spec/proposals - *please read this for -details on how to contribute spec changes*. +Changes to the protocol (new endpoints, ideas, etc) need to go through the +`proposals process `_. Other changes, +such as fixing bugs, typos, or clarifying existing behaviour do not need a proposal. +If you're not sure, visit us at `#matrix-spec:matrix.org`_ +and ask. Other changes @@ -51,8 +52,7 @@ following: `_ label. (If there is any doubt about whether it is the spec or the implementations - that need fixing, please discuss it with us first in `#matrix-dev:matrix.org - `_.) + that need fixing, please discuss it with us first in `#matrix-spec:matrix.org`_.) * Clarifications to the specification which do not change the behaviour of Matrix servers or clients in a way which might introduce compatibility @@ -60,14 +60,16 @@ following: `clarification `_ label. - For example, recommendations for UI behaviour do not require a proposal - document. On the other hand, changes to event contents would be best - discussed in a proposal document even though no changes would be necessary to - server implementations. + For example, areas where the specification is unclear do not require a proposal + to fix. On the other hand, introducing new behaviour is best represented by a + proposal. -For such changes, please do just open a `pull request`_. +For such changes, please do just open a `pull request`_. If you're not sure if +your change is covered by the above, please visit `#matrix-spec:matrix.org` and +ask. -.. _pull request: https://help.github.com/articles/about-pull-requests +.. _`pull request`: https://help.github.com/articles/about-pull-requests +.. _`#matrix-spec:matrix.org`: https://matrix.to/#/#matrix-spec:matrix.org Adding to the changelog @@ -96,7 +98,7 @@ the ``newsfragments`` directory. The ``type`` can be one of the following: * ``breaking`` - Used when the change is not backwards compatible. -* ``deprecation`` - Used when deprecating something +* ``deprecation`` - Used when deprecating something. All news fragments must have a brief summary explaining the change in the contents of the file. The summary must end in a full stop to be in line with diff --git a/api/application-service/transactions.yaml b/api/application-service/transactions.yaml index 981811969..09f152765 100644 --- a/api/application-service/transactions.yaml +++ b/api/application-service/transactions.yaml @@ -56,7 +56,7 @@ paths: example: { "events": [ {"$ref": "../../event-schemas/examples/m.room.member"}, - {"$ref": "../../event-schemas/examples/m.room.message#m.text"} + {"$ref": "../../event-schemas/examples/m.room.message$m.text"} ] } description: Transaction information diff --git a/api/client-server/administrative_contact.yaml b/api/client-server/administrative_contact.yaml index 33ea9786f..5cf018056 100644 --- a/api/client-server/administrative_contact.yaml +++ b/api/client-server/administrative_contact.yaml @@ -163,6 +163,14 @@ paths: schema: type: object properties: + id_server: + type: string + description: |- + The identity server to unbind from. If not provided, the homeserver + MUST use the ``id_server`` the identifier was added through. If the + homeserver does not know the original ``id_server``, it MUST return + a ``id_server_unbind_result`` of ``no-support``. + example: "example.org" medium: type: string description: The medium of the third party identifier being removed. @@ -180,7 +188,24 @@ paths: user. schema: type: object - properties: {} + properties: + id_server_unbind_result: + type: string + enum: + # XXX: I don't know why, but the order matters here so that "no-support" + # doesn't become "no- support" by the renderer. + - "no-support" + - "success" + description: |- + An indicator as to whether or not the homeserver was able to unbind + the 3PID from the identity server. ``success`` indicates that the + indentity server has unbound the identifier whereas ``no-support`` + indicates that the identity server refuses to support the request + or the homeserver was not able to determine an identity server to + unbind from. + example: "success" + required: + - id_server_unbind_result tags: - User data "/account/3pid/email/requestToken": diff --git a/api/client-server/content-repo.yaml b/api/client-server/content-repo.yaml index 5f4e9111a..4460bb69d 100644 --- a/api/client-server/content-repo.yaml +++ b/api/client-server/content-repo.yaml @@ -41,7 +41,7 @@ paths: name: Content-Type type: string description: The content type of the file being uploaded - x-example: "Content-Type: audio/mpeg" + x-example: "Content-Type: application/pdf" - in: query type: string x-example: "War and Peace.pdf" @@ -51,6 +51,7 @@ paths: name: "" description: The content to be uploaded. required: true + x-example: "" # so the spec shows "" without quotes. schema: type: string example: "" @@ -103,7 +104,7 @@ paths: default: true description: | Indicates to the server that it should not attempt to fetch the media if it is deemed - remote. This is to prevent routing loops where the server contacts itself. Defaults to + remote. This is to prevent routing loops where the server contacts itself. Defaults to true if not provided. responses: 200: @@ -158,7 +159,7 @@ paths: default: true description: | Indicates to the server that it should not attempt to fetch the media if it is deemed - remote. This is to prevent routing loops where the server contacts itself. Defaults to + remote. This is to prevent routing loops where the server contacts itself. Defaults to true if not provided. responses: 200: @@ -202,6 +203,7 @@ paths: type: integer x-example: 64 name: width + required: true description: |- The *desired* width of the thumbnail. The actual thumbnail may not match the size specified. @@ -209,6 +211,7 @@ paths: type: integer x-example: 64 name: height + required: true description: |- The *desired* height of the thumbnail. The actual thumbnail may not match the size specified. @@ -226,7 +229,7 @@ paths: default: true description: | Indicates to the server that it should not attempt to fetch the media if it is deemed - remote. This is to prevent routing loops where the server contacts itself. Defaults to + remote. This is to prevent routing loops where the server contacts itself. Defaults to true if not provided. responses: 200: @@ -328,7 +331,7 @@ paths: m.upload.size: type: integer format: int64 - description: |- + description: |- The maximum size an upload can be in bytes. Clients SHOULD use this as a guide when uploading content. If not listed or null, the size limit should be treated as unknown. diff --git a/api/client-server/definitions/push_condition.yaml b/api/client-server/definitions/push_condition.yaml index 796a51f47..8752274e2 100644 --- a/api/client-server/definitions/push_condition.yaml +++ b/api/client-server/definitions/push_condition.yaml @@ -16,16 +16,20 @@ title: PushCondition type: object properties: kind: - enum: - - event_match - - contains_display_name - - room_member_count type: string + description: |- + The kind of condition to apply. See `conditions <#conditions>`_ for + more information on the allowed kinds and how they work. key: type: string description: |- Required for ``event_match`` conditions. The dot-separated field of the event to match. + + Required for ``sender_notification_permission`` conditions. The field in + the power level event the user needs a minimum power level for. Fields + must be specified under the ``notifications`` property in the power level + event's ``content``. x-example: content.body pattern: type: string diff --git a/api/client-server/definitions/third_party_signed.yaml b/api/client-server/definitions/third_party_signed.yaml new file mode 100644 index 000000000..c9c761a11 --- /dev/null +++ b/api/client-server/definitions/third_party_signed.yaml @@ -0,0 +1,41 @@ +# Copyright 2019 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. +type: object +title: Third Party Signed +description: |- + A signature of an ``m.third_party_invite`` token to prove that this user + owns a third party identity which has been invited to the room. +properties: + sender: + type: string + description: The Matrix ID of the user who issued the invite. + example: "@alice:example.org" + mxid: + type: string + description: The Matrix ID of the invitee. + example: "@bob:example.org" + token: + type: string + description: The state key of the m.third_party_invite event. + example: "random8nonce" + signatures: + type: object + description: A signatures object containing a signature of the entire signed object. + title: Signatures + example: { + "example.org": { + "ed25519:0": "some9signature" + } + } +required: ["sender", "mxid", "token", "signatures"] diff --git a/api/client-server/directory.yaml b/api/client-server/directory.yaml index 78ddfa291..2c7c83867 100644 --- a/api/client-server/directory.yaml +++ b/api/client-server/directory.yaml @@ -148,5 +148,14 @@ paths: } schema: type: object + 404: + description: There is no mapped room ID for this room alias. + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Room alias #monkeys:example.org not found." + } + schema: + "$ref": "definitions/errors/error.yaml" tags: - Room directory diff --git a/api/client-server/event_context.yaml b/api/client-server/event_context.yaml index 91da3cf4f..e20180284 100644 --- a/api/client-server/event_context.yaml +++ b/api/client-server/event_context.yaml @@ -101,65 +101,35 @@ paths: - "$ref": "definitions/event-schemas/schema/core-event-schema/state_event.yaml" examples: application/json: { - "end": "t29-57_2_0_2", - "events_after": [ - { - "age": 91911336, - "content": { - "body": "7", - "msgtype": "m.text" - }, - "event_id": "$14460306086CiUaL:localhost:8480", - "origin_server_ts": 1446030608551, - "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", - "type": "m.room.message", - "sender": "@test:localhost:8480" - } - ], - "events_before": [ - { - "age": 91911903, - "content": { - "body": "5", - "msgtype": "m.text" - }, - "event_id": "$14460306074UYTlh:localhost:8480", - "origin_server_ts": 1446030607984, - "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", - "type": "m.room.message", - "sender": "@test:localhost:8480" - } - ], - "start": "t27-54_2_0_2", - "state": [ - { - "age": 3123715284, - "content": { - "creator": "@test:localhost:8480" - }, - "event_id": "$14429988040dgQAE:localhost:8480", - "origin_server_ts": 1442998804603, - "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", - "state_key": "", - "type": "m.room.create", - "sender": "@test:localhost:8480" - }, - { - "age": 2067105053, - "content": { - "avatar_url": "mxc://localhost:8480/tVWZTAIIfqtXMZZtmGCkVjTD#auto", - "displayname": "Bob2", - "membership": "join" - }, - "event_id": "$14440554144URDbf:localhost:8480", - "origin_server_ts": 1444055414834, - "replaces_state": "$14440552472PgiGk:localhost:8480", - "room_id": "!sCDvXTtzjpiPxaqkkt:localhost:8480", - "state_key": "@test:localhost:8480", - "type": "m.room.member", - "sender": "@test:localhost:8480" - } - ] + "end": "t29-57_2_0_2", + "events_after": [ + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" } + ], + "event": { + "event_id": "$f3h4d129462ha:example.com", + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.message$m.image" + }, + "events_before": [ + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.message$m.file" + } + ], + "start": "t27-54_2_0_2", + "state": [ + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.create" + }, + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.member" + } + ] + } tags: - Room participation diff --git a/api/client-server/joining.yaml b/api/client-server/joining.yaml index 1dcf769f3..af38d6f97 100644 --- a/api/client-server/joining.yaml +++ b/api/client-server/joining.yaml @@ -58,38 +58,9 @@ paths: name: third_party_signed schema: type: object - example: { - "third_party_signed": { - "sender": "@cat:the.hat", - "mxid": "@green:eggs.ham", - "token": "random8nonce", - "signatures": { - "horton.hears": { - "ed25519:0": "some9signature" - } - } - } - } properties: third_party_signed: - type: object - title: ThirdPartySigned - description: A signature of an ``m.third_party_invite`` token to prove that this user owns a third party identity which has been invited to the room. - properties: - sender: - type: string - description: The Matrix ID of the user who issued the invite. - mxid: - type: string - description: The Matrix ID of the invitee. - token: - type: string - description: The state key of the m.third_party_invite event. - signatures: - type: object - description: A signatures object containing a signature of the entire signed object. - title: Signatures - required: ["sender", "mxid", "token", "signatures"] + $ref: "definitions/third_party_signed.yaml" responses: 200: description: |- @@ -163,45 +134,9 @@ paths: name: third_party_signed schema: type: object - example: { - "third_party_signed": { - "signed": { - "sender": "@cat:the.hat", - "mxid": "@green:eggs.ham", - "token": "random8nonce", - "signatures": { - "horton.hears": { - "ed25519:0": "some9signature" - } - } - } - } - } properties: third_party_signed: - type: object - title: ThirdPartySigned - description: A signature of an ``m.third_party_invite`` token to prove that this user owns a third party identity which has been invited to the room. - properties: - signed: - type: object - title: Signed - properties: - sender: - type: string - description: The Matrix ID of the user who issued the invite. - mxid: - type: string - description: The Matrix ID of the invitee. - token: - type: string - description: The state key of the m.third_party_invite event. - signatures: - type: object - description: A signatures object containing a signature of the entire signed object. - title: Signatures - required: ["sender", "mxid", "token", "signatures"] - required: ["signed"] + $ref: "definitions/third_party_signed.yaml" responses: 200: description: |- diff --git a/api/client-server/keys.yaml b/api/client-server/keys.yaml index 55f8a5a53..718703fd6 100644 --- a/api/client-server/keys.yaml +++ b/api/client-server/keys.yaml @@ -253,7 +253,7 @@ paths: responses: 200: description: - The claimed keys + The claimed keys. schema: type: object properties: diff --git a/api/client-server/logout.yaml b/api/client-server/logout.yaml index 2dfd6d97c..75a3ec87a 100644 --- a/api/client-server/logout.yaml +++ b/api/client-server/logout.yaml @@ -32,7 +32,8 @@ paths: summary: Invalidates a user access token description: |- Invalidates an existing access token, so that it can no longer be used for - authorization. + authorization. The device associated with the access token is also deleted. + `Device keys <#device-keys>`_ for the device are deleted alongside the device. operationId: logout security: - accessToken: [] @@ -49,7 +50,9 @@ paths: summary: Invalidates all access tokens for a user description: |- Invalidates all access tokens for a user, so that they can no longer be used for - authorization. This includes the access token that made this request. + authorization. This includes the access token that made this request. All devices + for the user are also deleted. `Device keys <#device-keys>`_ for the device are + deleted alongside the device. This endpoint does not require UI authorization because UI authorization is designed to protect against attacks where the someone gets hold of a single access diff --git a/api/client-server/message_pagination.yaml b/api/client-server/message_pagination.yaml index 941e61fb9..9a24537c1 100644 --- a/api/client-server/message_pagination.yaml +++ b/api/client-server/message_pagination.yaml @@ -103,7 +103,10 @@ paths: chunk: type: array description: |- - A list of room events. + A list of room events. The order depends on the ``dir`` parameter. + For ``dir=b`` events will be in reverse-chronological order, + for ``dir=f`` in chronological order, so that events start + at the ``from`` point. items: type: object title: RoomEvent @@ -114,43 +117,16 @@ paths: "end": "t47409-4357353_219380_26003_2265", "chunk": [ { - "origin_server_ts": 1444812213737, - "sender": "@alice:example.com", - "event_id": "$1444812213350496Caaaa:example.com", - "content": { - "body": "hello world", - "msgtype":"m.text" - }, - "room_id":"!Xq3620DUiqCaoxq:example.com", - "type":"m.room.message", - "age": 1042 + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" }, { - "origin_server_ts": 1444812194656 , - "sender": "@bob:example.com", - "event_id": "$1444812213350496Cbbbb:example.com", - "content": { - "body": "the world is big", - "msgtype":"m.text" - }, - "room_id":"!Xq3620DUiqCaoxq:example.com", - "type":"m.room.message", - "age": 20123 + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.name" }, { - "origin_server_ts": 1444812163990, - "sender": "@bob:example.com", - "event_id": "$1444812213350496Ccccc:example.com", - "content": { - "name": "New room name" - }, - "prev_content": { - "name": "Old room name" - }, - "state_key": "", - "room_id":"!Xq3620DUiqCaoxq:example.com", - "type":"m.room.name", - "age": 50789 + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.message$m.video" } ] } diff --git a/api/client-server/notifications.yaml b/api/client-server/notifications.yaml index b450885b8..87341d418 100644 --- a/api/client-server/notifications.yaml +++ b/api/client-server/notifications.yaml @@ -75,16 +75,7 @@ paths: "room_id": "!abcdefg:example.com", "ts": 1475508881945, "event": { - "sender": "@alice:example.com", - "type": "m.room.message", - "age": 124524, - "txn_id": "1234", - "content": { - "body": "I am a fish", - "msgtype": "m.text" - }, - "origin_server_ts": 1417731086797, - "event_id": "$74686972643033:example.com" + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" } } ] diff --git a/api/client-server/old_sync.yaml b/api/client-server/old_sync.yaml index c502c239e..a79c3b322 100644 --- a/api/client-server/old_sync.yaml +++ b/api/client-server/old_sync.yaml @@ -64,18 +64,7 @@ paths: "start": "s3456_9_0", "end": "s3457_9_0", "chunk": [ - { - "age": 32, - "content": { - "body": "incoming message", - "msgtype": "m.text" - }, - "event_id": "$14328055551tzaee:localhost", - "origin_server_ts": 1432804485886, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "type": "m.room.message", - "sender": "@bob:localhost" - } + {"$ref": "definitions/event-schemas/examples/m.room.message$m.text"} ] } schema: @@ -142,16 +131,7 @@ paths: application/json: { "end": "s3456_9_0", "presence": [ - { - "content": { - "avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto", - "displayname": "Bob", - "last_active_ago": 31053, - "presence": "online", - "user_id": "@bob:localhost" - }, - "type": "m.presence" - } + {"$ref": "definitions/event-schemas/examples/m.presence"} ], "account_data": [ { @@ -167,28 +147,12 @@ paths: "messages": { "chunk": [ { - "age": 343513403, - "content": { - "body": "foo", - "msgtype": "m.text" - }, - "event_id": "$14328044851tzTJS:localhost", - "origin_server_ts": 1432804485886, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "type": "m.room.message", - "sender": "@alice:localhost" + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" }, { - "age": 343511809, - "content": { - "body": "bar", - "msgtype": "m.text" - }, - "event_id": "$14328044872spjFg:localhost", - "origin_server_ts": 1432804487480, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "type": "m.room.message", - "sender": "@bob:localhost" + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "$ref": "definitions/event-schemas/examples/m.room.message$m.video" } ], "end": "s3456_9_0", @@ -197,81 +161,20 @@ paths: "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state": [ { - "age": 7148266897, - "content": { - "join_rule": "public" - }, - "event_id": "$14259997323TLwtb:localhost", - "origin_server_ts": 1425999732392, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "state_key": "", - "type": "m.room.join_rules", - "sender": "@alice:localhost" - }, - { - "age": 6547561012, - "content": { - "avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto", - "membership": "join" - }, - "event_id": "$1426600438280zExKY:localhost", - "membership": "join", - "origin_server_ts": 1426600438277, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "state_key": "@alice:localhost", - "type": "m.room.member", - "sender": "@alice:localhost" + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "$ref": "definitions/event-schemas/examples/m.room.join_rules" }, { - "age": 7148267200, - "content": { - "creator": "@alice:localhost" - }, - "event_id": "$14259997320KhbwJ:localhost", - "origin_server_ts": 1425999732089, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "state_key": "", - "type": "m.room.create", - "sender": "@alice:localhost" + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "$ref": "definitions/event-schemas/examples/m.room.member" }, { - "age": 1622568720, - "content": { - "avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto", - "displayname": "Bob", - "membership": "join" - }, - "event_id": "$1431525430134MxlLX:localhost", - "origin_server_ts": 1431525430569, - "replaces_state": "$142652023736BSXcM:localhost", - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "state_key": "@bob:localhost", - "type": "m.room.member", - "sender": "@bob:localhost" + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "$ref": "definitions/event-schemas/examples/m.room.create" }, { - "age": 7148267004, - "content": { - "ban": 50, - "events": { - "m.room.name": 100, - "m.room.power_levels": 100 - }, - "events_default": 0, - "kick": 50, - "redact": 50, - "state_default": 50, - "users": { - "@alice:localhost": 100 - }, - "users_default": 0 - }, - "event_id": "$14259997322mqfaq:localhost", - "origin_server_ts": 1425999732285, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "state_key": "", - "type": "m.room.power_levels", - "sender": "@alice:localhost" + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "$ref": "definitions/event-schemas/examples/m.room.power_levels" } ], "visibility": "private", @@ -423,16 +326,7 @@ paths: 200: description: The full event. examples: - application/json: { - "content": { - "body": "Hello world!", - "msgtype": "m.text" - }, - "room_id": "!wfgy43Sg4a:matrix.org", - "sender": "@bob:matrix.org", - "event_id": "$asfDuShaf7Gafaw:matrix.org", - "type": "m.room.message" - } + application/json: {"$ref": "definitions/event-schemas/examples/m.room.message$m.text"} schema: allOf: - "$ref": "definitions/event-schemas/schema/core-event-schema/event.yaml" diff --git a/api/client-server/peeking_events.yaml b/api/client-server/peeking_events.yaml index 2f66bae7f..feac36f4b 100644 --- a/api/client-server/peeking_events.yaml +++ b/api/client-server/peeking_events.yaml @@ -75,16 +75,8 @@ paths: "end": "s3457_9_0", "chunk": [ { - "age": 32, - "content": { - "body": "incoming message", - "msgtype": "m.text" - }, - "event_id": "$14328055551tzaee:localhost", - "origin_server_ts": 1432804485886, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "type": "m.room.message", - "sender": "@bob:localhost" + "room_id": "!somewhere:over.the.rainbow", + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" } ] } diff --git a/api/client-server/registration.yaml b/api/client-server/registration.yaml index e2d35d2c2..5483f77e8 100644 --- a/api/client-server/registration.yaml +++ b/api/client-server/registration.yaml @@ -29,7 +29,8 @@ paths: post: summary: Register for an account on this homeserver. description: |- - This API endpoint uses the `User-Interactive Authentication API`_. + This API endpoint uses the `User-Interactive Authentication API`_, except in + the cases where a guest account is being registered. Register for an account on this homeserver. @@ -59,6 +60,11 @@ paths: supplied by the client or generated by the server. The server may invalidate any access token previously associated with that device. See `Relationship between access tokens and devices`_. + + When registering a guest account, all parameters in the request body + with the exception of ``initial_device_display_name`` MUST BE ignored + by the server. The server MUST pick a ``device_id`` for the account + regardless of input. operationId: register parameters: - in: query @@ -72,7 +78,7 @@ paths: enum: - guest - user - description: The kind of account to register. Defaults to `user`. + description: The kind of account to register. Defaults to ``user``. - in: body name: body schema: @@ -80,13 +86,11 @@ paths: properties: auth: description: |- - Additional authentication information for the - user-interactive authentication API. Note that this - information is *not* used to define how the registered user - should be authenticated, but is instead used to - authenticate the ``register`` call itself. It should be - left empty, or omitted, unless an earlier call returned an - response with status code 401. + Additional authentication information for the + user-interactive authentication API. Note that this + information is *not* used to define how the registered user + should be authenticated, but is instead used to + authenticate the ``register`` call itself. "$ref": "definitions/auth_data.yaml" bind_email: type: boolean @@ -94,6 +98,12 @@ paths: If true, the server binds the email used for authentication to the Matrix ID with the identity server. example: false + bind_msisdn: + type: boolean + description: |- + If true, the server binds the phone number used for authentication + to the Matrix ID with the identity server. + example: false username: type: string description: |- @@ -194,6 +204,18 @@ paths: The homeserver requires additional authentication information. schema: "$ref": "definitions/auth_response.yaml" + 403: + description: |- + The homeserver does not permit registering the account. This response + can be used to identify that a particular ``kind`` of account is not + allowed, or that registration is generally not supported by the homeserver. + examples: + application/json: { + "errcode": "M_FORBIDDEN", + "error": "Registration is disabled" + } + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: @@ -326,13 +348,17 @@ paths: description: |- Changes the password for an account on this homeserver. - This API endpoint uses the `User-Interactive Authentication API`_. + This API endpoint uses the `User-Interactive Authentication API`_ to + ensure the user changing the password is actually the owner of the + account. An access token should be submitted to this endpoint if the client has an active session. The homeserver may change the flows available depending on whether a - valid access token is provided. + valid access token is provided. The homeserver SHOULD NOT revoke the + access token provided in the request, however all other access tokens + for the user should be revoked if the request succeeds. security: - accessToken: [] operationId: changePassword @@ -520,13 +546,39 @@ paths: description: |- Additional authentication information for the user-interactive authentication API. "$ref": "definitions/auth_data.yaml" + id_server: + type: string + description: |- + The identity server to unbind all of the user's 3PIDs from. + If not provided, the homeserver MUST use the ``id_server`` + that was originally use to bind each identifier. If the + homeserver does not know which ``id_server`` that was, + it must return an ``id_server_unbind_result`` of + ``no-support``. + example: "example.org" responses: 200: description: The account has been deactivated. - examples: - application/json: {} schema: type: object + properties: + id_server_unbind_result: + type: string + enum: + - "success" + - "no-support" + description: |- + An indicator as to whether or not the homeserver was able to unbind + the user's 3PIDs from the identity server(s). ``success`` indicates + that all identifiers have been unbound from the identity server while + ``no-support`` indicates that one or more identifiers failed to unbind + due to the identity server refusing the request or the homeserver + being unable to determine an identity server to unbind from. This + must be ``success`` if the homeserver has no identifiers to unbind + for the user. + example: "success" + required: + - id_server_unbind_result 401: description: |- The homeserver requires additional authentication information. diff --git a/api/client-server/room_initial_sync.yaml b/api/client-server/room_initial_sync.yaml index c27f0f24b..72e56ba9f 100644 --- a/api/client-server/room_initial_sync.yaml +++ b/api/client-server/room_initial_sync.yaml @@ -43,28 +43,12 @@ paths: "messages": { "chunk": [ { - "age": 343513403, - "content": { - "body": "foo", - "msgtype": "m.text" - }, - "event_id": "$14328044851tzTJS:example.com", - "origin_server_ts": 1432804485886, "room_id": "!636q39766251:example.com", - "type": "m.room.message", - "sender": "@alice:example.com" + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" }, { - "age": 343511809, - "content": { - "body": "bar", - "msgtype": "m.text" - }, - "event_id": "$14328044872spjFg:example.com", - "origin_server_ts": 1432804487480, "room_id": "!636q39766251:example.com", - "type": "m.room.message", - "sender": "@bob:example.com" + "$ref": "definitions/event-schemas/examples/m.room.message$m.file" } ], "end": "s3456_9_0", @@ -73,81 +57,20 @@ paths: "room_id": "!636q39766251:example.com", "state": [ { - "age": 7148266897, - "content": { - "join_rule": "public" - }, - "event_id": "$14259997323TLwtb:example.com", - "origin_server_ts": 1425999732392, - "room_id": "!636q39766251:example.com", - "state_key": "", - "type": "m.room.join_rules", - "sender": "@alice:example.com" - }, - { - "age": 6547561012, - "content": { - "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", - "membership": "join" - }, - "event_id": "$1426600438280zExKY:example.com", - "membership": "join", - "origin_server_ts": 1426600438277, "room_id": "!636q39766251:example.com", - "state_key": "@alice:example.com", - "type": "m.room.member", - "sender": "@alice:example.com" + "$ref": "definitions/event-schemas/examples/m.room.join_rules" }, { - "age": 7148267200, - "content": { - "creator": "@alice:example.com" - }, - "event_id": "$14259997320KhbwJ:example.com", - "origin_server_ts": 1425999732089, "room_id": "!636q39766251:example.com", - "state_key": "", - "type": "m.room.create", - "sender": "@alice:example.com" + "$ref": "definitions/event-schemas/examples/m.room.member" }, { - "age": 1622568720, - "content": { - "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", - "displayname": "Bob", - "membership": "join" - }, - "event_id": "$1431525430134MxlLX:example.com", - "origin_server_ts": 1431525430569, - "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", - "state_key": "@bob:example.com", - "type": "m.room.member", - "sender": "@bob:example.com" + "$ref": "definitions/event-schemas/examples/m.room.create" }, { - "age": 7148267004, - "content": { - "ban": 50, - "events": { - "m.room.name": 100, - "m.room.power_levels": 100 - }, - "events_default": 0, - "kick": 50, - "redact": 50, - "state_default": 50, - "users": { - "@alice:example.com": 100 - }, - "users_default": 0 - }, - "event_id": "$14259997322mqfaq:example.com", - "origin_server_ts": 1425999732285, "room_id": "!636q39766251:example.com", - "state_key": "", - "type": "m.room.power_levels", - "sender": "@alice:example.com" + "$ref": "definitions/event-schemas/examples/m.room.power_levels" } ], "visibility": "private", diff --git a/api/client-server/rooms.yaml b/api/client-server/rooms.yaml index cc1f2bf7e..377783c68 100644 --- a/api/client-server/rooms.yaml +++ b/api/client-server/rooms.yaml @@ -42,7 +42,7 @@ paths: name: roomId description: The ID of the room the event is in. required: true - x-example: "!asfDuShaf7Gafaw:matrix.org" + x-example: "!636q39766251:matrix.org" - in: path type: string name: eventId @@ -54,15 +54,9 @@ paths: description: The full event. examples: application/json: { - "content": { - "body": "Hello world!", - "msgtype": "m.text" - }, - "room_id": "!wfgy43Sg4a:matrix.org", - "sender": "@bob:matrix.org", - "event_id": "$asfDuShaf7Gafaw:matrix.org", - "type": "m.room.message" - } + "room_id": "!636q39766251:matrix.org", + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" + } schema: allOf: - "$ref": "definitions/event-schemas/schema/core-event-schema/event.yaml" @@ -178,84 +172,23 @@ paths: description: The current state of the room examples: application/json: [ - { - "age": 7148266897, - "content": { - "join_rule": "public" - }, - "event_id": "$14259997323TLwtb:example.com", - "origin_server_ts": 1425999732392, - "room_id": "!636q39766251:example.com", - "state_key": "", - "type": "m.room.join_rules", - "sender": "@alice:example.com" - }, - { - "age": 6547561012, - "content": { - "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", - "membership": "join" - }, - "event_id": "$1426600438280zExKY:example.com", - "membership": "join", - "origin_server_ts": 1426600438277, - "room_id": "!636q39766251:example.com", - "state_key": "@alice:example.com", - "type": "m.room.member", - "sender": "@alice:example.com" - }, - { - "age": 7148267200, - "content": { - "creator": "@alice:example.com" - }, - "event_id": "$14259997320KhbwJ:example.com", - "origin_server_ts": 1425999732089, - "room_id": "!636q39766251:example.com", - "state_key": "", - "type": "m.room.create", - "sender": "@alice:example.com" - }, - { - "age": 1622568720, - "content": { - "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", - "displayname": "Bob", - "membership": "join" - }, - "event_id": "$1431525430134MxlLX:example.com", - "origin_server_ts": 1431525430569, - "replaces_state": "$142652023736BSXcM:example.com", - "room_id": "!636q39766251:example.com", - "state_key": "@bob:example.com", - "type": "m.room.member", - "sender": "@bob:example.com" - }, - { - "age": 7148267004, - "content": { - "ban": 50, - "events": { - "m.room.name": 100, - "m.room.power_levels": 100 - }, - "events_default": 0, - "kick": 50, - "redact": 50, - "state_default": 50, - "users": { - "@alice:example.com": 100 - }, - "users_default": 0 - }, - "event_id": "$14259997322mqfaq:example.com", - "origin_server_ts": 1425999732285, - "room_id": "!636q39766251:example.com", - "state_key": "", - "type": "m.room.power_levels", - "sender": "@alice:example.com" - } - ] + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.join_rules" + }, + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.member" + }, + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.create" + }, + { + "room_id": "!636q39766251:example.com", + "$ref": "definitions/event-schemas/examples/m.room.power_levels" + } + ] schema: type: array title: RoomState @@ -300,33 +233,8 @@ paths: application/json: { "chunk": [ { - "age": 6547561012, - "content": { - "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", - "membership": "join" - }, - "event_id": "$1426600438280zExKY:example.com", - "membership": "join", - "origin_server_ts": 1426600438277, - "room_id": "!636q39766251:example.com", - "state_key": "@alice:example.com", - "type": "m.room.member", - "sender": "@alice:example.com" - }, - { - "age": 1622568720, - "content": { - "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", - "displayname": "Bob", - "membership": "join" - }, - "event_id": "$1431525430134MxlLX:example.com", - "origin_server_ts": 1431525430569, - "replaces_state": "$142652023736BSXcM:example.com", "room_id": "!636q39766251:example.com", - "state_key": "@bob:example.com", - "type": "m.room.member", - "sender": "@bob:example.com" + "$ref": "definitions/event-schemas/examples/m.room.member" } ] } diff --git a/api/client-server/search.yaml b/api/client-server/search.yaml index 4a5f45150..4fe72d5bf 100644 --- a/api/client-server/search.yaml +++ b/api/client-server/search.yaml @@ -280,7 +280,7 @@ paths: Any groups that were requested. The outer ``string`` key is the group key requested (eg: ``room_id`` - or ``sender``). The inner ``string`` key is the grouped value (eg: + or ``sender``). The inner ``string`` key is the grouped value (eg: a room's ID or a user's ID). additionalProperties: type: object @@ -347,16 +347,9 @@ paths: { "rank": 0.00424866, "result": { - "age": 526228296, - "content": { - "body": "Test content martians and men", - "msgtype": "m.text" - }, - "event_id": "$144429830826TWwbB:localhost", - "origin_server_ts": 1444298308034, "room_id": "!qPewotXpIctQySfjSy:localhost", - "type": "m.room.message", - "sender": "@test:localhost" + "event_id": "$144429830826TWwbB:localhost", + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" } } ] diff --git a/api/client-server/sync.yaml b/api/client-server/sync.yaml index f204152a0..3db1fa540 100644 --- a/api/client-server/sync.yaml +++ b/api/client-server/sync.yaml @@ -212,30 +212,7 @@ paths: events: description: The StrippedState events that form the invite state. items: - description: |- - A stripped down state event, with only the ``type``, ``state_key``, - ``sender``, and ``content`` keys. - properties: - content: - description: The ``content`` for the event. - title: EventContent - type: object - state_key: - description: The ``state_key`` for the event. - type: string - type: - description: The ``type`` for the event. - type: string - sender: - description: The ``sender`` for the event. - type: string - required: - - type - - state_key - - content - - sender - title: StrippedState - type: object + $ref: "definitions/event-schemas/schema/stripped_state.yaml" type: array leave: title: Left rooms @@ -310,11 +287,7 @@ paths: "next_batch": "s72595_4483_1934", "presence": { "events": [ - { - "sender": "@alice:example.com", - "type": "m.presence", - "content": {"presence": "online"} - } + {"$ref": "definitions/event-schemas/examples/m.presence"} ] }, "account_data": { @@ -333,36 +306,20 @@ paths: "state": { "events": [ { - "sender": "@alice:example.com", - "type": "m.room.member", - "state_key": "@alice:example.com", - "content": {"membership": "join"}, - "origin_server_ts": 1417731086795, - "event_id": "$66697273743031:example.com" + "room_id": "!726s6s6q:example.com", + "$ref": "definitions/event-schemas/examples/m.room.member" } ] }, "timeline": { "events": [ { - "sender": "@bob:example.com", - "type": "m.room.member", - "state_key": "@bob:example.com", - "content": {"membership": "join"}, - "prev_content": {"membership": "invite"}, - "origin_server_ts": 1417731086795, - "event_id": "$7365636s6r6432:example.com" + "room_id": "!726s6s6q:example.com", + "$ref": "definitions/event-schemas/examples/m.room.member" }, { - "sender": "@alice:example.com", - "type": "m.room.message", - "txn_id": "1234", - "content": { - "body": "I am a fish", - "msgtype": "m.text" - }, - "origin_server_ts": 1417731086797, - "event_id": "$74686972643033:example.com" + "room_id": "!726s6s6q:example.com", + "$ref": "definitions/event-schemas/examples/m.room.message$m.text" } ], "limited": true, @@ -370,18 +327,12 @@ paths: }, "ephemeral": { "events": [ - { - "type": "m.typing", - "content": {"user_ids": ["@alice:example.com"]} - } + {"$ref": "definitions/event-schemas/examples/m.typing"} ] }, "account_data": { "events": [ - { - "type": "m.tag", - "content": {"tags": {"work": {"order": 1}}} - }, + {"$ref": "definitions/event-schemas/examples/m.tag"}, { "type": "org.example.custom.room.config", "content": { diff --git a/api/identity/associations.yaml b/api/identity/associations.yaml index edd43f5d9..f44fe3cc6 100644 --- a/api/identity/associations.yaml +++ b/api/identity/associations.yaml @@ -90,7 +90,7 @@ paths: } schema: $ref: "../client-server/definitions/errors/error.yaml" - "/bind": + "/3pid/bind": post: summary: Publish an association between a session and a Matrix user ID. description: |- @@ -201,3 +201,86 @@ paths: } schema: $ref: "../client-server/definitions/errors/error.yaml" + "/3pid/unbind": + post: + summary: Remove an association between a session and a Matrix user ID. + description: |- + Remove an association between a session and a Matrix user ID. + + Future calls to ``/lookup`` for any of the session's 3pids will not + return the removed association. + + The identity server should authenticate the request in one of two + ways: + + 1. The request is signed by the homeserver which controls the ``user_id``. + 2. The request includes the ``sid`` and ``client_secret`` parameters, + as per ``/3pid/bind``, which proves ownership of the 3PID. + + If this endpoint returns a JSON Matrix error, that error should be passed + through to the client requesting an unbind through a homeserver, if the + homeserver is acting on behalf of a client. + operationId: unbind + parameters: + - in: body + name: body + schema: + type: object + example: { + "sid": "1234", + "client_secret": "monkeys_are_GREAT", + "mxid": "@ears:example.org", + "threepid": { + "medium": "email", + "address": "monkeys_have_ears@example.org" + } + } + properties: + sid: + type: string + description: The Session ID generated by the ``requestToken`` call. + client_secret: + type: string + description: The client secret passed to the ``requestToken`` call. + mxid: + type: string + description: The Matrix user ID to remove from the 3pids. + threepid: + type: object + title: 3PID + description: |- + The 3PID to remove. Must match the 3PID used to generate the session + if using ``sid`` and ``client_secret`` to authenticate this request. + properties: + medium: + type: string + description: |- + A medium from the `3PID Types`_ Appendix, matching the medium + of the identifier to unbind. + address: + type: string + description: The 3PID address to remove. + required: ['medium', 'address'] + required: ["threepid", "mxid"] + responses: + 200: + description: The association was successfully removed. + examples: + application/json: {} + schema: + type: object + 400: + description: |- + If the response body is not a JSON Matrix error, the identity server + does not support unbinds. If a JSON Matrix error is in the response + body, the requesting party should respect the error. + 404: + description: |- + If the response body is not a JSON Matrix error, the identity server + does not support unbinds. If a JSON Matrix error is in the response + body, the requesting party should respect the error. + 501: + description: |- + If the response body is not a JSON Matrix error, the identity server + does not support unbinds. If a JSON Matrix error is in the response + body, the requesting party should respect the error. diff --git a/api/identity/definitions/request_email_validation.yaml b/api/identity/definitions/request_email_validation.yaml index 1194a18ee..5f15bd416 100644 --- a/api/identity/definitions/request_email_validation.yaml +++ b/api/identity/definitions/request_email_validation.yaml @@ -39,7 +39,8 @@ properties: avoid repeatedly sending the same email in the case of request retries between the POSTing user and the identity server. The client should increment this value if they desire a new - email (e.g. a reminder) to be sent. + email (e.g. a reminder) to be sent. If they do not, the server + should respond with success but not resend the email. example: 1 next_link: type: string diff --git a/api/identity/store_invite.yaml b/api/identity/store_invite.yaml index 691032947..bca78d7e6 100644 --- a/api/identity/store_invite.yaml +++ b/api/identity/store_invite.yaml @@ -50,31 +50,66 @@ paths: requests to ``/_matrix/identity/api/v1/pubkey/ephemeral/isvalid``. Currently, invites may only be issued for 3pids of the ``email`` medium. + + Optional fields in the request should be populated to the best of the + server's ability. Identity servers may use these variables when notifying + the ``address`` of the pending invite for display purposes. operationId: storeInvite parameters: - in: body name: body schema: type: object - example: { - "medium": "email", - "address": "foo@bar.baz", - "room_id": "!something:example.tld", - "sender": "@bob:example.com" - } properties: medium: type: string description: The literal string ``email``. + example: "email" address: type: string description: The email address of the invited user. + example: "foo@example.com" room_id: type: string description: The Matrix room ID to which the user is invited + example: "!something:example.org" sender: type: string description: The Matrix user ID of the inviting user + example: "@bob:example.com" + room_alias: + type: string + description: |- + The Matrix room alias for the room to which the user is + invited. This should be retrieved from the ``m.room.canonical_alias`` + state event. + example: "#somewhere:exmaple.org" + room_avatar_url: + type: string + description: |- + The Content URI for the room to which the user is invited. This should + be retrieved from the ``m.room.avatar`` state event. + example: "mxc://example.org/s0meM3dia" + room_join_rules: + type: string + description: |- + The ``join_rule`` for the room to which the user is invited. This should + be retrieved from the ``m.room.join_rules`` state event. + example: "public" + room_name: + type: string + description: |- + The name of the room to which the user is invited. This should be retrieved + from the ``m.room.name`` state event. + example: "Bob's Emporium of Messages" + sender_display_name: + type: string + description: The display name of the user ID initiating the invite. + example: "Bob Smith" + sender_avatar_url: + type: string + description: The Content URI for the avatar of the user ID initiating the invite. + example: "mxc://example.org/an0th3rM3dia" required: ["medium", "address", "room_id", "sender"] responses: 200: diff --git a/api/server-server/backfill.yaml b/api/server-server/backfill.yaml index 0da0e2341..2ed6298ce 100644 --- a/api/server-server/backfill.yaml +++ b/api/server-server/backfill.yaml @@ -64,7 +64,7 @@ paths: A transaction containing the PDUs that preceded the given event(s), including the given event(s), up to the given limit. schema: - $ref: "definitions/transaction.yaml" + $ref: "definitions/unlimited_pdu_transaction.yaml" "/get_missing_events/{roomId}": post: summary: Retrieves events that the sender is missing diff --git a/api/server-server/definitions/pdu_v3.yaml b/api/server-server/definitions/pdu_v3.yaml index 8d41fbdaf..381050984 100644 --- a/api/server-server/definitions/pdu_v3.yaml +++ b/api/server-server/definitions/pdu_v3.yaml @@ -20,6 +20,10 @@ allOf: - $ref: "unsigned_pdu_base.yaml" - type: object properties: + redacts: + type: string + description: For redaction events, the ID of the event being redacted. + example: "$def/456+oldevent" auth_events: type: array items: diff --git a/api/server-server/definitions/pdu_v4.yaml b/api/server-server/definitions/pdu_v4.yaml new file mode 100644 index 000000000..a045e657b --- /dev/null +++ b/api/server-server/definitions/pdu_v4.yaml @@ -0,0 +1,47 @@ +# Copyright 2019 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. +type: object +title: Persistent Data Unit +description: A persistent data unit (event) for room version 4 and beyond. +example: + $ref: "../examples/pdu_v4.json" +allOf: + - $ref: "pdu_v3.yaml" + - type: object + properties: + redacts: + type: string + description: For redaction events, the ID of the event being redacted. + example: "$def_456-oldevent" + auth_events: + type: array + items: + type: string + description: Event ID. + description: |- + Event IDs for the authorization events that would + allow this event to be in the room. + example: ["$URLsafe-base64EncodedHash", "$Another_Event"] + prev_events: + type: array + items: + type: string + description: Event ID. + description: |- + Event IDs for the most recent events in the room + that the homeserver was aware of when it made this event. + example: ["$URLsafe-base64EncodedHash", "$Another_Event"] + required: + - auth_events + - prev_events diff --git a/api/server-server/definitions/single_pdu_transaction.yaml b/api/server-server/definitions/single_pdu_transaction.yaml new file mode 100644 index 000000000..ff682a44f --- /dev/null +++ b/api/server-server/definitions/single_pdu_transaction.yaml @@ -0,0 +1,32 @@ +# Copyright 2019 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. +type: object +allOf: + - $ref: "transaction.yaml" +properties: + pdus: + type: array + description: |- + A single PDU. Note that events have a different format depending on the room + version - check the `room version specification`_ for precise event formats. + items: + type: object + title: PDU + description: |- + The `PDUs <#pdus>`_ contained in the transaction. The event format varies depending + on the room version - check the `room version specification`_ for precise event formats. + properties: [] + example: + $ref: "../examples/minimal_pdu.json" +required: ['origin', 'origin_server_ts', 'pdus'] diff --git a/api/server-server/definitions/unlimited_pdu_transaction.yaml b/api/server-server/definitions/unlimited_pdu_transaction.yaml new file mode 100644 index 000000000..0fc31ee41 --- /dev/null +++ b/api/server-server/definitions/unlimited_pdu_transaction.yaml @@ -0,0 +1,33 @@ +# Copyright 2019 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. +type: object +allOf: + - $ref: "transaction.yaml" +properties: + pdus: + type: array + description: |- + List of persistent updates to rooms. Note that events have a different format + depending on the room version - check the `room version specification`_ for + precise event formats. + items: + type: object + title: PDU + description: |- + The `PDUs <#pdus>`_ contained in the transaction. The event format varies depending + on the room version - check the `room version specification`_ for precise event formats. + properties: [] + example: + $ref: "../examples/minimal_pdu.json" +required: ['origin', 'origin_server_ts', 'pdus'] diff --git a/api/server-server/events.yaml b/api/server-server/events.yaml index 1f1a802dd..1f8ee537f 100644 --- a/api/server-server/events.yaml +++ b/api/server-server/events.yaml @@ -156,4 +156,4 @@ paths: 200: description: A transaction containing a single PDU which is the event requested. schema: - $ref: "definitions/transaction.yaml" + $ref: "definitions/single_pdu_transaction.yaml" diff --git a/api/server-server/examples/pdu_v3.json b/api/server-server/examples/pdu_v3.json index 6a454b4ea..acffdf266 100644 --- a/api/server-server/examples/pdu_v3.json +++ b/api/server-server/examples/pdu_v3.json @@ -15,5 +15,6 @@ "prev_events": [ "$base64encodedeventid", "$adifferenteventid" - ] + ], + "redacts": "$some/old+event" } diff --git a/api/server-server/examples/pdu_v4.json b/api/server-server/examples/pdu_v4.json new file mode 100644 index 000000000..3c2f0e220 --- /dev/null +++ b/api/server-server/examples/pdu_v4.json @@ -0,0 +1,12 @@ +{ + "$ref": "pdu_v3.json", + "auth_events": [ + "$urlsafe_base64_encoded_eventid", + "$a-different-event-id" + ], + "prev_events": [ + "$urlsafe_base64_encoded_eventid", + "$a-different-event-id" + ], + "redacts": "$some-old_event" +} diff --git a/api/server-server/invites-v1.yaml b/api/server-server/invites-v1.yaml index 2ad0f2201..8e1c861d7 100644 --- a/api/server-server/invites-v1.yaml +++ b/api/server-server/invites-v1.yaml @@ -82,35 +82,9 @@ paths: identify the room. The recommended events to include are the join rules, canonical alias, avatar, and name of the room. items: - type: object - title: Invite Room State Event - properties: - type: - type: string - description: The type of event. - example: "m.room.join_rules" - state_key: - type: string - description: The state key for the event. May be an empty string. - example: "" - content: - type: object - description: The content for the event. - sender: - type: string - description: The sender of the event. - example: "@someone:matrix.org" - required: ['type', 'state_key', 'content', 'sender'] - example: [ - { - "type": "m.room.join_rules", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "join_rule": "public" - } - } - ] + $ref: "../../event-schemas/schema/stripped_state.yaml" + example: + $ref: "../../event-schemas/examples/invite_room_state.json" example: { "$ref": "examples/minimal_pdu.json", "type": "m.room.member", @@ -118,26 +92,6 @@ paths: "origin": "example.org", "origin_server_ts": 1549041175876, "sender": "@someone:example.org", - "unsigned": { - "invite_room_state": [ - { - "type": "m.room.join_rules", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "join_rule": "public" - } - }, - { - "type": "m.room.name", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "name": "Cool New Room" - } - } - ] - }, "content": { "membership": "invite" }, @@ -180,24 +134,9 @@ paths: "origin_server_ts": 1549041175876, "sender": "@someone:example.org", "unsigned": { - "invite_room_state": [ - { - "type": "m.room.join_rules", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "join_rule": "public" - } - }, - { - "type": "m.room.name", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "name": "Cool New Room" - } - } - ] + "invite_room_state": { + "$ref": "../../../event-schemas/examples/invite_room_state.json" + } }, "content": { "membership": "invite" diff --git a/api/server-server/invites-v2.yaml b/api/server-server/invites-v2.yaml index c459a8485..cae14bb45 100644 --- a/api/server-server/invites-v2.yaml +++ b/api/server-server/invites-v2.yaml @@ -83,35 +83,9 @@ paths: identify the room. The recommended events to include are the join rules, canonical alias, avatar, and name of the room. items: - type: object - title: Invite Room State Event - properties: - type: - type: string - description: The type of event. - example: "m.room.join_rules" - state_key: - type: string - description: The state key for the event. May be an empty string. - example: "" - content: - type: object - description: The content for the event. - sender: - type: string - description: The sender of the event. - example: "@someone:matrix.org" - required: ['type', 'state_key', 'content', 'sender'] - example: [ - { - "type": "m.room.join_rules", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "join_rule": "public" - } - } - ] + $ref: "../../event-schemas/schema/stripped_state.yaml" + example: + $ref: "../../event-schemas/examples/invite_room_state.json" required: ['room_version', 'event'] example: { "room_version": "2", @@ -130,25 +104,7 @@ paths: "ed25519:key_version": "SomeSignatureHere" }, } - }, - "invite_room_state": [ - { - "type": "m.room.join_rules", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "join_rule": "public" - } - }, - { - "type": "m.room.name", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "name": "Cool New Room" - } - } - ] + } } responses: 200: @@ -174,24 +130,9 @@ paths: "origin_server_ts": 1549041175876, "sender": "@someone:example.org", "unsigned": { - "invite_room_state": [ - { - "type": "m.room.join_rules", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "join_rule": "public" - } - }, - { - "type": "m.room.name", - "sender": "@someone:matrix.org", - "state_key": "", - "content": { - "name": "Cool New Room" - } - } - ] + "invite_room_state": { + "$ref": "../../../event-schemas/examples/invite_room_state.json" + } }, "content": { "membership": "invite" diff --git a/api/server-server/user_keys.yaml b/api/server-server/user_keys.yaml index 63c74d20e..3c59cf81e 100644 --- a/api/server-server/user_keys.yaml +++ b/api/server-server/user_keys.yaml @@ -63,7 +63,7 @@ paths: - one_time_keys responses: 200: - description: The claimed keys + description: The claimed keys. schema: type: object properties: diff --git a/changelogs/application_service/newsfragments/1650.clarification b/changelogs/application_service/newsfragments/1650.clarification new file mode 100644 index 000000000..617b7ab68 --- /dev/null +++ b/changelogs/application_service/newsfragments/1650.clarification @@ -0,0 +1 @@ +Change examples to use example.org instead of a real domain. diff --git a/changelogs/application_service/newsfragments/2037.clarification b/changelogs/application_service/newsfragments/2037.clarification new file mode 100644 index 000000000..f425b1c19 --- /dev/null +++ b/changelogs/application_service/newsfragments/2037.clarification @@ -0,0 +1 @@ +Add missing definition for how appservices verify requests came from a homeserver. diff --git a/changelogs/client_server/newsfragments/1650.clarification b/changelogs/client_server/newsfragments/1650.clarification new file mode 100644 index 000000000..617b7ab68 --- /dev/null +++ b/changelogs/client_server/newsfragments/1650.clarification @@ -0,0 +1 @@ +Change examples to use example.org instead of a real domain. diff --git a/changelogs/client_server/newsfragments/1656.clarification b/changelogs/client_server/newsfragments/1656.clarification new file mode 100644 index 000000000..0c8f4ad04 --- /dev/null +++ b/changelogs/client_server/newsfragments/1656.clarification @@ -0,0 +1 @@ +Clarify that ``state_default`` in ``m.room.power_levels`` always defaults to 50. diff --git a/changelogs/client_server/newsfragments/1701.feature b/changelogs/client_server/newsfragments/1701.feature index 39c22dd7e..cf6084aea 100644 --- a/changelogs/client_server/newsfragments/1701.feature +++ b/changelogs/client_server/newsfragments/1701.feature @@ -1 +1 @@ -Documented megolm session export format. \ No newline at end of file +Add megolm session export format. diff --git a/changelogs/client_server/newsfragments/1744.clarification b/changelogs/client_server/newsfragments/1744.clarification index dc1039200..dfe838f15 100644 --- a/changelogs/client_server/newsfragments/1744.clarification +++ b/changelogs/client_server/newsfragments/1744.clarification @@ -1 +1 @@ -Add missing status_msg to m.presence schema. +Add missing ``status_msg`` to ``m.presence`` schema. diff --git a/changelogs/client_server/newsfragments/1889.clarification b/changelogs/client_server/newsfragments/1889.clarification index 5026dab38..2737a7ee5 100644 --- a/changelogs/client_server/newsfragments/1889.clarification +++ b/changelogs/client_server/newsfragments/1889.clarification @@ -1 +1 @@ -Add the missing `m.push_rules` event schema. +Add the missing ``m.push_rules`` event schema. diff --git a/changelogs/client_server/newsfragments/1891.clarification b/changelogs/client_server/newsfragments/1891.clarification new file mode 100644 index 000000000..ef4edfb4a --- /dev/null +++ b/changelogs/client_server/newsfragments/1891.clarification @@ -0,0 +1 @@ +Clarify how modern day local echo is meant to be solved by clients. diff --git a/changelogs/client_server/newsfragments/1903.feature b/changelogs/client_server/newsfragments/1908.feature similarity index 100% rename from changelogs/client_server/newsfragments/1903.feature rename to changelogs/client_server/newsfragments/1908.feature diff --git a/changelogs/client_server/newsfragments/1969.clarification b/changelogs/client_server/newsfragments/1969.clarification new file mode 100644 index 000000000..b0f052035 --- /dev/null +++ b/changelogs/client_server/newsfragments/1969.clarification @@ -0,0 +1 @@ +Fix various spelling mistakes throughout the specification. diff --git a/changelogs/client_server/newsfragments/1975.clarification b/changelogs/client_server/newsfragments/1975.clarification new file mode 100644 index 000000000..ac118bfd2 --- /dev/null +++ b/changelogs/client_server/newsfragments/1975.clarification @@ -0,0 +1 @@ +Clarify that ``width`` and ``height`` are required parameters on ``/_matrix/media/r0/thumbnail/{serverName}/{mediaId}``. diff --git a/changelogs/client_server/newsfragments/1988.clarification b/changelogs/client_server/newsfragments/1988.clarification new file mode 100644 index 000000000..b0f052035 --- /dev/null +++ b/changelogs/client_server/newsfragments/1988.clarification @@ -0,0 +1 @@ +Fix various spelling mistakes throughout the specification. diff --git a/changelogs/client_server/newsfragments/1989.clarification b/changelogs/client_server/newsfragments/1989.clarification new file mode 100644 index 000000000..b0f052035 --- /dev/null +++ b/changelogs/client_server/newsfragments/1989.clarification @@ -0,0 +1 @@ +Fix various spelling mistakes throughout the specification. diff --git a/changelogs/client_server/newsfragments/1991.clarification b/changelogs/client_server/newsfragments/1991.clarification new file mode 100644 index 000000000..b0f052035 --- /dev/null +++ b/changelogs/client_server/newsfragments/1991.clarification @@ -0,0 +1 @@ +Fix various spelling mistakes throughout the specification. diff --git a/changelogs/client_server/newsfragments/1992.clarification b/changelogs/client_server/newsfragments/1992.clarification new file mode 100644 index 000000000..b0f052035 --- /dev/null +++ b/changelogs/client_server/newsfragments/1992.clarification @@ -0,0 +1 @@ +Fix various spelling mistakes throughout the specification. diff --git a/changelogs/client_server/newsfragments/1999.clarification b/changelogs/client_server/newsfragments/1999.clarification new file mode 100644 index 000000000..748c55f2e --- /dev/null +++ b/changelogs/client_server/newsfragments/1999.clarification @@ -0,0 +1 @@ +Clarify how ``m.login.dummy`` can be used to disambiguate login flows. diff --git a/changelogs/client_server/newsfragments/2016.clarification b/changelogs/client_server/newsfragments/2016.clarification new file mode 100644 index 000000000..77ea0d4c9 --- /dev/null +++ b/changelogs/client_server/newsfragments/2016.clarification @@ -0,0 +1 @@ +Remove ``prev_content`` from the redaction algorithm's essential keys list. diff --git a/changelogs/client_server/newsfragments/2020.feature b/changelogs/client_server/newsfragments/2020.feature new file mode 100644 index 000000000..0d7c7eb83 --- /dev/null +++ b/changelogs/client_server/newsfragments/2020.feature @@ -0,0 +1 @@ +Add a ``.m.rule.tombstone`` default push rule for room ugprade notifications. diff --git a/changelogs/client_server/newsfragments/2025.clarification b/changelogs/client_server/newsfragments/2025.clarification new file mode 100644 index 000000000..9e99b23d0 --- /dev/null +++ b/changelogs/client_server/newsfragments/2025.clarification @@ -0,0 +1 @@ +Fix the ``third_party_signed`` definitions for the join APIs. diff --git a/changelogs/client_server/newsfragments/2026.feature b/changelogs/client_server/newsfragments/2026.feature new file mode 100644 index 000000000..f82b9aea4 --- /dev/null +++ b/changelogs/client_server/newsfragments/2026.feature @@ -0,0 +1 @@ +Add support for sending server notices to clients. diff --git a/changelogs/client_server/newsfragments/2027.clarification b/changelogs/client_server/newsfragments/2027.clarification new file mode 100644 index 000000000..db74ea565 --- /dev/null +++ b/changelogs/client_server/newsfragments/2027.clarification @@ -0,0 +1 @@ +Clarify why User Interactive Auth is used on password changes and how access tokens are handled. diff --git a/changelogs/client_server/newsfragments/2028.clarification b/changelogs/client_server/newsfragments/2028.clarification new file mode 100644 index 000000000..75e21e743 --- /dev/null +++ b/changelogs/client_server/newsfragments/2028.clarification @@ -0,0 +1 @@ +Clarify that devices are deleted upon logout. diff --git a/changelogs/client_server/newsfragments/2029.clarification b/changelogs/client_server/newsfragments/2029.clarification new file mode 100644 index 000000000..95b654813 --- /dev/null +++ b/changelogs/client_server/newsfragments/2029.clarification @@ -0,0 +1 @@ +Add ``M_NOT_FOUND`` error definition for deleting room aliases. diff --git a/changelogs/client_server/newsfragments/2030.feature b/changelogs/client_server/newsfragments/2030.feature new file mode 100644 index 000000000..b5975a737 --- /dev/null +++ b/changelogs/client_server/newsfragments/2030.feature @@ -0,0 +1 @@ +Add MSISDN (phone number) support to User-Interactive Authentication. diff --git a/changelogs/client_server/newsfragments/2031.clarification b/changelogs/client_server/newsfragments/2031.clarification new file mode 100644 index 000000000..9bed3bcc0 --- /dev/null +++ b/changelogs/client_server/newsfragments/2031.clarification @@ -0,0 +1 @@ +Add missing ``reason`` to ``m.call.hangup``. diff --git a/changelogs/client_server/newsfragments/2032.clarification b/changelogs/client_server/newsfragments/2032.clarification new file mode 100644 index 000000000..e497b8be5 --- /dev/null +++ b/changelogs/client_server/newsfragments/2032.clarification @@ -0,0 +1 @@ +Clarify how redactions affect room state. diff --git a/changelogs/client_server/newsfragments/2036.clarification b/changelogs/client_server/newsfragments/2036.clarification new file mode 100644 index 000000000..96058b7b2 --- /dev/null +++ b/changelogs/client_server/newsfragments/2036.clarification @@ -0,0 +1 @@ +Clarify that ``FAIL_ERROR`` in autodiscovery is not limited to just homeservers. diff --git a/changelogs/client_server/newsfragments/2041.clarification b/changelogs/client_server/newsfragments/2041.clarification new file mode 100644 index 000000000..39bbddb5a --- /dev/null +++ b/changelogs/client_server/newsfragments/2041.clarification @@ -0,0 +1 @@ +Fix example ``Content-Type`` for ``/media/upload`` request. diff --git a/changelogs/client_server/newsfragments/2042.clarification b/changelogs/client_server/newsfragments/2042.clarification new file mode 100644 index 000000000..4e17b99fa --- /dev/null +++ b/changelogs/client_server/newsfragments/2042.clarification @@ -0,0 +1 @@ +Clarify that login flows are meant to be completed in order. diff --git a/changelogs/client_server/newsfragments/2043.clarification b/changelogs/client_server/newsfragments/2043.clarification new file mode 100644 index 000000000..9bb975fa1 --- /dev/null +++ b/changelogs/client_server/newsfragments/2043.clarification @@ -0,0 +1 @@ +Clarify that clients should not send read receipts for their own messages. diff --git a/changelogs/client_server/newsfragments/2046.feature b/changelogs/client_server/newsfragments/2046.feature new file mode 100644 index 000000000..e54df5350 --- /dev/null +++ b/changelogs/client_server/newsfragments/2046.feature @@ -0,0 +1 @@ +Add ``id_server`` to ``/deactivate`` and ``/3pid/delete`` endpoints to unbind from a specific identity server. diff --git a/changelogs/client_server/newsfragments/2051.clarification b/changelogs/client_server/newsfragments/2051.clarification new file mode 100644 index 000000000..384daa11d --- /dev/null +++ b/changelogs/client_server/newsfragments/2051.clarification @@ -0,0 +1 @@ +Use consistent examples of events throughout the specification. diff --git a/changelogs/client_server/newsfragments/2052.clarification b/changelogs/client_server/newsfragments/2052.clarification new file mode 100644 index 000000000..95bdc9282 --- /dev/null +++ b/changelogs/client_server/newsfragments/2052.clarification @@ -0,0 +1 @@ +Clarify which push rule condition kinds exist. diff --git a/changelogs/client_server/newsfragments/2053.clarification b/changelogs/client_server/newsfragments/2053.clarification new file mode 100644 index 000000000..2a72a88ed --- /dev/null +++ b/changelogs/client_server/newsfragments/2053.clarification @@ -0,0 +1 @@ +Clarify the required fields on ``m.file`` (and similar) messages. diff --git a/changelogs/client_server/newsfragments/2054.clarification b/changelogs/client_server/newsfragments/2054.clarification new file mode 100644 index 000000000..e43aea2d5 --- /dev/null +++ b/changelogs/client_server/newsfragments/2054.clarification @@ -0,0 +1 @@ +Clarify that User-Interactive Authentication stages cannot be attempted more than once. diff --git a/changelogs/client_server/newsfragments/2055.clarification b/changelogs/client_server/newsfragments/2055.clarification new file mode 100644 index 000000000..3a57ef7eb --- /dev/null +++ b/changelogs/client_server/newsfragments/2055.clarification @@ -0,0 +1 @@ +Clarify which parameters apply in what scenarios on ``/register``. diff --git a/changelogs/client_server/newsfragments/2056.clarification b/changelogs/client_server/newsfragments/2056.clarification new file mode 100644 index 000000000..12521867e --- /dev/null +++ b/changelogs/client_server/newsfragments/2056.clarification @@ -0,0 +1 @@ +Clarify how to interpret changes of ``membership`` over time. diff --git a/changelogs/client_server/newsfragments/2059.feature b/changelogs/client_server/newsfragments/2059.feature new file mode 100644 index 000000000..fde106ce2 --- /dev/null +++ b/changelogs/client_server/newsfragments/2059.feature @@ -0,0 +1 @@ +Add support for Olm sessions becoming un-stuck. diff --git a/changelogs/client_server/newsfragments/2067.clarification b/changelogs/client_server/newsfragments/2067.clarification new file mode 100644 index 000000000..cc7062745 --- /dev/null +++ b/changelogs/client_server/newsfragments/2067.clarification @@ -0,0 +1 @@ +Clarify exactly what invite_room_state consists of. diff --git a/changelogs/client_server/newsfragments/2069.clarification b/changelogs/client_server/newsfragments/2069.clarification new file mode 100644 index 000000000..127573a6d --- /dev/null +++ b/changelogs/client_server/newsfragments/2069.clarification @@ -0,0 +1 @@ +Clarify the order events in chunk are returned in for ``/messages``. diff --git a/changelogs/client_server/newsfragments/2072.feature b/changelogs/client_server/newsfragments/2072.feature new file mode 100644 index 000000000..c7d8bd765 --- /dev/null +++ b/changelogs/client_server/newsfragments/2072.feature @@ -0,0 +1 @@ +Add interactive device verification, including a common framework for device verification. diff --git a/changelogs/client_server/newsfragments/2090.clarification b/changelogs/client_server/newsfragments/2090.clarification new file mode 100644 index 000000000..23ab50f7a --- /dev/null +++ b/changelogs/client_server/newsfragments/2090.clarification @@ -0,0 +1 @@ +Clarify when authorization and rate-limiting are not applicable. diff --git a/changelogs/identity_service/newsfragments/1967.clarification b/changelogs/identity_service/newsfragments/1967.clarification new file mode 100644 index 000000000..b080caeb9 --- /dev/null +++ b/changelogs/identity_service/newsfragments/1967.clarification @@ -0,0 +1 @@ +Fix route for ``/3pid/bind``. diff --git a/changelogs/identity_service/newsfragments/2046.new b/changelogs/identity_service/newsfragments/2046.new new file mode 100644 index 000000000..7146799bb --- /dev/null +++ b/changelogs/identity_service/newsfragments/2046.new @@ -0,0 +1 @@ +Add ``/3pid/unbind`` for removing 3PIDs. diff --git a/changelogs/identity_service/newsfragments/2049.clarification b/changelogs/identity_service/newsfragments/2049.clarification new file mode 100644 index 000000000..403ac8d08 --- /dev/null +++ b/changelogs/identity_service/newsfragments/2049.clarification @@ -0,0 +1 @@ +Add missing aesthetic parameters to ``/store-invite``. diff --git a/changelogs/identity_service/newsfragments/2057.clarification b/changelogs/identity_service/newsfragments/2057.clarification new file mode 100644 index 000000000..de72c201a --- /dev/null +++ b/changelogs/identity_service/newsfragments/2057.clarification @@ -0,0 +1 @@ +Clarify what the client should receive upon sending an identical email validation request multiple times. diff --git a/changelogs/identity_service/newsfragments/2086.clarification b/changelogs/identity_service/newsfragments/2086.clarification new file mode 100644 index 000000000..7016308bc --- /dev/null +++ b/changelogs/identity_service/newsfragments/2086.clarification @@ -0,0 +1 @@ +Clarify that the default transport is JSON over HTTP. diff --git a/changelogs/server_server/newsfragments/1650.clarification b/changelogs/server_server/newsfragments/1650.clarification new file mode 100644 index 000000000..617b7ab68 --- /dev/null +++ b/changelogs/server_server/newsfragments/1650.clarification @@ -0,0 +1 @@ +Change examples to use example.org instead of a real domain. diff --git a/changelogs/server_server/newsfragments/1904.clarification b/changelogs/server_server/newsfragments/1904.clarification deleted file mode 100644 index 94174ebd1..000000000 --- a/changelogs/server_server/newsfragments/1904.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix the `access_token` parameter in the open_id endpoint. diff --git a/changelogs/server_server/newsfragments/1906.clarification b/changelogs/server_server/newsfragments/1906.clarification new file mode 100644 index 000000000..531fdb946 --- /dev/null +++ b/changelogs/server_server/newsfragments/1906.clarification @@ -0,0 +1 @@ +Fix the ``access_token`` parameter in the open_id endpoint. diff --git a/changelogs/server_server/newsfragments/1991.clarification b/changelogs/server_server/newsfragments/1991.clarification new file mode 100644 index 000000000..b0f052035 --- /dev/null +++ b/changelogs/server_server/newsfragments/1991.clarification @@ -0,0 +1 @@ +Fix various spelling mistakes throughout the specification. diff --git a/changelogs/server_server/newsfragments/2067.clarification b/changelogs/server_server/newsfragments/2067.clarification new file mode 100644 index 000000000..cc7062745 --- /dev/null +++ b/changelogs/server_server/newsfragments/2067.clarification @@ -0,0 +1 @@ +Clarify exactly what invite_room_state consists of. diff --git a/changelogs/server_server/newsfragments/2081.clarification b/changelogs/server_server/newsfragments/2081.clarification new file mode 100644 index 000000000..fd291273d --- /dev/null +++ b/changelogs/server_server/newsfragments/2081.clarification @@ -0,0 +1 @@ +Clarify which servers are supposed to sign events. diff --git a/changelogs/server_server/newsfragments/2095.clarification b/changelogs/server_server/newsfragments/2095.clarification new file mode 100644 index 000000000..66257e17b --- /dev/null +++ b/changelogs/server_server/newsfragments/2095.clarification @@ -0,0 +1 @@ +Clarify how many PDUs are contained in transaction objects for various endpoints. diff --git a/data-definitions/sas-emoji.json b/data-definitions/sas-emoji.json new file mode 100644 index 000000000..060fbd490 --- /dev/null +++ b/data-definitions/sas-emoji.json @@ -0,0 +1,66 @@ +[ + {"number": 0, "emoji": "🐶", "description": "Dog", "unicode": "U+1F436"}, + {"number": 1, "emoji": "🐱", "description": "Cat", "unicode": "U+1F431"}, + {"number": 2, "emoji": "🦁", "description": "Lion", "unicode": "U+1F981"}, + {"number": 3, "emoji": "🐎", "description": "Horse", "unicode": "U+1F40E"}, + {"number": 4, "emoji": "🦄", "description": "Unicorn", "unicode": "U+1F984"}, + {"number": 5, "emoji": "🐷", "description": "Pig", "unicode": "U+1F437"}, + {"number": 6, "emoji": "🐘", "description": "Elephant", "unicode": "U+1F418"}, + {"number": 7, "emoji": "🐰", "description": "Rabbit", "unicode": "U+1F430"}, + {"number": 8, "emoji": "🐼", "description": "Panda", "unicode": "U+1F43C"}, + {"number": 9, "emoji": "🐓", "description": "Rooster", "unicode": "U+1F413"}, + {"number": 10, "emoji": "🐧", "description": "Penguin", "unicode": "U+1F427"}, + {"number": 11, "emoji": "🐢", "description": "Turtle", "unicode": "U+1F422"}, + {"number": 12, "emoji": "🐟", "description": "Fish", "unicode": "U+1F41F"}, + {"number": 13, "emoji": "🐙", "description": "Octopus", "unicode": "U+1F419"}, + {"number": 14, "emoji": "🦋", "description": "Butterfly", "unicode": "U+1F98B"}, + {"number": 15, "emoji": "🌷", "description": "Flower", "unicode": "U+1F337"}, + {"number": 16, "emoji": "🌳", "description": "Tree", "unicode": "U+1F333"}, + {"number": 17, "emoji": "🌵", "description": "Cactus", "unicode": "U+1F335"}, + {"number": 18, "emoji": "🍄", "description": "Mushroom", "unicode": "U+1F344"}, + {"number": 19, "emoji": "🌏", "description": "Globe", "unicode": "U+1F30F"}, + {"number": 20, "emoji": "🌙", "description": "Moon", "unicode": "U+1F319"}, + {"number": 21, "emoji": "☁️", "description": "Cloud", "unicode": "U+2601U+FE0F"}, + {"number": 22, "emoji": "🔥", "description": "Fire", "unicode": "U+1F525"}, + {"number": 23, "emoji": "🍌", "description": "Banana", "unicode": "U+1F34C"}, + {"number": 24, "emoji": "🍎", "description": "Apple", "unicode": "U+1F34E"}, + {"number": 25, "emoji": "🍓", "description": "Strawberry", "unicode": "U+1F353"}, + {"number": 26, "emoji": "🌽", "description": "Corn", "unicode": "U+1F33D"}, + {"number": 27, "emoji": "🍕", "description": "Pizza", "unicode": "U+1F355"}, + {"number": 28, "emoji": "🎂", "description": "Cake", "unicode": "U+1F382"}, + {"number": 29, "emoji": "❤️", "description": "Heart", "unicode": "U+2764U+FE0F"}, + {"number": 30, "emoji": "😀", "description": "Smiley", "unicode": "U+1F600"}, + {"number": 31, "emoji": "🤖", "description": "Robot", "unicode": "U+1F916"}, + {"number": 32, "emoji": "🎩", "description": "Hat", "unicode": "U+1F3A9"}, + {"number": 33, "emoji": "👓", "description": "Glasses", "unicode": "U+1F453"}, + {"number": 34, "emoji": "🔧", "description": "Spanner", "unicode": "U+1F527"}, + {"number": 35, "emoji": "🎅", "description": "Santa", "unicode": "U+1F385"}, + {"number": 36, "emoji": "👍", "description": "Thumbs Up", "unicode": "U+1F44D"}, + {"number": 37, "emoji": "☂️", "description": "Umbrella", "unicode": "U+2602U+FE0F"}, + {"number": 38, "emoji": "⌛", "description": "Hourglass", "unicode": "U+231B"}, + {"number": 39, "emoji": "⏰", "description": "Clock", "unicode": "U+23F0"}, + {"number": 40, "emoji": "🎁", "description": "Gift", "unicode": "U+1F381"}, + {"number": 41, "emoji": "💡", "description": "Light Bulb", "unicode": "U+1F4A1"}, + {"number": 42, "emoji": "📕", "description": "Book", "unicode": "U+1F4D5"}, + {"number": 43, "emoji": "✏️", "description": "Pencil", "unicode": "U+270FU+FE0F"}, + {"number": 44, "emoji": "📎", "description": "Paperclip", "unicode": "U+1F4CE"}, + {"number": 45, "emoji": "✂️", "description": "Scissors", "unicode": "U+2702U+FE0F"}, + {"number": 46, "emoji": "🔒", "description": "Lock", "unicode": "U+1F512"}, + {"number": 47, "emoji": "🔑", "description": "Key", "unicode": "U+1F511"}, + {"number": 48, "emoji": "🔨", "description": "Hammer", "unicode": "U+1F528"}, + {"number": 49, "emoji": "☎️", "description": "Telephone", "unicode": "U+260EU+FE0F"}, + {"number": 50, "emoji": "🏁", "description": "Flag", "unicode": "U+1F3C1"}, + {"number": 51, "emoji": "🚂", "description": "Train", "unicode": "U+1F682"}, + {"number": 52, "emoji": "🚲", "description": "Bicycle", "unicode": "U+1F6B2"}, + {"number": 53, "emoji": "✈️", "description": "Aeroplane", "unicode": "U+2708U+FE0F"}, + {"number": 54, "emoji": "🚀", "description": "Rocket", "unicode": "U+1F680"}, + {"number": 55, "emoji": "🏆", "description": "Trophy", "unicode": "U+1F3C6"}, + {"number": 56, "emoji": "⚽", "description": "Ball", "unicode": "U+26BD"}, + {"number": 57, "emoji": "🎸", "description": "Guitar", "unicode": "U+1F3B8"}, + {"number": 58, "emoji": "🎺", "description": "Trumpet", "unicode": "U+1F3BA"}, + {"number": 59, "emoji": "🔔", "description": "Bell", "unicode": "U+1F514"}, + {"number": 60, "emoji": "⚓", "description": "Anchor", "unicode": "U+2693"}, + {"number": 61, "emoji": "🎧", "description": "Headphones", "unicode": "U+1F3A7"}, + {"number": 62, "emoji": "📁", "description": "Folder", "unicode": "U+1F4C1"}, + {"number": 63, "emoji": "📌", "description": "Pin", "unicode": "U+1F4CC"} +] diff --git a/event-schemas/check_examples.py b/event-schemas/check_examples.py index 3e536ec3b..31daa4783 100755 --- a/event-schemas/check_examples.py +++ b/event-schemas/check_examples.py @@ -106,14 +106,17 @@ def check_example_dir(exampledir, schemadir): if filename.startswith("."): # Skip over any vim .swp files. continue + if filename.endswith(".json"): + # Skip over any explicit examples (partial event definitions) + continue cwd = os.path.basename(os.path.dirname(os.path.join(root, filename))) if cwd == "core": # Skip checking the underlying definitions continue examplepath = os.path.join(root, filename) schemapath = examplepath.replace(exampledir, schemadir) - if schemapath.find("#") >= 0: - schemapath = schemapath[:schemapath.find("#")] + if schemapath.find("$") >= 0: + schemapath = schemapath[:schemapath.find("$")] try: check_example_file(examplepath, schemapath) except Exception as e: diff --git a/event-schemas/examples/invite_room_state.json b/event-schemas/examples/invite_room_state.json new file mode 100644 index 000000000..9d8c1b2bf --- /dev/null +++ b/event-schemas/examples/invite_room_state.json @@ -0,0 +1,18 @@ +[ + { + "type": "m.room.name", + "sender": "@bob:example.org", + "state_key": "", + "content": { + "name": "Example Room" + } + }, + { + "type": "m.room.join_rules", + "sender": "@bob:example.org", + "state_key": "", + "content": { + "join_rule": "invite" + } + } +] diff --git a/event-schemas/examples/m.dummy b/event-schemas/examples/m.dummy new file mode 100644 index 000000000..0cd39166f --- /dev/null +++ b/event-schemas/examples/m.dummy @@ -0,0 +1,4 @@ +{ + "content": {}, + "type": "m.dummy" +} diff --git a/event-schemas/examples/m.key.verification.accept b/event-schemas/examples/m.key.verification.accept new file mode 100644 index 000000000..98e89c06e --- /dev/null +++ b/event-schemas/examples/m.key.verification.accept @@ -0,0 +1,12 @@ +{ + "type": "m.key.verification.accept", + "content": { + "transaction_id": "S0meUniqueAndOpaqueString", + "method": "m.sas.v1", + "key_agreement_protocol": "curve25519", + "hash": "sha256", + "message_authentication_code": "hkdf-hmac-sha256", + "short_authentication_string": ["decimal", "emoji"], + "commitment": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } +} diff --git a/event-schemas/examples/m.key.verification.cancel b/event-schemas/examples/m.key.verification.cancel new file mode 100644 index 000000000..9d78f67c5 --- /dev/null +++ b/event-schemas/examples/m.key.verification.cancel @@ -0,0 +1,8 @@ +{ + "type": "m.key.verification.cancel", + "content": { + "transaction_id": "S0meUniqueAndOpaqueString", + "code": "m.user", + "reason": "User rejected the key verification request" + } +} diff --git a/event-schemas/examples/m.key.verification.key b/event-schemas/examples/m.key.verification.key new file mode 100644 index 000000000..608a2ebd3 --- /dev/null +++ b/event-schemas/examples/m.key.verification.key @@ -0,0 +1,7 @@ +{ + "type": "m.key.verification.key", + "content": { + "transaction_id": "S0meUniqueAndOpaqueString", + "key": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } +} diff --git a/event-schemas/examples/m.key.verification.mac b/event-schemas/examples/m.key.verification.mac new file mode 100644 index 000000000..c77c3a8d9 --- /dev/null +++ b/event-schemas/examples/m.key.verification.mac @@ -0,0 +1,10 @@ +{ + "type": "m.key.verification.mac", + "content": { + "transaction_id": "S0meUniqueAndOpaqueString", + "keys": "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA", + "mac": { + "ed25519:ABCDEF": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } + } +} diff --git a/event-schemas/examples/m.key.verification.request b/event-schemas/examples/m.key.verification.request new file mode 100644 index 000000000..258471d29 --- /dev/null +++ b/event-schemas/examples/m.key.verification.request @@ -0,0 +1,11 @@ +{ + "type": "m.key.verification.request", + "content": { + "from_device": "AliceDevice2", + "transaction_id": "S0meUniqueAndOpaqueString", + "methods": [ + "m.sas.v1" + ], + "timestamp": 1559598944869 + } +} diff --git a/event-schemas/examples/m.key.verification.start b/event-schemas/examples/m.key.verification.start new file mode 100644 index 000000000..52f16150f --- /dev/null +++ b/event-schemas/examples/m.key.verification.start @@ -0,0 +1,8 @@ +{ + "type": "m.key.verification.start", + "content": { + "from_device": "BobDevice1", + "transaction_id": "S0meUniqueAndOpaqueString", + "method": "m.sas.v1" + } +} diff --git a/event-schemas/examples/m.key.verification.start$m.sas.v1 b/event-schemas/examples/m.key.verification.start$m.sas.v1 new file mode 100644 index 000000000..dae1d4053 --- /dev/null +++ b/event-schemas/examples/m.key.verification.start$m.sas.v1 @@ -0,0 +1,12 @@ +{ + "type": "m.key.verification.start", + "content": { + "from_device": "BobDevice1", + "transaction_id": "S0meUniqueAndOpaqueString", + "method": "m.sas.v1", + "key_agreement_protocols": ["curve25519"], + "hashes": ["sha256"], + "message_authentication_codes": ["hkdf-hmac-sha256"], + "short_authentication_string": ["decimal", "emoji"] + } +} diff --git a/event-schemas/examples/m.room.encrypted#megolm b/event-schemas/examples/m.room.encrypted$megolm similarity index 100% rename from event-schemas/examples/m.room.encrypted#megolm rename to event-schemas/examples/m.room.encrypted$megolm diff --git a/event-schemas/examples/m.room.encrypted#olm b/event-schemas/examples/m.room.encrypted$olm similarity index 100% rename from event-schemas/examples/m.room.encrypted#olm rename to event-schemas/examples/m.room.encrypted$olm diff --git a/event-schemas/examples/m.room.member#invite_room_state b/event-schemas/examples/m.room.member#invite_room_state deleted file mode 100644 index f8f05484c..000000000 --- a/event-schemas/examples/m.room.member#invite_room_state +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$ref": "m.room.member", - "content": { - "membership": "invite", - "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF#auto", - "displayname": "Alice Margatroid" - }, - "unsigned": { - "age": 1234, - "invite_room_state": [ - { - "type": "m.room.name", - "state_key": "", - "content": { - "name": "Forest of Magic" - } - }, - { - "type": "m.room.join_rules", - "state_key": "", - "content": { - "join_rule": "invite" - } - } - ] - } -} diff --git a/event-schemas/examples/m.room.member$invite_room_state b/event-schemas/examples/m.room.member$invite_room_state new file mode 100644 index 000000000..2c93eb9b0 --- /dev/null +++ b/event-schemas/examples/m.room.member$invite_room_state @@ -0,0 +1,14 @@ +{ + "$ref": "m.room.member", + "content": { + "membership": "invite", + "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF#auto", + "displayname": "Alice Margatroid" + }, + "unsigned": { + "age": 1234, + "invite_room_state": { + "$ref": "invite_room_state.json" + } + } +} diff --git a/event-schemas/examples/m.room.member#third_party_invite b/event-schemas/examples/m.room.member$third_party_invite similarity index 100% rename from event-schemas/examples/m.room.member#third_party_invite rename to event-schemas/examples/m.room.member$third_party_invite diff --git a/event-schemas/examples/m.room.message#m.audio b/event-schemas/examples/m.room.message$m.audio similarity index 99% rename from event-schemas/examples/m.room.message#m.audio rename to event-schemas/examples/m.room.message$m.audio index 2f743d49e..58e874e0c 100644 --- a/event-schemas/examples/m.room.message#m.audio +++ b/event-schemas/examples/m.room.message$m.audio @@ -11,4 +11,4 @@ }, "msgtype": "m.audio" } -} +} diff --git a/event-schemas/examples/m.room.message#m.emote b/event-schemas/examples/m.room.message$m.emote similarity index 100% rename from event-schemas/examples/m.room.message#m.emote rename to event-schemas/examples/m.room.message$m.emote diff --git a/event-schemas/examples/m.room.message#m.file b/event-schemas/examples/m.room.message$m.file similarity index 100% rename from event-schemas/examples/m.room.message#m.file rename to event-schemas/examples/m.room.message$m.file diff --git a/event-schemas/examples/m.room.message#m.image b/event-schemas/examples/m.room.message$m.image similarity index 100% rename from event-schemas/examples/m.room.message#m.image rename to event-schemas/examples/m.room.message$m.image diff --git a/event-schemas/examples/m.room.message#m.location b/event-schemas/examples/m.room.message$m.location similarity index 100% rename from event-schemas/examples/m.room.message#m.location rename to event-schemas/examples/m.room.message$m.location diff --git a/event-schemas/examples/m.room.message#m.notice b/event-schemas/examples/m.room.message$m.notice similarity index 100% rename from event-schemas/examples/m.room.message#m.notice rename to event-schemas/examples/m.room.message$m.notice diff --git a/event-schemas/examples/m.room.message$m.server_notice b/event-schemas/examples/m.room.message$m.server_notice new file mode 100644 index 000000000..0eb44ea7f --- /dev/null +++ b/event-schemas/examples/m.room.message$m.server_notice @@ -0,0 +1,11 @@ +{ + "$ref": "core/room_event.json", + "type": "m.room.message", + "content": { + "body": "Human-readable message to explain the notice", + "msgtype": "m.server_notice", + "server_notice_type": "m.server_notice.usage_limit_reached", + "admin_contact": "mailto:server.admin@example.org", + "limit_type": "monthly_active_user" + } +} diff --git a/event-schemas/examples/m.room.message#m.text b/event-schemas/examples/m.room.message$m.text similarity index 100% rename from event-schemas/examples/m.room.message#m.text rename to event-schemas/examples/m.room.message$m.text diff --git a/event-schemas/examples/m.room.message#m.video b/event-schemas/examples/m.room.message$m.video similarity index 100% rename from event-schemas/examples/m.room.message#m.video rename to event-schemas/examples/m.room.message$m.video diff --git a/event-schemas/examples/m.room_key_request#cancel_request b/event-schemas/examples/m.room_key_request$cancel_request similarity index 100% rename from event-schemas/examples/m.room_key_request#cancel_request rename to event-schemas/examples/m.room_key_request$cancel_request diff --git a/event-schemas/examples/m.room_key_request#request b/event-schemas/examples/m.room_key_request$request similarity index 100% rename from event-schemas/examples/m.room_key_request#request rename to event-schemas/examples/m.room_key_request$request diff --git a/event-schemas/schema/m.call.hangup b/event-schemas/schema/m.call.hangup index 9d45d179a..c0478f5a7 100644 --- a/event-schemas/schema/m.call.hangup +++ b/event-schemas/schema/m.call.hangup @@ -15,6 +15,14 @@ "version": { "type": "integer", "description": "The version of the VoIP specification this message adheres to. This specification is version 0." + }, + "reason": { + "type": "string", + "description": "Optional error reason for the hangup. This should not be provided when the user naturally ends or rejects the call. When there was an error in the call negotiation, this should be ``ice_failed`` for when ICE negotiation fails or ``invite_timeout`` for when the other party did not answer in time.", + "enum": [ + "ice_failed", + "invite_timeout" + ] } }, "required": ["call_id", "version"] diff --git a/event-schemas/schema/m.call.invite b/event-schemas/schema/m.call.invite index ebf09267b..65796e1e9 100644 --- a/event-schemas/schema/m.call.invite +++ b/event-schemas/schema/m.call.invite @@ -10,7 +10,7 @@ "properties": { "call_id": { "type": "string", - "description": "A unique identifer for the call." + "description": "A unique identifier for the call." }, "offer": { "type": "object", diff --git a/event-schemas/schema/m.dummy b/event-schemas/schema/m.dummy new file mode 100644 index 000000000..8e4b6f944 --- /dev/null +++ b/event-schemas/schema/m.dummy @@ -0,0 +1,23 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + This event type is used to indicate new Olm sessions for end-to-end encryption. + Typically it is encrypted as an ``m.room.encrypted`` event, then sent as a `to-device`_ + event. + + The event does not have any content associated with it. The sending client is expected + to send a key share request shortly after this message, causing the receiving client to + process this ``m.dummy`` event as the most recent event and using the keyshare request + to set up the session. The keyshare request and ``m.dummy`` combination should result + in the original sending client receiving keys over the newly established session. +properties: + content: + properties: {} + type: object + type: + enum: + - m.dummy + type: string +type: object diff --git a/event-schemas/schema/m.key.verification.accept b/event-schemas/schema/m.key.verification.accept new file mode 100644 index 000000000..41c59968a --- /dev/null +++ b/event-schemas/schema/m.key.verification.accept @@ -0,0 +1,64 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + Accepts a previously sent ``m.key.verification.start`` messge. Typically sent as a + `to-device`_ event. +properties: + content: + properties: + transaction_id: + type: string + description: |- + An opaque identifier for the verification process. Must be the same as + the one used for the ``m.key.verification.start`` message. + method: + type: string + enum: ["m.sas.v1"] + description: |- + The verification method to use. + key_agreement_protocol: + type: string + description: |- + The key agreement protocol the device is choosing to use, out of the + options in the ``m.key.verification.start`` message. + hash: + type: string + description: |- + The hash method the device is choosing to use, out of the options in + the ``m.key.verification.start`` message. + message_authentication_code: + type: string + description: |- + The message authentication code the device is choosing to use, out of + the options in the ``m.key.verification.start`` message. + short_authentication_string: + type: array + description: |- + The SAS methods both devices involved in the verification process + understand. Must be a subset of the options in the ``m.key.verification.start`` + message. + items: + type: string + enum: ["decimal", "emoji"] + commitment: + type: string + description: |- + The hash (encoded as unpadded base64) of the concatenation of the device's + ephemeral public key (encoded as unpadded base64) and the canonical JSON + representation of the ``m.key.verification.start`` message. + required: + - transaction_id + - method + - key_agreement_protocol + - hash + - message_authentication_code + - short_authentication_string + - commitment + type: object + type: + enum: + - m.key.verification.accept + type: string +type: object diff --git a/event-schemas/schema/m.key.verification.cancel b/event-schemas/schema/m.key.verification.cancel new file mode 100644 index 000000000..36ffc9ea7 --- /dev/null +++ b/event-schemas/schema/m.key.verification.cancel @@ -0,0 +1,70 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + Cancels a key verification process/request. Typically sent as a `to-device`_ event. +properties: + content: + properties: + transaction_id: + type: string + description: |- + The opaque identifier for the verification process/request. + reason: + type: string + description: |- + A human readable description of the ``code``. The client should only rely on this + string if it does not understand the ``code``. + code: + type: string + # Note: this is not an enum because we go into detail about the different + # error codes. If we made this an enum, we'd be repeating information. + # Also, we can't put a real bulleted list in here because the HTML2RST parser + # cuts the text at weird points, breaking the list completely. + description: |- + The error code for why the process/request was cancelled by the user. Error + codes should use the Java package naming convention if not in the following + list: + + ``m.user``: The user cancelled the verification. + + ``m.timeout``: The verification process timed out. Verification processes + can define their own timeout parameters. + + ``m.unknown_transaction``: The device does not know about the given transaction + ID. + + ``m.unknown_method``: The device does not know how to handle the requested + method. This should be sent for ``m.key.verification.start`` messages and + messages defined by individual verification processes. + + ``m.unexpected_message``: The device received an unexpected message. Typically + raised when one of the parties is handling the verification out of order. + + ``m.key_mismatch``: The key was not verified. + + ``m.user_mismatch``: The expected user did not match the user verified. + + ``m.invalid_message``: The message received was invalid. + + ``m.accepted``: A ``m.key.verification.request`` was accepted by a different + device. The device receiving this error can ignore the verification request. + + Clients should be careful to avoid error loops. For example, if a device sends + an incorrect message and the client returns ``m.invalid_message`` to which it + gets an unexpected response with ``m.unexpected_message``, the client should not + respond again with ``m.unexpected_message`` to avoid the other device potentially + sending another error response. + + .. The above blank line is important for RST. + required: + - transaction_id + - code + - reason + type: object + type: + enum: + - m.key.verification.cancel + type: string +type: object diff --git a/event-schemas/schema/m.key.verification.key b/event-schemas/schema/m.key.verification.key new file mode 100644 index 000000000..6dc4954ba --- /dev/null +++ b/event-schemas/schema/m.key.verification.key @@ -0,0 +1,28 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + Sends the ephemeral public key for a device to the partner device. Typically sent as a + `to-device`_ event. +properties: + content: + properties: + transaction_id: + type: string + description: |- + An opaque identifier for the verification process. Must be the same as + the one used for the ``m.key.verification.start`` message. + key: + type: string + description: |- + The device's ephemeral public key, encoded as unpadded base64. + required: + - transaction_id + - key + type: object + type: + enum: + - m.key.verification.key + type: string +type: object diff --git a/event-schemas/schema/m.key.verification.mac b/event-schemas/schema/m.key.verification.mac new file mode 100644 index 000000000..769ebe150 --- /dev/null +++ b/event-schemas/schema/m.key.verification.mac @@ -0,0 +1,38 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + Sends the MAC of a device's key to the partner device. Typically sent as a + `to-device`_ event. +properties: + content: + properties: + transaction_id: + type: string + description: |- + An opaque identifier for the verification process. Must be the same as + the one used for the ``m.key.verification.start`` message. + mac: + type: object + description: |- + A map of the key ID to the MAC of the key, using the algorithm in the + verification process. The MAC is encoded as unpadded base64. + additionalProperties: + type: string + description: The key's MAC, encoded as unpadded base64. + keys: + type: string + description: |- + The MAC of the comma-separated, sorted, list of key IDs given in the ``mac`` + property, encoded as unpadded base64. + required: + - transaction_id + - mac + - keys + type: object + type: + enum: + - m.key.verification.mac + type: string +type: object diff --git a/event-schemas/schema/m.key.verification.request b/event-schemas/schema/m.key.verification.request new file mode 100644 index 000000000..c9efa14e9 --- /dev/null +++ b/event-schemas/schema/m.key.verification.request @@ -0,0 +1,43 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + Requests a key verification with another user's devices. Typically sent as a + `to-device`_ event. +properties: + content: + properties: + from_device: + type: string + description: |- + The device ID which is initiating the request. + transaction_id: + type: string + description: |- + An opaque identifier for the verification request. Must be unique + with respect to the devices involved. + methods: + type: array + description: |- + The verification methods supported by the sender. + items: + type: string + timestamp: + type: integer + format: int64 + description: |- + The POSIX timestamp in milliseconds for when the request was made. If + the request is in the future by more than 5 minutes or more than 10 + minutes in the past, the message should be ignored by the receiver. + required: + - from_device + - transaction_id + - methods + - timestamp + type: object + type: + enum: + - m.key.verification.request + type: string +type: object diff --git a/event-schemas/schema/m.key.verification.start b/event-schemas/schema/m.key.verification.start new file mode 100644 index 000000000..ad59d6c7f --- /dev/null +++ b/event-schemas/schema/m.key.verification.start @@ -0,0 +1,39 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + Begins a key verification process. Typically sent as a `to-device`_ event. +properties: + content: + properties: + from_device: + type: string + description: |- + The device ID which is initiating the process. + transaction_id: + type: string + description: |- + An opaque identifier for the verification process. Must be unique + with respect to the devices involved. Must be the same as the + ``transaction_id`` given in the ``m.key.verification.request`` + if this process is originating from a request. + method: + type: string + description: |- + The verification method to use. + next_method: + type: string + description: |- + Optional method to use to verify the other user's key with. Applicable + when the ``method`` chosen only verifies one user's key. + required: + - from_device + - transaction_id + - method + type: object + type: + enum: + - m.key.verification.start + type: string +type: object diff --git a/event-schemas/schema/m.key.verification.start$m.sas.v1 b/event-schemas/schema/m.key.verification.start$m.sas.v1 new file mode 100644 index 000000000..867ca8208 --- /dev/null +++ b/event-schemas/schema/m.key.verification.start$m.sas.v1 @@ -0,0 +1,69 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml + +description: |- + Begins a SAS key verification process. Typically sent as a `to-device`_ event. +properties: + content: + properties: + from_device: + type: string + description: |- + The device ID which is initiating the process. + transaction_id: + type: string + description: |- + An opaque identifier for the verification process. Must be unique + with respect to the devices involved. Must be the same as the + ``transaction_id`` given in the ``m.key.verification.request`` + if this process is originating from a request. + method: + type: string + enum: ["m.sas.v1"] + description: |- + The verification method to use. Must be ``m.sas.v1``. + key_agreement_protocols: + type: array + description: |- + The key agreement protocols the sending device understands. Must + include at least ``curve25519``. + items: + type: string + hashes: + type: array + description: |- + The hash methods the sending device understands. Must include at least + ``sha256``. + items: + type: string + message_authentication_codes: + type: array + description: |- + The message authentication codes that the sending device understands. + Must include at least ``hkdf-hmac-sha256``. + items: + type: string + short_authentication_string: + type: array + description: |- + The SAS methods the sending device (and the sending device's user) + understands. Must include at least ``decimal``. Optionally can include + ``emoji``. + items: + type: string + enum: ["decimal", "emoji"] + required: + - from_device + - transaction_id + - method + - key_agreement_protocols + - hashes + - message_authentication_codes + - short_authentication_string + type: object + type: + enum: + - m.key.verification.start + type: string +type: object diff --git a/event-schemas/schema/m.room.member b/event-schemas/schema/m.room.member index de14644d4..1033c098d 100644 --- a/event-schemas/schema/m.room.member +++ b/event-schemas/schema/m.room.member @@ -21,6 +21,29 @@ description: |- This event may also include an ``invite_room_state`` key inside the event's ``unsigned`` data. If present, this contains an array of ``StrippedState`` Events. These events provide information on a subset of state events such as the room name. + + The user for which a membership applies is represented by the ``state_key``. Under some conditions, + the ``sender`` and ``state_key`` may not match - this may be interpreted as the ``sender`` affecting + the membership state of the ``state_key`` user. + + The ``membership`` for a given user can change over time. The table below represents the various changes + over time and how clients and servers must interpret those changes. Previous membership can be retrieved + from the ``prev_content`` object on an event. If not present, the user's previous membership must be assumed + as ``leave``. + + .. TODO: Improve how this table is written? We use a csv-table to get around vertical header restrictions. + + .. csv-table:: + :header-rows: 1 + :stub-columns: 1 + + "","to ``invite``","to ``join``","to ``leave``","to ``ban``","to ``knock``" + "from ``invite``","No change.","User joined the room.","If the ``state_key`` is the same as the ``sender``, the user rejected the invite. Otherwise, the ``state_key`` user had their invite revoked.","User was banned.","Not implemented." + "from ``join``","Must never happen.","``displayname`` or ``avatar_url`` changed.","If the ``state_key`` is the same as the ``sender``, the user left. Otherwise, the ``state_key`` user was kicked.","User was kicked and banned.","Not implemented." + "from ``leave``","New invitation sent.","User joined.","No change.","User was banned.","Not implemented." + "from ``ban``","Must never happen.","Must never happen.","User was unbanned.","No change.","Not implemented." + "from ``knock``","Not implemented.","Not implemented.","Not implemented.","Not implemented.","Not implemented." + properties: content: properties: @@ -81,24 +104,7 @@ properties: invite_room_state: description: 'A subset of the state of the room at the time of the invite, if ``membership`` is ``invite``. Note that this state is informational, and SHOULD NOT be trusted; once the client has joined the room, it SHOULD fetch the live state from the server and discard the invite_room_state. Also, clients must not rely on any particular state being present here; they SHOULD behave properly (with possibly a degraded but not a broken experience) in the absence of any particular events here. If they are set on the room, at least the state for ``m.room.avatar``, ``m.room.canonical_alias``, ``m.room.join_rules``, and ``m.room.name`` SHOULD be included.' items: - description: 'A stripped down state event, with only the ``type``, ``state_key`` and ``content`` keys.' - properties: - content: - description: The ``content`` for the event. - title: EventContent - type: object - state_key: - description: The ``state_key`` for the event. - type: string - type: - description: The ``type`` for the event. - type: string - required: - - type - - state_key - - content - title: StrippedState - type: object + $ref: "stripped_state.yaml" type: array required: - membership diff --git a/event-schemas/schema/m.room.message#m.audio b/event-schemas/schema/m.room.message$m.audio similarity index 99% rename from event-schemas/schema/m.room.message#m.audio rename to event-schemas/schema/m.room.message$m.audio index c258b85f5..99e281107 100644 --- a/event-schemas/schema/m.room.message#m.audio +++ b/event-schemas/schema/m.room.message$m.audio @@ -38,6 +38,7 @@ properties: required: - msgtype - body + - url type: object type: enum: diff --git a/event-schemas/schema/m.room.message#m.emote b/event-schemas/schema/m.room.message$m.emote similarity index 100% rename from event-schemas/schema/m.room.message#m.emote rename to event-schemas/schema/m.room.message$m.emote diff --git a/event-schemas/schema/m.room.message#m.file b/event-schemas/schema/m.room.message$m.file similarity index 99% rename from event-schemas/schema/m.room.message#m.file rename to event-schemas/schema/m.room.message$m.file index 2fb4fe500..2389d8a9e 100644 --- a/event-schemas/schema/m.room.message#m.file +++ b/event-schemas/schema/m.room.message$m.file @@ -53,7 +53,7 @@ properties: required: - msgtype - body - - filename + - url type: object type: enum: diff --git a/event-schemas/schema/m.room.message#m.image b/event-schemas/schema/m.room.message$m.image similarity index 98% rename from event-schemas/schema/m.room.message#m.image rename to event-schemas/schema/m.room.message$m.image index 349f78f40..1e6ebeaa3 100644 --- a/event-schemas/schema/m.room.message#m.image +++ b/event-schemas/schema/m.room.message$m.image @@ -28,6 +28,7 @@ properties: required: - msgtype - body + - url type: object type: enum: diff --git a/event-schemas/schema/m.room.message#m.location b/event-schemas/schema/m.room.message$m.location similarity index 100% rename from event-schemas/schema/m.room.message#m.location rename to event-schemas/schema/m.room.message$m.location diff --git a/event-schemas/schema/m.room.message#m.notice b/event-schemas/schema/m.room.message$m.notice similarity index 100% rename from event-schemas/schema/m.room.message#m.notice rename to event-schemas/schema/m.room.message$m.notice diff --git a/event-schemas/schema/m.room.message$m.server_notice b/event-schemas/schema/m.room.message$m.server_notice new file mode 100644 index 000000000..f18488218 --- /dev/null +++ b/event-schemas/schema/m.room.message$m.server_notice @@ -0,0 +1,39 @@ +--- +allOf: + - $ref: core-event-schema/room_event.yaml +description: Represents a server notice for a user. +properties: + content: + properties: + body: + description: A human-readable description of the notice. + type: string + msgtype: + enum: + - m.server_notice + type: string + server_notice_type: + description: |- + The type of notice being represented. + type: string + admin_contact: + description: |- + A URI giving a contact method for the server administrator. Required if the + notice type is ``m.server_notice.usage_limit_reached``. + type: string + limit_type: + description: |- + The kind of usage limit the server has exceeded. Required if the notice type is + ``m.server_notice.usage_limit_reached``. + type: string + required: + - msgtype + - body + - server_notice_type + type: object + type: + enum: + - m.room.message + type: string +title: ServerNoticeMessage +type: object diff --git a/event-schemas/schema/m.room.message#m.text b/event-schemas/schema/m.room.message$m.text similarity index 100% rename from event-schemas/schema/m.room.message#m.text rename to event-schemas/schema/m.room.message$m.text diff --git a/event-schemas/schema/m.room.message#m.video b/event-schemas/schema/m.room.message$m.video similarity index 99% rename from event-schemas/schema/m.room.message#m.video rename to event-schemas/schema/m.room.message$m.video index 8a66fdeb5..2da7e0bc9 100644 --- a/event-schemas/schema/m.room.message#m.video +++ b/event-schemas/schema/m.room.message$m.video @@ -59,6 +59,7 @@ properties: required: - msgtype - body + - url type: object type: enum: diff --git a/event-schemas/schema/stripped_state.yaml b/event-schemas/schema/stripped_state.yaml new file mode 100644 index 000000000..ec591bf15 --- /dev/null +++ b/event-schemas/schema/stripped_state.yaml @@ -0,0 +1,44 @@ +# Copyright 2019 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. + +# Note: this, and the example, are in the `event-schemas` directory because +# the CS API uses a symlink. In order for the `m.room.member` event to +# reference this, we'd need to use relative pathing. The symlink makes this +# difficult because the schema would be at two different locations, with +# different relative pathing. + +title: StrippedState +type: object +description: |- + A stripped down state event, with only the ``type``, ``state_key``, + ``sender``, and ``content`` keys. +properties: + content: + description: The ``content`` for the event. + title: EventContent + type: object + state_key: + description: The ``state_key`` for the event. + type: string + type: + description: The ``type`` for the event. + type: string + sender: + description: The ``sender`` for the event. + type: string +required: + - type + - state_key + - content + - sender diff --git a/jenkins.sh b/jenkins.sh deleted file mode 100755 index 79b77acb5..000000000 --- a/jenkins.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec ./scripts/test-and-build.sh diff --git a/proposals/1704-matrix.to-permalinks.md b/proposals/1704-matrix.to-permalinks.md index 1430565cf..7e1a2b28d 100644 --- a/proposals/1704-matrix.to-permalinks.md +++ b/proposals/1704-matrix.to-permalinks.md @@ -33,4 +33,7 @@ is to pick up to 3 unique servers where the first one is that of the user with t highest power level in the room, provided that power level is 50 or higher. The other 2 servers should be the most popular servers in the room based on the number of joined users. This same heuristic should apply to the first server if no user meets the power -level requirements. +level requirements. Servers blocked by server ACLs should not be picked because they +are unlikely to continue being residents of the room. Similarly, IP addresses should +not be picked because they cannot be redirected to another location like domain names +can, making them a higher risk option. diff --git a/proposals/1717-key_verification.md b/proposals/1717-key_verification.md new file mode 100644 index 000000000..429e3a97b --- /dev/null +++ b/proposals/1717-key_verification.md @@ -0,0 +1,167 @@ +# Key verification mechanisms + +Key verification is an essential part of ensuring that end-to-end encrypted +messages are secure. Matrix may support multiple verification methods that +require sending events; in fact, two such methods (such as [MSC +1267](https://github.com/matrix-org/matrix-doc/issues/1267) and [MSC +1543](https://github.com/matrix-org/matrix-doc/issues/1543)) have already been +proposed. + +This proposal tries to present a common framework for verification methods to +use, and presents a way to request key verification. + +## Proposal + +Each key verification method is identified by a name. Verification method +names defined in the Matrix spec will begin with `m.`, and verification method +names that are not defined in the Matrix spec must be namespaced following the +Java package naming convention. + +If Alice wants to verify keys with Bob, Alice's device may send `to_device` +events to Bob's devices with the `type` set to `m.key.verification.request`, as +described below. The `m.key.verification.request` messages should all have the +same `transaction_id`, and are considered to be a single request. Thus, for +example, if Bob rejects the request on one device, then the entire request +should be considered as rejected across all of his devices. Similarly, if Bob +accepts the request on one device, that device is now in charge of completing +the key verification, and Bob's other devices no longer need to be involved. + +The `m.key.verification.request` event lists the verification methods that +Alice's device supports, and upon receipt of this message, Bob's client should +prompt him to verify keys with Alice using one of the applicable methods. In +order to avoid displaying stale key verification prompts, if Bob does not +interact with the prompt, it should be automatically hidden 10 minutes after +the message is sent (according to the `timestamp` field), or 2 minutes after +the client receives the message, whichever comes first. The prompt should also +be hidden if an appropriate `m.key.verification.cancel` message is received. + +If Bob chooses to reject the key verification request, Bob's client should send +a `m.key.verification.cancel` message to Alice's device. This indicates to +Alice that Bob does not wish to verify keys with her. In this case, Alice's +device should send an `m.key.verification.cancel` message to all of Bob's +devices to notify them that the request has been rejected. + +If one of Bob's clients does not understand any of the methods offered, it +should display a message to Bob saying so. However, it should not send a +`m.key.verification.cancel` message to Alice's device unless Bob chooses to +reject the verification request, as Bob may have another device that is capable +of verifying using one of the given methods. + +To initiate a key verification process, Bob's device sends a `to_device` event +to one of Alice's devices with the `type` set to `m.key.verification.start`. +This may either be done in response to an `m.key.verification.request` message, +or can be done independently. If it is done in response to an +`m.key.verification.request` messsage, it should use the same `transaction_id` +as the `m.key.verification.request` message. If Alice's device receives an +`m.key.verification.start` message in response to an +`m.key.verification.request` message, it should send an +`m.key.verification.cancel` message to Bob's other devices that it had +originally sent an `m.key.verification.request` to, in order to cancel the key +verification request. + +Verification methods can define other events required to complete the +verification. Event types for verification methods defined in the Matrix spec +should be in the `m.key.verification` namespace. Event types that are not +defined in the Matrix spec must be namespaced following the Java package naming +convention. + +Alice's or Bob's devices can cancel a key verification process or a key +verification request by sending a `to_device` event with `type` set to +`m.key.verification.cancel`. + +### Event Definitions + +#### `m.key.verification.request` + +Requests a key verification. + +Properties: + +- `from_device` (string): Required. The device ID of the device requesting + verification. +- `transaction_id` (string): Required. An identifier for the verification + request. Must be unique with respect to the pair of devices. +- `methods` ([string]): Required. The verification methods supported by the + sender. +- `timestamp` (integer): Required. The time when the request was made. If the + timestamp is in the future (by more than 5 minutes, to allow for clock skew), + or more than 10 minutes in the past, then the message must be ignored. + +#### `m.key.verification.start` + +Begins a key verification process. + +Properties: + +- `method` (string): Required. The verification method to use. +- `from_device` (string): Required. The device ID of the device starting the + verification process. +- `transaction_id` (string): Required. An identifier for the verification + process. If this message is sent in reponse to an + `m.key.verification.request` event, then it must use the same + `transaction_id` as the one given in the `m.key.verification.request`. +- `next_method` (string): Optional. If the selected verification method only + verifies one user's key, then this property can be used to indicate the + method to use to verify the other user's key, which will be started + immediately after after the current key verification is complete. + +Key verification methods can define additional properties to be included. + +#### `m.key.verification.cancel` + +Cancels a key verification process or a key verification request. Upon +receiving an `m.key.verification.cancel` message, the receiving device must +cancel the verification or the request. If it is a verification process that +is cancelled, or a verification request initiated by the recipient of the +cancellation message, the device should inform the user of the reason. + +Properties: + +- `transaction_id` (string): the identifier for the request or key verification + to cancel. +- `code` (string): machine-readable reason for cancelling. Possible reasons + are: + - `m.user`: the user cancelled the verification. + - `m.timeout`: the verification process has timed out. Different verification + methods may define their own timeouts. + - `m.unknown_transaction`: the device does not know about the given transaction + ID. + - `m.unknown_method`: the device does not know how to handle the given method. + This can be sent in response to an `m.key.verification.start` message, or + can be sent in response to other verification method-specific messages. + - `m.unexpected_message`: the device received an unexpected message. For + example, a message for a verification method may have been received when it + was not expected. + - `m.key_mismatch`: the key was not verified. + - `m.user_mismatch`: the expected user did not match the user verified. + - `m.invalid_message`: an invalid message was received. + - `m.accepted`: when an `m.key.verification.request` is accepted by one + device, an `m.key.verification.cancel` message with `code` set to + `m.accepted` is sent to the other devices +- `reason` (string): human-readable reason for cancelling. This should only be + used if the recieving client does not understand the code given in the `code` + property. + +Verification methods may define their own additional cancellation codes. +Cancellation codes defined in the Matrix spec will begin with `m.`; other +cancellation codes must be namespaced following the Java package naming +convention. + +## Tradeoffs + +Rather than broadcasting verification requests to Bob's devices, Alice could +simply send an `m.key.verification.start` request to a single device. However, +this would require Alice to choose the right device to send to, which may be +hard for Alice to do if, for example, Bob has many devices, or if his devices +have similar names. + +## Security considerations + +An attacker could try to spam a user with verification requests. Clients +should take care that such requests do not interfere with a user's use of the +client. + +## Conclusion + +This proposal presents common event definitions for use by key verification +methods and defines a way for users to request key verification. diff --git a/proposals/1719-olm_unwedging.md b/proposals/1719-olm_unwedging.md new file mode 100644 index 000000000..dffdc8b19 --- /dev/null +++ b/proposals/1719-olm_unwedging.md @@ -0,0 +1,59 @@ +# Olm unwedging + +Olm sessions sometimes get out of sync, resulting in undecryptable messages. +This can happen for several reasons. For example, if a user restores their +client state from a backup, the client will be using an old ratchet state +([riot-web#3822](https://github.com/vector-im/riot-web/issues/3822)). Or a +client might expire a one-time key that another client is trying to use +([riot-web#3309](https://github.com/vector-im/riot-web/issues/3309)). This +proposal documents a method for devices to create a new session to replace the +broken session. + +## Proposal + +When a device receives an olm-encrypted message that it cannot decrypt, it +should assume that the olm session has become corrupted and create a new olm +session to replace it. It should then send a dummy message, using that +session, to the other party in order to inform them of the new session. To +send a dummy message, clients may send an event with type `m.dummy`, and with +empty contents. + +In order to avoid creating too many extra sessions, a client should rate-limit +the number of new sessions it creates per device that it receives a message +from; the client should not create a new session with another device if it has +already created one for that given device in the past 1 hour. + +Clients may wish to take steps to mitigate the loss of the undecryptable +messages. For example, megolm sessions that were sent using the old session +would have been lost, so the client can send +[`m.room_key_request`](https://matrix.org/docs/spec/client_server/latest.html#m-room-key-request) +messages to re-request any megolm sessions that it is unable to decrypt. + +The spec currently says, "If a client has multiple sessions established with +another device, it should use the session from which it last received a +message." (the last paragraph of the [`m.olm.v1.curve25519-aes-sha2` +section](https://matrix.org/docs/spec/client_server/r0.4.0.html#m-olm-v1-curve25519-aes-sha2)). +When comparing the time of the last received message for each session, the +client should only consider messages that were successfully decrypted, +and for sessions that have never received a message, it should use the creation +time of the session. The spec will be changed to read: + +> If a client has multiple sessions established with another device, it should +> use the session from which it last received and successfully decrypted a +> message. For these purposes, a session that has not received any messages +> should use its creation time as the time that it last received a message. + +## Tradeoffs + +## Potential issues + +## Security considerations + +An attacker could use this to create a new session on a device that they are +able to read. However, this would require the attacker to have compromised the +device's keys. + +## Conclusion + +This proposal outlines how wedged olm sessions can be replaced by a new +session. diff --git a/proposals/1884-replace-slashes-in-event_ids.md b/proposals/1884-replace-slashes-in-event_ids.md new file mode 100644 index 000000000..bec8d7adc --- /dev/null +++ b/proposals/1884-replace-slashes-in-event_ids.md @@ -0,0 +1,166 @@ +# MSC1884: Proposal to replace slashes in event IDs + +[MSC1659](https://github.com/matrix-org/matrix-doc/pull/1659) mandated that, +starting in version 3 rooms, event IDs must be calculated as a base64-encoding +of a hash. This implies that event IDs may contain any character in the +standard Base64 alphabet, which notably includes the slash character, `/`. + +Event IDs are often embedded in URI paths, and since the slash character is +used as a separator in URI paths, this presents a problem. The immediate +solution is to ensure that event IDs are URL-encoded, so that `/` is instead +represented as `%2F`. However, this is not entirely satisfactory for a number +of reasons: + + * The act of escaping and unescaping slash characters when manually calling + the API during devops work becomes an constant and annoying chore which + is entirely avoidable. Whenever using tools like `curl` and `grep` or + manipulating SQL, developers will have to constantly keep in mind whether + they are dealing with escaped or unescaped IDs, and manually convert between + the two as needed. This will only get worse with further keys-as-IDs + landing with MSC1228. + + * There exist a number of client (and possibly server) implementations which + do not currently URL-encode such parameters; these are therefore broken by + such event IDs and must be updated. Furthermore, all future client + implementers must remember to do the encoding correctly. + + * Even if client implementations do remember to URL-encode their parameters, + they may not do it correctly: many URL-encoding implementations may be + intended to encode parameters in the query-string (which can of course + contain literal slashes) rather than the path component. + + * Some proxy software may treat `%2F` specially: for instance, Apache, when + configured as a reverse-proxy, will reject requests for a path containing + `%2F` unless it is also configured with `nocanon`. Again this means that + existing setups will be broken by this change, and it is a trap for new + users of the software. + + * Cosmetically, URL-escaping base64 in otherwise-constant-length IDs results + in variable length IDs, making it harder to visually scan lists of IDs and + manipulate them in columnar form when doing devops work. + + * Those developing against the CS API might reasonably expect us to use + URL-safe identifiers in URLs where available, rather than deliberately + choosing non-URL-safe IDs, which could be seen as developer-unfriendly. + +## Proposal + +This MSC proposes that we should introduce a new room version, in which event +IDs are encoded using the [URL-safe Base64 +encoding](https://tools.ietf.org/html/rfc4648#section-5) (which uses `-` and +`_` as the 62nd and 63rd characters instead of `+` and `/`). + +We will then aim to use URL-safe Base64 encoding across Matrix in future, +such that typical CS API developers should be able to safely assume +that for all common cases (including upcoming MSC1228 identifiers) they should +use URL-safe Base64 when decoding base64 strings. + +The exception would be for E2EE data (device keys and signatures etc) which +currently use normal Base64 with no easy mechanism to migrate to a new encoding. +Given E2EE development is rare and requires expert skills, it seems acceptable +to expect E2EE developers to be able to use the right encoding without tripping +up significantly. + +Similarly, the S2S API could continue to use standard base64-encoded hashes and +signatures in the places it does today, given they are only exposed to S2S API +developers who are necessarily expert and should be able to correctly pick the +right encoding. + +## Counterarguments + +1. Inconsistency. Base64 encoding is used heavily elsewhere in the matrix + protocol and in all cases the standard encoding is used (though with some + variation as to the inclusion of padding characters). Further, SHA256 hashes + are used in a number of places and are universally included with standard, + unpadded Base64. + + Changing event IDs alone would therefore leave us with a confusing mix of + encodings. + + However, the current uses of standard Base64 encodings are not exposed to + common CS API developers, and so whilst this might be slightly confusing + for the minority of expert homeserver developers, the confusion does not + exist today for client developers (except those implementing E2EE). + Therefore it seems safe to standardise on URL-safe Base64 for identifiers + exposed to the client developers, who form by far the majority of the + Matrix ecosystem today, and expect as simple an API as possible. + + A potential extension would be to change *all* Base64 encodings to be + URL-safe. This would address the inconsistency. However, it feels like a + large job which would span the entire matrix ecosystem (far larger than + updating clients to URL-encode their URL prarameters), and again the + situation would be confusing while the transition was in progress. + +2. Incompleteness. Event IDs are certainly not the only identifier which can + contain slashes - Room aliases, Room IDs, Group IDs, User IDs [1], and state + keys can all contain slashes, as well as a number of identifiers whose + grammars are currently underspecified (eg transaction ids, event types, + device IDs). (Indeed, there was nothing preventing Event IDs from containing + slashes before room v3 - it just happened that Synapse used an algorithm + which didn't generate them). + + All of these other identifiers can appear in URLs in either or both the + client-server or server-server APIs, and all have the potential to cause + misbehaviour if software does not correctly URL-encode them. + + It can be argued that it is better for software to fail 50% of the time [2] + so that it can be fixed than it is to fail only on edge-cases or, worse, + when deliberately provoked by a malicious or "curious" actor. + + Of course, an alternative is to modify the grammars of all of these + identifiers to forbid slashes. + + The counter-counterargument to this is that it is of course best practice + for implementations is to URL-escape any IDs used in URLs, and human-selected + IDs such as Room aliases, Group IDs, Matrix user IDs etc apply an adequate + forcing function already to remind developers to do this. However, + it doesn't follow that we should then also deliberately pick URL-unsafe + encodings for machine-selected IDs - the argument that it is better for software + to fail 50% of the time to force a fix is irrelevant when the possibility + exists for the software to fail 0% of the time in the first place by picking + an identifier format which cannot fail. + +[1] Discussion remains open as to whether allowing slashes in User IDs was a +good idea. + +[2] 48% of random 32-byte sequences will contain a slash when Base64-encoded. + +## Alternatives + +An alternative would be to modify all REST endpoints to use query or body +parameters instead of path parameters. This would of course be a significant +and incompatible change, but it would also bring the benefit of solving a +common problem where forgetting to use `nocanon` in a reverse-proxy +configuration [breaks +federation](https://github.com/matrix-org/synapse/issues/3294) (though other +solutions to that are also possible). + +## Conclusion + +There are two main questions here: + + 1. Whether it's worth forcing CS API developers to juggle escaping of + machine-selected IDs during manual use of the API in order to remind them + to escape all variables in their URIs correctly when writing code. + + 2. Whether it's a significant problem for E2EE & SS API developers to have to + handle strings which are a mix of standard Base64 and URL-safe Base64 + encodings. + +Both of these are a subjective judgement call. + +Given we wish the CS API particularly to be as easy as possible for manual +use, it feels that we should find another way to encourage developers to +escape variables in their URLs in general - e.g. by recommending that +developers test their clients against a 'torture room' full of exotic IDs and +data, or by improving warnings in the spec... rather than (ab)using +machine-selected IDs as a reminder. + +Meanwhile, given we have many more people manually invoking the CS API than +developing on the SS or E2EE APIs, and we wish to make the CS API particularly +easy for developers to manually invoke, it feels we should not prioritise +consistency of encodings for SS/E2EE developers over the usability of the CS +API. + +Therefore, on balance, it seems plausible that changing the format of event IDs +does solve sufficient problems to make it desirable. diff --git a/proposals/1915-unbind-identity-server-param.md b/proposals/1915-unbind-identity-server-param.md index 053552f6f..5b7a1a505 100644 --- a/proposals/1915-unbind-identity-server-param.md +++ b/proposals/1915-unbind-identity-server-param.md @@ -27,7 +27,9 @@ known by the homeserver). The 200 response is a JSON object with an `id_server_unbind_result` field whose value is either `success` or `no-support`, where the latter indicates that the identity server (IS) does not support unbinding 3PIDs directly. If the identity -server returns an error then that should be returned to the client. +server returns an error then that should be returned to the client. If the homeserver +is unable to determine an `id_server` to use, it should return `no-support` for +the `id_server_unbind_result`. Example: @@ -55,12 +57,12 @@ from the given identity server. ### Identity Server 3PID Unbind API -Add `POST /_matrix/identity/api/v1/unbind` with `mxid` and `threepid` fields. +Add `POST /_matrix/identity/api/v1/3pid/unbind` with `mxid` and `threepid` fields. The `mxid` is the user's `user_id` and `threepid` is a dict with the usual `medium` and `address` fields. If the server returns a 400, 404 or 501 HTTP error code then the homeserver -should assume that the identity server doesn't support the `/unbind` API, unless +should assume that the identity server doesn't support the `/3pid/unbind` API, unless it returns a specific matrix error response (i.e. the body is a JSON object with `error` and `errcode` fields). @@ -73,7 +75,7 @@ The identity server should authenticate the request in one of two ways: Example: ``` -POST /_matrix/identity/api/v1/unbind HTTP/1.1 +POST /_matrix/identity/api/v1/3pid/unbind HTTP/1.1 { "mxid": "@foobar:example.com", diff --git a/proposals/1930-tombstone-notifications.md b/proposals/1930-tombstone-notifications.md new file mode 100644 index 000000000..715921aa4 --- /dev/null +++ b/proposals/1930-tombstone-notifications.md @@ -0,0 +1,40 @@ +# Proposal to add a default push rule for m.room.tombstone events + +Currently users are unaware of when a room becomes upgraded, leaving them potentially in the old room +without knowing until they visit the room again. By having a notification for when the room is upgraded, +users are able to ensure they are able to stay relevant in rooms by joining the upgraded room. + + +## Proposal + +A new default override rule is to be added which is similar to `@room` notifications: + +```json +{ + "rule_id": ".m.rule.tombstone", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.tombstone" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": true + } + ] +} +``` + + +## Tradeoffs + +Clients could calculate this on their own and show some sort of "room upgraded" notification instead, +however by doing it this way it means that all clients would need to be aware of room upgrades. Having +a default push rule means that clients get this notification for free. Clients which want a more diverse +UX can still do so by ignoring this push rule locally. diff --git a/proposals/1954-remove-prev_event-from-essential-keys-list.md b/proposals/1954-remove-prev_event-from-essential-keys-list.md new file mode 100644 index 000000000..735fac012 --- /dev/null +++ b/proposals/1954-remove-prev_event-from-essential-keys-list.md @@ -0,0 +1,77 @@ +# Remove prev_content from the essential keys list + +Matrix supports the concept of event redaction. The ability to redact rather +than delete is necessary because some events e.g. membership events are +essential to the protocol and _cannot_ be deleted. Therefore we do not delete +events outright and instead redact them. This involves removing all keys from +an event that are not required by the protocol. The stripped down event is +thereafter returned anytime a client or remote server requests it. + + +## Proposal + +[The redaction algorithm](https://matrix.org/docs/spec/client_server/r0.4.0.html#redactions) +defines which keys must be retained through a redaction. Currently it lists +```prev_content``` as a key to retain, though in practice there is no need to +do so at the protocol level. + +The proposal is simply to remove ```prev_content``` from the essential keys +list. + +Note: the inclusion of ```prev_content``` in the essential keys list was +unintentional and should be considered a spec bug. Synapse (and other server +implementations) have not implemented the bug and already omit +```prev_content``` from redacted events. + + +## Tradeoffs + +When sending events over federation the events are [hashed and +signed](https://matrix.org/docs/spec/server_server/unstable.html#adding-hashes-and-signatures-to-outgoing-events), +this involves operating not only on the original event but also the redacted +form of the event. The redacted hash and redacted signed event are necessary if +the event is ever redacted in future. As a result, any change of the essential +keys list must be managed carefully. If disparate servers implement different +versions of the redaction algorithm (for a given event) attempts to send the +event over federation will fail. + +We _could_ manage this change via room versioning and create a new room +version that implements this MSC. However, because the federation already +omits the ```prev_content``` key by convention, implementing this MSC only in +the new room version would mean that the entire existing federation would not +be spec compliant. + +As a result it seems pragmatic to have the spec reflect reality, acknowledge +that the spec and federation have deviated and instead update the spec +retrospectively to describe the de-facto redaction algorithm. + +## Potential issues + +It is theoretically possible that a closed federation could exist whose servers +do follow the spec as is. This MSC would render those servers non-compliant with +the spec. On balance this seems unlikely and in the worst case those +implementors could add the change to a subsequent room version, eventually +reaching spec consistency as older room versions are deprecated. + +Another scenario is that a client may redact events according to the spec as is +and persist prev_content through the redaction, thereby diverting from that on +the server(s). Client authors will have to update their code to drop +```prev_content``` - however, given that prev_content should not be used in +important calculations and/or visualisations, this ought to be a relatively +non-invasive change. + + +## Security considerations + +A further reason to support removal of ```prev_content``` is the case where a +malicious user adds illegal or abusive content into a state event and then +overwrites that state event. The content would then be preserved through the +redaction. + +Additionally, there are plenty of reasons to have security concerns over a +precedent that the federation can deviate from the spec. + +## Conclusions +Removing ```prev_content``` is pragmatic response to the current situation. It +alligns the federation and the spec, and does so in a way that removes +unecessary overhead. diff --git a/proposals/2002-rooms-v4.md b/proposals/2002-rooms-v4.md new file mode 100644 index 000000000..defacee13 --- /dev/null +++ b/proposals/2002-rooms-v4.md @@ -0,0 +1,54 @@ +# MSC 2002 - Rooms V4 + +This MSC proposes creating a new room version named v4 to allow servers to switch +event ID grammar to that proposed in MSC1884. + +## Proposal + +The new room version is called "4". The only difference between v4 and v3 is +that v4 rooms use the grammar for defining event IDs as proposed in MSC1884 - +expressing event IDs as url-safe base64 rather than plain base64 for the +convenience of client implementors. + +It is not proposed that servers change the default room version used when +creating new rooms, and it is not proposed that servers recommend upgrading +existing rooms to v4. + +## Rationale and Context + +We would like to default to creating rooms with a reasonably secure room +algorithm in upcoming Matrix 1.0. We do not want to default to creating v3 +rooms due to the inconvenience the v3 event ID grammar might cause, so instead +we are proposing favouring v4. + +Ideally we would also include other room algorithm changes in v4 (e.g. +honouring server signing key validity periods, as per +https://github.com/matrix-org/synapse/issues/4364), but as spec & +implementation work is still ongoing there, we are proposing using v4 as a +room version which can be supported in the wild before Matrix 1.0 and then +used as the initial default for creating rooms. The expectation is for the +versions of the spec which coincide with 1.0 to also support v5 rooms, but in +practice v5 will not be marked as default until it has sufficient adoption on +the public network. + +The expectation is never to recommend upgrading existing +rooms to v4, but instead v5 (once ready), to avoid overburdening room admins +with upgrade notifications. + +To conclude, the proposed plan is: + 1. Define room v4 as MSC1884 + 2. Introduce servers with v4 support into the public network as rapidly as possible + 3. Wait for enough servers to speak v4. Meanwhile: + 1. Define an MSC for honouring server signing key validity periods + 2. Implement this MSC + 3. Define room v5 as this MSC + 4. Release Matrix 1.0, defining room v4 as the new default for creating rooms, + but also shipping support for room v5 for the first time. + 5. Wait for enough servers to speak v5 rooms. + 6. Define room v5 as the new default for creating rooms. + 7. Define room versions prior to v5 as unsafe, thus prompting users to upgrade their + rooms to v5. + +The reason we don't wait for v5 to be widespread before releasing 1.0 is to avoid +delaying the 1.0 yet further. It is good enough for 1.0 to support v5 without it +also being the default for creating rooms. diff --git a/scripts/continuserv/main.go b/scripts/continuserv/main.go index 2ef6fed91..1bd07e6ef 100644 --- a/scripts/continuserv/main.go +++ b/scripts/continuserv/main.go @@ -52,7 +52,7 @@ func main() { walker := makeWalker(dir, w) paths := []string{"api", "changelogs", "event-schemas", "scripts", - "specification"} + "specification", "schemas", "data-definitions"} for _, p := range paths { filepath.Walk(path.Join(dir, p), walker) diff --git a/scripts/css/tables.css b/scripts/css/tables.css new file mode 100644 index 000000000..03ee1d851 --- /dev/null +++ b/scripts/css/tables.css @@ -0,0 +1,4 @@ +/* Column with header cells */ +table.docutils tbody th.stub { + background: #eeeeee; +} diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 2a7d7ff85..66027f91e 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -4,8 +4,12 @@ docutils >= 0.14 pygments >= 2.2.0 Jinja2 >= 2.9.6 -jsonschema >= 2.6.0 + +# jsonschema 3.0.0 objects to the $refs in our schema file. TODO: figure out +# why. +jsonschema >= 2.6.0, < 3.0.0 + PyYAML >= 3.12 requests >= 2.18.4 towncrier == 18.6.0 -six >= 1.11.0 \ No newline at end of file +six >= 1.11.0 diff --git a/scripts/templating/matrix_templates/sections.py b/scripts/templating/matrix_templates/sections.py index 5961aa246..7000916bc 100644 --- a/scripts/templating/matrix_templates/sections.py +++ b/scripts/templating/matrix_templates/sections.py @@ -18,6 +18,7 @@ import inspect import json import os import logging +import re logger = logging.getLogger(__name__) @@ -110,12 +111,13 @@ class MatrixSections(Sections): # Special function: Returning a dict will specify multiple sections where # the key is the section name and the value is the value of the section def render_group_events(self): - # map all event schemata to the form $EVENTTYPE_event with s/./_/g - # e.g. m_room_topic_event + # map all event schemata to the form $EVENTTYPE_event with s/.#/_/g + # e.g. m_room_topic_event or m_room_message_m_text_event schemas = self.units.get("event_schemas") renders = {} for event_type in schemas: - renders[event_type.replace(".", "_") + "_event"] = self._render_events( + underscored_event_type = event_type.replace(".", "_").replace("$", "_") + renders[underscored_event_type + "_event"] = self._render_events( lambda x: x == event_type, sorted ) return renders @@ -124,7 +126,7 @@ class MatrixSections(Sections): def filterFn(eventType): return ( eventType.startswith("m.room") and - not eventType.startswith("m.room.message#m.") + not eventType.startswith("m.room.message$m.") ) return self._render_events(filterFn, sorted) @@ -137,16 +139,22 @@ class MatrixSections(Sections): ]["subtitle"] sections = [] msgtype_order = [ - "m.room.message#m.text", "m.room.message#m.emote", - "m.room.message#m.notice", "m.room.message#m.image", - "m.room.message#m.file" + "m.room.message$m.text", "m.room.message$m.emote", + "m.room.message$m.notice", "m.room.message$m.image", + "m.room.message$m.file" + ] + excluded_types = [ + # We exclude server notices from here because we handle them in a + # dedicated module. We do not want to confuse developers this early + # in the spec. + "m.room.message$m.server_notice", ] other_msgtypes = [ - k for k in schemas.keys() if k.startswith("m.room.message#") and - k not in msgtype_order + k for k in schemas.keys() if k.startswith("m.room.message$") and + k not in msgtype_order and k not in excluded_types ] for event_name in (msgtype_order + other_msgtypes): - if not event_name.startswith("m.room.message#m."): + if not event_name.startswith("m.room.message$m."): continue sections.append(template.render( example=examples[event_name][0], @@ -218,3 +226,19 @@ class MatrixSections(Sections): examples=swagger_def['examples'], title_kind=subtitle_title_char) return rendered + + def render_sas_emoji_table(self): + emoji = self.units.get("sas_emoji") + rendered = ".. csv-table::\n" + rendered += " :header: \"Number\", \"Emoji\", \"Unicode\", \"Description\"\n" + rendered += " :widths: 10, 10, 15, 20\n" + rendered += "\n" + for row in emoji: + rendered += " %d, \"%s\", \"``%s``\", \"%s\"\n" % ( + row['number'], + row['emoji'], + row['unicode'], + row['description'], + ) + rendered += "\n" + return rendered diff --git a/scripts/templating/matrix_templates/templates/events.tmpl b/scripts/templating/matrix_templates/templates/events.tmpl index 0955cf4c9..f55be73f6 100644 --- a/scripts/templating/matrix_templates/templates/events.tmpl +++ b/scripts/templating/matrix_templates/templates/events.tmpl @@ -1,7 +1,14 @@ {% import 'tables.tmpl' as tables -%} +{% if (event.type_with_msgtype) %} +``{{event.type_with_msgtype}}`` +{{(4 + event.type_with_msgtype | length) * title_kind}} +{% endif -%} + +{% if (not event.type_with_msgtype) %} ``{{event.type}}`` {{(4 + event.type | length) * title_kind}} +{% endif -%} {% if (event.typeof | length) %} *{{event.typeof}}* diff --git a/scripts/templating/matrix_templates/templates/http-api.tmpl b/scripts/templating/matrix_templates/templates/http-api.tmpl index 0b9207d9e..748360452 100644 --- a/scripts/templating/matrix_templates/templates/http-api.tmpl +++ b/scripts/templating/matrix_templates/templates/http-api.tmpl @@ -10,13 +10,13 @@ {{endpoint.desc}} -{{":Rate-limited: Yes." if endpoint.rate_limited else "" }} -{{":Requires auth: Yes." if endpoint.requires_auth else "" }} +{{":Rate-limited: Yes." if endpoint.rate_limited else ":Rate-limited: No." }} +{{":Requires auth: Yes." if endpoint.requires_auth else ":Requires auth: No." }} .. class:: httpheaders - + Request format: - + {% if (endpoint.req_param_by_loc | length) %} {{ tables.split_paramtable(endpoint.req_param_by_loc) }} {% if (endpoint.req_body_tables) %} @@ -33,7 +33,7 @@ {% if endpoint.res_headers is not none -%} .. class:: httpheaders - + Response headers: {{ tables.paramtable(endpoint.res_headers.rows) }} @@ -42,7 +42,7 @@ {% if endpoint.res_tables|length > 0 -%} .. class:: httpheaders - + Response format: {% for table in endpoint.res_tables -%} @@ -54,7 +54,7 @@ {% endif -%} .. class:: httpheaders - + Example request: .. code:: http @@ -64,7 +64,7 @@ {% if endpoint.responses|length > 0 -%} .. class:: httpheaders - + Response{{"s" if endpoint.responses|length > 1 else "" }}: {% endif -%} @@ -78,7 +78,7 @@ {% if res["example"] -%} .. class:: httpheaders - + Example .. code:: json diff --git a/scripts/templating/matrix_templates/units.py b/scripts/templating/matrix_templates/units.py index c1755119e..fe3ba5d21 100644 --- a/scripts/templating/matrix_templates/units.py +++ b/scripts/templating/matrix_templates/units.py @@ -59,6 +59,8 @@ TARGETS = os.path.join(matrix_doc_dir, "specification/targets.yaml") ROOM_EVENT = "core-event-schema/room_event.yaml" STATE_EVENT = "core-event-schema/state_event.yaml" +SAS_EMOJI_JSON = os.path.join(matrix_doc_dir, "data-definitions/sas-emoji.json") + logger = logging.getLogger(__name__) # a yaml Loader which loads mappings into OrderedDicts instead of regular @@ -521,6 +523,7 @@ class MatrixUnits(Units): path_template = path example_query_params = [] example_body = "" + example_mime = "application/json" for param in endpoint_swagger.get("parameters", []): # even body params should have names, otherwise the active docs don't work. param_name = param["name"] @@ -533,6 +536,10 @@ class MatrixUnits(Units): example_body = get_example_for_param(param) continue + if param_loc == "header": + if param["name"] == "Content-Type" and param["x-example"]: + example_mime = param["x-example"] + # description desc = param.get("description", "") if param.get("required"): @@ -610,8 +617,8 @@ class MatrixUnits(Units): example_query_params) if example_body: endpoint["example"][ - "req"] = "%s %s%s HTTP/1.1\nContent-Type: application/json\n\n%s" % ( - method.upper(), path_template, query_string, example_body + "req"] = "%s %s%s HTTP/1.1\nContent-Type: %s\n\n%s" % ( + method.upper(), path_template, query_string, example_mime, example_body ) else: endpoint["example"]["req"] = "%s %s%s HTTP/1.1\n\n" % ( @@ -790,7 +797,7 @@ class MatrixUnits(Units): if not filename.startswith("m."): continue - event_name = filename.split("#")[0] + event_name = filename.split("$")[0] filepath = os.path.join(path, filename) logger.info("Reading event example: %s" % filepath) try: @@ -846,6 +853,7 @@ class MatrixUnits(Units): "title": None, "desc": None, "msgtype": None, + "type_with_msgtype": None, # for the template's sake "content_fields": [ # ] @@ -884,6 +892,7 @@ class MatrixUnits(Units): ) if msgtype: schema["msgtype"] = msgtype[0] # enum prop + schema["type_with_msgtype"] = schema["type"] + " (" + msgtype[0] + ")" # link to msgtypes for m.room.message if schema["type"] == "m.room.message" and not msgtype: @@ -1081,3 +1090,21 @@ class MatrixUnits(Units): "string": git_version, "revision": git_commit } + + def load_sas_emoji(self): + with open(SAS_EMOJI_JSON, 'r', encoding='utf-8') as sas_json: + emoji = json.load(sas_json) + + # Verify the emoji matches the unicode + for c in emoji: + e = c['emoji'] + logger.info("Checking emoji %s (%s)", e, c['description']) + u = re.sub(r'U\+([0-9a-fA-F]+)', lambda m: chr(int(m.group(1), 16)), c['unicode']) + if e != u: + raise Exception("Emoji %s should be %s not %s" % ( + c['description'], + repr(e), + c['unicode'], + )) + + return emoji diff --git a/scripts/test-and-build.sh b/scripts/test-and-build.sh index 710b03ddf..f45e2da61 100755 --- a/scripts/test-and-build.sh +++ b/scripts/test-and-build.sh @@ -30,5 +30,5 @@ go get gopkg.in/fsnotify/fsnotify.v1 # build the spec for matrix.org. # (we don't actually use it on travis, but it's still useful to check we -# can build it. On Jenkins, this is then used to deploy to matrix.org). +# can build it. On Buildkite, this is then used to deploy to matrix.org). ./scripts/generate-matrix-org-assets diff --git a/specification/appendices/identifier_grammar.rst b/specification/appendices/identifier_grammar.rst index 729246d07..ea805955d 100644 --- a/specification/appendices/identifier_grammar.rst +++ b/specification/appendices/identifier_grammar.rst @@ -311,13 +311,16 @@ in the room's history (a permalink). A matrix.to URI has the following format, based upon the specification defined in RFC 3986: - https://matrix.to/#// + https://matrix.to/#//? The identifier may be a room ID, room alias, user ID, or group ID. The extra parameter is only used in the case of permalinks where an event ID is referenced. The matrix.to URI, when referenced, must always start with ``https://matrix.to/#/`` followed by the identifier. +The ```` and the preceeding question mark are optional and +only apply in certain circumstances, documented below. + Clients should not rely on matrix.to URIs falling back to a web server if accessed and instead should perform some sort of action within the client. For example, if the user were to click on a matrix.to URI for a room alias, the client may open @@ -331,7 +334,7 @@ Examples of matrix.to URIs are: * Room alias: ``https://matrix.to/#/%23somewhere%3Aexample.org`` * Room: ``https://matrix.to/#/!somewhere%3Aexample.org`` * Permalink by room: ``https://matrix.to/#/!somewhere%3Aexample.org/%24event%3Aexample.org`` -* Permalink by room alias: ``https://matrix.to/#/#somewhere:example.org/%24event%3Aexample.org`` +* Permalink by room alias: ``https://matrix.to/#/%23somewhere:example.org/%24event%3Aexample.org`` * User: ``https://matrix.to/#/%40alice%3Aexample.org`` * Group: ``https://matrix.to/#/%2Bexample%3Aexample.org`` @@ -345,7 +348,53 @@ Examples of matrix.to URIs are: appearing due to some `room versions `_. These slashes should normally be encoded when producing matrix.to URIs, however. -.. Note:: - Room ID permalinks are unroutable as there is no reliable domain to send requests - to upon receipt of the permalink. Clients should do their best route Room IDs to - where they need to go, however they should also be aware of `issue #1579 `_. +Routing +<<<<<<< + +Room IDs are not routable on their own as there is no reliable domain to send requests +to. This is partially mitigated with the addition of a ``via`` argument on a matrix.to +URI, however the problem of routability is still present. Clients should do their best +to route Room IDs to where they need to go, however they should also be aware of +`issue #1579 `_. + +A room (or room permalink) which isn't using a room alias should supply at least one +server using ``via`` in the ````, like so: +``https://matrix.to/!somewhere%3Aexample.org?via=example.org&via=alt.example.org``. The +parameter can be supplied multiple times to specify multiple servers to try. + +The values of ``via`` are intended to be passed along as the ``server_name`` parameters +on the Client Server ``/join`` API. + +When generating room links and permalinks, the application should pick servers which +have a high probability of being in the room in the distant future. How these servers +are picked is left as an implementation detail, however the current recommendation is +to pick 3 unique servers based on the following criteria: + +* The first server should be the server of the highest power level user in the room, + provided they are at least power level 50. If no user meets this criteria, pick the + most popular server in the room (most joined users). The rationale for not picking + users with power levels under 50 is that they are unlikely to be around into the + distant future while higher ranking users (and therefore servers) are less likely + to give up their power and move somewhere else. Most rooms in the public federation + have a power level 100 user and have not deviated from the default structure where + power level 50 users have moderator-style privileges. + +* The second server should be the next highest server by population, or the first + highest by population if the first server was based on a user's power level. The + rationale for picking popular servers is that the server is unlikely to be removed + as the room naturally grows in membership due to that server joining users. The + server could be refused participation in the future due to server ACLs or similar, + however the chance of that happening to a server which is organically joining the + room is unlikely. + +* The third server should be the next highest server by population. + +* Servers which are blocked due to server ACLs should never be chosen. + +* Servers which are IP addresses should never be chosen. Servers which use a domain + name are less likely to be unroutable in the future whereas IP addresses cannot be + pointed to a different location and therefore higher risk options. + +* All 3 servers should be unique from each other. If the room does not have enough users + to supply 3 servers, the application should only specify the servers it can. For example, + a room with only 2 users in it would result in maximum 2 ``via`` parameters. diff --git a/specification/appendices/signing_json.rst b/specification/appendices/signing_json.rst index 795d66693..8036950e4 100644 --- a/specification/appendices/signing_json.rst +++ b/specification/appendices/signing_json.rst @@ -59,7 +59,7 @@ Grammar +++++++ Adapted from the grammar in http://tools.ietf.org/html/rfc7159 removing -insignificant whitespace, fractions, exponents and redundant character escapes +insignificant whitespace, fractions, exponents and redundant character escapes. .. code:: diff --git a/specification/appendices/test_vectors.rst b/specification/appendices/test_vectors.rst index e2b8fb588..05b115db8 100644 --- a/specification/appendices/test_vectors.rst +++ b/specification/appendices/test_vectors.rst @@ -91,11 +91,17 @@ Given the following minimally-sized event: .. code:: json { - "event_id": "$0:domain", + "room_id": "!x:domain", + "sender": "@a:domain", "origin": "domain", "origin_server_ts": 1000000, "signatures": {}, + "hashes": {}, "type": "X", + "content": {}, + "prev_events": [], + "auth_events": [], + "depth": 3, "unsigned": { "age_ts": 1000000 } @@ -106,15 +112,20 @@ The event signing algorithm should emit the following signed event: .. code:: json { - "event_id": "$0:domain", + "auth_events": [], + "content": {}, + "depth": 3, "hashes": { - "sha256": "6tJjLpXtggfke8UxFhAKg82QVkJzvKOVOOSjUDK4ZSI" + "sha256": "5jM4wQpv6lnBo7CLIghJuHdW+s2CMBJPUOGOC89ncos" }, "origin": "domain", "origin_server_ts": 1000000, + "prev_events": [], + "room_id": "!x:domain", + "sender": "@a:domain", "signatures": { "domain": { - "ed25519:1": "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA" + "ed25519:1": "KxwGjPSDEtvnFgU00fwFz+l6d2pJM6XBIaMEn81SXPTRl16AqLAYqfIReFGZlHi5KLjAWbOoMszkwsQma+lYAg" } }, "type": "X", @@ -129,7 +140,7 @@ Given the following event containing redactable content: { "content": { - "body": "Here is the message content", + "body": "Here is the message content" }, "event_id": "$0:domain", "origin": "domain", @@ -149,7 +160,7 @@ The event signing algorithm should emit the following signed event: { "content": { - "body": "Here is the message content", + "body": "Here is the message content" }, "event_id": "$0:domain", "hashes": { diff --git a/specification/application_service_api.rst b/specification/application_service_api.rst index 865544dd0..3220df2d4 100644 --- a/specification/application_service_api.rst +++ b/specification/application_service_api.rst @@ -187,6 +187,15 @@ An example registration file for an IRC-bridging application service is below: Homeserver -> Application Service API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Authorization ++++++++++++++ + +Homeservers MUST include a query parameter named ``access_token`` containing the +``hs_token`` from the application service's registration when making requests to +the application service. Application services MUST verify the provided ``access_token`` +matches their known ``hs_token``, failing the request with a ``M_FORBIDDEN`` error +if it does not match. + Legacy routes +++++++++++++ diff --git a/specification/client_server_api.rst b/specification/client_server_api.rst index f9f815f7f..11609896c 100644 --- a/specification/client_server_api.rst +++ b/specification/client_server_api.rst @@ -57,6 +57,8 @@ The following other versions are also available, in reverse chronological order: API Standards ------------- +.. TODO: Move a lot of this to a common area for all specs. + .. TODO Need to specify any HMAC or access_token lifetime/ratcheting tricks We need to specify capability negotiation for extensible transports @@ -82,7 +84,6 @@ names in JSON objects passed over the API also follow this convention. ``/createRoom``. A future version of this specification will address the inconsistency. - Any errors which occur at the Matrix API level MUST return a "standard error response". This is a JSON object which looks like: @@ -219,9 +220,12 @@ Other error codes the client might encounter are: to modify state (eg: sending messages, account data, etc) and not routes which only read state (eg: ``/sync``, get account data, etc). +:``M_CANNOT_LEAVE_SERVER_NOTICE_ROOM``: + The user is unable to reject an invite to join the server notices room. See the + `Server Notices <#server-notices>`_ module for more information. + .. TODO: More error codes (covered by other issues) .. * M_CONSENT_NOT_GIVEN - GDPR: https://github.com/matrix-org/matrix-doc/issues/1512 -.. * M_CANNOT_LEAVE_SERVER_NOTICE_ROOM - GDPR: https://github.com/matrix-org/matrix-doc/issues/1254 .. _sect:txn_ids: @@ -286,7 +290,7 @@ In this section, the following terms are used with specific meanings: ``FAIL_ERROR`` Inform the user that auto-discovery did not return any usable URLs. Do not continue further with the current login process. At this point, valid data - was obtained, but no homeserver is available to serve the client. No further + was obtained, but no server is available to serve the client. No further guess should be attempted and the user should make a conscientious decision what to do next. @@ -403,8 +407,10 @@ an additional stage. This exchange continues until the final success. For each endpoint, a server offers one or more 'flows' that the client can use to authenticate itself. Each flow comprises a series of stages, as described -above. The client is free to choose which flow it follows. When all stages in a -flow are complete, authentication is complete and the API call succeeds. +above. The client is free to choose which flow it follows, however the flow's +stages must be completed in order. Failing to follow the flows in order must +result in an HTTP 401 response, as defined below. When all stages in a flow +are complete, authentication is complete and the API call succeeds. User-interactive API in the REST API <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -448,11 +454,10 @@ params presented, that type may be present as a key in this dictionary. For example, the public part of an OAuth client ID could be given here. session - This is a session identifier that the client must pass back to the home - server, if one is provided, in subsequent attempts to authenticate in the same - API call. + This is a session identifier that the client must pass back to the homeserver, + if one is provided, in subsequent attempts to authenticate in the same API call. -The client then chooses a flow and attempts to complete one of the stages. It +The client then chooses a flow and attempts to complete the first stage. It does this by resubmitting the same request with the addition of an ``auth`` key in the object that it submits. This dictionary contains a ``type`` key whose value is the name of the authentication type that the client is attempting to complete. @@ -553,7 +558,10 @@ message in the standard format. For example: } If the client has completed all stages of a flow, the homeserver performs the -API call and returns the result as normal. +API call and returns the result as normal. Completed stages cannot be retried +by clients, therefore servers must return either a 401 response with the completed +stages, or the result of the API call if all stages were completed when a client +retries a stage. Some authentication types may be completed by means other than through the Matrix client, for example, an email confirmation may be completed when the user @@ -618,6 +626,7 @@ This specification defines the following auth types: - ``m.login.recaptcha`` - ``m.login.oauth2`` - ``m.login.email.identity`` + - ``m.login.msisdn`` - ``m.login.token`` - ``m.login.dummy`` @@ -782,6 +791,34 @@ To use this authentication type, clients should submit an auth dict as follows: "session": "" } +Phone number/MSISDN-based (identity server) +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +:Type: + ``m.login.msisdn`` +:Description: + Authentication is supported by authorising a phone number with an identity + server. + +Prior to submitting this, the client should authenticate with an identity +server. After authenticating, the session information should be submitted to +the homeserver. + +To use this authentication type, clients should submit an auth dict as follows: + +.. code:: json + + { + "type": "m.login.msisdn", + "threepidCreds": [ + { + "sid": "", + "client_secret": "", + "id_server": "" + } + ], + "session": "" + } + Dummy Auth <<<<<<<<<< :Type: @@ -789,7 +826,14 @@ Dummy Auth :Description: Dummy authentication always succeeds and requires no extra parameters. Its purpose is to allow servers to not require any form of User-Interactive - Authentication to perform a request. + Authentication to perform a request. It can also be used to differentiate + flows where otherwise one flow would be a subset of another flow. eg. if + a server offers flows ``m.login.recaptcha`` and ``m.login.recaptcha, + m.login.email.identity`` and the client completes the recaptcha stage first, + the auth would succeed with the former flow, even if the client was intending + to then complete the email auth stage. A server can instead send flows + ``m.login.recaptcha, m.login.dummy`` and ``m.login.recaptcha, + m.login.email.identity`` to fix the ambiguity. To use this authentication type, clients should submit an auth dict with just the type and session, if provided: @@ -1493,7 +1537,6 @@ the following list: - ``room_id`` - ``sender`` - ``state_key`` -- ``prev_content`` - ``content`` - ``hashes`` - ``signatures`` @@ -1525,6 +1568,16 @@ property of the redacted event, under the ``redacted_because`` key. When a client receives a redaction event it should change the redacted event in the same way a server does. +.. NOTE:: + + Redacted events can still affect the state of the room. When redacted, + state events behave as though their properties were simply not specified, + except those protected by the redaction algorithm. For example, + a redacted ``join`` event will still result in the user being considered joined. + Similarly, a redacted topic does not necessarily cause the topic to revert to + what is was prior to the event - it causes the topic to be removed from the room. + + Events ++++++ diff --git a/specification/index.rst b/specification/index.rst index 19c5ad223..a6f6f62b4 100644 --- a/specification/index.rst +++ b/specification/index.rst @@ -485,7 +485,7 @@ some other reason. Versions can switch between stable and unstable periodically for a variety of reasons, including discovered security vulnerabilities and age. Clients should not ask room administrators to upgrade their rooms if the room is -running a stable version. Servers SHOULD use room version 1 as the default room +running a stable version. Servers SHOULD use room version 4 as the default room version when creating new rooms. The available room versions are: @@ -493,6 +493,7 @@ The available room versions are: * `Version 1 `_ - **Stable**. The current version of most rooms. * `Version 2 `_ - **Stable**. Implements State Resolution Version 2. * `Version 3 `_ - **Stable**. Introduces events whose IDs are the event's hash. +* `Version 4 `_ - **Stable**. Builds on v3 by using URL-safe base64 for event IDs. Specification Versions ---------------------- diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 59d241b67..628819670 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -1,4 +1,5 @@ .. Copyright 2016 OpenMarket Ltd +.. Copyright 2019 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. @@ -18,7 +19,7 @@ End-to-End Encryption .. _module:e2e: Matrix optionally supports end-to-end encryption, allowing rooms to be created -whose conversation contents is not decryptable or interceptable on any of the +whose conversation contents are not decryptable or interceptable on any of the participating homeservers. Key Distribution @@ -182,7 +183,7 @@ process: field as the ``from`` parameter. If the client is tracking the device list of any of the users listed in the response, it marks them as outdated. It combines this list with those already flagged as outdated, and initiates a - |/keys/query|_ requests for all of them. + |/keys/query|_ request for all of them. .. Warning:: @@ -383,20 +384,10 @@ man-in-the-middle. This verification process requires an out-of-band channel: there is no way to do it within Matrix without trusting the administrators of the homeservers. -In Matrix, the basic process for device verification is for Alice to verify -that the public Ed25519 signing key she received via ``/keys/query`` for Bob's -device corresponds to the private key in use by Bob's device. For now, it is -recommended that clients provide mechanisms by which the user can see: - -1. The public part of their device's Ed25519 signing key, encoded using - `unpadded Base64`_. - -2. The list of devices in use for each user in a room, along with the public - Ed25519 signing key for each device, again encoded using unpadded Base64. - -Alice can then meet Bob in person, or contact him via some other trusted -medium, and ask him to read out the Ed25519 key shown on his device. She -compares this with the value shown for his device on her client. +In Matrix, verification works by Alice meeting Bob in person, or contacting him +via some other trusted medium, and use `SAS Verification`_ to interactively +verify Bob's devices. Alice and Bob may also read aloud their unpadded base64 +encoded Ed25519 public key, as returned by ``/keys/query``. Device verification may reach one of several conclusions. For example: @@ -422,6 +413,328 @@ Device verification may reach one of several conclusions. For example: decrypted by such a device. For the Olm protocol, this is documented at https://matrix.org/git/olm/about/docs/signing.rst. + +Key verification framework +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Verifying keys manually by reading out the Ed25519 key is not very user friendly, +and can lead to errors. In order to help mitigate errors, and to make the process +eaiser for users, some verification methods are supported by the specification. +The methods all use a common framework for negotiating the key verification. + +To use this framework, Alice's client would send ``m.key.verification.request`` +events to Bob's devices. All of the ``to_device`` messages sent to Bob MUST have +the same ``transaction_id`` to indicate they are part of the same request. This +allows Bob to reject the request on one device, and have it apply to all of his +devices. Similarly, it allows Bob to process the verification on one device without +having to involve all of his devices. + +When Bob's device receives a ``m.key.verification.request``, it should prompt Bob +to verify keys with Alice using one of the supported methods in the request. If +Bob's device does not understand any of the methods, it should not cancel the request +as one of his other devices may support the request. Instead, Bob's device should +tell Bob that an unsupported method was used for starting key verification. The +prompt for Bob to accept/reject Alice's request (or the unsupported method prompt) +should be automatically dismissed 10 minutes after the ``timestamp`` field or 2 +minutes after Bob's client receives the message, whichever comes first, if Bob +does not interact with the prompt. The prompt should additionally be hidden if +an appropriate ``m.key.verification.cancel`` message is received. + +If Bob rejects the request, Bob's client must send a ``m.key.verification.cancel`` +message to Alice's device. Upon receipt, Alice's device should tell her that Bob +does not want to verify her device and send ``m.key.verification.cancel`` messages +to all of Bob's devices to notify them that the request was rejected. + +If Bob accepts the request, Bob's device starts the key verification process by +sending a ``m.key.verification.start`` message to Alice's device. Upon receipt +of this message, Alice's device should send a ``m.key.verification.cancel`` message +to all of Bob's other devices to indicate the process has been started. The start +message must use the same ``transaction_id`` from the original key verification +request if it is in response to the request. The start message can be sent indepdently +of any request. + +Individual verification methods may add additional steps, events, and properties to +the verification messages. Event types for methods defined in this specification must +be under the ``m.key.verification`` namespace and any other event types must be namespaced +according to the Java package naming convention. + +Any of Alice's or Bob's devices can cancel the key verification request or process +at any time with a ``m.key.verification.cancel`` message to all applicable devices. + +This framework yields the following handshake, assuming both Alice and Bob each have +2 devices, Bob's first device accepts the key verification request, and Alice's second +device initiates the request. Note how Alice's first device is not involved in the +request or verification process. + +:: + + +---------------+ +---------------+ +-------------+ +-------------+ + | AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 | + +---------------+ +---------------+ +-------------+ +-------------+ + | | | | + | | m.key.verification.request | | + | |---------------------------------->| | + | | | | + | | m.key.verification.request | | + | |-------------------------------------------------->| + | | | | + | | m.key.verification.start | | + | |<----------------------------------| | + | | | | + | | m.key.verification.cancel | | + | |-------------------------------------------------->| + | | | | + + +After the handshake, the verification process begins. + +{{m_key_verification_request_event}} + +{{m_key_verification_start_event}} + +{{m_key_verification_cancel_event}} + + +.. _`SAS Verification`: + +Short Authentication String (SAS) verification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +SAS verification is a user-friendly key verification process built off the common +framework outlined above. SAS verification is intended to be a highly interactive +process for users, and as such exposes verfiication methods which are easier for +users to use. + +The verification process is heavily inspired by Phil Zimmerman's ZRTP key agreement +handshake. A key part of key agreement in ZRTP is the hash commitment: the party that +begins the Diffie-Hellman key sharing sends a hash of their part of the Diffie-Hellman +exchange, and does not send their part of the Diffie-Hellman exchange until they have +received the other party's part. Thus an attacker essentially only has one attempt to +attack the Diffie-Hellman exchange, and hence we can verify fewer bits while still +achieving a high degree of security: if we verify n bits, then an attacker has a 1 in +2\ :sup:`n` chance of success. For example, if we verify 40 bits, then an attacker has +a 1 in 1,099,511,627,776 chance (or less than 1 in 1012 chance) of success. A failed +attack would result in a mismatched Short Authentication String, alerting users to the +attack. + +The verification process takes place over `to-device`_ messages in two phases: + +1. Key agreement phase (based on `ZRTP key agreement `_). +#. Key verification phase (based on HMAC). + +The process between Alice and Bob verifying each other would be: + +.. |AlicePublicKey| replace:: :math:`K_{A}^{public}` +.. |AlicePrivateKey| replace:: :math:`K_{A}^{private}` +.. |AliceCurve25519| replace:: :math:`K_{A}^{private},K_{A}^{public}` +.. |BobPublicKey| replace:: :math:`K_{B}^{public}` +.. |BobPrivateKey| replace:: :math:`K_{B}^{private}` +.. |BobCurve25519| replace:: :math:`K_{B}^{private},K_{B}^{public}` +.. |BobAliceCurve25519| replace:: :math:`K_{B}^{private}K_{A}^{public}` +.. |AliceBobECDH| replace:: :math:`ECDH(K_{A}^{private},K_{B}^{public})` + +1. Alice and Bob establish a secure out-of-band connection, such as meeting + in-person or a video call. "Secure" here means that either party cannot be + impersonated, not explicit secrecy. +#. Alice and Bob communicate which devices they'd like to verify with each other. +#. Alice selects Bob's device from the device list and begins verification. +#. Alice's client ensures it has a copy of Bob's device key. +#. Alice's device sends Bob's device a ``m.key.verification.start`` message. +#. Bob's device receives the message and selects a key agreement protocol, hash + algorithm, message authentication code, and SAS method supported by Alice's + device. +#. Bob's device ensures it has a copy of Alice's device key. +#. Bob's device creates an ephemeral Curve25519 key pair (|BobCurve25519|), and + calculates the hash (using the chosen algorithm) of the public key |BobPublicKey|. +#. Bob's device replies to Alice's device with a ``m.key.verification.accept`` message. +#. Alice's device receives Bob's message and stores the commitment hash for later use. +#. Alice's device creates an ephemeral Curve25519 key pair (|AliceCurve25519|) and + replies to Bob's device with a ``m.key.verification.key``, sending only the public + key |AlicePublicKey|. +#. Bob's device receives Alice's message and replies with its own ``m.key.verification.key`` + message containing its public key |BobPublicKey|. +#. Alice's device receives Bob's message and verifies the commitment hash from earlier + matches the hash of the key Bob's device just sent and the content of Alice's + ``m.key.verification.start`` message. +#. Both Alice and Bob's devices perform an Elliptic-curve Diffie-Hellman (|AliceBobECDH|), + using the result as the shared secret. +#. Both Alice and Bob's devices display a SAS to their users, which is derived + from the shared key using one of the methods in this section. If multiple SAS + methods are available, clients should allow the users to select a method. +#. Alice and Bob compare the strings shown by their devices, and tell their devices if + they match or not. +#. Assuming they match, Alice and Bob's devices calculate the HMAC of their own device keys + and a comma-separated sorted list of of the key IDs that they wish the other user + to verify, using SHA-256 as the hash function. HMAC is defined in [RFC 2104](https://tools.ietf.org/html/rfc2104). + The key for the HMAC is different for each item and is calculated by generating + 32 bytes (256 bits) using `the key verification HKDF <#SAS-HKDF>`_. +#. Alice's device sends Bob's device a ``m.key.verification.mac`` message containing the + MAC of Alice's device keys and the MAC of her key IDs to be verified. Bob's device does + the same for Bob's device keys and key IDs concurrently with Alice. +#. When the other device receives the ``m.key.verification.mac`` message, the device + calculates the HMAC of its copies of the other device's keys given in the message, + as well as the HMAC of the comma-seperated, sorted, list of key IDs in the message. + The device compares these with the HMAC values given in the message, and if everything + matches then the device keys are verified. + +The wire protocol looks like the following between Alice and Bob's devices:: + + +-------------+ +-----------+ + | AliceDevice | | BobDevice | + +-------------+ +-----------+ + | | + | m.key.verification.start | + |-------------------------------->| + | | + | m.key.verification.accept | + |<--------------------------------| + | | + | m.key.verification.key | + |-------------------------------->| + | | + | m.key.verification.key | + |<--------------------------------| + | | + | m.key.verification.mac | + |-------------------------------->| + | | + | m.key.verification.mac | + |<--------------------------------| + | | + +Error and exception handling +<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +At any point the interactive verfication can go wrong. The following describes what +to do when an error happens: + +* Alice or Bob can cancel the verification at any time. A ``m.key.verification.cancel`` + message must be sent to signify the cancellation. +* The verification can time out. Clients should time out a verification that does not + complete within 10 minutes. Additionally, clients should expire a ``transaction_id`` + which goes unused for 10 minutes after having last sent/received it. The client should + inform the user that the verification timed out, and send an appropriate + ``m.key.verification.cancel`` message to the other device. +* When the same device attempts to intiate multiple verification attempts, the receipient + should cancel all attempts with that device. +* When a device receives an unknown ``transaction_id``, it should send an appropriate + ``m.key.verfication.cancel`` message to the other device indicating as such. This + does not apply for inbound ``m.key.verification.start`` or ``m.key.verification.cancel`` + messages. +* If the two devices do not share a common key share, hash, HMAC, or SAS method then + the device should notify the other device with an appropriate ``m.key.verification.cancel`` + message. +* If the user claims the Short Authentication Strings do not match, the device should + send an appropriate ``m.key.verification.cancel`` message to the other device. +* If the device receives a message out of sequence or that it was not expecting, it should + notify the other device with an appropriate ``m.key.verification.cancel`` message. + + +Verification messages specific to SAS +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +Building off the common framework, the following events are involved in SAS verification. + +The ``m.key.verification.cancel`` event is unchanged, however the following error codes +are used in addition to those already specified: + +* ``m.unknown_method``: The devices are unable to agree on the key agreement, hash, MAC, + or SAS method. +* ``m.mismatched_commitment``: The hash commitment did not match. +* ``m.mismatched_sas``: The SAS did not match. + + +{{m_key_verification_start_m_sas_v1_event}} + +{{m_key_verification_accept_event}} + +{{m_key_verification_key_event}} + +{{m_key_verification_mac_event}} + + +.. _`SAS-HKDF`: + +HKDF calculation +<<<<<<<<<<<<<<<< + +In all of the SAS methods, HKDF is as defined in [RFC 5869](https://tools.ietf.org/html/rfc5869) +and uses the previously agreed-upon hash function for the hash function. The shared +secret is supplied as the input keying material. No salt is used, and the input +parameter is the concatenation of: + + * The string ``MATRIX_KEY_VERIFICATION_SAS``. + * The Matrix ID of the user who sent the ``m.key.verification.start`` message. + * The Device ID of the device which sent the ``m.key.verification.start`` message. + * The Matrix ID of the user who sent the ``m.key.verification.accept`` message. + * The Device ID of the device which sent the ``m.key.verification.accept`` message. + * The ``transaction_id`` being used. + +.. admonition:: Rationale + HKDF is used over the plain shared secret as it results in a harder attack + as well as more uniform data to work with. + +For verification of each party's device keys, HKDF is as defined in RFC 5869 and +uses SHA-256 as the hash function. The shared secret is supplied as the input keying +material. No salt is used, and in the input parameter is the concatenation of: + + * The string ``MATRIX_KEY_VERIFICATION_MAC``. + * The Matrix ID of the user whose key is being MAC-ed. + * The Device ID of the device sending the MAC. + * The Matrix ID of the other user. + * The Device ID of the device receiving the MAC. + * The ``transaction_id`` being used. + * The Key ID of the key being MAC-ed, or the string ``KEY_IDS`` if the item + being MAC-ed is the list of key IDs. + +SAS method: ``decimal`` +<<<<<<<<<<<<<<<<<<<<<<< + +Generate 5 bytes using `HKDF <#SAS-HKDF>`_ then take sequences of 13 bits to +convert to decimal numbers (resulting in 3 numbers between 0 and 8191 inclusive +each). Add 1000 to each calculated number. + +The bitwise operations to get the numbers given the 5 bytes +:math:`B_{0}, B_{1}, B_{2}, B_{3}, B_{4}` would be: + +* First: :math:`(B_{0} \ll 5 | B_{1} \gg 3) + 1000` +* Second: :math:`((B_{1} \& 0x7) \ll 10 | B_{2} \ll 2 | B_{3} \gg 6) + 1000` +* Third: :math:`((B_{3} \& 0x3F) \ll 7 | B_{4} \gg 1) + 1000` + +The digits are displayed to the user either with an appropriate separator, +such as dashes, or with the numbers on individual lines. + +SAS method: ``emoji`` +<<<<<<<<<<<<<<<<<<<<< + +Generate 6 bytes using `HKDF <#SAS-HKDF>`_ then split the first 42 bits into +7 groups of 6 bits, similar to how one would base64 encode something. Convert +each group of 6 bits to a number and use the following table to get the corresponding +emoji: + +{{sas_emoji_table}} + +.. Note:: + This table is available as JSON at + https://github.com/matrix-org/matrix-doc/blob/master/data-definitions/sas-emoji.json + +.. admonition:: Rationale + + The emoji above were chosen to: + + * Be recognisable without colour. + * Be recognisable at a small size. + * Be recognisable by most cultures. + * Be distinguishable from each other. + * Easily described by a few words. + * Avoid symbols with negative connotations. + * Be likely similar across multiple platforms. + +Clients SHOULD show the emoji with the descriptions from the table, or appropriate +translation of those descriptions. Client authors SHOULD collaborate to create a +common set of translations for all languages. + + .. section name changed, so make sure that old links keep working .. _key-sharing: @@ -460,7 +773,7 @@ Keys can be manually exported from one device to an encrypted file, copied to another device, and imported. The file is encrypted using a user-supplied passphrase, and is created as follows: -1. Encode the sessions a JSON object, formatted as described in `Key export +1. Encode the sessions as a JSON object, formatted as described in `Key export format`_. 2. Generate a 512-bit key from the user-entered passphrase by computing `PBKDF2`_\(HMAC-SHA-512, passphrase, S, N, 512), where S is a 128-bit @@ -658,10 +971,38 @@ part of the ed25519 key it claims to have in the Olm payload. This is crucial when the ed25519 key corresponds to a verified device. If a client has multiple sessions established with another device, it should -use the session from which it last received a message. A client may expire old -sessions by defining a maximum number of olm sessions that it will maintain for -each device, and expiring sessions on a Least Recently Used basis. The maximum -number of olm sessions maintained per device should be at least 4. +use the session from which it last received and successfully decrypted a +message. For these purposes, a session that has not received any messages +should use its creation time as the time that it last received a message. +A client may expire old sessions by defining a maximum number of olm sessions +that it will maintain for each device, and expiring sessions on a Least Recently +Used basis. The maximum number of olm sessions maintained per device should +be at least 4. + +Recovering from undecryptable messages +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +Occasionally messages may be undecryptable by clients due to a variety of reasons. +When this happens to an Olm-encrypted message, the client should assume that the Olm +session has become corrupted and create a new one to replace it. + +.. Note:: + Megolm-encrypted messages generally do not have the same problem. Usually the key + for an undecryptable Megolm-encrypted message will come later, allowing the client + to decrypt it successfully. Olm does not have a way to recover from the failure, + making this session replacement process required. + +To establish a new session, the client sends a `m.dummy <#m-dummy>`_ to-device event +to the other party to notify them of the new session details. + +Clients should rate-limit the number of sessions it creates per device that it receives +a message from. Clients should not create a new session with another device if it has +already created one for that given device in the past 1 hour. + +Clients should attempt to mitigate loss of the undecryptable messages. For example, +Megolm sessions that were sent using the old session would have been lost. The client +can attempt to retrieve the lost sessions through ``m.room_key_request`` messages. + ``m.megolm.v1.aes-sha2`` ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -740,6 +1081,8 @@ Events {{m_forwarded_room_key_event}} +{{m_dummy_event}} + Key management API ~~~~~~~~~~~~~~~~~~ diff --git a/specification/modules/push.rst b/specification/modules/push.rst index 9830729a1..1bac0c2ee 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -177,7 +177,7 @@ notification is delivered for a matching event. The following actions are define This prevents each matching event from generating a notification ``coalesce`` This enables notifications for matching events but activates homeserver - specific behaviour to intelligently coalesce multiple events into a single + specific behaviour to intelligently coalesce multiple events into a single notification. Not all homeservers may support this. Those that do not support it should treat it as the ``notify`` action. ``set_tweak`` @@ -369,6 +369,37 @@ Definition: } +``.m.rule.tombstone`` +````````````````````` +Matches any event whose type is ``m.room.tombstone``. This is intended +to notify users of a room when it is upgraded, similar to what an +``@room`` notification would accomplish. + +Definition: + +.. code:: json + + { + "rule_id": ".m.rule.tombstone", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.tombstone" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": true + } + ] + } + + ``.m.rule.roomnotif`` ````````````````````` Matches any message whose content is unencrypted and contains the @@ -599,7 +630,7 @@ Definition: Conditions ++++++++++ -Override, Underride and Default Rules MAY have a list of 'conditions'. +Override, Underride and Default Rules MAY have a list of 'conditions'. All conditions must hold true for an event in order to apply the ``action`` for the event. A rule with no conditions always matches. Room, Sender, User and Content rules do not have conditions in the same way, but instead have diff --git a/specification/modules/receipts.rst b/specification/modules/receipts.rst index faba7b625..ee2b697a6 100644 --- a/specification/modules/receipts.rst +++ b/specification/modules/receipts.rst @@ -60,7 +60,8 @@ Clients should send read receipts when there is some certainty that the event in question has been **displayed** to the user. Simply receiving an event does not provide enough certainty that the user has seen the event. The user SHOULD need to *take some action* such as viewing the room that the event was sent to or -dismissing a notification in order for the event to count as "read". +dismissing a notification in order for the event to count as "read". Clients +SHOULD NOT send read receipts for events sent by their own user. A client can update the markers for its user by interacting with the following HTTP APIs. @@ -94,4 +95,3 @@ Security considerations As receipts are sent outside the context of the event graph, there are no integrity checks performed on the contents of ``m.receipt`` events. - diff --git a/specification/modules/send_to_device.rst b/specification/modules/send_to_device.rst index 862885461..cca0338a2 100644 --- a/specification/modules/send_to_device.rst +++ b/specification/modules/send_to_device.rst @@ -108,7 +108,7 @@ to_device ToDevice Optional. Information on the send-to-device messages ========= ========= ============================================= Parameter Type Description ========= ========= ============================================= -events [Event] List of send-to-device messages +events [Event] List of send-to-device messages. ========= ========= ============================================= ``Event`` diff --git a/specification/modules/server_notices.rst b/specification/modules/server_notices.rst new file mode 100644 index 000000000..63b7bfc5e --- /dev/null +++ b/specification/modules/server_notices.rst @@ -0,0 +1,78 @@ +.. Copyright 2019 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. + +Server Notices +============== + +.. _module:server-notices: + +Homeserver hosts often want to send messages to users in an official capacity, +or have resource limits which affect a user's ability to use the homeserver. +For example, the homeserver may be limited to a certain number of active users +per month and has exceeded that limit. To communicate this failure to users, +the homeserver would use the Server Notices room. + +The aesthetics of the room (name, topic, avatar, etc) are left as an implementation +detail. It is recommended that the homeserver decorate the room such that it looks +like an official room to users. + +Events +------ +Notices are sent to the client as normal ``m.room.message`` events with a +``msgtype`` of ``m.server_notice`` in the server notices room. Events with +a ``m.server_notice`` ``msgtype`` outside of the server notice room must +be ignored by clients. + +The specified values for ``server_notice_type`` are: + +:``m.server_notice.usage_limit_reached``: + The server has exceeded some limit which requires the server administrator + to intervene. The ``limit_type`` describes the kind of limit reached. + The specified values for ``limit_type`` are: + + :``monthly_active_user``: + The server's number of active users in the last 30 days has exceeded the + maximum. New connections are being refused by the server. What defines + "active" is left as an implementation detail, however servers are encouraged + to treat syncing users as "active". + + +{{m_room_message_m_server_notice_event}} + +Client behaviour +---------------- +Clients can identify the server notices room by the ``m.server_notice`` tag +on the room. Active notices are represented by the `pinned events <#m-room-pinned-events>`_ +in the server notices room. Server notice events pinned in that room should +be shown to the user through special UI and not through the normal pinned +events interface in the client. For example, clients may show warning banners +or bring up dialogs to get the user's attention. Events which are not server +notice events and are pinned in the server notices room should be shown just +like any other pinned event in a room. + +The client must not expect to be able to reject an invite to join the server +notices room. Attempting to reject the invite must result in a +``M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`` error. Servers should not prevent the user +leaving the room after joining the server notices room, however the same error +code must be used if the server will prevent leaving the room. + +Server behaviour +---------------- +Servers should manage exactly 1 server notices room per user. Servers must +identify this room to clients with the ``m.server_notice`` tag. Servers should +invite the target user rather than automatically join them to the server notice +room. + +How servers send notices to clients, and which user they use to send the events, +is left as an implementation detail for the server. diff --git a/specification/modules/tags.rst b/specification/modules/tags.rst index a4b0becf6..9d0cd5544 100644 --- a/specification/modules/tags.rst +++ b/specification/modules/tags.rst @@ -34,9 +34,9 @@ The JSON object associated with each tag gives information about the tag, e.g ho to order the rooms with a given tag. Ordering information is given under the ``order`` key as a number between 0 and -1. The numbers are compared such that 0 is displayed first. Therefore a room -with an ``order`` of ``0.2`` would be displayed before a room with an ``order`` -of ``0.7``. If a room has a tag without an ``order`` key then it should appear +1. The numbers are compared such that 0 is displayed first. Therefore a room +with an ``order`` of ``0.2`` would be displayed before a room with an ``order`` +of ``0.7``. If a room has a tag without an ``order`` key then it should appear after the rooms with that tag that have an ``order`` key. The name of a tag MUST NOT exceed 255 bytes. @@ -60,6 +60,7 @@ The following tags are defined in the ``m.*`` namespace: * ``m.favourite``: The user's favourite rooms. These should be shown with higher precedence than other rooms. * ``m.lowpriority``: These should be shown with lower precedence than others. +* ``m.server_notice``: Used to identify `Server Notice Rooms <#module-server-notices>`_. {{m_tag_event}} diff --git a/specification/modules/third_party_invites.rst b/specification/modules/third_party_invites.rst index 3e11d9295..b8ab9657f 100644 --- a/specification/modules/third_party_invites.rst +++ b/specification/modules/third_party_invites.rst @@ -38,7 +38,8 @@ When the invitee's homeserver receives the notification of the binding, it should insert an ``m.room.member`` event into the room's graph for that user, with ``content.membership`` = ``invite``, as well as a ``content.third_party_invite`` property which contains proof that the invitee -does indeed own that third party identifier. +does indeed own that third party identifier. See the `m.room.member <#m-room-member>`_ +schema for more information. Events diff --git a/specification/proposals.rst b/specification/proposals.rst index 371850ab3..94878f804 100644 --- a/specification/proposals.rst +++ b/specification/proposals.rst @@ -1,6 +1,6 @@ Tables of Tracked Proposals --------------------------- -This file is autogenerated by a jenkins build process +This file is generated by an automated process on our build server. -View the current live version `at https://matrix.org/docs/spec/proposals `_ +View the current live version `at https://matrix.org/docs/spec/proposals `_. diff --git a/specification/proposals_intro.rst b/specification/proposals_intro.rst index 81a3b89a3..20cfd48d2 100644 --- a/specification/proposals_intro.rst +++ b/specification/proposals_intro.rst @@ -13,14 +13,18 @@ Proposals for Spec Changes to Matrix If you are interested in submitting a change to the Matrix Specification, please take note of the following guidelines. -All changes to Specification content require a formal proposal process. This -involves writing a proposal, having it reviewed by everyone, having the -proposal being accepted, then actually having your ideas implemented as -committed changes to the `Specification repository +Most changes to the Specification require a formal proposal. Bug fixes, typos, +and clarifications to existing behaviour do not need proposals - see the +`contributing guide `_ +for more information on what does and does not need a proposal. + +The proposal process involves some technical writing, having it reviewed by +everyone, having the proposal being accepted, then actually having your ideas +implemented as committed changes to the `Specification repository `_. -Meet the `members of the Spec Core Team -`_, a group of +Meet the `members of the Core Team +`_, a group of individuals tasked with ensuring the spec process is as smooth and painless as possible. Members of the Spec Core Team will do their best to participate in discussion, summarise when things become long-winded, and generally try to act @@ -33,22 +37,23 @@ Guiding Principles Proposals **must** act to the greater benefit of the entire Matrix ecosystem, rather than benefiting or privileging any single player or subset of players - -and must not contain any patent encumbered intellectual property. -Members of the Spec Core Team pledge to act as -a neutral custodian for Matrix on behalf of the whole ecosystem. +and must not contain any patent encumbered intellectual property. Members of +the Core Team pledge to act as a neutral custodian for Matrix on behalf of the +whole ecosystem. For clarity: the Matrix ecosystem is anyone who uses the Matrix protocol. That -includes client users, server admins, client developers, bot developers, bridge -and application service developers, users and admins who are indirectly using -Matrix via 3rd party networks which happen to be bridged, server developers, +includes client users, server admins, client developers, bot developers, +bridge and application service developers, users and admins who are indirectly +using Matrix via 3rd party networks which happen to be bridged, server developers, room moderators and admins, companies/projects building products or services on -Matrix, spec contributors, translators, and those who created it in the first -place. +Matrix, spec contributors, translators, and those who created it in +the first place. -"Greater benefit" is defined as maximising: +"Greater benefit" could include maximising: -* the number of Matrix-native end-users reachable on the open Matrix network -* the number of regular users on the Matrix network (e.g. 30-day retained federated users) +* the number of end-users reachable on the open Matrix network +* the number of regular users on the Matrix network (e.g. 30-day retained + federated users) * the number of online servers in the open federation * the number of developers building on Matrix * the number of independent implementations which use Matrix @@ -333,6 +338,7 @@ Spec PR Merged merged A proposal with Postponed proposal-postponed A proposal that is temporarily blocked or a feature that may not be useful currently but perhaps sometime in the future Closed proposal-closed A proposal which has been reviewed and deemed unsuitable for acceptance +Obsolete obsolete A proposal which has been made obsolete by another proposal or decision elsewhere. =============================== ============================= ==================================== diff --git a/specification/rooms/v1.rst b/specification/rooms/v1.rst index 1c7a56c4c..e8cbf6639 100644 --- a/specification/rooms/v1.rst +++ b/specification/rooms/v1.rst @@ -293,5 +293,5 @@ Events in version 1 rooms have the following structure: {{definition_ss_pdu}} -.. _`auth events selection`: ../../server_server/r0.1.1.html#auth-events-selection -.. _`Signing Events`: ../../server_server/r0.1.1.html#signing-events +.. _`auth events selection`: ../server_server/r0.1.1.html#auth-events-selection +.. _`Signing Events`: ../server_server/r0.1.1.html#signing-events diff --git a/specification/rooms/v4.rst b/specification/rooms/v4.rst new file mode 100644 index 000000000..8d2cc59b1 --- /dev/null +++ b/specification/rooms/v4.rst @@ -0,0 +1,76 @@ +.. Copyright 2019 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. + +Room Version 4 +============== + +This room version builds on `version 3 `_ using a different encoding for +event IDs. + +.. contents:: Table of Contents +.. sectnum:: + + +Client considerations +--------------------- + +This room version changes the format form event IDs sent to clients. Clients should +already be treating event IDs as opaque identifiers, and should not be concerned with +the format of them. Clients should still encode the event ID when including it in a +request path. + +Clients should expect to see event IDs changed from the format of ``$randomstring:example.org`` +to something like ``$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg`` (note the lack of domain). + + +Server implementation components +-------------------------------- + +.. WARNING:: + The information contained in this section is strictly for server implementors. + Applications which use the Client-Server API are generally unaffected by the + intricacies contained here. The section above regarding client considerations + is the resource that Client-Server API use cases should reference. + + +Room version 4 uses the same algorithms defined in `room version 3 `_, however +using URL-safe base64 to generate the event ID. + +Event IDs +~~~~~~~~~ + +.. admonition:: Rationale + + Room version 3 generated event IDs that were difficult for client implementations + which were not encoding the event ID to function in those rooms. It additionally + raised concern due to the ``/`` character being interpretted differently by some + reverse proxy software, and generally made administration harder. + +The event ID is the `reference hash`_ of the event encoded using a variation of +`Unpadded Base64`_ which replaces the 62nd and 63rd characters with ``-`` and ``_`` +instead of using ``+`` and ``/``. This matches `RFC4648's definition of URL-safe base64 +`_. Event IDs are still prefixed +with ``$`` and may result in looking like ``$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg``. + +Just like in room version 3, event IDs should not be sent over federation to servers +when the room uses this room version. On the receiving end of an event, the server +should compute the relevant event ID for itself. Room version 3 also changes the format +of ``auth_events`` and ``prev_events`` in a PDU. + +{{definition_ss_pdu_v4}} + +.. _`Unpadded Base64`: ../appendices.html#unpadded-base64 +.. _`Canonical JSON`: ../appendices.html#canonical-json +.. _`Signing Events`: ../server_server/r0.1.1.html#signing-events +.. _`reference hash`: ../server_server/r0.1.1.html#reference-hashes diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index b765e36a1..d608965bd 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -83,6 +83,17 @@ The following other versions are also available, in reverse chronological order: - `r0.1.1 `_ - `r0.1.0 `_ + +API standards +------------- + +The mandatory baseline for client-server communication in Matrix is exchanging +JSON objects over HTTP APIs. More efficient optional transports will in future +be supported as optional extensions - e.g. a packed binary encoding over +stream-cipher encrypted TCP socket for low-bandwidth/low-roundtrip mobile usage. +For the default HTTP transport, all API calls use a Content-Type of +``application/json``. In addition, all strings MUST be encoded as UTF-8. + Server discovery ---------------- @@ -421,9 +432,8 @@ must ensure that the event: Further details of these checks, and how to handle failures, are described below. -.. TODO: - Flesh this out a bit more, and probably change the doc to group the various - checks in one place, rather than have them spread out. +The `Signing Events <#signing-events>`_ section has more information on which hashes +and signatures are expected on events, and how to calculate them. Definitions @@ -1099,6 +1109,15 @@ originating server, following the algorithm described in `Checking for a signatu Note that this step should succeed whether we have been sent the full event or a redacted copy. +The signatures expected on an event are: + +* The ``sender``'s server, unless the invite was created as a result of 3rd party invite. + The sender must already match the 3rd party invite, and the server which actually + sends the event may be a different server. +* For room versions 1 and 2, the server which created the ``event_id``. Other room + versions do not track the ``event_id`` over federation and therefore do not need + a signature from those servers. + If the signature is found to be valid, the expected content hash is calculated as described below. The content hash in the ``hashes`` property of the received event is base64-decoded, and the two are compared for equality. diff --git a/specification/targets.yaml b/specification/targets.yaml index 830449ae5..abcdc2400 100644 --- a/specification/targets.yaml +++ b/specification/targets.yaml @@ -38,6 +38,10 @@ targets: files: - rooms/v3.rst version_label: v3 + rooms@v4: # this is translated to be rooms/v4.html + files: + - rooms/v4.rst + version_label: v4 appendices: files: - appendices.rst @@ -83,6 +87,7 @@ groups: # reusable blobs of files when prefixed with 'group:' - modules/server_acls.rst - modules/mentions.rst - modules/room_upgrades.rst + - modules/server_notices.rst title_styles: ["=", "-", "~", "+", "^", "`", "@", ":"]