diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index 6e3198ef..00000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. 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/api/client-server/application_service.yaml b/api/application-service/application_service.yaml similarity index 99% rename from api/client-server/application_service.yaml rename to api/application-service/application_service.yaml index 1a5ec838..3fd864d2 100644 --- a/api/client-server/application_service.yaml +++ b/api/application-service/application_service.yaml @@ -198,4 +198,3 @@ paths: } schema: type: object - diff --git a/api/check_examples.py b/api/check_examples.py index ee3c773c..b206a737 100755 --- a/api/check_examples.py +++ b/api/check_examples.py @@ -49,7 +49,8 @@ def check_parameter(filepath, request, parameter): # 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) + resolver = jsonschema.RefResolver(filepath, schema, handlers={"file": load_yaml}) + jsonschema.validate(example, schema, resolver=resolver) except Exception as e: raise ValueError("Error validating JSON schema for %r" % ( request @@ -76,7 +77,8 @@ def check_response(filepath, request, code, response): # 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) + resolver = jsonschema.RefResolver(filepath, schema, handlers={"file": load_yaml}) + jsonschema.validate(example, schema, resolver=resolver) except Exception as e: raise ValueError("Error validating JSON schema for %r %r" % ( request, code @@ -103,6 +105,14 @@ def check_swagger_file(filepath): check_response(filepath, request, code, response) +def load_yaml(path): + if not path.startswith("file:///"): + raise Exception("Bad ref: %s" % (path,)) + path = path[len("file://"):] + with open(path, "r") as f: + return yaml.load(f) + + if __name__ == '__main__': paths = sys.argv[1:] if not paths: diff --git a/api/client-server/account-data.yaml b/api/client-server/account-data.yaml index b634dddc..5921dc29 100644 --- a/api/client-server/account-data.yaml +++ b/api/client-server/account-data.yaml @@ -6,7 +6,7 @@ host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/v2_alpha +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -57,6 +57,8 @@ paths: 200: description: The account_data was successfully added. + tags: + - User data "/user/{userId}/rooms/{roomId}/account_data/{type}": put: summary: Set some account_data for the user. @@ -103,3 +105,5 @@ paths: 200: description: The account_data was successfully added. + tags: + - User data diff --git a/api/client-server/admin.yaml b/api/client-server/admin.yaml new file mode 100644 index 00000000..349dfbf4 --- /dev/null +++ b/api/client-server/admin.yaml @@ -0,0 +1,105 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server Administration API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% +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: + "/admin/whois/{userId}": + get: + summary: Gets information about a particular user. + description: |- + Gets information about a particular user. + + This API may be restricted to only be called by the user being looked + up, or by a server admin. Server-local administrator privileges are not + specified in this document. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: userId + description: The user to look up. + required: true + x-example: "@peter:rabbit.rocks" + responses: + 200: + description: The lookup was successful. + examples: + application/json: |- + { + "user_id": "@peter:rabbit.rocks", + "devices": { + "teapot": { + "sessions": [ + { + "connections": [ + { + "ip": "127.0.0.1", + "last_seen": 1411996332123, + "user_agent": "curl/7.31.0-DEV" + }, + { + "ip": "10.0.0.2", + "last_seen": 1411996332123, + "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36" + } + ] + } + ] + } + } + } + schema: + type: object + properties: + user_id: + type: string + description: The Matrix user ID of the user. + devices: + type: object + description: |- + Each key is an identitfier for one of the user's devices. + additionalProperties: + type: object + title: DeviceInfo + properties: + sessions: + type: array + description: A user's sessions (i.e. what they did with an access token from one login). + items: + type: object + title: SessionInfo + properties: + connections: + type: array + description: Information particular connections in the session. + items: + type: object + title: ConnectionInfo + properties: + ip: + type: string + description: Most recently seen IP address of the session. + last_seen: + type: number + description: Unix timestamp that the session was last active. + user_agent: + type: string + description: User agent string last seen in the session. + tags: + - Server administration diff --git a/api/client-server/administrative_contact.yaml b/api/client-server/administrative_contact.yaml index 68fd0fba..8c8e0a35 100644 --- a/api/client-server/administrative_contact.yaml +++ b/api/client-server/administrative_contact.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Account Administrative Contact API" + title: "Matrix Client-Server Account Administrative Contact API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/v2_alpha +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -25,7 +25,7 @@ paths: This API endpoint uses the User-Interactive Authentication API. An access token should be submitted to this endpoint if the client has an active session. - The Home Server may change the flows available depending on whether a + The homeserver may change the flows available depending on whether a valid access token is provided. security: - accessToken: [] @@ -54,6 +54,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - User data "/account/3pid": get: summary: Gets a list of a user's third party identifiers. @@ -64,7 +66,7 @@ paths: This is *not* the same as the list of third party identifiers bound to the user's Matrix ID in Identity Servers. - Identifiers in this list may be used by the Home Server as, for example, + Identifiers in this list may be used by the homeserver as, for example, identifiers that it will accept to reset the user's account password. security: - accessToken: [] @@ -97,6 +99,8 @@ paths: address: type: string description: The third party identifier address. + tags: + - User data post: summary: Adds contact information to the user's account. description: Adds contact information to the user's account. @@ -126,7 +130,7 @@ paths: bind: type: boolean description: |- - Whether the home server should also bind this third party + Whether the homeserver should also bind this third party identifier to the account's Matrix ID with the passed identity server. Default: ``false``. x-example: true @@ -155,3 +159,5 @@ paths: "errcode": "M_THREEPID_AUTH_FAILED", "error": "The third party credentials could not be verified by the identity server." } + tags: + - User data diff --git a/api/client-server/banning.yaml b/api/client-server/banning.yaml index e841050f..ad0e2834 100644 --- a/api/client-server/banning.yaml +++ b/api/client-server/banning.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Room Banning API" + title: "Matrix Client-Server Room Banning API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -74,3 +74,5 @@ paths: "errcode": "M_FORBIDDEN", "error": "You do not have a high enough power level to ban from this room." } + tags: + - Room membership diff --git a/api/client-server/content-repo.yaml b/api/client-server/content-repo.yaml index 8e6e8d1a..7a44b866 100644 --- a/api/client-server/content-repo.yaml +++ b/api/client-server/content-repo.yaml @@ -1,11 +1,11 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Content Repository API" + title: "Matrix Client-Server Content Repository API" version: "1.0.0" host: localhost:8008 schemes: - https -basePath: /_matrix/media/v1 +basePath: /_matrix/media/%CLIENT_MAJOR_VERSION% produces: - application/json - "*/*" @@ -43,6 +43,8 @@ paths: { "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" } + tags: + - Media "/download/{serverName}/{mediaId}": get: summary: "Download content from the content repository." @@ -74,6 +76,8 @@ paths: type: "string" schema: type: file + tags: + - Media "/thumbnail/{serverName}/{mediaId}": get: summary: "Download a thumbnail of the content from the content repository." @@ -123,5 +127,5 @@ paths: enum: ["image/jpeg", "image/png"] schema: type: file - - + tags: + - Media diff --git a/api/client-server/create_room.yaml b/api/client-server/create_room.yaml index 051c4b84..6e19b1d8 100644 --- a/api/client-server/create_room.yaml +++ b/api/client-server/create_room.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Room Creation API" + title: "Matrix Client-Server Room Creation API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -57,7 +57,7 @@ paths: description: |- The desired room alias **local part**. If this is included, a room alias will be created and mapped to the newly created - room. The alias will belong on the *same* home server which + room. The alias will belong on the *same* homeserver which created the room. For example, if this was set to "foo" and sent to the homeserver "example.com" the complete room alias would be ``#foo:example.com``. @@ -146,3 +146,5 @@ paths: 400: description: > The request body is malformed or the room alias specified is already taken. + tags: + - Room creation diff --git a/api/client-server/definitions/event.json b/api/client-server/definitions/event.json deleted file mode 100644 index 5a8f52f6..00000000 --- a/api/client-server/definitions/event.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "type": "object", - "title": "Event", - "properties": { - "content": { - "type": "object", - "title": "EventContent", - "description": "The content of this event. The fields in this object will vary depending on the type of event." - }, - "origin_server_ts": { - "type": "integer", - "format": "int64", - "description": "Timestamp in milliseconds on originating homeserver when this event was sent." - }, - "sender": { - "type": "string", - "description": "The MXID of the user who sent this event." - }, - "state_key": { - "type": "string", - "description": "Optional. This key will only be present for state events. A unique key which defines the overwriting semantics for this piece of room state." - }, - "type": { - "type": "string", - "description": "The type of event." - }, - "unsigned": { - "type": "object", - "title": "Unsigned", - "description": "Information about this event which was not sent by the originating homeserver", - "properties": { - "age": { - "type": "integer", - "format": "int64", - "description": "Time in milliseconds since the event was sent." - }, - "prev_content": { - "title": "EventContent", - "type": "object", - "description": "Optional. The previous ``content`` for this state. This will be present only for state events appearing in the ``timeline``. If this is not a state event, or there is no previous content, this key will be missing." - }, - "replaces_state": { - "type": "string", - "description": "Optional. The event_id of the previous event for this state. This will be present only for state events appearing in the ``timeline``. If this is not a state event, or there is no previous content, this key will be missing." - }, - "transaction_id": { - "type": "string", - "description": "Optional. The transaction ID set when this message was sent. This key will only be present for message events sent by the device calling this API." - } - } - } - } -} diff --git a/api/client-server/definitions/event.yaml b/api/client-server/definitions/event.yaml new file mode 100644 index 00000000..d40be8a9 --- /dev/null +++ b/api/client-server/definitions/event.yaml @@ -0,0 +1,45 @@ +properties: + content: + description: The content of this event. The fields in this object will vary depending + on the type of event. + title: EventContent + type: object + origin_server_ts: + description: Timestamp in milliseconds on originating homeserver when this event + was sent. + format: int64 + type: integer + sender: + description: The MXID of the user who sent this event. + type: string + state_key: + description: Optional. This key will only be present for state events. A unique + key which defines the overwriting semantics for this piece of room state. + type: string + type: + description: The type of event. + type: string + unsigned: + description: Information about this event which was not sent by the originating + homeserver + properties: + age: + description: Time in milliseconds since the event was sent. + format: int64 + type: integer + prev_content: + description: Optional. The previous ``content`` for this state. This will + be present only for state events appearing in the ``timeline``. If this + is not a state event, or there is no previous content, this key will be + missing. + title: EventContent + type: object + transaction_id: + description: Optional. The transaction ID set when this message was sent. + This key will only be present for message events sent by the device calling + this API. + type: string + title: Unsigned + type: object +title: Event +type: object diff --git a/api/client-server/definitions/event_batch.json b/api/client-server/definitions/event_batch.json deleted file mode 100644 index 7f489423..00000000 --- a/api/client-server/definitions/event_batch.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "object", - "properties": { - "events": { - "type": "array", - "description": "List of events", - "items": { - "type": "object", - "allOf": [{"$ref": "event.json" }] - } - } - } -} diff --git a/api/client-server/definitions/event_batch.yaml b/api/client-server/definitions/event_batch.yaml new file mode 100644 index 00000000..bc6faf5b --- /dev/null +++ b/api/client-server/definitions/event_batch.yaml @@ -0,0 +1,9 @@ +properties: + events: + description: List of events + items: + allOf: + - $ref: event.yaml + type: object + type: array +type: object diff --git a/api/client-server/definitions/event_filter.json b/api/client-server/definitions/event_filter.json deleted file mode 100644 index 1cdcb1f4..00000000 --- a/api/client-server/definitions/event_filter.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "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/definitions/event_filter.yaml b/api/client-server/definitions/event_filter.yaml new file mode 100644 index 00000000..23a2f11c --- /dev/null +++ b/api/client-server/definitions/event_filter.yaml @@ -0,0 +1,34 @@ +properties: + limit: + description: The maximum number of events to return. + type: integer + not_senders: + 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 + type: array + not_types: + 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 + type: array + senders: + 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 + type: array + types: + 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 + type: array +type: object diff --git a/api/client-server/definitions/push_condition.json b/api/client-server/definitions/push_condition.json deleted file mode 100644 index 1d84955c..00000000 --- a/api/client-server/definitions/push_condition.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/definitions/push_condition.yaml b/api/client-server/definitions/push_condition.yaml new file mode 100644 index 00000000..e698d73d --- /dev/null +++ b/api/client-server/definitions/push_condition.yaml @@ -0,0 +1,9 @@ +properties: + kind: + enum: + - event_match + - profile_tag + - contains_display_name + - room_member_count + type: string +type: object diff --git a/api/client-server/definitions/push_rule.json b/api/client-server/definitions/push_rule.json deleted file mode 100644 index d10f11f8..00000000 --- a/api/client-server/definitions/push_rule.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "title": "PushRule", - "type": "object", - "properties": { - "default": { - "type": "boolean" - }, - "enabled": { - "type": "boolean" - }, - "rule_id": { - "type": "string" - }, - "actions": { - "items": { - "type": ["object", "string"] - }, - "type": "array" - } - } -} diff --git a/api/client-server/definitions/push_rule.yaml b/api/client-server/definitions/push_rule.yaml new file mode 100644 index 00000000..0b2d78f4 --- /dev/null +++ b/api/client-server/definitions/push_rule.yaml @@ -0,0 +1,15 @@ +properties: + actions: + items: + type: + - object + - string + type: array + default: + type: boolean + enabled: + type: boolean + rule_id: + type: string +title: PushRule +type: object diff --git a/api/client-server/definitions/push_ruleset.json b/api/client-server/definitions/push_ruleset.json deleted file mode 100644 index 529ebeed..00000000 --- a/api/client-server/definitions/push_ruleset.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "type": "object", - "properties": { - "content": { - "items": { - "type": "object", - "title": "PushRule", - "allOf": [ - { - "$ref": "push_rule.json" - } - ] - }, - "type": "array" - }, - "override": { - "items": { - "type": "object", - "title": "PushRule", - "allOf": [ - { - "$ref": "push_rule.json" - } - ] - }, - "type": "array" - }, - "sender": { - "items": { - "type": "object", - "title": "PushRule", - "allOf": [ - { - "$ref": "push_rule.json" - } - ] - }, - "type": "array" - }, - "underride": { - "items": { - "type": "object", - "title": "PushRule", - "allOf": [ - { - "$ref": "push_rule.json" - } - ] - }, - "type": "array" - }, - "room": { - "items": { - "type": "object", - "title": "PushRule", - "allOf": [ - { - "$ref": "push_rule.json" - } - ] - }, - "type": "array" - } - } -} diff --git a/api/client-server/definitions/push_ruleset.yaml b/api/client-server/definitions/push_ruleset.yaml new file mode 100644 index 00000000..52ae5d1e --- /dev/null +++ b/api/client-server/definitions/push_ruleset.yaml @@ -0,0 +1,37 @@ +properties: + content: + items: + allOf: + - $ref: push_rule.yaml + title: PushRule + type: object + type: array + override: + items: + allOf: + - $ref: push_rule.yaml + title: PushRule + type: object + type: array + room: + items: + allOf: + - $ref: push_rule.yaml + title: PushRule + type: object + type: array + sender: + items: + allOf: + - $ref: push_rule.yaml + title: PushRule + type: object + type: array + underride: + items: + allOf: + - $ref: push_rule.yaml + title: PushRule + type: object + type: array +type: object diff --git a/api/client-server/definitions/room_event_filter.json b/api/client-server/definitions/room_event_filter.json deleted file mode 100644 index 02e5d0e0..00000000 --- a/api/client-server/definitions/room_event_filter.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "object", - "allOf": [{"$ref": "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/definitions/room_event_filter.yaml b/api/client-server/definitions/room_event_filter.yaml new file mode 100644 index 00000000..4826693d --- /dev/null +++ b/api/client-server/definitions/room_event_filter.yaml @@ -0,0 +1,17 @@ +allOf: +- $ref: event_filter.yaml +properties: + not_rooms: + 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 + type: array + rooms: + 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 + type: array +type: object diff --git a/api/client-server/definitions/sync_filter.json b/api/client-server/definitions/sync_filter.json deleted file mode 100644 index defc318a..00000000 --- a/api/client-server/definitions/sync_filter.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "type": "object", - "properties": { - "room": { - "type": "object", - "properties": { - "state": { - "description": - "The state events to include for rooms.", - "allOf": [{"$ref": "room_event_filter.json"}] - }, - "timeline": { - "description": - "The message and state update events to include for rooms.", - "allOf": [{"$ref": "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": "room_event_filter.json"}] - } - } - }, - "presence": { - "description": - "The presence updates to include.", - "allOf": [{"$ref": "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/definitions/sync_filter.yaml b/api/client-server/definitions/sync_filter.yaml new file mode 100644 index 00000000..4aa78e77 --- /dev/null +++ b/api/client-server/definitions/sync_filter.yaml @@ -0,0 +1,42 @@ +properties: + event_fields: + 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 + type: array + 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'. + enum: + - client + - federation + type: string + presence: + allOf: + - $ref: event_filter.yaml + description: The presence updates to include. + room: + properties: + ephemeral: + allOf: + - $ref: room_event_filter.yaml + description: The events that aren't recorded in the room history, e.g. typing + and receipts, to include for rooms. + include_leave: + description: Include rooms that the user has left in the sync, default false + type: boolean + state: + allOf: + - $ref: room_event_filter.yaml + description: The state events to include for rooms. + timeline: + allOf: + - $ref: room_event_filter.yaml + description: The message and state update events to include for rooms. + type: object +type: object diff --git a/api/client-server/definitions/timeline_batch.json b/api/client-server/definitions/timeline_batch.json deleted file mode 100644 index 6f7e714a..00000000 --- a/api/client-server/definitions/timeline_batch.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "object", - "allOf": [{"$ref":"event_batch.json"}], - "properties": { - "limited": { - "type": "boolean", - "description": "True if the number of events returned was limited by the ``limit`` on the filter" - }, - "prev_batch": { - "type": "string", - "description": "If the batch was limited then this is a token that can be supplied to the server to retrieve earlier events" - } - } -} diff --git a/api/client-server/definitions/timeline_batch.yaml b/api/client-server/definitions/timeline_batch.yaml new file mode 100644 index 00000000..095bb61e --- /dev/null +++ b/api/client-server/definitions/timeline_batch.yaml @@ -0,0 +1,12 @@ +allOf: +- $ref: event_batch.yaml +properties: + limited: + description: True if the number of events returned was limited by the ``limit`` + on the filter + type: boolean + prev_batch: + description: If the batch was limited then this is a token that can be supplied + to the server to retrieve earlier events + type: string +type: object diff --git a/api/client-server/directory.yaml b/api/client-server/directory.yaml index 4966a920..773706a7 100644 --- a/api/client-server/directory.yaml +++ b/api/client-server/directory.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Directory API" + title: "Matrix Client-Server Directory API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1/directory +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%/directory consumes: - application/json produces: @@ -52,6 +52,8 @@ paths: {} schema: type: object + tags: + - Room directory get: summary: Get the room ID corresponding to this room alias. parameters: @@ -102,6 +104,8 @@ paths: "errcode": "M_UNKNOWN", "error": "Room alias #monkeys:matrix.org already exists." } + tags: + - Room directory delete: summary: Remove a mapping of room alias to room ID. description: |- @@ -125,3 +129,5 @@ paths: {} schema: type: object + tags: + - Room directory diff --git a/api/client-server/filter.yaml b/api/client-server/filter.yaml index 0c2761b7..bf81f60e 100644 --- a/api/client-server/filter.yaml +++ b/api/client-server/filter.yaml @@ -1,11 +1,11 @@ swagger: '2.0' info: - title: "Matrix Client-Server v2 filter API" + title: "Matrix Client-Server filter API" version: "1.0.0" host: localhost:8008 schemes: - https -basePath: /_matrix/client/v2_alpha +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -22,8 +22,8 @@ paths: 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. + Returns a filter ID that may be used in future requests to + restrict which events are returned to the client. security: - accessToken: [] parameters: @@ -42,7 +42,7 @@ paths: schema: type: object allOf: - - $ref: "definitions/sync_filter.json" + - $ref: "definitions/sync_filter.yaml" example: |- { "room": { @@ -84,6 +84,8 @@ paths: type: string description: |- The ID of the filter that was created. + tags: + - Room participation "/user/{userId}/filter/{filterId}": get: summary: Download a filter @@ -136,4 +138,6 @@ paths: schema: type: object allOf: - - $ref: "definitions/sync_filter.json" + - $ref: "definitions/sync_filter.yaml" + tags: + - Room participation diff --git a/api/client-server/guest_events.yaml b/api/client-server/guest_events.yaml index 671b355a..3dce4140 100644 --- a/api/client-server/guest_events.yaml +++ b/api/client-server/guest_events.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Sync Guest API" + title: "Matrix Client-Server Sync Guest API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -74,7 +74,7 @@ paths: "origin_server_ts": 1432804485886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", - "user_id": "@bob:localhost" + "sender": "@bob:localhost" } ] } @@ -98,6 +98,7 @@ paths: type: object title: Event allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" 400: description: "Bad pagination ``from`` parameter." + # No tags to exclude this from the swagger UI - use the non-guest version instead. diff --git a/api/client-server/inviting.yaml b/api/client-server/inviting.yaml index 0a028710..1dd7de5f 100644 --- a/api/client-server/inviting.yaml +++ b/api/client-server/inviting.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Room Joining API" + title: "Matrix Client-Server Room Joining API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -38,7 +38,7 @@ paths: 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 + If the user was invited to the room, the homeserver will append a ``m.room.member`` event to the room. .. _third party invites section: `invite-by-third-party-id-endpoint`_ @@ -88,3 +88,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Room membership diff --git a/api/client-server/joining.yaml b/api/client-server/joining.yaml index b6d2df18..23bdc6a5 100644 --- a/api/client-server/joining.yaml +++ b/api/client-server/joining.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Room Inviting API" + title: "Matrix Client-Server Room Inviting API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -63,6 +63,8 @@ paths: schema: "$ref": "definitions/error.yaml" x-alias: - canonical-link: "post-matrix-client-api-v1-rooms-roomid-join" + canonical-link: "post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-join" aliases: - - /_matrix/client/api/v1/join/{roomId} + - /_matrix/client/%CLIENT_MAJOR_VERSION%/join/{roomId} + tags: + - Room membership diff --git a/api/client-server/leaving.yaml b/api/client-server/leaving.yaml index e81d812b..95a2133a 100644 --- a/api/client-server/leaving.yaml +++ b/api/client-server/leaving.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Room Leaving API" + title: "Matrix Client-Server Room Leaving API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -55,6 +55,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Room membership "/rooms/{roomId}/forget": post: summary: Stop the requesting user remembering about a particular room. @@ -90,3 +92,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Room membership diff --git a/api/client-server/list_public_rooms.yaml b/api/client-server/list_public_rooms.yaml index 23b1c3d0..ad7dfca9 100644 --- a/api/client-server/list_public_rooms.yaml +++ b/api/client-server/list_public_rooms.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Room Creation API" + title: "Matrix Client-Server Room Creation API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -95,3 +95,5 @@ paths: 400: description: > The request body is malformed or the room alias specified is already taken. + tags: + - Room discovery diff --git a/api/client-server/login.yaml b/api/client-server/login.yaml index bbab46df..b9aa0596 100644 --- a/api/client-server/login.yaml +++ b/api/client-server/login.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Registration and Login API" + title: "Matrix Client-Server Registration and Login API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -81,7 +81,7 @@ paths: (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. + description: The hostname of the homeserver on which the account has been registered. 400: description: |- Part of the request was invalid. For example, the login type may not be recognised. @@ -101,6 +101,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Session management "/tokenrefresh": post: summary: Exchanges a refresh token for an access token. @@ -158,3 +160,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Session management diff --git a/api/client-server/message_pagination.yaml b/api/client-server/message_pagination.yaml index d2bc0554..b1d4cfb7 100644 --- a/api/client-server/message_pagination.yaml +++ b/api/client-server/message_pagination.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Rooms API" + title: "Matrix Client-Server Rooms API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -129,3 +129,5 @@ paths: 403: description: > You aren't a member of the room. + tags: + - Room participation diff --git a/api/client-server/old_sync.yaml b/api/client-server/old_sync.yaml index 6dbe7e5e..fafcb825 100644 --- a/api/client-server/old_sync.yaml +++ b/api/client-server/old_sync.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Sync API" + title: "Matrix Client-Server Sync API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -60,7 +60,7 @@ paths: "origin_server_ts": 1432804485886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", - "user_id": "@bob:localhost" + "sender": "@bob:localhost" } ] } @@ -84,9 +84,11 @@ paths: type: object title: Event allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" 400: description: "Bad pagination ``from`` parameter." + tags: + - Room participation "/initialSync": get: summary: Get the user's current state. @@ -154,7 +156,7 @@ paths: "origin_server_ts": 1432804485886, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", - "user_id": "@alice:localhost" + "sender": "@alice:localhost" }, { "age": 343511809, @@ -166,7 +168,7 @@ paths: "origin_server_ts": 1432804487480, "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "type": "m.room.message", - "user_id": "@bob:localhost" + "sender": "@bob:localhost" } ], "end": "s3456_9_0", @@ -184,13 +186,12 @@ paths: "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.join_rules", - "user_id": "@alice:localhost" + "sender": "@alice:localhost" }, { "age": 6547561012, "content": { "avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto", - "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:localhost", @@ -199,7 +200,7 @@ paths: "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "@alice:localhost", "type": "m.room.member", - "user_id": "@alice:localhost" + "sender": "@alice:localhost" }, { "age": 7148267200, @@ -211,7 +212,7 @@ paths: "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.create", - "user_id": "@alice:localhost" + "sender": "@alice:localhost" }, { "age": 1622568720, @@ -226,7 +227,7 @@ paths: "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "@bob:localhost", "type": "m.room.member", - "user_id": "@bob:localhost" + "sender": "@bob:localhost" }, { "age": 7148267004, @@ -250,7 +251,7 @@ paths: "room_id": "!TmaZBKYIFrIPVGoUYp:localhost", "state_key": "", "type": "m.room.power_levels", - "user_id": "@alice:localhost" + "sender": "@alice:localhost" } ], "visibility": "private", @@ -285,7 +286,7 @@ paths: type: object title: Event allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml" rooms: type: array items: @@ -332,7 +333,7 @@ paths: type: object title: RoomEvent allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" required: ["start", "end", "chunk"] state: type: array @@ -345,7 +346,7 @@ paths: title: StateEvent type: object allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/state_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml" visibility: type: string enum: ["private", "public"] @@ -361,11 +362,13 @@ paths: title: Event type: object allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml" required: ["room_id", "membership"] required: ["end", "rooms", "presence"] 404: description: There is no avatar URL for this user or this user does not exist. + tags: + - Room participation "/events/{eventId}": get: summary: Get a single event by event ID. @@ -392,12 +395,14 @@ paths: "msgtype": "m.text" }, "room_id:": "!wfgy43Sg4a:matrix.org", - "user_id": "@bob:matrix.org", + "sender": "@bob:matrix.org", "event_id": "$asfDuShaf7Gafaw:matrix.org", "type": "m.room.message" } schema: allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml" 404: description: The event was not found or you do not have permission to read this event. + tags: + - Room participation diff --git a/api/client-server/presence.yaml b/api/client-server/presence.yaml index 33df17d2..d9a1b866 100644 --- a/api/client-server/presence.yaml +++ b/api/client-server/presence.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Presence API" + title: "Matrix Client-Server Presence API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -67,6 +67,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Presence get: summary: Get this user's presence state. description: |- @@ -85,8 +87,7 @@ paths: application/json: |- { "presence": "unavailable", - "last_active_ago": 420845, - "status_msg": null + "last_active_ago": 420845 } schema: type: object @@ -107,6 +108,8 @@ paths: description: |- There is no presence state for this user. This user may not exist or isn't exposing presence information to you. + tags: + - Presence "/presence/list/{userId}": post: summary: Add or remove users from this presence list. @@ -161,6 +164,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Presence get: summary: Get presence events for this presence list. description: |- @@ -205,4 +210,6 @@ paths: type: object title: PresenceEvent allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml" + tags: + - Presence diff --git a/api/client-server/profile.yaml b/api/client-server/profile.yaml index e19466bf..2791714d 100644 --- a/api/client-server/profile.yaml +++ b/api/client-server/profile.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Profile API" + title: "Matrix Client-Server Profile API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -59,6 +59,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - User data get: summary: Get the user's display name. description: |- @@ -88,6 +90,8 @@ paths: 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. + tags: + - User data "/profile/{userId}/avatar_url": put: summary: Set the user's avatar URL. @@ -129,6 +133,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - User data get: summary: Get the user's avatar URL. description: |- @@ -158,6 +164,8 @@ paths: 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. + tags: + - User data "/profile/{userId}": get: summary: Get this user's profile information. @@ -192,4 +200,6 @@ paths: 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 + description: There is no profile information for this user or this user does not exist. + tags: + - User data diff --git a/api/client-server/push_notifier.yaml b/api/client-server/push_notifier.yaml index be3b5f74..271597d8 100644 --- a/api/client-server/push_notifier.yaml +++ b/api/client-server/push_notifier.yaml @@ -6,7 +6,7 @@ host: localhost:8008 schemes: - https - http -basePath: /_matrix/push/v1 +basePath: /_matrix/push/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -189,4 +189,5 @@ paths: items: type: string description: A pushkey - + tags: + - Push notifications diff --git a/api/client-server/pusher.yaml b/api/client-server/pusher.yaml index 8c243f2b..d8566053 100644 --- a/api/client-server/pusher.yaml +++ b/api/client-server/pusher.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Push API" + title: "Matrix Client-Server Push API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -60,7 +60,6 @@ paths: 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. @@ -114,7 +113,7 @@ paths: 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 + different user IDs. Otherwise, the homeserver 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', @@ -141,4 +140,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" - + tags: + - Push notifications diff --git a/api/client-server/pushrules.yaml b/api/client-server/pushrules.yaml index 31e84f55..07bd6bdb 100644 --- a/api/client-server/pushrules.yaml +++ b/api/client-server/pushrules.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Push Rules API" + title: "Matrix Client-Server Push Rules API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -45,14 +45,14 @@ paths: description: The ruleset for this profile tag. title: Ruleset allOf: [ - "$ref": "definitions/push_ruleset.json" + "$ref": "definitions/push_ruleset.yaml" ] global: type: object description: The global ruleset. title: Ruleset allOf: [ - "$ref": "definitions/push_ruleset.json" + "$ref": "definitions/push_ruleset.yaml" ] examples: application/json: |- @@ -245,6 +245,8 @@ paths: ] } } + tags: + - Push notifications "/pushrules/{scope}/{kind}/{ruleId}": get: summary: Retrieve a push rule. @@ -295,8 +297,10 @@ paths: description: The push rule. title: PushRule allOf: [ - "$ref": "definitions/push_rule.json" + "$ref": "definitions/push_rule.yaml" ] + tags: + - Push notifications delete: summary: Delete a push rule. description: |- @@ -335,6 +339,8 @@ paths: {} schema: type: object # empty json object + tags: + - Push notifications put: summary: Add or change a push rule. description: |- @@ -414,7 +420,7 @@ paths: items: type: object title: conditions - allOf: [ "$ref": "definitions/push_condition.json" ] + allOf: [ "$ref": "definitions/push_condition.yaml" ] required: ["actions"] responses: 200: @@ -438,6 +444,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Push notifications "/pushrules/{scope}/{kind}/{ruleId}/enabled": put: summary: "Enable or disable a push rule." @@ -470,14 +478,21 @@ paths: description: | The identifier for the rule. - in: body - name: + name: body description: | Whether the push rule is enabled or not. required: true schema: - type: boolean + type: object + properties: + enabled: + type: boolean + description: Whether the push rule is enabled or not. + required: ["enabled"] example: |- - true + { + "enabled": true + } responses: 200: description: The push rule was enabled or disabled. @@ -485,4 +500,6 @@ paths: application/json: |- {} schema: - type: object # empty json object + type: object + tags: + - Push notifications diff --git a/api/client-server/receipts.yaml b/api/client-server/receipts.yaml index b60f72e6..791e3938 100644 --- a/api/client-server/receipts.yaml +++ b/api/client-server/receipts.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v2 Receipts API" + title: "Matrix Client-Server Receipts API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/v2_alpha +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -67,3 +67,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Room participation diff --git a/api/client-server/redaction.yaml b/api/client-server/redaction.yaml new file mode 100644 index 00000000..91948b2b --- /dev/null +++ b/api/client-server/redaction.yaml @@ -0,0 +1,84 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server message redaction API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/api/%CLIENT_MAJOR_VERSION% +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}/redact/{eventId}/{txnId}": + put: + summary: Strips all non-integrity-critical information out of an event. + description: |- + Strips all information out of an event which isn't critical to the + integrity of the server-side representation of the room. + + This cannot be undone. + + Users may redact their own events, and any user with a power level + greater than or equal to the `redact` power level of the room may + redact events there. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room from which to redact the event. + required: true + x-example: "!637q39766251:example.com" + - in: path + type: string + name: eventId + description: The ID of the event to redact + required: true + x-example: "bai2b1i9:matrix.org" + - in: path + name: txnId + type: string + description: |- + The transaction ID for this event. Clients should generate a + unique ID; it will be used by the server to ensure idempotency of requests. + required: true + x-example: "37" + - in: body + name: body + schema: + type: object + example: |- + { + "reason": "Indecent material" + } + properties: + reason: + type: string + description: The reason for the event being redacted. + responses: + 200: + description: "An ID for the redaction event." + examples: + application/json: |- + { + "event_id": "YUwQidLecu" + } + schema: + type: object + properties: + event_id: + type: string + description: |- + A unique identifier for the event. + tags: + - Room participation diff --git a/api/client-server/registration.yaml b/api/client-server/registration.yaml index 681654ae..fe57f950 100644 --- a/api/client-server/registration.yaml +++ b/api/client-server/registration.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v2 Registration API" + title: "Matrix Client-Server Registration API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v2_alpha +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -94,7 +94,7 @@ paths: (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. + description: The hostname of the homeserver on which the account has been registered. 400: description: |- Part of the request was invalid. This may include one of the following error codes: @@ -107,7 +107,7 @@ paths: including after authentication if the requested user ID was registered whilst the client was performing authentication. - Home Servers MUST perform the relevant checks and return these codes before + Homeservers MUST perform the relevant checks and return these codes before performing `User-Interactive Authentication`_, although they may also return them after authentication is completed if, for example, the requested user ID was registered whilst the client was performing authentication. @@ -121,3 +121,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - User data diff --git a/api/client-server/room_send.yaml b/api/client-server/room_send.yaml index 3ab1ac40..70d005c2 100644 --- a/api/client-server/room_send.yaml +++ b/api/client-server/room_send.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 message event send API" + title: "Matrix Client-Server message event send API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -76,3 +76,5 @@ paths: type: string description: |- A unique identifier for the event. + tags: + - Room participation diff --git a/api/client-server/room_state.yaml b/api/client-server/room_state.yaml index ec30fd34..e28dfde4 100644 --- a/api/client-server/room_state.yaml +++ b/api/client-server/room_state.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 state event send API" + title: "Matrix Client-Server state event send API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -20,12 +20,12 @@ securityDefinitions: paths: "/rooms/{roomId}/state/{eventType}/{stateKey}": put: - summary: Send a message event to the given room. + summary: Send a state event to the given room. description: | - State events can be sent using this endpoint. These events will be - overwritten if ````, ```` and ```` all - match. If the state event has an empty ``state_key``, it can be - omitted from the path. + State events can be sent using this endpoint. This endpoint is + equivalent to calling `/rooms/{roomId}/state/{eventType}/{stateKey}` + with an empty `stateKey`. Previous state events with matching + `` and ``, and empty ``, will be overwritten. Requests to this endpoint **cannot use transaction IDs** like other ``PUT`` paths because they cannot be differentiated from the @@ -78,3 +78,60 @@ paths: type: string description: |- A unique identifier for the event. + tags: + - Room participation + "/rooms/{roomId}/state/{eventType}": + put: + summary: Send a state event to the given room. + description: | + State events can be sent using this endpoint. These events will be + overwritten if ````, ```` and ```` all + match. This endpoint forces the state key to be the empty string. + + Requests to this endpoint **cannot use transaction IDs** + like other ``PUT`` paths because they cannot be differentiated from the + ``state_key``. Furthermore, ``POST`` is unsupported on state paths. + + The body of the request should be the content object of the event; the + fields in this object will vary depending on the type of event. See + `Room Events`_ for the ``m.`` event specification. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room to set the state in + required: true + x-example: "!636q39766251:example.com" + - in: path + type: string + name: eventType + description: The type of event to send. + required: true + x-example: "m.room.name" + - in: body + name: body + schema: + type: object + example: |- + { + "name": "New name for the room" + } + responses: + 200: + description: "An ID for the sent event." + examples: + application/json: |- + { + "event_id": "YUwRidLecu" + } + schema: + type: object + properties: + event_id: + type: string + description: |- + A unique identifier for the event. + tags: + - Room participation diff --git a/api/client-server/rooms.yaml b/api/client-server/rooms.yaml index f7654f14..c21bd5b6 100644 --- a/api/client-server/rooms.yaml +++ b/api/client-server/rooms.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Rooms API" + title: "Matrix Client-Server Rooms API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -44,7 +44,7 @@ paths: - in: path type: string name: stateKey - description: The key of the state to look up. Defaults to the empty string. + description: The key of the state to look up. required: true x-example: "" responses: @@ -61,7 +61,49 @@ paths: description: > You aren't a member of the room and weren't previously a member of the room. + tags: + - Room participation + "/rooms/{roomId}/state/{eventType}": + get: + summary: Get the state identified by the type, with the empty state 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. + This looks up the state event with the empty state key. + 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" + 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. + tags: + - Room participation "/rooms/{roomId}/state": get: summary: Get all state events in the current state of a room. @@ -92,13 +134,12 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.join_rules", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 6547561012, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", - "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", @@ -107,7 +148,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 7148267200, @@ -119,7 +160,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.create", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 1622568720, @@ -134,7 +175,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", - "user_id": "@bob:example.com" + "sender": "@bob:example.com" }, { "age": 7148267004, @@ -158,7 +199,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.power_levels", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" } ] schema: @@ -173,12 +214,13 @@ paths: title: StateEvent type: object allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/state_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml" 403: description: > You aren't a member of the room and weren't previously a member of the room. - + tags: + - Room participation "/rooms/{roomId}/initialSync": get: summary: Snapshot the current state of a room and its most recent messages. @@ -212,7 +254,7 @@ paths: "origin_server_ts": 1432804485886, "room_id": "!636q39766251:example.com", "type": "m.room.message", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 343511809, @@ -224,7 +266,7 @@ paths: "origin_server_ts": 1432804487480, "room_id": "!636q39766251:example.com", "type": "m.room.message", - "user_id": "@bob:example.com" + "sender": "@bob:example.com" } ], "end": "s3456_9_0", @@ -242,13 +284,12 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.join_rules", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 6547561012, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", - "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", @@ -257,7 +298,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 7148267200, @@ -269,7 +310,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.create", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 1622568720, @@ -284,7 +325,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", - "user_id": "@bob:example.com" + "sender": "@bob:example.com" }, { "age": 7148267004, @@ -308,7 +349,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "", "type": "m.room.power_levels", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" } ], "visibility": "private", @@ -355,7 +396,7 @@ paths: type: object title: RoomEvent allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" required: ["start", "end", "chunk"] state: type: array @@ -368,7 +409,7 @@ paths: title: StateEvent type: object allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/state_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/state_event.yaml" visibility: type: string enum: ["private", "public"] @@ -383,13 +424,14 @@ paths: title: Event type: object allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/event.yaml" required: ["room_id"] 403: description: > You aren't a member of the room and weren't previously a member of the room. - + tags: + - Room participation "/rooms/{roomId}/members": get: summary: Get the m.room.member events for the room. @@ -416,7 +458,6 @@ paths: "age": 6547561012, "content": { "avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto", - "displayname": null, "membership": "join" }, "event_id": "$1426600438280zExKY:example.com", @@ -425,7 +466,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "@alice:example.com", "type": "m.room.member", - "user_id": "@alice:example.com" + "sender": "@alice:example.com" }, { "age": 1622568720, @@ -440,7 +481,7 @@ paths: "room_id": "!636q39766251:example.com", "state_key": "@bob:example.com", "type": "m.room.member", - "user_id": "@bob:example.com" + "sender": "@bob:example.com" } ] } @@ -458,4 +499,5 @@ paths: description: > You aren't a member of the room and weren't previously a member of the room. - + tags: + - Room participation diff --git a/api/client-server/search.yaml b/api/client-server/search.yaml index 894e5668..cd70af75 100644 --- a/api/client-server/search.yaml +++ b/api/client-server/search.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Search API" + title: "Matrix Client-Server Search API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -74,7 +74,6 @@ paths: type: object title: Filter description: |- - The filter to apply to search results. This has the same format as v2 filter API. order_by: title: "Ordering" @@ -178,7 +177,7 @@ paths: title: Event description: The event that matched. allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" context: type: object title: Event Context @@ -218,7 +217,7 @@ paths: type: object title: Event allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" events_after: type: array title: Events After @@ -227,7 +226,7 @@ paths: type: object title: Event allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" state: type: object title: Current state @@ -238,7 +237,7 @@ paths: type: object title: Event allOf: - - "$ref": "../../event-schemas/schema/core-event-schema/room_event.json" + - "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml" groups: type: object title: Groups @@ -309,7 +308,7 @@ paths: "origin_server_ts": 1444298308034, "room_id": "!qPewotXpIctQySfjSy:localhost", "type": "m.room.message", - "user_id": "@test:localhost" + "sender": "@test:localhost" } } ] @@ -322,3 +321,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Search diff --git a/api/client-server/sync.yaml b/api/client-server/sync.yaml index 675eda5d..4b399d07 100644 --- a/api/client-server/sync.yaml +++ b/api/client-server/sync.yaml @@ -1,11 +1,11 @@ swagger: '2.0' info: - title: "Matrix Client-Server v2 sync API" + title: "Matrix Client-Server sync API" version: "1.0.0" host: localhost:8008 schemes: - https -basePath: /_matrix/client/v2_alpha +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -114,7 +114,7 @@ paths: ``timeline``, if ``since`` is not given, or ``full_state`` is true). allOf: - - $ref: "definitions/event_batch.json" + - $ref: "definitions/event_batch.yaml" timeline: title: Timeline type: object @@ -122,7 +122,7 @@ paths: The timeline of messages and state changes in the room. allOf: - - $ref: "definitions/timeline_batch.json" + - $ref: "definitions/timeline_batch.yaml" ephemeral: title: Ephemeral type: object @@ -131,7 +131,7 @@ paths: recorded in the timeline or state of the room. e.g. typing. allOf: - - $ref: "definitions/event_batch.json" + - $ref: "definitions/event_batch.yaml" account_data: title: Account Data type: object @@ -139,7 +139,7 @@ paths: The private data that this user has attached to this room. allOf: - - $ref: "definitions/event_batch.json" + - $ref: "definitions/event_batch.yaml" invite: title: Invited Rooms type: object @@ -166,7 +166,7 @@ paths: delta against the archived ``state`` not the ``invite_state``. allOf: - - $ref: "definitions/event_batch.json" + - $ref: "definitions/event_batch.yaml" leave: title: Left rooms type: object @@ -182,7 +182,7 @@ paths: description: |- The state updates for the room up to the start of the timeline. allOf: - - $ref: "definitions/event_batch.json" + - $ref: "definitions/event_batch.yaml" timeline: title: Timeline type: object @@ -190,14 +190,14 @@ paths: The timeline of messages and state changes in the room up to the point when the user left. allOf: - - $ref: "definitions/timeline_batch.json" + - $ref: "definitions/timeline_batch.yaml" presence: title: Presence type: object description: |- The updates to the presence status of other users. allOf: - - $ref: "definitions/event_batch.json" + - $ref: "definitions/event_batch.yaml" examples: application/json: |- { @@ -310,3 +310,5 @@ paths: "leave": {} } } + tags: + - Room participation diff --git a/api/client-server/tags.yaml b/api/client-server/tags.yaml index 91945dca..404ed7ef 100644 --- a/api/client-server/tags.yaml +++ b/api/client-server/tags.yaml @@ -6,7 +6,7 @@ host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/v2_alpha +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -59,6 +59,8 @@ paths: "pinned": {} } } + tags: + - User data "/user/{userId}/rooms/{roomId}/tags/{tag}": put: summary: Add a tag to a room. @@ -107,6 +109,8 @@ paths: examples: application/json: |- {} + tags: + - User data delete: summary: Remove a tag from the room. description: |- @@ -145,3 +149,5 @@ paths: examples: application/json: |- {} + tags: + - User data diff --git a/api/client-server/third_party_membership.yaml b/api/client-server/third_party_membership.yaml index a10d6167..da3d4160 100644 --- a/api/client-server/third_party_membership.yaml +++ b/api/client-server/third_party_membership.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Room Membership API for third party identifiers" + title: "Matrix Client-Server Room Membership API for third party identifiers" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -39,7 +39,7 @@ paths: 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`` + third party identifier, the homeserver will append a ``m.room.member`` event to the room. If the identity server does not know a Matrix user identifier for the @@ -62,7 +62,7 @@ paths: - The matrix user ID who invited them to the room - If a token is requested from the identity server, the home server will + If a token is requested from the identity server, the homeserver will append a ``m.room.third_party_invite`` event to the room. .. _joining rooms section: `invite-by-user-id-endpoint`_ @@ -121,3 +121,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" + tags: + - Room membership diff --git a/api/client-server/typing.yaml b/api/client-server/typing.yaml index 737c6928..02ad0efd 100644 --- a/api/client-server/typing.yaml +++ b/api/client-server/typing.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Typing API" + title: "Matrix Client-Server Typing API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -74,4 +74,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" - + tags: + - Room participation diff --git a/api/client-server/voip.yaml b/api/client-server/voip.yaml index 5fdf1ca7..bdeeaa8d 100644 --- a/api/client-server/voip.yaml +++ b/api/client-server/voip.yaml @@ -1,12 +1,12 @@ swagger: '2.0' info: - title: "Matrix Client-Server v1 Voice over IP API" + title: "Matrix Client-Server Voice over IP API" version: "1.0.0" host: localhost:8008 schemes: - https - http -basePath: /_matrix/client/api/v1 +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% consumes: - application/json produces: @@ -18,7 +18,7 @@ securityDefinitions: name: access_token in: query paths: - "/turnServer": + "/voip/turnServer": get: summary: Obtain TURN server credentials. description: |- @@ -65,4 +65,5 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" - + tags: + - VOIP diff --git a/attic/v1_registration_login.rst b/attic/v1_registration_login.rst index 4b80600b..1364319b 100644 --- a/attic/v1_registration_login.rst +++ b/attic/v1_registration_login.rst @@ -1,17 +1,17 @@ Registration and Login ---------------------- -Clients must register with a home server in order to use Matrix. After +Clients must register with a homeserver in order to use Matrix. After registering, the client will be given an access token which must be used in ALL -requests to that home server as a query parameter 'access_token'. +requests to that homeserver as a query parameter 'access_token'. If the client has already registered, they need to be able to login to their -account. The home server may provide many different ways of logging in, such as +account. The homeserver may provide many different ways of logging in, such as user/password auth, login via a social network (OAuth2), login by confirming a token sent to their email address, etc. This specification does not define how -home servers should authorise their users who want to login to their existing +homeservers should authorise their users who want to login to their existing accounts, but instead defines the standard interface which implementations -should follow so that ANY client can login to ANY home server. Clients login +should follow so that ANY client can login to ANY homeserver. Clients login using the |login|_ API. Clients register using the |register|_ API. Registration follows the same general procedure as login, but the path requests are sent to and the details contained in them are different. @@ -26,7 +26,7 @@ In order to determine up-front what the server's requirements are, the client can request from the server a complete description of all of its acceptable flows of the registration or login process. It can then inspect the list of returned flows looking for one for which it believes it can complete all of the -required stages, and perform it. As each home server may have different ways of +required stages, and perform it. As each homeserver may have different ways of logging in, the client needs to know how they should login. All distinct login stages MUST have a corresponding ``type``. A ``type`` is a namespaced string which details the mechanism for logging in. @@ -64,12 +64,12 @@ ID and a new access token MUST be returned:: "access_token": "abcdef0123456789" } -The ``user_id`` key is particularly useful if the home server wishes to support +The ``user_id`` key is particularly useful if the homeserver wishes to support localpart entry of usernames (e.g. "user" rather than "@user:matrix.org"), as the client may not be able to determine its ``user_id`` in this case. -If the flow has multiple stages to it, the home server may wish to create a -session to store context between requests. If a home server responds with a +If the flow has multiple stages to it, the homeserver may wish to create a +session to store context between requests. If a homeserver responds with a ``session`` key to a request, clients MUST submit it in subsequent requests until the flow is completed:: @@ -99,7 +99,7 @@ To respond to this type, reply with:: "password": "" } -The home server MUST respond with either new credentials, the next stage of the +The homeserver MUST respond with either new credentials, the next stage of the login process, or a standard error response. Captcha-based @@ -123,7 +123,7 @@ To respond to this type, reply with:: Recaptcha.get_challenge(); Recaptcha.get_response(); -The home server MUST respond with either new credentials, the next stage of the +The homeserver MUST respond with either new credentials, the next stage of the login process, or a standard error response. OAuth2-based @@ -146,24 +146,24 @@ The server MUST respond with:: "uri": } -The home server acts as a 'confidential' client for the purposes of OAuth2. If +The homeserver acts as a 'confidential' client for the purposes of OAuth2. If the uri is a ``sevice selection URI``, it MUST point to a webpage which prompts the user to choose which service to authorize with. On selection of a service, this MUST link through to an ``Authorization Request URI``. If there is only 1 -service which the home server accepts when logging in, this indirection can be +service which the homeserver accepts when logging in, this indirection can be skipped and the "uri" key can be the ``Authorization Request URI``. The client then visits the ``Authorization Request URI``, which then shows the OAuth2 Allow/Deny prompt. Hitting 'Allow' returns the ``redirect URI`` with the -auth code. Home servers can choose any path for the ``redirect URI``. The +auth code. Homeservers can choose any path for the ``redirect URI``. The client should visit the ``redirect URI``, which will then finish the OAuth2 -login process, granting the home server an access token for the chosen service. -When the home server gets this access token, it verifies that the cilent has +login process, granting the homeserver an access token for the chosen service. +When the homeserver gets this access token, it verifies that the cilent has authorised with the 3rd party, and can now complete the login. The OAuth2 ``redirect URI`` (with auth code) MUST respond with either new credentials, the next stage of the login process, or a standard error response. -For example, if a home server accepts OAuth2 from Google, it would return the +For example, if a homeserver accepts OAuth2 from Google, it would return the Authorization Request URI for Google:: { @@ -171,7 +171,7 @@ Authorization Request URI for Google:: client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos" } -The client then visits this URI and authorizes the home server. The client then +The client then visits this URI and authorizes the homeserver. The client then visits the REDIRECT_URI with the auth code= query parameter which returns:: { @@ -195,7 +195,7 @@ To respond to this type, reply with:: "email": "" } -After validating the email address, the home server MUST send an email +After validating the email address, the homeserver MUST send an email containing an authentication code and return:: { @@ -212,7 +212,7 @@ code:: "code": "" } -The home server MUST respond to this with either new credentials, the next +The homeserver MUST respond to this with either new credentials, the next stage of the login process, or a standard error response. Email-based (url) @@ -231,7 +231,7 @@ To respond to this type, reply with:: "email": "" } -After validating the email address, the home server MUST send an email +After validating the email address, the homeserver MUST send an email containing an authentication URL and return:: { @@ -247,7 +247,7 @@ client should perform another request:: "session": "" } -The home server MUST respond to this with either new credentials, the next +The homeserver MUST respond to this with either new credentials, the next stage of the login process, or a standard error response. A common client implementation will be to periodically poll until the link is @@ -264,7 +264,7 @@ Email-based (identity server) Prior to submitting this, the client should authenticate with an identity server. After authenticating, the session information should be submitted to -the home server. +the homeserver. To respond to this type, reply with:: @@ -293,7 +293,7 @@ of a previous login stage:: "next": "" } -If a home server implements N-factor authentication, it MUST respond with all +If a homeserver implements N-factor authentication, it MUST respond with all ``stages`` when initially queried for their login requirements:: { diff --git a/changelogs/client_server.rst b/changelogs/client_server.rst new file mode 100644 index 00000000..f1c8f10c --- /dev/null +++ b/changelogs/client_server.rst @@ -0,0 +1,37 @@ +r0 +=== + +This is the first release of the client-server specification. It is largely a dump of what has currently been implemented, and there are several inconsistencies. + +An upcoming minor release will deprecate many of these inconsistencies, and they will be removed in the next major release. + +Since the draft stage, the following major changes have been made: +- /api/v1 and /v2_alpha path segments have been replaced with the major version of the release (i.e. 'r0'). +- Some POST versions of APIs with both POST and PUT have been removed. +- The specification has been split into one specification per API. This is the client-server API. The server-server API can be found documented separately. +- All APIs are now documented using Swagger +- The following modules have been added: + - Content repository + - Instant messaging + - Push notification + - History visibility + - Search + - Invites based on third party identifiers + - Room tagging + - Guest access + - Client config +- The following APIs were added: + - ``/sync`` + - ``/publicRooms`` + - ``/rooms/{roomId}/forget`` + - ``/admin/whois`` + - ``/rooms/{roomId}/redact`` + - ``/user/{userId}/filter`` +- The following APIs have been significantly modified: + - Invitations now contain partial room state + - Invitations can now be rejected + - ``/directory`` +- The following events have been added: + - ``m.room.avatar`` +- Example signed json is included for reference +- Commentary on display name calculation was added diff --git a/drafts/ancient_federated_versioning_design_notes.rst b/drafts/ancient_federated_versioning_design_notes.rst index ffda6063..036989eb 100644 --- a/drafts/ancient_federated_versioning_design_notes.rst +++ b/drafts/ancient_federated_versioning_design_notes.rst @@ -1,11 +1,11 @@ -Versioning is, like, hard for backfilling backwards because of the number of Home Servers involved. +Versioning is, like, hard for backfilling backwards because of the number of homeservers involved. -The way we solve this is by doing versioning as an acyclic directed graph of PDUs. For backfilling purposes, this is done on a per context basis. +The way we solve this is by doing versioning as an acyclic directed graph of PDUs. For backfilling purposes, this is done on a per context basis. When we send a PDU we include all PDUs that have been received for that context that hasn't been subsequently listed in a later PDU. The trivial case is a simple list of PDUs, e.g. A <- B <- C. However, if two servers send out a PDU at the same to, both B and C would point at A - a later PDU would then list both B and C. Problems with opaque version strings: - - How do you do clustering without mandating that a cluster can only have one transaction in flight to a given remote home server at a time. + - How do you do clustering without mandating that a cluster can only have one transaction in flight to a given remote homeserver at a time. If you have multiple transactions sent at once, then you might drop one transaction, receive another with a version that is later than the dropped transaction and which point ARGH WE LOST A TRANSACTION. - - How do you do backfilling? A version string defines a point in a stream w.r.t. a single home server, not a point in the context. + - How do you do backfilling? A version string defines a point in a stream w.r.t. a single homeserver, not a point in the context. We only need to store the ends of the directed graph, we DO NOT need to do the whole one table of nodes and one of edges. diff --git a/drafts/as-http-api.rst b/drafts/as-http-api.rst index 2c8f8e37..4f8d6bd4 100644 --- a/drafts/as-http-api.rst +++ b/drafts/as-http-api.rst @@ -13,9 +13,9 @@ Application Services HTTP API .. sectnum:: -Application Service -> Home Server +Application Service -> Homeserver ---------------------------------- -This contains home server APIs which are used by the application service. +This contains homeserver APIs which are used by the application service. Registration API ``[Draft]`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -34,7 +34,7 @@ Output: Side effects: - The HS will start delivering events to the URL base specified if this 200s. API called when: - - The application service wants to register with a brand new home server. + - The application service wants to register with a brand new homeserver. Notes: - An application service can state whether they should be the only ones who can manage a specified namespace. This is referred to as an "exclusive" @@ -100,7 +100,7 @@ Notes: Unregister API ``[Draft]`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ -This API unregisters a previously registered AS from the home server. +This API unregisters a previously registered AS from the homeserver. Inputs: - AS token @@ -122,9 +122,9 @@ API called when: } -Home Server -> Application Service +Homeserver -> Application Service ---------------------------------- -This contains application service APIs which are used by the home server. +This contains application service APIs which are used by the homeserver. User Query ``[Draft]`` ~~~~~~~~~~~~~~~~~~~~~~ @@ -152,9 +152,9 @@ Notes: - This is deemed more flexible than alternative methods (e.g. returning a JSON blob with the user's display name and get the HS to provision the user). Retry notes: - - The home server cannot respond to the client's request until the response to + - The homeserver cannot respond to the client's request until the response to this API is obtained from the AS. - - Recommended that home servers try a few times then time out, returning a + - Recommended that homeservers try a few times then time out, returning a 408 Request Timeout to the client. :: @@ -199,9 +199,9 @@ Notes: style JSON blob and get the HS to provision the room). It also means that the AS knows the room ID -> alias mapping. Retry notes: - - The home server cannot respond to the client's request until the response to + - The homeserver cannot respond to the client's request until the response to this API is obtained from the AS. - - Recommended that home servers try a few times then time out, returning a + - Recommended that homeservers try a few times then time out, returning a 408 Request Timeout to the client. :: @@ -236,13 +236,13 @@ Data flows: :: Typical - HS ---> AS : Home server sends events with transaction ID T. + HS ---> AS : Homeserver sends events with transaction ID T. <--- : AS sends back 200 OK. AS ACK Lost - HS ---> AS : Home server sends events with transaction ID T. + HS ---> AS : Homeserver sends events with transaction ID T. <-/- : AS 200 OK is lost. - HS ---> AS : Home server retries with the same transaction ID of T. + HS ---> AS : Homeserver retries with the same transaction ID of T. <--- : AS sends back 200 OK. If the AS had processed these events already, it can NO-OP this request (and it knows if it is the same events based on the transacton ID). @@ -253,15 +253,15 @@ Retry notes: - Since ASes by definition cannot alter the traffic being passed to it (unlike say, a Policy Server), these requests can be done in parallel to general HS processing; the HS doesn't need to block whilst doing this. - - Home servers should use exponential backoff as their retry algorithm. - - Home servers MUST NOT alter (e.g. add more) events they were going to + - Homeservers should use exponential backoff as their retry algorithm. + - Homeservers MUST NOT alter (e.g. add more) events they were going to send within that transaction ID on retries, as the AS may have already processed the events. Ordering notes: - The events sent to the AS should be linearised, as they are from the event stream. - - The home server will need to maintain a queue of transactions to send to + - The homeserver will need to maintain a queue of transactions to send to the AS. :: @@ -336,7 +336,7 @@ Notes: Server admin style permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The home server needs to give the application service *full control* over its +The homeserver needs to give the application service *full control* over its namespace, both for users and for room aliases. This means that the AS should be able to create/edit/delete any room alias in its namespace, as well as create/delete any user in its namespace. No additional API changes need to be @@ -451,15 +451,15 @@ Examples IRC ~~~ Pre-conditions: - - Server admin stores the AS token "T_a" on the home server. - - Home server has a token "T_h". - - Home server has the domain "hsdomain.com" + - Server admin stores the AS token "T_a" on the homeserver. + - Homeserver has a token "T_h". + - Homeserver has the domain "hsdomain.com" 1. Application service registration :: - AS -> HS: Registers itself with the home server + AS -> HS: Registers itself with the homeserver POST /register { url: "https://someapp.com/matrix", diff --git a/drafts/erikj_federation.rst b/drafts/erikj_federation.rst index 0644f271..ce089def 100644 --- a/drafts/erikj_federation.rst +++ b/drafts/erikj_federation.rst @@ -237,7 +237,7 @@ Domain specific string ``room_id`` A domain specific string with prefix ``!`` that is static across all events in a graph and uniquely identifies it. The ``domain`` should be that of the - home server that created the room (i.e., the server that generated the + homeserver that created the room (i.e., the server that generated the first ``m.room.create`` event). ``sender`` @@ -246,7 +246,7 @@ Domain specific string User Id A domain specific string with prefix ``@`` representing a user account. The - ``domain`` is the home server of the user and is the server used to contact + ``domain`` is the homeserver of the user and is the server used to contact the user. Joining a room @@ -280,7 +280,7 @@ can then process the join event itself. Inviting a user --------------- -To invite a remote user to a room we need their home server to sign the invite +To invite a remote user to a room we need their homeserver to sign the invite event. This is done by sending the event to the remote server, which then signs the event, before distributing the invite to other servers. diff --git a/drafts/general_api.rst b/drafts/general_api.rst index ae2446d6..baad3901 100644 --- a/drafts/general_api.rst +++ b/drafts/general_api.rst @@ -61,7 +61,7 @@ This version will change the path prefix for HTTP: - Version 2: ``/_matrix/client/v2`` Note the lack of the ``api`` segment. This is for consistency between other -home server path prefixes. +homeserver path prefixes. Terminology: - ``Chunk token`` : An opaque string which can be used to return another chunk @@ -169,16 +169,16 @@ Outputs: ``content`` key. Deleted message events are ``m.room.redaction`` events. - New position in the stream. (chunk token) State Events Ordering Notes: - - Home servers may receive state events over federation that are superceded by - state events previously sent to the client. The home server *cannot* send + - Homeservers may receive state events over federation that are superceded by + state events previously sent to the client. The homeserver *cannot* send these events to the client else they would end up erroneously clobbering the superceding state event. - - As a result, the home server reserves the right to omit sending state events + - As a result, the homeserver reserves the right to omit sending state events which are known to be superceded already. - This may result in missed *state* events. However, the state of the room will always be eventually consistent. Message Events Ordering Notes: - - Home servers may receive message events over federation that happened a long + - Homeservers may receive message events over federation that happened a long time ago. The client may or may not be interested in these message events. - For clients which do not store scrollback for a room (they discard events after processing them), this is not a problem as they only care about the @@ -191,11 +191,11 @@ Message Events Ordering Notes: - The event, when it comes down the stream, will indicate which event it comes after. Rejected events: - - A home server may find out via federation that it should not have accepted + - A homeserver may find out via federation that it should not have accepted an event (e.g. to send a message/state event in a room). For example, it may - send an event to another home server and receive an auth event stating + send an event to another homeserver and receive an auth event stating that the event should not have been sent. - - If this happens, the home server will send a ``m.room.redaction`` for the + - If this happens, the homeserver will send a ``m.room.redaction`` for the event in question. This will be a local server event (not shared with other servers). - If the event was a state event, it will synthesise a new state event to @@ -206,7 +206,7 @@ Unknown rooms: - You could receive events for rooms you are unaware of (e.g. you didn't do an initial sync, or your HS lost its database and is told from another HS that they are in this room). How do you handle this? - - The simplest option would be to redo the initial sync with a filter on the + - The simplest option would be to redo the initial sync with a filter on the room ID you're unaware of. This would retrieve the room state so you can display the room. What data flows does it address: @@ -291,7 +291,7 @@ Scrollback API ``[Draft]`` but as a purely informational display thing it would be nice. Additional Inputs: - - flag to say if the home server should do a backfill over federation + - flag to say if the homeserver should do a backfill over federation Additional Outputs: - whether there are more events on the local HS / over federation. What data flows does it address: @@ -313,7 +313,7 @@ Additional Outputs: Room Alias API ``[Draft]`` -------------------------- This provides mechanisms for creating and removing room aliases for a room on a -home server. Typically, any user in a room can make an alias for that room. The +homeserver. Typically, any user in a room can make an alias for that room. The alias creator (or anyone in the room?) can delete that alias. Server admins can also delete any alias on their server. @@ -323,7 +323,7 @@ Inputs: - Room Alias Output: - Room ID - - List of home servers to join via. + - List of homeservers to join via. Mapping a room to an alias: @@ -334,7 +334,7 @@ Inputs: Output: - Room alias Notes: - - The home server may add restrictions e.g. the user must be in the room. + - The homeserver may add restrictions e.g. the user must be in the room. Deleting a mapping: @@ -347,11 +347,11 @@ Output: Published room list API ``[Draft]`` ----------------------------------- -This provides mechanisms for searching for published rooms on a home server. +This provides mechanisms for searching for published rooms on a homeserver. Inputs: - Search text (e.g. room alias/name/topic to search on) - - Home server to search on (this may just be the URL hit for HTTP) + - Homeserver to search on (this may just be the URL hit for HTTP) - Any existing pagination token, can be missing if this is the first hit. - Limit for pagination Output: @@ -378,7 +378,7 @@ Notes: User Profile API ``[Draft]`` ---------------------------- -Every user on a home server has a profile. This profile is effectively a +Every user on a homeserver has a profile. This profile is effectively a key-value store scoped to a user ID. It can include an ``avatar_url``, ``displayname`` and other metadata. Updates to a profile should propagate to other interested users. @@ -435,7 +435,7 @@ This had a number of problems associated with it: flicker. - Name/avatar changes created more ``m.room.member`` events which meant they needed to be included in the auth chains for federation. This - created long auth chains which is suboptimal since home servers need + created long auth chains which is suboptimal since homeservers need to store the auth chains forever. These problems can be resolved by creating an ``m.room.member.profile`` @@ -448,7 +448,7 @@ However, this introduces its own set of problems, namely flicker. The client would receive the ``m.room.member`` event first, followed by the ``m.room.member.profile`` event, which could cause a flicker. In addition, federation may not send both events in a single transaction, -resulting in missing information on the receiving home server. +resulting in missing information on the receiving homeserver. For federation, these problems can be resolved by sending the ``m.room.member`` event as they are in v1 (with ``displayname`` and @@ -457,7 +457,7 @@ they cannot be in the ``unsigned`` part of the event. The receiving home server will then extract these keys and create a server-generated ``m.room.member.profile`` event. To avoid confusion with duplicate information, the ``avatar_url`` and ``displayname`` keys should be -removed from the ``m.room.member`` event by the receiving home server. +removed from the ``m.room.member`` event by the receiving homeserver. When a client requests these events (either from the event stream or from an initial sync), the server will send the generated ``m.room.member.profile`` event under the ``unsigned.profile`` key of the @@ -840,17 +840,17 @@ information per device to all other users just redirects the union problem to the client, which will commonly be presenting this information as an icon alongside the user. -When a client hits the event stream, the home server can treat the user as +When a client hits the event stream, the homeserver can treat the user as "online". This behaviour should be able to be overridden to avoid flicker during connection losses when the client is appear offline (e.g. device is appear offline > goes into a tunnel > server times out > device regains connection and hits the event stream forcing the device online before the "appear offline" state can be set). When the client has not hit the event -stream for a certain period of time, the home server can treat the user as +stream for a certain period of time, the homeserver can treat the user as "offline". The user can also set a global *per-user* appear offline flag. The user should also be able to set their presence state via a direct API, -without having to hit the event stream. The home server will set a timer when +without having to hit the event stream. The homeserver will set a timer when the connection ends, after which it will set that device to offline. As the idle flag and online state is determined per device, there needs to be a @@ -970,12 +970,12 @@ the hashes the same is the best as that means clients do not need to request the capabilities for the given hash. On first signup, the client will attempt to send the hash and be most likely -refused by the home server as it does not know the full capability set for that +refused by the homeserver as it does not know the full capability set for that hash. The client will then have to upload the full capability set to the home server. The client will then be able to send the hash as normal. When a client receives a hash, the client will either recognise the hash or -will have to request the capability set from their home server: +will have to request the capability set from their homeserver: Inputs: - Hash @@ -1070,7 +1070,7 @@ Main use cases for ``updates``: - Call signalling (child events are ICE candidates, answer to the offer, and termination) - *Local* Delivery/Read receipts : "Local" means they are not shared with other - users on the same home server or via federation but *are* shared between + users on the same homeserver or via federation but *are* shared between clients for the same user; useful for push notifications, read count markers, etc. This is done to avoid the ``n^2`` problem for sending receipts, where the vast majority of traffic tends towards sending more receipts. @@ -1168,11 +1168,11 @@ Events (breaking changes; event version 2) ``[Draft]`` when dealing with custom event types. E.g. ``_custom.event`` would allow anything in the state key, ``_@custom.event`` would only allow user IDs in the state key, etc. -- s/user_id/sender/g given that home servers can send events, not just users. +- s/user_id/sender/g given that homeservers can send events, not just users. Server-generated events ``[Draft]`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Home servers may want to send events to their local clients or to other home +Homeservers may want to send events to their local clients or to other home servers e.g. for server status notifications. These events look like regular events but have a server domain name as the diff --git a/drafts/human-id-rules.rst b/drafts/human-id-rules.rst index 914a9a42..d0c2ee2c 100644 --- a/drafts/human-id-rules.rst +++ b/drafts/human-id-rules.rst @@ -13,9 +13,9 @@ phishing/spoofing of IDs, commonly known as a homograph attack. Web browers encountered this problem when International Domain Names were introduced. A variety of checks were put in place in order to protect users. If an address failed the check, the raw punycode would be displayed to -disambiguate the address. Similar checks are performed by home servers in +disambiguate the address. Similar checks are performed by homeservers in Matrix. However, Matrix does not use punycode representations, and so does not -show raw punycode on a failed check. Instead, home servers must outright reject +show raw punycode on a failed check. Instead, homeservers must outright reject these misleading IDs. Types of human-readable IDs @@ -48,12 +48,12 @@ Checks Rejecting --------- -- Home servers MUST reject room aliases which do not pass the check, both on +- Homeservers MUST reject room aliases which do not pass the check, both on GETs and PUTs. -- Home servers MUST reject user ID localparts which do not pass the check, both +- Homeservers MUST reject user ID localparts which do not pass the check, both on creation and on events. -- Any home server whose domain does not pass this check, MUST use their punycode - domain name instead of the IDN, to prevent other home servers rejecting you. +- Any homeserver whose domain does not pass this check, MUST use their punycode + domain name instead of the IDN, to prevent other homeservers rejecting you. - Error code is ``M_FAILED_HUMAN_ID_CHECK``. (generic enough for both failing due to homograph attacks, and failing due to including ``:`` s, etc) - Error message MAY go into further information about which characters were @@ -74,7 +74,7 @@ Other considerations - High security: Outright rejection of the ID at the point of creation / receiving event. Point of creation rejection is preferable to avoid the ID entering the system in the first place. However, malicious HSes can just - allow the ID. Hence, other home servers must reject them if they see them in + allow the ID. Hence, other homeservers must reject them if they see them in events. Client never sees the problem ID, provided the HS is correctly implemented. - High security decided; client doesn't need to worry about it, no additional diff --git a/drafts/markjh_end_to_end.rst b/drafts/markjh_end_to_end.rst deleted file mode 100644 index 07390b5e..00000000 --- a/drafts/markjh_end_to_end.rst +++ /dev/null @@ -1,146 +0,0 @@ -Goals of Key-Distribution in Matrix -=================================== - -* No Central Authority: Users should not need to trust a central authority - when determining the authenticity of keys. - -* Easy to Add New Devices: It should be easy for a user to start using a - new device. - -* Possible to discover MITM: It should be possible for a user to determine if - they are being MITM. - -* Lost Devices: It should be possible for a user to recover if they lose all - their devices. - -* No Copying Keys: Keys should be per device and shouldn't leave the device - they were created on. - -A Possible Mechanism for Key Distribution -========================================= - -Basic API for setting up keys on a server: - -https://github.com/matrix-org/matrix-doc/pull/24 - -Client shouldn't trust the keys unless they have been verified, e.g by -comparing fingerprints. - -If a user adds a new device it should some yet to be specified protocol -communicate with an old device and obtain a cross-signature from the old -device for its public key. - -The new device can then present the cross-signed key to all the devices -that the user is in conversations with. Those devices should then include -the new device into those conversations. - -If the user cannot cross-sign the new key, e.g. because their old device -is lost or stolen. Then they will need to reauthenticate their conversations -out of band, e.g by comparing fingerprints. - - -Goals of End-to-end encryption in Matrix -======================================== - -* Access to Chat History: Users should be able to see the history of a - conversation on a new device. User should be able to control who can - see their chat history and how much of the chat history they can see. - -* Forward Secrecy of Discarded Chat History: Users should be able to discard - history from their device, once they have discarded the history it should be - impossible for an adversary to recover that history. - -* Forward Secrecy of Future Messages: Users should be able to recover from - disclosure of the chat history on their device. - -* Deniablity of Chat History: It should not be possible to prove to a third - party that a given user sent a message. - -* Authenticity of Chat History: It should be possible to prove amoungst - the members of a chat that a message sent by a user was authored by that - user. - - -Bonus Goals: - -* Traffic Analysis: It would be nice if the protocol was resilient to traffic - or metadata analysis. However it's not something we want to persue if it - harms the usability of the protocol. It might be cool if there was a - way for the user to could specify the trade off between performance and - resilience to traffic analysis that they wanted. - - -A Possible Design for Group Chat using Olm -========================================== - -Protecting the secrecy of history ---------------------------------- - -Each message sent by a client has a 32-bit counter. This counter increments -by one for each message sent by the client. This counter is used to advance a -ratchet. The ratchet is split into a vector four 256-bit values, -:math:`R_{n,j}` for :math:`j \in {0,1,2,3}`. The ratchet can be advanced as -follows: - -.. math:: - \begin{align} - R_{2^24n,0} &= H_0\left(R_{2^24(i-1),0}\right) \\ - R_{2^24n,1} &= H_1\left(R_{2^24(i-1),0}\right) \\ - R_{2^24n,2} &= H_2\left(R_{2^24(i-1),0}\right) \\ - R_{2^24n,3} &= H_3\left(R_{2^24(i-1),0}\right) \\ - R_{2^16n,1} &= H_1\left(R_{2^16(i-1),1}\right) \\ - R_{2^16n,2} &= H_2\left(R_{2^16(i-1),1}\right) \\ - R_{2^16n,3} &= H_3\left(R_{2^16(i-1),1}\right) \\ - R_{2^8i,2} &= H_2\left(R_{2^8(i-1),2}\right) \\ - R_{2^8i,3} &= H_3\left(R_{2^8(i-1),2}\right) \\ - R_{i,3} &= H_3\left(R_{(i-1),3}\right) - \end{align} - -Where :math:`H_0`, :math:`H_1`, :math:`H_2`, and :math:`H_3` -are different hash functions. For example -:math:`H_0` could be :math:`HMAC\left(X,\text{"\textbackslash x00"}\right)` and -:math:`H_1` could be :math:`HMAC\left(X,\text{"\textbackslash x01"}\right)`. - -So every :math:`2^24` iterations :math:`R_{n,1}` is reseeded from :math:`R_{n,0}`. -Every :math:`2^16` iterations :math:`R_{n,2}` is reseeded from :math:`R_{n,1}`. -Every :math:`2^8` iterations :math:`R_{n,3}` is reseeded from :math:`R_{n,2}`. - -This scheme allows the ratchet to be advanced an arbitrary amount forwards -while needing only 1024 hash computations. - -This the value of the ratchet is hashed to generate the keys used to encrypt -each mesage. - -A client can decrypt chat history onwards from the earliest value of the -ratchet it is aware of. But cannot decrypt history from before that point -without reversing the hash function. - -This allows a client to share its ability to decrypt chat history with another -from a point in the conversation onwards by giving a copy of the ratchet at -that point in the conversation. - -A client can discard history by advancing a ratchet to beyond the last message -they want to discard and then forgetting all previous values of the ratchet. - -Proving and denying the authenticity of history ------------------------------------------------ - -Client sign the messages they send using a Ed25519 key generated per -conversation. That key, along with the ratchet key, is distributed -to other clients using 1:1 olm ratchets. Those 1:1 ratchets are started using -Triple Diffie-Hellman which provides authenticity of the messages to the -participants and deniability of the messages to third parties. Therefore -any keys shared over those keys inherit the same levels of deniability and -authenticity. - -Protecting the secrecy of future messages ------------------------------------------ - -A client would need to generate new keys if it wanted to prevent access to -messages beyond a given point in the conversation. It must generate new keys -whenever someone leaves the room. It should generate new keys periodically -anyway. - -The frequency of key generation in a large room may need to be restricted to -keep the frequency of messages broadcast over the individual 1:1 channels -low. diff --git a/drafts/model/presence.rst b/drafts/model/presence.rst index bd60cba0..c2c88737 100644 --- a/drafts/model/presence.rst +++ b/drafts/model/presence.rst @@ -5,14 +5,14 @@ A simple implementation of presence messaging has the ability to cause a large amount of Internet traffic relating to presence updates. In order to minimise the impact of such a feature, the following observations can be made: - * There is no point in a Home Server polling status for peers in a user's + * There is no point in a homeserver polling status for peers in a user's presence list if the user has no clients connected that care about it. * It is highly likely that most presence subscriptions will be symmetric - a given user watching another is likely to in turn be watched by that user. * It is likely that most subscription pairings will be between users who share - at least one Room in common, and so their Home Servers are actively + at least one Room in common, and so their homeservers are actively exchanging message PDUs or transactions relating to that Room. * Presence update messages do not need realtime guarantees. It is acceptable to @@ -25,7 +25,7 @@ promise to send them when required. Rather than actively polling for the current state all the time, HSes can rely on their relative stability to only push updates when required. -A Home Server should not rely on the longterm validity of this presence +A homeserver should not rely on the longterm validity of this presence information, however, as this would not cover such cases as a user's server crashing and thus failing to inform their peers that users it used to host are no longer available online. Therefore, each promise of future updates should @@ -33,7 +33,7 @@ carry with a timeout value (whether explicit in the message, or implicit as some defined default in the protocol), after which the receiving HS should consider the information potentially stale and request it again. -However, because of the likelihood that two home servers are exchanging messages +However, because of the likelihood that two homeservers are exchanging messages relating to chat traffic in a room common to both of them, the ongoing receipt of these messages can be taken by each server as an implicit notification that the sending server is still up and running, and therefore that no status changes @@ -98,7 +98,7 @@ The data model presented here puts the following requirements on the APIs: Client-Server ------------- -Requests that a client can make to its Home Server +Requests that a client can make to its homeserver * get/set current presence state Basic enumeration + ability to set a custom piece of text @@ -128,7 +128,7 @@ Requests that a client can make to its Home Server Server-Server ------------- -Requests that Home Servers make to others +Requests that homeservers make to others * request permission to add a user to presence list diff --git a/drafts/model/profiles.rst b/drafts/model/profiles.rst index 15f65feb..f81e115e 100644 --- a/drafts/model/profiles.rst +++ b/drafts/model/profiles.rst @@ -9,7 +9,7 @@ Overview ======== Internally within Synapse users are referred to by an opaque ID, which consists -of some opaque localpart combined with the domain name of their home server. +of some opaque localpart combined with the domain name of their homeserver. Obviously this does not yield a very nice user experience; users would like to see readable names for other users that are in some way meaningful to them. Additionally, users like to be able to publish "profile" details to inform other @@ -59,7 +59,7 @@ servers should be accounted for here.]] Visibility Permissions ====================== -A home server implementation could offer the ability to set permissions on +A homeserver implementation could offer the ability to set permissions on limited visibility of those fields. When another user requests access to the target user's profile, their own identity should form part of that request. The HS implementation can then decide which fields to make available to the @@ -130,12 +130,12 @@ namespace to allocate names into. It would also be nice from a user experience perspective if the profile that a given name links to can also declare that name as part of its metadata. Furthermore as a security and consistency perspective it would be nice if each -end (the directory server and the user's home server) check the validity of the +end (the directory server and the user's homeserver) check the validity of the mapping in some way. This needs investigation from a security perspective to ensure against spoofing. One such model may be that the user starts by declaring their intent to use a -given user name link to their home server, which then contacts the directory +given user name link to their homeserver, which then contacts the directory service. At some point later (maybe immediately for "public open FCFS servers", maybe after some kind of human intervention for verification) the DS decides to honour this link, and includes it in its served output. It should also tell the @@ -170,7 +170,7 @@ balancing choice on behalf of the user who would choose, or not, to make use of such a feature to publish their information. Additionally, unless some form of strong end-to-end user-based encryption is -used, a user of ACLs for information privacy has to trust other home servers not +used, a user of ACLs for information privacy has to trust other homeservers not to lie about the identify of the user requesting access to the Profile. @@ -182,7 +182,7 @@ The data model presented here puts the following requirements on the APIs: Client-Server ------------- -Requests that a client can make to its Home Server +Requests that a client can make to its homeserver * get/set my Display Name This should return/take a simple "text/plain" field @@ -207,7 +207,7 @@ TODO(paul): At some later stage we should consider the API for: Server-Server ------------- -Requests that Home Servers make to others +Requests that homeservers make to others * get a user's Display Name / Avatar @@ -221,7 +221,7 @@ Requests that Home Servers make to others Room Event PDU Types -------------------- -Events that are pushed from Home Servers to other Home Servers or clients. +Events that are pushed from homeservers to other homeservers or clients. * user Display Name change diff --git a/drafts/model/room-join-workflow.rst b/drafts/model/room-join-workflow.rst index c321a64f..ff469740 100644 --- a/drafts/model/room-join-workflow.rst +++ b/drafts/model/room-join-workflow.rst @@ -8,7 +8,7 @@ Discovery ========= To join a room, a user has to discover the room by some mechanism in order to -obtain the (opaque) Room ID and a candidate list of likely home servers that +obtain the (opaque) Room ID and a candidate list of likely homeservers that contain it. Sending an Invitation @@ -21,7 +21,7 @@ The inviter's HS sets the membership status of the invitee to "invited" in the "m.members" state key by sending a state update PDU. The HS then broadcasts this PDU among the existing members in the usual way. An invitation message is also sent to the invited user, containing the Room ID and the PDU ID of this -invitation state change and potentially a list of some other home servers to use +invitation state change and potentially a list of some other homeservers to use to accept the invite. The user's client can then choose to display it in some way to alert the user. @@ -34,7 +34,7 @@ Directory Service Alternatively, the user may discover the channel via a directory service; either by performing a name lookup, or some kind of browse or search acitivty. However -this is performed, the end result is that the user's home server requests the +this is performed, the end result is that the user's homeserver requests the Room ID and candidate list from the directory service. [[TODO(paul): At present, no API has been designed or described for this @@ -44,14 +44,14 @@ directory service]] Joining ======= -Once the ID and home servers are obtained, the user can then actually join the +Once the ID and homeservers are obtained, the user can then actually join the room. Accepting an Invite ------------------- If a user has received and accepted an invitation to join a room, the invitee's -home server can now send an invite acceptance message to a chosen candidate +homeserver can now send an invite acceptance message to a chosen candidate server from the list given in the invitation, citing also the PDU ID of the invitation as "proof" of their invite. (This is required as due to late message propagation it could be the case that the acceptance is received before the @@ -85,7 +85,7 @@ can instead post a "knock" message, which informs other members of the room that the would-be joiner wishes to become a member and sets their membership value to "knocked". If any of them wish to accept this, they can then send an invitation in the usual way described above. Knowing that the user has already knocked and -expressed an interest in joining, the invited user's home server should +expressed an interest in joining, the invited user's homeserver should immediately accept that invitation on the user's behalf, and go on to join the room in the usual way. diff --git a/drafts/model/rooms.rst b/drafts/model/rooms.rst index 07c5e71f..2f57f2bc 100644 --- a/drafts/model/rooms.rst +++ b/drafts/model/rooms.rst @@ -18,19 +18,19 @@ users, and other management and miscellaneous metadata), and a message history. Room Identity and Naming ======================== -Rooms can be arbitrarily created by any user on any home server; at which point -the home server will sign the message that creates the channel, and the +Rooms can be arbitrarily created by any user on any homeserver; at which point +the homeserver will sign the message that creates the channel, and the fingerprint of this signature becomes the strong persistent identify of the -room. This now identifies the room to any home server in the network regardless +room. This now identifies the room to any homeserver in the network regardless of its original origin. This allows the identify of the room to outlive any particular server. Subject to appropriate permissions [to be discussed later], any current member of a room can invite others to join it, can post messages that become part of its history, and can change the persistent state of the room (including its current set of permissions). -Home servers can provide a directory service, allowing a lookup from a +Homeservers can provide a directory service, allowing a lookup from a convenient human-readable form of room label to a room ID. This mapping is -scoped to the particular home server domain and so simply represents that server +scoped to the particular homeserver domain and so simply represents that server administrator's opinion of what room should take that label; it does not have to be globally replicated and does not form part of the stored state of that room. @@ -156,7 +156,7 @@ m.public_history to be a member of the room. m.archive_servers - For "public" rooms with public history, gives a list of home servers that + For "public" rooms with public history, gives a list of homeservers that should be included in message distribution to the room, even if no users on that server are present. These ensure that a public room can still persist even if no users are currently members of it. This list should be consulted by @@ -179,7 +179,7 @@ m.topic Room Creation Templates ======================= -A client (or maybe home server?) could offer a few templates for the creation of +A client (or maybe homeserver?) could offer a few templates for the creation of new rooms. For example, for a simple private one-to-one chat the channel could assign the creator a power-level of 1, requiring a level of 1 to invite, and needing an invite before members can join. An invite is then sent to the other @@ -215,7 +215,7 @@ permissions to allow this direct messaging. Between any given pair of user IDs that wish to exchange private messages, there will exist a single shared Room, created lazily by either side. These rooms will -need a certain amount of special handling in both home servers and display on +need a certain amount of special handling in both homeservers and display on clients, but as much as possible should be treated by the lower layers of code the same as other rooms. @@ -226,7 +226,7 @@ clients should display these in a special way too as the room name is not important; instead it should distinguish them on the Display Name of the other party. -Home Servers will need a client-API option to request setting up a new user-user +Homeservers will need a client-API option to request setting up a new user-user chat room, which will then need special handling within the server. It will create a new room with the following @@ -260,7 +260,7 @@ history with each other simultaneously create a room and invite the other to it. This is called a "glare" situation. There are two possible ideas for how to resolve this: - * Each Home Server should persist the mapping of (user ID pair) to room ID, so + * Each homeserver should persist the mapping of (user ID pair) to room ID, so that duplicate requests can be suppressed. On receipt of a room creation request that the HS thinks there already exists a room for, the invitation to join can be rejected if: diff --git a/drafts/model/third-party-id.rst b/drafts/model/third-party-id.rst index 1f8138dd..838a6799 100644 --- a/drafts/model/third-party-id.rst +++ b/drafts/model/third-party-id.rst @@ -66,7 +66,7 @@ Privacy A User may publish the association between their phone number and Matrix User ID on the Identity Server without publishing the number in their Profile hosted on -their Home Server. +their homeserver. Identity Servers should refrain from publishing reverse mappings and should take steps, such as rate limiting, to prevent attackers enumerating the space of diff --git a/event-schemas/check_examples.py b/event-schemas/check_examples.py index 5a409407..0e879541 100755 --- a/event-schemas/check_examples.py +++ b/event-schemas/check_examples.py @@ -38,13 +38,12 @@ def check_example_file(examplepath, schemapath): schema = yaml.load(f) fileurl = "file://" + os.path.abspath(schemapath) + schema["id"] = fileurl + resolver = jsonschema.RefResolver(schemapath, schema, handlers={"file": load_yaml}) print ("Checking schema for: %r %r" % (examplepath, schemapath)) - # Setting the 'id' tells jsonschema where the file is so that it - # can correctly resolve relative $ref references in the schema - schema['id'] = fileurl try: - jsonschema.validate(example, schema) + jsonschema.validate(example, schema, resolver=resolver) except Exception as e: raise ValueError("Error validating JSON schema for %r %r" % ( examplepath, schemapath @@ -71,6 +70,15 @@ def check_example_dir(exampledir, schemadir): if errors: raise ValueError("Error validating examples") + +def load_yaml(path): + if not path.startswith("file:///"): + raise Exception("Bad ref: %s" % (path,)) + path = path[len("file://"):] + with open(path, "r") as f: + return yaml.load(f) + + if __name__ == '__main__': try: check_example_dir("examples", "schema") diff --git a/event-schemas/examples/m.call.answer b/event-schemas/examples/m.call.answer index 0301fb3b..f7d14439 100644 --- a/event-schemas/examples/m.call.answer +++ b/event-schemas/examples/m.call.answer @@ -13,5 +13,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.call.answer", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.call.candidates b/event-schemas/examples/m.call.candidates index 389d2271..8e6849bb 100644 --- a/event-schemas/examples/m.call.candidates +++ b/event-schemas/examples/m.call.candidates @@ -15,5 +15,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.call.candidates", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.call.hangup b/event-schemas/examples/m.call.hangup index 52ddad16..42e1f346 100644 --- a/event-schemas/examples/m.call.hangup +++ b/event-schemas/examples/m.call.hangup @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.call.hangup", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.call.invite b/event-schemas/examples/m.call.invite index 2df25929..974a5b4c 100644 --- a/event-schemas/examples/m.call.invite +++ b/event-schemas/examples/m.call.invite @@ -13,5 +13,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.call.invite", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.aliases b/event-schemas/examples/m.room.aliases index 07b4b330..ca87510e 100644 --- a/event-schemas/examples/m.room.aliases +++ b/event-schemas/examples/m.room.aliases @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.aliases", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.avatar b/event-schemas/examples/m.room.avatar index 9fb1189c..2080d96e 100644 --- a/event-schemas/examples/m.room.avatar +++ b/event-schemas/examples/m.room.avatar @@ -14,5 +14,5 @@ "type": "m.room.avatar", "state_key": "", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.canonical_alias b/event-schemas/examples/m.room.canonical_alias index 0203a851..59df586d 100644 --- a/event-schemas/examples/m.room.canonical_alias +++ b/event-schemas/examples/m.room.canonical_alias @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.canonical_alias", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.create b/event-schemas/examples/m.room.create index a3598853..34dabb53 100644 --- a/event-schemas/examples/m.room.create +++ b/event-schemas/examples/m.room.create @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.create", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.guest_access b/event-schemas/examples/m.room.guest_access index 8ad4d294..c636ff39 100644 --- a/event-schemas/examples/m.room.guest_access +++ b/event-schemas/examples/m.room.guest_access @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEG:localhost", "type": "m.room.guest_access", "room_id": "!Cuyf34gef24u:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.history_visibility b/event-schemas/examples/m.room.history_visibility index fcc3f881..6fedc5dc 100644 --- a/event-schemas/examples/m.room.history_visibility +++ b/event-schemas/examples/m.room.history_visibility @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.history_visibility", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.join_rules b/event-schemas/examples/m.room.join_rules index f22ad97e..39e14fc5 100644 --- a/event-schemas/examples/m.room.join_rules +++ b/event-schemas/examples/m.room.join_rules @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.join_rules", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.member b/event-schemas/examples/m.room.member index e2ca5668..133cad96 100644 --- a/event-schemas/examples/m.room.member +++ b/event-schemas/examples/m.room.member @@ -26,5 +26,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.member", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.member#invite_room_state b/event-schemas/examples/m.room.member#invite_room_state index e2ca5668..133cad96 100644 --- a/event-schemas/examples/m.room.member#invite_room_state +++ b/event-schemas/examples/m.room.member#invite_room_state @@ -26,5 +26,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.member", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.member#third_party_invite b/event-schemas/examples/m.room.member#third_party_invite index 2457302a..1bae2e9f 100644 --- a/event-schemas/examples/m.room.member#third_party_invite +++ b/event-schemas/examples/m.room.member#third_party_invite @@ -21,5 +21,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.member", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.message#m.audio b/event-schemas/examples/m.room.message#m.audio index b57adc9a..367eb954 100644 --- a/event-schemas/examples/m.room.message#m.audio +++ b/event-schemas/examples/m.room.message#m.audio @@ -14,5 +14,5 @@ "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "type": "m.room.message", - "user_id": "@example:localhost" -} \ No newline at end of file + "sender": "@example:localhost" +} diff --git a/event-schemas/examples/m.room.message#m.emote b/event-schemas/examples/m.room.message#m.emote index bd984831..4280928e 100644 --- a/event-schemas/examples/m.room.message#m.emote +++ b/event-schemas/examples/m.room.message#m.emote @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.message", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.message#m.file b/event-schemas/examples/m.room.message#m.file index 7ac36c90..e52c3a94 100644 --- a/event-schemas/examples/m.room.message#m.file +++ b/event-schemas/examples/m.room.message#m.file @@ -14,5 +14,5 @@ "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "type": "m.room.message", - "user_id": "@example:localhost" -} \ No newline at end of file + "sender": "@example:localhost" +} diff --git a/event-schemas/examples/m.room.message#m.image b/event-schemas/examples/m.room.message#m.image index ba405a1a..91e72be2 100644 --- a/event-schemas/examples/m.room.message#m.image +++ b/event-schemas/examples/m.room.message#m.image @@ -15,5 +15,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.message", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.message#m.location b/event-schemas/examples/m.room.message#m.location index 54198acb..fcbeb97e 100644 --- a/event-schemas/examples/m.room.message#m.location +++ b/event-schemas/examples/m.room.message#m.location @@ -16,5 +16,5 @@ "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "type": "m.room.message", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.message#m.notice b/event-schemas/examples/m.room.message#m.notice index 2e5fff97..978c67e6 100644 --- a/event-schemas/examples/m.room.message#m.notice +++ b/event-schemas/examples/m.room.message#m.notice @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.message", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.message#m.text b/event-schemas/examples/m.room.message#m.text index d877ee64..e00c7aa5 100644 --- a/event-schemas/examples/m.room.message#m.text +++ b/event-schemas/examples/m.room.message#m.text @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.message", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.message#m.video b/event-schemas/examples/m.room.message#m.video index e3da9077..576d80de 100644 --- a/event-schemas/examples/m.room.message#m.video +++ b/event-schemas/examples/m.room.message#m.video @@ -23,5 +23,5 @@ "origin_server_ts": 1432735824653, "room_id": "!jEsUZKDJdhlrceRyVU:localhost", "type": "m.room.message", - "user_id": "@example:localhost" -} \ No newline at end of file + "sender": "@example:localhost" +} diff --git a/event-schemas/examples/m.room.message.feedback b/event-schemas/examples/m.room.message.feedback index 6282305b..16fe0ee0 100644 --- a/event-schemas/examples/m.room.message.feedback +++ b/event-schemas/examples/m.room.message.feedback @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.message.feedback", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.name b/event-schemas/examples/m.room.name index 636119b8..87db2008 100644 --- a/event-schemas/examples/m.room.name +++ b/event-schemas/examples/m.room.name @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.name", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.power_levels b/event-schemas/examples/m.room.power_levels index 8278597a..42ef5a5d 100644 --- a/event-schemas/examples/m.room.power_levels +++ b/event-schemas/examples/m.room.power_levels @@ -20,5 +20,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.power_levels", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.redaction b/event-schemas/examples/m.room.redaction index 2e8260ea..5f4aae1e 100644 --- a/event-schemas/examples/m.room.redaction +++ b/event-schemas/examples/m.room.redaction @@ -8,5 +8,5 @@ "type": "m.room.redaction", "room_id": "!Cuyf34gef24t:localhost", "redacts": "!fukweghifu23:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.room.topic b/event-schemas/examples/m.room.topic index 8a469122..65daa987 100644 --- a/event-schemas/examples/m.room.topic +++ b/event-schemas/examples/m.room.topic @@ -8,5 +8,5 @@ "event_id": "$WLGTSEFSEF:localhost", "type": "m.room.topic", "room_id": "!Cuyf34gef24t:localhost", - "user_id": "@example:localhost" + "sender": "@example:localhost" } diff --git a/event-schemas/examples/m.typing b/event-schemas/examples/m.typing index bd53f6fb..1d2c517b 100644 --- a/event-schemas/examples/m.typing +++ b/event-schemas/examples/m.typing @@ -4,4 +4,4 @@ "content": { "user_ids": ["@alice:matrix.org", "@bob:example.com"] } -} \ No newline at end of file +} diff --git a/event-schemas/schema/core-event-schema/event.json b/event-schemas/schema/core-event-schema/event.json deleted file mode 100644 index f9103715..00000000 --- a/event-schemas/schema/core-event-schema/event.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "type": "object", - "title": "Event", - "description": "The basic set of fields all events must have.", - "properties": { - "content": { - "type": "object", - "title": "EventContent", - "description": "The fields in this object will vary depending on the type of event. When interacting with the REST API, this is the HTTP body." - }, - "type": { - "type": "string", - "description": "The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. 'com.example.subdomain.event.type'" - } - } -} diff --git a/event-schemas/schema/core-event-schema/event.yaml b/event-schemas/schema/core-event-schema/event.yaml new file mode 100644 index 00000000..ebf67aa3 --- /dev/null +++ b/event-schemas/schema/core-event-schema/event.yaml @@ -0,0 +1,13 @@ +description: The basic set of fields all events must have. +properties: + content: + description: The fields in this object will vary depending on the type of event. + When interacting with the REST API, this is the HTTP body. + title: EventContent + type: object + type: + description: The type of event. This SHOULD be namespaced similar to Java package + naming conventions e.g. 'com.example.subdomain.event.type' + type: string +title: Event +type: object diff --git a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.json b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.json deleted file mode 100644 index ee75745e..00000000 --- a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "ImageInfo", - "description": "Metadata about an image.", - "properties": { - "size": { - "type": "integer", - "description": "Size of the image in bytes." - }, - "w": { - "type": "integer", - "description": "The width of the image in pixels." - }, - "h": { - "type": "integer", - "description": "The height of the image in pixels." - }, - "mimetype": { - "type": "string", - "description": "The mimetype of the image, e.g. ``image/jpeg``." - } - } -} diff --git a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml new file mode 100644 index 00000000..7ef7a86f --- /dev/null +++ b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml @@ -0,0 +1,16 @@ +$schema: http://json-schema.org/draft-04/schema# +description: Metadata about an image. +properties: + h: + description: The height of the image in pixels. + type: integer + mimetype: + description: The mimetype of the image, e.g. ``image/jpeg``. + type: string + size: + description: Size of the image in bytes. + type: integer + w: + description: The width of the image in pixels. + type: integer +title: ImageInfo diff --git a/event-schemas/schema/core-event-schema/room_event.json b/event-schemas/schema/core-event-schema/room_event.json deleted file mode 100644 index 80f7d265..00000000 --- a/event-schemas/schema/core-event-schema/room_event.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "type": "object", - "title": "Room Event", - "description": "In addition to the Event fields, Room Events MUST have the following additional field.", - "allOf":[{ - "$ref": "event.json" - }], - "properties": { - "room_id": { - "type": "string", - "description": "The ID of the room associated with this event." - }, - "event_id": { - "type": "string", - "description": "The globally unique event identifier." - }, - "user_id": { - "type": "string", - "description": "Contains the fully-qualified ID of the user who *sent* this event." - } - }, - "required": ["room_id"] -} diff --git a/event-schemas/schema/core-event-schema/room_event.yaml b/event-schemas/schema/core-event-schema/room_event.yaml new file mode 100644 index 00000000..96c16031 --- /dev/null +++ b/event-schemas/schema/core-event-schema/room_event.yaml @@ -0,0 +1,37 @@ +allOf: +- $ref: event.yaml +description: In addition to the Event fields, Room Events may have the following additional + fields. +properties: + event_id: + description: Required. The globally unique event identifier. + type: string + room_id: + description: Required. The ID of the room associated with this event. + type: string + sender: + description: Required. Contains the fully-qualified ID of the user who *sent* + this event. + type: string + unsigned: + description: Contains optional extra information about the event. + properties: + age: + description: The time in milliseconds that has elapsed since the event was + sent + type: integer + redacted_because: + description: The reason this event was redacted, if it was redacted + type: string + transaction_id: + description: The client-supplied transaction ID, if the client being given + the event is the same one which sent it. + type: string + title: UnsignedData + type: object +required: +- event_id +- room_id +- sender +title: Room Event +type: object diff --git a/event-schemas/schema/core-event-schema/state_event.json b/event-schemas/schema/core-event-schema/state_event.json deleted file mode 100644 index cfcb212c..00000000 --- a/event-schemas/schema/core-event-schema/state_event.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "object", - "title": "State Event", - "description": "In addition to the Room Event fields, State Events have the following additional fields.", - "allOf":[{ - "$ref": "room_event.json" - }], - "properties": { - "state_key": { - "type": "string", - "description": "A unique key which defines the overwriting semantics for this piece of room state. This value is often a zero-length string. The presence of this key makes this event a State Event. The key MUST NOT start with '_'." - }, - "prev_content": { - "title": "EventContent", - "type": "object", - "description": "Optional. The previous ``content`` for this event. If there is no previous content, this key will be missing." - } - }, - "required": ["state_key"] -} diff --git a/event-schemas/schema/core-event-schema/state_event.yaml b/event-schemas/schema/core-event-schema/state_event.yaml new file mode 100644 index 00000000..020e9087 --- /dev/null +++ b/event-schemas/schema/core-event-schema/state_event.yaml @@ -0,0 +1,19 @@ +allOf: +- $ref: room_event.yaml +description: In addition to the Room Event fields, State Events have the following + additional fields. +properties: + prev_content: + description: Optional. The previous ``content`` for this event. If there is no + previous content, this key will be missing. + title: EventContent + type: object + state_key: + description: A unique key which defines the overwriting semantics for this piece + of room state. This value is often a zero-length string. The presence of this + key makes this event a State Event. The key MUST NOT start with '_'. + type: string +required: +- state_key +title: State Event +type: object diff --git a/event-schemas/schema/m.call.answer b/event-schemas/schema/m.call.answer index f11a61ba..9d98dd7d 100644 --- a/event-schemas/schema/m.call.answer +++ b/event-schemas/schema/m.call.answer @@ -2,7 +2,7 @@ "type": "object", "description": "This event is sent by the callee when they wish to answer the call.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.call.candidates b/event-schemas/schema/m.call.candidates index 52e06705..7426717c 100644 --- a/event-schemas/schema/m.call.candidates +++ b/event-schemas/schema/m.call.candidates @@ -2,7 +2,7 @@ "type": "object", "description": "This event is sent by callers after sending an invite and by the callee after answering. Its purpose is to give the other party additional ICE candidates to try using to communicate.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.call.hangup b/event-schemas/schema/m.call.hangup index 02667635..9d45d179 100644 --- a/event-schemas/schema/m.call.hangup +++ b/event-schemas/schema/m.call.hangup @@ -2,7 +2,7 @@ "type": "object", "description": "Sent by either party to signal their termination of the call. This can be sent either once the call has has been established or before to abort the call.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.call.invite b/event-schemas/schema/m.call.invite index 585403d0..ebf09267 100644 --- a/event-schemas/schema/m.call.invite +++ b/event-schemas/schema/m.call.invite @@ -2,7 +2,7 @@ "type": "object", "description": "This event is sent by the caller when they wish to establish a call.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.aliases b/event-schemas/schema/m.room.aliases index 43cc9dbc..a3427703 100644 --- a/event-schemas/schema/m.room.aliases +++ b/event-schemas/schema/m.room.aliases @@ -3,7 +3,7 @@ "title": "Informs the room about what room aliases it has been given.", "description": "This event is sent by a homeserver directly to inform of changes to the list of aliases it knows about for that room. The ``state_key`` for this event is set to the homeserver which owns the room alias. The entire set of known aliases for the room is the union of all the ``m.room.aliases`` events, one for each homeserver. Clients **should** check the validity of any room alias given in this list before presenting it to the user as trusted fact. The lists given by this event should be considered simply as advice on which aliases might exist, for which the client can perform the lookup to confirm whether it receives the correct room ID.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.avatar b/event-schemas/schema/m.room.avatar index 276c975c..60a3e1b6 100644 --- a/event-schemas/schema/m.room.avatar +++ b/event-schemas/schema/m.room.avatar @@ -3,7 +3,7 @@ "description": "A picture that is associated with the room. This can be displayed alongside the room information.", "type": "object", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { @@ -22,7 +22,7 @@ "title": "ImageInfo", "description": "Metadata about the image referred to in ``thumbnail_url``.", "allOf": [{ - "$ref": "core-event-schema/msgtype_infos/image_info.json" + "$ref": "core-event-schema/msgtype_infos/image_info.yaml" }] }, "info": { diff --git a/event-schemas/schema/m.room.canonical_alias b/event-schemas/schema/m.room.canonical_alias index 49e0e669..4d6f956b 100644 --- a/event-schemas/schema/m.room.canonical_alias +++ b/event-schemas/schema/m.room.canonical_alias @@ -3,7 +3,7 @@ "title": "Informs the room as to which alias is the canonical one.", "description": "This event is used to inform the room about which alias should be considered the canonical one. This could be for display purposes or as suggestion to users which alias to use to advertise the room.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.create b/event-schemas/schema/m.room.create index 348b6d86..13e5513c 100644 --- a/event-schemas/schema/m.room.create +++ b/event-schemas/schema/m.room.create @@ -3,7 +3,7 @@ "title": "The first event in the room.", "description": "This is the first event in a room and cannot be changed. It acts as the root of all other events.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.guest_access b/event-schemas/schema/m.room.guest_access index a0141f37..c7ef9026 100644 --- a/event-schemas/schema/m.room.guest_access +++ b/event-schemas/schema/m.room.guest_access @@ -3,7 +3,7 @@ "title": "Controls whether guest users are allowed to join rooms.", "description": "This event controls whether guest users are allowed to join rooms. If this event is absent, servers should act as if it is present and has the guest_access value \"forbidden\".", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.history_visibility b/event-schemas/schema/m.room.history_visibility index 9abcf5b8..aaf25261 100644 --- a/event-schemas/schema/m.room.history_visibility +++ b/event-schemas/schema/m.room.history_visibility @@ -3,7 +3,7 @@ "title": "Controls visibility of history.", "description": "This event controls whether a user can see the events that happened in a room from before they joined.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.join_rules b/event-schemas/schema/m.room.join_rules index 70c36ccb..680d6f60 100644 --- a/event-schemas/schema/m.room.join_rules +++ b/event-schemas/schema/m.room.join_rules @@ -3,7 +3,7 @@ "title": "Describes how users are allowed to join the room.", "description": "A room may be ``public`` meaning anyone can join the room without any prior action. Alternatively, it can be ``invite`` meaning that a user who wishes to join the room must first receive an invite to the room from someone already inside of the room. Currently, ``knock`` and ``private`` are reserved keywords which are not implemented.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.member b/event-schemas/schema/m.room.member index 25b30109..28a49c3a 100644 --- a/event-schemas/schema/m.room.member +++ b/event-schemas/schema/m.room.member @@ -3,7 +3,7 @@ "title": "The current membership state of a user in the room.", "description": "Adjusts the membership state for a user in a room. It is preferable to use the membership APIs (``/rooms//invite`` etc) when performing membership actions rather than adjusting the state directly as there are a restricted set of valid transformations. For example, user A cannot force user B to join a room, and trying to force this state change directly will fail. \n\nThe ``third_party_invite`` property will be set if this invite is an ``invite`` event and is the successor of an ``m.room.third_party_invite`` event, and absent otherwise.\n\nThis event may also include an ``invite_room_state`` key **outside the** ``content`` **key**. If present, this contains an array of ``StrippedState`` Events. These events provide information on a few select state events such as the room name.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { @@ -30,6 +30,7 @@ "signed": { "type": "object", "title": "signed", + "description": "A block of content which has been signed, which servers can use to verify the event. Clients should ignore this.", "properties": { "mxid": { "type": "string", @@ -41,7 +42,7 @@ }, "signatures": { "type": "object", - "description": "A single signature from the verifying server, in the format specified by the Signing Events section.", + "description": "A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API.", "title": "Signatures" } }, diff --git a/event-schemas/schema/m.room.message b/event-schemas/schema/m.room.message index 91c04b7f..82de26a8 100644 --- a/event-schemas/schema/m.room.message +++ b/event-schemas/schema/m.room.message @@ -3,7 +3,7 @@ "title": "Message", "description": "This event is used when sending messages in a room. Messages are not limited to be text. The ``msgtype`` key outlines the type of message, e.g. text, audio, image, video, etc. The ``body`` key is text and MUST be used with every kind of ``msgtype`` as a fallback mechanism for when a client cannot render a message. This allows clients to display *something* even if it is just plain text.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.message#m.audio b/event-schemas/schema/m.room.message#m.audio index 0a6625f5..cd55426c 100644 --- a/event-schemas/schema/m.room.message#m.audio +++ b/event-schemas/schema/m.room.message#m.audio @@ -3,7 +3,7 @@ "title": "AudioMessage", "description": "This message represents a single audio clip.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.message#m.emote b/event-schemas/schema/m.room.message#m.emote index 690600f4..8fa63951 100644 --- a/event-schemas/schema/m.room.message#m.emote +++ b/event-schemas/schema/m.room.message#m.emote @@ -3,7 +3,7 @@ "title": "EmoteMessage", "description": "This message is similar to ``m.text`` except that the sender is 'performing' the action contained in the ``body`` key, similar to ``/me`` in IRC. This message should be prefixed by the name of the sender. This message could also be represented in a different colour to distinguish it from regular ``m.text`` messages.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.message#m.file b/event-schemas/schema/m.room.message#m.file index c97480ef..f921b23f 100644 --- a/event-schemas/schema/m.room.message#m.file +++ b/event-schemas/schema/m.room.message#m.file @@ -3,7 +3,7 @@ "title": "FileMessage", "description": "This message represents a generic file.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { @@ -49,7 +49,7 @@ "title": "ImageInfo", "description": "Metadata about the image referred to in ``thumbnail_url``.", "allOf": [{ - "$ref": "core-event-schema/msgtype_infos/image_info.json" + "$ref": "core-event-schema/msgtype_infos/image_info.yaml" }] } }, diff --git a/event-schemas/schema/m.room.message#m.image b/event-schemas/schema/m.room.message#m.image index af78096d..1085bb85 100644 --- a/event-schemas/schema/m.room.message#m.image +++ b/event-schemas/schema/m.room.message#m.image @@ -3,7 +3,7 @@ "title": "ImageMessage", "description": "This message represents a single image and an optional thumbnail.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { @@ -30,7 +30,7 @@ "title": "ImageInfo", "description": "Metadata about the image referred to in ``thumbnail_url``.", "allOf": [{ - "$ref": "core-event-schema/msgtype_infos/image_info.json" + "$ref": "core-event-schema/msgtype_infos/image_info.yaml" }] }, "info": { diff --git a/event-schemas/schema/m.room.message#m.location b/event-schemas/schema/m.room.message#m.location index ef4b5e81..7deb6f8d 100644 --- a/event-schemas/schema/m.room.message#m.location +++ b/event-schemas/schema/m.room.message#m.location @@ -3,7 +3,7 @@ "title": "LocationMessage", "description": "This message represents a real-world location.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { @@ -29,7 +29,7 @@ "type": "object", "title": "ImageInfo", "allOf": [{ - "$ref": "core-event-schema/msgtype_infos/image_info.json" + "$ref": "core-event-schema/msgtype_infos/image_info.yaml" }] } }, diff --git a/event-schemas/schema/m.room.message#m.notice b/event-schemas/schema/m.room.message#m.notice index 195c56a3..100c3d60 100644 --- a/event-schemas/schema/m.room.message#m.notice +++ b/event-schemas/schema/m.room.message#m.notice @@ -3,7 +3,7 @@ "title": "NoticeMessage", "description": "A m.notice message should be considered similar to a plain m.text message except that clients should visually distinguish it in some way. It is intended to be used by automated clients, such as bots, bridges, and other entities, rather than humans. Additionally, such automated agents which watch a room for messages and respond to them ought to ignore m.notice messages. This helps to prevent infinite-loop situations where two automated clients continuously exchange messages, as each responds to the other.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.message#m.text b/event-schemas/schema/m.room.message#m.text index de59cf0e..0b638113 100644 --- a/event-schemas/schema/m.room.message#m.text +++ b/event-schemas/schema/m.room.message#m.text @@ -3,7 +3,7 @@ "title": "TextMessage", "description": "This message is the most basic message and is used to represent text.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.message#m.video b/event-schemas/schema/m.room.message#m.video index ad68e72a..6381543f 100644 --- a/event-schemas/schema/m.room.message#m.video +++ b/event-schemas/schema/m.room.message#m.video @@ -3,7 +3,7 @@ "title": "VideoMessage", "description": "This message represents a single video clip.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { @@ -54,7 +54,7 @@ "type": "object", "title": "ImageInfo", "allOf": [{ - "$ref": "core-event-schema/msgtype_infos/image_info.json" + "$ref": "core-event-schema/msgtype_infos/image_info.yaml" }] } } diff --git a/event-schemas/schema/m.room.message.feedback b/event-schemas/schema/m.room.message.feedback index 2eaed999..38e5ce05 100644 --- a/event-schemas/schema/m.room.message.feedback +++ b/event-schemas/schema/m.room.message.feedback @@ -3,7 +3,7 @@ "title": "MessageFeedback", "description": "**NB: Usage of this event is discouraged in favour of the** `receipts module`_. **Most clients will not recognise this event.** Feedback events are events sent to acknowledge a message in some way. There are two supported acknowledgements: ``delivered`` (sent when the event has been received) and ``read`` (sent when the event has been observed by the end-user). The ``target_event_id`` should reference the ``m.room.message`` event being acknowledged.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.name b/event-schemas/schema/m.room.name index 0e0b25be..9a21c26f 100644 --- a/event-schemas/schema/m.room.name +++ b/event-schemas/schema/m.room.name @@ -3,7 +3,7 @@ "description": "A room has an opaque room ID which is not human-friendly to read. A room alias is human-friendly, but not all rooms have room aliases. The room name is a human-friendly string designed to be displayed to the end-user. The room name is not unique, as multiple rooms can have the same room name set. The room name can also be set when creating a room using ``/createRoom`` with the ``name`` key.", "type": "object", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.power_levels b/event-schemas/schema/m.room.power_levels index 2ef3bfa3..e9082b7f 100644 --- a/event-schemas/schema/m.room.power_levels +++ b/event-schemas/schema/m.room.power_levels @@ -3,7 +3,7 @@ "title": "Defines the power levels (privileges) of users in the room.", "description": "This event specifies the minimum level a user must have in order to perform a certain action. It also specifies the levels of each user in the room. If a ``user_id`` is in the ``users`` list, then that ``user_id`` has the associated power level. Otherwise they have the default level ``users_default``. If ``users_default`` is not supplied, it is assumed to be 0. The level required to send a certain event is governed by ``events``, ``state_default`` and ``events_default``. If an event type is specified in ``events``, then the user must have at least the level specified in order to send that event. If the event type is not supplied, it defaults to ``events_default`` for Message Events and ``state_default`` for State Events.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.redaction b/event-schemas/schema/m.room.redaction index 5c3ef391..173969f4 100644 --- a/event-schemas/schema/m.room.redaction +++ b/event-schemas/schema/m.room.redaction @@ -3,7 +3,7 @@ "title": "Redaction", "description": "Events can be redacted by either room or server admins. Redacting an event means that all keys not required by the protocol are stripped off, allowing admins to remove offensive or illegal content that may have been attached to any event. This cannot be undone, allowing server owners to physically delete the offending data. There is also a concept of a moderator hiding a message event, which can be undone, but cannot be applied to state events. The event that has been redacted is specified in the ``redacts`` event level key.", "allOf": [{ - "$ref": "core-event-schema/room_event.json" + "$ref": "core-event-schema/room_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.third_party_invite b/event-schemas/schema/m.room.third_party_invite index ba66100f..cc11fe09 100644 --- a/event-schemas/schema/m.room.third_party_invite +++ b/event-schemas/schema/m.room.third_party_invite @@ -4,7 +4,7 @@ "title": "An invitation to a room issued to a third party identifier, rather than a matrix user ID.", "description": "Acts as an ``m.room.member`` invite event, where there isn't a target user_id to invite. This event contains a token and a public key whose private key must be used to sign the token. Any user who can present that signature may use this invitation to join the target room.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/event-schemas/schema/m.room.topic b/event-schemas/schema/m.room.topic index d13f0c23..dec649ea 100644 --- a/event-schemas/schema/m.room.topic +++ b/event-schemas/schema/m.room.topic @@ -3,7 +3,7 @@ "title": "Topic", "description": "A topic is a short message detailing what is currently being discussed in the room. It can also be used as a way to display extra information about the room, which may not be suitable for the room name. The room topic can also be set when creating a room using ``/createRoom`` with the ``topic`` key.", "allOf": [{ - "$ref": "core-event-schema/state_event.json" + "$ref": "core-event-schema/state_event.yaml" }], "properties": { "content": { diff --git a/scripts/continuserv/main.go b/scripts/continuserv/main.go index 14d0c5bf..a1295077 100644 --- a/scripts/continuserv/main.go +++ b/scripts/continuserv/main.go @@ -26,7 +26,7 @@ var ( port = flag.Int("port", 8000, "Port on which to serve HTTP") mu sync.Mutex // Prevent multiple updates in parallel. - toServe atomic.Value // Always contains valid []byte to serve. May be stale unless wg is zero. + toServe atomic.Value // Always contains a bytesOrErr. May be stale unless wg is zero. wgMu sync.Mutex // Prevent multiple calls to wg.Wait() or wg.Add(positive number) in parallel. wg sync.WaitGroup // Indicates how many updates are pending. @@ -116,14 +116,29 @@ func serve(w http.ResponseWriter, req *http.Request) { wgMu.Lock() wg.Wait() wgMu.Unlock() - b := toServe.Load().(bytesOrErr) - if b.err != nil { - w.Header().Set("Content-Type", "text/plain") - w.Write([]byte(b.err.Error())) - } else { - w.Header().Set("Content-Type", "text/html") - w.Write([]byte(b.bytes)) + + file := req.URL.Path + if file[0] == '/' { + file = file[1:] } + if file == "" { + file = "index.html" + } + m := toServe.Load().(bytesOrErr) + if m.err != nil { + w.Header().Set("Content-Type", "text/plain") + w.Write([]byte(m.err.Error())) + return + } + b, ok := m.bytes[file] + if ok { + w.Header().Set("Content-Type", "text/html") + w.Write([]byte(b)) + return + } + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(404) + w.Write([]byte("Not found")) } func populateOnce(dir string) { @@ -139,12 +154,21 @@ func populateOnce(dir string) { toServe.Store(bytesOrErr{nil, fmt.Errorf("error generating spec: %v\nOutput from gendoc:\n%v", err, b.String())}) return } - specBytes, err := ioutil.ReadFile(path.Join(dir, "scripts", "gen", "specification.html")) + fis, err := ioutil.ReadDir(path.Join(dir, "scripts", "gen")) if err != nil { - toServe.Store(bytesOrErr{nil, fmt.Errorf("error reading spec: %v", err)}) + toServe.Store(bytesOrErr{nil, err}) return } - toServe.Store(bytesOrErr{specBytes, nil}) + files := make(map[string][]byte) + for _, fi := range fis { + bytes, err := ioutil.ReadFile(path.Join(dir, "scripts", "gen", fi.Name())) + if err != nil { + toServe.Store(bytesOrErr{nil, fmt.Errorf("error reading spec: %v", err)}) + return + } + files[fi.Name()] = bytes + } + toServe.Store(bytesOrErr{files, nil}) } func doPopulate(ch chan struct{}, dir string) { @@ -173,6 +197,6 @@ func exists(path string) bool { } type bytesOrErr struct { - bytes []byte + bytes map[string][]byte // filename -> contents err error } diff --git a/scripts/dump-swagger.py b/scripts/dump-swagger.py new file mode 100755 index 00000000..22e4e10d --- /dev/null +++ b/scripts/dump-swagger.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python2 + +# dump-swagger reads all of the swagger API docs used in spec generation and +# outputs a JSON file which merges them all, for use as input to a swagger UI +# viewer. +# See https://github.com/swagger-api/swagger-ui for details of swagger-ui. + +import errno +import json +import os.path +import re +import shutil +import sys + +templating_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "templating") +sys.path.insert(0, templating_dir) +os.chdir(templating_dir) + +from matrix_templates.units import resolve_references, MatrixUnits + +if len(sys.argv) < 2 or len(sys.argv) > 3: + sys.stderr.write("usage: %s output_directory [client_release_label]\n" % (sys.argv[0],)) + sys.exit(1) + +output_directory = sys.argv[1] +release_label = sys.argv[2] if len(sys.argv) > 2 else "unstable" + +major_version = release_label +match = re.match("^(r\d)+(\.\d+)?$", major_version) +if match: + major_version = match.group(1) + +apis = MatrixUnits().load_swagger_apis() + +output = { + "basePath": "/matrix/client/" + major_version, + "consumes": ["application/json"], + "produces": ["application/json"], + "host": "localhost:8008", + "info": { + "title": "Matrix Client-Server API", + "version": release_label, + }, + "paths": {}, + "swagger": "2.0", +} + +for file, contents in apis.items(): + for path, methods in contents["paths"].items(): + for method, spec in methods.items(): + if "tags" in spec.keys(): + if path not in output["paths"]: + output["paths"][path] = {} + output["paths"][path][method] = spec + +path = os.path.join(output_directory, "api-docs") +try: + os.makedirs(os.path.dirname(path)) +except OSError as e: + if e.errno != errno.EEXIST: + raise + +with open(path, "w") as f: + text = json.dumps(output, sort_keys=True, indent=4) + text = text.replace("%CLIENT_RELEASE_LABEL%", release_label) + text = text.replace("%CLIENT_MAJOR_VERSION%", major_version) + f.write(text) diff --git a/scripts/gendoc.py b/scripts/gendoc.py index 9b87cb30..801c06bb 100755 --- a/scripts/gendoc.py +++ b/scripts/gendoc.py @@ -250,7 +250,7 @@ def addAnchors(path): f.write(line + "\n") -def run_through_template(input, set_verbose): +def run_through_template(input, set_verbose, substitutions): tmpfile = './tmp/output' try: with open(tmpfile, 'w') as out: @@ -260,6 +260,9 @@ def run_through_template(input, set_verbose): "-o", "../scripts/tmp", "../scripts/"+input ] + for k, v in substitutions.items(): + args.append("--substitution=%s=%s" % (k, v)) + if set_verbose: args.insert(2, "-v") log("EXEC: %s" % " ".join(args)) @@ -392,7 +395,7 @@ def cleanup_env(): shutil.rmtree("./tmp") -def main(requested_target_name, keep_intermediates): +def main(requested_target_name, keep_intermediates, substitutions): prepare_env() log("Building spec [target=%s]" % requested_target_name) @@ -407,7 +410,7 @@ def main(requested_target_name, keep_intermediates): target = get_build_target("../specification/targets.yaml", target_name) build_spec(target=target, out_filename=templated_file) - run_through_template(templated_file, VERBOSE) + run_through_template(templated_file, VERBOSE, substitutions) fix_relative_titles( target=target, filename=templated_file, out_filename=rst_file, @@ -417,13 +420,21 @@ def main(requested_target_name, keep_intermediates): if requested_target_name == "all": shutil.copy("../supporting-docs/howtos/client-server.rst", "tmp/howto.rst") - run_through_template("tmp/howto.rst", False) # too spammy to mark -v on this + run_through_template("tmp/howto.rst", False, substitutions) # too spammy to mark -v on this rst2html("tmp/howto.rst", "gen/howtos.html") if not keep_intermediates: cleanup_env() +def extract_major(s): + major_version = s + match = re.match("^(r\d)+(\.\d+)?$", s) + if match: + major_version = match.group(1) + return major_version + + if __name__ == '__main__': parser = ArgumentParser( "gendoc.py - Generate the Matrix specification as HTML to the gen/ folder." @@ -441,9 +452,23 @@ if __name__ == '__main__': "--verbose", "-v", action="store_true", help="Turn on verbose mode." ) + parser.add_argument( + "--client_release", "-c", action="store", default="unstable", + help="The client-server release tag to generate, e.g. r1.2" + ) + parser.add_argument( + "--server_release", "-s", action="store", default="unstable", + help="The server-server release tag to generate, e.g. r1.2" + ) args = parser.parse_args() if not args.target: parser.print_help() sys.exit(1) VERBOSE = args.verbose - main(args.target, args.nodelete) + substitutions = { + "%CLIENT_RELEASE_LABEL%": args.client_release, + "%CLIENT_MAJOR_VERSION%": extract_major(args.client_release), + "%SERVER_RELEASE_LABEL%": args.server_release, + "%SERVER_MAJOR_VERSION%": extract_major(args.server_release), + } + main(args.target, args.nodelete, substitutions) diff --git a/scripts/generate-http-docs.sh b/scripts/generate-http-docs.sh deleted file mode 100755 index b3894a2c..00000000 --- a/scripts/generate-http-docs.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -eu - -# This script generates an HTML page containing all of the client-server API docs. -# It takes all of the swagger YAML files for the client-server API, and turns -# them into API docs, with none of the narrative found in the rst files which -# normally wrap these API docs. - -cd "$(dirname $0)" - -mkdir -p tmp gen - -cat >tmp/http_apis <> tmp/http_apis -done - -(cd ../templating ; python build.py -i matrix_templates -o ../scripts/gen ../scripts/tmp/http_apis) -rst2html.py --stylesheet-path=$(echo css/*.css | tr ' ' ',') gen/http_apis > gen/http_apis.html diff --git a/scripts/speculator/main.go b/scripts/speculator/main.go index 602cdb57..94a6c0c5 100644 --- a/scripts/speculator/main.go +++ b/scripts/speculator/main.go @@ -21,6 +21,7 @@ import ( "os" "os/exec" "path" + "regexp" "strconv" "strings" "sync" @@ -71,6 +72,8 @@ const ( permissionsOwnerFull = 0700 ) +var numericRegex = regexp.MustCompile(`^\d+$`) + func gitClone(url string, shared bool) (string, error) { directory := path.Join("/tmp/matrix-doc", strconv.FormatInt(rand.Int63(), 10)) if err := os.MkdirAll(directory, permissionsOwnerFull); err != nil { @@ -101,17 +104,16 @@ func runGitCommand(path string, args []string) error { return nil } -func lookupPullRequest(url url.URL, pathPrefix string) (*PullRequest, error) { - if !strings.HasPrefix(url.Path, pathPrefix+"/") { - return nil, fmt.Errorf("invalid path passed: %s expect %s/123", url.Path, pathPrefix) - } - prNumber := strings.Split(url.Path[len(pathPrefix)+1:], "/")[0] - +func lookupPullRequest(prNumber string) (*PullRequest, error) { resp, err := http.Get(fmt.Sprintf("%s/%s", pullsPrefix, prNumber)) defer resp.Body.Close() if err != nil { return nil, fmt.Errorf("error getting pulls: %v", err) } + if resp.StatusCode != 200 { + body, _ := ioutil.ReadAll(resp.Body) + return nil, fmt.Errorf("error getting pull request %s: %v", prNumber, string(body)) + } dec := json.NewDecoder(resp.Body) var pr PullRequest if err := dec.Decode(&pr); err != nil { @@ -120,6 +122,26 @@ func lookupPullRequest(url url.URL, pathPrefix string) (*PullRequest, error) { return &pr, nil } +func (s *server) lookupBranch(branch string) (string, error) { + err := s.updateBase() + if err != nil { + log.Printf("Error fetching: %v, will use cached branches") + } + + if strings.ToLower(branch) == "head" { + branch = "master" + } + branch = "origin/" + branch + sha, err := s.getSHAOf(branch) + if err != nil { + return "", fmt.Errorf("error getting branch %s: %v", branch, err) + } + if sha == "" { + return "", fmt.Errorf("Unable to get sha for %s", branch) + } + return sha, nil +} + func generate(dir string) error { cmd := exec.Command("python", "gendoc.py", "--nodelete") cmd.Dir = path.Join(dir, "scripts") @@ -193,6 +215,15 @@ func (s *server) getSHAOf(ref string) (string, error) { return strings.TrimSpace(b.String()), nil } +// extractPRNumber checks that the path begins with the given base, and returns +// the following component. +func extractPRNumber(path, base string) (string, error) { + if !strings.HasPrefix(path, base+"/") { + return "", fmt.Errorf("invalid path passed: %q expect %s/123", path, base) + } + return strings.Split(path[len(base)+1:], "/")[0], nil +} + // extractPath extracts the file path within the gen directory which should be served for the request. // Returns one of (file to serve, path to redirect to). // path is the actual path being requested, e.g. "/spec/head/client_server.html". @@ -230,17 +261,45 @@ func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) { return } - if strings.HasPrefix(strings.ToLower(req.URL.Path), "/spec/head") { - // err may be non-nil here but if headSha is non-empty we will serve a possibly-stale result in favour of erroring. - // This is to deal with cases like where github is down but we still want to serve the spec. - if headSha, err := s.lookupHeadSHA(); headSha == "" { - writeError(w, 500, err) - return + // we use URL.EscapedPath() to get hold of the %-encoded version of the + // path, so that we can handle branch names with slashes in. + urlPath := req.URL.EscapedPath() + + if urlPath == "/spec" { + // special treatment for /spec - redirect to /spec/HEAD/ + s.redirectTo(w, req, "/spec/HEAD/") + return + } + + if !strings.HasPrefix(urlPath, "/spec/") { + writeError(w, 500, fmt.Errorf("invalid path passed: %q expect /spec/...", urlPath)) + } + + splits := strings.SplitN(urlPath[6:], "/", 2) + + if len(splits) == 1 { + // "/spec/foo" - redirect to "/spec/foo/" (so that relative links from the index work) + if splits[0] == "" { + s.redirectTo(w, req, "/spec/HEAD/") } else { - sha = headSha + s.redirectTo(w, req, urlPath+"/") } - } else { - pr, err := lookupPullRequest(*req.URL, "/spec") + return + } + + // now we have: + // splits[0] is a PR#, or a branch name + // splits[1] is the file to serve + + branchName, _ := url.QueryUnescape(splits[0]) + requestedPath, _ := url.QueryUnescape(splits[1]) + if requestedPath == "" { + requestedPath = "index.html" + } + + if numericRegex.MatchString(branchName) { + // PR number + pr, err := lookupPullRequest(branchName) if err != nil { writeError(w, 400, err) return @@ -253,6 +312,20 @@ func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) { return } sha = pr.Head.SHA + log.Printf("Serving pr %s (%s)\n", branchName, sha) + } else if strings.ToLower(branchName) == "head" || + branchName == "master" || + strings.HasPrefix(branchName, "drafts/") { + branchSHA, err := s.lookupBranch(branchName) + if err != nil { + writeError(w, 400, err) + return + } + sha = branchSHA + log.Printf("Serving branch %s (%s)\n", branchName, sha) + } else { + writeError(w, 404, fmt.Errorf("invalid branch name")) + return } var cache = specCache @@ -299,11 +372,6 @@ func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) { cache.Add(sha, pathToContent) } - requestedPath, redirect := extractPath(req.URL.Path, "/spec/") - if redirect != "" { - s.redirectTo(w, req, redirect) - return - } if b, ok := pathToContent[requestedPath]; ok { w.Write(b) return @@ -320,30 +388,14 @@ func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) { } func (s *server) redirectTo(w http.ResponseWriter, req *http.Request, path string) { - req.URL.Path = path - w.Header().Set("Location", req.URL.String()) + u := *req.URL + u.Scheme = "http" + u.Host = req.Host + u.Path = path + w.Header().Set("Location", u.String()) w.WriteHeader(302) } -// lookupHeadSHA looks up what origin/master's HEAD SHA is. -// It attempts to `git fetch` before doing so. -// If this fails, it may still return a stale sha, but will also return an error. -func (s *server) lookupHeadSHA() (sha string, retErr error) { - retErr = s.updateBase() - if retErr != nil { - log.Printf("Error fetching: %v, attempting to fall back to current known value", retErr) - } - originHead, err := s.getSHAOf("origin/master") - if err != nil { - retErr = err - } - sha = originHead - if retErr != nil && originHead != "" { - log.Printf("Successfully fell back to possibly stale sha: %s", sha) - } - return -} - func checkAuth(pr *PullRequest) error { if !pr.User.IsTrusted() { return fmt.Errorf("%q is not a trusted pull requester", pr.User.Login) @@ -352,7 +404,12 @@ func checkAuth(pr *PullRequest) error { } func (s *server) serveRSTDiff(w http.ResponseWriter, req *http.Request) { - pr, err := lookupPullRequest(*req.URL, "/diff/rst") + prNumber, err := extractPRNumber(req.URL.Path, "/diff/rst") + if err != nil { + writeError(w, 400, err) + return + } + pr, err := lookupPullRequest(prNumber) if err != nil { writeError(w, 400, err) return @@ -390,7 +447,12 @@ func (s *server) serveRSTDiff(w http.ResponseWriter, req *http.Request) { } func (s *server) serveHTMLDiff(w http.ResponseWriter, req *http.Request) { - pr, err := lookupPullRequest(*req.URL, "/diff/html") + prNumber, err := extractPRNumber(req.URL.Path, "/diff/html") + if err != nil { + writeError(w, 400, err) + return + } + pr, err := lookupPullRequest(prNumber) if err != nil { writeError(w, 400, err) return @@ -450,32 +512,86 @@ func findHTMLDiffer() (string, error) { return "", fmt.Errorf("unable to find htmldiff.pl") } -func listPulls(w http.ResponseWriter, req *http.Request) { +func getPulls() ([]PullRequest, error) { resp, err := http.Get(pullsPrefix) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + body, _ := ioutil.ReadAll(resp.Body) + return nil, fmt.Errorf("error getting pull requests: %v", string(body)) + } + dec := json.NewDecoder(resp.Body) + var pulls []PullRequest + err = dec.Decode(&pulls) + return pulls, err +} + +// getBranches returns a list of the upstream branch names. +// It attempts to `git fetch` before doing so. +func (s *server) getBranches() ([]string, error) { + err := s.updateBase() + if err != nil { + log.Printf("Error fetching: %v, will use cached branches") + } + + cmd := exec.Command("git", "branch", "-r") + cmd.Dir = path.Join(s.matrixDocCloneURL) + var b bytes.Buffer + cmd.Stdout = &b + s.mu.Lock() + err = cmd.Run() + s.mu.Unlock() + if err != nil { + return nil, fmt.Errorf("Error reading branch names: %v. Output from git:\n%v", err, b.String()) + } + branches := []string{} + for _, b := range strings.Split(b.String(), "\n") { + b = strings.TrimSpace(b) + if strings.HasPrefix(b, "origin/") { + branches = append(branches, b[7:]) + } + } + return branches, nil +} + +func (srv *server) makeIndex(w http.ResponseWriter, req *http.Request) { + pulls, err := getPulls() if err != nil { writeError(w, 500, err) return } - defer resp.Body.Close() - dec := json.NewDecoder(resp.Body) - var pulls []PullRequest - if err := dec.Decode(&pulls); err != nil { + s := "
    " + for _, pull := range pulls { + s += fmt.Sprintf(`
  • %d: %s: %s: spec spec diff rst diff
  • `, + pull.Number, pull.User.HTMLURL, pull.User.Login, pull.HTMLURL, pull.Title, pull.Number, pull.Number, pull.Number) + } + s += "
" + + branches, err := srv.getBranches() + if err != nil { writeError(w, 500, err) return } - if len(pulls) == 0 { - io.WriteString(w, "No pull requests found") - return + + s += `
View the spec at:
    ` + branchNames := []string{} + for _, branch := range branches { + if strings.HasPrefix(branch, "drafts/") { + branchNames = append(branchNames, branch) + } } - s := "
      " - for _, pull := range pulls { - s += fmt.Sprintf(`
    • %d: %s: %s: spec spec diff rst diff
    • `, - pull.Number, pull.User.HTMLURL, pull.User.Login, pull.HTMLURL, pull.Title, pull.Number, pull.Number, pull.Number) - } - s += `
    ` - if *includesDir != "" { - s += `
` + branchNames = append(branchNames, "HEAD") + for _, branch := range branchNames { + href := "spec/"+url.QueryEscape(branch)+"/" + s += fmt.Sprintf(`
  • %s
  • `, href, branch) + if *includesDir != "" { + s += fmt.Sprintf(`
  • %s, styled like matrix.org
  • `, + href, branch) + } } + s += "
    " io.WriteString(w, s) } @@ -506,6 +622,7 @@ func main() { "Kegsay": true, "NegativeMjark": true, "richvdh": true, + "ara4n": true, "leonerd": true, } if err := initCache(); err != nil { @@ -521,7 +638,7 @@ func main() { http.HandleFunc("/diff/rst/", s.serveRSTDiff) http.HandleFunc("/diff/html/", forceHTML(s.serveHTMLDiff)) http.HandleFunc("/healthz", serveText("ok")) - http.HandleFunc("/", forceHTML(listPulls)) + http.HandleFunc("/", forceHTML(s.makeIndex)) fmt.Printf("Listening on port %d\n", *port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)) diff --git a/specification/application_service_api.rst b/specification/application_service_api.rst index bdf8a52e..1f442748 100644 --- a/specification/application_service_api.rst +++ b/specification/application_service_api.rst @@ -89,7 +89,7 @@ traffic to the AS is: identify the application service. The homeserver MUST enforce this. -Home Server -> Application Service API +Homeserver -> Application Service API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pushing events @@ -101,13 +101,13 @@ events. Each list of events includes a transaction ID, which works as follows: :: Typical - HS ---> AS : Home server sends events with transaction ID T. + HS ---> AS : Homeserver sends events with transaction ID T. <--- : AS sends back 200 OK. AS ACK Lost - HS ---> AS : Home server sends events with transaction ID T. + HS ---> AS : Homeserver sends events with transaction ID T. <-/- : AS 200 OK is lost. - HS ---> AS : Home server retries with the same transaction ID of T. + HS ---> AS : Homeserver retries with the same transaction ID of T. <--- : AS sends back 200 OK. If the AS had processed these events already, it can NO-OP this request (and it knows if it is the same events based on the transaction ID). @@ -145,7 +145,7 @@ this request (e.g. to join a room alias). HTTP APIs +++++++++ -This contains application service APIs which are used by the home server. All +This contains application service APIs which are used by the homeserver. All application services MUST implement these APIs. These APIs are defined below. {{application_service_http_api}} @@ -153,12 +153,12 @@ application services MUST implement these APIs. These APIs are defined below. .. _create the user: `sect:asapi-permissions`_ -Client-Server v2 API Extensions +Client-Server API Extensions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Application services can utilise a more powerful version of the +Application services can use a more powerful version of the client-server API by identifying itself as an application service to the -home server. +homeserver. Identity assertion ++++++++++++++++++ @@ -212,7 +212,7 @@ Server admin style permissions .. _sect:asapi-permissions: -The home server needs to give the application service *full control* over its +The homeserver needs to give the application service *full control* over its namespace, both for users and for room aliases. This means that the AS should be able to create/edit/delete any room alias in its namespace, as well as create/delete any user in its namespace. No additional API changes need to be @@ -281,7 +281,7 @@ an API is exposed. :: - GET /_matrix/app/v1/user?uri=$url_encoded_uri + GET /_matrix/app/%CLIENT_MAJOR_VERSION%/user?uri=$url_encoded_uri Returns 200 OK: { @@ -305,7 +305,7 @@ SHOULD be mapped in the same way as "user" URIs. :: - GET /_matrix/app/v1/alias?uri=$url_encoded_uri + GET /_matrix/app/%CLIENT_MAJOR_VERSION%/alias?uri=$url_encoded_uri Returns 200 OK: { diff --git a/specification/client_server_api.rst b/specification/client_server_api.rst index 67973c6b..c0db2355 100644 --- a/specification/client_server_api.rst +++ b/specification/client_server_api.rst @@ -7,19 +7,22 @@ support both lightweight clients which store no state and lazy-load data from the server as required - as well as heavyweight clients which maintain a full local persistent copy of server state. -This mostly describes v1 of the Client-Server API as featured in the original September -2014 launch of Matrix, apart from user-interactive authentication where it is -encouraged to move to v2, therefore this is the version documented here. -Version 2 is currently in development (as of Jan-March 2015) as an incremental -but backwards-incompatible refinement of Version 1 and will be released -shortly. - -Documentation for the old `V1 authentication -<../attic/v1_registration_login.rst>`_ is still available separately. - .. contents:: Table of Contents .. sectnum:: +Changelog +--------- + +Version of this specification: **%CLIENT_RELEASE_LABEL%**. + +{{client_server_changelog}} + +For the full historical changelog, see +https://github.com/matrix-org/matrix-doc/blob/master/changelogs/client-server.rst + +If this is an unstable snapshot, any changes since the last release may be +viewed using ``git log``. + API Standards ------------- @@ -93,41 +96,17 @@ Some requests have unique error codes: .. _sect:txn_ids: -The Client-Server API typically uses ``HTTP POST`` to submit requests. This -means these requests are not idempotent. The C-S API also allows ``HTTP PUT`` to -make requests idempotent. In order to use a ``PUT``, paths should be suffixed -with ``/{txnId}``. ``{txnId}`` is a unique client-generated transaction ID which -identifies the request, and is scoped to a given Client (identified by that -client's ``access_token``). Crucially, it **only** serves to identify new +The Client-Server API typically uses ``HTTP PUT`` to submit requests with a +client-generated transaction identifier. This means that these requests are +idempotent. The scope of a transaction identifier is a particular access token. +It **only** serves to identify new requests from retransmits. After the request has finished, the ``{txnId}`` value should be changed (how is not specified; a monotonically increasing -integer is recommended). It is preferable to use ``HTTP PUT`` to make sure -requests to send messages do not get sent more than once should clients need to -retransmit requests. +integer is recommended). -Valid requests look like:: - - POST /some/path/here?access_token=secret - { - "key": "This is a post." - } - - PUT /some/path/here/11?access_token=secret - { - "key": "This is a put with a txnId of 11." - } - -In contrast, these are invalid requests:: - - POST /some/path/here/11?access_token=secret - { - "key": "This is a post, but it has a txnId." - } - - PUT /some/path/here?access_token=secret - { - "key": "This is a put but it is missing a txnId." - } +Some API endpoints may allow or require the use of ``POST`` requests without a +transaction ID. Where this is optional, the use of a ``PUT`` request is strongly +recommended. Client Authentication --------------------- @@ -135,7 +114,7 @@ Most API endpoints require the user to identify themselves by presenting previously obtained credentials in the form of an ``access_token`` query parameter. -In API version 2, when credentials are missing or invalid, the HTTP call will +When credentials are required but missing or invalid, the HTTP call will return with a status of 401 and the error code, ``M_MISSING_TOKEN`` or ``M_UNKNOWN_TOKEN`` respectively. @@ -144,15 +123,13 @@ User-Interactive Authentication API .. _sect:auth-api: -This section refers to API Version 2. - Some API endpoints such as ``login`` or ``register`` require authentication that -interacts with the user. The home server may provide many different ways of +interacts with the user. The homeserver may provide many different ways of authenticating, such as user/password auth, login via a social network (OAuth2), login by confirming a token sent to their email address, etc. This specification -does not define how home servers should authorise their users but instead +does not define how homeservers should authorise their users but instead defines the standard interface which implementations should follow so that ANY -client can login to ANY home server. +client can login to ANY homeserver. The process takes the form of one or more stages, where at each stage the client submits a set of data for a given stage type and awaits a response from the @@ -168,9 +145,9 @@ more than one stage to implement n-factor auth. When all stages are complete, authentication is complete and the API call succeeds. To establish what flows a server supports for an endpoint, a client sends the request with no authentication. A request to an endpoint that uses User-Interactive -Authentication never succeeds without auth. Home Servers may allow requests that +Authentication never succeeds without auth. Homeservers may allow requests that don't require auth by offering a stage with only the ``m.login.dummy`` auth -type. The home server returns a response with HTTP status 401 and a JSON object +type. The homeserver returns a response with HTTP status 401 and a JSON object as follows:: { @@ -208,7 +185,7 @@ does this by resubmitting the same request with the the addition of an 'auth' key in the object that it submits. This dictionary contains a ``type`` key whose value is the name of the stage type that the client is attempting to complete. It must also contains a ``session`` key with the value of the session key given -by the home server, if one was given. It also contains other keys dependent on +by the homeserver, if one was given. It also contains other keys dependent on the stage type being attempted. For example, if the client is attempting to complete login type ``example.type.foo``, it might submit something like this:: @@ -222,7 +199,7 @@ complete login type ``example.type.foo``, it might submit something like this:: } } -If the home server deems the authentication attempt to be successful but still +If the homeserver deems the authentication attempt to be successful but still requires more stages to be completed, it returns HTTP status 401 along with the same object as when no authentication was attempted, with the addition of the ``completed`` key which is an array of stage type the client has completed @@ -246,7 +223,7 @@ successfully:: "session": "xxxxxx" } -If the home server decides the attempt was unsuccessful, it returns an error +If the homeserver decides the attempt was unsuccessful, it returns an error message in the standard format:: { @@ -258,7 +235,7 @@ Individual stages may require more than one request to complete, in which case the response will be as if the request was unauthenticated with the addition of any other keys as defined by the login type. -If the client has completed all stages of a flow, the home server performs the +If the client has completed all stages of a flow, the homeserver performs the API call and returns the result as normal. Some authentication types may be completed by means other than through the @@ -389,16 +366,16 @@ OAuth2-based ``uri``: Authorization Request URI OR service selection URI. Both contain an encoded ``redirect URI``. -The home server acts as a 'confidential' client for the purposes of OAuth2. If +The homeserver acts as a 'confidential' client for the purposes of OAuth2. If the uri is a ``service selection URI``, it MUST point to a webpage which prompts the user to choose which service to authorize with. On selection of a service, this MUST link through to an ``Authorization Request URI``. If there is only one -service which the home server accepts when logging in, this indirection can be +service which the homeserver accepts when logging in, this indirection can be skipped and the "uri" key can be the ``Authorization Request URI``. The client then visits the ``Authorization Request URI``, which then shows the OAuth2 Allow/Deny prompt. Hitting 'Allow' redirects to the ``redirect URI`` with -the auth code. Home servers can choose any path for the ``redirect URI``. Once +the auth code. Homeservers can choose any path for the ``redirect URI``. Once the OAuth flow has completed, the client retries the request with the session only, as above. @@ -412,7 +389,7 @@ Email-based (identity server) Prior to submitting this, the client should authenticate with an identity server. After authenticating, the session information should be submitted to -the home server. +the homeserver. To respond to this type, reply with an auth dict as follows:: @@ -450,12 +427,12 @@ Clients cannot be expected to be able to know how to process every single login type. If a client does not know how to handle a given login type, it can direct the user to a web browser with the URL of a fallback page which will allow the user to complete that login step out-of-band in their web browser. The URL it -should open is the Home Server base URL plus prefix, plus:: +should open is:: - /auth//fallback/web?session= + /_matrix/client/%CLIENT_MAJOR_VERSION%/auth//fallback/web?session= Where ``stage type`` is the type name of the stage it is attempting and -``session id`` is the ID of the session given by the home server. +``session id`` is the ID of the session given by the homeserver. This MUST return an HTML page which can perform this authentication stage. This page must attempt to call the JavaScript function ``window.onAuthDone`` when @@ -463,15 +440,10 @@ the authentication has been completed. API calls using the User-Interactive Authentication mechanism ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This section refers to API Version 2. These API calls currently use the prefix -``/_matrix/client/v2_alpha``. - .. _User-Interactive Authentication: `sect:auth-api`_ {{registration_http_api}} -Old V1 API docs: |register|_ - {{login_http_api}} Login Fallback @@ -490,11 +462,11 @@ Changing Password +++++++++++++++++ Request:: - POST $V2PREFIX/account/password + POST /_matrix/client/%CLIENT_MAJOR_VERSION%/account/password This API endpoint uses the User-Interactive Authentication API. An access token should be submitted to this endpoint if the client has an active session. The -Home Server may change the flows available depending on whether a valid access +homeserver may change the flows available depending on whether a valid access token is provided. The body of the POST request is a JSON object containing: @@ -505,7 +477,7 @@ new_password On success, an empty JSON object is returned. The error code M_NOT_FOUND is returned if the user authenticated with a third -party identifier but the Home Server could not find a matching account in its +party identifier but the homeserver could not find a matching account in its database. Adding Account Administrative Contact Information @@ -610,6 +582,15 @@ Where $streamtoken is an opaque token which can be used in another query to get the next set of results. The "start" and "end" keys can only be omitted if the complete dataset is provided in "chunk". +Filtering +--------- + +Filters can be created on the server and can be passed as as a parameter to APIs +which return events. These filters alter the data returned from those APIs. +Not all APIs accept filters. + +{{filter_http_api}} + Events ------ @@ -622,15 +603,21 @@ point in time:: [E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9] -Clients can add to the stream by POSTing message or state events, and can read -from the stream via the |initialSync|_, |/rooms//initialSync|_, `Event -Stream`_ and |/rooms//messages|_ APIs. +Clients can add to the stream by PUTing message or state events, and can read +from the stream via the +|initialSync|_, +|events|_, +|/rooms//initialSync|_, and +|/rooms//messages|_ +APIs. For reading events, the intended flow of operation is to call -$PREFIX/initialSync, which returns all of the state and the last N events in the +/_matrix/client/%CLIENT_MAJOR_VERSION%/initialSync, which returns all of the +state and the last N events in the event stream for each room, including ``start`` and ``end`` values describing the pagination of each room's event stream. For instance, -$PREFIX/initialSync?limit=5 might return the events for a room in the +/_matrix/client/%CLIENT_MAJOR_VERSION%/initialSync?limit=5 might return the +events for a room in the rooms[0].messages.chunk[] array, with tokens describing the start and end of the range in rooms[0].messages.start as '1-2-3' and rooms[0].messages.end as 'a-b-c'. @@ -643,7 +630,8 @@ You can visualise the range of events being returned as:: start: '1-2-3' end: 'a-b-c' Now, to receive future events in real-time on the event stream, you simply GET -$PREFIX/events with a ``from`` parameter of 'a-b-c': in other words passing in the +/_matrix/client/%CLIENT_MAJOR_VERSION%/events with a ``from`` parameter of +'a-b-c': in other words passing in the ``end`` token returned by initial sync. The request blocks until new events are available or until your specified timeout elapses, and then returns a new paginatable chunk of events alongside new start and end parameters:: @@ -655,10 +643,11 @@ new paginatable chunk of events alongside new start and end parameters:: start: 'a-b-c' To resume polling the events stream, you pass in the new ``end`` token as the -``from`` parameter of $PREFIX/events and poll again. +``from`` parameter of /_matrix/client/%CLIENT_MAJOR_VERSION%/events and poll again. Similarly, to paginate events backwards in order to lazy-load in previous -history from the room, you simply GET $PREFIX/rooms//messages +history from the room, you simply +GET /_matrix/client/%CLIENT_MAJOR_VERSION%/rooms//messages specifying the ``from`` token to paginate backwards from and a limit of the number of messages to retrieve. For instance, calling this API with a ``from`` parameter of '1-2-3' and a limit of 5 would return:: @@ -699,7 +688,7 @@ namespaced for each application and reduces the risk of clashes. Syncing ~~~~~~~ -Clients receive new events by "long-polling" the home server via the events API. +Clients receive new events by "long-polling" the homeserver via the events API. This involves specifying a timeout in the request which will hold open the HTTP connection for a short period of time waiting for new events, returning early if an event occurs. Only the events API supports long-polling. @@ -719,7 +708,7 @@ last request left off. Multiple events can be returned per long-poll. Do we ever support streaming requests? Why not websockets? When the client first logs in, they will need to initially synchronise with -their home server. This is achieved via the initial sync API described below. +their homeserver. This is achieved via the initial sync API described below. This API also returns an ``end`` token which can be used with the event stream. {{old_sync_http_api}} @@ -793,10 +782,6 @@ owners to delete the offending content from the databases. Events that have been redacted include a ``redacted_because`` key whose value is the event that caused it to be redacted, which may include a reason. -.. TODO - Currently, only room admins can redact events by sending a ``m.room.redaction`` - event, but server admins also need to be able to redact events by a similar - mechanism. Upon receipt of a redaction event, the server should strip off any keys not in the following list: @@ -819,19 +804,26 @@ one of the following event types: ``kick``, ``redact``, ``state_default``, ``users``, ``users_default``. - ``m.room.aliases`` allows key ``aliases`` -.. TODO - Need to update m.room.power_levels to reflect new power levels formatting - The redaction event should be added under the key ``redacted_because``. When a client receives a redaction event it should change the redacted event in the same way a server does. +Events +++++++ + +{{m_room_redaction_event}} + +Client behaviour +++++++++++++++++ + +{{redaction_http_api}} + Rooms ----- Creation ~~~~~~~~ -The home server will create an ``m.room.create`` event when a room is created, +The homeserver will create an ``m.room.create`` event when a room is created, which serves as the root of the event graph for this room. This event also has a ``creator`` key which contains the user ID of the room creator. It will also generate several other events in order to manage permissions in this room. This @@ -852,9 +844,9 @@ Room aliases Servers may host aliases for rooms with human-friendly names. Aliases take the form ``#friendlyname:server.name``. -As room aliases are scoped to a particular home server domain name, it is -likely that a home server will reject attempts to maintain aliases on other -domain names. This specification does not provide a way for home servers to +As room aliases are scoped to a particular homeserver domain name, it is +likely that a homeserver will reject attempts to maintain aliases on other +domain names. This specification does not provide a way for homeservers to send update requests to other servers. Rooms store a *partial* list of room aliases via the ``m.room.aliases`` state @@ -867,8 +859,8 @@ appears to have a room alias of ``#alias:example.com``, this SHOULD be checked to make sure that the room's ID matches the ``room_id`` returned from the request. -Home servers can respond to resolve requests for aliases on other domains than -their own by using the federation API to ask other domain name home servers. +Homeservers can respond to resolve requests for aliases on other domains than +their own by using the federation API to ask other domain name homeservers. {{directory_http_api}} @@ -985,10 +977,10 @@ values. This change is conveyed using two separate mechanisms: values of the ``displayname`` and ``avatar_url`` keys, in addition to the required ``presence`` key containing the current presence state of the user. -Both of these should be done automatically by the home server when a user +Both of these should be done automatically by the homeserver when a user successfully changes their display name or avatar URL fields. -Additionally, when home servers emit room membership events for their own +Additionally, when homeservers emit room membership events for their own users, they should include the display name and avatar URL fields in these events so that clients already have these details to hand, and do not have to perform extra round trips to query it. @@ -998,7 +990,7 @@ Security Rate limiting ~~~~~~~~~~~~~ -Home servers SHOULD implement rate limiting to reduce the risk of being +Homeservers SHOULD implement rate limiting to reduce the risk of being overloaded. If a request is refused due to rate limiting, it should return a standard error response of the form:: @@ -1020,44 +1012,33 @@ have to wait in milliseconds before they can try again. .. Links through the external API docs are below .. ============================================= -.. |createRoom| replace:: ``/createRoom`` -.. _createRoom: /docs/api/client-server/#!/-rooms/create_room - .. |initialSync| replace:: ``/initialSync`` -.. _initialSync: /docs/api/client-server/#!/-events/initial_sync +.. _initialSync: #get-matrix-client-%CLIENT_MAJOR_VERSION%-initialsync + +.. |events| replace:: ``/events`` +.. _events: #get-matrix-client-%CLIENT_MAJOR_VERSION%-events .. |/rooms//initialSync| replace:: ``/rooms//initialSync`` -.. _/rooms//initialSync: /docs/api/client-server/#!/-rooms/get_room_sync_data - -.. |login| replace:: ``/login`` -.. _login: /docs/api/client-server/#!/-login - -.. |register| replace:: ``/register`` -.. _register: /docs/api/client-server/#!/-registration +.. _/rooms//initialSync: #get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-initialsync .. |/rooms//messages| replace:: ``/rooms//messages`` -.. _/rooms//messages: /docs/api/client-server/#!/-rooms/get_messages +.. _/rooms//messages: #get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-messages .. |/rooms//members| replace:: ``/rooms//members`` -.. _/rooms//members: /docs/api/client-server/#!/-rooms/get_members +.. _/rooms//members: #get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-members .. |/rooms//state| replace:: ``/rooms//state`` -.. _/rooms//state: /docs/api/client-server/#!/-rooms/get_state_events +.. _/rooms//state: #get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-state .. |/rooms//invite| replace:: ``/rooms//invite`` -.. _/rooms//invite: /docs/api/client-server/#!/-rooms/invite +.. _/rooms//invite: #post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-invite .. |/rooms//join| replace:: ``/rooms//join`` -.. _/rooms//join: /docs/api/client-server/#!/-rooms/join_room +.. _/rooms//join: #post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-join .. |/rooms//leave| replace:: ``/rooms//leave`` -.. _/rooms//leave: /docs/api/client-server/#!/-rooms/leave +.. _/rooms//leave: #post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-leave .. |/rooms//ban| replace:: ``/rooms//ban`` -.. _/rooms//ban: /docs/api/client-server/#!/-rooms/ban - -.. |/join/| replace:: ``/join/`` -.. _/join/: /docs/api/client-server/#!/-rooms/join - -.. _`Event Stream`: /docs/api/client-server/#!/-events/get_event_stream +.. _/rooms//ban: #post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-ban diff --git a/specification/event_signing.rst b/specification/event_signing.rst index 3ad3d8a7..2a985764 100644 --- a/specification/event_signing.rst +++ b/specification/event_signing.rst @@ -80,7 +80,7 @@ Signing Details JSON is signed by encoding the JSON object without ``signatures`` or keys grouped as ``unsigned``, using the canonical encoding described above. The JSON bytes are then signed using the -signature algorithm and the signature encoded using base64 with the padding +signature algorithm and the signature is encoded using base64 with the padding stripped. The resulting base64 signature is added to an object under the *signing key identifier* which is added to the ``signatures`` object under the name of the server signing it which is added back to the original JSON object diff --git a/specification/events.rst b/specification/events.rst index 5a003115..92d52d22 100644 --- a/specification/events.rst +++ b/specification/events.rst @@ -5,6 +5,9 @@ All communication in Matrix is expressed in the form of data objects called Events. These are the fundamental building blocks common to the client-server, server-server and application-service APIs, and are described below. +Note that the structure of these events may be different than those in the +server-server API. + {{common_event_fields}} {{common_room_event_fields}} @@ -12,51 +15,13 @@ server-server and application-service APIs, and are described below. {{common_state_event_fields}} -Differences between /v1 and /v2 events --------------------------------------- - -There are a few differences between how events are formatted for sending -between servers over federation and how they are formatted for sending between -a server and its clients. - -Additionally there are a few differences between the format of events in the -responses to client APIs with a /v1 prefix and responses APIs with a /v2 -prefix. - -Events in responses for APIs with the /v2 prefix are generated from an event -formatted for federation by: - -* Removing the following keys: - ``auth_events``, ``prev_events``, ``hashes``, ``signatures``, ``depth``, - ``origin``, ``prev_state``. -* Adding an ``age`` to the ``unsigned`` object which gives the time in - milliseconds that has elapsed since the event was sent. -* Adding ``prev_content`` and ``prev_sender`` to the ``unsigned`` object if the - event is a ``state event``, which give the previous content and previous - sender of that state key -* Adding a ``redacted_because`` to the ``unsigned`` object if the event was - redacted which gives the event that redacted it. -* Adding a ``transaction_id`` to the ``unsigned`` object if the event was sent - by the client requesting it. - -Events in responses for APIs with the /v1 prefix are generated from an event -formatted for the /v2 prefix by: - -* Moving the folling keys from the ``unsigned`` object to the top level event - object: ``age``, ``redacted_because``, ``replaces_state``, ``prev_content``. -* Removing the ``unsigned`` object. -* Rename the ``sender`` key to ``user_id``. -* If the event was an ``m.room.member`` with ``membership`` set to ``invite`` - then adding a ``invite_room_state`` key to the top level event object. - - Size limits ----------- The total size of any event MUST NOT exceed 65 KB. There are additional restrictions on sizes per key: -- ``user_id`` MUST NOT exceed 255 bytes (including domain). +- ``sender`` MUST NOT exceed 255 bytes (including domain). - ``room_id`` MUST NOT exceed 255 bytes. - ``state_key`` MUST NOT exceed 255 bytes. - ``type`` MUST NOT exceed 255 bytes. diff --git a/specification/feature_profiles.rst b/specification/feature_profiles.rst index f79b92c5..a5d19a61 100644 --- a/specification/feature_profiles.rst +++ b/specification/feature_profiles.rst @@ -25,13 +25,12 @@ Summary `VoIP`_ Required Required Required Optional Optional `Content Repository`_ Required Required Required Optional Optional `Managing History Visibility`_ Required Required Required Required Optional - `End-to-End Encryption`_ Optional Optional Optional Optional Optional `Server Side Search`_ Optional Optional Optional Optional Optional + `Server Administration`_ Optional Optional Optional Optional Optional ===================================== ========== ========== ========== ========== ========== *Please see each module for more details on what clients need to implement.* -.. _End-to-End Encryption: `module:e2e`_ .. _Instant Messaging: `module:im`_ .. _Presence: `module:presence`_ .. _Push Notifications: `module:push`_ @@ -41,6 +40,7 @@ Summary .. _Content Repository: `module:content`_ .. _Managing History Visibility: `module:history-visibility`_ .. _Server Side Search: `module:search`_ +.. _Server Administration: `module:admin`_ Clients ------- diff --git a/specification/intro.rst b/specification/intro.rst index 8c08bf24..cd28b9f7 100644 --- a/specification/intro.rst +++ b/specification/intro.rst @@ -1,35 +1,28 @@ Matrix Specification ==================== -Version: {{spec_version}} ------------------------------ This specification has been generated from https://github.com/matrix-org/matrix-doc using https://github.com/matrix-org/matrix-doc/blob/master/scripts/gendoc.py as of -revision ``{{git_version}}`` - https://github.com/matrix-org/matrix-doc/tree/{{git_rev}} +revision ``{{git_version}}`` - +https://github.com/matrix-org/matrix-doc/tree/{{git_rev}}. -APIs -~~~~ The following APIs are documented in this specification: -- `Client-Server API `_ for writing Matrix clients. -- `Server-Server API `_ for writing servers which can federate with Matrix. -- `Application Service API `_ for writing privileged plugins to servers. +- `Client-Server API `_ version %CLIENT_RELEASE_LABEL% for writing Matrix clients. +- `Server-Server API `_ version %SERVER_RELEASE_LABEL% for writing servers which can federate with Matrix. +- `Application Service API `_ version %CLIENT_RELEASE_LABEL% for writing privileged plugins to servers. There are also some `appendices `_. -Changelog -~~~~~~~~~ -{{spec_changelog}} - -For a full changelog, see -https://github.com/matrix-org/matrix-doc/blob/master/CHANGELOG.rst +Before we formally started releasing the specification, the last working copy +we had can be found `here `_. .. contents:: Table of Contents .. sectnum:: Introduction -============ +------------ .. WARNING:: The Matrix specification is still evolving: the APIs are not yet frozen and this document is in places a work in progress or stale. We have made every @@ -103,10 +96,10 @@ reliably and persistently pushed from A to B in an inter-operable and federated manner. Overview -======== +-------- Architecture ------------- +~~~~~~~~~~~~ Matrix defines APIs for synchronising extensible JSON objects known as "events" between compatible clients, servers and services. Clients are @@ -150,7 +143,7 @@ a long-lived GET request. | V | V +------------------+ +------------------+ | |---------( HTTPS )--------->| | - | Home Server | | Home Server | + | homeserver | | homeserver | | |<--------( HTTPS )----------| | +------------------+ Server-Server API +------------------+ History Synchronisation @@ -158,7 +151,7 @@ a long-lived GET request. Users -~~~~~ ++++++ Each client is associated with a user account, which is identified in Matrix using a unique "User ID". This ID is namespaced to the homeserver which @@ -173,7 +166,7 @@ this user. The ``domain`` of a user ID is the domain of the homeserver. - Need to specify precise grammar for Matrix IDs Events -~~~~~~ +++++++ All data exchanged over Matrix is expressed as an "event". Typically each client action (e.g. sending a message) correlates with exactly one event. Each event @@ -188,7 +181,7 @@ of a "Room". .. _package naming conventions: https://en.wikipedia.org/wiki/Java_package#Package_naming_conventions Event Graphs -~~~~~~~~~~~~ +++++++++++++ .. _sect:event-graph: @@ -212,7 +205,7 @@ of its parents. The root event should have a depth of 1. Thus if one event is before another, then it must have a strictly smaller depth. Room structure -~~~~~~~~~~~~~~ +++++++++++++++ A room is a conceptual place where users can send and receive events. Events are sent to a room, and all participants in that room with sufficient access will @@ -237,7 +230,7 @@ They are case-sensitive. The following conceptual diagram shows an | | V | +------------------+ +------------------+ - | Home Server | | Home Server | + | homeserver | | homeserver | | matrix.org | | domain.com | +------------------+ +------------------+ | ^ @@ -291,7 +284,7 @@ from the other servers participating in a room. Room Aliases -++++++++++++ +^^^^^^^^^^^^ Each room can also have multiple "Room Aliases", which look like:: @@ -327,7 +320,7 @@ that are in the room that can be used to join via. |________________________________| Identity -~~~~~~~~ +++++++++ Users in Matrix are identified via their matrix user ID (MXID). However, existing 3rd party ID namespaces can also be used in order to identify Matrix @@ -347,7 +340,7 @@ user IDs using 3PIDs. Profiles -~~~~~~~~ +++++++++ Users may publish arbitrary key/value data associated with their account - such as a human readable display name, a profile photo URL, contact information @@ -358,7 +351,7 @@ as a human readable display name, a profile photo URL, contact information names allowed to be? Private User Data -~~~~~~~~~~~~~~~~~ ++++++++++++++++++ Users may also store arbitrary private key/value data in their account - such as client preferences, or server configuration settings which lack any other diff --git a/specification/modules/account_data.rst b/specification/modules/account_data.rst index f3fc72b6..e7c650ac 100644 --- a/specification/modules/account_data.rst +++ b/specification/modules/account_data.rst @@ -14,11 +14,11 @@ Events ------ The client recieves the account data as events in the ``account_data`` sections -of a v2 /sync. +of a ``/sync``. -These events can also be received in a v1 /events response or in the -``account_data`` section of a room in v1 /initialSync. ``m.tag`` -events appearing in v1 /events will have a ``room_id`` with the room +These events can also be received in a ``/events`` response or in the +``account_data`` section of a room in ``/initialSync``. ``m.tag`` +events appearing in ``/events`` will have a ``room_id`` with the room the tags are for. Client Behaviour diff --git a/specification/modules/admin.rst b/specification/modules/admin.rst new file mode 100644 index 00000000..45d1064f --- /dev/null +++ b/specification/modules/admin.rst @@ -0,0 +1,12 @@ +Server Administration +===================== + +.. _module:admin: + +This module adds capabilities for server administrators to inspect server state +and data. + +Client Behaviour +---------------- + +{{admin_http_api}} diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 8b38ab93..435b4b20 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -3,341 +3,7 @@ End-to-End Encryption .. _module:e2e: -.. TODO-doc - - Why is this needed. - - Overview of process - - Implementation +End to end encryption is being worked on and will be coming soon. -Matrix optionally supports end-to-end encryption, allowing rooms to be created -whose conversation contents is not decryptable or interceptable on any of the -participating homeservers. +You can read about what's underway at http://matrix.org/speculator/spec/drafts%2Fe2e/client_server.html#end-to-end-encryption. -End-to-end crypto is still being designed and prototyped - notes on the design -may be found at https://lwn.net/Articles/634144/ - - -Overview --------- - -.. code:: - - 1) Bob publishes the public keys and supported algorithms for his device. - - +----------+ +--------------+ - | Bob's HS | | Bob's Device | - +----------+ +--------------+ - | | - |<=============| - /keys/upload - - 2) Alice requests Bob's public key and supported algorithms. - - +----------------+ +------------+ +----------+ - | Alice's Device | | Alice's HS | | Bob's HS | - +----------------+ +------------+ +----------+ - | | | - |=================>|==============>| - /keys/query - - 3) Alice selects an algorithm and claims any one-time keys needed. - - +----------------+ +------------+ +----------+ - | Alice's Device | | Alice's HS | | Bob's HS | - +----------------+ +------------+ +----------+ - | | | - |=================>|==============>| - /keys/claim - - 4) Alice sends an encrypted message to Bob. - - +----------------+ +------------+ +----------+ +--------------+ - | Alice's Device | | Alice's HS | | Bob's HS | | Bob's Device | - +----------------+ +------------+ +----------+ +--------------+ - | | | | - |----------------->|-------------->|------------->| - /send/ - - -Algorithms ----------- - -There are two kinds of algorithms: messaging algorithms and key algorithms. -Messaging algorithms are used to securely send messages between devices. -Key algorithms are used for key agreement and digital signatures. - -Messaging Algorithm Names -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Messaging algorithm names use the extensible naming scheme used throughout this -specification. Algorithm names that start with ``m.`` are reserved for -algorithms defined by this specification. Implementations wanting to experiment -with new algorithms are encouraged to pick algorithm names that start with -their domain to reduce the risk of collisions. - -Algorithm names should be short and meaningful, and should list the primitives -used by the algorithm so that it is easier to see if the algorithm is using a -broken primitive. - -The name ``m.olm.v1.curve25519-aes-sha2`` corresponds to version 1 of the Olm -ratchet using Curve25519 for the initial key agreement, HKDF-SHA-256 for -ratchet key derivation, Curve25519 for the DH ratchet, HMAC-SHA-256 for the -hash ratchet, and HKDF-SHA-256, AES-256 in CBC mode, and 8 byte truncated -HMAC-SHA-256 for authenticated encryption. - -A name of ``m.olm.v1`` is too short: it gives no information about the primitives -in use, and is difficult to extend for different primitives. However a name of -``m.olm.v1.ecdh-curve25519-hdkfsha256.hmacsha256.hkdfsha256-aes256-cbc-hmac64sha256`` -is too long despite giving a more precise description of the algorithm: it adds -to the data transfer overhead and sacrifices clarity for human readers without -adding any useful extra information. - -Key Algorithms -~~~~~~~~~~~~~~ - -The name ``ed25519`` corresponds to the Ed25519 signature algorithm. The key is -a Base64 encoded 32-byte Ed25519 public key. - -The name ``curve25519`` corresponds to the Curve25519 ECDH algorithm. The key is -a Base64 encoded 32-byte Curve25519 public key. - -Client Behaviour ----------------- - -Uploading Keys -~~~~~~~~~~~~~~ - -Keys are uploaded as a signed JSON object. The JSON object must include an -ed25519 key and must be signed by that key. A device may only have one ed25519 -signing key. This key is used as the fingerprint for a device by other clients. - -The JSON object is signed using the process given by `Signing JSON`_. - - -.. code:: http - - POST /_matrix/client/v2_alpha/keys/upload/ HTTP/1.1 - Content-Type: application/json - - { - "device_keys": { - "user_id": "", - "device_id": "", - "valid_after_ts": 1234567890123, - "valid_until_ts": 2345678901234, - "algorithms": [ - "", - ], - "keys": { - ":": "", - }, - "signatures": { - "": { - ":": "" - } } }, - "one_time_keys": { - ":": "" - } } - -.. code:: http - - HTTP/1.1 200 OK - Content-Type: application/json - - { - "one_time_key_counts": { - "": 50 - } - } - - -Downloading Keys -~~~~~~~~~~~~~~~~ - -Keys are downloaded as a collection of signed JSON objects. There -will be one JSON object per device per user. If one of the user's -devices doesn't support end-to-end encryption then their -homeserver must synthesise a JSON object without any device keys -for that device. - -The JSON must be signed by both the homeserver of -the user querying the keys and by the homeserver of the device -being queried. This provides an audit trail if either homeserver -lies about the keys a user owns. - -.. code:: http - - POST /keys/query HTTP/1.1 - Content-Type: application/json - - { - "device_keys": { - "": [""] - } } - - -.. code:: http - - HTTP/1.1 200 OK - Content-Type: application/json - - { - "device_keys": { - "": { - "": { - "user_id": "", - "device_id": "", - "valid_after_ts": 1234567890123, - "valid_until_ts": 2345678901234, - "algorithms": [ - "", - ], - "keys": { - ":": "", - }, - "signatures": { - "": { - ":": "" - }, - "": { - ":": "" - }, - "": { - ":": "" - } } } } } } - - -Clients use ``/_matrix/client/v2_alpha/keys/query`` on their own homeservers to -query keys for any user they wish to contact. Homeservers will respond with the -keys for their local users and forward requests for remote users to -``/_matrix/federation/v1/user/keys/query`` over federation to the remote -server. - - -Claiming One Time Keys -~~~~~~~~~~~~~~~~~~~~~~ - -Some algorithms require one-time keys to improve their secrecy and deniability. -These keys are used once during session establishment, and are then thrown -away. In order for these keys to be useful for improving deniability they -must not be signed using the ed25519 key for a device. - -A device must generate a number of these keys and publish them onto their -homeserver. A device must periodically check how many one-time keys their -homeserver still has. If the number has become too small then the device must -generate new one-time keys and upload them to the homeserver. - -Devices must store the private part of each one-time key they upload. They can -discard the private part of the one-time key when they receive a message using -that key. However it's possible that a one-time key given out by a homeserver -will never be used, so the device that generates the key will never know that -it can discard the key. Therefore a device could end up trying to store too -many private keys. A device that is trying to store too many private keys may -discard keys starting with the oldest. - -A homeserver should rate-limit the number of one-time keys that a given user or -remote server can claim. A homeserver should discard the public part of a one -time key once it has given that key to another user. - - -.. code:: http - - POST /keys/claim HTTP/1.1 - Content-Type: application/json - - { - "one_time_keys": { - "": { - "": "" - } } } - -.. code:: http - - HTTP/1.1 200 OK - Content-Type: application/json - - { - "one_time_keys": { - "": { - "": { - ":": "" - } } } } - - -Clients use ``/_matrix/client/v2_alpha/keys/claim`` on their own homeservers to -claim keys for any user they wish to contact. Homeservers will respond with the -keys for their local users and forward requests for remote users to -``/_matrix/federation/v1/user/keys/claim`` over federation to the remote -server. - -Sending a Message -~~~~~~~~~~~~~~~~~ - -Encrypted messages are sent in the form. - -.. code:: json - - { - "type": "m.room.encrypted", - "content": { - "algorithm": "", - "": "" - } } - - -Using Olm -+++++++++ - -Devices that support olm must include "m.olm.v1.curve25519-aes-sha2" in their -list of supported chat algorithms, must list a Curve25519 device key, and -must publish Curve25519 one-time keys. - -.. code:: json - - { - "type": "m.room.encrypted", - "content": { - "algorithm": "m.olm.v1.curve25519-aes-sha2", - "sender_key": "", - "ciphertext": { - "": { - "type": 0, - "body": "" - } } } } - -The ciphertext is a mapping from device curve25519 key to an encrypted payload -for that device. The ``body`` is a base64 encoded message body. The type is an -integer indicating the type of the message body: 0 for the initial pre-key -message, 1 for ordinary messages. - -Olm sessions will generate messages with a type of 0 until they receive a -message. Once a session has decrypted a message it will produce messages with -a type of 1. - -When a client receives a message with a type of 0 it must first check if it -already has a matching session. If it does then it will use that session to -try to decrypt the message. If there is no existing session then the client -must create a new session and use the new session to decrypt the message. A -client must not persist a session or remove one-time keys used by a session -until it has successfully decrypted a message using that session. - -The plaintext payload is of the form: - -.. code:: json - - { - "type": "", - "content": "", - "room_id": "", - "fingerprint": "" - } - -The type and content of the plaintext message event are given in the payload. -Encrypting state events is not supported. - -We include the room ID in the payload, because otherwise the homeserver would -be able to change the room a message was sent in. We include a hash of the -participating keys so that clients can detect if another device is unexpectedly -included in the conversation. - -Clients must confirm that the ``sender_key`` belongs to the user that sent the -message. diff --git a/specification/modules/guest_access.rst b/specification/modules/guest_access.rst index 1f393981..cd43524b 100644 --- a/specification/modules/guest_access.rst +++ b/specification/modules/guest_access.rst @@ -9,7 +9,7 @@ the room. This module specifies how these clients should interact with servers in order to participate in rooms as guests. Guest users retrieve access tokens from a homeserver using the ordinary -`register endpoint <#post-matrix-client-api-v2-alpha-register>`_, specifying +`register endpoint <#post-matrix-client-%CLIENT_MAJOR_VERSION%-register>`_, specifying the ``kind`` parameter as ``guest``. They may then interact with the client-server API as any other user would, but will only have access to a subset of the API as described the Client behaviour subsection below. @@ -29,13 +29,13 @@ Client behaviour The following API endpoints are allowed to be accessed by guest accounts for retrieving events: -* `GET /rooms/:room_id/state <#get-matrix-client-api-v1-rooms-roomid-state>`_ -* `GET /rooms/:room_id/state/:event_type/:state_key <#get-matrix-client-api-v1-rooms-roomid-state-eventtype-statekey>`_ -* `GET /rooms/:room_id/messages <#get-matrix-client-api-v1-rooms-roomid-messages>`_ -* `GET /rooms/:room_id/initialSync <#get-matrix-client-api-v1-rooms-roomid-initialsync>`_ +* `GET /rooms/:room_id/state <#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-state>`_ +* `GET /rooms/:room_id/state/:event_type/:state_key <#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-state-eventtype-statekey>`_ +* `GET /rooms/:room_id/messages <#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-messages>`_ +* `GET /rooms/:room_id/initialSync <#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-initialsync>`_ There is also a special version of the -`GET /events <#get-matrix-client-api-v1-events>`_ endpoint: +`GET /events <#get-matrix-client-%CLIENT_MAJOR_VERSION%-events>`_ endpoint: {{guest_events_http_api}} @@ -47,15 +47,15 @@ receive events for them. The following API endpoints are allowed to be accessed by guest accounts for sending events: -* `POST /rooms/:room_id/join <#post-matrix-client-api-v1-rooms-roomid-join>`_ -* `PUT /rooms/:room_id/send/m.room.message/:txn_id <#put-matrix-client-api-v1-rooms-roomid-send-eventtype-txnid>`_ +* `POST /rooms/:room_id/join <#post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-join>`_ +* `PUT /rooms/:room_id/send/m.room.message/:txn_id <#put-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-send-eventtype-txnid>`_ Guest clients *do* need to join rooms in order to send events to them. The following API endpoints are allowed to be accessed by guest accounts for their own account maintenance: -* `PUT /profile/:user_id/displayname <#put-matrix-client-api-v1-profile-userid-displayname>`_ +* `PUT /profile/:user_id/displayname <#put-matrix-client-%CLIENT_MAJOR_VERSION%-profile-userid-displayname>`_ Server behaviour ---------------- diff --git a/specification/modules/instant_messaging.rst b/specification/modules/instant_messaging.rst index cd385001..ebbeaca3 100644 --- a/specification/modules/instant_messaging.rst +++ b/specification/modules/instant_messaging.rst @@ -269,11 +269,9 @@ code of 400. Security considerations ----------------------- -Messages sent using this module are not encrypted. Messages can be encrypted -using the `E2E module`_. +Messages sent using this module are not encrypted, although end to end encryption is in development (see `E2E module`_). Clients should sanitise **all displayed keys** for unsafe HTML to prevent Cross-Site Scripting (XSS) attacks. This includes room names and topics. .. _`E2E module`: `module:e2e`_ - diff --git a/specification/modules/presence.rst b/specification/modules/presence.rst index 3602d105..4eddaeee 100644 --- a/specification/modules/presence.rst +++ b/specification/modules/presence.rst @@ -61,7 +61,7 @@ recommended. Server behaviour ---------------- -Each user's home server stores a "presence list" per user. Once a user accepts +Each user's homeserver stores a "presence list" per user. Once a user accepts a presence list, both user's HSes must track the subscription. Propagating profile information @@ -73,7 +73,7 @@ automatic propagation event to occur, informing likely-interested parties of the new values. One of these change mechanisms SHOULD be via ``m.presence`` events. These events should set ``displayname`` and ``avatar_url`` to the new values along with the presence-specific keys. This SHOULD be done automatically by the -home server when a user successfully changes their display name or avatar URL. +homeserver when a user successfully changes their display name or avatar URL. .. admonition:: Rationale diff --git a/specification/modules/push.rst b/specification/modules/push.rst index 893e9481..2834688c 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -11,7 +11,7 @@ Push Notifications | | | | +-------------------+ | +----------------+ | | +---------------+ | | | | | | | | | | | - | Matrix Home Server+-----> Push Gateway +------> Push Provider | | + | Matrix homeserver+-----> Push Gateway +------> Push Provider | | | | | | | | | | | | +-^-----------------+ | +----------------+ | | +----+----------+ | | | | | | | @@ -355,14 +355,14 @@ Examples To create a rule that suppresses notifications for the room with ID ``!dj234r78wl45Gh4D:matrix.org``:: - curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/v1/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \ + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/%CLIENT_MAJOR_VERSION%/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \ '{ "actions" : ["dont_notify"] }' To suppress notifications for the user ``@spambot:matrix.org``:: - curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/v1/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \ + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/%CLIENT_MAJOR_VERSION%/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \ '{ "actions" : ["dont_notify"] }' @@ -370,7 +370,7 @@ To suppress notifications for the user ``@spambot:matrix.org``:: To always notify for messages that contain the work 'cake' and set a specific sound (with a rule_id of ``SSByZWFsbHkgbGlrZSBjYWtl``):: - curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/v1/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \ + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/%CLIENT_MAJOR_VERSION%/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \ '{ "pattern": "cake", "actions" : ["notify", {"set_sound":"cakealarm.wav"}] @@ -379,7 +379,7 @@ sound (with a rule_id of ``SSByZWFsbHkgbGlrZSBjYWtl``):: To add a rule suppressing notifications for messages starting with 'cake' but ending with 'lie', superseding the previous rule:: - curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/v1/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \ + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/%CLIENT_MAJOR_VERSION%/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \ '{ "pattern": "cake*lie", "actions" : ["notify"] @@ -389,7 +389,7 @@ To add a custom sound for notifications messages containing the word 'beer' in any rooms with 10 members or fewer (with greater importance than the room, sender and content rules):: - curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/v1/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \ + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/api/%CLIENT_MAJOR_VERSION%/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \ '{ "conditions": [ {"kind": "event_match", "key": "content.body", "pattern": "beer" }, diff --git a/specification/modules/receipts.rst b/specification/modules/receipts.rst index 702a7275..70135801 100644 --- a/specification/modules/receipts.rst +++ b/specification/modules/receipts.rst @@ -24,8 +24,8 @@ single ``event_id``. Client behaviour ---------------- -In v1 ``/initialSync``, receipts are listed in a separate top level ``receipts`` -key. In v2 ``/sync``, receipts are contained in the ``ephemeral`` block for a +In ``/initialSync``, receipts are listed in a separate top level ``receipts`` +key. In ``/sync``, receipts are contained in the ``ephemeral`` block for a room. New receipts that come down the event streams are deltas which update existing mappings. Clients should replace older receipt acknowledgements based on ``user_id`` and ``receipt_type`` pairs. For example:: diff --git a/specification/modules/search.rst b/specification/modules/search.rst index bef748c7..f795e18a 100644 --- a/specification/modules/search.rst +++ b/specification/modules/search.rst @@ -34,7 +34,7 @@ The supported keys to search over are: The search will *not* include rooms that are end to end encrypted. The results include a ``rank`` key that can be used to sort the results by -revelancy. The higher the ``rank`` the more relevant the result is. +relevancy. The higher the ``rank`` the more relevant the result is. The value of ``count`` may not match the number of results. For example due to the search query matching 1000s of results and the server truncating the diff --git a/specification/modules/tags.rst b/specification/modules/tags.rst index f8c28c55..4bed9657 100644 --- a/specification/modules/tags.rst +++ b/specification/modules/tags.rst @@ -11,11 +11,11 @@ Events ------ The tags on a room are received as single ``m.tag`` event in the -``account_data`` section of a room in a v2 /sync. +``account_data`` section of a room in a ``/sync``. -The ``m.tag`` can also be received in a v1 /events response or in the -``account_data`` section of a room in v1 /initialSync. ``m.tag`` -events appearing in v1 /events will have a ``room_id`` with the room +The ``m.tag`` can also be received in a ``/events`` response or in the +``account_data`` section of a room in ``/initialSync``. ``m.tag`` +events appearing in ``/events`` will have a ``room_id`` with the room the tags are for. Each tag has an associated JSON object with information about the tag, e.g how diff --git a/specification/modules/typing_notifications.rst b/specification/modules/typing_notifications.rst index da383e73..8be1ac28 100644 --- a/specification/modules/typing_notifications.rst +++ b/specification/modules/typing_notifications.rst @@ -34,28 +34,6 @@ to inform the server that the user has stopped typing. {{typing_http_api}} -Server behaviour ----------------- - -Servers MUST emit typing EDUs in a different form to ``m.typing`` events which -are shown to clients. This form looks like:: - - { - "type": "m.typing", - "content": { - "room_id": "!room-id-here:matrix.org", - "user_id": "@user-id-here:matrix.org", - "typing": true/false - } - } - -This does not contain timing information so it is up to originating homeservers -to ensure they eventually send "stop" notifications. - -.. TODO - ((This will eventually need addressing, as part of the wider typing/presence - timer addition work)) - Security considerations ----------------------- diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 012c2ac9..ba6b7d35 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -1,8 +1,8 @@ Federation API ============== -Matrix home servers use the Federation APIs (also known as server-server APIs) -to communicate with each other. Home servers use these APIs to push messages to +Matrix homeservers use the Federation APIs (also known as server-server APIs) +to communicate with each other. Homeservers use these APIs to push messages to each other in real-time, to request historic messages from each other, and to query profile and presence information about users on each other's servers. @@ -11,10 +11,10 @@ servers. These HTTPS requests are strongly authenticated using public key signatures at the TLS transport layer and using public key signatures in HTTP Authorization headers at the HTTP layer. -There are three main kinds of communication that occur between home servers: +There are three main kinds of communication that occur between homeservers: Persisted Data Units (PDUs): - These events are broadcast from one home server to any others that have + These events are broadcast from one homeserver to any others that have joined the same room (identified by Room ID). They are persisted in long-term storage and record the history of messages and state for a room. @@ -25,9 +25,9 @@ Persisted Data Units (PDUs): deliver them through third-party servers. Ephemeral Data Units (EDUs): - These events are pushed between pairs of home servers. They are not + These events are pushed between pairs of homeservers. They are not persisted and are not part of the history of a room, nor does the - receiving home server have to reply to them. + receiving homeserver have to reply to them. Queries: These are single request/response interactions between a given pair of @@ -38,7 +38,7 @@ Queries: EDUs and PDUs are further wrapped in an envelope called a Transaction, which is -transferred from the origin to the destination home server using an HTTPS PUT +transferred from the origin to the destination homeserver using an HTTPS PUT request. .. contents:: Table of Contents @@ -50,7 +50,7 @@ Server Discovery Resolving Server Names ~~~~~~~~~~~~~~~~~~~~~~ -Each matrix home server is identified by a server name consisting of a DNS name +Each matrix homeserver is identified by a server name consisting of a DNS name and an optional TLS port. .. code:: @@ -67,7 +67,7 @@ is absent then the server is discovered by looking up a ``_matrix._tcp`` SRV record for the DNS name. If this record does not exist then the server is discovered by looking up an AAAA or A record on the DNS name and taking the default fallback port number of 8448. -Home servers may use SRV records to load balance requests between multiple TLS +Homeservers may use SRV records to load balance requests between multiple TLS endpoints or to failover to another endpoint if an endpoint fails. Retrieving Server Keys @@ -76,8 +76,8 @@ Retrieving Server Keys Version 2 +++++++++ -Each home server publishes its public keys under ``/_matrix/key/v2/server/``. -Home servers query for keys by either getting ``/_matrix/key/v2/server/`` +Each homeserver publishes its public keys under ``/_matrix/key/v2/server/``. +Homeservers query for keys by either getting ``/_matrix/key/v2/server/`` directly or by querying an intermediate notary server using a ``/_matrix/key/v2/query`` API. Intermediate notary servers query the ``/_matrix/key/v2/server/`` API on behalf of another server and sign the @@ -95,7 +95,7 @@ server by querying other servers. Publishing Keys ^^^^^^^^^^^^^^^ -Home servers publish the allowed TLS fingerprints and signing keys in a JSON +Homeservers publish the allowed TLS fingerprints and signing keys in a JSON object at ``/_matrix/key/v2/server/{key_id}``. The response contains a list of ``verify_keys`` that are valid for signing federation requests made by the server and for signing events. It contains a list of ``old_verify_keys`` @@ -114,7 +114,7 @@ certificate currently in use by the server. These fingerprints are valid until the millisecond POSIX timestamp in ``valid_until_ts``. The ``verify_keys`` can be used to sign requests and events made by the server -until the millisecond POSIX timestamp in ``valid_until_ts``. If a Home Server +until the millisecond POSIX timestamp in ``valid_until_ts``. If a homeserver receives an event with a ``origin_server_ts`` after the ``valid_until_ts`` then it should request that ``key_id`` for the originating server to check whether the key has expired. @@ -136,8 +136,8 @@ events sent by that server can still be checked. ==================== =================== ====================================== Key Type Description ==================== =================== ====================================== -``server_name`` String DNS name of the home server. -``verify_keys`` Object Public keys of the home server for +``server_name`` String DNS name of the homeserver. +``verify_keys`` Object Public keys of the homeserver for verifying digital signatures. ``old_verify_keys`` Object The public keys that the server used to use and when it stopped using them. @@ -238,14 +238,14 @@ Version 1 Version 1 of key distribution is obsolete -Home servers publish their TLS certificates and signing keys in a JSON object +Homeservers publish their TLS certificates and signing keys in a JSON object at ``/_matrix/key/v1``. ==================== =================== ====================================== Key Type Description ==================== =================== ====================================== -``server_name`` String DNS name of the home server. -``verify_keys`` Object Public keys of the home server for +``server_name`` String DNS name of the homeserver. +``verify_keys`` Object Public keys of the homeserver for verifying digital signatures. ``signatures`` Object Digital signatures for this object signed using the ``verify_keys``. @@ -278,9 +278,9 @@ Transactions .. WARNING:: This section may be misleading or inaccurate. -The transfer of EDUs and PDUs between home servers is performed by an exchange +The transfer of EDUs and PDUs between homeservers is performed by an exchange of Transaction messages, which are encoded as JSON objects, passed over an HTTP -PUT request. A Transaction is meaningful only to the pair of home servers that +PUT request. A Transaction is meaningful only to the pair of homeservers that exchanged it; they are not globally-meaningful. Each transaction has: @@ -445,7 +445,7 @@ EDUs EDUs, by comparison to PDUs, do not have an ID, a room ID, or a list of "previous" IDs. The only mandatory fields for these are the type, origin and -destination home server names, and the actual nested content. +destination homeserver names, and the actual nested content. ======================== ============ ========================================= Key Type Description @@ -531,7 +531,7 @@ To make a query:: Query args: as specified by the individual query types Response: JSON encoding of a response object -Performs a single query request on the receiving home server. The Query Type +Performs a single query request on the receiving homeserver. The Query Type part of the path specifies the kind of query being made, and its query arguments have a meaning specific to that kind of query. The response is a JSON-encoded object whose meaning also depends on the kind of query. @@ -791,9 +791,9 @@ because HTTP services like Matrix are often deployed behind load balancers that handle the TLS and these load balancers make it difficult to check TLS client certificates. -A home server may provide a TLS client certificate and the receiving home server +A homeserver may provide a TLS client certificate and the receiving homeserver may check that the client certificate matches the certificate of the origin -home server. +homeserver. Server-Server Authorization --------------------------- @@ -905,7 +905,7 @@ Querying profile information:: If the query contains the optional ``field`` key, it should give the name of a result field. If such is present, then the result should contain only a field of that name, with no others present. If not, the result should contain as much -of the user's profile as the home server has available and can make public. +of the user's profile as the homeserver has available and can make public. Directory --------- diff --git a/specification/targets.yaml b/specification/targets.yaml index cdbfa62e..cbe40dc7 100644 --- a/specification/targets.yaml +++ b/specification/targets.yaml @@ -6,16 +6,16 @@ targets: files: - client_server_api.rst - { 1: events.rst } - - { 1: event_signing.rst } - - modules.rst - - { 1: feature_profiles.rst } - - { 1: "group:modules" } # reference a group of files + - { 1: modules.rst } + - { 2: feature_profiles.rst } + - { 2: "group:modules" } # reference a group of files application_service: files: - application_service_api.rst server_server: files: - server_server_api.rst + - { 1: event_signing.rst } appendices: files: - appendices.rst @@ -35,9 +35,10 @@ groups: # reusable blobs of files when prefixed with 'group:' - modules/guest_access.rst - modules/tags.rst - modules/account_data.rst + - modules/admin.rst -title_styles: ["=", "-", "~", "+", "^", "`"] +title_styles: ["=", "-", "~", "+", "^", "`", "@"] # The templating system doesn't know the right title style to use when generating # RST. These symbols are 'relative' to say "make a sub-title" (-1), "make a title diff --git a/supporting-docs/examples/application-services.rst b/supporting-docs/examples/application-services.rst index bde4531b..fae3613d 100644 --- a/supporting-docs/examples/application-services.rst +++ b/supporting-docs/examples/application-services.rst @@ -6,15 +6,15 @@ This file contains examples of some application service IRC Bridge ---------- Pre-conditions: - - Server admin stores the AS token "T_a" on the home server. - - Home server has a token "T_h". - - Home server has the domain "hsdomain.com" + - Server admin stores the AS token "T_a" on the homeserver. + - Homeserver has a token "T_h". + - Homeserver has the domain "hsdomain.com" 1. Application service registration :: - AS -> HS: Registers itself with the home server + AS -> HS: Registers itself with the homeserver POST /register { url: "https://someapp.com/matrix", diff --git a/supporting-docs/guides/2015-08-10-client-server.rst b/supporting-docs/guides/2015-08-10-client-server.rst index 2800584c..fe6b464a 100644 --- a/supporting-docs/guides/2015-08-10-client-server.rst +++ b/supporting-docs/guides/2015-08-10-client-server.rst @@ -19,11 +19,11 @@ How to use the client-server API The git version of this document is {% project_version %} This guide focuses on how the client-server APIs *provided by the reference -home server* can be used. Since this is specific to a home server +homeserver* can be used. Since this is specific to a homeserver implementation, there may be variations in relation to registering/logging in which are not covered in extensive detail in this guide. -If you haven't already, get a home server up and running on +If you haven't already, get a homeserver up and running on ``http://localhost:8008``. @@ -56,8 +56,8 @@ if you forget the ``access_token``. Implementation note: The matrix specification does not enforce how users register with a server. It just specifies the URL path and absolute minimum -keys. The reference home server uses a username/password to authenticate user, -but other home servers may use different methods. This is why you need to +keys. The reference homeserver uses a username/password to authenticate user, +but other homeservers may use different methods. This is why you need to specify the ``type`` of method. Login @@ -82,13 +82,13 @@ The aim when logging in is to get an access token for your existing user ID:: "user_id": "@example:localhost" } -Implementation note: Different home servers may implement different methods for +Implementation note: Different homeservers may implement different methods for logging in to an existing account. In order to check that you know how to login -to this home server, you must perform a ``GET`` first and make sure you +to this homeserver, you must perform a ``GET`` first and make sure you recognise the login type. If you do not know how to login, you can ``GET /login/fallback`` which will return a basic webpage which you can use to -login. The reference home server implementation support username/password login, -but other home servers may support different login methods (e.g. OAuth2). +login. The reference homeserver implementation support username/password login, +but other homeservers may support different login methods (e.g. OAuth2). Communicating diff --git a/supporting-docs/guides/2015-08-21-application_services.md b/supporting-docs/guides/2015-08-21-application_services.md index dd532d42..e034e154 100644 --- a/supporting-docs/guides/2015-08-21-application_services.md +++ b/supporting-docs/guides/2015-08-21-application_services.md @@ -6,7 +6,7 @@ categories: guides # Application services -Application services are distinct modules which which sit alongside a home server providing arbitrary extensible functionality decoupled from the home server implementation. Just like the rest of Matrix, they communicate via HTTP using JSON. Application services function in a very similar way to traditional clients, but they are given much more power than a normal client. They can reserve entire namespaces of room aliases and user IDs for their own purposes. They can silently monitor events in rooms, or any events directed at any user ID. This power allows application services to have extremely useful abilities which overall enhance the end user experience. +Application services are distinct modules which which sit alongside a homeserver providing arbitrary extensible functionality decoupled from the homeserver implementation. Just like the rest of Matrix, they communicate via HTTP using JSON. Application services function in a very similar way to traditional clients, but they are given much more power than a normal client. They can reserve entire namespaces of room aliases and user IDs for their own purposes. They can silently monitor events in rooms, or any events directed at any user ID. This power allows application services to have extremely useful abilities which overall enhance the end user experience. | @@ -47,17 +47,17 @@ At present, the IRC application service is in beta, and is being run on #matrix | # What Application services can do for you -Application services have enormous potential for creating new and exciting ways to transform and enhance the core Matrix protocol. For example, you could aggregate information from multiple rooms into a summary room, or create throwaway virtual user accounts to proxy messages for a fixed user ID on-the-fly. As you may expect, all of this power assumes a high degree of trust between application services and home servers. Only home server admins can allow an application service to link up with their home server, and the application service is in no way federated to other home servers. You can think of application services as additional logic on the home server itself, without messing around with the book-keeping that home servers have to do. This makes adding useful functionality very easy. +Application services have enormous potential for creating new and exciting ways to transform and enhance the core Matrix protocol. For example, you could aggregate information from multiple rooms into a summary room, or create throwaway virtual user accounts to proxy messages for a fixed user ID on-the-fly. As you may expect, all of this power assumes a high degree of trust between application services and homeservers. Only homeserver admins can allow an application service to link up with their homeserver, and the application service is in no way federated to other homeservers. You can think of application services as additional logic on the homeserver itself, without messing around with the book-keeping that homeservers have to do. This makes adding useful functionality very easy. | ### Example -The application service (AS) API itself uses webhooks to communicate from the home server to the AS: +The application service (AS) API itself uses webhooks to communicate from the homeserver to the AS: -- Room Alias Query API : The home server hits a URL on your application server to see if a room alias exists. -- User Query API : The home server hits a URL on your application server to see if a user ID exists. -- Push API : The home server hits a URL on your application server to notify you of new events for your users and rooms. +- Room Alias Query API : The homeserver hits a URL on your application server to see if a room alias exists. +- User Query API : The homeserver hits a URL on your application server to see if a user ID exists. +- Push API : The homeserver hits a URL on your application server to notify you of new events for your users and rooms. A very basic application service may want to log all messages in rooms which have an alias starting with "#logged_" (side note: logging won't work if these rooms are using end-to-end encryption). @@ -85,7 +85,7 @@ Set your new application service running on port 5000 with: python app_service.py -The home server needs to know that the application service exists before it will send requests to it. This is done via a registration YAML file which is specified in Synapse's main config file e.g. homeserver.yaml. The server admin needs to add the application service registration configuration file as an entry to this file. +The homeserver needs to know that the application service exists before it will send requests to it. This is done via a registration YAML file which is specified in Synapse's main config file e.g. homeserver.yaml. The server admin needs to add the application service registration configuration file as an entry to this file. # homeserver.yaml app_service_config_files: @@ -115,7 +115,7 @@ NB: Note the "-" at the start; this indicates a list element. The registration f - exclusive: false regex: "#logged_.*" -**You will need to restart the home server after editing the config file before it will take effect.** +**You will need to restart the homeserver after editing the config file before it will take effect.** | @@ -138,6 +138,6 @@ This makes the application service lazily create a room with the requested alias | -Application services are powerful components which extend the functionality of home servers, but they are limited. They can only ever function in a "passive" way. For example, you cannot implement an application service which censors swear words in rooms, because there is no way to prevent the event from being sent. Aside from the fact that censoring will not work when using end-to-end encryption, all federated home servers would also need to reject the event in order to stop developing an inconsistent event graph. To "actively" monitor events, another component called a "Policy Server" is required, which is beyond the scope of this post.  Also, Application Services can result in a performance bottleneck, as all events on the homeserver must be ordered and sent to the registered application services.  If you are bridging huge amounts of traffic, you may be better off having your bridge directly talk the Server-Server federation API rather than the simpler Application Service API. +Application services are powerful components which extend the functionality of homeservers, but they are limited. They can only ever function in a "passive" way. For example, you cannot implement an application service which censors swear words in rooms, because there is no way to prevent the event from being sent. Aside from the fact that censoring will not work when using end-to-end encryption, all federated homeservers would also need to reject the event in order to stop developing an inconsistent event graph. To "actively" monitor events, another component called a "Policy Server" is required, which is beyond the scope of this post.  Also, Application Services can result in a performance bottleneck, as all events on the homeserver must be ordered and sent to the registered application services.  If you are bridging huge amounts of traffic, you may be better off having your bridge directly talk the Server-Server federation API rather than the simpler Application Service API. I hope this demonstrates how easy it is to create an application service, along with a few ideas of the kinds of things you can do with them. Obvious uses include build protocol bridges, search engines, invisible bots, etc. For more information on the AS HTTP API, check out the new Application Service API section in the spec, or the raw drafts and spec in https://github.com/matrix-org/matrix-doc/. diff --git a/supporting-docs/howtos/client-server.rst b/supporting-docs/howtos/client-server.rst index 3bed5a9f..e5a85d41 100644 --- a/supporting-docs/howtos/client-server.rst +++ b/supporting-docs/howtos/client-server.rst @@ -11,11 +11,11 @@ How to use the client-server API The git version of this document is ``{{git_version}}`` This guide focuses on how the client-server APIs *provided by the reference -home server* can be used. Since this is specific to a home server +homeserver* can be used. Since this is specific to a homeserver implementation, there may be variations in relation to registering/logging in which are not covered in extensive detail in this guide. -If you haven't already, get a home server up and running on +If you haven't already, get a homeserver up and running on ``http://localhost:8008``. @@ -48,8 +48,8 @@ if you forget the ``access_token``. Implementation note: The matrix specification does not enforce how users register with a server. It just specifies the URL path and absolute minimum -keys. The reference home server uses a username/password to authenticate user, -but other home servers may use different methods. This is why you need to +keys. The reference homeserver uses a username/password to authenticate user, +but other homeservers may use different methods. This is why you need to specify the ``type`` of method. Login @@ -74,13 +74,13 @@ The aim when logging in is to get an access token for your existing user ID:: "user_id": "@example:localhost" } -Implementation note: Different home servers may implement different methods for +Implementation note: Different homeservers may implement different methods for logging in to an existing account. In order to check that you know how to login -to this home server, you must perform a ``GET`` first and make sure you +to this homeserver, you must perform a ``GET`` first and make sure you recognise the login type. If you do not know how to login, you can ``GET /login/fallback`` which will return a basic webpage which you can use to -login. The reference home server implementation support username/password login, -but other home servers may support different login methods (e.g. OAuth2). +login. The reference homeserver implementation support username/password login, +but other homeservers may support different login methods (e.g. OAuth2). Communicating diff --git a/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.html b/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.html index 088ff7ac..b7e874c2 100644 --- a/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.html +++ b/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.html @@ -1,5 +1,5 @@
    -

    This room creation / message sending demo requires a home server to be running on http://localhost:8008

    +

    This room creation / message sending demo requires a homeserver to be running on http://localhost:8008

    diff --git a/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.js b/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.js index 9c346e2f..c16395ac 100644 --- a/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.js +++ b/supporting-docs/howtos/jsfiddles/create_room_send_msg/demo.js @@ -19,7 +19,7 @@ $('.login').live('click', function() { showLoggedIn(data); }, error: function(err) { - var errMsg = "To try this, you need a home server running!"; + var errMsg = "To try this, you need a homeserver running!"; var errJson = $.parseJSON(err.responseText); if (errJson) { errMsg = JSON.stringify(errJson); diff --git a/supporting-docs/howtos/jsfiddles/event_stream/demo.html b/supporting-docs/howtos/jsfiddles/event_stream/demo.html index 7657780d..3de7b081 100644 --- a/supporting-docs/howtos/jsfiddles/event_stream/demo.html +++ b/supporting-docs/howtos/jsfiddles/event_stream/demo.html @@ -1,5 +1,5 @@
    -

    This event stream demo requires a home server to be running on http://localhost:8008

    +

    This event stream demo requires a homeserver to be running on http://localhost:8008

    diff --git a/supporting-docs/howtos/jsfiddles/event_stream/demo.js b/supporting-docs/howtos/jsfiddles/event_stream/demo.js index acba8391..65b118d2 100644 --- a/supporting-docs/howtos/jsfiddles/event_stream/demo.js +++ b/supporting-docs/howtos/jsfiddles/event_stream/demo.js @@ -58,7 +58,7 @@ $('.login').live('click', function() { showLoggedIn(data); }, error: function(err) { - var errMsg = "To try this, you need a home server running!"; + var errMsg = "To try this, you need a homeserver running!"; var errJson = $.parseJSON(err.responseText); if (errJson) { errMsg = JSON.stringify(errJson); diff --git a/supporting-docs/howtos/jsfiddles/example_app/demo.html b/supporting-docs/howtos/jsfiddles/example_app/demo.html index 7a9dffdd..a183f61d 100644 --- a/supporting-docs/howtos/jsfiddles/example_app/demo.html +++ b/supporting-docs/howtos/jsfiddles/example_app/demo.html @@ -1,5 +1,5 @@