From 8ad056b2079880145163f6e562ec99f480e87a7f Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 10:32:51 +0100 Subject: Prefix API links with /docs/api/client-server so they should link through correctly on matrix.org --- docs/specification.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index fdd5f07917..bae3f3a7b4 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1672,45 +1672,45 @@ User ID: .. ============================================= .. |createRoom| replace:: ``/createRoom`` -.. _createRoom: /-rooms/create_room +.. _createRoom: /docs/api/client-server/#!/-rooms/create_room .. |initialSync| replace:: ``/initialSync`` -.. _initialSync: /-events/initial_sync +.. _initialSync: /docs/api/client-server/#!/-events/initial_sync .. |/rooms//initialSync| replace:: ``/rooms//initialSync`` -.. _/rooms//initialSync: /-rooms/get_room_sync_data +.. _/rooms//initialSync: /docs/api/client-server/#!/-rooms/get_room_sync_data .. |login| replace:: ``/login`` -.. _login: /-login +.. _login: /docs/api/client-server/#!/-login .. |/rooms//messages| replace:: ``/rooms//messages`` -.. _/rooms//messages: /-rooms/get_messages +.. _/rooms//messages: /docs/api/client-server/#!/-rooms/get_messages .. |/rooms//members| replace:: ``/rooms//members`` -.. _/rooms//members: /-rooms/get_members +.. _/rooms//members: /docs/api/client-server/#!/-rooms/get_members .. |/rooms//state| replace:: ``/rooms//state`` -.. _/rooms//state: /-rooms/get_state_events +.. _/rooms//state: /docs/api/client-server/#!/-rooms/get_state_events .. |/rooms//send/| replace:: ``/rooms//send/`` -.. _/rooms//send/: /-rooms/send_non_state_event +.. _/rooms//send/: /docs/api/client-server/#!/-rooms/send_non_state_event .. |/rooms//state//| replace:: ``/rooms//state//`` -.. _/rooms//state//: /-rooms/send_state_event +.. _/rooms//state//: /docs/api/client-server/#!/-rooms/send_state_event .. |/rooms//invite| replace:: ``/rooms//invite`` -.. _/rooms//invite: /-rooms/invite +.. _/rooms//invite: /docs/api/client-server/#!/-rooms/invite .. |/rooms//join| replace:: ``/rooms//join`` -.. _/rooms//join: /-rooms/join_room +.. _/rooms//join: /docs/api/client-server/#!/-rooms/join_room .. |/rooms//leave| replace:: ``/rooms//leave`` -.. _/rooms//leave: /-rooms/leave +.. _/rooms//leave: /docs/api/client-server/#!/-rooms/leave .. |/rooms//ban| replace:: ``/rooms//ban`` -.. _/rooms//ban: /-rooms/ban +.. _/rooms//ban: /docs/api/client-server/#!/-rooms/ban .. |/join/| replace:: ``/join/`` -.. _/join/: /-rooms/join +.. _/join/: /docs/api/client-server/#!/-rooms/join -.. _`Event Stream`: /-events/get_event_stream +.. _`Event Stream`: /docs/api/client-server/#!/-events/get_event_stream -- cgit 1.5.1 From 46ac4a2f854e3338334abd990ecbb7fbb2b5f786 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Wed, 3 Sep 2014 10:44:40 +0100 Subject: Fill out power level bits in the spec --- docs/specification.rst | 105 +++++++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 42 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index bae3f3a7b4..c67b4ca2b4 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -428,9 +428,10 @@ 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 includes: - - ``m.room.power_levels`` : Sets the authority of the room creator. + - ``m.room.power_levels`` : Sets the power levels of users. - ``m.room.join_rules`` : Whether the room is "invite-only" or not. - - ``m.room.add_state_level`` + - ``m.room.add_state_level``: The power level required in order to + add new state to the room (as opposed to updating exisiting state) - ``m.room.send_event_level`` : The power level required in order to send a message in this room. - ``m.room.ops_level`` : The power level required in order to kick or @@ -463,6 +464,27 @@ Permissions Link through to respective sections where necessary. How does this tie in with permissions, e.g. give example of creating a read-only room. +Permissions for rooms are done via the concept of power levels - to do any +action in a room a user must have a suitable power level. + +Power levels for users are defined in ``m.room.power_levels``, where both +a default and specific users' power levels can be set. By default all users +have a power level of 0. + +State events may contain a ``required_power_level`` key, which indicates the +minimum power a user must have before they can update that state key. The only +exception to this is when a user leaves a room. + +To perform certain actions there are additional power level requirements +defined in the following state events: + +- ``m.room.send_event_level`` defines the minimum level for sending non-state + events. Defaults to 5. +- ``m.room.add_state_level`` defines the minimum level for adding new state, + rather than updating existing state. Defaults to 5. +- ``m.room.ops_level`` defines the minimum levels to ban and kick other users. + This defaults to a kick and ban levels of 5 each. + Joining rooms ------------- @@ -797,89 +819,88 @@ prefixed with ``m.`` to force this state change directly will fail. See the `Rooms`_ section for how to use the membership APIs. -``m.room.config`` +``m.room.create`` Summary: - The room config. + The first event in the room. Type: State event JSON format: - TODO + ``{ "creator": "string"}`` Example: - TODO + ``{ "creator": "@user:example.com" }`` Description: - TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what + This is the first event in a room and cannot be changed. It acts as the + root of all other events. -``m.room.invite_join`` - Summary: - TODO. - Type: - State event - JSON format: - TODO - Example: - TODO - Description: - TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what - ``m.room.join_rules`` Summary: - TODO. + Descripes how/if people are allowed to join. Type: State event JSON format: - TODO + ``{ "join_rule": "enum [ public|knock|invite|private ]" }`` Example: - TODO + ``{ "join_rule": "public" }`` Description: - TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what - + TODO : Use docs/models/rooms.rst + ``m.room.power_levels`` Summary: - TODO. + Defines the power levels of users in the room. Type: State event JSON format: - TODO + ``{ "": , ..., "default": }`` Example: - TODO + ``{ "@user:example.com": 5, "@user2:example.com": 10, "default": 0 }`` Description: - TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what - + If a user is in the list, then they have the associated power level. + Otherwise they have the default level. If not ``default`` key is supplied, + it is assumed to be 0. + ``m.room.add_state_level`` Summary: - TODO. + Defines the minimum power level a user needs to add state. Type: State event JSON format: - TODO + ``{ "level": }`` Example: - TODO + ``{ "level": 5 }`` Description: - TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what + To add a new piece of state to the room a user must have the given power + level. This does not apply to updating current state, which is goverened + by the ``required_power_level`` event key. ``m.room.send_event_level`` Summary: - TODO. + Defines the minimum power level a user needs to send an event. Type: State event JSON format: - TODO + ``{ "level": }`` Example: - TODO + ``{ "level": 0 }`` Description: - TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what - + To send a new event into the room a user must have at least this power + level. This allows ops to make the room read only by increasing this level, + or muting individual users by lowering their power level below this + threshold. + ``m.room.ops_levels`` Summary: - TODO. + Defines the minimum power levels that a user must have before they can + kick and/or ban other users. Type: State event JSON format: - TODO + ``{ "ban_level": , "kick_level": }`` Example: - TODO + ``{ "ban_level": 5, "kick_level": 5 }`` Description: - TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what + This defines who can ban and/or kick people in the room. Most of the time + ``ban_level`` will be greater than or equal to ``kick_level`` since + banning is more severe than kicking. ``m.room.message`` Summary: -- cgit 1.5.1 From ce5c88006eed9f59103f3aeb73d265731f3d7c4e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 10:47:00 +0100 Subject: Update port numbers. --- docs/client-server/swagger_matrix/api-docs-directory | 2 +- docs/client-server/swagger_matrix/api-docs-events | 2 +- docs/client-server/swagger_matrix/api-docs-login | 2 +- docs/client-server/swagger_matrix/api-docs-presence | 2 +- docs/client-server/swagger_matrix/api-docs-profile | 2 +- docs/client-server/swagger_matrix/api-docs-registration | 2 +- docs/client-server/swagger_matrix/api-docs-rooms | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-directory b/docs/client-server/swagger_matrix/api-docs-directory index 98109a0fbc..380ec3f477 100644 --- a/docs/client-server/swagger_matrix/api-docs-directory +++ b/docs/client-server/swagger_matrix/api-docs-directory @@ -1,7 +1,7 @@ { "apiVersion": "1.0.0", "swaggerVersion": "1.2", - "basePath": "http://localhost:8080/_matrix/client/api/v1", + "basePath": "http://localhost:8008/_matrix/client/api/v1", "resourcePath": "/directory", "produces": [ "application/json" diff --git a/docs/client-server/swagger_matrix/api-docs-events b/docs/client-server/swagger_matrix/api-docs-events index e5dd3a6113..1bdb9b034a 100644 --- a/docs/client-server/swagger_matrix/api-docs-events +++ b/docs/client-server/swagger_matrix/api-docs-events @@ -1,7 +1,7 @@ { "apiVersion": "1.0.0", "swaggerVersion": "1.2", - "basePath": "http://localhost:8080/_matrix/client/api/v1", + "basePath": "http://localhost:8008/_matrix/client/api/v1", "resourcePath": "/events", "produces": [ "application/json" diff --git a/docs/client-server/swagger_matrix/api-docs-login b/docs/client-server/swagger_matrix/api-docs-login index 8cc598b3c1..77a588a68e 100644 --- a/docs/client-server/swagger_matrix/api-docs-login +++ b/docs/client-server/swagger_matrix/api-docs-login @@ -40,7 +40,7 @@ "path": "/login" } ], - "basePath": "http://localhost:8080/_matrix/client/api/v1", + "basePath": "http://localhost:8008/_matrix/client/api/v1", "consumes": [ "application/json" ], diff --git a/docs/client-server/swagger_matrix/api-docs-presence b/docs/client-server/swagger_matrix/api-docs-presence index d52ce2164a..99630d2056 100644 --- a/docs/client-server/swagger_matrix/api-docs-presence +++ b/docs/client-server/swagger_matrix/api-docs-presence @@ -1,7 +1,7 @@ { "apiVersion": "1.0.0", "swaggerVersion": "1.2", - "basePath": "http://localhost:8080/_matrix/client/api/v1", + "basePath": "http://localhost:8008/_matrix/client/api/v1", "resourcePath": "/presence", "produces": [ "application/json" diff --git a/docs/client-server/swagger_matrix/api-docs-profile b/docs/client-server/swagger_matrix/api-docs-profile index 188259fa3d..d2fccaa67d 100644 --- a/docs/client-server/swagger_matrix/api-docs-profile +++ b/docs/client-server/swagger_matrix/api-docs-profile @@ -1,7 +1,7 @@ { "apiVersion": "1.0.0", "swaggerVersion": "1.2", - "basePath": "http://localhost:8080/_matrix/client/api/v1", + "basePath": "http://localhost:8008/_matrix/client/api/v1", "resourcePath": "/profile", "produces": [ "application/json" diff --git a/docs/client-server/swagger_matrix/api-docs-registration b/docs/client-server/swagger_matrix/api-docs-registration index 2048aec1d2..a3dbc01b36 100644 --- a/docs/client-server/swagger_matrix/api-docs-registration +++ b/docs/client-server/swagger_matrix/api-docs-registration @@ -37,7 +37,7 @@ "path": "/register" } ], - "basePath": "http://localhost:8080/_matrix/client/api/v1", + "basePath": "http://localhost:8008/_matrix/client/api/v1", "consumes": [ "application/json" ], diff --git a/docs/client-server/swagger_matrix/api-docs-rooms b/docs/client-server/swagger_matrix/api-docs-rooms index 0a8bb3c2a5..7d1aeb837f 100644 --- a/docs/client-server/swagger_matrix/api-docs-rooms +++ b/docs/client-server/swagger_matrix/api-docs-rooms @@ -1,7 +1,7 @@ { "apiVersion": "1.0.0", "swaggerVersion": "1.2", - "basePath": "http://localhost:8080/_matrix/client/api/v1", + "basePath": "http://localhost:8008/_matrix/client/api/v1", "resourcePath": "/rooms", "produces": [ "application/json" -- cgit 1.5.1 From 3a3fadcece2f90171d82aee1b44956bb4b383549 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 10:58:53 +0100 Subject: Make API docs not lie on registration/login. --- docs/client-server/swagger_matrix/api-docs-login | 22 ++++++++++++++++++++-- .../swagger_matrix/api-docs-registration | 4 ++++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-login b/docs/client-server/swagger_matrix/api-docs-login index 77a588a68e..d6f8d84f29 100644 --- a/docs/client-server/swagger_matrix/api-docs-login +++ b/docs/client-server/swagger_matrix/api-docs-login @@ -8,7 +8,7 @@ "nickname": "get_login_info", "notes": "All login stages MUST be mentioned if there is >1 login type.", "summary": "Get the login mechanism to use when logging in.", - "type": "LoginInfo" + "type": "LoginFlows" }, { "method": "POST", @@ -45,12 +45,26 @@ "application/json" ], "models": { + "LoginFlows": { + "id": "LoginFlows", + "properties": { + "flows": { + "description": "A list of valid login flows.", + "type": "array", + "items": { + "$ref": "LoginInfo" + } + } + } + }, "LoginInfo": { "id": "LoginInfo", "properties": { "stages": { "description": "Multi-stage login only: An array of all the login types required to login.", - "format": "string", + "items": { + "$ref": "string" + }, "type": "array" }, "type": { @@ -65,6 +79,10 @@ "access_token": { "description": "The access token for this user's login if this is the final stage of the login process.", "type": "string" + }, + "user_id": { + "description": "The user's fully-qualified user ID.", + "type": "string" }, "next": { "description": "Multi-stage login only: The next login type to submit.", diff --git a/docs/client-server/swagger_matrix/api-docs-registration b/docs/client-server/swagger_matrix/api-docs-registration index a3dbc01b36..f4669ea2f0 100644 --- a/docs/client-server/swagger_matrix/api-docs-registration +++ b/docs/client-server/swagger_matrix/api-docs-registration @@ -52,6 +52,10 @@ "user_id": { "description": "The fully-qualified user ID.", "type": "string" + }, + "home_server": { + "description": "The name of the home server.", + "type": "string" } } }, -- cgit 1.5.1 From c54d8df5040140c95b8ca31ce2ac023379f8cfdc Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 11:45:30 +0100 Subject: Update API docs to use 'presence' key not 'state'. Fixed error messages when setting presence. --- docs/client-server/swagger_matrix/api-docs-presence | 2 +- synapse/handlers/presence.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-presence b/docs/client-server/swagger_matrix/api-docs-presence index 99630d2056..5c9f160508 100644 --- a/docs/client-server/swagger_matrix/api-docs-presence +++ b/docs/client-server/swagger_matrix/api-docs-presence @@ -106,7 +106,7 @@ "PresenceUpdate": { "id": "PresenceUpdate", "properties": { - "state": { + "presence": { "type": "string", "description": "Enum: The presence state.", "enum": [ diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py index 48549b03e5..beb5aa3a6a 100644 --- a/synapse/handlers/presence.py +++ b/synapse/handlers/presence.py @@ -207,7 +207,7 @@ class PresenceHandler(BaseHandler): raise SynapseError(400, "User is not hosted on this Home Server") if target_user != auth_user: - raise AuthError(400, "Cannot set another user's displayname") + raise AuthError(400, "Cannot set another user's presence") if "status_msg" not in state: state["status_msg"] = None -- cgit 1.5.1 From dfea1730dcb7f75189ede3f8ee71c5421d2aa5ed Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 12:09:11 +0100 Subject: apidocs: mtime_age > last_active_ago. Presence REST: Sanity check values in invite/drop arrays. --- docs/client-server/swagger_matrix/api-docs-presence | 4 ++-- synapse/rest/presence.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-presence b/docs/client-server/swagger_matrix/api-docs-presence index 5c9f160508..6b22446024 100644 --- a/docs/client-server/swagger_matrix/api-docs-presence +++ b/docs/client-server/swagger_matrix/api-docs-presence @@ -128,10 +128,10 @@ "Presence": { "id": "Presence", "properties": { - "mtime_age": { + "last_active_ago": { "type": "integer", "format": "int64", - "description": "The last time this user's presence state changed, in milliseconds." + "description": "The last time this user performed an action on their home server." }, "user_id": { "type": "string", diff --git a/synapse/rest/presence.py b/synapse/rest/presence.py index 69be6fe989..5c5adb4236 100644 --- a/synapse/rest/presence.py +++ b/synapse/rest/presence.py @@ -125,12 +125,20 @@ class PresenceListRestServlet(RestServlet): if "invite" in content: for u in content["invite"]: + if not isinstance(u, basestring): + raise SynapseError(400, "Bad invite value.") + if len(u) == 0: + continue invited_user = self.hs.parse_userid(u) deferreds.append(self.handlers.presence_handler.send_invite( observer_user=user, observed_user=invited_user)) if "drop" in content: for u in content["drop"]: + if not isinstance(u, basestring): + raise SynapseError(400, "Bad drop value.") + if len(u) == 0: + continue dropped_user = self.hs.parse_userid(u) deferreds.append(self.handlers.presence_handler.drop( observer_user=user, observed_user=dropped_user)) -- cgit 1.5.1 From cd0afb85c42aa7d550a61661547a6e7131c83f3d Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 13:08:17 +0100 Subject: Updated feedback api docs and fixed feedback content template bug --- docs/client-server/swagger_matrix/api-docs-rooms | 10 ++++++++++ synapse/api/events/room.py | 3 +-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-rooms b/docs/client-server/swagger_matrix/api-docs-rooms index 7d1aeb837f..3638e44e8c 100644 --- a/docs/client-server/swagger_matrix/api-docs-rooms +++ b/docs/client-server/swagger_matrix/api-docs-rooms @@ -640,6 +640,16 @@ "Feedback": { "id": "Feedback", "properties": { + "target_event_id": { + "type": "string", + "description": "The event ID being acknowledged.", + "required": true + }, + "type": { + "type": "string", + "description": "The type of feedback. Either 'delivered' or 'read'.", + "required": true + } } }, "Member": { diff --git a/synapse/api/events/room.py b/synapse/api/events/room.py index f6d3c59a9a..e4a99ff216 100644 --- a/synapse/api/events/room.py +++ b/synapse/api/events/room.py @@ -103,8 +103,7 @@ class FeedbackEvent(SynapseEvent): def get_content_template(self): return { "type": u"string", - "target_event_id": u"string", - "msg_sender_id": u"string" + "target_event_id": u"string" } -- cgit 1.5.1 From 27cdbf7b94d495e501309e42402d3a656b42f26b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 13:32:25 +0100 Subject: apidocs: Tweak join response format. Explicitly state empty JSON objects where they are required by the spec. Mark unimplemented room GET APIs clearly. --- docs/client-server/swagger_matrix/api-docs-rooms | 40 +++++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-rooms b/docs/client-server/swagger_matrix/api-docs-rooms index 3638e44e8c..40bcc45a78 100644 --- a/docs/client-server/swagger_matrix/api-docs-rooms +++ b/docs/client-server/swagger_matrix/api-docs-rooms @@ -267,6 +267,12 @@ "required": true, "type": "string", "paramType": "path" + }, + { + "name": "body", + "required": true, + "type": "JoinRequest", + "paramType": "body" } ] } @@ -291,6 +297,12 @@ "required": true, "type": "string", "paramType": "path" + }, + { + "name": "body", + "required": true, + "type": "LeaveRequest", + "paramType": "body" } ] } @@ -424,10 +436,10 @@ "path": "/join/{roomAliasOrId}", "operations": [ { - "method": "PUT", + "method": "POST", "summary": "Join a room via a room alias or room ID.", "notes": "Join a room via a room alias or room ID.", - "type": "RoomInfo", + "type": "JoinRoomInfo", "nickname": "join", "consumes": [ "application/json" @@ -574,7 +586,7 @@ { "method": "GET", "summary": "Get a list of all the current state events for this room.", - "notes": "Get a list of all the current state events for this room.", + "notes": "NOT YET IMPLEMENTED.", "type": "array", "items": { "$ref": "Event" @@ -598,7 +610,7 @@ { "method": "GET", "summary": "Get all the current information for this room, including messages and state events.", - "notes": "Get all the current information for this room, including messages and state events.", + "notes": "NOT YET IMPLEMENTED.", "type": "InitialSyncRoomData", "nickname": "get_room_sync_data", "parameters": [ @@ -662,7 +674,7 @@ "invite", "join", "leave", - "knock" + "ban" ] } } @@ -682,6 +694,16 @@ } } }, + "JoinRoomInfo": { + "id": "JoinRoomInfo", + "properties": { + "room_id": { + "type": "string", + "description": "The room ID joined, if joined via a room alias only.", + "required": true + } + } + }, "RoomConfig": { "id": "RoomConfig", "properties": { @@ -840,6 +862,14 @@ } } }, + "JoinRequest": { + "id": "JoinRequest", + "properties": {} + }, + "LeaveRequest": { + "id": "LeaveRequest", + "properties": {} + }, "BanRequest": { "id": "BanRequest", "properties": { -- cgit 1.5.1 From 56bc57cf5095559cb77f69bffbedafdaf5d7b689 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 13:42:56 +0100 Subject: apidocs: Added m.room.name --- docs/client-server/swagger_matrix/api-docs-rooms | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-rooms b/docs/client-server/swagger_matrix/api-docs-rooms index 40bcc45a78..0e1fa452a2 100644 --- a/docs/client-server/swagger_matrix/api-docs-rooms +++ b/docs/client-server/swagger_matrix/api-docs-rooms @@ -180,6 +180,59 @@ } ] }, + { + "path": "/rooms/{roomId}/state/m.room.name", + "operations": [ + { + "method": "PUT", + "summary": "Set the name of this room.", + "notes": "Set the name of this room.", + "type": "void", + "nickname": "set_room_name", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "body", + "description": "The name contents", + "required": true, + "type": "RoomName", + "paramType": "body" + }, + { + "name": "roomId", + "description": "The room to set the name of.", + "required": true, + "type": "string", + "paramType": "path" + } + ] + }, + { + "method": "GET", + "summary": "Get the room's name.", + "notes": "", + "type": "RoomName", + "nickname": "get_room_name", + "parameters": [ + { + "name": "roomId", + "description": "The room to get the name of.", + "required": true, + "type": "string", + "paramType": "path" + } + ], + "responseMessages": [ + { + "code": 404, + "message": "Name not found." + } + ] + } + ] + }, { "path": "/rooms/{roomId}/send/m.room.message.feedback", "operations": [ @@ -636,6 +689,15 @@ } } }, + "RoomName": { + "id": "RoomName", + "properties": { + "name": { + "type": "string", + "description": "The human-readable name for the room. Can contain spaces." + } + } + }, "Message": { "id": "Message", "properties": { -- cgit 1.5.1 From 581c54bebef865039352f4ec141c98413cb45f53 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 16:27:01 +0100 Subject: Add exception handling to directory servlet, so we don't 500. Mark directory API as volatile in the api docs. --- docs/client-server/swagger_matrix/api-docs-directory | 2 ++ synapse/rest/directory.py | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/client-server/swagger_matrix/api-docs-directory b/docs/client-server/swagger_matrix/api-docs-directory index 380ec3f477..ce12be8c96 100644 --- a/docs/client-server/swagger_matrix/api-docs-directory +++ b/docs/client-server/swagger_matrix/api-docs-directory @@ -13,6 +13,7 @@ { "method": "GET", "summary": "Get the room ID corresponding to this room alias.", + "notes": "Volatile: This API is likely to change.", "type": "DirectoryResponse", "nickname": "get_room_id_for_alias", "parameters": [ @@ -28,6 +29,7 @@ { "method": "PUT", "summary": "Create a new mapping from room alias to room ID.", + "notes": "Volatile: This API is likely to change.", "type": "void", "nickname": "add_room_alias", "parameters": [ diff --git a/synapse/rest/directory.py b/synapse/rest/directory.py index 29ace4f1d3..d02b15395b 100644 --- a/synapse/rest/directory.py +++ b/synapse/rest/directory.py @@ -16,6 +16,7 @@ from twisted.internet import defer +from synapse.api.errors import SynapseError, Codes from base import RestServlet, client_path_pattern import json @@ -44,8 +45,10 @@ class ClientDirectoryServer(RestServlet): @defer.inlineCallbacks def on_PUT(self, request, room_alias): - # TODO(erikj): Exceptions - content = json.loads(request.content.read()) + content = _parse_json(request) + if not "room_id" in content: + raise SynapseError(400, "Missing room_id key", + errcode=Codes.BAD_JSON) logger.debug("Got content: %s", content) @@ -72,3 +75,14 @@ class ClientDirectoryServer(RestServlet): logger.exception("Failed to create association") defer.returnValue((200, {})) + + +def _parse_json(request): + try: + content = json.loads(request.content.read()) + if type(content) != dict: + raise SynapseError(400, "Content must be a JSON object.", + errcode=Codes.NOT_JSON) + return content + except ValueError: + raise SynapseError(400, "Content not JSON.", errcode=Codes.NOT_JSON) -- cgit 1.5.1 From e3b261b0b7f3e3097270f1a55bf9651fc120ec5b Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Wed, 3 Sep 2014 17:26:16 +0100 Subject: Move securitY threat model docs into specification --- docs/server-server/security-threat-model.rst | 141 --------------------------- docs/specification.rst | 124 +++++++++++++++++++++++ 2 files changed, 124 insertions(+), 141 deletions(-) delete mode 100644 docs/server-server/security-threat-model.rst (limited to 'docs') diff --git a/docs/server-server/security-threat-model.rst b/docs/server-server/security-threat-model.rst deleted file mode 100644 index cf0430e43d..0000000000 --- a/docs/server-server/security-threat-model.rst +++ /dev/null @@ -1,141 +0,0 @@ -Overview -======== - -Scope ------ - -This document considers threats specific to the server to server federation -synapse protocol. - - -Attacker --------- - -It is assumed that the attacker can see and manipulate all network traffic -between any of the servers and may be in control of one or more homeservers -participating in the federation protocol. - -Threat Model -============ - -Denial of Service ------------------ - -The attacker could attempt to prevent delivery of messages to or from the -victim in order to: - - * Disrupt service or marketing campaign of a commercial competitor. - * Censor a discussion or censor a participant in a discussion. - * Perform general vandalism. - -Threat: Resource Exhaustion -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could cause the victims server to exhaust a particular resource -(e.g. open TCP connections, CPU, memory, disk storage) - -Threat: Unrecoverable Consistency Violations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could send messages which created an unrecoverable "split-brain" -state in the cluster such that the victim's servers could no longer dervive a -consistent view of the chatroom state. - -Threat: Bad History -~~~~~~~~~~~~~~~~~~~ - -An attacker could convince the victim to accept invalid messages which the -victim would then include in their view of the chatroom history. Other servers -in the chatroom would reject the invalid messages and potentially reject the -victims messages as well since they depended on the invalid messages. - -Threat: Block Network Traffic -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could try to firewall traffic between the victim's server and some -or all of the other servers in the chatroom. - -Threat: High Volume of Messages -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could send large volumes of messages to a chatroom with the victim -making the chatroom unusable. - -Threat: Banning users without necessary authorisation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could attempt to ban a user from a chatroom with the necessary -authorisation. - -Spoofing --------- - -An attacker could try to send a message claiming to be from the victim without -the victim having sent the message in order to: - - * Impersonate the victim while performing illict activity. - * Obtain privileges of the victim. - -Threat: Altering Message Contents -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could try to alter the contents of an existing message from the -victim. - -Threat: Fake Message "origin" Field -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could try to send a new message purporting to be from the victim -with a phony "origin" field. - -Spamming --------- - -The attacker could try to send a high volume of solicicted or unsolicted -messages to the victim in order to: - - * Find victims for scams. - * Market unwanted products. - -Threat: Unsoliticted Messages -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could try to send messages to victims who do not wish to receive -them. - -Threat: Abusive Messages -~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could send abusive or threatening messages to the victim - -Spying ------- - -The attacker could try to access message contents or metadata for messages sent -by the victim or to the victim that were not intended to reach the attacker in -order to: - - * Gain sensitive personal or commercial information. - * Impersonate the victim using credentials contained in the messages. - (e.g. password reset messages) - * Discover who the victim was talking to and when. - -Threat: Disclosure during Transmission -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could try to expose the message contents or metadata during -transmission between the servers. - -Threat: Disclosure to Servers Outside Chatroom -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could try to convince servers within a chatroom to send messages to -a server it controls that was not authorised to be within the chatroom. - -Threat: Disclosure to Servers Within Chatroom -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An attacker could take control of a server within a chatroom to expose message -contents or metadata for messages in that room. - - diff --git a/docs/specification.rst b/docs/specification.rst index c67b4ca2b4..bae18147a8 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1625,6 +1625,130 @@ SRV Records Security ======== + +Threat Model +------------ + +Denial of Service +~~~~~~~~~~~~~~~~~ + +The attacker could attempt to prevent delivery of messages to or from the +victim in order to: + + * Disrupt service or marketing campaign of a commercial competitor. + * Censor a discussion or censor a participant in a discussion. + * Perform general vandalism. + +Threat: Resource Exhaustion ++++++++++++++++++++++++++++ + +An attacker could cause the victims server to exhaust a particular resource +(e.g. open TCP connections, CPU, memory, disk storage) + +Threat: Unrecoverable Consistency Violations +++++++++++++++++++++++++++++++++++++++++++++ + +An attacker could send messages which created an unrecoverable "split-brain" +state in the cluster such that the victim's servers could no longer dervive a +consistent view of the chatroom state. + +Threat: Bad History ++++++++++++++++++++ + +An attacker could convince the victim to accept invalid messages which the +victim would then include in their view of the chatroom history. Other servers +in the chatroom would reject the invalid messages and potentially reject the +victims messages as well since they depended on the invalid messages. + +Threat: Block Network Traffic ++++++++++++++++++++++++++++++ + +An attacker could try to firewall traffic between the victim's server and some +or all of the other servers in the chatroom. + +Threat: High Volume of Messages ++++++++++++++++++++++++++++++++ + +An attacker could send large volumes of messages to a chatroom with the victim +making the chatroom unusable. + +Threat: Banning users without necessary authorisation ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +An attacker could attempt to ban a user from a chatroom with the necessary +authorisation. + +Spoofing +~~~~~~~~ + +An attacker could try to send a message claiming to be from the victim without +the victim having sent the message in order to: + +* Impersonate the victim while performing illict activity. +* Obtain privileges of the victim. + +Threat: Altering Message Contents ++++++++++++++++++++++++++++++++++ + +An attacker could try to alter the contents of an existing message from the +victim. + +Threat: Fake Message "origin" Field ++++++++++++++++++++++++++++++++++++ + +An attacker could try to send a new message purporting to be from the victim +with a phony "origin" field. + +Spamming +~~~~~~~~ + +The attacker could try to send a high volume of solicicted or unsolicted +messages to the victim in order to: + +* Find victims for scams. +* Market unwanted products. + +Threat: Unsoliticted Messages ++++++++++++++++++++++++++++++ + +An attacker could try to send messages to victims who do not wish to receive +them. + +Threat: Abusive Messages +++++++++++++++++++++++++ + +An attacker could send abusive or threatening messages to the victim + +Spying +~~~~~~ + +The attacker could try to access message contents or metadata for messages sent +by the victim or to the victim that were not intended to reach the attacker in +order to: + +* Gain sensitive personal or commercial information. +* Impersonate the victim using credentials contained in the messages. + (e.g. password reset messages) +* Discover who the victim was talking to and when. + +Threat: Disclosure during Transmission +++++++++++++++++++++++++++++++++++++++ + +An attacker could try to expose the message contents or metadata during +transmission between the servers. + +Threat: Disclosure to Servers Outside Chatroom +++++++++++++++++++++++++++++++++++++++++++++++ + +An attacker could try to convince servers within a chatroom to send messages to +a server it controls that was not authorised to be within the chatroom. + +Threat: Disclosure to Servers Within Chatroom +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An attacker could take control of a server within a chatroom to expose message +contents or metadata for messages in that room. + .. NOTE:: This section is a work in progress. -- cgit 1.5.1 From f93aba1d66689efa89f11c5230b31b7d04220af2 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Wed, 3 Sep 2014 17:28:35 +0100 Subject: Fix formating for threat model --- docs/specification.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index bae18147a8..e1c83bed78 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1626,6 +1626,9 @@ SRV Records Security ======== +.. NOTE:: + This section is a work in progress. + Threat Model ------------ @@ -1635,9 +1638,9 @@ Denial of Service The attacker could attempt to prevent delivery of messages to or from the victim in order to: - * Disrupt service or marketing campaign of a commercial competitor. - * Censor a discussion or censor a participant in a discussion. - * Perform general vandalism. +* Disrupt service or marketing campaign of a commercial competitor. +* Censor a discussion or censor a participant in a discussion. +* Perform general vandalism. Threat: Resource Exhaustion +++++++++++++++++++++++++++ @@ -1749,9 +1752,6 @@ Threat: Disclosure to Servers Within Chatroom An attacker could take control of a server within a chatroom to expose message contents or metadata for messages in that room. -.. NOTE:: - This section is a work in progress. - Rate limiting ------------- Home servers SHOULD implement rate limiting to reduce the risk of being overloaded. If a -- cgit 1.5.1 From 7c4ce957c76a187a5ef8fd79646ce77457137138 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Wed, 3 Sep 2014 17:37:08 +0100 Subject: Unindent list in specification to remove blockquote --- docs/specification.rst | 68 ++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index e1c83bed78..c5b6fe29c8 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -30,48 +30,52 @@ ecosystem to communicate with one another. The principles that Matrix attempts to follow are: - - Pragmatic Web-friendly APIs (i.e. JSON over REST) - - Keep It Simple & Stupid +- Pragmatic Web-friendly APIs (i.e. JSON over REST) +- Keep It Simple & Stupid - + provide a simple architecture with minimal third-party dependencies. + + provide a simple architecture with minimal third-party dependencies. - - Fully open: +- Fully open: - + Fully open federation - anyone should be able to participate in the global Matrix network - + Fully open standard - publicly documented standard with no IP or patent licensing encumbrances - + Fully open source reference implementation - liberally-licensed example implementations with no - IP or patent licensing encumbrances + + Fully open federation - anyone should be able to participate in the global + Matrix network + + Fully open standard - publicly documented standard with no IP or patent + licensing encumbrances + + Fully open source reference implementation - liberally-licensed example + implementations with no IP or patent licensing encumbrances - - Empowering the end-user +- Empowering the end-user - + The user should be able to choose the server and clients they use - + The user should be control how private their communication is - + The user should know precisely where their data is stored + + The user should be able to choose the server and clients they use + + The user should be control how private their communication is + + The user should know precisely where their data is stored - - Fully decentralised - no single points of control over conversations or the network as a whole - - Learning from history to avoid repeating it +- Fully decentralised - no single points of control over conversations or the + network as a whole +- Learning from history to avoid repeating it - + Trying to take the best aspects of XMPP, SIP, IRC, SMTP, IMAP and NNTP whilst trying to avoid their failings + + Trying to take the best aspects of XMPP, SIP, IRC, SMTP, IMAP and NNTP + whilst trying to avoid their failings The functionality that Matrix provides includes: - - Creation and management of fully distributed chat rooms with no - single points of control or failure - - Eventually-consistent cryptographically secure synchronisation of room - state across a global open network of federated servers and services - - Sending and receiving extensible messages in a room with (optional) - end-to-end encryption - - Extensible user management (inviting, joining, leaving, kicking, banning) - mediated by a power-level based user privilege system. - - Extensible room state management (room naming, aliasing, topics, bans) - - Extensible user profile management (avatars, displaynames, etc) - - Managing user accounts (registration, login, logout) - - Use of 3rd Party IDs (3PIDs) such as email addresses, phone numbers, - Facebook accounts to authenticate, identify and discover users on Matrix. - - Trusted federation of Identity servers for: - - + Publishing user public keys for PKI - + Mapping of 3PIDs to Matrix IDs +- Creation and management of fully distributed chat rooms with no + single points of control or failure +- Eventually-consistent cryptographically secure synchronisation of room + state across a global open network of federated servers and services +- Sending and receiving extensible messages in a room with (optional) + end-to-end encryption +- Extensible user management (inviting, joining, leaving, kicking, banning) + mediated by a power-level based user privilege system. +- Extensible room state management (room naming, aliasing, topics, bans) +- Extensible user profile management (avatars, displaynames, etc) +- Managing user accounts (registration, login, logout) +- Use of 3rd Party IDs (3PIDs) such as email addresses, phone numbers, + Facebook accounts to authenticate, identify and discover users on Matrix. +- Trusted federation of Identity servers for: + + + Publishing user public keys for PKI + + Mapping of 3PIDs to Matrix IDs The end goal of Matrix is to be a ubiquitous messaging layer for synchronising arbitrary data between sets of people, devices and services - be that for instant -- cgit 1.5.1 From 79bf9d25db8758a0368c0de568918cc72074965c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 17:48:01 +0100 Subject: Added more terms. --- docs/specification.rst | 72 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index c5b6fe29c8..d331f36b4b 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1809,12 +1809,76 @@ Glossary .. NOTE:: This section is a work in progress. -.. TODO - - domain specific words/acronyms with definitions +Backfilling: + The process of synchronising historic state from one home server to another, + to backfill the event storage so that scrollback can be presented to the + client(s). Not to be confused with pagination. + +Context: + A single human-level entity of interest (currently, a chat room) + +EDU (Ephemeral Data Unit): + A message that relates directly to a given pair of home servers that are + exchanging it. EDUs are short-lived messages that related only to one single + pair of servers; they are not persisted for a long time and are not forwarded + on to other servers. Because of this, they have no internal ID nor previous + EDUs reference chain. + +Event: + A record of activity that records a single thing that happened on to a context + (currently, a chat room). These are the "chat messages" that Synapse makes + available. + +PDU (Persistent Data Unit): + A message that relates to a single context, irrespective of the server that + is communicating it. PDUs either encode a single Event, or a single State + change. A PDU is referred to by its PDU ID; the pair of its origin server + and local reference from that server. + +PDU ID: + The pair of PDU Origin and PDU Reference, that together globally uniquely + refers to a specific PDU. + +PDU Origin: + The name of the origin server that generated a given PDU. This may not be the + server from which it has been received, due to the way they are copied around + from server to server. The origin always records the original server that + created it. + +PDU Reference: + A local ID used to refer to a specific PDU from a given origin server. These + references are opaque at the protocol level, but may optionally have some + structured meaning within a given origin server or implementation. + +Presence: + The concept of whether a user is currently online, how available they declare + they are, and so on. See also: doc/model/presence + +Profile: + A set of metadata about a user, such as a display name, provided for the + benefit of other users. See also: doc/model/profiles + +Room ID: + An opaque string (of as-yet undecided format) that identifies a particular + room and used in PDUs referring to it. + +Room Alias: + A human-readable string of the form #name:some.domain that users can use as a + pointer to identify a room; a Directory Server will map this to its Room ID + +State: + A set of metadata maintained about a Context, which is replicated among the + servers in addition to the history of Events. User ID: - An opaque ID which identifies an end-user, which consists of some opaque - localpart combined with the domain name of their home server. + A string of the form @localpart:domain.name that identifies a user for + wire-protocol purposes. The localpart is meaningless outside of a particular + home server. This takes a human-readable form that end-users can use directly + if they so wish, avoiding the 3PIDs. + +Transaction: + A message which relates to the communication between a given pair of servers. + A transaction contains possibly-empty lists of PDUs and EDUs. .. Links through the external API docs are below -- cgit 1.5.1 From f68dbbd3dad4fd589197d3a3f55136eef2b43acd Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 17:59:54 +0100 Subject: More explanation of federation keys. --- docs/specification.rst | 132 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 8 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index d331f36b4b..44eddcaf87 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1510,6 +1510,31 @@ Each transaction has: - An origin and destination server name. - A list of "previous IDs". - A list of PDUs and EDUs - the actual message payload that the Transaction carries. + +``origin`` + Type: + String + Description: + DNS name of homeserver making this transaction. + +``ts`` + Type: + Integer + Description: + Timestamp in milliseconds on originating homeserver when this transaction + started. + +``previous_ids`` + Type: + List of strings + Description: + List of transactions that were sent immediately prior to this transaction. + +``pdus`` + Type: + List of Objects. + Description: + List of updates contained in this transaction. :: @@ -1551,8 +1576,98 @@ All PDUs have: - A list of other PDU IDs that have been seen recently on that context (regardless of which origin sent them) -[[TODO(paul): Update this structure so that 'pdu_id' is a two-element -[origin,ref] pair like the prev_pdus are]] +``context`` + Type: + String + Description: + Event context identifier + +``origin`` + Type: + String + Description: + DNS name of homeserver that created this PDU. + +``pdu_id`` + Type: + String + Description: + Unique identifier for PDU within the context for the originating homeserver + +``ts`` + Type: + Integer + Description: + Timestamp in milliseconds on originating homeserver when this PDU was created. + +``pdu_type`` + Type: + String + Description: + PDU event type. + +``prev_pdus`` + Type: + List of pairs of strings + Description: + The originating homeserver and PDU ids of the most recent PDUs the + homeserver was aware of for this context when it made this PDU. + +``depth`` + Type: + Integer + Description: + The maximum depth of the previous PDUs plus one. + + +.. TODO paul + [[TODO(paul): Update this structure so that 'pdu_id' is a two-element + [origin,ref] pair like the prev_pdus are]] + + +For state updates: + +``is_state`` + Type: + Boolean + Description: + True if this PDU is updating state. + +``state_key`` + Type: + String + Description: + Optional key identifying the updated state within the context. + +``power_level`` + Type: + Integer + Description: + The asserted power level of the user performing the update. + +``min_update`` + Type: + Integer + Description: + The required power level needed to replace this update. + +``prev_state_id`` + Type: + String + Description: + PDU event type. + +``prev_state_origin`` + Type: + String + Description: + The PDU id of the update this replaces. + +``user`` + Type: + String + Description: + The user updating the state. :: @@ -1593,12 +1708,13 @@ keys exist to support this: "prev_state_id":TODO "prev_state_origin":TODO} -[[TODO(paul): At this point we should probably have a long description of how -State management works, with descriptions of clobbering rules, power levels, etc -etc... But some of that detail is rather up-in-the-air, on the whiteboard, and -so on. This part needs refining. And writing in its own document as the details -relate to the server/system as a whole, not specifically to server-server -federation.]] +.. TODO paul + [[TODO(paul): At this point we should probably have a long description of how + State management works, with descriptions of clobbering rules, power levels, etc + etc... But some of that detail is rather up-in-the-air, on the whiteboard, and + so on. This part needs refining. And writing in its own document as the details + relate to the server/system as a whole, not specifically to server-server + federation.]] EDUs, by comparison to PDUs, do not have an ID, a context, or a list of "previous" IDs. The only mandatory fields for these are the type, origin and -- cgit 1.5.1 From 5391ccdfe67fa21493f5402830e7e494a9bc4787 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 18:02:33 +0100 Subject: Marked docs/client-server/specification.rst as old. --- docs/client-server/OLD_specification.rst | 1283 ++++++++++++++++++++++++++++++ docs/client-server/specification.rst | 1269 ----------------------------- 2 files changed, 1283 insertions(+), 1269 deletions(-) create mode 100644 docs/client-server/OLD_specification.rst delete mode 100644 docs/client-server/specification.rst (limited to 'docs') diff --git a/docs/client-server/OLD_specification.rst b/docs/client-server/OLD_specification.rst new file mode 100644 index 0000000000..47fba5eeac --- /dev/null +++ b/docs/client-server/OLD_specification.rst @@ -0,0 +1,1283 @@ +======================== +Matrix Client-Server API +======================== + + +.. WARNING:: + This specification is old. Please see /docs/specification.rst instead. + + + + + + + + + + + +The following specification outlines how a client can send and receive data from +a home server. + +[[TODO(kegan): 4/7/14 Grilling +- Mechanism for getting historical state changes (e.g. topic updates) - add + query param flag? +- Generic mechanism for linking first class events (e.g. feedback) with other s + first class events (e.g. messages)? +- Generic mechanism for updating 'stuff about the room' (e.g. favourite coffee) + AND specifying clobbering rules (clobber/add to list/etc)? +- How to ensure a consistent view for clients paginating through room lists? + They aren't really ordered in any way, and if you're paginating + through them, how can you show them a consistent result set? Temporary 'room + list versions' akin to event version? How does that work? +]] + +[[TODO(kegan): +Outstanding problems / missing spec: +- Push +- Typing notifications +]] + +Terminology +----------- +Stream Tokens: +An opaque token used to make further streaming requests. When using any +pagination streaming API, responses will contain a start and end stream token. +When reconnecting to the stream, these tokens can be used to tell the server +where the client got up to in the stream. + +Event ID: +Every event that comes down the event stream or that is returned from the REST +API has an associated event ID (event_id). This ID will be the same between the +REST API and the event stream, so any duplicate events can be clobbered +correctly without knowing anything else about the event. + +Message ID: +The ID of a message sent by a client in a room. Clients send IMs to each other +in rooms. Each IM sent by a client must have a unique message ID which is unique +for that particular client. + +User ID: +The @username:host style ID of the client. When registering for an account, the +client specifies their username. The user_id is this username along with the +home server's unique hostname. When federating between home servers, the user_id +is used to uniquely identify users across multiple home servers. + +Room ID: +The room_id@host style ID for the room. When rooms are created, the client either +specifies or is allocated a room ID. This room ID must be used to send messages +in that room. Like with clients, there may be multiple rooms with the same ID +across multiple home servers. The room_id is used to uniquely identify a room +when federating. + +Global message ID: +The globally unique ID for a message. This ID is formed from the msg_id, the +client's user_id and the room_id. This uniquely identifies any +message. It is represented with '-' as the delimeter between IDs. The +global_msg_id is of the form: room_id-user_id-msg_id + + +REST API and the Event Stream +----------------------------- +Clients send data to the server via a RESTful API. They can receive data via +this API or from an event stream. An event stream is a special path which +streams all events the client may be interested in. This makes it easy to +immediately receive updates from the REST API. All data is represented as JSON. + +Pagination streaming API +======================== +Clients are often interested in very large datasets. The data itself could +be 1000s of messages in a given room, 1000s of rooms in a public room list, or +1000s of events (presence, typing, messages, etc) in the system. It is not +practical to send vast quantities of data to the client every time they +request a list of public rooms for example. There needs to be a way to show a +subset of this data, and apply various filters to it. This is what the pagination +streaming API is. This API defines standard request/response parameters which +can be used when navigating this stream of data. + +Pagination Request Query Parameters +----------------------------------- +Clients may wish to paginate results from the event stream, or other sources of +information where the amount of information may be a problem, +e.g. in a room with 10,000s messages. The pagination query parameters provide a +way to navigate a 'window' around a large set of data. These +parameters are only valid for GET requests. + + S e r v e r - s i d e d a t a + |-------------------------------------------------| +START ^ ^ END + |_______________| + | + Client-extraction + +'START' and 'END' are magic token values which specify the start and end of the +dataset respectively. + +Query parameters: + from : $streamtoken - The opaque token to start streaming from. + to : $streamtoken - The opaque token to end streaming at. Typically, + clients will not know the item of data to end at, so this will usually be + START or END. + limit : integer - An integer representing the maximum number of items to + return. + +For example, the event stream has events E1 -> E15. The client wants the last 5 +events and doesn't know any previous events: + +S E +|-E1-E2-E3-E4-E5-E6-E7-E8-E9-E10-E11-E12-E13-E14-E15-| +| | | +| _____| | +|__________________ | ___________________| + | | | + GET /events?to=START&limit=5&from=END + Returns: + E15,E14,E13,E12,E11 + + +Another example: a public room list has rooms R1 -> R17. The client is showing 5 +rooms at a time on screen, and is on page 2. They want to +now show page 3 (rooms R11 -> 15): + +S E +| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | stream token +|-R1-R2-R3-R4-R5-R6-R7-R8-R9-R10-R11-R12-R13-R14-R15-R16-R17| room + |____________| |________________| + | | + Currently | + viewing | + | + GET /rooms/list?from=9&to=END&limit=5 + Returns: R11,R12,R13,R14,R15 + +Note that tokens are treated in an *exclusive*, not inclusive, manner. The end +token from the intial request was '9' which corresponded to R10. When the 2nd +request was made, R10 did not appear again, even though from=9 was specified. If +you know the token, you already have the data. + +Pagination Response +------------------- +Responses to pagination requests MUST follow the format: +{ + "chunk": [ ... , Responses , ... ], + "start" : $streamtoken, + "end" : $streamtoken +} +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". + +If the client wants earlier results, they should use from=$start_streamtoken, +to=START. Likewise, if the client wants later results, they should use +from=$end_streamtoken, to=END. + +Unless specified, the default pagination parameters are from=START, to=END, +without a limit set. This allows you to hit an API like +/events without any query parameters to get everything. + +The Event Stream +---------------- +The event stream returns events using the pagination streaming API. When the +client disconnects for a while and wants to reconnect to the event stream, they +should specify from=$end_streamtoken. This lets the server know where in the +event stream the client is. These tokens are completely opaque, and the client +cannot infer anything from them. + + GET /events?from=$LAST_STREAM_TOKEN + REST Path: /events + Returns (success): A JSON array of Event Data. + Returns (failure): An Error Response + +LAST_STREAM_TOKEN is the last stream token obtained from the event stream. If the +client is connecting for the first time and does not know any stream tokens, +they can use "START" to request all events from the start. For more information +on this, see "Pagination Request Query Parameters". + +The event stream supports shortpoll and longpoll with the "timeout" query +parameter. This parameter specifies the number of milliseconds the server should +hold onto the connection waiting for incoming events. If no events occur in this +period, the connection will be closed and an empty chunk will be returned. To +use shortpoll, specify "timeout=0". + +Event Data +---------- +This is a JSON object which looks like: +{ + "event_id" : $EVENT_ID, + "type" : $EVENT_TYPE, + $URL_ARGS, + "content" : { + $EVENT_CONTENT + } +} + +EVENT_ID + An ID identifying this event. This is so duplicate events can be suppressed on + the client. + +EVENT_TYPE + The namespaced event type (m.*) + +URL_ARGS + Path specific data from the REST API. + +EVENT_CONTENT + The event content, matching the REST content PUT previously. + +Events are differentiated via the event type "type" key. This is the type of +event being received. This can be expanded upon by using different namespaces. +Every event MUST have a 'type' key. + +Most events will have a corresponding REST URL. This URL will generally have +data in it to represent the resource being modified, +e.g. /rooms/$room_id. The event data will contain extra top-level keys to expose +this information to clients listening on an event +stream. The event content maps directly to the contents submitted via the REST +API. + +For example: + Event Type: m.example.room.members + REST Path: /examples/room/$room_id/members/$user_id + REST Content: { "membership" : "invited" } + +is represented in the event stream as: + +{ + "event_id" : "e_some_event_id", + "type" : "m.example.room.members", + "room_id" : $room_id, + "user_id" : $user_id, + "content" : { + "membership" : "invited" + } +} + +As convention, the URL variable "$varname" will map directly onto the name +of the JSON key "varname". + +Error Responses +--------------- +If the client sends an invalid request, the server MAY respond with an error +response. This is of the form: +{ + "error" : "string", + "errcode" : "string" +} +The 'error' string will be a human-readable error message, usually a sentence +explaining what went wrong. + +The 'errcode' string will be a unique string which can be used to handle an +error message e.g. "M_FORBIDDEN". These error codes should have their namespace +first in ALL CAPS, followed by a single _. For example, if there was a custom +namespace com.mydomain.here, and a "FORBIDDEN" code, the error code should look +like "COM.MYDOMAIN.HERE_FORBIDDEN". There may be additional keys depending on +the error, but the keys 'error' and 'errcode' will always be present. + +Some standard error codes are below: + +M_FORBIDDEN: +Forbidden access, e.g. joining a room without permission, failed login. + +M_UNKNOWN_TOKEN: +The access token specified was not recognised. + +M_BAD_JSON: +Request contained valid JSON, but it was malformed in some way, e.g. missing +required keys, invalid values for keys. + +M_NOT_JSON: +Request did not contain valid JSON. + +M_NOT_FOUND: +No resource was found for this request. + +Some requests have unique error codes: + +M_USER_IN_USE: +Encountered when trying to register a user ID which has been taken. + +M_ROOM_IN_USE: +Encountered when trying to create a room which has been taken. + +M_BAD_PAGINATION: +Encountered when specifying bad pagination values to a Pagination Streaming API. + + +======== +REST API +======== + +All content must be application/json. Some keys are required, while others are +optional. Unless otherwise specified, +all HTTP PUT/POST/DELETEs will return a 200 OK with an empty response body on +success, and a 4xx/5xx with an optional Error Response on failure. When sending +data, if there are no keys to send, an empty JSON object should be sent. + +All POST/PUT/GET/DELETE requests MUST have an 'access_token' query parameter to +allow the server to authenticate the client. All +POST requests MUST be submitted as application/json. + +All paths MUST be namespaced by the version of the API being used. This should +be: + +/_matrix/client/api/v1 + +All REST paths in this section MUST be prefixed with this. E.g. + REST Path: /rooms/$room_id + Absolute Path: /_matrix/client/api/v1/rooms/$room_id + +Registration +============ +Clients must register with the server in order to use the service. After +registering, the client will be given an +access token which must be used in ALL requests as a query parameter +'access_token'. + +Registering for an account +-------------------------- + POST /register + With: A JSON object containing the key "user_id" which contains the desired + user_id, or an empty JSON object to have the server allocate a user_id + automatically. + Returns (success): 200 OK with a JSON object: + { + "user_id" : "string [user_id]", + "access_token" : "string" + } + Returns (failure): An Error Response. M_USER_IN_USE if the user ID is taken. + + +Unregistering an account +------------------------ + POST /unregister + With query parameters: access_token=$ACCESS_TOKEN + Returns (success): 200 OK + Returns (failure): An Error Response. + + +Logging in to an existing account +================================= +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 user/password auth, login via a social network (OAuth), login by confirming +a token sent to their email address, etc. This section does NOT define how home +servers should authorise their users who want to login to their existing +accounts. This section defines the standard interface which implementations +should follow so that ANY client can login to ANY home server. + +The login process breaks down into the following: + 1: Get login process info. + 2: Submit the login stage credentials. + 3: Get access token or be told the next stage in the login process and repeat + step 2. + +Getting login process info: + GET /login + Returns (success): 200 OK with LoginInfo. + Returns (failure): An Error Response. + +Submitting the login stage credentials: + POST /login + With: LoginSubmission + Returns (success): 200 OK with LoginResult + Returns (failure): An Error Response + +Where LoginInfo is a JSON object which MUST have a "type" key which denotes the +login type. If there are multiple login stages, this object MUST also contain a +"stages" key, which has a JSON array of login types denoting all the steps in +order to login, including the first stage which is in "type". This allows the +client to make an informed decision as to whether or not they can natively +handle the entire login process, or whether they should fallback (see below). + +Where LoginSubmission is a JSON object which MUST have a "type" key. + +Where LoginResult is a JSON object which MUST have either a "next" key OR an +"access_token" key, depending if the login process is over or not. This object +MUST have a "session" key if multiple POSTs need to be sent to /login. + +Fallback +-------- +If the client does NOT know how to handle the given type, they should: + GET /login/fallback +This MUST return an HTML page which can perform the entire login process. + +Password-based +-------------- +Type: "m.login.password" +LoginSubmission: +{ + "type": "m.login.password", + "user": , + "password": +} + +Example: +Assume you are @bob:matrix.org and you wish to login on another mobile device. +First, you GET /login which returns: +{ + "type": "m.login.password" +} +Your client knows how to handle this, so your client prompts the user to enter +their username and password. This is then submitted: +{ + "type": "m.login.password", + "user": "@bob:matrix.org", + "password": "monkey" +} +The server checks this, finds it is valid, and returns: +{ + "access_token": "abcdef0123456789" +} +The server may optionally return "user_id" to confirm or change the user's ID. +This is particularly useful if the home server wishes to support localpart entry +of usernames (e.g. "bob" rather than "@bob:matrix.org"). + +OAuth2-based +------------ +Type: "m.login.oauth2" +This is a multi-stage login. + +LoginSubmission: +{ + "type": "m.login.oauth2", + "user": +} +Returns: +{ + "uri": +} + +The home server acts as a 'confidential' Client for the purposes of OAuth2. + +If the uri is a "sevice selection uri", it is a simple page which prompts the +user to choose which service to authorize with. On selection of a service, they +link through to Authorization Request URIs. If there is only 1 service which the +home server accepts when logging in, this indirection can be skipped and the +"uri" key can be the Authorization Request URI. + +The client 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 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 knows that the cilent has authed with the 3rd party, and +so can return a LoginResult. + +The OAuth redirect URI (with auth code) MUST return a LoginResult. + +Example: +Assume you are @bob:matrix.org and you wish to login on another mobile device. +First, you GET /login which returns: +{ + "type": "m.login.oauth2" +} +Your client knows how to handle this, so your client prompts the user to enter +their username. This is then submitted: +{ + "type": "m.login.oauth2", + "user": "@bob:matrix.org" +} +The server only accepts auth from Google, so returns the Authorization Request +URI for Google: +{ + "uri": "https://accounts.google.com/o/oauth2/auth?response_type=code& + client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos" +} +The client then visits this URI and authorizes the home server. The client then +visits the REDIRECT_URI with the auth code= query parameter which returns: +{ + "access_token": "0123456789abcdef" +} + +Email-based (code) +------------------ +Type: "m.login.email.code" +This is a multi-stage login. + +First LoginSubmission: +{ + "type": "m.login.email.code", + "user": + "email": +} +Returns: +{ + "session": +} + +The email contains a code which must be sent in the next LoginSubmission: +{ + "type": "m.login.email.code", + "session": , + "code": +} +Returns: +{ + "access_token": +} + +Example: +Assume you are @bob:matrix.org and you wish to login on another mobile device. +First, you GET /login which returns: +{ + "type": "m.login.email.code" +} +Your client knows how to handle this, so your client prompts the user to enter +their email address. This is then submitted: +{ + "type": "m.login.email.code", + "user": "@bob:matrix.org", + "email": "bob@mydomain.com" +} +The server confirms that bob@mydomain.com is linked to @bob:matrix.org, then +sends an email to this address and returns: +{ + "session": "ewuigf7462" +} +The client's screen changes to a code submission page. The email arrives and it +says something to the effect of "please enter 2348623 into the app". This is +the submitted along with the session: +{ + "type": "m.login.email.code", + "session": "ewuigf7462", + "code": "2348623" +} +The server accepts this and returns: +{ + "access_token": "abcdef0123456789" +} + +Email-based (url) +----------------- +Type: "m.login.email.url" +This is a multi-stage login. + +First LoginSubmission: +{ + "type": "m.login.email.url", + "user": + "email": +} +Returns: +{ + "session": +} + +The email contains a URL which must be clicked. After it has been clicked, the +client should perform a request: +{ + "type": "m.login.email.code", + "session": +} +Returns: +{ + "access_token": +} + +Example: +Assume you are @bob:matrix.org and you wish to login on another mobile device. +First, you GET /login which returns: +{ + "type": "m.login.email.url" +} +Your client knows how to handle this, so your client prompts the user to enter +their email address. This is then submitted: +{ + "type": "m.login.email.url", + "user": "@bob:matrix.org", + "email": "bob@mydomain.com" +} +The server confirms that bob@mydomain.com is linked to @bob:matrix.org, then +sends an email to this address and returns: +{ + "session": "ewuigf7462" +} +The client then starts polling the server with the following: +{ + "type": "m.login.email.url", + "session": "ewuigf7462" +} +(Alternatively, the server could send the device a push notification when the +email has been validated). The email arrives and it contains a URL to click on. +The user clicks on the which completes the login process with the server. The +next time the client polls, it returns: +{ + "access_token": "abcdef0123456789" +} + +N-Factor auth +------------- +Multiple login stages can be combined with the "next" key in the LoginResult. + +Example: +A server demands an email.code then password auth before logging in. First, the +client performs a GET /login which returns: +{ + "type": "m.login.email.code", + "stages": ["m.login.email.code", "m.login.password"] +} +The client performs the email login (See "Email-based (code)"), but instead of +returning an access_token, it returns: +{ + "next": "m.login.password" +} +The client then presents a user/password screen and the login continues until +this is complete (See "Password-based"), which then returns the "access_token". + +Rooms +===== +A room is a conceptual place where users can send and receive messages. Rooms +can be created, joined and left. Messages are sent +to a room, and all participants in that room will receive the message. Rooms are +uniquely identified via the room_id. + +Creating a room (with a room ID) +-------------------------------- + Event Type: m.room.create [TODO(kegan): Do we generate events for this?] + REST Path: /rooms/$room_id + Valid methods: PUT + Required keys: None. + Optional keys: + visibility : [public|private] - Set whether this room shows up in the public + room list. + Returns: + On Failure: MAY return a suggested alternative room ID if this room ID is + taken. + { + suggested_room_id : $new_room_id + error : "Room already in use." + errcode : "M_ROOM_IN_USE" + } + + +Creating a room (without a room ID) +----------------------------------- + Event Type: m.room.create [TODO(kegan): Do we generate events for this?] + REST Path: /rooms + Valid methods: POST + Required keys: None. + Optional keys: + visibility : [public|private] - Set whether this room shows up in the public + room list. + Returns: + On Success: The allocated room ID. Additional information about the room + such as the visibility MAY be included as extra keys in this response. + { + room_id : $room_id + } + +Setting the topic for a room +---------------------------- + Event Type: m.room.topic + REST Path: /rooms/$room_id/topic + Valid methods: GET/PUT + Required keys: + topic : $topicname - Set the topic to $topicname in room $room_id. + + +See a list of public rooms +-------------------------- + REST Path: /public/rooms?pagination_query_parameters + Valid methods: GET + This API can use pagination query parameters. + Returns: + { + "chunk" : JSON array of RoomInfo JSON objects - Required. + "start" : "string (start token)" - See Pagination Response. + "end" : "string (end token)" - See Pagination Response. + "total" : integer - Optional. The total number of rooms. + } + +RoomInfo: Information about a single room. + Servers MUST send the key: room_id + Servers MAY send the keys: topic, num_members + { + "room_id" : "string", + "topic" : "string", + "num_members" : integer + } + +Room Members +============ + +Invite/Joining/Leaving a room +----------------------------- + Event Type: m.room.member + REST Path: /rooms/$room_id/members/$user_id/state + Valid methods: PUT/GET/DELETE + Required keys: + membership : [join|invite] - The membership state of $user_id in room + $room_id. + Optional keys: + displayname, + avatar_url : String fields from the member user's profile + state, + status_msg, + mtime_age : Presence information + + These optional keys provide extra information that the client is likely to + be interested in so it doesn't have to perform an additional profile or + presence information fetch. + +Where: + join - Indicate you ($user_id) are joining the room $room_id. + invite - Indicate that $user_id has been invited to room $room_id. + +User $user_id can leave room $room_id by DELETEing this path. + +Checking the user list of a room +-------------------------------- + REST Path: /rooms/$room_id/members/list + This API can use pagination query parameters. + Valid methods: GET + Returns: + A pagination response with chunk data as m.room.member events. + +Messages +======== +Users send messages to other users in rooms. These messages may be text, images, +video, etc. Clients may also want to acknowledge messages by sending feedback, +in the form of delivery/read receipts. + +Server-attached keys +-------------------- +The server MAY attach additional keys to messages and feedback. If a client +submits keys with the same name, they will be clobbered by +the server. + +Required keys: +from : "string [user_id]" + The user_id of the user who sent the message/feedback. + +Optional keys: +hsob_ts : integer + A timestamp (ms resolution) representing when the message/feedback got to the + sender's home server ("home server outbound timestamp"). + +hsib_ts : integer + A timestamp (ms resolution) representing when the + message/feedback got to the receiver's home server ("home server inbound + timestamp"). This may be the same as hsob_ts if the sender/receiver are on the + same home server. + +Sending messages +---------------- + Event Type: m.room.message + REST Path: /rooms/$room_id/messages/$from/$msg_id + Valid methods: GET/PUT + URL parameters: + $from : user_id - The sender's user_id. This value will be clobbered by the + server before sending. + Required keys: + msgtype: [m.text|m.emote|m.image|m.audio|m.video|m.location|m.file] - + The type of message. Not to be confused with the Event 'type'. + Optional keys: + sender_ts : integer - A timestamp (ms resolution) representing the + wall-clock time when the message was sent from the client. + Reserved keys: + body : "string" - The human readable string for compatibility with clients + which cannot process a given msgtype. This key is optional, but + if it is included, it MUST be human readable text + describing the message. See individual msgtypes for more + info on what this means in practice. + +Each msgtype may have required fields of their own. + +msgtype: m.text +---------------- +Required keys: + body : "string" - The body of the message. +Optional keys: + None. + +msgtype: m.emote +----------------- +Required keys: + body : "string" - *tries to come up with a witty explanation*. +Optional keys: + None. + +msgtype: m.image +----------------- +Required keys: + url : "string" - The URL to the image. +Optional keys: + body : "string" - info : JSON object (ImageInfo) - The image info for image + referred to in 'url'. + thumbnail_url : "string" - The URL to the thumbnail. + thumbnail_info : JSON object (ImageInfo) - The image info for the image + referred to in 'thumbnail_url'. + +ImageInfo: Information about an image. +{ + "size" : integer (size of image in bytes), + "w" : integer (width of image in pixels), + "h" : integer (height of image in pixels), + "mimetype" : "string (e.g. image/jpeg)" +} + +Interpretation of 'body' key: The alt text of the image, or some kind of content +description for accessibility e.g. "image attachment". + +msgtype: m.audio +----------------- +Required keys: + url : "string" - The URL to the audio. +Optional keys: + info : JSON object (AudioInfo) - The audio info for the audio referred to in + 'url'. + +AudioInfo: Information about a piece of audio. +{ + "mimetype" : "string (e.g. audio/aac)", + "size" : integer (size of audio in bytes), + "duration" : integer (duration of audio in milliseconds) +} + +Interpretation of 'body' key: A description of the audio e.g. "Bee Gees - +Stayin' Alive", or some kind of content description for accessibility e.g. +"audio attachment". + +msgtype: m.video +----------------- +Required keys: + url : "string" - The URL to the video. +Optional keys: + info : JSON object (VideoInfo) - The video info for the video referred to in + 'url'. + +VideoInfo: Information about a video. +{ + "mimetype" : "string (e.g. video/mp4)", + "size" : integer (size of video in bytes), + "duration" : integer (duration of video in milliseconds), + "w" : integer (width of video in pixels), + "h" : integer (height of video in pixels), + "thumbnail_url" : "string (URL to image)", + "thumbanil_info" : JSON object (ImageInfo) +} + +Interpretation of 'body' key: A description of the video e.g. "Gangnam style", +or some kind of content description for accessibility e.g. "video attachment". + +msgtype: m.location +-------------------- +Required keys: + geo_uri : "string" - The geo URI representing the location. +Optional keys: + thumbnail_url : "string" - The URL to a thumnail of the location being + represented. + thumbnail_info : JSON object (ImageInfo) - The image info for the image + referred to in 'thumbnail_url'. + +Interpretation of 'body' key: A description of the location e.g. "Big Ben, +London, UK", or some kind of content description for accessibility e.g. +"location attachment". + + +Sending feedback +---------------- +When you receive a message, you may want to send delivery receipt to let the +sender know that the message arrived. You may also want to send a read receipt +when the user has read the message. These receipts are collectively known as +'feedback'. + + Event Type: m.room.message.feedback + REST Path: /rooms/$room_id/messages/$msgfrom/$msg_id/feedback/$from/$feedback + Valid methods: GET/PUT + URL parameters: + $msgfrom - The sender of the message's user_id. + $from : user_id - The sender of the feedback's user_id. This value will be + clobbered by the server before sending. + $feedback : [d|r] - Specify if this is a [d]elivery or [r]ead receipt. + Required keys: + None. + Optional keys: + sender_ts : integer - A timestamp (ms resolution) representing the + wall-clock time when the receipt was sent from the client. + +Receiving messages (bulk/pagination) +------------------------------------ + Event Type: m.room.message + REST Path: /rooms/$room_id/messages/list + Valid methods: GET + Query Parameters: + feedback : [true|false] - Specify if feedback should be bundled with each + message. + This API can use pagination query parameters. + Returns: + A JSON array of Event Data in "chunk" (see Pagination Response). If the + "feedback" parameter was set, the Event Data will also contain a "feedback" + key which contains a JSON array of feedback, with each element as Event Data + with compressed feedback for this message. + +Event Data with compressed feedback is a special type of feedback with +contextual keys removed. It is designed to limit the amount of redundant data +being sent for feedback. This removes the type, event_id, room ID, +message sender ID and message ID keys. + + ORIGINAL (via event streaming) +{ + "event_id":"e1247632487", + "type":"m.room.message.feedback", + "from":"string [user_id]", + "feedback":"string [d|r]", + "room_id":"$room_id", + "msg_id":"$msg_id", + "msgfrom":"$msgfromid", + "content":{ + "sender_ts":139880943 + } +} + + COMPRESSED (via /messages/list) +{ + "from":"string [user_id]", + "feedback":"string [d|r]", + "content":{ + "sender_ts":139880943 + } +} + +When you join a room $room_id, you may want the last 10 messages with feedback. +This is represented as: + GET + /rooms/$room_id/messages/list?from=END&to=START&limit=10&feedback=true + +You may want to get 10 messages even earlier than that without feedback. If the +start stream token from the previous request was stok_019173, this request would +be: + GET + /rooms/$room_id/messages/list?from=stok_019173&to=START&limit=10& + feedback=false + +NOTE: Care must be taken when using this API in conjunction with event + streaming. It is possible that this will return a message which will + then come down the event stream, resulting in a duplicate message. Clients + should clobber based on the global message ID, or event ID. + + +Get current state for all rooms (aka IM Initial Sync API) +------------------------------- + REST Path: /im/sync + Valid methods: GET + This API can use pagination query parameters. Pagination is applied on a per + *room* basis. E.g. limit=1 means "get 1 message for each room" and not "get 1 + room's messages". If there is no limit, all messages for all rooms will be + returned. + If you want 1 room's messages, see "Receiving messages (bulk/pagination)". + Additional query parameters: + feedback: [true] - Bundles feedback with messages. + Returns: + An array of RoomStateInfo. + +RoomStateInfo: A snapshot of information about a single room. + { + "room_id" : "string", + "membership" : "string [join|invite]", + "messages" : { + "start": "string", + "end": "string", + "chunk": + m.room.message pagination stream events (with feedback if specified), + this is the same as "Receiving messages (bulk/pagination)". + } + } +The "membership" key is the calling user's membership state in the given +"room_id". The "messages" key may be omitted if the "membership" value is +"invite". Additional keys may be added to the top-level object, such as: + "topic" : "string" - The topic for the room in question. + "room_image_url" : "string" - The URL of the room image if specified. + "num_members" : integer - The number of members in the room. + + +Profiles +======== + +Getting/Setting your own displayname +------------------------------------ + REST Path: /profile/$user_id/displayname + Valid methods: GET/PUT + Required keys: + displayname : The displayname text + +Getting/Setting your own avatar image URL +----------------------------------------- +The homeserver does not currently store the avatar image itself, but offers +storage for the user to specify a web URL that points at the required image, +leaving it up to clients to fetch it themselves. + REST Path: /profile/$user_id/avatar_url + Valid methods: GET/PUT + Required keys: + avatar_url : The URL path to the required image + +Getting other user's profile information +---------------------------------------- +Either of the above REST methods may be used to fetch other user's profile +information by the client, either on other local users on the same homeserver or +for users from other servers entirely. + + +Presence +======== + +In the following messages, the presence state is a presence string as described in +the main specification document. + +Getting/Setting your own presence state +--------------------------------------- + REST Path: /presence/$user_id/status + Valid methods: GET/PUT + Required keys: + presence : - The user's new presence state + Optional keys: + status_msg : text string provided by the user to explain their status + +Fetching your presence list +--------------------------- + REST Path: /presence_list/$user_id + Valid methods: GET/(post) + Returns: + An array of presence list entries. Each entry is an object with the + following keys: + { + "user_id" : string giving the observed user's ID + "presence" : int giving their status + "status_msg" : optional text string + "displayname" : optional text string from the user's profile + "avatar_url" : optional text string from the user's profile + } + +Maintaining your presence list +------------------------------ + REST Path: /presence_list/$user_id + Valid methods: POST/(get) + With: A JSON object optionally containing either of the following keys: + "invite" : a list of strings giving user IDs to invite for presence + subscription + "drop" : a list of strings giving user IDs to remove from your presence + list + +Receiving presence update events +-------------------------------- + Event Type: m.presence + Keys of the event's content are the same as those returned by the presence + list. + +Examples +======== + +The following example is the story of "bob", who signs up at "sy.org" and joins +the public room "room_beta@sy.org". They get the 2 most recent +messages (with feedback) in that room and then send a message in that room. + +For context, here is the complete chat log for room_beta@sy.org: + +Room: "Hello world" (room_beta@sy.org) +Members: (2) alice@randomhost.org, friend_of_alice@randomhost.org +Messages: + alice@randomhost.org : hi friend! + [friend_of_alice@randomhost.org DELIVERED] + alice@randomhost.org : you're my only friend + [friend_of_alice@randomhost.org DELIVERED] + alice@randomhost.org : afk + [friend_of_alice@randomhost.org DELIVERED] + [ bob@sy.org joins ] + bob@sy.org : Hi everyone + [ alice@randomhost.org changes the topic to "FRIENDS ONLY" ] + alice@randomhost.org : Hello!!!! + alice@randomhost.org : Let's go to another room + alice@randomhost.org : You're not my friend + [ alice@randomhost.org invites bob@sy.org to the room + commoners@randomhost.org] + + +REGISTER FOR AN ACCOUNT +POST: /register +Content: {} +Returns: { "user_id" : "bob@sy.org" , "access_token" : "abcdef0123456789" } + +GET PUBLIC ROOM LIST +GET: /rooms/list?access_token=abcdef0123456789 +Returns: +{ + "total":3, + "chunk": + [ + { "room_id":"room_alpha@sy.org", "topic":"I am a fish" }, + { "room_id":"room_beta@sy.org", "topic":"Hello world" }, + { "room_id":"room_xyz@sy.org", "topic":"Goodbye cruel world" } + ] +} + +JOIN ROOM room_beta@sy.org +PUT +/rooms/room_beta%40sy.org/members/bob%40sy.org/state? + access_token=abcdef0123456789 +Content: { "membership" : "join" } +Returns: 200 OK + +GET LATEST 2 MESSAGES WITH FEEDBACK +GET +/rooms/room_beta%40sy.org/messages/list?from=END&to=START&limit=2& + feedback=true&access_token=abcdef0123456789 +Returns: +{ + "chunk": + [ + { + "event_id":"01948374", + "type":"m.room.message", + "room_id":"room_beta@sy.org", + "msg_id":"avefifu", + "from":"alice@randomhost.org", + "hs_ts":139985736, + "content":{ + "msgtype":"m.text", + "body":"afk" + } + "feedback": [ + { + "from":"friend_of_alice@randomhost.org", + "feedback":"d", + "hs_ts":139985850, + "content":{ + "sender_ts":139985843 + } + } + ] + }, + { + "event_id":"028dfe8373", + "type":"m.room.message", + "room_id":"room_beta@sy.org", + "msg_id":"afhgfff", + "from":"alice@randomhost.org", + "hs_ts":139970006, + "content":{ + "msgtype":"m.text", + "body":"you're my only friend" + } + "feedback": [ + { + "from":"friend_of_alice@randomhost.org", + "feedback":"d", + "hs_ts":139970144, + "content":{ + "sender_ts":139970122 + } + } + ] + }, + ], + "start": "stok_04823947", + "end": "etok_1426425" +} + +SEND MESSAGE IN ROOM +PUT +/rooms/room_beta%40sy.org/messages/bob%40sy.org/m0001? + access_token=abcdef0123456789 +Content: { "msgtype" : "text" , "body" : "Hi everyone" } +Returns: 200 OK + + +Checking the event stream for this user: +GET: /events?from=START&access_token=abcdef0123456789 +Returns: +{ + "chunk": + [ + { + "event_id":"e10f3d2b", + "type":"m.room.member", + "room_id":"room_beta@sy.org", + "user_id":"bob@sy.org", + "content":{ + "membership":"join" + } + }, + { + "event_id":"1b352d32", + "type":"m.room.message", + "room_id":"room_beta@sy.org", + "msg_id":"m0001", + "from":"bob@sy.org", + "hs_ts":140193857, + "content":{ + "msgtype":"m.text", + "body":"Hi everyone" + } + } + ], + "start": "stok_9348635", + "end": "etok_1984723" +} + +Client disconnects for a while and the topic is updated in this room, 3 new +messages arrive whilst offline, and bob is invited to another room. + +GET /events?from=etok_1984723&access_token=abcdef0123456789 +Returns: +{ + "chunk": + [ + { + "event_id":"feee0294", + "type":"m.room.topic", + "room_id":"room_beta@sy.org", + "from":"alice@randomhost.org", + "content":{ + "topic":"FRIENDS ONLY", + } + }, + { + "event_id":"a028bd9e", + "type":"m.room.message", + "room_id":"room_beta@sy.org", + "msg_id":"z839409", + "from":"alice@randomhost.org", + "hs_ts":140195000, + "content":{ + "msgtype":"m.text", + "body":"Hello!!!" + } + }, + { + "event_id":"49372d9e", + "type":"m.room.message", + "room_id":"room_beta@sy.org", + "msg_id":"z839410", + "from":"alice@randomhost.org", + "hs_ts":140196000, + "content":{ + "msgtype":"m.text", + "body":"Let's go to another room" + } + }, + { + "event_id":"10abdd01", + "type":"m.room.message", + "room_id":"room_beta@sy.org", + "msg_id":"z839411", + "from":"alice@randomhost.org", + "hs_ts":140197000, + "content":{ + "msgtype":"m.text", + "body":"You're not my friend" + } + }, + { + "event_id":"0018453d", + "type":"m.room.member", + "room_id":"commoners@randomhost.org", + "from":"alice@randomhost.org", + "user_id":"bob@sy.org", + "content":{ + "membership":"invite" + } + }, + ], + "start": "stok_0184288", + "end": "etok_1348723" +} diff --git a/docs/client-server/specification.rst b/docs/client-server/specification.rst deleted file mode 100644 index 2f6645ceb9..0000000000 --- a/docs/client-server/specification.rst +++ /dev/null @@ -1,1269 +0,0 @@ -======================== -Matrix Client-Server API -======================== - -The following specification outlines how a client can send and receive data from -a home server. - -[[TODO(kegan): 4/7/14 Grilling -- Mechanism for getting historical state changes (e.g. topic updates) - add - query param flag? -- Generic mechanism for linking first class events (e.g. feedback) with other s - first class events (e.g. messages)? -- Generic mechanism for updating 'stuff about the room' (e.g. favourite coffee) - AND specifying clobbering rules (clobber/add to list/etc)? -- How to ensure a consistent view for clients paginating through room lists? - They aren't really ordered in any way, and if you're paginating - through them, how can you show them a consistent result set? Temporary 'room - list versions' akin to event version? How does that work? -]] - -[[TODO(kegan): -Outstanding problems / missing spec: -- Push -- Typing notifications -]] - -Terminology ------------ -Stream Tokens: -An opaque token used to make further streaming requests. When using any -pagination streaming API, responses will contain a start and end stream token. -When reconnecting to the stream, these tokens can be used to tell the server -where the client got up to in the stream. - -Event ID: -Every event that comes down the event stream or that is returned from the REST -API has an associated event ID (event_id). This ID will be the same between the -REST API and the event stream, so any duplicate events can be clobbered -correctly without knowing anything else about the event. - -Message ID: -The ID of a message sent by a client in a room. Clients send IMs to each other -in rooms. Each IM sent by a client must have a unique message ID which is unique -for that particular client. - -User ID: -The @username:host style ID of the client. When registering for an account, the -client specifies their username. The user_id is this username along with the -home server's unique hostname. When federating between home servers, the user_id -is used to uniquely identify users across multiple home servers. - -Room ID: -The room_id@host style ID for the room. When rooms are created, the client either -specifies or is allocated a room ID. This room ID must be used to send messages -in that room. Like with clients, there may be multiple rooms with the same ID -across multiple home servers. The room_id is used to uniquely identify a room -when federating. - -Global message ID: -The globally unique ID for a message. This ID is formed from the msg_id, the -client's user_id and the room_id. This uniquely identifies any -message. It is represented with '-' as the delimeter between IDs. The -global_msg_id is of the form: room_id-user_id-msg_id - - -REST API and the Event Stream ------------------------------ -Clients send data to the server via a RESTful API. They can receive data via -this API or from an event stream. An event stream is a special path which -streams all events the client may be interested in. This makes it easy to -immediately receive updates from the REST API. All data is represented as JSON. - -Pagination streaming API -======================== -Clients are often interested in very large datasets. The data itself could -be 1000s of messages in a given room, 1000s of rooms in a public room list, or -1000s of events (presence, typing, messages, etc) in the system. It is not -practical to send vast quantities of data to the client every time they -request a list of public rooms for example. There needs to be a way to show a -subset of this data, and apply various filters to it. This is what the pagination -streaming API is. This API defines standard request/response parameters which -can be used when navigating this stream of data. - -Pagination Request Query Parameters ------------------------------------ -Clients may wish to paginate results from the event stream, or other sources of -information where the amount of information may be a problem, -e.g. in a room with 10,000s messages. The pagination query parameters provide a -way to navigate a 'window' around a large set of data. These -parameters are only valid for GET requests. - - S e r v e r - s i d e d a t a - |-------------------------------------------------| -START ^ ^ END - |_______________| - | - Client-extraction - -'START' and 'END' are magic token values which specify the start and end of the -dataset respectively. - -Query parameters: - from : $streamtoken - The opaque token to start streaming from. - to : $streamtoken - The opaque token to end streaming at. Typically, - clients will not know the item of data to end at, so this will usually be - START or END. - limit : integer - An integer representing the maximum number of items to - return. - -For example, the event stream has events E1 -> E15. The client wants the last 5 -events and doesn't know any previous events: - -S E -|-E1-E2-E3-E4-E5-E6-E7-E8-E9-E10-E11-E12-E13-E14-E15-| -| | | -| _____| | -|__________________ | ___________________| - | | | - GET /events?to=START&limit=5&from=END - Returns: - E15,E14,E13,E12,E11 - - -Another example: a public room list has rooms R1 -> R17. The client is showing 5 -rooms at a time on screen, and is on page 2. They want to -now show page 3 (rooms R11 -> 15): - -S E -| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | stream token -|-R1-R2-R3-R4-R5-R6-R7-R8-R9-R10-R11-R12-R13-R14-R15-R16-R17| room - |____________| |________________| - | | - Currently | - viewing | - | - GET /rooms/list?from=9&to=END&limit=5 - Returns: R11,R12,R13,R14,R15 - -Note that tokens are treated in an *exclusive*, not inclusive, manner. The end -token from the intial request was '9' which corresponded to R10. When the 2nd -request was made, R10 did not appear again, even though from=9 was specified. If -you know the token, you already have the data. - -Pagination Response -------------------- -Responses to pagination requests MUST follow the format: -{ - "chunk": [ ... , Responses , ... ], - "start" : $streamtoken, - "end" : $streamtoken -} -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". - -If the client wants earlier results, they should use from=$start_streamtoken, -to=START. Likewise, if the client wants later results, they should use -from=$end_streamtoken, to=END. - -Unless specified, the default pagination parameters are from=START, to=END, -without a limit set. This allows you to hit an API like -/events without any query parameters to get everything. - -The Event Stream ----------------- -The event stream returns events using the pagination streaming API. When the -client disconnects for a while and wants to reconnect to the event stream, they -should specify from=$end_streamtoken. This lets the server know where in the -event stream the client is. These tokens are completely opaque, and the client -cannot infer anything from them. - - GET /events?from=$LAST_STREAM_TOKEN - REST Path: /events - Returns (success): A JSON array of Event Data. - Returns (failure): An Error Response - -LAST_STREAM_TOKEN is the last stream token obtained from the event stream. If the -client is connecting for the first time and does not know any stream tokens, -they can use "START" to request all events from the start. For more information -on this, see "Pagination Request Query Parameters". - -The event stream supports shortpoll and longpoll with the "timeout" query -parameter. This parameter specifies the number of milliseconds the server should -hold onto the connection waiting for incoming events. If no events occur in this -period, the connection will be closed and an empty chunk will be returned. To -use shortpoll, specify "timeout=0". - -Event Data ----------- -This is a JSON object which looks like: -{ - "event_id" : $EVENT_ID, - "type" : $EVENT_TYPE, - $URL_ARGS, - "content" : { - $EVENT_CONTENT - } -} - -EVENT_ID - An ID identifying this event. This is so duplicate events can be suppressed on - the client. - -EVENT_TYPE - The namespaced event type (m.*) - -URL_ARGS - Path specific data from the REST API. - -EVENT_CONTENT - The event content, matching the REST content PUT previously. - -Events are differentiated via the event type "type" key. This is the type of -event being received. This can be expanded upon by using different namespaces. -Every event MUST have a 'type' key. - -Most events will have a corresponding REST URL. This URL will generally have -data in it to represent the resource being modified, -e.g. /rooms/$room_id. The event data will contain extra top-level keys to expose -this information to clients listening on an event -stream. The event content maps directly to the contents submitted via the REST -API. - -For example: - Event Type: m.example.room.members - REST Path: /examples/room/$room_id/members/$user_id - REST Content: { "membership" : "invited" } - -is represented in the event stream as: - -{ - "event_id" : "e_some_event_id", - "type" : "m.example.room.members", - "room_id" : $room_id, - "user_id" : $user_id, - "content" : { - "membership" : "invited" - } -} - -As convention, the URL variable "$varname" will map directly onto the name -of the JSON key "varname". - -Error Responses ---------------- -If the client sends an invalid request, the server MAY respond with an error -response. This is of the form: -{ - "error" : "string", - "errcode" : "string" -} -The 'error' string will be a human-readable error message, usually a sentence -explaining what went wrong. - -The 'errcode' string will be a unique string which can be used to handle an -error message e.g. "M_FORBIDDEN". These error codes should have their namespace -first in ALL CAPS, followed by a single _. For example, if there was a custom -namespace com.mydomain.here, and a "FORBIDDEN" code, the error code should look -like "COM.MYDOMAIN.HERE_FORBIDDEN". There may be additional keys depending on -the error, but the keys 'error' and 'errcode' will always be present. - -Some standard error codes are below: - -M_FORBIDDEN: -Forbidden access, e.g. joining a room without permission, failed login. - -M_UNKNOWN_TOKEN: -The access token specified was not recognised. - -M_BAD_JSON: -Request contained valid JSON, but it was malformed in some way, e.g. missing -required keys, invalid values for keys. - -M_NOT_JSON: -Request did not contain valid JSON. - -M_NOT_FOUND: -No resource was found for this request. - -Some requests have unique error codes: - -M_USER_IN_USE: -Encountered when trying to register a user ID which has been taken. - -M_ROOM_IN_USE: -Encountered when trying to create a room which has been taken. - -M_BAD_PAGINATION: -Encountered when specifying bad pagination values to a Pagination Streaming API. - - -======== -REST API -======== - -All content must be application/json. Some keys are required, while others are -optional. Unless otherwise specified, -all HTTP PUT/POST/DELETEs will return a 200 OK with an empty response body on -success, and a 4xx/5xx with an optional Error Response on failure. When sending -data, if there are no keys to send, an empty JSON object should be sent. - -All POST/PUT/GET/DELETE requests MUST have an 'access_token' query parameter to -allow the server to authenticate the client. All -POST requests MUST be submitted as application/json. - -All paths MUST be namespaced by the version of the API being used. This should -be: - -/_matrix/client/api/v1 - -All REST paths in this section MUST be prefixed with this. E.g. - REST Path: /rooms/$room_id - Absolute Path: /_matrix/client/api/v1/rooms/$room_id - -Registration -============ -Clients must register with the server in order to use the service. After -registering, the client will be given an -access token which must be used in ALL requests as a query parameter -'access_token'. - -Registering for an account --------------------------- - POST /register - With: A JSON object containing the key "user_id" which contains the desired - user_id, or an empty JSON object to have the server allocate a user_id - automatically. - Returns (success): 200 OK with a JSON object: - { - "user_id" : "string [user_id]", - "access_token" : "string" - } - Returns (failure): An Error Response. M_USER_IN_USE if the user ID is taken. - - -Unregistering an account ------------------------- - POST /unregister - With query parameters: access_token=$ACCESS_TOKEN - Returns (success): 200 OK - Returns (failure): An Error Response. - - -Logging in to an existing account -================================= -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 user/password auth, login via a social network (OAuth), login by confirming -a token sent to their email address, etc. This section does NOT define how home -servers should authorise their users who want to login to their existing -accounts. This section defines the standard interface which implementations -should follow so that ANY client can login to ANY home server. - -The login process breaks down into the following: - 1: Get login process info. - 2: Submit the login stage credentials. - 3: Get access token or be told the next stage in the login process and repeat - step 2. - -Getting login process info: - GET /login - Returns (success): 200 OK with LoginInfo. - Returns (failure): An Error Response. - -Submitting the login stage credentials: - POST /login - With: LoginSubmission - Returns (success): 200 OK with LoginResult - Returns (failure): An Error Response - -Where LoginInfo is a JSON object which MUST have a "type" key which denotes the -login type. If there are multiple login stages, this object MUST also contain a -"stages" key, which has a JSON array of login types denoting all the steps in -order to login, including the first stage which is in "type". This allows the -client to make an informed decision as to whether or not they can natively -handle the entire login process, or whether they should fallback (see below). - -Where LoginSubmission is a JSON object which MUST have a "type" key. - -Where LoginResult is a JSON object which MUST have either a "next" key OR an -"access_token" key, depending if the login process is over or not. This object -MUST have a "session" key if multiple POSTs need to be sent to /login. - -Fallback --------- -If the client does NOT know how to handle the given type, they should: - GET /login/fallback -This MUST return an HTML page which can perform the entire login process. - -Password-based --------------- -Type: "m.login.password" -LoginSubmission: -{ - "type": "m.login.password", - "user": , - "password": -} - -Example: -Assume you are @bob:matrix.org and you wish to login on another mobile device. -First, you GET /login which returns: -{ - "type": "m.login.password" -} -Your client knows how to handle this, so your client prompts the user to enter -their username and password. This is then submitted: -{ - "type": "m.login.password", - "user": "@bob:matrix.org", - "password": "monkey" -} -The server checks this, finds it is valid, and returns: -{ - "access_token": "abcdef0123456789" -} -The server may optionally return "user_id" to confirm or change the user's ID. -This is particularly useful if the home server wishes to support localpart entry -of usernames (e.g. "bob" rather than "@bob:matrix.org"). - -OAuth2-based ------------- -Type: "m.login.oauth2" -This is a multi-stage login. - -LoginSubmission: -{ - "type": "m.login.oauth2", - "user": -} -Returns: -{ - "uri": -} - -The home server acts as a 'confidential' Client for the purposes of OAuth2. - -If the uri is a "sevice selection uri", it is a simple page which prompts the -user to choose which service to authorize with. On selection of a service, they -link through to Authorization Request URIs. If there is only 1 service which the -home server accepts when logging in, this indirection can be skipped and the -"uri" key can be the Authorization Request URI. - -The client 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 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 knows that the cilent has authed with the 3rd party, and -so can return a LoginResult. - -The OAuth redirect URI (with auth code) MUST return a LoginResult. - -Example: -Assume you are @bob:matrix.org and you wish to login on another mobile device. -First, you GET /login which returns: -{ - "type": "m.login.oauth2" -} -Your client knows how to handle this, so your client prompts the user to enter -their username. This is then submitted: -{ - "type": "m.login.oauth2", - "user": "@bob:matrix.org" -} -The server only accepts auth from Google, so returns the Authorization Request -URI for Google: -{ - "uri": "https://accounts.google.com/o/oauth2/auth?response_type=code& - client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos" -} -The client then visits this URI and authorizes the home server. The client then -visits the REDIRECT_URI with the auth code= query parameter which returns: -{ - "access_token": "0123456789abcdef" -} - -Email-based (code) ------------------- -Type: "m.login.email.code" -This is a multi-stage login. - -First LoginSubmission: -{ - "type": "m.login.email.code", - "user": - "email": -} -Returns: -{ - "session": -} - -The email contains a code which must be sent in the next LoginSubmission: -{ - "type": "m.login.email.code", - "session": , - "code": -} -Returns: -{ - "access_token": -} - -Example: -Assume you are @bob:matrix.org and you wish to login on another mobile device. -First, you GET /login which returns: -{ - "type": "m.login.email.code" -} -Your client knows how to handle this, so your client prompts the user to enter -their email address. This is then submitted: -{ - "type": "m.login.email.code", - "user": "@bob:matrix.org", - "email": "bob@mydomain.com" -} -The server confirms that bob@mydomain.com is linked to @bob:matrix.org, then -sends an email to this address and returns: -{ - "session": "ewuigf7462" -} -The client's screen changes to a code submission page. The email arrives and it -says something to the effect of "please enter 2348623 into the app". This is -the submitted along with the session: -{ - "type": "m.login.email.code", - "session": "ewuigf7462", - "code": "2348623" -} -The server accepts this and returns: -{ - "access_token": "abcdef0123456789" -} - -Email-based (url) ------------------ -Type: "m.login.email.url" -This is a multi-stage login. - -First LoginSubmission: -{ - "type": "m.login.email.url", - "user": - "email": -} -Returns: -{ - "session": -} - -The email contains a URL which must be clicked. After it has been clicked, the -client should perform a request: -{ - "type": "m.login.email.code", - "session": -} -Returns: -{ - "access_token": -} - -Example: -Assume you are @bob:matrix.org and you wish to login on another mobile device. -First, you GET /login which returns: -{ - "type": "m.login.email.url" -} -Your client knows how to handle this, so your client prompts the user to enter -their email address. This is then submitted: -{ - "type": "m.login.email.url", - "user": "@bob:matrix.org", - "email": "bob@mydomain.com" -} -The server confirms that bob@mydomain.com is linked to @bob:matrix.org, then -sends an email to this address and returns: -{ - "session": "ewuigf7462" -} -The client then starts polling the server with the following: -{ - "type": "m.login.email.url", - "session": "ewuigf7462" -} -(Alternatively, the server could send the device a push notification when the -email has been validated). The email arrives and it contains a URL to click on. -The user clicks on the which completes the login process with the server. The -next time the client polls, it returns: -{ - "access_token": "abcdef0123456789" -} - -N-Factor auth -------------- -Multiple login stages can be combined with the "next" key in the LoginResult. - -Example: -A server demands an email.code then password auth before logging in. First, the -client performs a GET /login which returns: -{ - "type": "m.login.email.code", - "stages": ["m.login.email.code", "m.login.password"] -} -The client performs the email login (See "Email-based (code)"), but instead of -returning an access_token, it returns: -{ - "next": "m.login.password" -} -The client then presents a user/password screen and the login continues until -this is complete (See "Password-based"), which then returns the "access_token". - -Rooms -===== -A room is a conceptual place where users can send and receive messages. Rooms -can be created, joined and left. Messages are sent -to a room, and all participants in that room will receive the message. Rooms are -uniquely identified via the room_id. - -Creating a room (with a room ID) --------------------------------- - Event Type: m.room.create [TODO(kegan): Do we generate events for this?] - REST Path: /rooms/$room_id - Valid methods: PUT - Required keys: None. - Optional keys: - visibility : [public|private] - Set whether this room shows up in the public - room list. - Returns: - On Failure: MAY return a suggested alternative room ID if this room ID is - taken. - { - suggested_room_id : $new_room_id - error : "Room already in use." - errcode : "M_ROOM_IN_USE" - } - - -Creating a room (without a room ID) ------------------------------------ - Event Type: m.room.create [TODO(kegan): Do we generate events for this?] - REST Path: /rooms - Valid methods: POST - Required keys: None. - Optional keys: - visibility : [public|private] - Set whether this room shows up in the public - room list. - Returns: - On Success: The allocated room ID. Additional information about the room - such as the visibility MAY be included as extra keys in this response. - { - room_id : $room_id - } - -Setting the topic for a room ----------------------------- - Event Type: m.room.topic - REST Path: /rooms/$room_id/topic - Valid methods: GET/PUT - Required keys: - topic : $topicname - Set the topic to $topicname in room $room_id. - - -See a list of public rooms --------------------------- - REST Path: /public/rooms?pagination_query_parameters - Valid methods: GET - This API can use pagination query parameters. - Returns: - { - "chunk" : JSON array of RoomInfo JSON objects - Required. - "start" : "string (start token)" - See Pagination Response. - "end" : "string (end token)" - See Pagination Response. - "total" : integer - Optional. The total number of rooms. - } - -RoomInfo: Information about a single room. - Servers MUST send the key: room_id - Servers MAY send the keys: topic, num_members - { - "room_id" : "string", - "topic" : "string", - "num_members" : integer - } - -Room Members -============ - -Invite/Joining/Leaving a room ------------------------------ - Event Type: m.room.member - REST Path: /rooms/$room_id/members/$user_id/state - Valid methods: PUT/GET/DELETE - Required keys: - membership : [join|invite] - The membership state of $user_id in room - $room_id. - Optional keys: - displayname, - avatar_url : String fields from the member user's profile - state, - status_msg, - mtime_age : Presence information - - These optional keys provide extra information that the client is likely to - be interested in so it doesn't have to perform an additional profile or - presence information fetch. - -Where: - join - Indicate you ($user_id) are joining the room $room_id. - invite - Indicate that $user_id has been invited to room $room_id. - -User $user_id can leave room $room_id by DELETEing this path. - -Checking the user list of a room --------------------------------- - REST Path: /rooms/$room_id/members/list - This API can use pagination query parameters. - Valid methods: GET - Returns: - A pagination response with chunk data as m.room.member events. - -Messages -======== -Users send messages to other users in rooms. These messages may be text, images, -video, etc. Clients may also want to acknowledge messages by sending feedback, -in the form of delivery/read receipts. - -Server-attached keys --------------------- -The server MAY attach additional keys to messages and feedback. If a client -submits keys with the same name, they will be clobbered by -the server. - -Required keys: -from : "string [user_id]" - The user_id of the user who sent the message/feedback. - -Optional keys: -hsob_ts : integer - A timestamp (ms resolution) representing when the message/feedback got to the - sender's home server ("home server outbound timestamp"). - -hsib_ts : integer - A timestamp (ms resolution) representing when the - message/feedback got to the receiver's home server ("home server inbound - timestamp"). This may be the same as hsob_ts if the sender/receiver are on the - same home server. - -Sending messages ----------------- - Event Type: m.room.message - REST Path: /rooms/$room_id/messages/$from/$msg_id - Valid methods: GET/PUT - URL parameters: - $from : user_id - The sender's user_id. This value will be clobbered by the - server before sending. - Required keys: - msgtype: [m.text|m.emote|m.image|m.audio|m.video|m.location|m.file] - - The type of message. Not to be confused with the Event 'type'. - Optional keys: - sender_ts : integer - A timestamp (ms resolution) representing the - wall-clock time when the message was sent from the client. - Reserved keys: - body : "string" - The human readable string for compatibility with clients - which cannot process a given msgtype. This key is optional, but - if it is included, it MUST be human readable text - describing the message. See individual msgtypes for more - info on what this means in practice. - -Each msgtype may have required fields of their own. - -msgtype: m.text ----------------- -Required keys: - body : "string" - The body of the message. -Optional keys: - None. - -msgtype: m.emote ------------------ -Required keys: - body : "string" - *tries to come up with a witty explanation*. -Optional keys: - None. - -msgtype: m.image ------------------ -Required keys: - url : "string" - The URL to the image. -Optional keys: - body : "string" - info : JSON object (ImageInfo) - The image info for image - referred to in 'url'. - thumbnail_url : "string" - The URL to the thumbnail. - thumbnail_info : JSON object (ImageInfo) - The image info for the image - referred to in 'thumbnail_url'. - -ImageInfo: Information about an image. -{ - "size" : integer (size of image in bytes), - "w" : integer (width of image in pixels), - "h" : integer (height of image in pixels), - "mimetype" : "string (e.g. image/jpeg)" -} - -Interpretation of 'body' key: The alt text of the image, or some kind of content -description for accessibility e.g. "image attachment". - -msgtype: m.audio ------------------ -Required keys: - url : "string" - The URL to the audio. -Optional keys: - info : JSON object (AudioInfo) - The audio info for the audio referred to in - 'url'. - -AudioInfo: Information about a piece of audio. -{ - "mimetype" : "string (e.g. audio/aac)", - "size" : integer (size of audio in bytes), - "duration" : integer (duration of audio in milliseconds) -} - -Interpretation of 'body' key: A description of the audio e.g. "Bee Gees - -Stayin' Alive", or some kind of content description for accessibility e.g. -"audio attachment". - -msgtype: m.video ------------------ -Required keys: - url : "string" - The URL to the video. -Optional keys: - info : JSON object (VideoInfo) - The video info for the video referred to in - 'url'. - -VideoInfo: Information about a video. -{ - "mimetype" : "string (e.g. video/mp4)", - "size" : integer (size of video in bytes), - "duration" : integer (duration of video in milliseconds), - "w" : integer (width of video in pixels), - "h" : integer (height of video in pixels), - "thumbnail_url" : "string (URL to image)", - "thumbanil_info" : JSON object (ImageInfo) -} - -Interpretation of 'body' key: A description of the video e.g. "Gangnam style", -or some kind of content description for accessibility e.g. "video attachment". - -msgtype: m.location --------------------- -Required keys: - geo_uri : "string" - The geo URI representing the location. -Optional keys: - thumbnail_url : "string" - The URL to a thumnail of the location being - represented. - thumbnail_info : JSON object (ImageInfo) - The image info for the image - referred to in 'thumbnail_url'. - -Interpretation of 'body' key: A description of the location e.g. "Big Ben, -London, UK", or some kind of content description for accessibility e.g. -"location attachment". - - -Sending feedback ----------------- -When you receive a message, you may want to send delivery receipt to let the -sender know that the message arrived. You may also want to send a read receipt -when the user has read the message. These receipts are collectively known as -'feedback'. - - Event Type: m.room.message.feedback - REST Path: /rooms/$room_id/messages/$msgfrom/$msg_id/feedback/$from/$feedback - Valid methods: GET/PUT - URL parameters: - $msgfrom - The sender of the message's user_id. - $from : user_id - The sender of the feedback's user_id. This value will be - clobbered by the server before sending. - $feedback : [d|r] - Specify if this is a [d]elivery or [r]ead receipt. - Required keys: - None. - Optional keys: - sender_ts : integer - A timestamp (ms resolution) representing the - wall-clock time when the receipt was sent from the client. - -Receiving messages (bulk/pagination) ------------------------------------- - Event Type: m.room.message - REST Path: /rooms/$room_id/messages/list - Valid methods: GET - Query Parameters: - feedback : [true|false] - Specify if feedback should be bundled with each - message. - This API can use pagination query parameters. - Returns: - A JSON array of Event Data in "chunk" (see Pagination Response). If the - "feedback" parameter was set, the Event Data will also contain a "feedback" - key which contains a JSON array of feedback, with each element as Event Data - with compressed feedback for this message. - -Event Data with compressed feedback is a special type of feedback with -contextual keys removed. It is designed to limit the amount of redundant data -being sent for feedback. This removes the type, event_id, room ID, -message sender ID and message ID keys. - - ORIGINAL (via event streaming) -{ - "event_id":"e1247632487", - "type":"m.room.message.feedback", - "from":"string [user_id]", - "feedback":"string [d|r]", - "room_id":"$room_id", - "msg_id":"$msg_id", - "msgfrom":"$msgfromid", - "content":{ - "sender_ts":139880943 - } -} - - COMPRESSED (via /messages/list) -{ - "from":"string [user_id]", - "feedback":"string [d|r]", - "content":{ - "sender_ts":139880943 - } -} - -When you join a room $room_id, you may want the last 10 messages with feedback. -This is represented as: - GET - /rooms/$room_id/messages/list?from=END&to=START&limit=10&feedback=true - -You may want to get 10 messages even earlier than that without feedback. If the -start stream token from the previous request was stok_019173, this request would -be: - GET - /rooms/$room_id/messages/list?from=stok_019173&to=START&limit=10& - feedback=false - -NOTE: Care must be taken when using this API in conjunction with event - streaming. It is possible that this will return a message which will - then come down the event stream, resulting in a duplicate message. Clients - should clobber based on the global message ID, or event ID. - - -Get current state for all rooms (aka IM Initial Sync API) -------------------------------- - REST Path: /im/sync - Valid methods: GET - This API can use pagination query parameters. Pagination is applied on a per - *room* basis. E.g. limit=1 means "get 1 message for each room" and not "get 1 - room's messages". If there is no limit, all messages for all rooms will be - returned. - If you want 1 room's messages, see "Receiving messages (bulk/pagination)". - Additional query parameters: - feedback: [true] - Bundles feedback with messages. - Returns: - An array of RoomStateInfo. - -RoomStateInfo: A snapshot of information about a single room. - { - "room_id" : "string", - "membership" : "string [join|invite]", - "messages" : { - "start": "string", - "end": "string", - "chunk": - m.room.message pagination stream events (with feedback if specified), - this is the same as "Receiving messages (bulk/pagination)". - } - } -The "membership" key is the calling user's membership state in the given -"room_id". The "messages" key may be omitted if the "membership" value is -"invite". Additional keys may be added to the top-level object, such as: - "topic" : "string" - The topic for the room in question. - "room_image_url" : "string" - The URL of the room image if specified. - "num_members" : integer - The number of members in the room. - - -Profiles -======== - -Getting/Setting your own displayname ------------------------------------- - REST Path: /profile/$user_id/displayname - Valid methods: GET/PUT - Required keys: - displayname : The displayname text - -Getting/Setting your own avatar image URL ------------------------------------------ -The homeserver does not currently store the avatar image itself, but offers -storage for the user to specify a web URL that points at the required image, -leaving it up to clients to fetch it themselves. - REST Path: /profile/$user_id/avatar_url - Valid methods: GET/PUT - Required keys: - avatar_url : The URL path to the required image - -Getting other user's profile information ----------------------------------------- -Either of the above REST methods may be used to fetch other user's profile -information by the client, either on other local users on the same homeserver or -for users from other servers entirely. - - -Presence -======== - -In the following messages, the presence state is a presence string as described in -the main specification document. - -Getting/Setting your own presence state ---------------------------------------- - REST Path: /presence/$user_id/status - Valid methods: GET/PUT - Required keys: - presence : - The user's new presence state - Optional keys: - status_msg : text string provided by the user to explain their status - -Fetching your presence list ---------------------------- - REST Path: /presence_list/$user_id - Valid methods: GET/(post) - Returns: - An array of presence list entries. Each entry is an object with the - following keys: - { - "user_id" : string giving the observed user's ID - "presence" : int giving their status - "status_msg" : optional text string - "displayname" : optional text string from the user's profile - "avatar_url" : optional text string from the user's profile - } - -Maintaining your presence list ------------------------------- - REST Path: /presence_list/$user_id - Valid methods: POST/(get) - With: A JSON object optionally containing either of the following keys: - "invite" : a list of strings giving user IDs to invite for presence - subscription - "drop" : a list of strings giving user IDs to remove from your presence - list - -Receiving presence update events --------------------------------- - Event Type: m.presence - Keys of the event's content are the same as those returned by the presence - list. - -Examples -======== - -The following example is the story of "bob", who signs up at "sy.org" and joins -the public room "room_beta@sy.org". They get the 2 most recent -messages (with feedback) in that room and then send a message in that room. - -For context, here is the complete chat log for room_beta@sy.org: - -Room: "Hello world" (room_beta@sy.org) -Members: (2) alice@randomhost.org, friend_of_alice@randomhost.org -Messages: - alice@randomhost.org : hi friend! - [friend_of_alice@randomhost.org DELIVERED] - alice@randomhost.org : you're my only friend - [friend_of_alice@randomhost.org DELIVERED] - alice@randomhost.org : afk - [friend_of_alice@randomhost.org DELIVERED] - [ bob@sy.org joins ] - bob@sy.org : Hi everyone - [ alice@randomhost.org changes the topic to "FRIENDS ONLY" ] - alice@randomhost.org : Hello!!!! - alice@randomhost.org : Let's go to another room - alice@randomhost.org : You're not my friend - [ alice@randomhost.org invites bob@sy.org to the room - commoners@randomhost.org] - - -REGISTER FOR AN ACCOUNT -POST: /register -Content: {} -Returns: { "user_id" : "bob@sy.org" , "access_token" : "abcdef0123456789" } - -GET PUBLIC ROOM LIST -GET: /rooms/list?access_token=abcdef0123456789 -Returns: -{ - "total":3, - "chunk": - [ - { "room_id":"room_alpha@sy.org", "topic":"I am a fish" }, - { "room_id":"room_beta@sy.org", "topic":"Hello world" }, - { "room_id":"room_xyz@sy.org", "topic":"Goodbye cruel world" } - ] -} - -JOIN ROOM room_beta@sy.org -PUT -/rooms/room_beta%40sy.org/members/bob%40sy.org/state? - access_token=abcdef0123456789 -Content: { "membership" : "join" } -Returns: 200 OK - -GET LATEST 2 MESSAGES WITH FEEDBACK -GET -/rooms/room_beta%40sy.org/messages/list?from=END&to=START&limit=2& - feedback=true&access_token=abcdef0123456789 -Returns: -{ - "chunk": - [ - { - "event_id":"01948374", - "type":"m.room.message", - "room_id":"room_beta@sy.org", - "msg_id":"avefifu", - "from":"alice@randomhost.org", - "hs_ts":139985736, - "content":{ - "msgtype":"m.text", - "body":"afk" - } - "feedback": [ - { - "from":"friend_of_alice@randomhost.org", - "feedback":"d", - "hs_ts":139985850, - "content":{ - "sender_ts":139985843 - } - } - ] - }, - { - "event_id":"028dfe8373", - "type":"m.room.message", - "room_id":"room_beta@sy.org", - "msg_id":"afhgfff", - "from":"alice@randomhost.org", - "hs_ts":139970006, - "content":{ - "msgtype":"m.text", - "body":"you're my only friend" - } - "feedback": [ - { - "from":"friend_of_alice@randomhost.org", - "feedback":"d", - "hs_ts":139970144, - "content":{ - "sender_ts":139970122 - } - } - ] - }, - ], - "start": "stok_04823947", - "end": "etok_1426425" -} - -SEND MESSAGE IN ROOM -PUT -/rooms/room_beta%40sy.org/messages/bob%40sy.org/m0001? - access_token=abcdef0123456789 -Content: { "msgtype" : "text" , "body" : "Hi everyone" } -Returns: 200 OK - - -Checking the event stream for this user: -GET: /events?from=START&access_token=abcdef0123456789 -Returns: -{ - "chunk": - [ - { - "event_id":"e10f3d2b", - "type":"m.room.member", - "room_id":"room_beta@sy.org", - "user_id":"bob@sy.org", - "content":{ - "membership":"join" - } - }, - { - "event_id":"1b352d32", - "type":"m.room.message", - "room_id":"room_beta@sy.org", - "msg_id":"m0001", - "from":"bob@sy.org", - "hs_ts":140193857, - "content":{ - "msgtype":"m.text", - "body":"Hi everyone" - } - } - ], - "start": "stok_9348635", - "end": "etok_1984723" -} - -Client disconnects for a while and the topic is updated in this room, 3 new -messages arrive whilst offline, and bob is invited to another room. - -GET /events?from=etok_1984723&access_token=abcdef0123456789 -Returns: -{ - "chunk": - [ - { - "event_id":"feee0294", - "type":"m.room.topic", - "room_id":"room_beta@sy.org", - "from":"alice@randomhost.org", - "content":{ - "topic":"FRIENDS ONLY", - } - }, - { - "event_id":"a028bd9e", - "type":"m.room.message", - "room_id":"room_beta@sy.org", - "msg_id":"z839409", - "from":"alice@randomhost.org", - "hs_ts":140195000, - "content":{ - "msgtype":"m.text", - "body":"Hello!!!" - } - }, - { - "event_id":"49372d9e", - "type":"m.room.message", - "room_id":"room_beta@sy.org", - "msg_id":"z839410", - "from":"alice@randomhost.org", - "hs_ts":140196000, - "content":{ - "msgtype":"m.text", - "body":"Let's go to another room" - } - }, - { - "event_id":"10abdd01", - "type":"m.room.message", - "room_id":"room_beta@sy.org", - "msg_id":"z839411", - "from":"alice@randomhost.org", - "hs_ts":140197000, - "content":{ - "msgtype":"m.text", - "body":"You're not my friend" - } - }, - { - "event_id":"0018453d", - "type":"m.room.member", - "room_id":"commoners@randomhost.org", - "from":"alice@randomhost.org", - "user_id":"bob@sy.org", - "content":{ - "membership":"invite" - } - }, - ], - "start": "stok_0184288", - "end": "etok_1348723" -} -- cgit 1.5.1 From f196d77f6602fc61fa6df3790d217aa2c3b9c5f3 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 18:07:36 +0100 Subject: Added federation protocol urls section from other docs. --- docs/specification.rst | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 44eddcaf87..239e51b4f3 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1726,6 +1726,79 @@ destination home server names, and the actual nested content. "origin":"blue", "destination":"orange", "content":...} + + +Protocol URLs +============= +.. WARNING:: + This section may be misleading or inaccurate. + +All these URLs are namespaced within a prefix of:: + + /_matrix/federation/v1/... + +For active pushing of messages representing live activity "as it happens":: + + PUT .../send/:transaction_id/ + Body: JSON encoding of a single Transaction + Response: TODO + +The transaction_id path argument will override any ID given in the JSON body. +The destination name will be set to that of the receiving server itself. Each +embedded PDU in the transaction body will be processed. + + +To fetch a particular PDU:: + + GET .../pdu/:origin/:pdu_id/ + Response: JSON encoding of a single Transaction containing one PDU + +Retrieves a given PDU from the server. The response will contain a single new +Transaction, inside which will be the requested PDU. + + +To fetch all the state of a given context:: + + GET .../state/:context/ + Response: JSON encoding of a single Transaction containing multiple PDUs + +Retrieves a snapshot of the entire current state of the given context. The +response will contain a single Transaction, inside which will be a list of +PDUs that encode the state. + +To backfill events on a given context:: + + GET .../backfill/:context/ + Query args: v, limit + Response: JSON encoding of a single Transaction containing multiple PDUs + +Retrieves a sliding-window history of previous PDUs that occurred on the +given context. Starting from the PDU ID(s) given in the "v" argument, the +PDUs that preceeded it are retrieved, up to a total number given by the +"limit" argument. These are then returned in a new Transaction containing all +off the PDUs. + + +To stream events all the events:: + + GET .../pull/ + Query args: origin, v + Response: JSON encoding of a single Transaction consisting of multiple PDUs + +Retrieves all of the transactions later than any version given by the "v" +arguments. + + +To make a query:: + + GET .../query/:query_type + 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 +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. Backfilling ----------- -- cgit 1.5.1