diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..74b1c7d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +scripts/gen +scripts/continuserv/continuserv +scripts/speculator/speculator +templating/out +*.pyc +supporting-docs/_site +supporting-docs/.sass-cache +api/node_modules diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 00000000..6e3198ef --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,41 @@ +.. This file is automatically processed by the templating system. To make it +.. happy, you MUST use '=' as the title underline and you MUST stick the version +.. in the title. The version MUST follow the numbering format +.. "v.." - You cannot use a-z. If the templating system fails to +.. find the right info, it will be treated as a test failure and so will show up +.. in Jenkins. Comments like this are ignored by both RST and the templating +.. system. Add the newest release notes beneath this comment. + +Specification changes in v0.2.0 (2015-10-02) +============================================ + +This update fundamentally restructures the specification. The specification has +been split into more digestible "modules" which each describe a particular +function (e.g. typing). This was done in order make the specification easier to +maintain and help define which modules are mandatory for certain types +of clients. Types of clients along with the mandatory modules can be found in a +new "Feature Profiles" section. This update also begins to aggressively +standardise on using Swagger and JSON Schema to document HTTP endpoints and +Events respectively. It also introduces a number of new concepts to Matrix. + +Additions: + - New section: Feature Profiles. + - New section: Receipts. + - New section: Room history visibility. + - New event: ``m.receipt``. + - New event: ``m.room.canonical_alias`` + - New event: ``m.room.history_visibility`` + - New keys: ``/createRoom`` - allows room "presets" using ``preset`` and + ``initial_state`` keys. + - New endpoint: ``/tokenrefresh`` - Related to refreshing access tokens. + +Modifications: + - Convert most of the older HTTP APIs to Swagger documentation. + - Convert most of the older event formats to JSON Schema. + - Move selected client-server sections to be "Modules". + +Specification changes in v0.1.0 (2015-06-01) +============================================ +- First numbered release. +- Restructure the format of Event information. Add more information. +- Restructure the format of the Client-Server HTTP APIs. \ No newline at end of file diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..f0da0267 --- /dev/null +++ b/README.rst @@ -0,0 +1,30 @@ +This repository contains the documentation for Matrix. + +Structure +========= + +- ``api`` : Contains the HTTP API specification. +- ``drafts`` : Contains documents which will make it into the specification + and/or supporting documentation at some point in the future. +- ``event-schemas`` : Contains the `JSON Schema`_ for all Matrix events + contained in the specification, along with example JSON files. +- ``meta`` : Contains documents outlining the processes involved when writing + documents, e.g. documentation style, guidelines. +- ``scripts`` : Contains scripts to generate formatted versions of the + documentation, typically HTML. +- ``specification`` : Contains the specification split up into sections. +- ``supporting-docs`` : Contains additional documents which explain design + decisions, examples, use cases, etc. +- ``templating`` : Contains the templates and templating system used to + generate the spec. + +Contributing +============ + +Known issues with the specification are represented as JIRA issues at +https://matrix.org/jira/browse/SPEC + +If you want to ask more about the specification, or have suggestions for +improvements, join us on ``#matrix-dev:matrix.org`` via https://matrix.org/beta. + +.. _JSON Schema: http://json-schema.org/ diff --git a/swagger/README b/api/README similarity index 100% rename from swagger/README rename to api/README diff --git a/api/check_examples.py b/api/check_examples.py new file mode 100755 index 00000000..ee3c773c --- /dev/null +++ b/api/check_examples.py @@ -0,0 +1,118 @@ +#! /usr/bin/env python + +import sys +import json +import os + + +def import_error(module, package, debian, error): + sys.stderr.write(( + "Error importing %(module)s: %(error)r\n" + "To install %(module)s run:\n" + " pip install %(package)s\n" + "or on Debian run:\n" + " sudo apt-get install python-%(debian)s\n" + ) % locals()) + if __name__ == '__main__': + sys.exit(1) + +try: + import jsonschema +except ImportError as e: + import_error("jsonschema", "jsonschema", "jsonschema", e) + raise + +try: + import yaml +except ImportError as e: + import_error("yaml", "PyYAML", "yaml", e) + raise + + +def check_parameter(filepath, request, parameter): + schema = parameter.get("schema") + example = None + try: + example_json = schema.get('example') + if example_json and not schema.get("format") == "byte": + example = json.loads(example_json) + except Exception as e: + raise ValueError("Error parsing JSON example request for %r" % ( + request + ), e) + fileurl = "file://" + os.path.abspath(filepath) + if example and schema: + try: + print ("Checking request schema for: %r %r" % ( + filepath, request + )) + # Setting the 'id' tells jsonschema where the file is so that it + # can correctly resolve relative $ref references in the schema + schema['id'] = fileurl + jsonschema.validate(example, schema) + except Exception as e: + raise ValueError("Error validating JSON schema for %r" % ( + request + ), e) + + +def check_response(filepath, request, code, response): + example = None + try: + example_json = response.get('examples', {}).get('application/json') + if example_json: + example = json.loads(example_json) + except Exception as e: + raise ValueError("Error parsing JSON example response for %r %r" % ( + request, code + ), e) + schema = response.get('schema') + fileurl = "file://" + os.path.abspath(filepath) + if example and schema: + try: + print ("Checking response schema for: %r %r %r" % ( + filepath, request, code + )) + # Setting the 'id' tells jsonschema where the file is so that it + # can correctly resolve relative $ref references in the schema + schema['id'] = fileurl + jsonschema.validate(example, schema) + except Exception as e: + raise ValueError("Error validating JSON schema for %r %r" % ( + request, code + ), e) + + +def check_swagger_file(filepath): + with open(filepath) as f: + swagger = yaml.load(f) + + for path, path_api in swagger.get('paths', {}).items(): + + for method, request_api in path_api.items(): + request = "%s %s" % (method.upper(), path) + for parameter in request_api.get('parameters', ()): + if parameter['in'] == 'body': + check_parameter(filepath, request, parameter) + + try: + responses = request_api['responses'] + except KeyError: + raise ValueError("No responses for %r" % (request,)) + for code, response in responses.items(): + check_response(filepath, request, code, response) + + +if __name__ == '__main__': + paths = sys.argv[1:] + if not paths: + paths = [] + for (root, dirs, files) in os.walk(os.curdir): + for filename in files: + if filename.endswith(".yaml"): + paths.append(os.path.join(root, filename)) + for path in paths: + try: + check_swagger_file(path) + except Exception as e: + raise ValueError("Error checking file %r" % (path,), e) diff --git a/swagger/client-server/api-docs b/api/client-server/api-docs similarity index 100% rename from swagger/client-server/api-docs rename to api/client-server/api-docs diff --git a/swagger/client-server/api-docs-content b/api/client-server/api-docs-content similarity index 100% rename from swagger/client-server/api-docs-content rename to api/client-server/api-docs-content diff --git a/swagger/client-server/api-docs-directory b/api/client-server/api-docs-directory similarity index 100% rename from swagger/client-server/api-docs-directory rename to api/client-server/api-docs-directory diff --git a/swagger/client-server/api-docs-events b/api/client-server/api-docs-events similarity index 100% rename from swagger/client-server/api-docs-events rename to api/client-server/api-docs-events diff --git a/swagger/client-server/api-docs-login b/api/client-server/api-docs-login similarity index 100% rename from swagger/client-server/api-docs-login rename to api/client-server/api-docs-login diff --git a/swagger/client-server/api-docs-presence b/api/client-server/api-docs-presence similarity index 100% rename from swagger/client-server/api-docs-presence rename to api/client-server/api-docs-presence diff --git a/swagger/client-server/api-docs-profile b/api/client-server/api-docs-profile similarity index 100% rename from swagger/client-server/api-docs-profile rename to api/client-server/api-docs-profile diff --git a/swagger/client-server/api-docs-registration b/api/client-server/api-docs-registration similarity index 100% rename from swagger/client-server/api-docs-registration rename to api/client-server/api-docs-registration diff --git a/swagger/client-server/api-docs-rooms b/api/client-server/api-docs-rooms similarity index 99% rename from swagger/client-server/api-docs-rooms rename to api/client-server/api-docs-rooms index 9a4ddbe8..0d3d9fbc 100644 --- a/swagger/client-server/api-docs-rooms +++ b/api/client-server/api-docs-rooms @@ -714,7 +714,7 @@ }, { "name": "body", - "description": "The typing information", + "description": "The typing information.", "required": true, "type": "Typing", "paramType": "body" diff --git a/api/client-server/v1/content-repo.yaml b/api/client-server/v1/content-repo.yaml new file mode 100644 index 00000000..8e6e8d1a --- /dev/null +++ b/api/client-server/v1/content-repo.yaml @@ -0,0 +1,127 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Content Repository API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https +basePath: /_matrix/media/v1 +produces: + - application/json + - "*/*" +paths: + "/upload": + post: + summary: Upload some content to the content repository. + produces: ["application/json"] + parameters: + - in: header + name: Content-Type + type: string + description: The content type of the file being uploaded + x-example: "Content-Type: audio/mpeg" + - in: body + name: "" + description: The content to be uploaded. + required: true + schema: + type: string + example: "" + format: byte + responses: + 200: + description: The MXC URI for the uploaded content. + schema: + type: object + required: ["content_uri"] + properties: + content_uri: + type: string + description: "The MXC URI to the uploaded content." + examples: + "application/json": |- + { + "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" + } + "/download/{serverName}/{mediaId}": + get: + summary: "Download content from the content repository." + produces: ["*/*"] + parameters: + - in: path + type: string + name: serverName + x-example: matrix.org + required: true + description: | + The server name from the ``mxc://`` URI (the authoritory component) + - in: path + type: string + name: mediaId + x-example: ascERGshawAWawugaAcauga + required: true + description: | + The media ID from the ``mxc://`` URI (the path component) + responses: + 200: + description: "The content that was previously uploaded." + headers: + Content-Type: + description: "The content type of the file that was previously uploaded." + type: "string" + Content-Disposition: + description: "The name of the file that was previously uploaded, if set." + type: "string" + schema: + type: file + "/thumbnail/{serverName}/{mediaId}": + get: + summary: "Download a thumbnail of the content from the content repository." + produces: ["image/jpeg", "image/png"] + parameters: + - in: path + type: string + name: serverName + required: true + x-example: matrix.org + description: | + The server name from the ``mxc://`` URI (the authoritory component) + - in: path + type: string + name: mediaId + x-example: ascERGshawAWawugaAcauga + required: true + description: | + The media ID from the ``mxc://`` URI (the path component) + - in: query + type: integer + x-example: 64 + name: width + description: |- + The *desired* width of the thumbnail. The actual thumbnail may not + match the size specified. + - in: query + type: integer + x-example: 64 + name: height + description: |- + The *desired* height of the thumbnail. The actual thumbnail may not + match the size specified. + - in: query + type: string + enum: ["crop", "scale"] + name: method + x-example: "scale" + description: The desired resizing method. + responses: + 200: + description: "A thumbnail of the requested content." + headers: + Content-Type: + description: "The content type of the thumbnail." + type: "string" + enum: ["image/jpeg", "image/png"] + schema: + type: file + + diff --git a/api/client-server/v1/core-event-schema b/api/client-server/v1/core-event-schema new file mode 120000 index 00000000..045aecb0 --- /dev/null +++ b/api/client-server/v1/core-event-schema @@ -0,0 +1 @@ +v1-event-schema/core-event-schema \ No newline at end of file diff --git a/api/client-server/v1/definitions/error.yaml b/api/client-server/v1/definitions/error.yaml new file mode 100644 index 00000000..20312ae4 --- /dev/null +++ b/api/client-server/v1/definitions/error.yaml @@ -0,0 +1,10 @@ +type: object +description: A Matrix-level Error +properties: + errcode: + type: string + description: An error code. + error: + type: string + description: A human-readable error message. +required: ["errcode"] \ No newline at end of file diff --git a/api/client-server/v1/definitions/push_condition.json b/api/client-server/v1/definitions/push_condition.json new file mode 100644 index 00000000..1d84955c --- /dev/null +++ b/api/client-server/v1/definitions/push_condition.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": ["event_match", "profile_tag", "contains_display_name", "room_member_count"] + } + } +} \ No newline at end of file diff --git a/api/client-server/v1/definitions/push_rule.json b/api/client-server/v1/definitions/push_rule.json new file mode 100644 index 00000000..4df93f67 --- /dev/null +++ b/api/client-server/v1/definitions/push_rule.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "properties": { + "default": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "rule_id": { + "type": "string" + }, + "actions": { + "items": { + "type": ["object", "string"] + }, + "type": "array" + } + } +} \ No newline at end of file diff --git a/api/client-server/v1/definitions/push_ruleset.json b/api/client-server/v1/definitions/push_ruleset.json new file mode 100644 index 00000000..e0372701 --- /dev/null +++ b/api/client-server/v1/definitions/push_ruleset.json @@ -0,0 +1,60 @@ +{ + "type": "object", + "properties": { + "content": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "override": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "sender": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "underride": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "room": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + } + } +} \ No newline at end of file diff --git a/api/client-server/v1/directory.yaml b/api/client-server/v1/directory.yaml new file mode 100644 index 00000000..c70b9f6b --- /dev/null +++ b/api/client-server/v1/directory.yaml @@ -0,0 +1,87 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Directory API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1/directory +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/room/{roomAlias}": + put: + summary: Create a new mapping from room alias to room ID. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomAlias + description: The room alias to set. + required: true + - in: body + name: roomInfo + description: Information about this room alias. + required: true + schema: + type: object + properties: + room_id: + type: string + description: The room ID to set. + responses: + 200: + description: The mapping was created. + schema: + type: object # empty json object + get: + summary: Get the room ID corresponding to this room alias. + parameters: + - in: path + type: string + name: roomAlias + description: The room alias. + required: true + responses: + 200: + description: The room ID and other information for this alias. + schema: + type: object + properties: + room_id: + type: string + description: The room ID for this room alias. + servers: + type: array + description: A list of servers that are aware of this room ID. + items: + type: string + description: A server which is aware of this room ID. + 404: + description: There is no mapped room ID for this room alias. + delete: + summary: Remove a mapping of room alias to room ID. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomAlias + description: The room alias to remove. + required: true + responses: + 200: + description: The mapping was removed. + schema: + type: object # empty json object + diff --git a/api/client-server/v1/login.yaml b/api/client-server/v1/login.yaml new file mode 100644 index 00000000..3d415c29 --- /dev/null +++ b/api/client-server/v1/login.yaml @@ -0,0 +1,147 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Registration and Login API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/login": + post: + summary: Authenticates the user. + description: |- + Authenticates the user by password, and issues an access token they can + use to authorize themself in subsequent requests. + security: + - accessToken: [] + parameters: + - in: body + name: body + schema: + type: object + example: |- + { + "username": "cheeky_monkey", + "password": "ilovebananas" + } + properties: + username: + type: string + description: The fully qualified user ID or just local part of the user ID, to log in. + password: + type: string + description: The user's password. + required: ["username", "password"] + responses: + 200: + description: The user has been authenticated. + examples: + application/json: |- + { + "user_id": "@cheeky_monkey:matrix.org", + "access_token": "abc123", + "home_server": "matrix.org" + } + schema: + type: object + properties: + user_id: + type: string + description: The fully-qualified Matrix ID that has been registered. + access_token: + type: string + description: |- + An access token for the account. + This access token can then be used to authorize other requests. + The access token may expire at some point, and if so, it SHOULD come with a ``refresh_token``. + There is no specific error message to indicate that a request has failed because + an access token has expired; instead, if a client has reason to believe its + access token is valid, and it receives an auth error, they should attempt to + refresh for a new token on failure, and retry the request with the new token. + refresh_token: + type: string + # TODO: Work out how to linkify /tokenrefresh + description: |- + (optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the /tokenrefresh API endpoint. + home_server: + type: string + description: The hostname of the Home Server on which the account has been registered. + 403: + description: |- + The login attempt failed. For example, the password may have been incorrect. + examples: + application/json: |- + {"errcode": "M_FORBIDDEN"} + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + "/tokenrefresh": + post: + summary: Exchanges a refresh token for an access token. + description: |- + Exchanges a refresh token for a new access token. + This is intended to be used if the access token has expired. + security: + - accessToken: [] + parameters: + - in: body + name: body + schema: + type: object + example: |- + { + "refresh_token": "a1b2c3" + } + properties: + refresh_token: + type: string + description: The refresh token which was issued by the server. + required: ["refresh_token"] + responses: + 200: + description: |- + The refresh token was accepted, and a new access token has been issued. + The passed refresh token is no longer valid and cannot be used. + A new refresh token will have been returned unless some policy does + not allow the user to continue to renew their session. + examples: + application/json: |- + { + "access_token": "bearwithme123", + "refresh_token": "exchangewithme987" + } + schema: + type: object + properties: + access_token: + type: string + description: |- + An access token for the account. + This access token can then be used to authorize other requests. + The access token may expire at some point, and if so, it SHOULD come with a ``refresh_token``. + refresh_token: + type: string + description: (optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the TODO Linkify /tokenrefresh API endpoint. + 403: + description: |- + The exchange attempt failed. For example, the refresh token may have already been used. + examples: + application/json: |- + {"errcode": "M_FORBIDDEN"} + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" diff --git a/api/client-server/v1/membership.yaml b/api/client-server/v1/membership.yaml new file mode 100644 index 00000000..efc82578 --- /dev/null +++ b/api/client-server/v1/membership.yaml @@ -0,0 +1,234 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Room Membership API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/rooms/{roomId}/join": + post: + summary: Start the requesting user participating in a particular room. + description: |- + This API starts a user participating in a particular room, if that user + is allowed to participate in that room. After this call, the client is + allowed to see all current state events in the room, and all subsequent + events associated with the room until the user leaves the room. + + After a user has joined a room, the room will appear as an entry in the + response of the |initialSync| API. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room identifier or room alias to join. + required: true + x-example: "#monkeys:matrix.org" + responses: + 200: + description: |- + The room has been joined. + + The joined room ID must be returned in the ``room_id`` field. + examples: + application/json: |- + {"room_id": "!d41d8cd:matrix.org"} + schema: + type: object + 403: + description: |- + You do not have permission to join the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejection are: + - The room is invite-only and the user was not invited. + - The user has been banned from the room. + examples: + application/json: |- + {"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."} + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + x-alias: + canonical-link: "post-matrix-client-api-v1-rooms-roomid-join" + aliases: + - /join/{roomId} + + # With an extra " " to disambiguate from the 3pid invite endpoint + # The extra space makes it sort first for what I'm sure is a good reason. + "/rooms/{roomId}/invite ": + post: + summary: Invite a user to participate in a particular room. + description: |- + *Note that there are two forms of this API, which are documented separately. + This version of the API requires that the inviter knows the Matrix + identifier of the invitee.* + + This API invites a user to participate in a particular room. + They do not start participating in the room until they actually join the + room. + + Only users currently in a particular room can invite other users to + join that room. + + If the user was invited to the room, the home server will append a + ``m.room.member`` event to the room. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room identifier (not alias) to which to invite the user. + required: true + x-example: "!d41d8cd:matrix.org" + - in: body + name: body + required: true + schema: + type: object + example: |- + { + "user_id": "@cheeky_monkey:matrix.org" + } + properties: + user_id: + type: string + description: The fully qualified user ID of the invitee. + required: ["user_id"] + responses: + 200: + description: The user has been invited to join the room. + examples: + application/json: |- + {} + schema: + type: object + 403: + description: |- + You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are: + - The invitee has been banned from the room. + - The invitee is already a member of the room. + - The inviter is not currently in the room. + - The inviter's power level is insufficient to invite users to the room. + examples: + application/json: |- + {"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"} + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + + "/rooms/{roomId}/invite": + post: + summary: Invite a user to participate in a particular room. + description: |- + *Note that there are two forms of this API, which are documented separately. + This version of the API does not require that the inviter know the Matrix + identifier of the invitee, and instead relies on third party identifiers. + The homeserver uses an identity server to perform the mapping from + third party identifier to a Matrix identifier.* + + This API invites a user to participate in a particular room. + They do not start participating in the room until they actually join the + room. + + Only users currently in a particular room can invite other users to + join that room. + + If the identity server did know the Matrix user identifier for the + third party identifier, the home server will append a ``m.room.member`` + event to the room. + + If the identity server does not know a Matrix user identifier for the + passed third party identifier, the homeserver will issue an invitation + which can be accepted upon providing proof of ownership of the third + party identifier. This is achieved by the identity server generating a + token, which it gives to the inviting homeserver. The homeserver will + add an ``m.room.third_party_invite`` event into the graph for the room, + containing that token. + + When the invitee binds the invited third party identifier to a Matrix + user ID, the identity server will give the user a list of pending + invitations, each containing: + + - The room ID to which they were invited + + - The token given to the homeserver + + - A signature of the token, signed with the identity server's private key + + - The matrix user ID who invited them to the room + + If a token is requested from the identity server, the home server will + append a ``m.room.third_party_invite`` event to the room. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room identifier (not alias) to which to invite the user. + required: true + x-example: "!d41d8cd:matrix.org" + - in: body + name: body + required: true + schema: + type: object + example: |- + { + "id_server": "matrix.org", + "medium": "email", + "address": "cheeky@monkey.com", + "display_name": "A very cheeky monkey" + } + properties: + id_server: + type: string + description: The hostname+port of the identity server which should be used for third party identifier lookups. + medium: + type: string + # TODO: Link to identity service spec when it eixsts + description: The kind of address being passed in the address field, for example ``email``. + address: + type: string + description: The invitee's third party identifier. + display_name: + type: string + description: A user-friendly string describing who has been invited. It should not contain the address of the invitee, to avoid leaking mappings between third party identities and matrix user IDs. + required: ["id_server", "medium", "address", "display_name"] + responses: + 200: + description: The user has been invited to join the room. + examples: + application/json: |- + {} + schema: + type: object + 403: + description: |- + You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are: + - The invitee has been banned from the room. + - The invitee is already a member of the room. + - The inviter is not currently in the room. + - The inviter's power level is insufficient to invite users to the room. + examples: + application/json: |- + {"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"} + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" diff --git a/api/client-server/v1/presence.yaml b/api/client-server/v1/presence.yaml new file mode 100644 index 00000000..5684398b --- /dev/null +++ b/api/client-server/v1/presence.yaml @@ -0,0 +1,208 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Presence API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/presence/{userId}/status": + put: + summary: Update this user's presence state. + description: |- + This API sets the given user's presence state. When setting the status, + the activity time is updated to reflect that activity; the client does + not need to specify the ``last_active_ago`` field. You cannot set the + presence state of another user. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: userId + description: The user whose presence state to update. + required: true + x-example: "@alice:example.com" + - in: body + name: presenceState + description: The updated presence state. + required: true + schema: + type: object + example: |- + { + "presence": "online", + "status_msg": "I am here." + } + properties: + presence: + type: string + enum: ["online", "offline", "unavailable", "free_for_chat"] + description: The new presence state. + status_msg: + type: string + description: "The status message to attach to this state." + required: ["presence"] + responses: + 200: + description: The new presence state was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + get: + summary: Get this user's presence state. + description: |- + Get the given user's presence state. + parameters: + - in: path + type: string + name: userId + description: The user whose presence state to get. + required: true + x-example: "@alice:example.com" + responses: + 200: + description: The presence state for this user. + examples: + application/json: |- + { + "presence": "unavailable", + "last_active_ago": 420845, + "status_msg": null + } + schema: + type: object + properties: + presence: + type: string + enum: ["online", "offline", "unavailable", "free_for_chat"] + description: This user's presence. + last_active_ago: + type: integer + description: |- + The length of time in milliseconds since an action was performed + by this user. + status_msg: + type: [string, "null"] + description: The state message for this user if one was set. + 404: + description: |- + There is no presence state for this user. This user may not exist or + isn't exposing presence information to you. + "/presence/list/{userId}": + post: + summary: Add or remove users from this presence list. + description: |- + Adds or removes users from this presence list. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: userId + description: The user whose presence list is being modified. + required: true + x-example: "@alice:example.com" + - in: body + name: presence_diff + description: The modifications to make to this presence list. + required: true + schema: + type: object + example: |- + { + "invite": [ + "@bob:matrix.org" + ], + "drop": [ + "@alice:matrix.org" + ] + } + properties: + invite: + type: array + description: A list of user IDs to add to the list. + items: + type: string + description: A list of user IDs. + drop: + type: array + description: A list of user IDs to remove from the list. + items: + type: string + description: A list of user IDs. + responses: + 200: + description: The list was updated. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + get: + summary: Get presence events for this presence list. + description: |- + Retrieve a list of presence events for every user on this list. + parameters: + - in: path + type: string + name: userId + description: The user whose presence list should be retrieved. + required: true + x-example: "@alice:example.com" + responses: + 200: + description: A list of presence events for this list. + examples: + application/json: |- + [ + { + "content": { + "avatar_url": "mxc://matrix.org/AfwefuigfWEfhuiPP", + "displayname": "Alice Margatroid", + "last_active_ago": 395, + "presence": "offline", + "user_id": "@alice:matrix.org" + }, + "type": "m.presence" + }, + { + "content": { + "avatar_url": "mxc://matrix.org/FWEhuiwegfWEfhuiwf", + "displayname": "Marisa Kirisame", + "last_active_ago": 16874, + "presence": "online", + "user_id": "@marisa:matrix.org" + }, + "type": "m.presence" + } + ] + schema: + type: array + items: + type: object + title: PresenceEvent + allOf: + - "$ref": "core-event-schema/event.json" diff --git a/api/client-server/v1/profile.yaml b/api/client-server/v1/profile.yaml new file mode 100644 index 00000000..e19466bf --- /dev/null +++ b/api/client-server/v1/profile.yaml @@ -0,0 +1,195 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Profile API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/profile/{userId}/displayname": + put: + summary: Set the user's display name. + description: |- + This API sets the given user's display name. You must have permission to + set this user's display name, e.g. you need to have their ``access_token``. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: userId + description: The user whose display name to set. + required: true + x-example: "@alice:example.com" + - in: body + name: displayName + description: The display name info. + required: true + schema: + type: object + example: |- + { + "displayname": "Alice Margatroid" + } + properties: + displayname: + type: string + description: The new display name for this user. + responses: + 200: + description: The display name was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + get: + summary: Get the user's display name. + description: |- + Get the user's display name. This API may be used to fetch the user's + own displayname or to query the name of other users; either locally or + on remote homeservers. + parameters: + - in: path + type: string + name: userId + description: The user whose display name to get. + required: true + x-example: "@alice:example.com" + responses: + 200: + description: The display name for this user. + examples: + application/json: |- + { + "displayname": "Alice Margatroid" + } + schema: + type: object + properties: + displayname: + type: string + description: The user's display name if they have set one. + 404: + description: There is no display name for this user or this user does not exist. + "/profile/{userId}/avatar_url": + put: + summary: Set the user's avatar URL. + description: |- + This API sets the given user's avatar URL. You must have permission to + set this user's avatar URL, e.g. you need to have their ``access_token``. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: userId + description: The user whose avatar URL to set. + required: true + x-example: "@alice:example.com" + - in: body + name: avatar_url + description: The avatar url info. + required: true + schema: + type: object + example: |- + { + "avatar_url": "mxc://matrix.org/wefh34uihSDRGhw34" + } + properties: + avatar_url: + type: string + description: The new avatar URL for this user. + responses: + 200: + description: The avatar URL was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + get: + summary: Get the user's avatar URL. + description: |- + Get the user's avatar URL. This API may be used to fetch the user's + own avatar URL or to query the URL of other users; either locally or + on remote homeservers. + parameters: + - in: path + type: string + name: userId + description: The user whose avatar URL to get. + required: true + x-example: "@alice:example.com" + responses: + 200: + description: The avatar URL for this user. + examples: + application/json: |- + { + "avatar_url": "mxc://matrix.org/SDGdghriugerRg" + } + schema: + type: object + properties: + avatar_url: + type: string + description: The user's avatar URL if they have set one. + 404: + description: There is no avatar URL for this user or this user does not exist. + "/profile/{userId}": + get: + summary: Get this user's profile information. + description: |- + Get the combined profile information for this user. This API may be used + to fetch the user's own profile information or other users; either + locally or on remote homeservers. This API may return keys which are not + limited to ``displayname`` or ``avatar_url``. + parameters: + - in: path + type: string + name: userId + description: The user whose avatar URL to get. + required: true + x-example: "@alice:example.com" + responses: + 200: + description: The avatar URL for this user. + examples: + application/json: |- + { + "avatar_url": "mxc://matrix.org/SDGdghriugerRg", + "displayname": "Alice Margatroid" + } + schema: + type: object + properties: + avatar_url: + type: string + description: The user's avatar URL if they have set one. + displayname: + type: string + description: The user's display name if they have set one. + 404: + description: There is no profile information for this user or this user does not exist. \ No newline at end of file diff --git a/api/client-server/v1/push_notifier.yaml b/api/client-server/v1/push_notifier.yaml new file mode 100644 index 00000000..be3b5f74 --- /dev/null +++ b/api/client-server/v1/push_notifier.yaml @@ -0,0 +1,192 @@ +swagger: '2.0' +info: + title: "Matrix Push Notification API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/push/v1 +consumes: + - application/json +produces: + - application/json +paths: + "/notify": + post: + summary: Notify a push gateway about an event. + description: |- + This endpoint is invoked by HTTP pushers to notify a push gateway about + an event. + *NB: Notifications are sent to the URL configured when the pusher is + created. This means that the HTTP path may be different depending on the + push gateway.* + parameters: + - in: body + name: notification + description: Information about the push notification. + required: true + schema: + type: object + example: |- + { + "notification": { + "id": "$3957tyerfgewrf384", + "room_id": "!slw48wfj34rtnrf:example.com", + "type": "m.room.message", + "sender": "@exampleuser:matrix.org", + "sender_display_name": "Major Tom", + "room_name": "Mission Control", + "room_alias": "#exampleroom:matrix.org", + "prio": "high", + "content": { + "msgtype": "m.text", + "body": "I'm floating in a most peculiar way." + } + }, + "counts": { + "unread" : 2, + "missed_calls": 1 + }, + "devices": [ + { + "app_id": "org.matrix.matrixConsole.ios", + "pushkey": "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/", + "pushkey_ts": 12345678, + "data" : {}, + "tweaks": { + "sound": "bing" + } + } + ] + } + required: ["notification", "counts", "devices"] + properties: + notification: + type: object + description: Information about the push notification + required: ["id", "room_id", "type", "sender"] + properties: + id: + type: string + description: |- + An identifier for this notification that may be used to + detect duplicate notification requests. This is not + necessarily the ID of the event that triggered the + notification. + room_id: + type: string + description: The ID of the room in which this event occurred. + type: + type: string + description: The type of the event as in the event's ``type`` field. + sender: + type: string + description: The sender of the event as in the corresponding event field. + sender_display_name: + type: string + description: |- + The current display name of the sender in the room in which + the event occurred. + room_name: + type: string + description: The name of the room in which the event occurred. + room_alias: + type: string + description: An alias to display for the room in which the event occurred. + user_is_target: + type: boolean + description: |- + This is true if the user receiving the notification is the + subject of a member event (i.e. the ``state_key`` of the + member event is equal to the user's Matrix ID). + prio: + type: string + enum: ["high", "low"] + description: |- + The priority of the notification. If omitted, ``high`` is + assumed. This may be used by push gateways to deliver less + time-sensitive notifications in a way that will preserve + battery power on mobile devices. + content: + type: object + title: EventContent + description: |- + The ``content`` field from the event, if present. If the + event had no content field, this field is omitted. + counts: + type: object + description: |- + This is a dictionary of the current number of unacknowledged + communications for the recipient user. Counts whose value is + zero are omitted. + properties: + unread: + type: integer + description: |- + The number of unread messages a user has across all of the + rooms they are a member of. + missed_calls: + type: integer + description: |- + The number of unacknowledged missed calls a user has + across all rooms of which they are a member. + devices: + type: array + title: Devices + description: |- + This is an array of devices that the notification should be sent to. + items: + type: object + properties: + app_id: + type: string + description: |- + The app_id given when the pusher was created. + pushkey: + type: string + description: The pushkey given when the pusher was created. + pushkey_ts: + type: integer + description: |- + The unix timestamp (in seconds) when the + pushkey was last updated. + data: + type: object + title: PusherData + description: |- + A dictionary of additional pusher-specific data. For + 'http' pushers, this is the data dictionary passed in at + pusher creation minus the ``url`` key. + tweaks: + type: object + title: Tweaks + description: |- + A dictionary of customisations made to the way this + notification is to be presented. These are added by push rules. + responses: + 200: + description: A list of rejected push keys. + examples: + application/json: |- + { + "rejected": [ "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/" ] + } + schema: + type: object # empty json object + properties: + rejected: + type: array + description: |- + A list of all pushkeys given in the notification request that + are not valid. These could have been rejected by an upstream + gateway because they have expired or have never been valid. + Homeservers must cease sending notification requests for these + pushkeys and remove the associated pushers. It may not + necessarily be the notification in the request that failed: + it could be that a previous notification to the same pushkey + failed. + items: + type: string + description: A pushkey + diff --git a/api/client-server/v1/pusher.yaml b/api/client-server/v1/pusher.yaml new file mode 100644 index 00000000..8c243f2b --- /dev/null +++ b/api/client-server/v1/pusher.yaml @@ -0,0 +1,144 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Push API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/pushers/set": + post: + summary: Modify a pusher for this user on the homeserver. + description: |- + This endpoint allows the creation, modification and deletion of `pushers`_ + for this user ID. The behaviour of this endpoint varies depending on the + values in the JSON body. + security: + - accessToken: [] + parameters: + - in: body + name: pusher + description: The pusher information + required: true + schema: + type: object + example: |- + { + "lang": "en", + "kind": "http", + "app_display_name": "Mat Rix", + "device_display_name": "iPhone 9", + "app_id": "com.example.app.ios", + "profile_tag": "4bea66906d0111e59d70feff819cdc9f", + "pushkey": "APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ", + "data": { + "url": "https://push-gateway.location.here" + }, + "append": false + } + properties: + pushkey: + type: string + description: |- + This is a unique identifier for this pusher. The value you + should use for this is the routing or destination address + information for the notification, for example, the APNS token + for APNS or the Registration ID for GCM. If your notification + client has no such concept, use any unique identifier. + Max length, 512 bytes. + kind: + type: string + enum: ["http", null] + description: |- + The kind of pusher to configure. ``"http"`` makes a pusher that + sends HTTP pokes. ``null`` deletes the pusher. + profile_tag: + type: string + description: |- + This is a string that determines what set of device rules will + be matched when evaluating push rules for this pusher. It is + an arbitrary string. Multiple devices may use the same + ``profile_tag``. It is advised that when an app's data is + copied or restored to a different device, this value remain + the same. Client apps should offer ways to change the + ``profile_tag``, optionally copying rules from the old + profile tag. Max length, 32 bytes. + app_id: + type: string + description: |- + This is a reverse-DNS style identifier for the application. + It is recommended that this end with the platform, such that + different platform versions get different app identifiers. + Max length, 64 chars. + app_display_name: + type: string + description: |- + A string that will allow the user to identify what application + owns this pusher. + device_display_name: + type: string + description: |- + A string that will allow the user to identify what device owns + this pusher. + lang: + type: string + description: |- + The preferred language for receiving notifications (e.g. 'en' + or 'en-US') + data: + type: object + description: |- + A dictionary of information for the pusher implementation + itself. If ``kind`` is ``http``, this should contain ``url`` + which is the URL to use to send notifications to. + properties: + url: + type: string + description: |- + Required if ``kind`` is ``http``. The URL to use to send + notifications to. + append: + type: boolean + description: |- + If true, the homeserver should add another pusher with the + given pushkey and App ID in addition to any others with + different user IDs. Otherwise, the Home Server must remove any + other pushers with the same App ID and pushkey for different + users. The default is ``false``. + required: ['profile_tag', 'kind', 'app_id', 'app_display_name', + 'device_display_name', 'pushkey', 'lang', 'data'] + responses: + 200: + description: The pusher was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 400: + description: One or more of the pusher values were invalid. + examples: + application/json: |- + { + "error": "Missing parameters: lang, data", + "errcode": "M_MISSING_PARAM" + } + schema: + type: object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + diff --git a/api/client-server/v1/pushrules.yaml b/api/client-server/v1/pushrules.yaml new file mode 100644 index 00000000..31e84f55 --- /dev/null +++ b/api/client-server/v1/pushrules.yaml @@ -0,0 +1,488 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Push Rules API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/pushrules/": + get: + summary: Retrieve all push rulesets. + description: |- + Retrieve all push rulesets for this user. Clients can "drill-down" on + the rulesets by suffixing a ``scope`` to this path e.g. + ``/pushrules/global/``. This will return a subset of this data under the + specified key e.g. the ``global`` key. + security: + - accessToken: [] + responses: + 200: + description: All the push rulesets for this user. + schema: + type: object + required: ["device", "global"] + properties: + device: + type: object + title: Devices + description: A dictionary of profile tags to rulesets. + additionalProperties: + x-pattern: "$PROFILE_TAG" + type: object + description: The ruleset for this profile tag. + title: Ruleset + allOf: [ + "$ref": "definitions/push_ruleset.json" + ] + global: + type: object + description: The global ruleset. + title: Ruleset + allOf: [ + "$ref": "definitions/push_ruleset.json" + ] + examples: + application/json: |- + { + "device": {}, + "global": { + "content": [ + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ], + "default": true, + "enabled": true, + "pattern": "alice", + "rule_id": ".m.rule.contains_user_name" + } + ], + "override": [ + { + "actions": [ + "dont_notify" + ], + "conditions": [], + "default": true, + "enabled": false, + "rule_id": ".m.rule.master" + }, + { + "actions": [ + "dont_notify" + ], + "conditions": [ + { + "key": "content.msgtype", + "kind": "event_match", + "pattern": "m.notice" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.suppress_notices" + } + ], + "room": [], + "sender": [], + "underride": [ + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "ring" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.call.invite" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.call" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ], + "conditions": [ + { + "kind": "contains_display_name" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.contains_display_name" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "is": "2", + "kind": "room_member_count" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.room_one_to_one" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + }, + { + "key": "content.membership", + "kind": "event_match", + "pattern": "invite" + }, + { + "key": "state_key", + "kind": "event_match", + "pattern": "@alice:example.com" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.invite_for_me" + }, + { + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.member_event" + }, + { + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.message" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.message" + } + ] + } + } + "/pushrules/{scope}/{kind}/{ruleId}": + get: + summary: Retrieve a push rule. + description: |- + Retrieve a single specified push rule. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + responses: + 200: + description: |- + The specific push rule. This will also include keys specific to the + rule itself such as the rule's ``actions`` and ``conditions`` if set. + examples: + application/json: |- + { + "actions": [ + "dont_notify" + ], + "rule_id": "#spam:matrix.org", + "enabled": true + } + schema: + type: object + description: The push rule. + title: PushRule + allOf: [ + "$ref": "definitions/push_rule.json" + ] + delete: + summary: Delete a push rule. + description: |- + This endpoint removes the push rule defined in the path. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + responses: + 200: + description: The push rule was deleted. + examples: + application/json: |- + {} + schema: + type: object # empty json object + put: + summary: Add or change a push rule. + description: |- + This endpoint allows the creation, modification and deletion of pushers + for this user ID. The behaviour of this endpoint varies depending on the + values in the JSON body. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + - in: query + type: string + name: before + required: false + x-example: someRuleId + description: |- + Use 'before' with a ``rule_id`` as its value to make the new rule the + next-most important rule with respect to the given rule. + - in: query + type: string + name: after + required: false + x-example: anotherRuleId + description: |- + This makes the new rule the next-less important rule relative to the + given rule. + - in: body + name: pushrule + description: |- + The push rule data. Additional top-level keys may be present depending + on the parameters for the rule ``kind``. + required: true + schema: + type: object + example: |- + { + "pattern": "cake*lie", + "actions": ["notify"] + } + properties: + actions: + type: array + description: |- + The action(s) to perform when the conditions for this rule are met. + items: + type: string + enum: ["notify", "dont_notify", "coalesce", "set_tweak"] + # TODO: type: object e.g. {"set_sound":"beeroclock.wav"} :/ + conditions: + type: array + description: |- + The conditions that must hold true for an event in order for a + rule to be applied to an event. A rule with no conditions + always matches. + items: + type: object + title: conditions + allOf: [ "$ref": "definitions/push_condition.json" ] + required: ["actions"] + responses: + 200: + description: The pusher was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 400: + description: There was a problem configuring this push rule. + examples: + application/json: |- + { + "error": "before/after rule not found: someRuleId", + "errcode": "M_UNKNOWN" + } + schema: + type: object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + "/pushrules/{scope}/{kind}/{ruleId}/enabled": + put: + summary: "Enable or disable a push rule." + description: |- + This endpoint allows clients to enable or disable the specified push rule. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + - in: body + name: + description: | + Whether the push rule is enabled or not. + required: true + schema: + type: boolean + example: |- + true + responses: + 200: + description: The push rule was enabled or disabled. + examples: + application/json: |- + {} + schema: + type: object # empty json object diff --git a/api/client-server/v1/rooms.yaml b/api/client-server/v1/rooms.yaml new file mode 100644 index 00000000..9300d7d1 --- /dev/null +++ b/api/client-server/v1/rooms.yaml @@ -0,0 +1,448 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Rooms API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/rooms/{roomId}/state/{eventType}/{stateKey}": + get: + summary: Get the state identified by the type and key. + description: |- + Looks up the contents of a state event in a room. If the user is + joined to the room then the state is taken from the current + state of the room. If the user has left the room then the state is + taken from the state of the room when they left. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room to look up the state in. + required: true + x-example: "!636q39766251:example.com" + - in: path + type: string + name: eventType + description: The type of state to look up. + required: true + x-example: "m.room.name" + - in: path + type: string + name: stateKey + description: The key of the state to look up. Defaults to the empty string. + required: true + x-example: "" + responses: + 200: + description: The content of the state event. + examples: + application/json: |- + {"name": "Example room name"} + schema: + type: object + 404: + description: The room has no state with the given type or key. + 403: + description: > + You aren't a member of the room and weren't previously a + member of the room. + + "/rooms/{roomId}/state": + get: + summary: Get all state events in the current state of a room. + description: |- + Get the state events for the current state of a room. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room to look up the state for. + required: true + x-example: "!636q39766251:example.com" + responses: + 200: + description: The current state of the room + examples: + application/json: |- + [ + { + "age": 7148266897, + "content": { + "join_rule": "public" + }, + "event_id": "$14259997323TLwtb:example.com", + "origin_server_ts": 1425999732392, + "room_id": "!636q39766251:example.com", + "state_key": "", + "type": "m.room.join_rules", + "user_id": "@alice:example.com" + }, + { + "age": 6547561012, + "content": { + "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", + "displayname": null, + "membership": "join" + }, + "event_id": "$1426600438280zExKY:example.com", + "membership": "join", + "origin_server_ts": 1426600438277, + "room_id": "!636q39766251:example.com", + "state_key": "@alice:example.com", + "type": "m.room.member", + "user_id": "@alice:example.com" + }, + { + "age": 7148267200, + "content": { + "creator": "@alice:example.com" + }, + "event_id": "$14259997320KhbwJ:example.com", + "origin_server_ts": 1425999732089, + "room_id": "!636q39766251:example.com", + "state_key": "", + "type": "m.room.create", + "user_id": "@alice:example.com" + }, + { + "age": 1622568720, + "content": { + "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", + "displayname": "Bob", + "membership": "join" + }, + "event_id": "$1431525430134MxlLX:example.com", + "origin_server_ts": 1431525430569, + "replaces_state": "$142652023736BSXcM:example.com", + "room_id": "!636q39766251:example.com", + "state_key": "@bob:example.com", + "type": "m.room.member", + "user_id": "@bob:example.com" + }, + { + "age": 7148267004, + "content": { + "ban": 50, + "events": { + "m.room.name": 100, + "m.room.power_levels": 100 + }, + "events_default": 0, + "kick": 50, + "redact": 50, + "state_default": 50, + "users": { + "@alice:example.com": 100 + }, + "users_default": 0 + }, + "event_id": "$14259997322mqfaq:example.com", + "origin_server_ts": 1425999732285, + "room_id": "!636q39766251:example.com", + "state_key": "", + "type": "m.room.power_levels", + "user_id": "@alice:example.com" + } + ] + schema: + type: array + title: RoomState + description: |- + If the user is a member of the room this will be the + current state of the room as a list of events. If the user + has left the room then this will be the state of the room + when they left as a list of events. + items: + title: StateEvent + type: object + allOf: + - "$ref": "core-event-schema/state_event.json" + 403: + description: > + You aren't a member of the room and weren't previously a + member of the room. + + "/rooms/{roomId}/initialSync": + get: + summary: Snapshot the current state of a room and its most recent messages. + description: |- + Get a copy of the current state and the most recent messages in a room. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room to get the data. + required: true + x-example: "!636q39766251:example.com" + responses: + 200: + description: The current state of the room + examples: + application/json: |- + { + "membership": "join", + "messages": { + "chunk": [ + { + "age": 343513403, + "content": { + "body": "foo", + "msgtype": "m.text" + }, + "event_id": "$14328044851tzTJS:example.com", + "origin_server_ts": 1432804485886, + "room_id": "!636q39766251:example.com", + "type": "m.room.message", + "user_id": "@alice:example.com" + }, + { + "age": 343511809, + "content": { + "body": "bar", + "msgtype": "m.text" + }, + "event_id": "$14328044872spjFg:example.com", + "origin_server_ts": 1432804487480, + "room_id": "!636q39766251:example.com", + "type": "m.room.message", + "user_id": "@bob:example.com" + } + ], + "end": "s3456_9_0", + "start": "t44-3453_9_0" + }, + "room_id": "!636q39766251:example.com", + "state": [ + { + "age": 7148266897, + "content": { + "join_rule": "public" + }, + "event_id": "$14259997323TLwtb:example.com", + "origin_server_ts": 1425999732392, + "room_id": "!636q39766251:example.com", + "state_key": "", + "type": "m.room.join_rules", + "user_id": "@alice:example.com" + }, + { + "age": 6547561012, + "content": { + "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", + "displayname": null, + "membership": "join" + }, + "event_id": "$1426600438280zExKY:example.com", + "membership": "join", + "origin_server_ts": 1426600438277, + "room_id": "!636q39766251:example.com", + "state_key": "@alice:example.com", + "type": "m.room.member", + "user_id": "@alice:example.com" + }, + { + "age": 7148267200, + "content": { + "creator": "@alice:example.com" + }, + "event_id": "$14259997320KhbwJ:example.com", + "origin_server_ts": 1425999732089, + "room_id": "!636q39766251:example.com", + "state_key": "", + "type": "m.room.create", + "user_id": "@alice:example.com" + }, + { + "age": 1622568720, + "content": { + "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", + "displayname": "Bob", + "membership": "join" + }, + "event_id": "$1431525430134MxlLX:example.com", + "origin_server_ts": 1431525430569, + "replaces_state": "$142652023736BSXcM:example.com", + "room_id": "!636q39766251:example.com", + "state_key": "@bob:example.com", + "type": "m.room.member", + "user_id": "@bob:example.com" + }, + { + "age": 7148267004, + "content": { + "ban": 50, + "events": { + "m.room.name": 100, + "m.room.power_levels": 100 + }, + "events_default": 0, + "kick": 50, + "redact": 50, + "state_default": 50, + "users": { + "@alice:example.com": 100 + }, + "users_default": 0 + }, + "event_id": "$14259997322mqfaq:example.com", + "origin_server_ts": 1425999732285, + "room_id": "!636q39766251:example.com", + "state_key": "", + "type": "m.room.power_levels", + "user_id": "@alice:example.com" + } + ], + "visibility": "private" + } + schema: + title: RoomInfo + type: object + properties: + room_id: + type: string + description: "The ID of this room." + membership: + type: string + description: "The user's membership state in this room." + enum: ["invite", "join", "leave", "ban"] + messages: + type: object + title: PaginationChunk + description: "The pagination chunk for this room." + properties: + start: + type: string + description: |- + A token which correlates to the first value in ``chunk``. + Used for pagination. + end: + type: string + description: |- + A token which correlates to the last value in ``chunk``. + Used for pagination. + chunk: + type: array + description: |- + If the user is a member of the room this will be a + list of the most recent messages for this room. If + the user has left the room this will be the + messages that preceeded them leaving. This array + will consist of at most ``limit`` elements. + items: + type: object + title: RoomEvent + allOf: + - "$ref": "core-event-schema/room_event.json" + required: ["start", "end", "chunk"] + state: + type: array + description: |- + If the user is a member of the room this will be the + current state of the room as a list of events. If the + user has left the room this will be the state of the + room when they left it. + items: + title: StateEvent + type: object + allOf: + - "$ref": "core-event-schema/state_event.json" + visibility: + type: string + enum: ["private", "public"] + description: |- + Whether this room is visible to the ``/publicRooms`` API + or not." + required: ["room_id", "membership"] + 403: + description: > + You aren't a member of the room and weren't previously a + member of the room. + + "/rooms/{roomId}/members": + get: + summary: Get the m.room.member events for the room. + description: + Get the list of members for this room. + parameters: + - in: path + type: string + name: roomId + description: The room to get the member events for. + required: true + x-example: "!636q39766251:example.com" + responses: + 200: + description: |- + A list of members of the room. If you are joined to the room then + this will be the current members of the room. If you have left te + room then this will be the members of the room when you left. + examples: + application/json: |- + { + "chunk": [ + { + "age": 6547561012, + "content": { + "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", + "displayname": null, + "membership": "join" + }, + "event_id": "$1426600438280zExKY:example.com", + "membership": "join", + "origin_server_ts": 1426600438277, + "room_id": "!636q39766251:example.com", + "state_key": "@alice:example.com", + "type": "m.room.member", + "user_id": "@alice:example.com" + }, + { + "age": 1622568720, + "content": { + "avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto", + "displayname": "Bob", + "membership": "join" + }, + "event_id": "$1431525430134MxlLX:example.com", + "origin_server_ts": 1431525430569, + "replaces_state": "$142652023736BSXcM:example.com", + "room_id": "!636q39766251:example.com", + "state_key": "@bob:example.com", + "type": "m.room.member", + "user_id": "@bob:example.com" + } + ] + } + schema: + type: object + properties: + chunk: + type: array + items: + title: MemberEvent + type: object + allOf: + - "$ref": "v1-event-schema/m.room.member" + 403: + description: > + You aren't a member of the room and weren't previously a + member of the room. + diff --git a/api/client-server/v1/sync.yaml b/api/client-server/v1/sync.yaml new file mode 100644 index 00000000..7c1d43f3 --- /dev/null +++ b/api/client-server/v1/sync.yaml @@ -0,0 +1,371 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Sync API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/events": + get: + summary: Listen on the event stream. + description: |- + This will listen for new events and return them to the caller. This will + block until an event is received, or until the ``timeout`` is reached. + security: + - accessToken: [] + parameters: + - in: query + type: string + name: from + description: The token to stream from. + required: false + x-example: "s3456_9_0" + - in: query + type: integer + name: timeout + description: The maximum time in milliseconds to wait for an event. + required: false + x-example: "35000" + - in: query + type: string + name: archived + description: |- + Whether to include rooms that the user has left. If absent then + only rooms that the user has been invited to or has joined are + included. If set to "true" then rooms that the user has left are + included as well. + required: false + x-example: "true" + responses: + 200: + description: "The events received, which may be none." + examples: + application/json: |- + { + "start": "s3456_9_0", + "end": "s3457_9_0", + "chunk": [ + { + "age": 32, + "content": { + "body": "incoming message", + "msgtype": "m.text" + }, + "event_id": "$14328055551tzaee:localhost", + "origin_server_ts": 1432804485886, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "type": "m.room.message", + "user_id": "@bob:localhost" + } + ] + } + schema: + type: object + properties: + start: + type: string + description: |- + A token which correlates to the first value in ``chunk``. Used + for pagination. + end: + type: string + description: |- + A token which correlates to the last value in ``chunk``. Used + for pagination. + chunk: + type: array + description: "An array of events." + items: + type: object + title: RoomEvent + allOf: + - "$ref": "core-event-schema/room_event.json" + 400: + description: "Bad pagination ``from`` parameter." + "/initialSync": + get: + summary: Get the user's current state. + description: |- + This returns the full state for this user, with an optional limit on the + number of messages per room to return. + security: + - accessToken: [] + parameters: + - in: query + type: integer + name: limit + description: The maximum number of messages to return for each room. + required: false + x-example: "2" + responses: + 200: + description: The user's current state. + examples: + application/json: |- + { + "end": "s3456_9_0", + "presence": [ + { + "content": { + "avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto", + "displayname": "Bob", + "last_active_ago": 31053, + "presence": "online", + "user_id": "@bob:localhost" + }, + "type": "m.presence" + } + ], + "rooms": [ + { + "membership": "join", + "messages": { + "chunk": [ + { + "age": 343513403, + "content": { + "body": "foo", + "msgtype": "m.text" + }, + "event_id": "$14328044851tzTJS:localhost", + "origin_server_ts": 1432804485886, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "type": "m.room.message", + "user_id": "@alice:localhost" + }, + { + "age": 343511809, + "content": { + "body": "bar", + "msgtype": "m.text" + }, + "event_id": "$14328044872spjFg:localhost", + "origin_server_ts": 1432804487480, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "type": "m.room.message", + "user_id": "@bob:localhost" + } + ], + "end": "s3456_9_0", + "start": "t44-3453_9_0" + }, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "state": [ + { + "age": 7148266897, + "content": { + "join_rule": "public" + }, + "event_id": "$14259997323TLwtb:localhost", + "origin_server_ts": 1425999732392, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "state_key": "", + "type": "m.room.join_rules", + "user_id": "@alice:localhost" + }, + { + "age": 6547561012, + "content": { + "avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto", + "displayname": null, + "membership": "join" + }, + "event_id": "$1426600438280zExKY:localhost", + "membership": "join", + "origin_server_ts": 1426600438277, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "state_key": "@alice:localhost", + "type": "m.room.member", + "user_id": "@alice:localhost" + }, + { + "age": 7148267200, + "content": { + "creator": "@alice:localhost" + }, + "event_id": "$14259997320KhbwJ:localhost", + "origin_server_ts": 1425999732089, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "state_key": "", + "type": "m.room.create", + "user_id": "@alice:localhost" + }, + { + "age": 1622568720, + "content": { + "avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto", + "displayname": "Bob", + "membership": "join" + }, + "event_id": "$1431525430134MxlLX:localhost", + "origin_server_ts": 1431525430569, + "replaces_state": "$142652023736BSXcM:localhost", + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "state_key": "@bob:localhost", + "type": "m.room.member", + "user_id": "@bob:localhost" + }, + { + "age": 7148267004, + "content": { + "ban": 50, + "events": { + "m.room.name": 100, + "m.room.power_levels": 100 + }, + "events_default": 0, + "kick": 50, + "redact": 50, + "state_default": 50, + "users": { + "@alice:localhost": 100 + }, + "users_default": 0 + }, + "event_id": "$14259997322mqfaq:localhost", + "origin_server_ts": 1425999732285, + "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", + "state_key": "", + "type": "m.room.power_levels", + "user_id": "@alice:localhost" + } + ], + "visibility": "private" + } + ] + } + schema: + type: object + properties: + end: + type: string + description: |- + A token which correlates to the last value in ``chunk``. This + token should be used with the ``/events`` API to listen for new + events. + presence: + type: array + description: A list of presence events. + items: + type: object + title: Event + allOf: + - "$ref": "core-event-schema/event.json" + rooms: + type: array + items: + type: object + title: RoomInfo + properties: + room_id: + type: string + description: "The ID of this room." + membership: + type: string + description: "The user's membership state in this room." + enum: ["invite", "join", "leave", "ban"] + invite: + type: object + title: "InviteEvent" + description: "The invite event if ``membership`` is ``invite``" + allOf: + - "$ref": "v1-event-schema/m.room.member" + messages: + type: object + title: PaginationChunk + description: "The pagination chunk for this room." + properties: + start: + type: string + description: |- + A token which correlates to the first value in ``chunk``. + Used for pagination. + end: + type: string + description: |- + A token which correlates to the last value in ``chunk``. + Used for pagination. + chunk: + type: array + description: |- + If the user is a member of the room this will be a + list of the most recent messages for this room. If + the user has left the room this will be the + messages that preceeded them leaving. This array + will consist of at most ``limit`` elements. + items: + type: object + title: RoomEvent + allOf: + - "$ref": "core-event-schema/room_event.json" + required: ["start", "end", "chunk"] + state: + type: array + description: |- + If the user is a member of the room this will be the + current state of the room as a list of events. If the + user has left the room this will be the state of the + room when they left it. + items: + title: StateEvent + type: object + allOf: + - "$ref": "core-event-schema/state_event.json" + visibility: + type: string + enum: ["private", "public"] + description: |- + Whether this room is visible to the ``/publicRooms`` API + or not." + required: ["room_id", "membership"] + required: ["end", "rooms", "presence"] + 404: + description: There is no avatar URL for this user or this user does not exist. + "/events/{eventId}": + get: + summary: Get a single event by event ID. + description: |- + Get a single event based on ``event_id``. You must have permission to + retrieve this event e.g. by being a member in the room for this event. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: eventId + description: The event ID to get. + required: true + x-example: "$asfDuShaf7Gafaw:matrix.org" + responses: + 200: + description: The full event. + examples: + application/json: |- + { + "content": { + "body": "Hello world!", + "msgtype": "m.text" + }, + "room_id:": "!wfgy43Sg4a:matrix.org", + "user_id": "@bob:matrix.org", + "event_id": "$asfDuShaf7Gafaw:matrix.org", + "type": "m.room.message" + } + schema: + allOf: + - "$ref": "core-event-schema/event.json" + 404: + description: The event was not found or you do not have permission to read this event. diff --git a/api/client-server/v1/typing.yaml b/api/client-server/v1/typing.yaml new file mode 100644 index 00000000..737c6928 --- /dev/null +++ b/api/client-server/v1/typing.yaml @@ -0,0 +1,77 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Typing API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/rooms/{roomId}/typing/{userId}": + put: + summary: Informs the server that the user has started or stopped typing. + description: |- + This tells the server that the user is typing for the next N + milliseconds where N is the value specified in the ``timeout`` key. + Alternatively, if ``typing`` is ``false``, it tells the server that the + user has stopped typing. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: userId + description: The user who has started to type. + required: true + x-example: "@alice:example.com" + - in: path + type: string + name: roomId + description: The room in which the user is typing. + required: true + x-example: "!wefh3sfukhs:example.com" + - in: body + name: typingState + description: The current typing state. + required: true + schema: + type: object + example: |- + { + "typing": true, + "timeout": 30000 + } + properties: + typing: + type: boolean + description: |- + Whether the user is typing or not. If ``false``, the ``timeout`` + key can be omitted. + timeout: + type: integer + description: The length of time in milliseconds to mark this user as typing. + required: ["typing"] + responses: + 200: + description: The new typing state was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + diff --git a/api/client-server/v1/v1-event-schema b/api/client-server/v1/v1-event-schema new file mode 120000 index 00000000..7a0d0326 --- /dev/null +++ b/api/client-server/v1/v1-event-schema @@ -0,0 +1 @@ +../../../event-schemas/schema/v1 \ No newline at end of file diff --git a/api/client-server/v1/voip.yaml b/api/client-server/v1/voip.yaml new file mode 100644 index 00000000..5fdf1ca7 --- /dev/null +++ b/api/client-server/v1/voip.yaml @@ -0,0 +1,68 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Voice over IP API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/turnServer": + get: + summary: Obtain TURN server credentials. + description: |- + This API provides credentials for the client to use when initiating + calls. + security: + - accessToken: [] + responses: + 200: + description: The TURN server credentials. + examples: + application/json: |- + { + "username":"1443779631:@user:example.com", + "password":"JlKfBy1QwLrO20385QyAtEyIv0=", + "uris":[ + "turn:turn.example.com:3478?transport=udp", + "turn:10.20.30.40:3478?transport=tcp", + "turns:10.20.30.40:443?transport=tcp" + ], + "ttl":86400 + } + schema: + type: object + properties: + username: + type: string + description: |- + The username to use. + password: + type: string + description: |- + The password to use. + uris: + type: array + items: + type: string + description: A list of TURN URIs + ttl: + type: integer + description: The time-to-live in seconds + required: ["username", "password", "uris", "ttl"] + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + diff --git a/api/client-server/v2_alpha/core-event-schema b/api/client-server/v2_alpha/core-event-schema new file mode 120000 index 00000000..b020e6da --- /dev/null +++ b/api/client-server/v2_alpha/core-event-schema @@ -0,0 +1 @@ +../../../event-schemas/schema/v1/core-event-schema \ No newline at end of file diff --git a/api/client-server/v2_alpha/definitions/definitions b/api/client-server/v2_alpha/definitions/definitions new file mode 120000 index 00000000..945c9b46 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/definitions @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/api/client-server/v2_alpha/definitions/error.yaml b/api/client-server/v2_alpha/definitions/error.yaml new file mode 100644 index 00000000..20312ae4 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/error.yaml @@ -0,0 +1,10 @@ +type: object +description: A Matrix-level Error +properties: + errcode: + type: string + description: An error code. + error: + type: string + description: A human-readable error message. +required: ["errcode"] \ No newline at end of file diff --git a/api/client-server/v2_alpha/definitions/event_batch.json b/api/client-server/v2_alpha/definitions/event_batch.json new file mode 100644 index 00000000..75762d75 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/event_batch.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "events": { + "type": "array", + "description": "List of events", + "items": { + "type": "object" + } + } + } +} diff --git a/api/client-server/v2_alpha/definitions/event_filter.json b/api/client-server/v2_alpha/definitions/event_filter.json new file mode 100644 index 00000000..1cdcb1f4 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/event_filter.json @@ -0,0 +1,42 @@ +{ + "type": "object", + "properties": { + "limit": { + "type": "integer", + "description": + "The maximum number of events to return." + }, + "types": { + "type": "array", + "description": + "A list of event types to include. If this list is absent then all event types are included. A '*' can be used as a wildcard to match any sequence of characters.", + "items": { + "type": "string" + } + }, + "not_types": { + "type": "array", + "description": + "A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the 'types' filter. A '*' can be used as a wildcard to match any sequence of characters.", + "items": { + "type": "string" + } + }, + "senders": { + "type": "array", + "description": + "A list of senders IDs to include. If this list is absent then all senders are included. A '*' can be used as a wildcard to match any sequence of characters.", + "items": { + "type": "string" + } + }, + "not_senders": { + "type": "array", + "description": + "A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the 'senders' filter. A '*' can be used as a wildcard to match any sequence of characters.", + "items": { + "type": "string" + } + } + } +} diff --git a/api/client-server/v2_alpha/definitions/room_event_batch.json b/api/client-server/v2_alpha/definitions/room_event_batch.json new file mode 100644 index 00000000..fcf148f3 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/room_event_batch.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "events": { + "type": "array", + "description": "List of event ids", + "items": { + "type": "string" + } + } + } +} diff --git a/api/client-server/v2_alpha/definitions/room_event_filter.json b/api/client-server/v2_alpha/definitions/room_event_filter.json new file mode 100644 index 00000000..86375781 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/room_event_filter.json @@ -0,0 +1,22 @@ +{ + "type": "object", + "allOf": [{"$ref": "definitions/event_filter.json"}], + "properties": { + "rooms": { + "type": "array", + "description": + "A list of room IDs to include. If this list is absent then all rooms are included. A '*' can be used as a wildcard to match any sequence of characters.", + "items": { + "type": "string" + } + }, + "not_rooms": { + "type": "array", + "description": + "A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the 'rooms' filter. A '*' can be used as a wildcard to match any sequence of characters.", + "items": { + "type": "string" + } + } + } +} diff --git a/api/client-server/v2_alpha/definitions/sync_filter.json b/api/client-server/v2_alpha/definitions/sync_filter.json new file mode 100644 index 00000000..0cd6a798 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/sync_filter.json @@ -0,0 +1,44 @@ +{ + "type": "object", + "properties": { + "room": { + "type": "object", + "properties": { + "state": { + "description": + "The state events to include for rooms.", + "allOf": [{"$ref": "definitions/room_event_filter.json"}] + }, + "timeline": { + "description": + "The message and state update events to include for rooms.", + "allOf": [{"$ref": "definitions/room_event_filter.json"}] + }, + "ephemeral": { + "description": + "The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms.", + "allOf": [{"$ref": "definitions/room_event_filter.json"}] + } + } + }, + "presence": { + "description": + "The presence updates to include.", + "allOf": [{"$ref": "definitions/event_filter.json"}] + }, + "event_format": { + "description": + "The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as receieved over federation. The default is 'client'.", + "type": "string", + "enum": ["client", "federation"] + }, + "event_fields": { + "type": "array", + "description": + "List of event fields to include. If this list is absent then all fields are included. The entries may include '.' charaters to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' object. A literal '.' character in a field name may be escaped using a '\\'. A server may include more fields than were requested.", + "items": { + "type": "string" + } + } + } +} diff --git a/api/client-server/v2_alpha/definitions/timeline_batch.json b/api/client-server/v2_alpha/definitions/timeline_batch.json new file mode 100644 index 00000000..ddf8d341 --- /dev/null +++ b/api/client-server/v2_alpha/definitions/timeline_batch.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "allOf": [{"$ref":"definitions/room_event_batch.json"}], + "properties": { + "limited": { + "type": "boolean", + "description": "Whether there are more events on the server" + }, + "prev_batch": { + "type": "string", + "description": "If the batch was limited then this is a token that can be supplied to the server to retrieve more events" + } + } +} diff --git a/api/client-server/v2_alpha/filter.yaml b/api/client-server/v2_alpha/filter.yaml new file mode 100644 index 00000000..37a0a3aa --- /dev/null +++ b/api/client-server/v2_alpha/filter.yaml @@ -0,0 +1,139 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v2 filter API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https +basePath: /_matrix/client/v2_alpha +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/user/{userId}/filter": + post: + summary: Upload a new filter. + description: |- + Uploads a new filter definition to the homeserver. + Returns a filter ID that may be used in /sync requests to + retrict which events are returned to the client. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: userId + required: true + description: + The id of the user uploading the filter. The access token must be + authorized to make requests for this user id. + x-example: "@alice:example.com" + - in: body + name: filter + required: true + description: The filter to upload. + schema: + type: object + allOf: + - $ref: "definitions/sync_filter.json" + example: |- + { + "room": { + "state": { + "types": ["m.room.*"], + "not_rooms": ["!726s6s6q:example.com"] + }, + "timeline": { + "limit": 10, + "types": ["m.room.message"], + "not_rooms": ["!726s6s6q:example.com"], + "not_senders": ["@spam:example.com"] + }, + "emphemeral": { + "types": ["m.receipt", "m.typing"], + "not_rooms": ["!726s6s6q:example.com"], + "not_senders": ["@spam:example.com"] + } + }, + "presence": { + "types": ["m.presence"], + "not_senders": ["@alice:example.com"] + }, + "event_format": "client", + "event_fields": ["type", "content", "sender"] + } + responses: + 200: + description: The filter was created. + examples: + application/json: |- + { + "filter_id": "66696p746572" + } + schema: + type: object + properties: + filter_id: + type: string + description: |- + The ID of the filter that was created. + "/user/{userId}/filter/{filterId}": + get: + summary: Download a filter + parameters: + - in: path + name: userId + type: string + description: |- + The user ID to download a filter for. + x-example: "@alice:example.com" + required: true + - in: path + name: filterId + type: string + description: |- + The filter ID to download. + x-example: "66696p746572" + required: true + responses: + 200: + description: |- + "The filter defintion" + examples: + application/json: |- + { + "room": { + "state": { + "types": ["m.room.*"], + "not_rooms": ["!726s6s6q:example.com"] + }, + "timeline": { + "limit": 10, + "types": ["m.room.message"], + "not_rooms": ["!726s6s6q:example.com"], + "not_senders": ["@spam:example.com"] + }, + "emphemeral": { + "types": ["m.receipt", "m.typing"], + "not_rooms": ["!726s6s6q:example.com"], + "not_senders": ["@spam:example.com"] + } + }, + "presence": { + "types": ["m.presence"], + "not_senders": ["@alice:example.com"] + }, + "event_format": "client", + "event_fields": ["type", "content", "sender"] + } + schema: + type: object + allOf: + - $ref: "definitions/sync_filter.json" diff --git a/api/client-server/v2_alpha/receipts.yaml b/api/client-server/v2_alpha/receipts.yaml new file mode 100644 index 00000000..b60f72e6 --- /dev/null +++ b/api/client-server/v2_alpha/receipts.yaml @@ -0,0 +1,69 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v2 Receipts API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/v2_alpha +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/rooms/{roomId}/receipt/{receiptType}/{eventId}": + post: + summary: Send a receipt for the given event ID. + description: |- + This API updates the marker for the given receipt type to the event ID + specified. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room in which to send the event. + required: true + x-example: "!wefuh21ffskfuh345:example.com" + - in: path + type: string + name: receiptType + description: The type of receipt to send. + required: true + x-example: "m.read" + enum: ["m.read"] + - in: path + type: string + name: eventId + description: The event ID to acknowledge up to. + required: true + x-example: "$1924376522eioj:example.com" + - in: body + name: receipt + description: |- + Extra receipt information to attach to ``content`` if any. The + server will automatically set the ``ts`` field. + schema: + type: object + example: |- + {} + responses: + 200: + description: The receipt was sent. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" diff --git a/api/client-server/v2_alpha/sync.yaml b/api/client-server/v2_alpha/sync.yaml new file mode 100644 index 00000000..266f27bc --- /dev/null +++ b/api/client-server/v2_alpha/sync.yaml @@ -0,0 +1,286 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v2 sync API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https +basePath: /_matrix/client/v2_alpha +consumes: + - application/json +produces: + - application/json +securityDefinitions: + accessToken: + type: apiKey + description: The user_id or application service access_token + name: access_token + in: query +paths: + "/sync": + get: + summary: Synchronise the client's state and receive new messages. + description: |- + Synchronise the client's state with the latest state on the server. + Client's use this API when they first log in to get an initial snapshot + of the state on the server, and then continue to call this API to get + incremental deltas to the state, and to receive new messages. + security: + - accessToken: [] + parameters: + - in: query + name: filter + type: string + description: |- + The ID of a filter created using the filter API. + x-example: "66696p746572" + - in: query + name: since + type: string + description: |- + A point in time to continue a sync from. + x-example: "s72594_4483_1934" + - in: query + name: set_presence + type: string + enum: ["offline"] + description: |- + Controls whether the client is automatically marked as online by + polling this API. If this parameter is omitted then the client is + automatically marked as online when it uses this API. Otherwise if + the parameter is set to "offline" then the client is not marked as + being online when it uses this API. + x-example: "offline" + - in: query + name: timeout + type: integer + description: |- + The maximum time to poll in milliseconds before returning this + request. + x-example: 30000 + responses: + 200: + description: + The initial snapshot or delta for the client to use to update their + state. + schema: + type: object + properties: + next_batch: + type: string + description: |- + The batch token to supply in the ``since`` param of the next + ``/sync`` request. + rooms: + title: Rooms + type: object + description: |- + Updates to rooms. + properties: + joined: + title: Joined + type: object + additionalProperties: + title: Joined Room + type: object + properties: + event_map: + title: EventMap + type: object + description: |- + A map from event ID to events for this room. The + events are referenced from the ``timeline`` and + ``state`` keys for this room. + additionalProperties: + title: Event + description: An event object. + type: object + allOf: + - $ref: "core-event-schema/event.json" + state: + title: State + type: object + description: |- + The state updates for the room. + allOf: + - $ref: "definitions/room_event_batch.json" + timeline: + title: Timeline + type: object + description: |- + The timeline of messages and state changes in the + room. + allOf: + - $ref: "definitions/timeline_batch.json" + ephemeral: + title: Ephemeral + type: object + description: |- + The ephemeral events in the room that aren't + recorded in the timeline or state of the room. + e.g. typing. + allOf: + - $ref: "definitions/event_batch.json" + invited: + title: Invited + type: object + description: |- + The rooms that the user has been invited to. + additionalProperties: + title: Invited Room + type: object + properties: + invite_state: + title: InviteState + type: object + description: |- + The state of a room that the user has been invited + to. These state events may only have the `sender``, + ``type``, ``state_key`` and ``content`` keys + present. These events do not replace any state that + the client already has for the room, for example if + the client has archived the room. Instead the + client should keep two separate copies of the + state: the one from the ``invite_state`` and one + from the archived ``state``. If the client joins + the room then the current state will be given as a + delta against the archived ``state`` not the + ``invite_state``. + allOf: + - $ref: "definitions/event_batch.json" + archived: + title: Archived + type: object + description: |- + The rooms that the user has left or been banned from. The + entries in the room_map will lack an ``ephemeral`` key. + additionalProperties: + title: Archived Room + type: object + properties: + event_map: + title: EventMap + type: object + description: |- + A map from event ID to events for this room. The + events are referenced from the ``timeline`` and + ``state`` keys for this room. + additionalProperties: + title: Event + description: An event object. + type: object + allOf: + - $ref: "core-event-schema/event.json" + state: + title: State + type: object + description: |- + The state updates for the room up to the point when + the user left. + allOf: + - $ref: "definitions/room_event_batch.json" + timeline: + title: Timeline + type: object + description: |- + The timeline of messages and state changes in the + room up to the point when the user left. + allOf: + - $ref: "definitions/timeline_batch.json" + presence: + title: Presence + type: object + description: |- + The updates to the presence status of other users. + allOf: + - $ref: "definitions/event_batch.json" + examples: + application/json: |- + { + "next_batch": "s72595_4483_1934", + "presence": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.presence", + "content": {"presence": "online"} + } + ] + }, + "rooms": { + "joined": { + "!726s6s6q:example.com": { + "event_map": { + "$66697273743031:example.com": { + "sender": "@alice:example.com", + "type": "m.room.member", + "state_key": "@alice:example.com", + "content": {"membership": "join"}, + "origin_server_ts": 1417731086795 + }, + "$7365636s6r6432:example.com": { + "sender": "@bob:example.com", + "type": "m.room.member", + "state_key": "@bob:example.com", + "content": {"membership": "join"}, + "origin_server_ts": 1417731086795 + }, + "$74686972643033:example.com": { + "sender": "@alice:example.com", + "type": "m.room.message", + "unsigned": {"age": "124524", "txn_id": "1234"}, + "content": { + "body": "I am a fish", + "msgtype": "m.text" + }, + "origin_server_ts": 1417731086797 + } + }, + "state": { + "events": [ + "$66697273743031:example.com", + "$7365636s6r6432:example.com" + ] + }, + "timeline": { + "events": [ + "$7365636s6r6432:example.com", + "$74686972643033:example.com" + ], + "limited": true, + "prev_batch": "t34-23535_0_0" + }, + "ephemeral": { + "events": [ + { + "room_id": "!726s6s6q:example.com", + "type": "m.typing", + "content": {"user_ids": ["@alice:example.com"]} + } + ] + } + } + }, + "invited": { + "!696r7674:example.com": { + "invite_state": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.room.name", + "state_key": "", + "content": {"name": "My Room Name"} + }, + { + "sender": "@alice:example.com", + "type": "m.room.member", + "state_key": "@bob:example.com", + "content": {"membership": "invite"} + } + ] + } + } + }, + "archived": {} + } + } diff --git a/swagger/files/backbone-min.js b/api/files/backbone-min.js similarity index 100% rename from swagger/files/backbone-min.js rename to api/files/backbone-min.js diff --git a/swagger/files/css b/api/files/css similarity index 100% rename from swagger/files/css rename to api/files/css diff --git a/swagger/files/handlebars-1.0.0.js b/api/files/handlebars-1.0.0.js similarity index 100% rename from swagger/files/handlebars-1.0.0.js rename to api/files/handlebars-1.0.0.js diff --git a/swagger/files/highlight.7.3.pack.js b/api/files/highlight.7.3.pack.js similarity index 100% rename from swagger/files/highlight.7.3.pack.js rename to api/files/highlight.7.3.pack.js diff --git a/swagger/files/jquery-1.8.0.min.js b/api/files/jquery-1.8.0.min.js similarity index 100% rename from swagger/files/jquery-1.8.0.min.js rename to api/files/jquery-1.8.0.min.js diff --git a/swagger/files/jquery.ba-bbq.min.js b/api/files/jquery.ba-bbq.min.js similarity index 100% rename from swagger/files/jquery.ba-bbq.min.js rename to api/files/jquery.ba-bbq.min.js diff --git a/swagger/files/jquery.slideto.min.js b/api/files/jquery.slideto.min.js similarity index 100% rename from swagger/files/jquery.slideto.min.js rename to api/files/jquery.slideto.min.js diff --git a/swagger/files/jquery.wiggle.min.js b/api/files/jquery.wiggle.min.js similarity index 100% rename from swagger/files/jquery.wiggle.min.js rename to api/files/jquery.wiggle.min.js diff --git a/swagger/files/reset.css b/api/files/reset.css similarity index 100% rename from swagger/files/reset.css rename to api/files/reset.css diff --git a/swagger/files/screen.css b/api/files/screen.css similarity index 100% rename from swagger/files/screen.css rename to api/files/screen.css diff --git a/swagger/files/shred.bundle.js b/api/files/shred.bundle.js similarity index 100% rename from swagger/files/shred.bundle.js rename to api/files/shred.bundle.js diff --git a/swagger/files/swagger-oauth.js b/api/files/swagger-oauth.js similarity index 100% rename from swagger/files/swagger-oauth.js rename to api/files/swagger-oauth.js diff --git a/swagger/files/swagger-ui.js b/api/files/swagger-ui.js similarity index 100% rename from swagger/files/swagger-ui.js rename to api/files/swagger-ui.js diff --git a/swagger/files/swagger.js b/api/files/swagger.js similarity index 100% rename from swagger/files/swagger.js rename to api/files/swagger.js diff --git a/swagger/files/underscore-min.js b/api/files/underscore-min.js similarity index 100% rename from swagger/files/underscore-min.js rename to api/files/underscore-min.js diff --git a/api/package.json b/api/package.json new file mode 100644 index 00000000..84b9dd7b --- /dev/null +++ b/api/package.json @@ -0,0 +1,15 @@ +{ + "name": "swagger-cli-validator", + "version": "0.0.1", + "description": "", + "main": "validator.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "nopt": "^3.0.2", + "swagger-parser": "^3.2.1" + } +} diff --git a/swagger/swagger.html b/api/swagger.html similarity index 93% rename from swagger/swagger.html rename to api/swagger.html index 27e398f0..be6fb6b9 100644 --- a/swagger/swagger.html +++ b/api/swagger.html @@ -61,11 +61,9 @@ -