diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..3a0b60325 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,64 @@ +gendoc: &gendoc + name: Generate the docs + command: | + source /env/bin/activate + scripts/gendoc.py + +genswagger: &genswagger + name: Generate the swagger + command: | + source /env/bin/activate + scripts/dump-swagger.py + +buildswaggerui: &buildswaggerui + name: Build Swagger UI + command: | + ls scripts/ + mkdir -p api/client-server + git clone https://github.com/matrix-org/swagger-ui swagger-ui + cp -r swagger-ui/dist/* api/client-server/ + mkdir -p api/client-server/json + cp scripts/swagger/api-docs.json api/client-server/json/ + wget https://raw.githubusercontent.com/matrix-org/matrix.org/master/content/swagger.css -O api/client-server/swagger.css + wget https://raw.githubusercontent.com/matrix-org/matrix.org/master/scripts/swagger-ui.patch + patch api/client-server/index.html swagger-ui.patch + + +version: 2 +jobs: + build-docs: + docker: + - image: uhoreg/matrix-doc-build + steps: + - checkout + - run: *gendoc + - store_artifacts: + path: scripts/gen + - run: + name: "Doc build is available at:" + command: DOCS_URL="${CIRCLE_BUILD_URL}/artifacts/${CIRCLE_NODE_INDEX}/${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}/scripts/gen/index.html"; echo $DOCS_URL + + build-swagger: + docker: + - image: uhoreg/matrix-doc-build + steps: + - checkout + - run: *genswagger + - run: *buildswaggerui + - store_artifacts: + path: api/client-server/ + - run: + name: "Swagger UI is available at:" + command: DOCS_URL="${CIRCLE_BUILD_URL}/artifacts/${CIRCLE_NODE_INDEX}/${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}/api/client-server/index.html"; echo $DOCS_URL + +workflows: + version: 2 + + build-spec: + jobs: + - build-docs + - build-swagger + +notify: + webhooks: + - url: https://giles.cadair.com/circleci diff --git a/.gitignore b/.gitignore index 84ac4951c..a850d2faa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ /api/node_modules /assets /assets.tar.gz -/env +/env* /scripts/gen /scripts/continuserv/continuserv /scripts/speculator/speculator @@ -10,3 +10,4 @@ /templating/out *.pyc *.swp +_rendered.rst diff --git a/.travis.yml b/.travis.yml index 7d84f237d..9e9363aff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,15 +2,15 @@ language: go go: - 1.8 -sudo: false +sudo: required # we only need a single git commit git: depth: 1 -# test-and-build does the installation, so tell travis to skip the -# installation step -install: true +install: + - sudo apt-get update + - sudo apt-get install python3 python3-dev script: - ./scripts/test-and-build.sh diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2a7416b17..c592cf02b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -69,6 +69,41 @@ For such changes, please do just open a `pull request`_. .. _pull request: https://help.github.com/articles/about-pull-requests + +Adding to the changelog +~~~~~~~~~~~~~~~~~~~~~~~ + +Currently only changes to the client-server API need to end up in a changelog. The +other APIs are not yet stable and therefore do not have a changelog. Adding to the +changelog can only be done after you've opened your pull request, so be sure to do +that first. + +The changelog is managed by Towncrier (https://github.com/hawkowl/towncrier) in the +form of "news fragments". The news fragments for the client-server API are stored +under ``changelogs/client_server/newsfragments``. + +To create a changelog entry, create a file named in the format ``prNumber.type`` in +the ``newsfragments`` directory. The ``type`` can be one of the following: + +* ``new`` - Used when adding new endpoints. Please have the file contents be the + method and route being added, surrounded in RST code tags. For example: ``POST + /accounts/whoami`` + +* ``feature`` - Used when adding backwards-compatible changes to the API. + +* ``clarification`` - Used when an area of the spec is being improved upon and does + not change or introduce any functionality. + +* ``breaking`` - Used when the change is not backwards compatible. + +* ``deprecation`` - Used when deprecating something + +All news fragments must have a brief summary explaining the change in the contents +of the file. + +Changes that do not change the spec, such as changes to the build script, formatting, +CSS, etc should not get a news fragment. + Sign off -------- diff --git a/README.rst b/README.rst index 6c87201c4..b8847bfb6 100644 --- a/README.rst +++ b/README.rst @@ -41,9 +41,9 @@ specs and event schemas in this repository. Preparation ----------- -To use the scripts, it is best to create a Python 2.x virtualenv as follows:: +To use the scripts, it is best to create a Python 3.4+ virtualenv as follows:: - virtualenv env + virtualenv -p python3 env env/bin/pip install -r scripts/requirements.txt (Benjamin Synders has contributed a script for `Nix`_ users, which can be diff --git a/api/application-service/application_service.yaml b/api/application-service/application_service.yaml index c39ce198f..b459e29ff 100644 --- a/api/application-service/application_service.yaml +++ b/api/application-service/application_service.yaml @@ -1,4 +1,5 @@ # Copyright 2016 OpenMarket Ltd +# Copyright 2018 New Vector Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,8 +30,8 @@ paths: put: summary: Send some events to the application service. description: |- - This API is called by the HS when the HS wants to push an event (or - batch of events) to the AS. + This API is called by the homeserver when it wants to push an event + (or batch of events) to the application service. operationId: sendTransaction parameters: - in: path @@ -47,33 +48,33 @@ paths: schema: type: object example: { - "events": [ - { - "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", - "user_id": "@bob:localhost" + "events": [ + { + "age": 32, + "content": { + "body": "incoming message", + "msgtype": "m.text" }, - { - "age": 1984, - "content": { - "body": "another incoming message", - "msgtype": "m.text" - }, - "event_id": "$1228055551ffsef:localhost", - "origin_server_ts": 1432804485886, - "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", - "type": "m.room.message", - "user_id": "@bob:localhost" - } - ] - } + "event_id": "$14328055551tzaee:localhost", + "origin_server_ts": 1432804485886, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "type": "m.room.message", + "user_id": "@bob:localhost" + }, + { + "age": 1984, + "content": { + "body": "another incoming message", + "msgtype": "m.text" + }, + "event_id": "$1228055551ffsef:localhost", + "origin_server_ts": 1432804485886, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "type": "m.room.message", + "user_id": "@bob:localhost" + } + ] + } description: "Transaction informations" properties: events: @@ -88,10 +89,9 @@ paths: description: The transaction was processed successfully. examples: application/json: { - } + } schema: type: object - "/rooms/{roomAlias}": get: summary: Query if a room alias should exist on the application service. @@ -119,7 +119,7 @@ paths: before responding. examples: application/json: { - } + } schema: type: object 401: @@ -128,29 +128,29 @@ paths: Optional error information can be included in the body of this response. examples: application/json: { - "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" - } + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } schema: - type: object + $ref: ../client-server/definitions/errors/error.yaml 403: description: |- The credentials supplied by the homeserver were rejected. examples: application/json: { - "errcode": "M_FORBIDDEN" - } + "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" + } schema: - type: object + $ref: ../client-server/definitions/errors/error.yaml 404: description: |- The application service indicates that this room alias does not exist. Optional error information can be included in the body of this response. examples: application/json: { - "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" - } + "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" + } schema: - type: object + $ref: ../client-server/definitions/errors/error.yaml "/users/{userId}": get: summary: Query if a user should exist on the application service. @@ -175,7 +175,7 @@ paths: service MUST create the user using the client-server API. examples: application/json: { - } + } schema: type: object 401: @@ -184,26 +184,266 @@ paths: Optional error information can be included in the body of this response. examples: application/json: { - "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" - } + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } schema: - type: object + $ref: ../client-server/definitions/errors/error.yaml 403: description: |- The credentials supplied by the homeserver were rejected. examples: application/json: { - "errcode": "M_FORBIDDEN" - } + "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" + } schema: - type: object + $ref: ../client-server/definitions/errors/error.yaml 404: description: |- The application service indicates that this user does not exist. Optional error information can be included in the body of this response. examples: application/json: { - "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" - } + "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" + } schema: - type: object + $ref: ../client-server/definitions/errors/error.yaml + "/_matrix/app/unstable/thirdparty/protocol/{protocol}": + get: + summary: Retrieve metadata about a specific protocol that the application service supports. + description: |- + This API is called by the homeserver when it wants to present clients + with specific information about the various third party networks that + an application service supports. + operationId: queryMetadata + parameters: + - in: path + name: protocol + type: string + description: The protocol ID. + required: true + x-example: "irc" + responses: + 200: + description: The protocol was found and metadata returned. + schema: + $ref: definitions/protocol_metadata.yaml + 401: + description: |- + The homeserver has not supplied credentials to the application service. + Optional error information can be included in the body of this response. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 403: + description: |- + The credentials supplied by the homeserver were rejected. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 404: + description: No protocol was found with the given path. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + "/_matrix/app/unstable/thirdparty/user/{protocol}": + get: + summary: Retrieve the Matrix User ID of a corresponding third party user. + description: |- + This API is called by the homeserver in order to retrieve a Matrix + User ID linked to a user on the third party network, given a set of + user parameters. + operationId: queryUserByProtocol + parameters: + - in: path + name: protocol + type: string + description: The protocol ID. + required: true + x-example: irc + - in: query + name: field1, field2... + type: string + description: |- + One or more custom fields that are passed to the application + service to help identify the user. + responses: + 200: + description: The Matrix User IDs found with the given parameters. + schema: + $ref: definitions/user_batch.yaml + 401: + description: |- + The homeserver has not supplied credentials to the application service. + Optional error information can be included in the body of this response. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 403: + description: |- + The credentials supplied by the homeserver were rejected. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 404: + description: No users were found with the given parameters. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + "/_matrix/app/unstable/thirdparty/location/{protocol}": + get: + summary: Retreive Matrix-side portal rooms leading to a third party location. + description: |- + Retrieve a list of Matrix portal rooms that lead to the matched third party location. + operationId: queryLocationByProtocol + parameters: + - in: path + name: protocol + type: string + description: The protocol ID. + required: true + x-example: irc + - in: query + name: field1, field2... + type: string + description: |- + One or more custom fields that are passed to the application + service to help identify the third party location. + responses: + 200: + description: At least one portal room was found. + schema: + $ref: definitions/location_batch.yaml + 401: + description: |- + The homeserver has not supplied credentials to the application service. + Optional error information can be included in the body of this response. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 403: + description: |- + The credentials supplied by the homeserver were rejected. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 404: + description: No mappings were found with the given parameters. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + "/_matrix/app/unstable/thirdparty/location": + get: + summary: Reverse-lookup third party locations given a Matrix room alias. + description: |- + Retreive an array of third party network locations from a Matrix room + alias. + operationId: queryLocationByAlias + parameters: + - in: query + name: alias + type: string + description: The Matrix room alias to look up. + responses: + 200: + description: |- + All found third party locations. + schema: + $ref: definitions/location_batch.yaml + 401: + description: |- + The homeserver has not supplied credentials to the application service. + Optional error information can be included in the body of this response. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 403: + description: |- + The credentials supplied by the homeserver were rejected. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 404: + description: No mappings were found with the given parameters. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + "/_matrix/app/unstable/thirdparty/user": + get: + summary: Reverse-lookup third party users given a Matrix User ID. + description: |- + Retreive an array of third party users from a Matrix User ID. + operationId: queryUserByID + parameters: + - in: query + name: userid + type: string + description: The Matrix User ID to look up. + responses: + 200: + description: |- + An array of third party users. + schema: + $ref: definitions/user_batch.yaml + 401: + description: |- + The homeserver has not supplied credentials to the application service. + Optional error information can be included in the body of this response. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 403: + description: |- + The credentials supplied by the homeserver were rejected. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml + 404: + description: No mappings were found with the given parameters. + examples: + application/json: { + "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" + } + schema: + $ref: ../client-server/definitions/errors/error.yaml \ No newline at end of file diff --git a/api/application-service/definitions/location.yaml b/api/application-service/definitions/location.yaml new file mode 100644 index 000000000..4967ef61f --- /dev/null +++ b/api/application-service/definitions/location.yaml @@ -0,0 +1,30 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +properties: + alias: + description: An alias for a matrix room. + type: string + example: "#freenode_#matrix:matrix.org" + protocol: + description: The protocol ID that the third party location is a part of. + type: string + example: irc + fields: + description: Information used to identify this third party location. + type: object + example: + "network": "freenode" + "channel": "#matrix" +title: Location +type: object \ No newline at end of file diff --git a/api/application-service/definitions/location_batch.yaml b/api/application-service/definitions/location_batch.yaml new file mode 100644 index 000000000..3f6de9df0 --- /dev/null +++ b/api/application-service/definitions/location_batch.yaml @@ -0,0 +1,17 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: array +description: List of matched third party locations. +items: + $ref: location.yaml diff --git a/api/application-service/definitions/protocol.yaml b/api/application-service/definitions/protocol.yaml new file mode 100644 index 000000000..231e8288a --- /dev/null +++ b/api/application-service/definitions/protocol.yaml @@ -0,0 +1,79 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +properties: + user_fields: + description: Fields used to identify a third party user. + type: array + items: + type: string + description: Field used to identify a third party user. + example: ["network", "nickname"] + location_fields: + description: Fields used to identify a third party location. + type: array + items: + type: string + description: Field used to identify a third party location. + example: ["network", "channel"] + icon: + description: An icon representing the third party protocol. + type: string + example: "mxc://example.org/aBcDeFgH" + field_types: + title: Field Types + description: All location or user fields should have an entry here. + type: object + properties: + fieldname: + title: Field Type + description: Definition of valid values for a field. + type: object + properties: + regexp: + description: A regular expression for validation of a field's value. + type: string + placeholder: + description: An placeholder serving as a valid example of the field value. + type: string + example: { + "network": { + "regexp": "([a-z0-9]+\\.)*[a-z0-9]+", + "placeholder": "irc.example.org" + }, + "nickname": { + "regexp": "[^\\s#]+", + "placeholder": "username" + }, + "channel": { + "regexp": "#[^\\s]+", + "placeholder": "#foobar" + } + } + instances: + description: |- + A list of objects representing independent instances of configuration. + For instance multiple networks on IRC if multiple are bridged by the + same bridge. + type: array + items: + type: object + example: { + "desc": "Freenode", + "icon": "mxc://example.org/JkLmNoPq", + "fields": { + "network": "freenode.net", + } + } +title: Protocol +type: object \ No newline at end of file diff --git a/api/application-service/definitions/protocol_metadata.yaml b/api/application-service/definitions/protocol_metadata.yaml new file mode 100644 index 000000000..722640602 --- /dev/null +++ b/api/application-service/definitions/protocol_metadata.yaml @@ -0,0 +1,66 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +description: Dictionary of supported third party protocols. +example: { + "irc": { + "user_fields": ["network", "nickname"], + "location_fields": ["network", "channel"], + "icon": "mxc://example.org/aBcDeFgH", + "field_types": { + "network": { + "regexp": "([a-z0-9]+\\.)*[a-z0-9]+", + "placeholder": "irc.example.org" + }, + "nickname": { + "regexp": "[^\\s]+", + "placeholder": "username" + }, + "channel": { + "regexp": "#[^\\s]+", + "placeholder": "#foobar" + } + }, + "instances": [ + { + "desc": "Freenode", + "icon": "mxc://example.org/JkLmNoPq", + "fields": { + "network": "freenode.net", + } + } + ] + }, + "gitter": { + "user_fields": ["username"], + "location_fields": ["room"], + "field_types": { + "username": { + "regexp": "@[^\\s]+", + "placeholder": "@username" + }, + "room": { + "regexp": "[^\\s]+\\/[^\\s]+", + "placeholder": "matrix-org/matrix-doc" + } + }, + "instances": [ + { + "desc": "Gitter", + "icon": "mxc://example.org/zXyWvUt", + "fields": {} + } + ] + } +} \ No newline at end of file diff --git a/api/application-service/definitions/user.yaml b/api/application-service/definitions/user.yaml new file mode 100644 index 000000000..5f8d0460f --- /dev/null +++ b/api/application-service/definitions/user.yaml @@ -0,0 +1,31 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: Change userid to user_id as a breaking change +properties: + userid: + description: A Matrix User ID represting a third party user. + type: string + example: "@_gitter_jim:matrix.org" + protocol: + description: The protocol ID that the third party location is a part of. + type: string + example: gitter + fields: + description: Information used to identify this third party location. + type: object + example: + "user": "jim" +title: Location +type: object \ No newline at end of file diff --git a/api/application-service/definitions/user_batch.yaml b/api/application-service/definitions/user_batch.yaml new file mode 100644 index 000000000..3653feb44 --- /dev/null +++ b/api/application-service/definitions/user_batch.yaml @@ -0,0 +1,17 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: array +description: List of matched third party users. +items: + $ref: user.yaml diff --git a/api/client-server/administrative_contact.yaml b/api/client-server/administrative_contact.yaml index e7381a555..8f0319d5a 100644 --- a/api/client-server/administrative_contact.yaml +++ b/api/client-server/administrative_contact.yaml @@ -129,6 +129,8 @@ paths: "errcode": "M_THREEPID_AUTH_FAILED", "error": "The third party credentials could not be verified by the identity server." } + schema: + "$ref": "definitions/errors/error.yaml" tags: - User data "/account/3pid/email/requestToken": diff --git a/api/client-server/banning.yaml b/api/client-server/banning.yaml index 3877f0e90..6ef430df6 100644 --- a/api/client-server/banning.yaml +++ b/api/client-server/banning.yaml @@ -61,7 +61,8 @@ paths: description: The fully qualified user ID of the user being banned. reason: type: string - description: The reason the user has been banned. + description: The reason the user has been banned. This will be supplied as the + ``reason`` on the target's updated `m.room.member`_ event. required: ["user_id"] responses: 200: @@ -82,6 +83,8 @@ paths: "errcode": "M_FORBIDDEN", "error": "You do not have a high enough power level to ban from this room." } + schema: + "$ref": "definitions/errors/error.yaml" tags: - Room membership "/rooms/{roomId}/unban": @@ -133,5 +136,7 @@ paths: "errcode": "M_FORBIDDEN", "error": "You do not have a high enough power level to unban from this room." } + schema: + "$ref": "definitions/errors/error.yaml" tags: - Room membership diff --git a/api/client-server/content-repo.yaml b/api/client-server/content-repo.yaml index 943fee3cd..b3e9517b1 100644 --- a/api/client-server/content-repo.yaml +++ b/api/client-server/content-repo.yaml @@ -72,7 +72,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Media "/download/{serverName}/{mediaId}": @@ -120,7 +120,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Media "/download/{serverName}/{mediaId}/{fileName}": @@ -175,7 +175,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Media "/thumbnail/{serverName}/{mediaId}": @@ -241,7 +241,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Media "/preview_url": @@ -296,6 +296,47 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" + tags: + - Media + "/config": + get: + summary: Get the configuration for the content repository. + description: |- + This endpoint allows clients to retrieve the configuration of the content + repository, such as upload limitations. + Clients SHOULD use this as a guide when using content repository endpoints. + All values are intentionally left optional. Clients SHOULD follow + the advice given in the field description when the field is not available. + + **NOTE:** Both clients and server administrators should be aware that proxies + between the client and the server may affect the apparent behaviour of content + repository APIs, for example, proxies may enforce a lower upload size limit + than is advertised by the server on this endpoint. + operationId: getConfig + produces: ["application/json"] + security: + - accessToken: [] + responses: + 200: + description: The public content repository configuration for the matrix server. + schema: + type: object + properties: + m.upload.size: + type: number + 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. + examples: + application/json: { + "m.upload.size": 50000000 + } + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/error.yaml" + tags: - Media diff --git a/api/client-server/create_room.yaml b/api/client-server/create_room.yaml index 3e88ee0c0..66b5578a5 100644 --- a/api/client-server/create_room.yaml +++ b/api/client-server/create_room.yaml @@ -1,4 +1,5 @@ # Copyright 2016 OpenMarket Ltd +# Copyright 2018 New Vector Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -40,7 +41,7 @@ paths: 0. A default ``m.room.power_levels`` event, giving the room creator (and not other members) permission to send state events. - 1. Events set by ``presets``. + 1. Events set by the ``preset``. 2. Events listed in ``initial_state``, in the order that they are listed. @@ -49,6 +50,16 @@ paths: 4. Invite events implied by ``invite`` and ``invite_3pid``. + The available presets do the following with respect to room state: + + ======================== ============== ====================== ================ ========= + Preset ``join_rules`` ``history_visibility`` ``guest_access`` Other + ======================== ============== ====================== ================ ========= + ``private_chat`` ``invite`` ``shared`` ``can_join`` + ``trusted_private_chat`` ``invite`` ``shared`` ``can_join`` All invitees are given the same power level as the room creator. + ``public_chat`` ``public`` ``shared`` ``forbidden`` + ======================== ============== ====================== ================ ========= + operationId: createRoom security: - accessToken: [] @@ -142,7 +153,7 @@ paths: room. The expected format of the state events are an object with type, state_key and content keys set. - Takes precedence over events set by ``presets``, but gets + Takes precedence over events set by ``preset``, but gets overriden by ``name`` and ``topic`` keys. items: type: object @@ -163,20 +174,7 @@ paths: enum: ["private_chat", "public_chat", "trusted_private_chat"] description: |- Convenience parameter for setting various default state events - based on a preset. Must be either: - - ``private_chat`` => - ``join_rules`` is set to ``invite``. - ``history_visibility`` is set to ``shared``. - - ``trusted_private_chat`` => - ``join_rules`` is set to ``invite``. - ``history_visibility`` is set to ``shared``. - All invitees are given the same power level as the room creator. - - ``public_chat``: => - ``join_rules`` is set to ``public``. - ``history_visibility`` is set to ``shared``. + based on a preset. is_direct: type: boolean description: |- @@ -218,6 +216,8 @@ paths: invalid: for example, the user's ``power_level`` is set below that necessary to set the room name (``errcode`` set to ``M_INVALID_ROOM_STATE``). + schema: + "$ref": "definitions/errors/error.yaml" tags: - Room creation diff --git a/api/client-server/definitions/error.yaml b/api/client-server/definitions/errors/error.yaml similarity index 90% rename from api/client-server/definitions/error.yaml rename to api/client-server/definitions/errors/error.yaml index fa5cada7a..7471da6f6 100644 --- a/api/client-server/definitions/error.yaml +++ b/api/client-server/definitions/errors/error.yaml @@ -17,7 +17,9 @@ properties: errcode: type: string description: An error code. + example: M_UNKNOWN error: type: string description: A human-readable error message. + example: An unknown error occurred required: ["errcode"] \ No newline at end of file diff --git a/api/client-server/definitions/errors/rate_limited.yaml b/api/client-server/definitions/errors/rate_limited.yaml new file mode 100644 index 000000000..aca82ce7b --- /dev/null +++ b/api/client-server/definitions/errors/rate_limited.yaml @@ -0,0 +1,32 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +$ref: error.yaml +type: object +description: The rate limit was reached for this request +properties: + errcode: + type: string + description: The M_LIMIT_EXCEEDED error code + example: M_LIMIT_EXCEEDED + error: + type: string + description: A human-readable error message. + example: Too many requests + retry_after_ms: + type: integer + description: |- + The amount of time in milliseconds the client should wait + before trying the request again. + example: 2000 +required: ["errcode"] \ No newline at end of file diff --git a/api/client-server/directory.yaml b/api/client-server/directory.yaml index a50bab629..ee42cf845 100644 --- a/api/client-server/directory.yaml +++ b/api/client-server/directory.yaml @@ -68,6 +68,8 @@ paths: "errcode": "M_UNKNOWN", "error": "Room alias #monkeys:matrix.org already exists." } + schema: + "$ref": "definitions/errors/error.yaml" tags: - Room directory get: @@ -118,6 +120,8 @@ paths: "errcode": "M_NOT_FOUND", "error": "Room alias #monkeys:matrix.org not found." } + schema: + "$ref": "definitions/errors/error.yaml" tags: - Room directory delete: diff --git a/api/client-server/inviting.yaml b/api/client-server/inviting.yaml index 47f51bd47..f312d5ceb 100644 --- a/api/client-server/inviting.yaml +++ b/api/client-server/inviting.yaml @@ -93,9 +93,11 @@ paths: examples: application/json: { "errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"} + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room membership diff --git a/api/client-server/joining.yaml b/api/client-server/joining.yaml index da4e43371..7dc1e0a4a 100644 --- a/api/client-server/joining.yaml +++ b/api/client-server/joining.yaml @@ -110,10 +110,12 @@ paths: examples: application/json: { "errcode": "M_FORBIDDEN", "error": "You are not invited to this room."} + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room membership "/join/{roomIdOrAlias}": @@ -143,6 +145,15 @@ paths: description: The room identifier or alias to join. required: true x-example: "#monkeys:matrix.org" + - in: query + type: array + items: + type: string + name: server_name + description: |- + The servers to attempt to join the room through. One of the servers + must be participating in the room. + x-example: ["matrix.org", "elsewhere.ca"] - in: body name: third_party_signed schema: @@ -206,9 +217,11 @@ paths: examples: application/json: { "errcode": "M_FORBIDDEN", "error": "You are not invited to this room."} + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room membership diff --git a/api/client-server/kicking.yaml b/api/client-server/kicking.yaml index ef43c0ee9..7fbee38bd 100644 --- a/api/client-server/kicking.yaml +++ b/api/client-server/kicking.yaml @@ -34,6 +34,10 @@ paths: Kick a user from the room. The caller must have the required power level in order to perform this operation. + + Kicking a user adjusts the target member's membership state to be ``leave`` with an + optional ``reason``. Like with other membership changes, a user can directly adjust + the target member's state by making a request to ``/rooms//state/m.room.member/``. operationId: kick security: - accessToken: [] @@ -59,7 +63,9 @@ paths: description: The fully qualified user ID of the user being kicked. reason: type: string - description: The reason the user has been kicked. + description: |- + The reason the user has been kicked. This will be supplied as the + ``reason`` on the target's updated `m.room.member`_ event. required: ["user_id"] responses: 200: @@ -81,5 +87,7 @@ paths: "errcode": "M_FORBIDDEN", "error": "You do not have a high enough power level to kick from this room." } + schema: + "$ref": "definitions/errors/error.yaml" tags: - Room membership diff --git a/api/client-server/leaving.yaml b/api/client-server/leaving.yaml index 36351fd44..513b5b4d1 100644 --- a/api/client-server/leaving.yaml +++ b/api/client-server/leaving.yaml @@ -64,7 +64,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room membership "/rooms/{roomId}/forget": @@ -78,8 +78,8 @@ paths: for this room. If all users on a homeserver forget a room, the room is eligible for deletion from that homeserver. - If the user is currently joined to the room, they will implicitly leave - the room as part of this API call. + If the user is currently joined to the room, they must leave the room + before calling this API. operationId: forgetRoom security: - accessToken: [] @@ -99,9 +99,18 @@ paths: } schema: type: object + 400: + description: The user has not left the room + examples: + application/json: { + "errcode": "M_UNKNOWN", + "error": "User @example:matrix.org is in room !au1ba7o:matrix.org" + } + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room membership diff --git a/api/client-server/list_public_rooms.yaml b/api/client-server/list_public_rooms.yaml index 334d528c3..45034488a 100644 --- a/api/client-server/list_public_rooms.yaml +++ b/api/client-server/list_public_rooms.yaml @@ -59,6 +59,8 @@ paths: "errcode": "M_NOT_FOUND", "error": "Room not found" } + schema: + "$ref": "definitions/errors/error.yaml" put: summary: Sets the visibility of a room in the room directory description: |- @@ -107,6 +109,8 @@ paths: "errcode": "M_NOT_FOUND", "error": "Room not found" } + schema: + "$ref": "definitions/errors/error.yaml" "/publicRooms": get: summary: Lists the public rooms on the server. diff --git a/api/client-server/login.yaml b/api/client-server/login.yaml index c0db2299b..289b17e78 100644 --- a/api/client-server/login.yaml +++ b/api/client-server/login.yaml @@ -61,7 +61,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Session management post: @@ -167,15 +167,19 @@ paths: "errcode": "M_UNKNOWN", "error": "Bad login type." } + schema: + "$ref": "definitions/errors/error.yaml" 403: description: |- The login attempt failed. For example, the password may have been incorrect. examples: application/json: { "errcode": "M_FORBIDDEN"} + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Session management diff --git a/api/client-server/message_pagination.yaml b/api/client-server/message_pagination.yaml index 714066534..941e61fb9 100644 --- a/api/client-server/message_pagination.yaml +++ b/api/client-server/message_pagination.yaml @@ -107,6 +107,7 @@ paths: items: type: object title: RoomEvent + "$ref": "definitions/event-schemas/schema/core-event-schema/room_event.yaml" examples: application/json: { "start": "t47429-4392820_219380_26003_2265", diff --git a/api/client-server/presence.yaml b/api/client-server/presence.yaml index ba202c2da..91b75c6a8 100644 --- a/api/client-server/presence.yaml +++ b/api/client-server/presence.yaml @@ -75,7 +75,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Presence get: @@ -83,6 +83,8 @@ paths: description: |- Get the given user's presence state. operationId: getPresence + security: + - accessToken: [] parameters: - in: path type: string @@ -121,6 +123,17 @@ paths: description: |- There is no presence state for this user. This user may not exist or isn't exposing presence information to you. + schema: + "$ref": "definitions/errors/error.yaml" + 403: + description: You are not allowed to see this user's presence status. + examples: + application/json: { + "errcode": "M_FORBIDDEN", + "error": "You are not allowed to see their presence" + } + schema: + "$ref": "definitions/errors/error.yaml" tags: - Presence "/presence/list/{userId}": @@ -176,7 +189,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Presence get: diff --git a/api/client-server/profile.yaml b/api/client-server/profile.yaml index 0cada0cad..c8dc40563 100644 --- a/api/client-server/profile.yaml +++ b/api/client-server/profile.yaml @@ -67,7 +67,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data get: @@ -141,7 +141,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data get: diff --git a/api/client-server/pusher.yaml b/api/client-server/pusher.yaml index 9cf40a061..938014c60 100644 --- a/api/client-server/pusher.yaml +++ b/api/client-server/pusher.yaml @@ -228,10 +228,10 @@ paths: "errcode": "M_MISSING_PARAM" } schema: - type: object + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Push notifications diff --git a/api/client-server/pushrules.yaml b/api/client-server/pushrules.yaml index 801349efa..ceb9954b1 100644 --- a/api/client-server/pushrules.yaml +++ b/api/client-server/pushrules.yaml @@ -438,11 +438,11 @@ paths: "errcode": "M_UNKNOWN" } schema: - type: object + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Push notifications "/pushrules/{scope}/{kind}/{ruleId}/enabled": diff --git a/api/client-server/receipts.yaml b/api/client-server/receipts.yaml index e46359a99..a3e9789e9 100644 --- a/api/client-server/receipts.yaml +++ b/api/client-server/receipts.yaml @@ -76,6 +76,6 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room participation diff --git a/api/client-server/registration.yaml b/api/client-server/registration.yaml index 1c544afed..6ae4ddd37 100644 --- a/api/client-server/registration.yaml +++ b/api/client-server/registration.yaml @@ -177,6 +177,8 @@ paths: "errcode": "M_USER_IN_USE", "error": "Desired user ID is already taken." } + schema: + "$ref": "definitions/errors/error.yaml" 401: description: |- The homeserver requires additional authentication information. @@ -185,7 +187,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data "/register/email/requestToken": @@ -249,7 +251,7 @@ paths: "error": "The specified address is already in use" } schema: - type: object + "$ref": "definitions/errors/error.yaml" "/account/password": post: summary: "Changes a user's password." @@ -296,7 +298,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data "/account/password/email/requestToken": @@ -363,7 +365,7 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data "/register/available": @@ -420,9 +422,11 @@ paths: "errcode": "M_USER_IN_USE", "error": "Desired user ID is already taken." } + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data diff --git a/api/client-server/search.yaml b/api/client-server/search.yaml index e5f6a872b..e4118c32b 100644 --- a/api/client-server/search.yaml +++ b/api/client-server/search.yaml @@ -74,7 +74,7 @@ paths: properties: room_events: type: object - title: "Room Events" + title: Room Events Criteria description: Mapping of category name to search criteria. properties: search_term: @@ -103,7 +103,7 @@ paths: The order in which to search for results. By default, this is ``"rank"``. event_context: - title: "Event Context" + title: Include Event Context type: object description: |- Configures whether any context for the events @@ -169,13 +169,13 @@ paths: properties: search_categories: type: object - title: Categories + title: Result Categories description: Describes which categories to search in and their criteria. properties: room_events: type: object - title: Room Event Results + title: Result Room Events description: Mapping of category name to search criteria. properties: count: @@ -227,6 +227,9 @@ paths: description: |- The historic profile information of the users that sent the events returned. + + The ``string`` key is the user ID for which + the profile belongs to. additionalProperties: type: object title: User Profile @@ -260,15 +263,24 @@ paths: The current state for every room in the results. This is included if the request had the ``include_state`` key set with a value of ``true``. + + The ``string`` key is the room ID for which the ``State + Event`` array belongs to. additionalProperties: type: array title: Room State items: + type: object "$ref": "definitions/event-schemas/schema/core-event-schema/state_event.yaml" groups: type: object title: Groups - description: Any groups that were requested. + description: |- + 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: + a room's ID or a user's ID). additionalProperties: type: object title: Group Key @@ -355,6 +367,6 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Search diff --git a/api/client-server/third_party_lookup.yaml b/api/client-server/third_party_lookup.yaml new file mode 100644 index 000000000..55d4c70a2 --- /dev/null +++ b/api/client-server/third_party_lookup.yaml @@ -0,0 +1,194 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +swagger: '2.0' +info: + title: "Matrix Client-Server Third Party Lookup API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% +consumes: + - application/json +produces: + - application/json +securityDefinitions: + $ref: definitions/security.yaml +paths: + "/thirdparty/protocols": + get: + summary: Retrieve metadata about all protocols that a homeserver supports. + description: |- + Fetches the overall metadata about protocols supported by the + homeserver. Includes both the available protocols and all fields + required for queries against each protocol. + operationId: queryMetadata + responses: + 200: + description: The protocols supported by the homeserver. + schema: + $ref: ../application-service/definitions/protocol_metadata.yaml + "/thirdparty/protocol/{protocol}": + get: + summary: Retrieve metadata about a specific protocol that the homeserver supports. + description: |- + Fetches the metadata from the homeserver about a particular third party protocol. + operationId: queryMetadata + parameters: + - in: path + name: protocol + type: string + description: |- + The name of the protocol. + required: true + x-example: "irc" + responses: + 200: + description: The protocol was found and metadata returned. + schema: + $ref: ../application-service/definitions/protocol.yaml + 404: + description: The protocol is unknown. + examples: + application/json: { + "errcode": "M_NOT_FOUND" + } + schema: + $ref: definitions/errors/error.yaml + "/thirdparty/location/{protocol}": + get: + summary: Retreive Matrix-side portals rooms leading to a third party location. + description: |- + Requesting this endpoint with a valid protocol name results in a list + of successful mapping results in a JSON array. Each result contains + objects to represent the Matrix room or rooms that represent a portal + to this third party network. Each has the Matrix room alias string, + an identifier for the particular third party network protocol, and an + object containing the network-specific fields that comprise this + identifier. It should attempt to canonicalise the identifier as much + as reasonably possible given the network type. + operationId: queryLocationByProtocol + parameters: + - in: path + name: protocol + type: string + description: The protocol used to communicate to the third party network. + required: true + x-example: irc + - in: query + name: searchFields + type: string + description: |- + One or more custom fields to help identify the third party + location. + responses: + 200: + description: At least one portal room was found. + schema: + $ref: ../application-service/definitions/location_batch.yaml + 404: + description: No portal rooms were found. + examples: + application/json: { + "errcode": "M_NOT_FOUND" + } + schema: + $ref: definitions/errors/error.yaml + "/thirdparty/user/{protocol}": + get: + summary: Retrieve the Matrix User ID of a corresponding third party user. + description: |- + Retrieve a Matrix User ID linked to a user on the third party service, given + a set of user parameters. + operationId: queryUserByProtocol + parameters: + - in: path + name: protocol + type: string + description: |- + The name of the protocol. + required: true + x-example: irc + - in: query + name: field1, field2... + type: string + description: |- + One or more custom fields that are passed to the AS to help identify the user. + responses: + 200: + description: The Matrix User IDs found with the given parameters. + schema: + $ref: ../application-service/definitions/user_batch.yaml + 404: + description: The Matrix User ID was not found + examples: + application/json: { + "errcode": "M_NOT_FOUND" + } + schema: + $ref: definitions/errors/error.yaml + "/thirdparty/location": + get: + summary: Reverse-lookup third party locations given a Matrix room alias. + description: |- + Retreive an array of third party network locations from a Matrix room + alias. + operationId: queryLocationByAlias + parameters: + - in: query + name: alias + type: string + description: The Matrix room alias to look up. + required: true + responses: + 200: + description: |- + All found third party locations. + schema: + $ref: ../application-service/definitions/location_batch.yaml + 404: + description: The Matrix room alias was not found + examples: + application/json: { + "errcode": "M_NOT_FOUND" + } + schema: + $ref: definitions/errors/error.yaml + "/thirdparty/user": + get: + summary: Reverse-lookup third party users given a Matrix User ID. + description: |- + Retreive an array of third party users from a Matrix User ID. + operationId: queryUserByID + parameters: + - in: query + name: userid + type: string + description: The Matrix User ID to look up. + required: true + responses: + 200: + description: |- + An array of third party users. + schema: + $ref: ../application-service/definitions/user_batch.yaml + 404: + description: The Matrix User ID was not found + examples: + application/json: { + "errcode": "M_NOT_FOUND" + } + schema: + $ref: definitions/errors/error.yaml \ No newline at end of file diff --git a/api/client-server/third_party_membership.yaml b/api/client-server/third_party_membership.yaml index 612b22d05..66c14c4d3 100644 --- a/api/client-server/third_party_membership.yaml +++ b/api/client-server/third_party_membership.yaml @@ -126,9 +126,11 @@ paths: examples: application/json: { "errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"} + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room membership diff --git a/api/client-server/typing.yaml b/api/client-server/typing.yaml index e2a8f9bd1..e7cbe2d7d 100644 --- a/api/client-server/typing.yaml +++ b/api/client-server/typing.yaml @@ -82,6 +82,6 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - Room participation diff --git a/api/client-server/users.yaml b/api/client-server/users.yaml index 1734e3bb8..a682b4358 100644 --- a/api/client-server/users.yaml +++ b/api/client-server/users.yaml @@ -95,6 +95,6 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data diff --git a/api/client-server/voip.yaml b/api/client-server/voip.yaml index 6d6136a54..75ace4c3a 100644 --- a/api/client-server/voip.yaml +++ b/api/client-server/voip.yaml @@ -73,6 +73,6 @@ paths: 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - VOIP diff --git a/api/client-server/whoami.yaml b/api/client-server/whoami.yaml index 8f5abdf79..ad40eb869 100644 --- a/api/client-server/whoami.yaml +++ b/api/client-server/whoami.yaml @@ -65,7 +65,7 @@ paths: "error": "Unrecognised access token." } schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/error.yaml" 403: description: The appservice cannot masquerade as the user or has not registered them. @@ -75,10 +75,10 @@ paths: "error": "Application service has not registered this user." } schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: - "$ref": "definitions/error.yaml" + "$ref": "definitions/errors/rate_limited.yaml" tags: - User data diff --git a/api/server-server/definitions/edu.yaml b/api/server-server/definitions/edu.yaml new file mode 100644 index 000000000..c89573feb --- /dev/null +++ b/api/server-server/definitions/edu.yaml @@ -0,0 +1,40 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: Address any concerns about this being inaccurate (flagged as such in the EDUs section) + +type: object +title: Ephemeral Data Unit +description: An ephemeral data unit +example: + $ref: "../examples/edu.json" +properties: + edu_type: + type: string + description: The type of ephemeral message. + example: "m.presence" + required: true + origin: + type: string + description: The server name sending the ephemeral message. + example: "matrix.org" + required: true + destination: + type: string + description: The server name receiving the ephemeral message. + example: "elsewhere.com" + required: true + content: + type: object + description: The content of the ephemeral message. diff --git a/api/server-server/definitions/keys.yaml b/api/server-server/definitions/keys.yaml new file mode 100644 index 000000000..b08f24650 --- /dev/null +++ b/api/server-server/definitions/keys.yaml @@ -0,0 +1,96 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +title: Server Keys +description: Server keys +example: + $ref: "../examples/server_key.json" +properties: + server_name: + type: string + description: DNS name of the homeserver. + required: true # TODO: Verify + example: "example.org" + verify_keys: + type: object + description: Public keys of the homeserver for verifying digital signatures. + required: true # TODO: Verify + additionalProperties: + type: object + title: Verify Key + example: { + "ed25519:auto2": { + "key": "Base+64+Encoded+Signature+Verification+Key" + } + } + properties: + key: + type: string + description: The key + required: true + example: "Base+64+Encoded+Signature+Verification+Key" + old_verify_keys: + type: object + description: The public keys that the server used to use and when it stopped using them. + additionalProperties: + type: object + title: Old Verify Key + example: { + "ed25519:auto1": { + "expired_ts": 922834800000, + "key": "Base+64+Encoded+Signature+Verification+Key" + } + } + properties: + expired_ts: + type: integer + format: int64 + description: The expiration time. + required: true + example: 922834800000 + key: + type: string + description: The key. + required: true + example: "Base+64+Encoded+Signature+Verification+Key" + signatures: + type: object + description: Digital signatures for this object signed using the ``verify_keys``. + additionalProperties: + type: object + title: Signed Server + example: { + "example.org": { + "ad25519:auto2": "Base+64+Encoded+Signature+Verification+Key" + } + } + additionalProperties: + type: string + name: Encoded Signature Verification Key + tls_fingerprints: + type: array + description: Hashes of X.509 TLS certificates used by this server encoded as `Unpadded Base64`_. + items: + type: object + title: TLS Fingerprint + properties: + sha256: + type: string + description: The encoded fingerprint. + example: Base+64+Encoded+SHA-256-Fingerprint + valid_until_ts: + type: integer + format: int64 + description: POSIX timestamp when the list of valid keys should be refreshed. + example: 1052262000000 diff --git a/api/server-server/definitions/keys_query_response.yaml b/api/server-server/definitions/keys_query_response.yaml new file mode 100644 index 000000000..bf2d238f8 --- /dev/null +++ b/api/server-server/definitions/keys_query_response.yaml @@ -0,0 +1,27 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +description: Server keys +example: { + "server_keys": [{ + $ref: "../examples/server_key.json" + }] +} +properties: + server_keys: + type: array + title: Server Keys + description: The server keys. + items: + $ref: "keys.yaml" diff --git a/api/server-server/definitions/pdu.yaml b/api/server-server/definitions/pdu.yaml new file mode 100644 index 000000000..a5da57c04 --- /dev/null +++ b/api/server-server/definitions/pdu.yaml @@ -0,0 +1,52 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +title: Persistent Data Unit +description: A persistent data unit (event) +example: + $ref: "../examples/pdu.json" +allOf: + - $ref: "unsigned_pdu.yaml" + - type: object + properties: + hashes: + type: object + title: Event Hash + description: Hashes of the PDU, following the algorithm specified in `Signing Events`_. + example: { + "sha256": "thishashcoversallfieldsincasethisisredacted" + } + properties: + sha256: + type: string + description: The hash. + example: thishashcoversallfieldsincasthisisredacted + required: ['sha256'] + signatures: + type: object + description: |- + Signatures of the redacted PDU, following the algorithm specified in `Signing Events`_. + example: { + "example.com": { + "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus" + } + } + additionalProperties: + type: object + title: Server Signatures + additionalProperties: + type: string + required: + - hashes + - signatures diff --git a/api/server-server/definitions/transaction.yaml b/api/server-server/definitions/transaction.yaml new file mode 100644 index 000000000..930ddec1a --- /dev/null +++ b/api/server-server/definitions/transaction.yaml @@ -0,0 +1,35 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +title: Transaction +description: Transaction +example: + $ref: "../examples/transaction.json" +properties: + origin: + type: string + description: |- + The ``server_name`` of the homeserver sending this transaction. + example: "example.org" + origin_server_ts: + type: integer + format: int64 + description: Timestamp in milliseconds on originating homeserver when this transaction started. + example: 1234567890 + pdus: + type: array + description: List of persistent updates to rooms. + items: + $ref: "pdu.yaml" +required: ['origin', 'origin_server_ts', 'pdus'] \ No newline at end of file diff --git a/api/server-server/definitions/unsigned_pdu.yaml b/api/server-server/definitions/unsigned_pdu.yaml new file mode 100644 index 000000000..011b27363 --- /dev/null +++ b/api/server-server/definitions/unsigned_pdu.yaml @@ -0,0 +1,118 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +title: Unsigned Persistent Data Unit +description: An unsigned persistent data unit (event) +example: + $ref: "../examples/unsigned_pdu.json" +properties: + room_id: + type: string + description: Room identifier. + example: "!abc123:matrix.org" + sender: + type: string + description: The ID of the user sending the event. + example: "@someone:matrix.org" + origin: + type: string + description: The ``server_name`` of the homeserver that created this event. + example: "matrix.org" + origin_server_ts: + type: integer + format: int64 + description: Timestamp in milliseconds on origin homeserver when this event was created. + example: 1234567890 + type: + type: string + description: Event type + example: "m.room.message" + state_key: + type: string + description: |- + If this key is present, the event is a state event, and it will replace previous events + with the same ``type`` and ``state_key`` in the room state. + example: "my_key" + content: + type: object + description: The content of the event. + example: {"key": "value"} + prev_events: + type: array + description: |- + Event IDs and hashes of the most recent events in the room that the homeserver was aware + of when it made this event. + items: + type: array + maxItems: 2 + minItems: 2 + items: + - type: string + title: Event ID + example: "$abc123:matrix.org" + - type: object + title: Event Hash + example: { + "sha256": "abase64encodedsha256hashshouldbe43byteslong" + } + properties: + sha256: + type: string + description: The event hash. + example: abase64encodedsha256hashshouldbe43byteslong + required: ['sha256'] + depth: + type: integer + description: The maximum depth of the ``prev_events``, plus one. + example: 12 + auth_events: + type: array + description: Event IDs and hashes for the "auth events" of this event. + items: + type: array + maxItems: 2 + minItems: 2 + items: + - type: string + title: Event ID + example: "$abc123:matrix.org" + - type: object + title: Event Hash + example: { + "sha256": "abase64encodedsha256hashshouldbe43byteslong" + } + properties: + sha256: + type: string + description: The event hash. + example: abase64encodedsha256hashshouldbe43byteslong + required: ['sha256'] + redacts: + type: string + description: For redaction events, the ID of the event being redacted. + example: "$def456:matrix.org" + unsigned: + type: object + description: Additional data added by the origin server but not covered by the ``signatures``. + example: {"key": "value"} +required: + - room_id + - sender + - origin + - origin_server_ts + - type + - content + - prev_events + - depth + - auth_events diff --git a/api/server-server/directory.yaml b/api/server-server/directory.yaml index 516b1bf81..94f115b91 100644 --- a/api/server-server/directory.yaml +++ b/api/server-server/directory.yaml @@ -1,4 +1,5 @@ # Copyright 2017 Kamax.io +# Copyright 2018 New Vector Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,7 +15,7 @@ swagger: '2.0' info: - title: "Matrix Federation Query Directory API" + title: "Matrix Federation Query API" version: "1.0.0" host: localhost:8448 schemes: diff --git a/api/server-server/events.yaml b/api/server-server/events.yaml new file mode 100644 index 000000000..d540085d2 --- /dev/null +++ b/api/server-server/events.yaml @@ -0,0 +1,93 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +swagger: '2.0' +info: + title: "Matrix Federation Events API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/federation/v1 +produces: + - application/json +paths: + "/state/{roomId}": + get: + summary: Get all the state of a given room + description: |- + Retrieves a snapshot of the entire current state of the given room. + operationId: getRoomState + parameters: + - in: path + name: roomId + type: string + description: The room ID to get state for. + required: true + x-example: "!abc123:matrix.org" + responses: + 200: + description: The room state for the room (kept under ``pdus``). + schema: + $ref: "definitions/transaction.yaml" + "/event/{eventId}": + get: + summary: Get a single event + description: |- + Retrieves a single event. + operationId: getEvent + parameters: + - in: path + name: eventId + type: string + description: The event ID to get. + required: true + x-example: "$abc123:matrix.org" + responses: + 200: + description: A transaction containing a single PDU which is the event requested. + schema: + $ref: "definitions/transaction.yaml" + "/backfill/{roomId}": + get: + summary: Retrieves the events which precede the given event + description: |- + Retreives a sliding-window history of previous PDUs that occurred in the given room. + Starting from the PDU ID(s) given in the ``v`` argument, the PDUs that preceded it + are retrieved, up to the total number given by the ``limit``. + operationId: backfillRoom + parameters: + - in: path + name: roomId + type: string + description: The room ID to backfill. + required: true + x-example: "!abc123:matrix.org" + - in: query + name: v + type: string # TODO: The description says this is plural - figure out how to specify multiple, and spec it + description: The event ID to backfill from. + required: true + x-example: "$abc123:matrix.org" + - in: query + name: limit + type: integer + description: The maximum number of events to retrieve. + required: true + x-example: 10 + responses: + 200: + description: A transaction containing the PDUs that preceded the given event(s). + schema: + $ref: "definitions/transaction.yaml" diff --git a/api/server-server/examples/edu.json b/api/server-server/examples/edu.json new file mode 100644 index 000000000..95a7b55d9 --- /dev/null +++ b/api/server-server/examples/edu.json @@ -0,0 +1,8 @@ +{ + "edu_type": "m.presence", + "origin": "blue", + "destination": "orange", + "content": { + "key": "value" + } +} \ No newline at end of file diff --git a/api/server-server/examples/pdu.json b/api/server-server/examples/pdu.json new file mode 100644 index 000000000..81981b23c --- /dev/null +++ b/api/server-server/examples/pdu.json @@ -0,0 +1,11 @@ +{ + "$ref": "unsigned_pdu.json", + "hashes": { + "sha256": "thishashcoversallfieldsincasethisisredacted" + }, + "signatures": { + "example.com": { + "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus" + } + } +} \ No newline at end of file diff --git a/api/server-server/examples/server_key.json b/api/server-server/examples/server_key.json new file mode 100644 index 000000000..a3934bd36 --- /dev/null +++ b/api/server-server/examples/server_key.json @@ -0,0 +1,23 @@ +{ + "server_name": "example.org", + "verify_keys": { + "ed25519:auto2": { + "key": "Base+64+Encoded+Signature+Verification+Key" + } + }, + "old_verify_keys": { + "ed25519:auto1": { + "expired_ts": 922834800000, + "key": "Base+64+Encoded+Old+Verify+Key" + } + }, + "signatures": { + "example.org": { + "ed25519:auto2": "Base+64+Encoded+Signature" + } + }, + "tls_fingerprints": [{ + "sha256": "Base+64+Encoded+SHA-256-Fingerprint" + }], + "valid_until_ts": 1052262000000 +} \ No newline at end of file diff --git a/api/server-server/examples/transaction.json b/api/server-server/examples/transaction.json new file mode 100644 index 000000000..bd8ac3dc7 --- /dev/null +++ b/api/server-server/examples/transaction.json @@ -0,0 +1,5 @@ +{ + "origin": "matrix.org", + "origin_server_ts": 1234567890, + "pdus": [{"$ref": "pdu.json"}] +} \ No newline at end of file diff --git a/api/server-server/examples/unsigned_pdu.json b/api/server-server/examples/unsigned_pdu.json new file mode 100644 index 000000000..6ed4b79d6 --- /dev/null +++ b/api/server-server/examples/unsigned_pdu.json @@ -0,0 +1,17 @@ +{ + "room_id": "!UcYsUzyxTGDxLBEvLy:example.org", + "sender": "@alice:example.com", + "origin": "example.com", + "event_id": "$a4ecee13e2accdadf56c1025:example.com", + "origin_server_ts": 1404838188000, + "type": "m.room.message", + "prev_events": [ + [ + "$af232176:example.org", + {"sha256": "abase64encodedsha256hashshouldbe43byteslong"} + ] + ], + "content": { + "key": "value" + } +} \ No newline at end of file diff --git a/api/server-server/keys_query.yaml b/api/server-server/keys_query.yaml new file mode 100644 index 000000000..f41cb35b2 --- /dev/null +++ b/api/server-server/keys_query.yaml @@ -0,0 +1,99 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +swagger: '2.0' +info: + title: "Matrix Federation Key Exchange API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/key/v2 +produces: + - application/json +paths: + "/query/{serverName}/{keyId}": + get: + summary: Retrieve a server key. + description: Retrieve a server key. + operationId: perspectivesKeyQuery + parameters: + - in: path + name: serverName + type: string + description: Server name. + required: true + x-example: matrix.org + - in: path + name: keyId + type: string + description: Key ID. + required: true + x-example: TODO # No examples in spec so far + - in: query + name: minimum_valid_until_ts + type: integer + format: int64 + description: Minimum Valid Until Milliseconds. + required: true # TODO: Verify + x-example: 1234567890 + responses: + 200: + description: The keys for the server + schema: + $ref: "definitions/keys_query_response.yaml" + "/query": + post: + summary: Retrieve a server key + description: Retrieve a server key. + operationId: bulkPerspectivesKeyQuery + parameters: + - in: body + name: body + schema: + type: object + # TODO: Improve example + example: { + "server_keys": { + "{server_name}": { + "{key_id}": { + "minimum_valid_until_ts": 1234567890 + } + } + } + } + properties: + server_keys: + type: object + description: The query criteria. + additionalProperties: + type: object + name: ServerName + description: The server names to query. + additionalProperties: + type: object + title: Query Criteria + description: The server keys to query. + properties: + minimum_valid_until_ts: + type: integer + format: int64 + description: Minimum Valid Until MS. + example: 1234567890 + required: ['server_keys'] + responses: + 200: + description: The keys for the server. + schema: + $ref: "definitions/keys_query_response.yaml" diff --git a/api/server-server/keys_server.yaml b/api/server-server/keys_server.yaml new file mode 100644 index 000000000..46beeebba --- /dev/null +++ b/api/server-server/keys_server.yaml @@ -0,0 +1,42 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +swagger: '2.0' +info: + title: "Matrix Federation Key Exchange API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/key/v2 +produces: + - application/json +paths: + "/server/{keyId}": + get: + summary: Get the server's key + description: Get the server's key. + operationId: getServerKey + parameters: + - in: path + name: keyId + type: string + description: Key ID + required: false + x-example: TODO # No examples in the spec so far + responses: + 200: + description: The server's keys. + schema: + $ref: "definitions/keys.yaml" diff --git a/api/server-server/query_general.yaml b/api/server-server/query_general.yaml new file mode 100644 index 000000000..97e3406ea --- /dev/null +++ b/api/server-server/query_general.yaml @@ -0,0 +1,44 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +swagger: '2.0' +info: + title: "Matrix Federation Query API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/federation/v1 +produces: + - application/json +paths: + "/query/{queryType}": + get: + summary: Query for information + description: |- + Performs a single query request on the receiving homeserver. The query string + arguments are dependent on which type of query is being made. Known query types + are specified as their own endpoints as an extension to this definition. + operationId: queryInfo + parameters: + - in: path + name: queryType + type: string + description: The type of query to make + required: true + x-example: profile + responses: + 200: + description: |- + The query response. The schema varies depending on the query being made. diff --git a/api/server-server/third_party_invite.yaml b/api/server-server/third_party_invite.yaml new file mode 100644 index 000000000..42bdae23e --- /dev/null +++ b/api/server-server/third_party_invite.yaml @@ -0,0 +1,190 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +swagger: '2.0' +info: + title: "Matrix Federation Third Party Invites API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/federation/v1 +produces: + - application/json +paths: + "/exchange_third_party_invite/{roomId}": + put: + summary: Request a server to auth a third party invite event + description: |- + The receiving server will verify the partial ``m.room.member`` event + given in the request body. If valid, the receiving server will issue + an invite as per the `Inviting to a room`_ section before returning a + response to this request. + operationId: exchangeThirdPartyInvite + parameters: + - in: path + name: roomId + type: string + description: The room ID to exchange a third party invite in + required: true + x-example: "!abc123:matrix.org" + - in: body + name: body + type: object + description: A partial ``m.room.member`` event + required: true + schema: + type: object + properties: + type: + type: string + description: The event type. Must be ``m.room.member`` + example: "m.room.member" + room_id: + type: string + description: |- + The room ID the event is for. Must match the ID given in + the path. + example: "!abc123:matrix.org" + sender: + type: string + description: |- + The user ID of the user who sent the original ``m.room.third_party_invite`` + event. + example: "@joe:matrix.org" + state_key: + type: string + description: The user ID of the invited user + example: "@someone:example.org" + content: + type: object + description: The event content + title: Event Content + properties: + membership: + type: string + description: The membership state. Must be ``invite`` + example: invite + third_party_invite: + type: object + description: The third party invite + properties: + display_name: + type: string + description: |- + A name which can be displayed to represent the user instead of their + third party identifier. + example: "alice" + signed: + type: object + description: |- + A block of content which has been signed, which servers can use to + verify the event. + properties: + signatures: + type: object + description: The server signatures for this event. + additionalProperties: + type: object + title: Server Signatures + additionalProperties: + type: string + example: { + "magic.forest": { + "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } + } + mxid: + type: string + description: The invited matrix user ID + example: "@alice:localhost" + token: + type: string + description: The token used to verify the event + example: abc123 + required: ['signatures', 'mxid', 'token'] + example: { + "mxid": "@alice:localhost", + "token": "abc123", + "signatures": { + "magic.forest": { + "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } + } + } + required: ['display_name', 'signed'] + example: { + "display_name": "alice", + "signed": { + "mxid": "@alice:localhost", + "token": "abc123", + "signatures": { + "magic.forest": { + "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } + } + } + } + required: ['membership', 'third_party_invite'] + example: { + "membership": "invite", + "third_party_invite": { + "display_name": "alice", + "signed": { + "mxid": "@alice:localhost", + "token": "abc123", + "signatures": { + "magic.forest": { + "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } + } + } + } + } + required: + - type + - room_id + - sender + - state_key + - content + example: { + "type": "m.room.member", + "room_id": "!abc123:matrix.org", + "sender": "@joe:matrix.org", + "state_key": "@someone:example.org", + "content": { + "membership": "invite", + "third_party_invite": { + "display_name": "alice", + "signed": { + "mxid": "@alice:localhost", + "token": "abc123", + "signatures": { + "magic.forest": { + "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } + } + } + } + } + } + responses: + 200: + description: The invite has been issued successfully. + examples: + application/json: {} + schema: + type: object + description: An empty object + example: {} diff --git a/api/server-server/transactions.yaml b/api/server-server/transactions.yaml new file mode 100644 index 000000000..13ba6826b --- /dev/null +++ b/api/server-server/transactions.yaml @@ -0,0 +1,64 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +swagger: '2.0' +info: + title: "Matrix Federation Transaction API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/federation/v1 +produces: + - application/json +paths: + "/send/{txnId}": + put: + summary: Send a transaction + description: |- + Push messages representing live activity to another server. The destination name + will be set to that of the receiving server itself. Each embedded PDU in the + transaction body will be processed. + operationId: sendTransaction + parameters: + - in: path + name: txnId + type: string + # TODO: "Overrides any ID given in the JSON body" - What does this mean? + description: |- + The transaction ID. Overrides any ID given in the JSON body. + required: true + x-example: TODO # No examples in the spec so far + - in: body + name: body + type: object + required: true + schema: + allOf: + - $ref: "definitions/transaction.yaml" + - type: object + properties: + edus: + type: array + description: List of ephemeral messages. May be omitted if there are no ephemeral messages to be sent. + items: + $ref: "definitions/edu.yaml" + example: { + "$ref": "examples/transaction.json", + "edus": [{"$ref": "edu.json"}] # Relative to the examples directory + } + responses: + 200: + # TODO: Spec this (and figure out what it is) + description: TODO diff --git a/changelogs/README.md b/changelogs/README.md new file mode 100644 index 000000000..a5fb1fb7d --- /dev/null +++ b/changelogs/README.md @@ -0,0 +1,55 @@ + + +# Changelogs + +[Towncrier](https://github.com/hawkowl/towncrier) is used to manage the changelog and +keep it up to date. Because of this, updating a changelog is really easy. + +## How to update a changelog when releasing an API + +1. Ensure you're in your Python 3 virtual environment +2. `cd` your way to the API you're releasing (eg: `cd changelogs/client_server`) +3. Run `towncrier --version "r0.4.0" --name "client-server" --yes` substituting the + variables as approprite. Note that `--name` is required although the value is ignored. +4. Commit the changes and finish the release process. + +## How to prepare a changelog for a new API + +For this example, we're going to pretend that the `server_server` API doesn't exist. + +1. Create the file `changelogs/server_server.rst` +2. Create the folder `changelogs/server_server` +3. In the new folder, create a `pyproject.toml` file with these contents: + ```toml + [tool.towncrier] + filename = "../server_server.rst" + directory = "newsfragments" + issue_format = "`#{issue} `_" + title_format = "{version}" + + [[tool.towncrier.type]] + directory = "breaking" + name = "Breaking Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "deprecation" + name = "Deprecations" + showcontent = true + + [[tool.towncrier.type]] + directory = "new" + name = "New Endpoints" + showcontent = true + + [[tool.towncrier.type]] + directory = "feature" + name = "Backwards Compatible Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "clarification" + name = "Spec Clarifications" + showcontent = true + ``` +4. Create a `.gitignore` in `changelogs/server_server/newsfragments` with the contents `!.gitignore` diff --git a/changelogs/client_server.rst b/changelogs/client_server.rst index 44d41f4e4..d2ef7f2db 100644 --- a/changelogs/client_server.rst +++ b/changelogs/client_server.rst @@ -1,66 +1,3 @@ -Unreleased changes -================== - -- Changes to the API which will be backwards-compatible for clients: - - - New endpoints: - - - ``POST /user_directory/search`` - (`#1096 `_). - - ``GET /rooms/{roomId}/event/{eventId}`` - (`#1110 `_). - - ``POST /delete_devices`` - (`#1239 `_). - - - Sticker messages: - - Add sticker message event definition. - (`#1158 `_). - - Document the GET version of ``/login`` - (`#1361 `_). - -- Spec clarifications: - - - Update ``ImageInfo`` and ``ThumbnailInfo`` dimension schema descriptions - to clarify that they relate to intended display size, as opposed to the - intrinsic size of the image file. - (`#1158 `_). - - Mark ``home_server`` return field for ``/login`` and ``/register`` - endpoints as deprecated - (`#1097 `_). - - Fix response format of ``/keys/changes`` endpoint - (`#1106 `_). - - Clarify default values for some fields on the /search API - (`#1109 `_). - - Fix the representation of ``m.presence`` events - (`#1137 `_). - - Clarify that ``m.tag`` ordering is done with numbers, not strings - (`#1139 `_). - - Clarify that ``/account/whoami`` should consider application services - (`#1152 `_). - - Mark ``GET /rooms/{roomId}/members`` as requiring authentication - (`#1245 `_). - - Describe ``StateEvent`` for ``/createRoom`` - (`#1329 `_). - -- Changes to the API which will be backwards-compatible for clients: - - - Add 'token' parameter to /keys/query endpoint - (`#1104 `_). - - Add the room visibility options for the room directory - (`#1141 `_). - - Add spec for ignoring users - (`#1142 `_). - - Add the ``/register/available`` endpoint for username availability - (`#1151 `_). - - Add ``allow_remote`` to the content repo to avoid routing loops - (`#1265 `_). - - Add report content API - (`#1264 `_). - - Document ``/logout/all`` endpoint - (`#1263 `_). - - Document `highlights` field in /search response - (`#1274 `_). - r0.3.0 ====== diff --git a/changelogs/client_server/newsfragments/.gitignore b/changelogs/client_server/newsfragments/.gitignore new file mode 100644 index 000000000..b722e9e13 --- /dev/null +++ b/changelogs/client_server/newsfragments/.gitignore @@ -0,0 +1 @@ +!.gitignore \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1096.new b/changelogs/client_server/newsfragments/1096.new new file mode 100644 index 000000000..50d868799 --- /dev/null +++ b/changelogs/client_server/newsfragments/1096.new @@ -0,0 +1 @@ +``POST /user_directory/search`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1097.clarification b/changelogs/client_server/newsfragments/1097.clarification new file mode 100644 index 000000000..2a7cb93a5 --- /dev/null +++ b/changelogs/client_server/newsfragments/1097.clarification @@ -0,0 +1 @@ +Mark ``home_server`` return field for ``/login`` and ``/register`` endpoints as deprecated \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1104.feature b/changelogs/client_server/newsfragments/1104.feature new file mode 100644 index 000000000..9b85343f7 --- /dev/null +++ b/changelogs/client_server/newsfragments/1104.feature @@ -0,0 +1 @@ +Add ``token`` parameter to the ``/keys/query`` endpoint \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1106.clarification b/changelogs/client_server/newsfragments/1106.clarification new file mode 100644 index 000000000..f7a1fe3e7 --- /dev/null +++ b/changelogs/client_server/newsfragments/1106.clarification @@ -0,0 +1 @@ +Fix response format of ``/keys/changes`` endpoint \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1109.clarification b/changelogs/client_server/newsfragments/1109.clarification new file mode 100644 index 000000000..176d94030 --- /dev/null +++ b/changelogs/client_server/newsfragments/1109.clarification @@ -0,0 +1 @@ +Clarify default values for some fields on the ``/search`` API \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1110.new b/changelogs/client_server/newsfragments/1110.new new file mode 100644 index 000000000..e1b80b8b6 --- /dev/null +++ b/changelogs/client_server/newsfragments/1110.new @@ -0,0 +1 @@ +``GET /rooms/{roomId}/event/{eventId}`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1137.clarification b/changelogs/client_server/newsfragments/1137.clarification new file mode 100644 index 000000000..5ad8ec34f --- /dev/null +++ b/changelogs/client_server/newsfragments/1137.clarification @@ -0,0 +1 @@ +Fix the representation of ``m.presence`` events \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1139.clarification b/changelogs/client_server/newsfragments/1139.clarification new file mode 100644 index 000000000..b5193ad3c --- /dev/null +++ b/changelogs/client_server/newsfragments/1139.clarification @@ -0,0 +1 @@ +Clarify that ``m.tag`` ordering is done with numbers, not strings \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1141.feature b/changelogs/client_server/newsfragments/1141.feature new file mode 100644 index 000000000..da0418191 --- /dev/null +++ b/changelogs/client_server/newsfragments/1141.feature @@ -0,0 +1 @@ +Add the room visibility options for the room directory \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1142.feature b/changelogs/client_server/newsfragments/1142.feature new file mode 100644 index 000000000..0a0842c42 --- /dev/null +++ b/changelogs/client_server/newsfragments/1142.feature @@ -0,0 +1 @@ +Add spec for ignoring users \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1151.feature b/changelogs/client_server/newsfragments/1151.feature new file mode 100644 index 000000000..8875812bd --- /dev/null +++ b/changelogs/client_server/newsfragments/1151.feature @@ -0,0 +1 @@ +Add the ``/register/available`` endpoint for username availability \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1152.clarification b/changelogs/client_server/newsfragments/1152.clarification new file mode 100644 index 000000000..bbecc9b29 --- /dev/null +++ b/changelogs/client_server/newsfragments/1152.clarification @@ -0,0 +1 @@ +Clarify that ``/account/whoami`` should consider application services \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1158.clarification b/changelogs/client_server/newsfragments/1158.clarification new file mode 100644 index 000000000..dc1f6d149 --- /dev/null +++ b/changelogs/client_server/newsfragments/1158.clarification @@ -0,0 +1,3 @@ +Update ``ImageInfo`` and ``ThumbnailInfo`` dimension schema descriptions +to clarify that they relate to intended display size, as opposed to the +intrinsic size of the image file. \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1158.feature b/changelogs/client_server/newsfragments/1158.feature new file mode 100644 index 000000000..a55df4fb3 --- /dev/null +++ b/changelogs/client_server/newsfragments/1158.feature @@ -0,0 +1 @@ +Add sticker messages \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1239.new b/changelogs/client_server/newsfragments/1239.new new file mode 100644 index 000000000..9bcf357df --- /dev/null +++ b/changelogs/client_server/newsfragments/1239.new @@ -0,0 +1 @@ +``POST /delete_devices`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1245.clarification b/changelogs/client_server/newsfragments/1245.clarification new file mode 100644 index 000000000..e0a638345 --- /dev/null +++ b/changelogs/client_server/newsfragments/1245.clarification @@ -0,0 +1 @@ +Mark ``GET /rooms/{roomId}/members`` as requiring authentication \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1263.feature b/changelogs/client_server/newsfragments/1263.feature new file mode 100644 index 000000000..04964a7d6 --- /dev/null +++ b/changelogs/client_server/newsfragments/1263.feature @@ -0,0 +1 @@ +Document ``/logout/all`` endpoint \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1264.feature b/changelogs/client_server/newsfragments/1264.feature new file mode 100644 index 000000000..9cb06f719 --- /dev/null +++ b/changelogs/client_server/newsfragments/1264.feature @@ -0,0 +1 @@ +Add report content API \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1265.feature b/changelogs/client_server/newsfragments/1265.feature new file mode 100644 index 000000000..1e270fa8b --- /dev/null +++ b/changelogs/client_server/newsfragments/1265.feature @@ -0,0 +1 @@ +Add ``allow_remote`` to the content repo to avoid routing loops \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1274.feature b/changelogs/client_server/newsfragments/1274.feature new file mode 100644 index 000000000..d49581314 --- /dev/null +++ b/changelogs/client_server/newsfragments/1274.feature @@ -0,0 +1 @@ +Document `highlights` field in /search response \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1329.clarification b/changelogs/client_server/newsfragments/1329.clarification new file mode 100644 index 000000000..970d3d947 --- /dev/null +++ b/changelogs/client_server/newsfragments/1329.clarification @@ -0,0 +1 @@ +Describe ``StateEvent`` for ``/createRoom`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1353.new b/changelogs/client_server/newsfragments/1353.new new file mode 100644 index 000000000..0af0c5206 --- /dev/null +++ b/changelogs/client_server/newsfragments/1353.new @@ -0,0 +1 @@ +``GET /thirdparty/*`` Endpoints diff --git a/changelogs/client_server/newsfragments/1361.feature b/changelogs/client_server/newsfragments/1361.feature new file mode 100644 index 000000000..b1d4c2f11 --- /dev/null +++ b/changelogs/client_server/newsfragments/1361.feature @@ -0,0 +1 @@ +Document the GET version of ``/login`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1362.clarification b/changelogs/client_server/newsfragments/1362.clarification new file mode 100644 index 000000000..1deb45002 --- /dev/null +++ b/changelogs/client_server/newsfragments/1362.clarification @@ -0,0 +1 @@ +Describe how the ``reason`` is handled for kicks/bans \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1364.feature b/changelogs/client_server/newsfragments/1364.feature new file mode 100644 index 000000000..733d6a1f0 --- /dev/null +++ b/changelogs/client_server/newsfragments/1364.feature @@ -0,0 +1 @@ +Document the ``server_name`` parameter on ``/join/{roomIdOrAlias}`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1365.feature b/changelogs/client_server/newsfragments/1365.feature new file mode 100644 index 000000000..d2864e965 --- /dev/null +++ b/changelogs/client_server/newsfragments/1365.feature @@ -0,0 +1 @@ +Document the CORS/preflight headers \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1371.clarification b/changelogs/client_server/newsfragments/1371.clarification new file mode 100644 index 000000000..88552fcd5 --- /dev/null +++ b/changelogs/client_server/newsfragments/1371.clarification @@ -0,0 +1 @@ +Mark ``GET /presence/{userId}/status`` as requiring authentication \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1373.clarification b/changelogs/client_server/newsfragments/1373.clarification new file mode 100644 index 000000000..21e18966b --- /dev/null +++ b/changelogs/client_server/newsfragments/1373.clarification @@ -0,0 +1 @@ +Describe the rate limit error response schema diff --git a/changelogs/client_server/newsfragments/1378.clarification b/changelogs/client_server/newsfragments/1378.clarification new file mode 100644 index 000000000..f952428b5 --- /dev/null +++ b/changelogs/client_server/newsfragments/1378.clarification @@ -0,0 +1 @@ +Clarify that clients must leave rooms before forgetting them \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1379.clarification b/changelogs/client_server/newsfragments/1379.clarification new file mode 100644 index 000000000..122b39004 --- /dev/null +++ b/changelogs/client_server/newsfragments/1379.clarification @@ -0,0 +1 @@ +Document guest access in ``/createRoom`` presets diff --git a/changelogs/client_server/newsfragments/1380.clarification b/changelogs/client_server/newsfragments/1380.clarification new file mode 100644 index 000000000..490a9a43c --- /dev/null +++ b/changelogs/client_server/newsfragments/1380.clarification @@ -0,0 +1 @@ +Define what a ``RoomEvent`` is on ``/rooms/{roomId}/messages`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1381.clarification b/changelogs/client_server/newsfragments/1381.clarification new file mode 100644 index 000000000..e5e599acf --- /dev/null +++ b/changelogs/client_server/newsfragments/1381.clarification @@ -0,0 +1 @@ +Clarify the request and result types on ``/search`` \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1397.feature b/changelogs/client_server/newsfragments/1397.feature new file mode 100644 index 000000000..e4bd248a8 --- /dev/null +++ b/changelogs/client_server/newsfragments/1397.feature @@ -0,0 +1 @@ +Document message formats on ``m.text`` and ``m.emote`` messages diff --git a/changelogs/client_server/newsfragments/1400.clarification b/changelogs/client_server/newsfragments/1400.clarification new file mode 100644 index 000000000..3fd29e920 --- /dev/null +++ b/changelogs/client_server/newsfragments/1400.clarification @@ -0,0 +1 @@ +Clarify some of the properties on the search result diff --git a/changelogs/client_server/pyproject.toml b/changelogs/client_server/pyproject.toml new file mode 100644 index 000000000..8fa3f6b5a --- /dev/null +++ b/changelogs/client_server/pyproject.toml @@ -0,0 +1,30 @@ +[tool.towncrier] + filename = "../client_server.rst" + directory = "newsfragments" + issue_format = "`#{issue} `_" + title_format = "{version}" + + [[tool.towncrier.type]] + directory = "breaking" + name = "Breaking Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "deprecation" + name = "Deprecations" + showcontent = true + + [[tool.towncrier.type]] + directory = "new" + name = "New Endpoints" + showcontent = true + + [[tool.towncrier.type]] + directory = "feature" + name = "Backwards Compatible Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "clarification" + name = "Spec Clarifications" + showcontent = true diff --git a/event-schemas/examples/m.room.message#m.emote b/event-schemas/examples/m.room.message#m.emote index 4280928ee..79292ddf8 100644 --- a/event-schemas/examples/m.room.message#m.emote +++ b/event-schemas/examples/m.room.message#m.emote @@ -2,7 +2,9 @@ "age": 242352, "content": { "body": "thinks this is an example emote", - "msgtype": "m.emote" + "msgtype": "m.emote", + "format": "org.matrix.custom.html", + "formatted_body": "thinks this is an example emote" }, "origin_server_ts": 1431961217939, "event_id": "$WLGTSEFSEF:localhost", diff --git a/event-schemas/examples/m.room.message#m.text b/event-schemas/examples/m.room.message#m.text index e00c7aa56..48a97db80 100644 --- a/event-schemas/examples/m.room.message#m.text +++ b/event-schemas/examples/m.room.message#m.text @@ -2,7 +2,9 @@ "age": 242352, "content": { "body": "This is an example text message", - "msgtype": "m.text" + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "formatted_body": "This is an example text message" }, "origin_server_ts": 1431961217939, "event_id": "$WLGTSEFSEF:localhost", diff --git a/event-schemas/schema/m.room.message#m.emote b/event-schemas/schema/m.room.message#m.emote index 88860cb21..f67a184b1 100644 --- a/event-schemas/schema/m.room.message#m.emote +++ b/event-schemas/schema/m.room.message#m.emote @@ -12,6 +12,16 @@ properties: enum: - m.emote type: string + format: + description: |- + The format used in the ``formatted_body``. Currently only + ``org.matrix.custom.html`` is supported. + type: string + formatted_body: + description: |- + The formatted version of the ``body``. This is required if ``format`` + is specified. + type: string required: - msgtype - body diff --git a/event-schemas/schema/m.room.message#m.text b/event-schemas/schema/m.room.message#m.text index 2720172dd..b481bceab 100644 --- a/event-schemas/schema/m.room.message#m.text +++ b/event-schemas/schema/m.room.message#m.text @@ -12,6 +12,16 @@ properties: enum: - m.text type: string + format: + description: |- + The format used in the ``formatted_body``. Currently only + ``org.matrix.custom.html`` is supported. + type: string + formatted_body: + description: |- + The formatted version of the ``body``. This is required if ``format`` + is specified. + type: string required: - msgtype - body diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..b53982b87 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[ tool.giles ] + + [ tool.giles.circleci_artifacts.docs ] + url = "gen/index.html" + message = "Click details to preview the HTML documentation." + + [ tool.giles.circleci_artifacts.swagger ] + url = "client-server/index.html" + message = "Click to preview the swagger build." diff --git a/scripts/dump-swagger.py b/scripts/dump-swagger.py index 110c44466..e02c554eb 100755 --- a/scripts/dump-swagger.py +++ b/scripts/dump-swagger.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # dump-swagger reads all of the swagger API docs used in spec generation and # outputs a JSON file which merges them all, for use as input to a swagger UI @@ -103,7 +103,7 @@ for filename in os.listdir(cs_api_dir): output["paths"][path] = {} output["paths"][path][method] = spec -print "Generating %s" % output_file +print("Generating %s" % output_file) try: os.makedirs(os.path.dirname(output_file)) diff --git a/scripts/gendoc.py b/scripts/gendoc.py index 2b35f8015..16c40af5d 100755 --- a/scripts/gendoc.py +++ b/scripts/gendoc.py @@ -31,6 +31,7 @@ script_dir = os.path.dirname(os.path.abspath(__file__)) docs_dir = os.path.dirname(script_dir) spec_dir = os.path.join(docs_dir, "specification") tmp_dir = os.path.join(script_dir, "tmp") +changelog_dir = os.path.join(docs_dir, "changelogs") VERBOSE = False @@ -151,7 +152,7 @@ def is_title_line(prev_line, line, title_styles): def get_rst(file_info, title_level, title_styles, spec_dir, adjust_titles): # string are file paths to RST blobs - if isinstance(file_info, basestring): + if isinstance(file_info, str): log("%s %s" % (">" * (1 + title_level), file_info)) with open(os.path.join(spec_dir, file_info), "r") as f: rst = None @@ -194,7 +195,7 @@ def build_spec(target, out_filename): spec_dir=spec_dir, adjust_titles=True ) - outfile.write(section) + outfile.write(section.encode('UTF-8')) """ @@ -279,15 +280,16 @@ def rst2html(i, o, stylesheets): def addAnchors(path): log("add anchors %s" % path) - with open(path, "r") as f: + with open(path, "rb") as f: lines = f.readlines() - replacement = replacement = r'

\n\1' - with open(path, "w") as f: + replacement = r'

\n\1' + with open(path, "wb") as f: for line in lines: + line = line.decode("UTF-8") line = re.sub(r'()', replacement, line.rstrip()) - line = re.sub(r'(
)', replacement, line.rstrip()) - f.write(line + "\n") + line = re.sub(r'(
)', replacement, line.rstrip()) + f.write((line + "\n").encode('UTF-8')) def run_through_template(input_files, set_verbose, substitutions): @@ -364,7 +366,7 @@ def get_build_target(all_targets, target_name): resolved_files = [] for file_entry in target["files"]: # file_entry is a group id - if isinstance(file_entry, basestring) and file_entry.startswith("group:"): + if isinstance(file_entry, str) and file_entry.startswith("group:"): group = get_group(file_entry, 0) # The group may be resolved to a list of file entries, in which case # we want to extend the array to insert each of them rather than @@ -376,8 +378,8 @@ def get_build_target(all_targets, target_name): # file_entry is a dict which has more file entries as values elif isinstance(file_entry, dict): resolved_entry = {} - for (depth, entry) in file_entry.iteritems(): - if not isinstance(entry, basestring): + for (depth, entry) in file_entry.items(): + if not isinstance(entry, str): raise Exception( "Double-nested depths are not supported. Entry: %s" % (file_entry,) ) @@ -395,11 +397,11 @@ def get_build_target(all_targets, target_name): return build_target def log(line): - print "gendoc: %s" % line + print("gendoc: %s" % line) def logv(line): if VERBOSE: - print "gendoc:V: %s" % line + print("gendoc:V: %s" % line) def cleanup_env(): @@ -445,7 +447,7 @@ def main(targets, dest_dir, keep_intermediates, substitutions): stylesheets = glob.glob(os.path.join(script_dir, "css", "*.css")) - for target_name, templated_file in templated_files.iteritems(): + for target_name, templated_file in templated_files.items(): target = target_defs["targets"].get(target_name) version_label = None if target: @@ -480,7 +482,7 @@ def list_targets(): with open(os.path.join(spec_dir, "targets.yaml"), "r") as targ_file: target_defs = yaml.load(targ_file.read()) targets = target_defs["targets"].keys() - print "\n".join(targets) + print("\n".join(targets)) def extract_major(s): diff --git a/scripts/proposals.py b/scripts/proposals.py index b489f0d27..eec6d6527 100755 --- a/scripts/proposals.py +++ b/scripts/proposals.py @@ -12,13 +12,18 @@ authors = set() prs = set() def getpage(url, page): - resp = requests.get(url + str(page)) + url = url + str(page) + resp = requests.get(url) for link in resp.links.values(): if link['rel'] == 'last': pagecount = re.search('page=(.+?)', link['url']).group(1) - return resp.json() + val = resp.json() + if not isinstance(val, list): + print(val) # Just dump the raw (likely error) response to the log + raise Exception("Error calling %s" % url) + return val def getbylabel(label): pagecount = 1 @@ -27,7 +32,7 @@ def getbylabel(label): print(urlbase) json.extend(getpage(urlbase, 1)) for page in range(2, int(pagecount) + 1): - getpage(urlbase, page) + json.extend(getpage(urlbase, page)) return json diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 37d99dd3d..2a7d7ff85 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -7,3 +7,5 @@ Jinja2 >= 2.9.6 jsonschema >= 2.6.0 PyYAML >= 3.12 requests >= 2.18.4 +towncrier == 18.6.0 +six >= 1.11.0 \ No newline at end of file diff --git a/scripts/speculator/main.go b/scripts/speculator/main.go index 5e1225037..12ec2aec2 100644 --- a/scripts/speculator/main.go +++ b/scripts/speculator/main.go @@ -701,8 +701,8 @@ func ignoreExitCodeOne(err error) error { func main() { flag.Parse() - // It would be great to read this from github, but there's no convenient way to do so. - // Most of these memberships are "private", so would require some kind of auth. + // It would be great to read this from github + // cf https://github.com/matrix-org/matrix-doc/issues/1384 allowedMembers = map[string]bool{ "dbkr": true, "erikjohnston": true, @@ -715,6 +715,11 @@ func main() { "rxl881": true, "uhoreg": true, "turt2live": true, + "Half-Shot": true, + "anoadragon453": true, + "mujx": true, + "benparsons": true, + "KitsuneRal": true, } if err := initCache(); err != nil { log.Fatal(err) diff --git a/scripts/swagger-http-server.py b/scripts/swagger-http-server.py index 5ec001019..06d764aa0 100755 --- a/scripts/swagger-http-server.py +++ b/scripts/swagger-http-server.py @@ -19,14 +19,14 @@ import argparse import os -import SimpleHTTPServer -import SocketServer +import http.server +import socketserver # Thanks to http://stackoverflow.com/a/13354482 -class MyHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): +class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): def end_headers(self): self.send_my_headers() - SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self) + http.server.SimpleHTTPRequestHandler.end_headers(self) def send_my_headers(self): self.send_header("Access-Control-Allow-Origin", "*") @@ -49,7 +49,7 @@ if __name__ == '__main__': os.chdir(args.swagger_dir) - httpd = SocketServer.TCPServer(("localhost", args.port), + httpd = socketserver.TCPServer(("localhost", args.port), MyHTTPRequestHandler) - print "Serving at http://localhost:%i/api-docs.json" % args.port + print("Serving at http://localhost:%i/api-docs.json" % args.port) httpd.serve_forever() diff --git a/scripts/templating/batesian/__init__.py b/scripts/templating/batesian/__init__.py index da41b31bf..e901590f5 100644 --- a/scripts/templating/batesian/__init__.py +++ b/scripts/templating/batesian/__init__.py @@ -11,7 +11,6 @@ # 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. -from sets import Set class AccessKeyStore(object): @@ -22,7 +21,7 @@ class AccessKeyStore(object): if not existing_data: existing_data = {} self.data = existing_data - self.accessed_set = Set() + self.accessed_set = set() def keys(self): return self.data.keys() @@ -35,5 +34,5 @@ class AccessKeyStore(object): return self.data[key] def get_unaccessed_set(self): - data_list = Set(self.data.keys()) + data_list = set(self.data.keys()) return data_list - self.accessed_set \ No newline at end of file diff --git a/scripts/templating/batesian/sections.py b/scripts/templating/batesian/sections.py index c541d771d..18a622f65 100644 --- a/scripts/templating/batesian/sections.py +++ b/scripts/templating/batesian/sections.py @@ -29,7 +29,7 @@ class Sections(object): def log(self, text): if self.debug: - print "batesian:sections: %s" % text + print("batesian:sections: %s" % text) def get_sections(self): render_list = inspect.getmembers(self, predicate=inspect.ismethod) @@ -40,7 +40,7 @@ class Sections(object): section_key = func_name[len("render_"):] self.log("Generating section '%s'" % section_key) section = func() - if isinstance(section, basestring): + if isinstance(section, str): if section_key in section_dict: raise Exception( ("%s : Section %s already exists. It must have been " + @@ -54,8 +54,8 @@ class Sections(object): ) elif isinstance(section, dict): self.log(" Generated multiple sections:") - for (k, v) in section.iteritems(): - if not isinstance(k, basestring) or not isinstance(v, basestring): + for (k, v) in section.items(): + if not isinstance(k, str) or not isinstance(v, str): raise Exception( ("Method %s returned multiple sections as a dict but " + "expected the dict elements to be strings but they aren't.") % diff --git a/scripts/templating/batesian/units.py b/scripts/templating/batesian/units.py index 8f748f6da..82cc52f92 100644 --- a/scripts/templating/batesian/units.py +++ b/scripts/templating/batesian/units.py @@ -41,7 +41,7 @@ class Units(object): trace = inspect.stack() if len(trace) > 1 and len(trace[1]) > 2: func_name = trace[1][3] + ":" - print "batesian:units:%s %s" % (func_name, text) + print("batesian:units:%s %s" % (func_name, text)) def get_units(self, debug=False): unit_list = inspect.getmembers(self, predicate=inspect.ismethod) @@ -50,7 +50,7 @@ class Units(object): if not func_name.startswith("load_"): continue unit_key = func_name[len("load_"):] - if len(inspect.getargs(func.func_code).args) > 1: + if len(inspect.getargs(func.__code__).args) > 1: unit_dict[unit_key] = func(self.substitutions) else: unit_dict[unit_key] = func() diff --git a/scripts/templating/build.py b/scripts/templating/build.py index d18569b66..fae4db56f 100755 --- a/scripts/templating/build.py +++ b/scripts/templating/build.py @@ -63,6 +63,7 @@ import sys from textwrap import TextWrapper from matrix_templates.units import TypeTableRow +from functools import reduce def create_from_template(template, sections): @@ -138,7 +139,7 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={} return reduce(max, rowwidths, default if default is not None else default_width) - results = map(colwidth, keys, defaults) + results = list(map(colwidth, keys, defaults)) return results # make Jinja aware of the templates and filters @@ -167,7 +168,7 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={} # print out valid section keys if no file supplied if not files: - print "\nValid template variables:" + print("\nValid template variables:") for key in sections.keys(): sec_text = "" if (len(sections[key]) > 75) else ( "(Value: '%s')" % sections[key] @@ -175,8 +176,8 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={} sec_info = "%s characters" % len(sections[key]) if sections[key].count("\n") > 0: sec_info += ", %s lines" % sections[key].count("\n") - print " %s" % key - print " %s %s" % (sec_info, sec_text) + print(" %s" % key) + print(" %s %s" % (sec_info, sec_text)) return # check the input files and substitute in sections where required @@ -190,8 +191,8 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={} def process_file(env, sections, filename, output_filename): log("Parsing input template: %s" % filename) - with open(filename, "r") as file_stream: - temp_str = file_stream.read().decode("utf-8") + with open(filename, "rb") as file_stream: + temp_str = file_stream.read().decode('UTF-8') # do sanity checking on the template to make sure they aren't reffing things # which will never be replaced with a section. @@ -213,13 +214,13 @@ def process_file(env, sections, filename, output_filename): for old, new in substitutions.items(): output = output.replace(old, new) - with open(output_filename, "w") as f: - f.write(output.encode("utf-8")) + with open(output_filename, "wb") as f: + f.write(output.encode('UTF-8')) log("Output file for: %s" % output_filename) def log(line): - print "batesian: %s" % line + print("batesian: %s" % line) if __name__ == '__main__': parser = ArgumentParser( diff --git a/scripts/templating/matrix_templates/__init__.py b/scripts/templating/matrix_templates/__init__.py index 6b46192ca..b81c5a30d 100644 --- a/scripts/templating/matrix_templates/__init__.py +++ b/scripts/templating/matrix_templates/__init__.py @@ -11,8 +11,8 @@ # 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. -from sections import MatrixSections -from units import MatrixUnits +from .sections import MatrixSections +from .units import MatrixUnits import os exports = { diff --git a/scripts/templating/matrix_templates/units.py b/scripts/templating/matrix_templates/units.py index d8cfe1e34..5b39a2b3c 100644 --- a/scripts/templating/matrix_templates/units.py +++ b/scripts/templating/matrix_templates/units.py @@ -29,8 +29,9 @@ import os.path import re import subprocess import sys -import urllib import yaml +from functools import reduce +from six.moves.urllib.parse import urlencode, quote matrix_doc_dir=reduce(lambda acc,_: os.path.dirname(acc), range(1, 5), os.path.abspath(__file__)) @@ -138,6 +139,7 @@ def inherit_parents(obj): Recurse through the 'allOf' declarations in the object """ logger.debug("inherit_parents %r" % obj) + parents = obj.get("allOf", []) if not parents: return obj @@ -147,7 +149,7 @@ def inherit_parents(obj): # settings defined in the child take priority over the parents, so we # iterate through the parents first, and then overwrite with the settings # from the child. - for p in map(inherit_parents, parents) + [obj]: + for p in list(map(inherit_parents, parents)) + [obj]: # child blats out type, title and description for key in ('type', 'title', 'description'): if p.get(key): @@ -250,12 +252,12 @@ def get_json_schema_object_fields(obj, enforce_title=False): tables.extend(res["tables"]) logger.debug("Done property %s" % key_name) - except Exception, e: + except Exception as e: e2 = Exception("Error reading property %s.%s: %s" % (obj_title, key_name, str(e))) # throw the new exception with the old stack trace, so that # we don't lose information about where the error occurred. - raise e2, None, sys.exc_info()[2] + raise e2.with_traceback(sys.exc_info()[2]) tables.insert(0, TypeTable(title=obj_title, rows=first_table_rows)) @@ -292,10 +294,21 @@ def process_data_type(prop, required=False, enforce_title=True): is_object = True elif prop_type == "array": - nested = process_data_type(prop["items"]) - prop_title = "[%s]" % nested["title"] - tables = nested["tables"] - enum_desc = nested["enum_desc"] + items = prop["items"] + # Items can be a list of schemas or a schema itself + # http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.4 + if isinstance(items, list): + nested_titles = [] + for i in items: + nested = process_data_type(i) + tables.extend(nested['tables']) + nested_titles.append(nested['title']) + prop_title = "[%s]" % (", ".join(nested_titles), ) + else: + nested = process_data_type(prop["items"]) + prop_title = "[%s]" % nested["title"] + tables = nested["tables"] + enum_desc = nested["enum_desc"] else: prop_title = prop_type @@ -370,6 +383,7 @@ def get_tables_for_response(schema): def get_example_for_schema(schema): """Returns a python object representing a suitable example for this object""" schema = inherit_parents(schema) + if 'example' in schema: example = schema['example'] return example @@ -380,7 +394,7 @@ def get_example_for_schema(schema): if 'properties' not in schema: raise Exception('"object" property has neither properties nor example') res = OrderedDict() - for prop_name, prop in schema['properties'].iteritems(): + for prop_name, prop in schema['properties'].items(): logger.debug("Parsing property %r" % prop_name) prop_example = get_example_for_schema(prop) res[prop_name] = prop_example @@ -389,7 +403,10 @@ def get_example_for_schema(schema): if proptype == 'array': if 'items' not in schema: raise Exception('"array" property has neither items nor example') - return [get_example_for_schema(schema['items'])] + items = schema['items'] + if isinstance(items, list): + return [get_example_for_schema(i) for i in items] + return [get_example_for_schema(items)] if proptype == 'integer': return 0 @@ -502,6 +519,15 @@ class MatrixUnits(Units): # assign value expected for this param val_type = param.get("type") # integer/string + if val_type == "array": + items = param.get("items") + if items: + if isinstance(items, list): + types = ", ".join(i.get("type") for i in items) + val_type = "[%s]" % (types,) + else: + val_type = "[%s]" % items.get("type") + if param.get("enum"): val_type = "enum" desc += ( @@ -518,7 +544,7 @@ class MatrixUnits(Units): if param_loc == "path": path_template = path_template.replace( - "{%s}" % param_name, urllib.quote(example) + "{%s}" % param_name, quote(example) ) elif param_loc == "query": if type(example) == list: @@ -527,7 +553,7 @@ class MatrixUnits(Units): else: example_query_params.append((param_name, example)) - except Exception, e: + except Exception as e: raise Exception("Error handling parameter %s" % param_name, e) # endfor[param] good_response = None @@ -551,14 +577,14 @@ class MatrixUnits(Units): ) if "headers" in good_response: headers = TypeTable() - for (header_name, header) in good_response["headers"].iteritems(): + for (header_name, header) in good_response["headers"].items(): headers.add_row( TypeTableRow(key=header_name, title=header["type"], desc=header["description"]), ) endpoint["res_headers"] = headers query_string = "" if len( - example_query_params) == 0 else "?" + urllib.urlencode( + example_query_params) == 0 else "?" + urlencode( example_query_params) if example_body: endpoint["example"][ @@ -600,12 +626,12 @@ class MatrixUnits(Units): body_tables = req_body_tables[1:] endpoint_data['req_body_tables'].extend(body_tables) - except Exception, e: + except Exception as e: e2 = Exception( "Error decoding body of API endpoint %s %s: %s" % (endpoint_data["method"], endpoint_data["path"], e) ) - raise e2, None, sys.exc_info()[2] + raise e2.with_traceback(sys.exc_info()[2]) def load_swagger_apis(self): @@ -706,12 +732,12 @@ class MatrixUnits(Units): if filename != event_name: examples[event_name] = examples.get(event_name, []) examples[event_name].append(example) - except Exception, e: + except Exception as e: e2 = Exception("Error reading event example "+filepath+": "+ str(e)) # throw the new exception with the old stack trace, so that # we don't lose information about where the error occurred. - raise e2, None, sys.exc_info()[2] + raise e2.with_traceback(sys.exc_info()[2]) return examples @@ -725,12 +751,12 @@ class MatrixUnits(Units): filepath = os.path.join(path, filename) try: schemata[filename] = self.read_event_schema(filepath) - except Exception, e: + except Exception as e: e2 = Exception("Error reading event schema "+filepath+": "+ str(e)) # throw the new exception with the old stack trace, so that # we don't lose information about where the error occurred. - raise e2, None, sys.exc_info()[2] + raise e2.with_traceback(sys.exc_info()[2]) return schemata @@ -826,12 +852,42 @@ class MatrixUnits(Units): path = os.path.join(CHANGELOG_DIR, f) name = f[:-4] + # If there's a directory with the same name, we'll try to generate + # a towncrier changelog and prepend it to the general changelog. + tc_path = os.path.join(CHANGELOG_DIR, name) + tc_lines = [] + if os.path.isdir(tc_path): + logger.info("Generating towncrier changelog for: %s" % name) + p = subprocess.Popen( + ['towncrier', '--version', 'Unreleased Changes', '--name', name, '--draft'], + cwd=tc_path, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + stdout, stderr = p.communicate() + if p.returncode != 0: + # Something broke - dump as much information as we can + logger.error("Towncrier exited with code %s" % p.returncode) + logger.error(stdout.decode('UTF-8')) + logger.error(stderr.decode('UTF-8')) + raw_log = "" + else: + raw_log = stdout.decode('UTF-8') + + # This is a bit of a hack, but it does mean that the log at least gets *something* + # to tell us it broke + if not raw_log.startswith("Unreleased Changes"): + logger.error("Towncrier appears to have failed to generate a changelog") + logger.error(raw_log) + raw_log = "" + tc_lines = raw_log.splitlines() + title_part = None changelog_lines = [] with open(path, "r") as f: lines = f.readlines() prev_line = None - for line in lines: + for line in (tc_lines + lines): if prev_line is None: prev_line = line continue @@ -847,7 +903,10 @@ class MatrixUnits(Units): # then bail out. changelog_lines.pop() break - changelog_lines.append(" " + line) + # Don't generate subheadings (we'll keep the title though) + if re.match("^[-]{3,}$", line.strip()): + continue + changelog_lines.append(" " + line + '\n') changelogs[name] = "".join(changelog_lines) return changelogs @@ -866,7 +925,7 @@ class MatrixUnits(Units): ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], stderr=null, cwd=cwd, - ).strip() + ).strip().decode('UTF-8') except subprocess.CalledProcessError: git_branch = "" try: @@ -874,7 +933,7 @@ class MatrixUnits(Units): ['git', 'describe', '--exact-match'], stderr=null, cwd=cwd, - ).strip() + ).strip().decode('UTF-8') git_tag = "tag=" + git_tag except subprocess.CalledProcessError: git_tag = "" @@ -883,7 +942,7 @@ class MatrixUnits(Units): ['git', 'rev-parse', '--short', 'HEAD'], stderr=null, cwd=cwd, - ).strip() + ).strip().decode('UTF-8') except subprocess.CalledProcessError: git_commit = "" try: @@ -892,7 +951,7 @@ class MatrixUnits(Units): ['git', 'describe', '--dirty=' + dirty_string, "--all"], stderr=null, cwd=cwd, - ).strip().endswith(dirty_string) + ).strip().decode('UTF-8').endswith(dirty_string) git_dirty = "dirty" if is_dirty else "" except subprocess.CalledProcessError: git_dirty = "" @@ -903,7 +962,7 @@ class MatrixUnits(Units): s for s in (git_branch, git_tag, git_commit, git_dirty,) if s - ).encode("ascii") + ).encode("ascii").decode('ascii') return { "string": git_version, "revision": git_commit diff --git a/scripts/test-and-build.sh b/scripts/test-and-build.sh index 7794f8264..710b03ddf 100755 --- a/scripts/test-and-build.sh +++ b/scripts/test-and-build.sh @@ -4,8 +4,13 @@ set -ex cd `dirname $0`/.. -virtualenv env +virtualenv -p python3 env . env/bin/activate + +# Print out the python versions for debugging purposes +python --version +pip --version + pip install -r scripts/requirements.txt # do sanity checks on the examples and swagger diff --git a/specification/appendices/identifier_grammar.rst b/specification/appendices/identifier_grammar.rst index 3abcfae2b..7156c7d57 100644 --- a/specification/appendices/identifier_grammar.rst +++ b/specification/appendices/identifier_grammar.rst @@ -59,6 +59,7 @@ The sigil characters are as follows: * ``@``: User ID * ``!``: Room ID * ``$``: Event ID +* ``+``: Group ID * ``#``: Room alias The precise grammar defining the allowable format of an identifier depends on @@ -206,6 +207,35 @@ readable. .. TODO-spec What is the grammar for the opaque part? https://matrix.org/jira/browse/SPEC-389 + +Group Identifiers ++++++++++++++++++ + +Groups within Matrix are uniquely identified by their group ID. The group +ID is namespaced to the group server which hosts this group and has the +form:: + + +localpart:domain + +The ``localpart`` of a group ID is an opaque identifier for that group. It MUST +NOT be empty, and MUST contain only the characters ``a-z``, ``0-9``, ``.``, +``_``, ``=``, ``-``, and ``/``. + +The ``domain`` of a group ID is the `server name`_ of the group server which +hosts this group. + +The length of a group ID, including the ``+`` sigil and the domain, MUST NOT +exceed 255 characters. + +The complete grammar for a legal group ID is:: + + group_id = "+" group_id_localpart ":" server_name + group_id_localpart = 1*group_id_char + group_id_char = DIGIT + / %x61-7A ; a-z + / "-" / "." / "=" / "_" / "/" + + Room Aliases ++++++++++++ diff --git a/specification/client_server_api.rst b/specification/client_server_api.rst index dec3a4f44..1bb989ff6 100644 --- a/specification/client_server_api.rst +++ b/specification/client_server_api.rst @@ -164,6 +164,25 @@ recommended. {{versions_cs_http_api}} +Web Browser Clients +------------------- + +It is realistic to expect that some clients will be written to be run within a +web browser or similar environment. In these cases, the homeserver should respond +to pre-flight requests and supply Cross-Origin Resource Sharing (CORS) headers on +all requests. + +When a client approaches the server with a pre-flight (``OPTIONS``) request, the +server should respond with the CORS headers for that route. The recommended CORS +headers to be returned by servers on all requests are: + +.. code:: + + Access-Control-Allow-Origin: * + Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS + Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization + + Client Authentication --------------------- @@ -1398,7 +1417,7 @@ have to wait in milliseconds before they can try again. .. References .. _`macaroon`: http://research.google.com/pubs/pub41892.html -.. _`devices`: ../intro.html#devices +.. _`devices`: ../index.html#devices .. Links through the external API docs are below .. ============================================= diff --git a/specification/feature_profiles.rst b/specification/feature_profiles.rst index 7fc9696de..c6b8ef4c0 100644 --- a/specification/feature_profiles.rst +++ b/specification/feature_profiles.rst @@ -42,6 +42,7 @@ Summary `Server Side Search`_ Optional Optional Optional Optional Optional `Server Administration`_ Optional Optional Optional Optional Optional `Event Context`_ Optional Optional Optional Optional Optional + `Third Party Networks`_ Optional Optional Optional Optional Optional ===================================== ========== ========== ========== ========== ========== *Please see each module for more details on what clients need to implement.* @@ -57,6 +58,7 @@ Summary .. _Server Side Search: `module:search`_ .. _Server Administration: `module:admin`_ .. _Event Context: `module:event-context`_ +.. _Third Party Networks: `module:third-party-networks`_ Clients ------- diff --git a/specification/index.rst b/specification/index.rst index f9a3fef34..36c899580 100644 --- a/specification/index.rst +++ b/specification/index.rst @@ -30,18 +30,392 @@ communication ecosystem. To propose a change to the Matrix Spec, see the explanations at `Proposals for Spec Changes to Matrix `_. +.. contents:: Table of Contents +.. sectnum:: + Matrix APIs ----------- The specification consists of the following parts: -`Introduction to Matrix `_ provides a full introduction to Matrix and the spec. - {{apis}} The `Appendices `_ contain supplemental information not specific to one of the above APIs. +Introduction to the Matrix APIs +------------------------------- +.. WARNING:: + The Matrix specification is still evolving: the APIs are not yet frozen + and this document is in places a work in progress or stale. We have made every + effort to clearly flag areas which are still being finalised. + We're publishing it at this point because it's complete enough to be more than + useful and provide a canonical reference to how Matrix is evolving. Our end + goal is to mirror WHATWG's `Living Standard + `_. + +Matrix is a set of open APIs for open-federated Instant Messaging (IM), Voice +over IP (VoIP) and Internet of Things (IoT) communication, designed to create +and support a new global real-time communication ecosystem. The intention is to +provide an open decentralised pubsub layer for the internet for securely +persisting and publishing/subscribing JSON objects. This specification is the +ongoing result of standardising the APIs used by the various components of the +Matrix ecosystem to communicate with one another. + +The principles that Matrix attempts to follow are: + +- Pragmatic Web-friendly APIs (i.e. JSON over REST) +- Keep It Simple & Stupid + + + provide a simple architecture with minimal third-party dependencies. + +- Fully open: + + + Fully open federation - anyone should be able to participate in the global + Matrix network + + Fully open standard - publicly documented standard with no IP or patent + licensing encumbrances + + Fully open source reference implementation - liberally-licensed example + implementations with no IP or patent licensing encumbrances + +- Empowering the end-user + + + The user should be able to choose the server and clients they use + + The user should be control how private their communication is + + The user should know precisely where their data is stored + +- Fully decentralised - no single points of control over conversations or the + network as a whole +- Learning from history to avoid repeating it + + + Trying to take the best aspects of XMPP, SIP, IRC, SMTP, IMAP and NNTP + whilst trying to avoid their failings + + +The functionality that Matrix provides includes: + +- Creation and management of fully distributed chat rooms with no + single points of control or failure +- Eventually-consistent cryptographically secure synchronisation of room + state across a global open network of federated servers and services +- Sending and receiving extensible messages in a room with (optional) + end-to-end encryption +- Extensible user management (inviting, joining, leaving, kicking, banning) + mediated by a power-level based user privilege system. +- Extensible room state management (room naming, aliasing, topics, bans) +- Extensible user profile management (avatars, display names, etc) +- Managing user accounts (registration, login, logout) +- Use of 3rd Party IDs (3PIDs) such as email addresses, phone numbers, + Facebook accounts to authenticate, identify and discover users on Matrix. +- Trusted federation of Identity servers for: + + + Publishing user public keys for PKI + + Mapping of 3PIDs to Matrix IDs + + +The end goal of Matrix is to be a ubiquitous messaging layer for synchronising +arbitrary data between sets of people, devices and services - be that for +instant messages, VoIP call setups, or any other objects that need to be +reliably and persistently pushed from A to B in an interoperable and federated +manner. + + +Spec Change Proposals +~~~~~~~~~~~~~~~~~~~~~ +To propose a change to the Matrix Spec, see the explanations at `Proposals +for Spec Changes to Matrix `_. + + +Architecture +------------ + +Matrix defines APIs for synchronising extensible JSON objects known as +"events" between compatible clients, servers and services. Clients are +typically messaging/VoIP applications or IoT devices/hubs and communicate by +synchronising communication history with their "homeserver" using the +"Client-Server API". Each homeserver stores the communication history and +account information for all of its clients, and shares data with the wider +Matrix ecosystem by synchronising communication history with other homeservers +and their clients. + +Clients typically communicate with each other by emitting events in the +context of a virtual "room". Room data is replicated across *all of the +homeservers* whose users are participating in a given room. As such, *no +single homeserver has control or ownership over a given room*. Homeservers +model communication history as a partially ordered graph of events known as +the room's "event graph", which is synchronised with eventual consistency +between the participating servers using the "Server-Server API". This process +of synchronising shared conversation history between homeservers run by +different parties is called "Federation". Matrix optimises for the +Availability and Partitioned properties of CAP theorem at +the expense of Consistency. + +For example, for client A to send a message to client B, client A performs an +HTTP PUT of the required JSON event on its homeserver (HS) using the +client-server API. A's HS appends this event to its copy of the room's event +graph, signing the message in the context of the graph for integrity. A's HS +then replicates the message to B's HS by performing an HTTP PUT using the +server-server API. B's HS authenticates the request, validates the event's +signature, authorises the event's contents and then adds it to its copy of the +room's event graph. Client B then receives the message from his homeserver via +a long-lived GET request. + +:: + + How data flows between clients + ============================== + + { Matrix client A } { Matrix client B } + ^ | ^ | + | events | Client-Server API | events | + | V | V + +------------------+ +------------------+ + | |---------( HTTPS )--------->| | + | homeserver | | homeserver | + | |<--------( HTTPS )----------| | + +------------------+ Server-Server API +------------------+ + History Synchronisation + (Federation) + + +Users +~~~~~ + +Each client is associated with a user account, which is identified in Matrix +using a unique "user ID". This ID is namespaced to the homeserver which +allocated the account and has the form:: + + @localpart:domain + +See `'Identifier Grammar' the appendices `_ for full details of +the structure of user IDs. + +Devices +~~~~~~~ + +The Matrix specification has a particular meaning for the term "device". As a +user, I might have several devices: a desktop client, some web browsers, an +Android device, an iPhone, etc. They broadly relate to a real device in the +physical world, but you might have several browsers on a physical device, or +several Matrix client applications on a mobile device, each of which would be +its own device. + +Devices are used primarily to manage the keys used for end-to-end encryption +(each device gets its own copy of the decryption keys), but they also help +users manage their access - for instance, by revoking access to particular +devices. + +When a user first uses a client, it registers itself as a new device. The +longevity of devices might depend on the type of client. A web client will +probably drop all of its state on logout, and create a new device every time +you log in, to ensure that cryptography keys are not leaked to a new user. In +a mobile client, it might be acceptable to reuse the device if a login session +expires, provided the user is the same. + +Devices are identified by a ``device_id``, which is unique within the scope of +a given user. + +A user may assign a human-readable display name to a device, to help them +manage their devices. + +Events +~~~~~~ + +All data exchanged over Matrix is expressed as an "event". Typically each client +action (e.g. sending a message) correlates with exactly one event. Each event +has a ``type`` which is used to differentiate different kinds of data. ``type`` +values MUST be uniquely globally namespaced following Java's `package naming +conventions`_, e.g. +``com.example.myapp.event``. The special top-level namespace ``m.`` is reserved +for events defined in the Matrix specification - for instance ``m.room.message`` +is the event type for instant messages. Events are usually sent in the context +of a "Room". + +.. _package naming conventions: https://en.wikipedia.org/wiki/Java_package#Package_naming_conventions + +Event Graphs +~~~~~~~~~~~~ + +.. _sect:event-graph: + +Events exchanged in the context of a room are stored in a directed acyclic graph +(DAG) called an "event graph". The partial ordering of this graph gives the +chronological ordering of events within the room. Each event in the graph has a +list of zero or more "parent" events, which refer to any preceding events +which have no chronological successor from the perspective of the homeserver +which created the event. + +Typically an event has a single parent: the most recent message in the room at +the point it was sent. However, homeservers may legitimately race with each +other when sending messages, resulting in a single event having multiple +successors. The next event added to the graph thus will have multiple parents. +Every event graph has a single root event with no parent. + +To order and ease chronological comparison between the events within the graph, +homeservers maintain a ``depth`` metadata field on each event. An event's +``depth`` is a positive integer that is strictly greater than the depths of any +of its parents. The root event should have a depth of 1. Thus if one event is +before another, then it must have a strictly smaller depth. + +Room structure +~~~~~~~~~~~~~~ + +A room is a conceptual place where users can send and receive events. Events are +sent to a room, and all participants in that room with sufficient access will +receive the event. Rooms are uniquely identified internally via "Room IDs", +which have the form:: + + !opaque_id:domain + +There is exactly one room ID for each room. Whilst the room ID does contain a +domain, it is simply for globally namespacing room IDs. The room does NOT +reside on the domain specified. + +See `'Identifier Grammar' in the appendices `_ for full details of +the structure of a room ID. + +The following conceptual diagram shows an +``m.room.message`` event being sent to the room ``!qporfwt:matrix.org``:: + + { @alice:matrix.org } { @bob:domain.com } + | ^ + | | + [HTTP POST] [HTTP GET] + Room ID: !qporfwt:matrix.org Room ID: !qporfwt:matrix.org + Event type: m.room.message Event type: m.room.message + Content: { JSON object } Content: { JSON object } + | | + V | + +------------------+ +------------------+ + | homeserver | | homeserver | + | matrix.org | | domain.com | + +------------------+ +------------------+ + | ^ + | [HTTP PUT] | + | Room ID: !qporfwt:matrix.org | + | Event type: m.room.message | + | Content: { JSON object } | + `-------> Pointer to the preceding message ------` + PKI signature from matrix.org + Transaction-layer metadata + PKI Authorization header + + ................................... + | Shared Data | + | State: | + | Room ID: !qporfwt:matrix.org | + | Servers: matrix.org, domain.com | + | Members: | + | - @alice:matrix.org | + | - @bob:domain.com | + | Messages: | + | - @alice:matrix.org | + | Content: { JSON object } | + |...................................| + +Federation maintains *shared data structures* per-room between multiple home +servers. The data is split into ``message events`` and ``state events``. + +Message events: + These describe transient 'once-off' activity in a room such as an + instant messages, VoIP call setups, file transfers, etc. They generally + describe communication activity. + +State events: + These describe updates to a given piece of persistent information + ('state') related to a room, such as the room's name, topic, membership, + participating servers, etc. State is modelled as a lookup table of key/value + pairs per room, with each key being a tuple of ``state_key`` and ``event type``. + Each state event updates the value of a given key. + +The state of the room at a given point is calculated by considering all events +preceding and including a given event in the graph. Where events describe the +same state, a merge conflict algorithm is applied. The state resolution +algorithm is transitive and does not depend on server state, as it must +consistently select the same event irrespective of the server or the order the +events were received in. Events are signed by the originating server (the +signature includes the parent relations, type, depth and payload hash) and are +pushed over federation to the participating servers in a room, currently using +full mesh topology. Servers may also request backfill of events over federation +from the other servers participating in a room. + + +Room Aliases +++++++++++++ + +Each room can also have multiple "Room Aliases", which look like:: + + #room_alias:domain + +See `'Identifier Grammar' in the appendices `_ for full details of +the structure of a room alias. + +A room alias "points" to a room ID and is the human-readable label by which +rooms are publicised and discovered. The room ID the alias is pointing to can +be obtained by visiting the domain specified. Note that the mapping from a room +alias to a room ID is not fixed, and may change over time to point to a +different room ID. For this reason, Clients SHOULD resolve the room alias to a +room ID once and then use that ID on subsequent requests. + +When resolving a room alias the server will also respond with a list of servers +that are in the room that can be used to join via. + +:: + + HTTP GET + #matrix:domain.com !aaabaa:matrix.org + | ^ + | | + _______V____________________|____ + | domain.com | + | Mappings: | + | #matrix >> !aaabaa:matrix.org | + | #golf >> !wfeiofh:sport.com | + | #bike >> !4rguxf:matrix.org | + |________________________________| + +Identity +~~~~~~~~ + +Users in Matrix are identified via their Matrix user ID. However, +existing 3rd party ID namespaces can also be used in order to identify Matrix +users. A Matrix "Identity" describes both the user ID and any other existing IDs +from third party namespaces *linked* to their account. +Matrix users can *link* third-party IDs (3PIDs) such as email addresses, social +network accounts and phone numbers to their user ID. Linking 3PIDs creates a +mapping from a 3PID to a user ID. This mapping can then be used by Matrix +users in order to discover the user IDs of their contacts. +In order to ensure that the mapping from 3PID to user ID is genuine, a globally +federated cluster of trusted "Identity Servers" (IS) are used to verify the 3PID +and persist and replicate the mappings. + +Usage of an IS is not required in order for a client application to be part of +the Matrix ecosystem. However, without one clients will not be able to look up +user IDs using 3PIDs. + + +Profiles +~~~~~~~~ + +Users may publish arbitrary key/value data associated with their account - such +as a human readable display name, a profile photo URL, contact information +(email address, phone numbers, website URLs etc). + +.. TODO + Actually specify the different types of data - e.g. what format are display + names allowed to be? + +Private User Data +~~~~~~~~~~~~~~~~~ + +Users may also store arbitrary private key/value data in their account - such as +client preferences, or server configuration settings which lack any other +dedicated API. The API is symmetrical to managing Profile data. + +.. TODO + Would it really be overengineered to use the same API for both profile & + private user data, but with different ACLs? + Specification Versions ---------------------- @@ -57,3 +431,9 @@ The specification for each API is versioned in the form ``rX.Y.Z``. * A change to ``Z`` represents a change which is backwards-compatible on both sides. Typically this implies a clarification to the specification, rather than a change which must be implemented. + +License +------- + +The Matrix specification is licensed under the `Apache License, Version 2.0 +`_. diff --git a/specification/intro.rst b/specification/intro.rst deleted file mode 100644 index ad5452484..000000000 --- a/specification/intro.rst +++ /dev/null @@ -1,400 +0,0 @@ -.. Copyright 2016 OpenMarket Ltd -.. -.. Licensed under the Apache License, Version 2.0 (the "License"); -.. you may not use this file except in compliance with the License. -.. You may obtain a copy of the License at -.. -.. http://www.apache.org/licenses/LICENSE-2.0 -.. -.. Unless required by applicable law or agreed to in writing, software -.. distributed under the License is distributed on an "AS IS" BASIS, -.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -.. See the License for the specific language governing permissions and -.. limitations under the License. - -.. contents:: Table of Contents -.. sectnum:: - -.. Note that this file is specifically unversioned because we don't want to -.. have to add Yet Another version number, and the commentary on what specs we -.. have should hopefully not get complex enough that we need to worry about -.. versioning it. - -Introduction ------------- -.. WARNING:: - The Matrix specification is still evolving: the APIs are not yet frozen - and this document is in places a work in progress or stale. We have made every - effort to clearly flag areas which are still being finalised. - We're publishing it at this point because it's complete enough to be more than - useful and provide a canonical reference to how Matrix is evolving. Our end - goal is to mirror WHATWG's `Living Standard - `_. - -Matrix is a set of open APIs for open-federated Instant Messaging (IM), Voice -over IP (VoIP) and Internet of Things (IoT) communication, designed to create -and support a new global real-time communication ecosystem. The intention is to -provide an open decentralised pubsub layer for the internet for securely -persisting and publishing/subscribing JSON objects. This specification is the -ongoing result of standardising the APIs used by the various components of the -Matrix ecosystem to communicate with one another. - -The principles that Matrix attempts to follow are: - -- Pragmatic Web-friendly APIs (i.e. JSON over REST) -- Keep It Simple & Stupid - - + provide a simple architecture with minimal third-party dependencies. - -- Fully open: - - + Fully open federation - anyone should be able to participate in the global - Matrix network - + Fully open standard - publicly documented standard with no IP or patent - licensing encumbrances - + Fully open source reference implementation - liberally-licensed example - implementations with no IP or patent licensing encumbrances - -- Empowering the end-user - - + The user should be able to choose the server and clients they use - + The user should be control how private their communication is - + The user should know precisely where their data is stored - -- Fully decentralised - no single points of control over conversations or the - network as a whole -- Learning from history to avoid repeating it - - + Trying to take the best aspects of XMPP, SIP, IRC, SMTP, IMAP and NNTP - whilst trying to avoid their failings - - -The functionality that Matrix provides includes: - -- Creation and management of fully distributed chat rooms with no - single points of control or failure -- Eventually-consistent cryptographically secure synchronisation of room - state across a global open network of federated servers and services -- Sending and receiving extensible messages in a room with (optional) - end-to-end encryption -- Extensible user management (inviting, joining, leaving, kicking, banning) - mediated by a power-level based user privilege system. -- Extensible room state management (room naming, aliasing, topics, bans) -- Extensible user profile management (avatars, display names, etc) -- Managing user accounts (registration, login, logout) -- Use of 3rd Party IDs (3PIDs) such as email addresses, phone numbers, - Facebook accounts to authenticate, identify and discover users on Matrix. -- Trusted federation of Identity servers for: - - + Publishing user public keys for PKI - + Mapping of 3PIDs to Matrix IDs - - -The end goal of Matrix is to be a ubiquitous messaging layer for synchronising -arbitrary data between sets of people, devices and services - be that for -instant messages, VoIP call setups, or any other objects that need to be -reliably and persistently pushed from A to B in an interoperable and federated -manner. - - -Spec Change Proposals -~~~~~~~~~~~~~~~~~~~~~ -To propose a change to the Matrix Spec, see the explanations at `Proposals -for Spec Changes to Matrix `_. - - -Architecture ------------- - -Matrix defines APIs for synchronising extensible JSON objects known as -"events" between compatible clients, servers and services. Clients are -typically messaging/VoIP applications or IoT devices/hubs and communicate by -synchronising communication history with their "homeserver" using the -"Client-Server API". Each homeserver stores the communication history and -account information for all of its clients, and shares data with the wider -Matrix ecosystem by synchronising communication history with other homeservers -and their clients. - -Clients typically communicate with each other by emitting events in the -context of a virtual "room". Room data is replicated across *all of the -homeservers* whose users are participating in a given room. As such, *no -single homeserver has control or ownership over a given room*. Homeservers -model communication history as a partially ordered graph of events known as -the room's "event graph", which is synchronised with eventual consistency -between the participating servers using the "Server-Server API". This process -of synchronising shared conversation history between homeservers run by -different parties is called "Federation". Matrix optimises for the -Availability and Partitioned properties of CAP theorem at -the expense of Consistency. - -For example, for client A to send a message to client B, client A performs an -HTTP PUT of the required JSON event on its homeserver (HS) using the -client-server API. A's HS appends this event to its copy of the room's event -graph, signing the message in the context of the graph for integrity. A's HS -then replicates the message to B's HS by performing an HTTP PUT using the -server-server API. B's HS authenticates the request, validates the event's -signature, authorises the event's contents and then adds it to its copy of the -room's event graph. Client B then receives the message from his homeserver via -a long-lived GET request. - -:: - - How data flows between clients - ============================== - - { Matrix client A } { Matrix client B } - ^ | ^ | - | events | Client-Server API | events | - | V | V - +------------------+ +------------------+ - | |---------( HTTPS )--------->| | - | homeserver | | homeserver | - | |<--------( HTTPS )----------| | - +------------------+ Server-Server API +------------------+ - History Synchronisation - (Federation) - - -Users -~~~~~ - -Each client is associated with a user account, which is identified in Matrix -using a unique "user ID". This ID is namespaced to the homeserver which -allocated the account and has the form:: - - @localpart:domain - -See the `appendices `_ for full details of -the structure of user IDs. - -Devices -~~~~~~~ - -The Matrix specification has a particular meaning for the term "device". As a -user, I might have several devices: a desktop client, some web browsers, an -Android device, an iPhone, etc. They broadly relate to a real device in the -physical world, but you might have several browsers on a physical device, or -several Matrix client applications on a mobile device, each of which would be -its own device. - -Devices are used primarily to manage the keys used for end-to-end encryption -(each device gets its own copy of the decryption keys), but they also help -users manage their access - for instance, by revoking access to particular -devices. - -When a user first uses a client, it registers itself as a new device. The -longevity of devices might depend on the type of client. A web client will -probably drop all of its state on logout, and create a new device every time -you log in, to ensure that cryptography keys are not leaked to a new user. In -a mobile client, it might be acceptable to reuse the device if a login session -expires, provided the user is the same. - -Devices are identified by a ``device_id``, which is unique within the scope of -a given user. - -A user may assign a human-readable display name to a device, to help them -manage their devices. - -Events -~~~~~~ - -All data exchanged over Matrix is expressed as an "event". Typically each client -action (e.g. sending a message) correlates with exactly one event. Each event -has a ``type`` which is used to differentiate different kinds of data. ``type`` -values MUST be uniquely globally namespaced following Java's `package naming -conventions`_, e.g. -``com.example.myapp.event``. The special top-level namespace ``m.`` is reserved -for events defined in the Matrix specification - for instance ``m.room.message`` -is the event type for instant messages. Events are usually sent in the context -of a "Room". - -.. _package naming conventions: https://en.wikipedia.org/wiki/Java_package#Package_naming_conventions - -Event Graphs -~~~~~~~~~~~~ - -.. _sect:event-graph: - -Events exchanged in the context of a room are stored in a directed acyclic graph -(DAG) called an "event graph". The partial ordering of this graph gives the -chronological ordering of events within the room. Each event in the graph has a -list of zero or more "parent" events, which refer to any preceding events -which have no chronological successor from the perspective of the homeserver -which created the event. - -Typically an event has a single parent: the most recent message in the room at -the point it was sent. However, homeservers may legitimately race with each -other when sending messages, resulting in a single event having multiple -successors. The next event added to the graph thus will have multiple parents. -Every event graph has a single root event with no parent. - -To order and ease chronological comparison between the events within the graph, -homeservers maintain a ``depth`` metadata field on each event. An event's -``depth`` is a positive integer that is strictly greater than the depths of any -of its parents. The root event should have a depth of 1. Thus if one event is -before another, then it must have a strictly smaller depth. - -Room structure -~~~~~~~~~~~~~~ - -A room is a conceptual place where users can send and receive events. Events are -sent to a room, and all participants in that room with sufficient access will -receive the event. Rooms are uniquely identified internally via "Room IDs", -which have the form:: - - !opaque_id:domain - -There is exactly one room ID for each room. Whilst the room ID does contain a -domain, it is simply for globally namespacing room IDs. The room does NOT -reside on the domain specified. - -See the `appendices `_ for full details of -the structure of a room ID. - -The following conceptual diagram shows an -``m.room.message`` event being sent to the room ``!qporfwt:matrix.org``:: - - { @alice:matrix.org } { @bob:domain.com } - | ^ - | | - [HTTP POST] [HTTP GET] - Room ID: !qporfwt:matrix.org Room ID: !qporfwt:matrix.org - Event type: m.room.message Event type: m.room.message - Content: { JSON object } Content: { JSON object } - | | - V | - +------------------+ +------------------+ - | homeserver | | homeserver | - | matrix.org | | domain.com | - +------------------+ +------------------+ - | ^ - | [HTTP PUT] | - | Room ID: !qporfwt:matrix.org | - | Event type: m.room.message | - | Content: { JSON object } | - `-------> Pointer to the preceding message ------` - PKI signature from matrix.org - Transaction-layer metadata - PKI Authorization header - - ................................... - | Shared Data | - | State: | - | Room ID: !qporfwt:matrix.org | - | Servers: matrix.org, domain.com | - | Members: | - | - @alice:matrix.org | - | - @bob:domain.com | - | Messages: | - | - @alice:matrix.org | - | Content: { JSON object } | - |...................................| - -Federation maintains *shared data structures* per-room between multiple home -servers. The data is split into ``message events`` and ``state events``. - -Message events: - These describe transient 'once-off' activity in a room such as an - instant messages, VoIP call setups, file transfers, etc. They generally - describe communication activity. - -State events: - These describe updates to a given piece of persistent information - ('state') related to a room, such as the room's name, topic, membership, - participating servers, etc. State is modelled as a lookup table of key/value - pairs per room, with each key being a tuple of ``state_key`` and ``event type``. - Each state event updates the value of a given key. - -The state of the room at a given point is calculated by considering all events -preceding and including a given event in the graph. Where events describe the -same state, a merge conflict algorithm is applied. The state resolution -algorithm is transitive and does not depend on server state, as it must -consistently select the same event irrespective of the server or the order the -events were received in. Events are signed by the originating server (the -signature includes the parent relations, type, depth and payload hash) and are -pushed over federation to the participating servers in a room, currently using -full mesh topology. Servers may also request backfill of events over federation -from the other servers participating in a room. - - -Room Aliases -++++++++++++ - -Each room can also have multiple "Room Aliases", which look like:: - - #room_alias:domain - -See the `appendices `_ for full details of -the structure of a room alias. - -A room alias "points" to a room ID and is the human-readable label by which -rooms are publicised and discovered. The room ID the alias is pointing to can -be obtained by visiting the domain specified. Note that the mapping from a room -alias to a room ID is not fixed, and may change over time to point to a -different room ID. For this reason, Clients SHOULD resolve the room alias to a -room ID once and then use that ID on subsequent requests. - -When resolving a room alias the server will also respond with a list of servers -that are in the room that can be used to join via. - -:: - - HTTP GET - #matrix:domain.com !aaabaa:matrix.org - | ^ - | | - _______V____________________|____ - | domain.com | - | Mappings: | - | #matrix >> !aaabaa:matrix.org | - | #golf >> !wfeiofh:sport.com | - | #bike >> !4rguxf:matrix.org | - |________________________________| - -Identity -~~~~~~~~ - -Users in Matrix are identified via their Matrix user ID. However, -existing 3rd party ID namespaces can also be used in order to identify Matrix -users. A Matrix "Identity" describes both the user ID and any other existing IDs -from third party namespaces *linked* to their account. -Matrix users can *link* third-party IDs (3PIDs) such as email addresses, social -network accounts and phone numbers to their user ID. Linking 3PIDs creates a -mapping from a 3PID to a user ID. This mapping can then be used by Matrix -users in order to discover the user IDs of their contacts. -In order to ensure that the mapping from 3PID to user ID is genuine, a globally -federated cluster of trusted "Identity Servers" (IS) are used to verify the 3PID -and persist and replicate the mappings. - -Usage of an IS is not required in order for a client application to be part of -the Matrix ecosystem. However, without one clients will not be able to look up -user IDs using 3PIDs. - - -Profiles -~~~~~~~~ - -Users may publish arbitrary key/value data associated with their account - such -as a human readable display name, a profile photo URL, contact information -(email address, phone numbers, website URLs etc). - -.. TODO - Actually specify the different types of data - e.g. what format are display - names allowed to be? - -Private User Data -~~~~~~~~~~~~~~~~~ - -Users may also store arbitrary private key/value data in their account - such as -client preferences, or server configuration settings which lack any other -dedicated API. The API is symmetrical to managing Profile data. - -.. TODO - Would it really be overengineered to use the same API for both profile & - private user data, but with different ACLs? - -License -------- - -The Matrix specification is licensed under the `Apache License, Version 2.0 -`_. diff --git a/specification/modules/cas_login.rst b/specification/modules/cas_login.rst index b651431a3..5de980575 100644 --- a/specification/modules/cas_login.rst +++ b/specification/modules/cas_login.rst @@ -98,9 +98,9 @@ check for certain user attributes in the response. Any required attributes should be configured by the server administrator. Once the ticket has been validated, the server MUST map the CAS ``user_id`` -to a valid `Matrix user identifier <../intro.html#user-identifiers>`_. The +to a valid `Matrix user identifier <../index.html#user-identifiers>`_. The guidance in `Mapping from other character sets -<../intro.html#mapping-from-other-character-sets>`_ may be useful. +<../index.html#mapping-from-other-character-sets>`_ may be useful. If the generated user identifier represents a new user, it should be registered as a new user. diff --git a/specification/modules/third_party_networks.rst b/specification/modules/third_party_networks.rst new file mode 100644 index 000000000..cd4ce4143 --- /dev/null +++ b/specification/modules/third_party_networks.rst @@ -0,0 +1,20 @@ +Third Party Networks +==================== + +.. _module:third-party-networks: + +Application services can provide access to third party networks via bridging. +This allows Matrix users to communicate with users on other communication +platforms, with messages ferried back and forth by the application service. A +single application service may bridge multiple third party networks, and many +individual locations within those networks. A single third party network +location may be bridged to multiple Matrix rooms. + +Third Party Lookups +------------------- + +A client may wish to provide a rich interface for joining third party +locations and connecting with third party users. Information necessary for +such an interface is provided by third party lookups. + +{{third_party_lookup_cs_http_api}} \ No newline at end of file diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 70d495d33..c09d77913 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -1,5 +1,6 @@ .. Copyright 2016 OpenMarket Ltd .. Copyright 2017 New Vector Ltd +.. Copyright 2018 New Vector Ltd .. .. Licensed under the Apache License, Version 2.0 (the "License"); .. you may not use this file except in compliance with the License. @@ -16,6 +17,10 @@ Federation API ============== +.. WARNING:: + This API is unstable and will change without warning or discussion while + we work towards a r0 release (scheduled for August 2018). + Matrix homeservers use the Federation APIs (also known as server-server APIs) to communicate with each other. Homeservers use these APIs to push messages to each other in real-time, to @@ -162,50 +167,7 @@ If a server goes offline intermediate notary servers should continue to return the last response they received from that server so that the signatures of old events sent by that server can still be checked. -==================== =================== ====================================== - Key Type Description -==================== =================== ====================================== -``server_name`` String hostname of the homeserver. -``verify_keys`` Object Public keys of the homeserver for - verifying digital signatures. -``old_verify_keys`` Object The public keys that the server used - to use and when it stopped using them. -``signatures`` Object Digital signatures for this object - signed using the ``verify_keys``. -``tls_fingerprints`` Array of Objects Hashes of X.509 TLS certificates used - by this server encoded as `Unpadded Base64`_. -``valid_until_ts`` Integer POSIX timestamp when the list of valid - keys should be refreshed. -==================== =================== ====================================== - - -.. code:: json - - { - "old_verify_keys": { - "ed25519:auto1": { - "expired_ts": 922834800000, - "key": "Base+64+Encoded+Old+Verify+Key" - } - }, - "server_name": "example.org", - "signatures": { - "example.org": { - "ed25519:auto2": "Base+64+Encoded+Signature" - } - }, - "tls_fingerprints": [ - { - "sha256": "Base+64+Encoded+SHA-256-Fingerprint" - } - ], - "valid_until_ts": 1052262000000, - "verify_keys": { - "ed25519:auto2": { - "key": "Base+64+Encoded+Signature+Verification+Key" - } - } - } +{{keys_server_ss_http_api}} Querying Keys Through Another Server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -228,38 +190,7 @@ This API can return keys for servers that are offline by using cached responses taken from when the server was online. Keys can be queried from multiple servers to mitigate against DNS spoofing. -Example request: - -.. code:: - - GET /_matrix/key/v2/query/{server_name}/{key_id}/?minimum_valid_until_ts={minimum_valid_until_ts} HTTP/1.1 - - POST /_matrix/key/v2/query HTTP/1.1 - Content-Type: application/json - - { - "server_keys": { - "{server_name}": { - "{key_id}": { - "minimum_valid_until_ts": {posix_timestamp} - } - } - } - } - - -Response: - -.. code:: - - HTTP/1.1 200 OK - Content-Type: application/json - { - "server_keys": [ - # List of responses with same format as /_matrix/key/v2/server - # signed by both the originating server and this server. - ] - } +{{keys_query_ss_http_api}} Version 1 +++++++++ @@ -356,6 +287,10 @@ the destination. PDU Fields ~~~~~~~~~~ +.. TODO-spec + + Figure out how to embed swagger definitions in here (or improve the section) + ==================== ================== ======================================= Key Type Description ==================== ================== ======================================= @@ -745,68 +680,12 @@ All these URLs are name-spaced within a prefix of:: /_matrix/federation/v1/... -For active pushing of messages representing live activity "as it happens":: - - PUT .../send// - Body: JSON encoding of a single Transaction - Response: TODO-doc - -The transaction_id path argument will override any ID given in the JSON body. -The destination name will be set to that of the receiving server itself. Each -embedded PDU in the transaction body will be processed. - - -To fetch all the state of a given room:: - - GET .../state// - Response: JSON encoding of a single Transaction containing multiple PDUs - -Retrieves a snapshot of the entire current state of the given room. The -response will contain a single Transaction, inside which will be a list of PDUs -that encode the state. - - -To fetch a particular event:: - GET .../event// - Response: JSON encoding of a partial Transaction containing the event +{{transactions_ss_http_api}} -Retrieves a single event. The response will contain a partial Transaction, -having just the ``origin``, ``origin_server_ts`` and ``pdus`` fields; the -event will be encoded as the only PDU in the ``pdus`` list. +{{events_ss_http_api}} - -To backfill events on a given room:: - - GET .../backfill// - Query args: v, limit - Response: JSON encoding of a single Transaction containing multiple PDUs - -Retrieves a sliding-window history of previous PDUs that occurred on the given -room. Starting from the PDU ID(s) given in the "v" argument, the PDUs that -preceded it are retrieved, up to a total number given by the "limit" argument. - - -To stream all the events:: - - GET .../pull/ - Query args: origin, v - Response: JSON encoding of a single Transaction consisting of multiple PDUs - -Retrieves all of the transactions later than any version given by the "v" -arguments. - - -To make a query:: - - GET .../query/ - Query args: as specified by the individual query types - Response: JSON encoding of a response object - -Performs a single query request on the receiving homeserver. The Query Type -part of the path specifies the kind of query being made, and its query -arguments have a meaning specific to that kind of query. The response is a -JSON-encoded object whose meaning also depends on the kind of query. +{{query_general_ss_http_api}} To join a room:: @@ -1109,38 +988,9 @@ If the invited homeserver is in the room the invite came from, it can auth the event and send it. However, if the invited homeserver isn't in the room the invite came from, it -will need to request the room's homeserver to auth the event:: - - PUT .../exchange_third_party_invite/{roomId} - -Where ``roomId`` is the ID of the room the invite is for. - -The required fields in the JSON body are: - -==================== ======= ================================================== - Key Type Description -==================== ======= ================================================== -``type`` String The event type. Must be ``m.room.member``. -``room_id`` String The ID of the room the event is for. Must be the - same as the ID specified in the path. -``sender`` String The Matrix ID of the user who sent the original - ``m.room.third_party_invite``. -``state_key`` String The Matrix ID of the invited user. -``content`` Object The content of the event. -==================== ======= ================================================== - -Where the ``content`` key contains the content for the ``m.room.member`` event -as described in the `Client-Server API`_. Its ``membership`` key must be -``invite`` and its content must include the ``third_party_invite`` object. - -The inviting homeserver will then be able to authenticate the event. It will send -a fully authenticated event to the invited homeserver as described in the `Inviting -to a room`_ section above. +will need to request the room's homeserver to auth the event. -Once the invited homeserver responds with the event to which it appended its -signature, the inviting homeserver will respond with ``200 OK`` and an empty body -(``{}``) to the initial request on ``/exchange_third_party_invite/{roomId}`` and -send the now verified ``m.room.member`` invite event to the room's members. +{{third_party_invite_ss_http_api}} Verifying the invite ++++++++++++++++++++ diff --git a/specification/targets.yaml b/specification/targets.yaml index bc9d94c8f..53957e0af 100644 --- a/specification/targets.yaml +++ b/specification/targets.yaml @@ -2,9 +2,6 @@ targets: index: files: - index.rst - intro: - files: - - intro.rst client_server: files: - client_server_api.rst @@ -68,6 +65,7 @@ groups: # reusable blobs of files when prefixed with 'group:' - modules/ignore_users.rst - modules/stickers.rst - modules/report_content.rst + - modules/third_party_networks.rst title_styles: ["=", "-", "~", "+", "^", "`", "@", ":"]