From b4984d5e152e5a6d4998b08c30d714faefa1b785 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 15:29:38 +0100 Subject: Updated howto.rst to use the new APIs. Updated JSFiddles to use 8008. Linked new fiddles with howto.rst. Added more explanations. --- docs/client-server/howto.rst | 531 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 426 insertions(+), 105 deletions(-) (limited to 'docs') diff --git a/docs/client-server/howto.rst b/docs/client-server/howto.rst index 3660c73d36..54b80e7dea 100644 --- a/docs/client-server/howto.rst +++ b/docs/client-server/howto.rst @@ -1,6 +1,4 @@ -TODO(kegan): Tweak joinalias API keys/path? Event stream historical > live needs -a token (currently doesn't). im/sync responses include outdated event formats -(room membership change messages). Room config (specifically: message history, +TODO(kegan): Room config (specifically: message history, public rooms). /register seems super simplistic compared to /login, maybe it would be better if /register used the same technique as /login? /register should be "user" not "user_id". @@ -15,7 +13,7 @@ implementation, there may be variations in relation to registering/logging in which are not covered in extensive detail in this guide. If you haven't already, get a home server up and running on -``http://localhost:8080``. +``http://localhost:8008``. Accounts @@ -23,14 +21,14 @@ Accounts Before you can send and receive messages, you must **register** for an account. If you already have an account, you must **login** into it. -**Try out the fiddle: http://jsfiddle.net/jrf1h02d/** +**Try out the fiddle: http://jsfiddle.net/4q2jyxng/** Registration ------------ The aim of registration is to get a user ID and access token which you will need when accessing other APIs:: - curl -XPOST -d '{"user_id":"example", "password":"wordpass"}' "http://localhost:8080/_matrix/client/api/v1/register" + curl -XPOST -d '{"user_id":"example", "password":"wordpass"}' "http://localhost:8008/_matrix/client/api/v1/register" { "access_token": "QGV4YW1wbGU6bG9jYWxob3N0.AqdSzFmFYrLrTmteXc", @@ -51,13 +49,17 @@ Login ----- The aim when logging in is to get an access token for your existing user ID:: - curl -XGET "http://localhost:8080/_matrix/client/api/v1/login" + curl -XGET "http://localhost:8008/_matrix/client/api/v1/login" { - "type": "m.login.password" + "flows": [ + { + "type": "m.login.password" + } + ] } - curl -XPOST -d '{"type":"m.login.password", "user":"example", "password":"wordpass"}' "http://localhost:8080/_matrix/client/api/v1/login" + curl -XPOST -d '{"type":"m.login.password", "user":"example", "password":"wordpass"}' "http://localhost:8008/_matrix/client/api/v1/login" { "access_token": "QGV4YW1wbGU6bG9jYWxob3N0.vRDLTgxefmKWQEtgGd", @@ -80,14 +82,14 @@ Communicating In order to communicate with another user, you must **create a room** with that user and **send a message** to that room. -**Try out the fiddle: http://jsfiddle.net/jnwqcshc/** +**Try out the fiddle: http://jsfiddle.net/zL3zto9g/** Creating a room --------------- If you want to send a message to someone, you have to be in a room with them. To create a room:: - curl -XPOST -d '{"room_alias_name":"tutorial"}' "http://localhost:8080/_matrix/client/api/v1/rooms?access_token=QGV4YW1wbGU6bG9jYWxob3N0.vRDLTgxefmKWQEtgGd" + curl -XPOST -d '{"room_alias_name":"tutorial"}' "http://localhost:8008/_matrix/client/api/v1/createRoom?access_token=YOUR_ACCESS_TOKEN" { "room_alias": "#tutorial:localhost", @@ -105,13 +107,19 @@ Sending messages ---------------- You can now send messages to this room:: - curl -XPUT -d '{"msgtype":"m.text", "body":"hello"}' "http://localhost:8080/_matrix/client/api/v1/rooms/%21CvcvRuDYDzTOzfKKgh:localhost/messages/%40example%3Alocalhost/msgid1?access_token=QGV4YW1wbGU6bG9jYWxob3N0.vRDLTgxefmKWQEtgGd" + curl -XPOST -d '{"msgtype":"m.text", "body":"hello"}' "http://localhost:8008/_matrix/client/api/v1/rooms/%21CvcvRuDYDzTOzfKKgh%3Alocalhost/send/m.room.message?access_token=YOUR_ACCESS_TOKEN" + + { + "event_id": "YUwRidLecu" + } + +The event ID returned is a unique ID which identifies this message. NB: There are no limitations to the types of messages which can be exchanged. -The only requirement is that ``"msgtype"`` is specified. - -NB: Depending on the room config, users who join the room may be able to see -message history from before they joined. +The only requirement is that ``"msgtype"`` is specified. The Matrix +specification outlines the following standard types: ``m.text``, ``m.image``, +``m.audio``, ``m.video``, ``m.location``, ``m.emote``. See the specification for +more information on these types. Users and rooms =============== @@ -121,33 +129,32 @@ these rules may specify if you require an **invitation** from someone already in the room in order to **join the room**. In addition, you may also be able to join a room **via a room alias** if one was set up. -**Try out the fiddle: http://jsfiddle.net/og1xokcr/** +**Try out the fiddle: http://jsfiddle.net/7fhotf1b/** Inviting a user to a room ------------------------- You can directly invite a user to a room like so:: - curl -XPUT -d '{"membership":"invite"}' "http://localhost:8080/_matrix/client/api/v1/rooms/%21CvcvRuDYDzTOzfKKgh:localhost/members/%40myfriend%3Alocalhost/state?access_token=QGV4YW1wbGU6bG9jYWxob3N0.vRDLTgxefmKWQEtgGd" + curl -XPOST -d '{"user_id":"@myfriend:localhost"}' "http://localhost:8008/_matrix/client/api/v1/rooms/%21CvcvRuDYDzTOzfKKgh%3Alocalhost/invite?access_token=YOUR_ACCESS_TOKEN" This informs ``@myfriend:localhost`` of the room ID ``!CvcvRuDYDzTOzfKKgh:localhost`` and allows them to join the room. Joining a room via an invite ---------------------------- -If you receive an invite, you can join the room by changing the membership to -join:: +If you receive an invite, you can join the room:: - curl -XPUT -d '{"membership":"join"}' "http://localhost:8080/_matrix/client/api/v1/rooms/%21CvcvRuDYDzTOzfKKgh:localhost/members/%40myfriend%3Alocalhost/state?access_token=QG15ZnJpZW5kOmxvY2FsaG9zdA...XKuGdVsovHmwMyDDvK" + curl -XPOST -d '{}' "http://localhost:8008/_matrix/client/api/v1/rooms/%21CvcvRuDYDzTOzfKKgh%3Alocalhost/join?access_token=YOUR_ACCESS_TOKEN" NB: Only the person invited (``@myfriend:localhost``) can change the membership -state to ``"join"``. +state to ``"join"``. Repeatedly joining a room does nothing. Joining a room via an alias --------------------------- Alternatively, if you know the room alias for this room and the room config allows it, you can directly join a room via the alias:: - curl -XPUT -d '{}' "http://localhost:8080/_matrix/client/api/v1/join/%23tutorial%3Alocalhost?access_token=QG15ZnJpZW5kOmxvY2FsaG9zdA...XKuGdVsovHmwMyDDvK" + curl -XPOST -d '{}' "http://localhost:8008/_matrix/client/api/v1/join/%23tutorial%3Alocalhost?access_token=YOUR_ACCESS_TOKEN" { "room_id": "!CvcvRuDYDzTOzfKKgh:localhost" @@ -166,128 +173,442 @@ An event is some interesting piece of data that a client may be interested in. It can be a message in a room, a room invite, etc. There are many different ways of getting events, depending on what the client already knows. -**Try out the fiddle: http://jsfiddle.net/5uk4dqe2/** +**Try out the fiddle: http://jsfiddle.net/vw11mg37/** Getting all state ----------------- If the client doesn't know any information on the rooms the user is invited/joined on, they can get all the user's state for all rooms:: - curl -XGET "http://localhost:8080/_matrix/client/api/v1/im/sync?access_token=QG15ZnJpZW5kOmxvY2FsaG9zdA...XKuGdVsovHmwMyDDvK" + curl -XGET "http://localhost:8008/_matrix/client/api/v1/initialSync?access_token=YOUR_ACCESS_TOKEN" - [ - { - "membership": "join", - "messages": { - "chunk": [ + { + "end": "s39_18_0", + "presence": [ + { + "content": { + "last_active_ago": 1061436, + "user_id": "@example:localhost" + }, + "type": "m.presence" + } + ], + "rooms": [ + { + "membership": "join", + "messages": { + "chunk": [ + { + "content": { + "@example:localhost": 10, + "default": 0 + }, + "event_id": "wAumPSTsWF", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.power_levels", + "user_id": "@example:localhost" + }, + { + "content": { + "join_rule": "public" + }, + "event_id": "jrLVqKHKiI", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.join_rules", + "user_id": "@example:localhost" + }, + { + "content": { + "level": 10 + }, + "event_id": "WpmTgsNWUZ", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.add_state_level", + "user_id": "@example:localhost" + }, + { + "content": { + "level": 0 + }, + "event_id": "qUMBJyKsTQ", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.send_event_level", + "user_id": "@example:localhost" + }, + { + "content": { + "ban_level": 5, + "kick_level": 5 + }, + "event_id": "YAaDmKvoUW", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.ops_levels", + "user_id": "@example:localhost" + }, + { + "content": { + "avatar_url": null, + "displayname": null, + "membership": "join" + }, + "event_id": "RJbPMtCutf", + "membership": "join", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@example:localhost", + "ts": 1409665586730, + "type": "m.room.member", + "user_id": "@example:localhost" + }, + { + "content": { + "body": "hello", + "hsob_ts": 1409665660439, + "msgtype": "m.text" + }, + "event_id": "YUwRidLecu", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "ts": 1409665660439, + "type": "m.room.message", + "user_id": "@example:localhost" + }, + { + "content": { + "membership": "invite" + }, + "event_id": "YjNuBKnPsb", + "membership": "invite", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@myfriend:localhost", + "ts": 1409666426819, + "type": "m.room.member", + "user_id": "@example:localhost" + }, + { + "content": { + "avatar_url": null, + "displayname": null, + "membership": "join", + "prev": "join" + }, + "event_id": "KWwdDjNZnm", + "membership": "join", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@example:localhost", + "ts": 1409666551582, + "type": "m.room.member", + "user_id": "@example:localhost" + }, + { + "content": { + "avatar_url": null, + "displayname": null, + "membership": "join" + }, + "event_id": "JFLVteSvQc", + "membership": "join", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@example:localhost", + "ts": 1409666587265, + "type": "m.room.member", + "user_id": "@example:localhost" + } + ], + "end": "s39_18_0", + "start": "t1-11_18_0" + }, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state": [ { "content": { - "body": "@example:localhost joined the room.", - "hsob_ts": 1408444664249, - "membership": "join", - "membership_source": "@example:localhost", - "membership_target": "@example:localhost", - "msgtype": "m.text" + "creator": "@example:localhost" }, - "event_id": "lZjmmlrEvo", - "msg_id": "m1408444664249", - "room_id": "!CvcvRuDYDzTOzfKKgh:localhost", - "type": "m.room.message", - "user_id": "_homeserver_" + "event_id": "dMUoqVTZca", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.create", + "user_id": "@example:localhost" }, { "content": { - "body": "hello", - "hsob_ts": 1408445405672, - "msgtype": "m.text" + "@example:localhost": 10, + "default": 0 }, - "event_id": "BiBJqamISg", - "msg_id": "msgid1", - "room_id": "!CvcvRuDYDzTOzfKKgh:localhost", - "type": "m.room.message", + "event_id": "wAumPSTsWF", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.power_levels", "user_id": "@example:localhost" }, - [...] { "content": { - "body": "@myfriend:localhost joined the room.", - "hsob_ts": 1408446501661, - "membership": "join", - "membership_source": "@myfriend:localhost", - "membership_target": "@myfriend:localhost", - "msgtype": "m.text" + "join_rule": "public" + }, + "event_id": "jrLVqKHKiI", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.join_rules", + "user_id": "@example:localhost" + }, + { + "content": { + "level": 10 + }, + "event_id": "WpmTgsNWUZ", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.add_state_level", + "user_id": "@example:localhost" + }, + { + "content": { + "level": 0 + }, + "event_id": "qUMBJyKsTQ", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.send_event_level", + "user_id": "@example:localhost" + }, + { + "content": { + "ban_level": 5, + "kick_level": 5 + }, + "event_id": "YAaDmKvoUW", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.ops_levels", + "user_id": "@example:localhost" + }, + { + "content": { + "membership": "invite" + }, + "event_id": "YjNuBKnPsb", + "membership": "invite", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@myfriend:localhost", + "ts": 1409666426819, + "type": "m.room.member", + "user_id": "@example:localhost" + }, + { + "content": { + "avatar_url": null, + "displayname": null, + "membership": "join" }, - "event_id": "IMmXbOzFAa", - "msg_id": "m1408446501661", - "room_id": "!CvcvRuDYDzTOzfKKgh:localhost", - "type": "m.room.message", - "user_id": "_homeserver_" + "event_id": "JFLVteSvQc", + "membership": "join", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@example:localhost", + "ts": 1409666587265, + "type": "m.room.member", + "user_id": "@example:localhost" } - ], - "end": "20", - "start": "0" - }, - "room_id": "!CvcvRuDYDzTOzfKKgh:localhost" - } - ] + ] + } + ] + } -This returns all the room IDs of rooms the user is invited/joined on, as well as -all of the messages and feedback for these rooms. This can be a LOT of data. You -may just want the most recent message for each room. This can be achieved by -applying pagination stream parameters to this request:: +This returns all the room information the user is invited/joined on, as well as +all of the presences relevant for these rooms. This can be a LOT of data. You +may just want the most recent event for each room. This can be achieved by +applying query parameters to ``limit`` this request:: - curl -XGET "http://localhost:8080/_matrix/client/api/v1/im/sync?access_token=QG15ZnJpZW5kOmxvY2FsaG9zdA...XKuGdVsovHmwMyDDvK&from=END&to=START&limit=1" + curl -XGET "http://localhost:8008/_matrix/client/api/v1/initialSync?limit=1&access_token=YOUR_ACCESS_TOKEN" - [ - { - "membership": "join", - "messages": { - "chunk": [ + { + "end": "s39_18_0", + "presence": [ + { + "content": { + "last_active_ago": 1279484, + "user_id": "@example:localhost" + }, + "type": "m.presence" + } + ], + "rooms": [ + { + "membership": "join", + "messages": { + "chunk": [ + { + "content": { + "avatar_url": null, + "displayname": null, + "membership": "join" + }, + "event_id": "JFLVteSvQc", + "membership": "join", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@example:localhost", + "ts": 1409666587265, + "type": "m.room.member", + "user_id": "@example:localhost" + } + ], + "end": "s39_18_0", + "start": "t10-30_18_0" + }, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state": [ { "content": { - "body": "@myfriend:localhost joined the room.", - "hsob_ts": 1408446501661, - "membership": "join", - "membership_source": "@myfriend:localhost", - "membership_target": "@myfriend:localhost", - "msgtype": "m.text" + "creator": "@example:localhost" + }, + "event_id": "dMUoqVTZca", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.create", + "user_id": "@example:localhost" + }, + { + "content": { + "@example:localhost": 10, + "default": 0 + }, + "event_id": "wAumPSTsWF", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.power_levels", + "user_id": "@example:localhost" + }, + { + "content": { + "join_rule": "public" + }, + "event_id": "jrLVqKHKiI", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.join_rules", + "user_id": "@example:localhost" + }, + { + "content": { + "level": 10 }, - "event_id": "IMmXbOzFAa", - "msg_id": "m1408446501661", - "room_id": "!CvcvRuDYDzTOzfKKgh:localhost", - "type": "m.room.message", - "user_id": "_homeserver_" + "event_id": "WpmTgsNWUZ", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.add_state_level", + "user_id": "@example:localhost" + }, + { + "content": { + "level": 0 + }, + "event_id": "qUMBJyKsTQ", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.send_event_level", + "user_id": "@example:localhost" + }, + { + "content": { + "ban_level": 5, + "kick_level": 5 + }, + "event_id": "YAaDmKvoUW", + "required_power_level": 10, + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "", + "ts": 1409665585188, + "type": "m.room.ops_levels", + "user_id": "@example:localhost" + }, + { + "content": { + "membership": "invite" + }, + "event_id": "YjNuBKnPsb", + "membership": "invite", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@myfriend:localhost", + "ts": 1409666426819, + "type": "m.room.member", + "user_id": "@example:localhost" + }, + { + "content": { + "avatar_url": null, + "displayname": null, + "membership": "join" + }, + "event_id": "JFLVteSvQc", + "membership": "join", + "room_id": "!MkDbyRqnvTYnoxjLYx:localhost", + "state_key": "@example:localhost", + "ts": 1409666587265, + "type": "m.room.member", + "user_id": "@example:localhost" } - ], - "end": "20", - "start": "21" - }, - "room_id": "!CvcvRuDYDzTOzfKKgh:localhost" - } - ] + ] + } + ] + } Getting live state ------------------ Once you know which rooms the client has previously interacted with, you need to listen for incoming events. This can be done like so:: - curl -XGET "http://localhost:8080/_matrix/client/api/v1/events?access_token=QG15ZnJpZW5kOmxvY2FsaG9zdA...XKuGdVsovHmwMyDDvK&from=END" + curl -XGET "http://localhost:8008/_matrix/client/api/v1/events?access_token=YOUR_ACCESS_TOKEN" { "chunk": [], - "end": "215", - "start": "215" + "end": "s39_18_0", + "start": "s39_18_0" } This will block waiting for an incoming event, timing out after several seconds. Even if there are no new events (as in the example above), there will be some pagination stream response keys. The client should make subsequent requests -using the value of the ``"end"`` key (in this case ``215``) as the ``from`` -query parameter. This value should be stored so when the client reopens your app -after a period of inactivity, you can resume from where you got up to in the -event stream. If it has been a long period of inactivity, there may be LOTS of -events waiting for the user. In this case, you may wish to get all state instead -and then resume getting live state from a newer end token. +using the value of the ``"end"`` key (in this case ``s39_18_0``) as the ``from`` +query parameter e.g. ``http://localhost:8008/_matrix/client/api/v1/events?access +_token=YOUR_ACCESS_TOKEN&from=s39_18_0``. This value should be stored so when the +client reopens your app after a period of inactivity, you can resume from where +you got up to in the event stream. If it has been a long period of inactivity, +there may be LOTS of events waiting for the user. In this case, you may wish to +get all state instead and then resume getting live state from a newer end token. NB: The timeout can be changed by adding a ``timeout`` query parameter, which is in milliseconds. A timeout of 0 will not block. @@ -300,4 +621,4 @@ creating and joining rooms, sending messages, getting member lists and getting historical messages for a room. This covers most functionality of a messaging application. -**Try out the fiddle: http://jsfiddle.net/L8r3o1wr/** +**Try out the fiddle: http://jsfiddle.net/uztL3yme/** -- cgit 1.5.1 From 9613d65756ea591c3917185c67a2ba13312bcab7 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 16:38:16 +0100 Subject: spec: Added internal links to different sections. Added NOTE and WARNING admonitions and hide away loooong TODO lists behind comments. Smaller ones remain. --- docs/specification.rst | 187 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 123 insertions(+), 64 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 2b47009187..3c6ed6b1c0 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -278,7 +278,7 @@ which can be set when creating a room: The ``name`` value for the ``m.room.name`` state event. Description: If this is included, an ``m.room.name`` event will be sent into the room to indicate the - name of the room. See "Room Events" for more information on ``m.room.name``. + name of the room. See `Room Events`_ for more information on ``m.room.name``. ``topic`` Type: @@ -289,7 +289,7 @@ which can be set when creating a room: The ``topic`` value for the ``m.room.topic`` state event. Description: If this is included, an ``m.room.topic`` event will be sent into the room to indicate the - topic for the room. See "Room Events" for more information on ``m.room.topic``. + topic for the room. See `Room Events`_ for more information on ``m.room.topic``. Example:: @@ -301,22 +301,30 @@ Example:: } - TODO: This creates a room creation event which serves as the root of the PDU graph for this room. -- TODO: Keys for speccing a room name / room topic / invite these users? +- TODO: Key for invite these users? Modifying aliases ----------------- -- path to edit aliases -- format when retrieving list of aliases. NOT complete list. -- format for adding aliases. +.. NOTE:: + This section is a work in progress. + +.. TODO kegan + - path to edit aliases + - format when retrieving list of aliases. NOT complete list. + - format for adding aliases. Permissions ----------- -- TODO: What is a power level? How do they work? Defaults / required levels for X. How do they change - as people join and leave rooms? What do you do if you get a clash? Examples. -- TODO: List all actions which use power levels (sending msgs, inviting users, banning people, etc...) -- TODO: Room config - what is the event and what are the keys/values and explanations for them. - Link through to respective sections where necessary. How does this tie in with permissions, e.g. - give example of creating a read-only room. +.. NOTE:: + This section is a work in progress. + +.. TODO kegan + - TODO: What is a power level? How do they work? Defaults / required levels for X. How do they change + as people join and leave rooms? What do you do if you get a clash? Examples. + - TODO: List all actions which use power levels (sending msgs, inviting users, banning people, etc...) + - TODO: Room config - what is the event and what are the keys/values and explanations for them. + Link through to respective sections where necessary. How does this tie in with permissions, e.g. + give example of creating a read-only room. Joining rooms @@ -345,7 +353,7 @@ by sending the following request to "membership": "join" } -See the "Room events" section for more information on ``m.room.member``. +See the `Room events`_ section for more information on ``m.room.member``. After the user has joined a room, they will receive subsequent events in that room. This room will now appear as an entry in the ``/initialSync`` API. @@ -387,7 +395,7 @@ directly by sending the following request to "membership": "invite" } -See the "Room events" section for more information on ``m.room.member``. +See the `Room events`_ section for more information on ``m.room.member``. - TODO: In what circumstances will this NOT be equivalent to ``/invite``? @@ -408,7 +416,7 @@ directly by sending the following request to "membership": "leave" } -See the "Room events" section for more information on ``m.room.member``. +See the `Room events`_ section for more information on ``m.room.member``. Once a user has left a room, that room will no longer appear on the ``/initialSync`` API. Be aware that leaving a room is not equivalent to have never been @@ -506,7 +514,7 @@ In some cases, there may be no need for a ``state_key``, so it can be omitted:: PUT /rooms/!roomid:domain/state/m.room.bgd.color { "color": "red", "hex": "#ff0000" } -See "Room Events" for the ``m.`` event specification. +See `Room Events`_ for the ``m.`` event specification. Non-state events ---------------- @@ -521,7 +529,7 @@ For example:: PUT /rooms/!roomid:domain/send/m.custom.example.message/11 { "text": "Goodbye world!" } -See "Room Events" for the ``m.`` event specification. +See `Room Events`_ for the ``m.`` event specification. Syncing rooms ------------- @@ -588,7 +596,11 @@ There are several APIs provided to ``GET`` events for a room: Room Events =========== -- voip events? +.. NOTE:: + This section is a work in progress. + +.. TODO dave? + - voip events? This specification outlines several standard event types, all of which are prefixed with ``m.`` @@ -637,7 +649,7 @@ prefixed with ``m.`` membership APIs (``/rooms//invite`` etc) when performing membership actions rather than adjusting the state directly as there are a restricted set of valid transformations. For example, user A cannot force user B to join a room, and trying - to force this state change directly will fail. See the "Rooms" section for how to + to force this state change directly will fail. See the `Rooms`_ section for how to use the membership APIs. ``m.room.config`` @@ -678,7 +690,7 @@ prefixed with ``m.`` The ``msgtype`` key outlines the type of message, e.g. text, audio, image, video, etc. Whilst not required, the ``body`` key SHOULD be used with every kind of ``msgtype`` as a fallback mechanism when a client cannot render the message. For more information on - the types of messages which can be sent, see "m.room.message msgtypes". + the types of messages which can be sent, see `m.room.message msgtypes`_. ``m.room.message.feedback`` Summary: @@ -799,6 +811,8 @@ The following keys can be attached to any ``m.room.message``: Presence ======== +.. NOTE:: + This section is a work in progress. Each user has the concept of presence information. This encodes the "availability" of that user, suitable for display on other user's clients. This @@ -837,8 +851,9 @@ user was last seen online. Transmission ------------ -- Transmitted as an EDU. -- Presence lists determine who to send to. +.. TODO: + - Transmitted as an EDU. + - Presence lists determine who to send to. Presence List ------------- @@ -863,28 +878,43 @@ presence information in a user list for a room. Typing notifications ==================== -- what is the event type. Are they bundled with other event types? If so, which. -- what are the valid keys / values. What do they represent. Any gotchas? -- Timeouts. How do they work, who sets them and how do they expire. Does one - have priority over another? Give examples. +.. NOTE:: + This section is a work in progress. -TODO : Leo +.. TODO Leo + - what is the event type. Are they bundled with other event types? If so, which. + - what are the valid keys / values. What do they represent. Any gotchas? + - Timeouts. How do they work, who sets them and how do they expire. Does one + have priority over another? Give examples. Voice over IP ============= -- what are the event types. -- what are the valid keys/values. What do they represent. Any gotchas? -- In what sequence should the events be sent? -- How do you accept / decline inbound calls? How do you make outbound calls? - Give examples. -- How does negotiation work? Give examples. -- How do you hang up? -- What does call log information look like e.g. duration of call? - -TODO : Dave +.. NOTE:: + This section is a work in progress. + +.. TODO Dave + - what are the event types. + - what are the valid keys/values. What do they represent. Any gotchas? + - In what sequence should the events be sent? + - How do you accept / decline inbound calls? How do you make outbound calls? + Give examples. + - How does negotiation work? Give examples. + - How do you hang up? + - What does call log information look like e.g. duration of call? Profiles ======== +.. NOTE:: + This section is a work in progress. + +.. TODO + - Metadata extensibility + - Changing profile info generates m.presence events ("presencelike") + - keys on m.presence are optional, except presence which is required + - m.room.member is populated with the current displayname at that point in time. + - That is added by the HS, not you. + - Display name changes also generates m.room.member with displayname key f.e. room + the user is in. Internally within Matrix users are referred to by their user ID, which is not a human-friendly string. Profiles grant users the ability to see human-readable @@ -896,24 +926,20 @@ metadata fields that the user may wish to publish (email address, phone numbers, website URLs, etc...). This specification puts no requirements on the display name other than it being a valid unicode string. -- Metadata extensibility -- Changing profile info generates m.presence events ("presencelike") -- keys on m.presence are optional, except presence which is required -- m.room.member is populated with the current displayname at that point in time. -- That is added by the HS, not you. -- Display name changes also generates m.room.member with displayname key f.e. room - the user is in. + Registration and login ====================== +.. WARNING:: + The registration API is likely to change. + +- TODO Kegan : Make registration like login (just omit the "user" key on the + initial request?) Clients must register with a home server in order to use Matrix. After registering, the client will be given an access token which must be used in ALL requests to that home server as a query parameter 'access_token'. -- TODO Kegan : Make registration like login (just omit the "user" key on the - initial request?) - 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 (OAuth2), login by confirming @@ -1190,9 +1216,11 @@ This MUST return an HTML page which can perform the entire login process. Identity ======== +.. NOTE:: + This section is a work in progress. -TODO : Dave -- 3PIDs and identity server, functions +.. TODO Dave + - 3PIDs and identity server, functions Federation ========== @@ -1233,6 +1261,9 @@ transferred from the origin to the destination home server using an HTTP PUT req Transactions ------------ +.. WARNING:: + This section may be misleading or inaccurate. + The transfer of EDUs and PDUs between home servers is performed by an exchange of Transaction messages, which are encoded as JSON objects, passed over an HTTP PUT request. A Transaction is meaningful only to the pair of home servers that @@ -1275,6 +1306,8 @@ mechanism to encourage peers to continue to replicate content.) PDUs and EDUs ------------- +.. WARNING:: + This section may be misleading or inaccurate. All PDUs have: - An ID @@ -1345,43 +1378,69 @@ destination home server names, and the actual nested content. Backfilling ----------- -- What it is, when is it used, how is it done +.. NOTE:: + This section is a work in progress. + +.. TODO + - What it is, when is it used, how is it done SRV Records ----------- -- Why it is needed +.. NOTE:: + This section is a work in progress. + +.. TODO + - Why it is needed Security ======== - rate limiting -- crypto (s-s auth) -- E2E -- Lawful intercept + Key Escrow -TODO Mark +.. NOTE:: + This section is a work in progress. + +.. TODO + - crypto (s-s auth) + - E2E + - Lawful intercept + Key Escrow + TODO Mark Policy Servers ============== -TODO +.. NOTE:: + This section is a work in progress. Content repository ================== -- path to upload -- format for thumbnail paths, mention what it is protecting against. -- content size limit and associated M_ERROR. +.. NOTE:: + This section is a work in progress. + +.. TODO + - path to upload + - format for thumbnail paths, mention what it is protecting against. + - content size limit and associated M_ERROR. Address book repository ======================= -- format: POST(?) wodges of json, some possible processing, then return wodges of json on GET. -- processing may remove dupes, merge contacts, pepper with extra info (e.g. matrix-ability of - contacts), etc. -- Standard json format for contacts? Piggy back off vcards? +.. NOTE:: + This section is a work in progress. + +.. TODO + - format: POST(?) wodges of json, some possible processing, then return wodges of json on GET. + - processing may remove dupes, merge contacts, pepper with extra info (e.g. matrix-ability of + contacts), etc. + - Standard json format for contacts? Piggy back off vcards? Glossary ======== -- domain specific words/acronyms with definitions +.. NOTE:: + This section is a work in progress. + +.. TODO + - domain specific words/acronyms with definitions 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. + -- cgit 1.5.1 From 1952a1c68da3a6e1f26dc651d39aa90d9a54494c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 17:05:30 +0100 Subject: More formatting, more TODOs. Settled on a way of linking to external API docs; started converting references to relative links. --- docs/specification.rst | 84 +++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 31 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 3c6ed6b1c0..76a6eb0f76 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -134,8 +134,8 @@ Identity API Standards ------------- All communication in Matrix is performed over HTTP[S] using a Content-Type of ``application/json``. -Any errors which occur on the Matrix API level MUST return a "standard error response". This is a -JSON object which looks like:: +In addition, all strings MUST be encoded as UTF-8. Any errors which occur on the Matrix API level +MUST return a "standard error response". This is a JSON object which looks like:: { "errcode": "", @@ -219,22 +219,16 @@ In contrast, these are invalid requests:: "key": "This is a put but it is missing a txnId." } - - -- TODO: All strings everywhere are UTF-8 - - - Receiving live updates on a client ---------------------------------- Clients can receive new events by long-polling the home server. This will hold open the HTTP connection for a short period of time waiting for new events, returning early if an -event occurs. This is called the "Event Stream". All events which the client is authorised +event occurs. This is called the `Event Stream`_. All events which the client is authorised to view will appear in the event stream. When the stream is closed, an ``end`` token is returned. This token can be used in the next request to continue where the client left off. When the client first logs in, they will need to initially synchronise with their home -server. This is achieved via the ``/initialSync`` API. This API also returns an ``end`` +server. This is achieved via the |initialSync|_ API. This API also returns an ``end`` token which can be used with the event stream. Rooms @@ -242,7 +236,11 @@ Rooms Creation -------- -To create a room, a client has to use the ``/createRoom`` API. There are various options +.. TODO kegan + - TODO: This creates a room creation event which serves as the root of the PDU graph for this room. + - TODO: Key for invite these users? + +To create a room, a client has to use the |createRoom|_ API. There are various options which can be set when creating a room: ``visibility`` @@ -300,9 +298,6 @@ Example:: "topic": "All about happy hour" } -- TODO: This creates a room creation event which serves as the root of the PDU graph for this room. -- TODO: Key for invite these users? - Modifying aliases ----------------- .. NOTE:: @@ -329,7 +324,8 @@ Permissions Joining rooms ------------- -- TODO: What does the home server have to do to join a user to a room? +.. TODO kegan + - TODO: What does the home server have to do to join a user to a room? Users need to join a room in order to send and receive events in that room. A user can join a room by making a request to ``/join/`` with:: @@ -356,16 +352,17 @@ by sending the following request to See the `Room events`_ section for more information on ``m.room.member``. After the user has joined a room, they will receive subsequent events in that room. This room -will now appear as an entry in the ``/initialSync`` API. +will now appear as an entry in the |initialSync|_ API. Some rooms enforce that a user is *invited* to a room before they can join that room. Other rooms will allow anyone to join the room even if they have not received an invite. Inviting users -------------- -- Can invite users to a room if the room config key TODO is set to TODO. Must have required power level. -- Outline invite join dance. What is it? Why is it required? How does it work? -- What does the home server have to do? +.. TODO kegan + - Can invite users to a room if the room config key TODO is set to TODO. Must have required power level. + - Outline invite join dance. What is it? Why is it required? How does it work? + - What does the home server have to do? The purpose of inviting users to a room is to notify them that the room exists so they can choose to become a member of that room. Some rooms require that all @@ -401,6 +398,11 @@ See the `Room events`_ section for more information on ``m.room.member``. Leaving rooms ------------- +.. TODO kegan + - TODO: Grace period before deletion? + - TODO: Under what conditions should a room NOT be purged? + + A user can leave a room to stop receiving events for that room. A user must have joined the room before they are eligible to leave the room. If the room is an "invite-only" room, they will need to be re-invited before they can re-join the room. @@ -418,7 +420,7 @@ directly by sending the following request to See the `Room events`_ section for more information on ``m.room.member``. -Once a user has left a room, that room will no longer appear on the ``/initialSync`` +Once a user has left a room, that room will no longer appear on the |initialSync|_ API. Be aware that leaving a room is not equivalent to have never been in that room. A user who has previously left a room still maintains some residual state in that room. Their membership state will be marked as ``leave``. This contrasts with @@ -426,12 +428,9 @@ a user who has *never been invited or joined to that room* who will not have any membership state for that room. If all members in a room leave, that room becomes eligible for deletion. - - TODO: Grace period before deletion? - - TODO: Under what conditions should a room NOT be purged? Banning users in a room ----------------------- - A user may decide to ban another user in a room. 'Banning' forces the target user to leave the room and prevents them from re-joining the room. A banned user will not be treated as a joined user, and so will not be able to send or receive events @@ -533,19 +532,23 @@ See `Room Events`_ for the ``m.`` event specification. Syncing rooms ------------- +.. NOTE:: + This section is a work in progress. + When a client logs in, they may have a list of rooms which they have already joined. These rooms may also have a list of events associated with them. The purpose of 'syncing' is to present the current room and event information in a convenient, compact manner. The events returned are not limited to room events; presence events will also be returned. There are two APIs provided: - - ``/initialSync`` : A global sync which will present room and event information for all rooms + - |initialSync|_ : A global sync which will present room and event information for all rooms the user has joined. - - ``/rooms//initialSync`` : A sync scoped to a single room. Presents room and event + - |roomInitialSync|_ : A sync scoped to a single room. Presents room and event information for this room only. -- TODO: JSON response format for both types -- TODO: when would you use global? when would you use scoped? +.. TODO kegan + - TODO: JSON response format for both types + - TODO: when would you use global? when would you use scoped? Getting events for a room ------------------------- @@ -584,7 +587,7 @@ There are several APIs provided to ``GET`` events for a room: Example: TODO -``/rooms//initialSync`` +|roomInitialSync|_ Description: Get all relevant events for a room. This includes state events, paginated non-state events and presence events. @@ -851,6 +854,9 @@ user was last seen online. Transmission ------------ +.. NOTE:: + This section is a work in progress. + .. TODO: - Transmitted as an EDU. - Presence lists determine who to send to. @@ -933,8 +939,9 @@ Registration and login .. WARNING:: The registration API is likely to change. -- TODO Kegan : Make registration like login (just omit the "user" key on the - initial request?) +.. TODO + - TODO Kegan : Make registration like login (just omit the "user" key on the + initial request?) Clients must register with a home server in order to use Matrix. After registering, the client will be given an access token which must be used in ALL @@ -946,7 +953,8 @@ as user/password auth, login via a social network (OAuth2), login by confirming a token sent to their email address, etc. This specification does not define how home servers should authorise their users who want to login to their existing accounts, but instead defines the standard interface which implementations -should follow so that ANY client can login to ANY home server. +should follow so that ANY client can login to ANY home server. Clients login +using the |login|_ API. The login process breaks down into the following: 1. Determine the requirements for logging in. @@ -1444,3 +1452,17 @@ 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. +.. |createRoom| replace:: ``/createRoom`` +.. _createRoom: /-rooms/create_room + +.. |initialSync| replace:: ``/initialSync`` +.. _initialSync: /-events/initial_sync + +.. |roomInitialSync| replace:: ``/rooms//initialSync`` +.. _roomInitialSync: /-rooms/get_room_sync_data + +.. |login| replace:: ``/login`` +.. _login: /-login + +.. _`Event Stream`: /-events/get_event_stream +.. _`Initial Sync`: /-events/initial_sync -- cgit 1.5.1 From b175179e47730e14f8d7bdd04dd75bb1662d999a Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 17:34:16 +0100 Subject: ALL THE LINKS! Most APIs now link to relative paths off the doc, outlined at the bottom of the .rst. --- docs/specification.rst | 70 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 18 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 76a6eb0f76..0ef18aab68 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -328,11 +328,11 @@ Joining rooms - TODO: What does the home server have to do to join a user to a room? Users need to join a room in order to send and receive events in that room. A user can join a -room by making a request to ``/join/`` with:: +room by making a request to |/join/|_ with:: {} -Alternatively, a user can make a request to ``/rooms//join`` with the same request content. +Alternatively, a user can make a request to |/rooms//join|_ with the same request content. This is only provided for symmetry with the other membership APIs: ``/rooms//invite`` and ``/rooms//leave``. If a room alias was specified, it will be automatically resolved to a room ID, which will then be joined. The room ID that was joined will be returned in response:: @@ -363,6 +363,7 @@ Inviting users - Can invite users to a room if the room config key TODO is set to TODO. Must have required power level. - Outline invite join dance. What is it? Why is it required? How does it work? - What does the home server have to do? + - TODO: In what circumstances will direct member editing NOT be equivalent to ``/invite``? The purpose of inviting users to a room is to notify them that the room exists so they can choose to become a member of that room. Some rooms require that all @@ -377,7 +378,7 @@ Only users who have a membership state of ``join`` in a room can invite new users to said room. The person being invited must not be in the ``join`` state in the room. The fully-qualified user ID must be specified when inviting a user, as the user may reside on a different home server. To invite a user, send the -following request to ``/rooms//invite``, which will manage the +following request to |/rooms//invite|_, which will manage the entire invitation process:: { @@ -394,8 +395,6 @@ directly by sending the following request to See the `Room events`_ section for more information on ``m.room.member``. -- TODO: In what circumstances will this NOT be equivalent to ``/invite``? - Leaving rooms ------------- .. TODO kegan @@ -406,7 +405,7 @@ Leaving rooms A user can leave a room to stop receiving events for that room. A user must have joined the room before they are eligible to leave the room. If the room is an "invite-only" room, they will need to be re-invited before they can re-join the room. -To leave a room, a request should be made to ``/rooms//leave`` with:: +To leave a room, a request should be made to |/rooms//leave|_ with:: {} @@ -436,7 +435,7 @@ to leave the room and prevents them from re-joining the room. A banned user will not be treated as a joined user, and so will not be able to send or receive events in the room. In order to ban someone, the user performing the ban MUST have the required power level. To ban a user, a request should be made to -``/rooms//ban`` with:: +|/rooms//ban|_ with:: { "user_id": "/state//``. +State events can be sent by ``PUT`` ing to |/rooms//state//|_. These events will be overwritten if ````, ```` and ```` all match. If the state event has no ``state_key``, it can be omitted from the path. These requests **cannot use transaction IDs** like other ``PUT`` paths because they cannot be differentiated @@ -517,7 +516,7 @@ See `Room Events`_ for the ``m.`` event specification. Non-state events ---------------- -Non-state events can be sent by sending a request to ``/rooms//send/``. +Non-state events can be sent by sending a request to |/rooms//send/|_. These requests *can* use transaction IDs and ``PUT``/``POST`` methods. Non-state events allow access to historical events and pagination, making it best suited for sending messages. For example:: @@ -543,7 +542,7 @@ limited to room events; presence events will also be returned. There are two API - |initialSync|_ : A global sync which will present room and event information for all rooms the user has joined. - - |roomInitialSync|_ : A sync scoped to a single room. Presents room and event + - |/rooms//initialSync|_ : A sync scoped to a single room. Presents room and event information for this room only. .. TODO kegan @@ -562,7 +561,7 @@ There are several APIs provided to ``GET`` events for a room: Example: ``/rooms/!room:domain.com/state/m.room.name`` returns ``{ "name": "Room name" }`` -``/rooms//state`` +|/rooms//state|_ Description: Get all state events for a room. Response format: @@ -571,7 +570,7 @@ There are several APIs provided to ``GET`` events for a room: TODO -``/rooms//members`` +|/rooms//members|_ Description: Get all ``m.room.member`` state events. Response format: @@ -579,7 +578,7 @@ There are several APIs provided to ``GET`` events for a room: Example: TODO -``/rooms//messages`` +|/rooms//messages|_ Description: Get all ``m.room.message`` events. Response format: @@ -587,7 +586,7 @@ There are several APIs provided to ``GET`` events for a room: Example: TODO -|roomInitialSync|_ +|/rooms//initialSync|_ Description: Get all relevant events for a room. This includes state events, paginated non-state events and presence events. @@ -622,7 +621,7 @@ prefixed with ``m.`` human-friendly, but not all rooms have room aliases. The room name is a human-friendly string designed to be displayed to the end-user. The room name is not *unique*, as multiple rooms can have the same room name set. The room name can also be set when - creating a room using ``/createRoom`` with the ``name`` key. + creating a room using |createRoom|_ with the ``name`` key. ``m.room.topic`` Summary: @@ -636,7 +635,8 @@ prefixed with ``m.`` Description: A topic is a short message detailing what is currently being discussed in the room. It can also be used as a way to display extra information about the room, which may - not be suitable for the room name. + not be suitable for the room name. The room topic can also be set when creating a + room using |createRoom|_ with the ``topic`` key. ``m.room.member`` Summary: @@ -1452,17 +1452,51 @@ 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. + +.. Links through the external API docs are below +.. ============================================= + .. |createRoom| replace:: ``/createRoom`` .. _createRoom: /-rooms/create_room .. |initialSync| replace:: ``/initialSync`` .. _initialSync: /-events/initial_sync -.. |roomInitialSync| replace:: ``/rooms//initialSync`` -.. _roomInitialSync: /-rooms/get_room_sync_data +.. |/rooms//initialSync| replace:: ``/rooms//initialSync`` +.. _/rooms//initialSync: /-rooms/get_room_sync_data .. |login| replace:: ``/login`` .. _login: /-login +.. |/rooms//messages| replace:: ``/rooms//messages`` +.. _/rooms//messages: /-rooms/get_messages + +.. |/rooms//members| replace:: ``/rooms//members`` +.. _/rooms//members: /-rooms/get_members + +.. |/rooms//state| replace:: ``/rooms//state`` +.. _/rooms//state: /-rooms/get_state_events + +.. |/rooms//send/| replace:: ``/rooms//send/`` +.. _/rooms//send/: /-rooms/send_non_state_event + +.. |/rooms//state//| replace:: ``/rooms//state//`` +.. _/rooms//state//: /-rooms/send_state_event + +.. |/rooms//invite| replace:: ``/rooms//invite`` +.. _/rooms//invite: /-rooms/invite + +.. |/rooms//join| replace:: ``/rooms//join`` +.. _/rooms//join: /-rooms/join_room + +.. |/rooms//leave| replace:: ``/rooms//leave`` +.. _/rooms//leave: /-rooms/leave + +.. |/rooms//ban| replace:: ``/rooms//ban`` +.. _/rooms//ban: /-rooms/ban + +.. |/join/| replace:: ``/join/`` +.. _/join/: /-rooms/join + .. _`Event Stream`: /-events/get_event_stream .. _`Initial Sync`: /-events/initial_sync -- cgit 1.5.1 From 9f94b11d4c9e3f87a06c976cffb69d3b9a9d59a4 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 17:51:45 +0100 Subject: Added section on rate limiting. --- docs/specification.rst | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 0ef18aab68..1e472d46bf 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1402,11 +1402,24 @@ SRV Records Security ======== -- rate limiting - .. 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 +request is refused due to rate limiting, it should return a standard error response of +the form:: + + { + "errcode": "M_LIMIT_EXCEEDED", + "error": "string", + "retry_after_ms": integer (optional) + } + +The ``retry_after_ms`` key SHOULD be included to tell the client how long they have to wait +in milliseconds before they can try again. + .. TODO - crypto (s-s auth) - E2E @@ -1499,4 +1512,3 @@ User ID: .. _/join/: /-rooms/join .. _`Event Stream`: /-events/get_event_stream -.. _`Initial Sync`: /-events/initial_sync -- cgit 1.5.1 From 3167d478828061c78d98306d7adb6264c1dfb618 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 17:58:16 +0100 Subject: Minor formatting tweaks. --- docs/specification.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 1e472d46bf..d7285328d9 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1019,7 +1019,7 @@ This specification defines the following login types: Password-based -------------- :Type: - m.login.password + ``m.login.password`` :Description: Login is supported via a username and password. @@ -1037,7 +1037,7 @@ process, or a standard error response. OAuth2-based ------------ :Type: - m.login.oauth2 + ``m.login.oauth2`` :Description: Login is supported via OAuth2 URLs. This login consists of multiple requests. @@ -1090,7 +1090,7 @@ visits the REDIRECT_URI with the auth code= query parameter which returns:: Email-based (code) ------------------ :Type: - m.login.email.code + ``m.login.email.code`` :Description: Login is supported by typing in a code which is sent in an email. This login consists of multiple requests. @@ -1125,7 +1125,7 @@ the login process, or a standard error response. Email-based (url) ----------------- :Type: - m.login.email.url + ``m.login.email.url`` :Description: Login is supported by clicking on a URL in an email. This login consists of multiple requests. -- cgit 1.5.1 From 2f5182b2d2193efb58bf67ca1e2fccd15ad63813 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 20:32:09 +0100 Subject: Finished up Identity section in the architecture section. --- docs/specification.rst | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index d7285328d9..b679c8cb6e 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -118,18 +118,31 @@ once and then use that ID on subsequent requests. | domain.com | | Mappings: | | #matrix >> !aaabaa:matrix.org | - | #golf >> !wfeiofh:sport.com | - | #bike >> !4rguxf:matrix.org | + | #golf >> !wfeiofh:sport.com | + | #bike >> !4rguxf:matrix.org | |________________________________| Identity -------- -- Identity in relation to 3PIDs. Discovery of users based on 3PIDs. -- Identity servers; trusted clique of servers which replicate content. -- They govern the mapping of 3PIDs to user IDs and the creation of said mappings. -- Not strictly required in order to communicate. - +Users in Matrix are identified via their user ID. However, existing ID namespaces +can also be used in order to identify Matrix users. A Matrix "Identity" describes +both the user ID and any other existing ID namespaces *linked* to their account. + +Matrix users can *link* third-party IDs (3PIDs) such as email addresses, social +network accounts and phone numbers to their +user ID. Linking 3PIDs creates a mapping from a 3PID to a user ID. This mapping +can then be used by other Matrix users in order to discover other users, according +to a strict set of privacy permissions. + +In order to ensure that the mapping from 3PID to user ID is genuine, dedicated +trusted servers called "Identity Servers" (IS) are used to perform authentication +of the 3PID. Identity servers are also used to preserve the mapping indefinitely, +by replicating the mappings across multiple ISes. + +Usage of an IS is not required in order for a client application to be part of +the Matrix ecosystem. However, by not using an IS, discovery of users is greatly +impacted. API Standards ------------- -- cgit 1.5.1 From 707cd32b13dee473e2230dc9ac66762dfe413e04 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 20:38:25 +0100 Subject: Added more room alias bullet points. --- docs/specification.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index b679c8cb6e..1b844b963f 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -317,9 +317,11 @@ Modifying aliases This section is a work in progress. .. TODO kegan - - path to edit aliases + - path to edit aliases + - PUT /directory/room/ { room_id : foo } + - GET /directory/room/ { room_id : foo, servers: [a.com, b.com] } - format when retrieving list of aliases. NOT complete list. - - format for adding aliases. + - format for adding/removing aliases. Permissions ----------- -- cgit 1.5.1 From ab6e1abe9cc0c98deb2838e6ff53c639b83bf7e6 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 21:12:46 +0100 Subject: Added the new power level related events which were recently introduced. --- docs/specification.rst | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 1b844b963f..78c600db24 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -693,6 +693,66 @@ prefixed with ``m.`` TODO Description: TODO + +``m.room.join_rules`` + Summary: + TODO. + Type: + State event + JSON format: + TODO + Example: + TODO + Description: + TODO + +``m.room.power_levels`` + Summary: + TODO. + Type: + State event + JSON format: + TODO + Example: + TODO + Description: + TODO + +``m.room.add_state_level`` + Summary: + TODO. + Type: + State event + JSON format: + TODO + Example: + TODO + Description: + TODO + +``m.room.send_event_level`` + Summary: + TODO. + Type: + State event + JSON format: + TODO + Example: + TODO + Description: + TODO + +``m.room.ops_levels`` + Summary: + TODO. + Type: + State event + JSON format: + TODO + Example: + TODO + Description: + TODO ``m.room.message`` Summary: -- cgit 1.5.1 From 7819a1010c8a12df71c60b5acf8ed6d28509beea Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 2 Sep 2014 21:14:32 +0100 Subject: general documentation review and editing --- README.rst | 14 ++-- docs/specification.rst | 194 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 156 insertions(+), 52 deletions(-) (limited to 'docs') diff --git a/README.rst b/README.rst index a6652da419..98af91ea42 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Introduction ============ Matrix is an ambitious new ecosystem for open federated Instant Messaging and -VoIP[1]. The basics you need to know to get up and running are: +VoIP. The basics you need to know to get up and running are: - Chatrooms are distributed and do not exist on any single server. Rooms can be found using names like ``#matrix:matrix.org`` or @@ -39,8 +39,6 @@ To get up and running: For more detailed setup instructions, please see further down this document. -[1] VoIP currently in development - About Matrix ============ @@ -50,15 +48,15 @@ which handle: - Creating and managing fully distributed chat rooms with no single points of control or failure - - Eventually-consistent cryptographically secure[2] synchronisation of room + - Eventually-consistent cryptographically secure[1] 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[3] + end-to-end encryption[2] - Inviting, joining, leaving, kicking, banning room members - Managing user accounts (registration, login, logout) - Using 3rd Party IDs (3PIDs) such as email addresses, phone numbers, Facebook accounts to authenticate, identify and discover users on Matrix. - - Placing 1:1 VoIP and Video calls (in development) + - Placing 1:1 VoIP and Video calls These APIs are intended to be implemented on a wide range of servers, services and clients, letting developers build messaging and VoIP functionality on top of @@ -92,9 +90,9 @@ https://github.com/matrix-org/synapse/issues or at matrix@matrix.org. Thanks for trying Matrix! -[2] Cryptographic signing of messages isn't turned on yet +[1] Cryptographic signing of messages isn't turned on yet -[3] End-to-end encryption is currently in development +[2] End-to-end encryption is currently in development Homeserver Installation diff --git a/docs/specification.rst b/docs/specification.rst index 78c600db24..50bf716952 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1,11 +1,73 @@ Matrix Specification ==================== -TODO(Introduction) : Matthew - - Similar to intro paragraph from README. - - Explaining the overall mission, what this spec describes... - - "What is Matrix?" - - Draw parallels with email? +WARNING +======= + +.. NOTE:: + The Matrix specification is still very much evolving: the API is not yet frozen + and this document is in places incomplete, stale, and may contain security + issues. Needless to say, we have made every effort to highlight the problem + areas that we're aware of. + + We're publishing it at this point because it's complete enough to be more than + useful and provide a canonical reference to how Matrix is evolving. Our end + goal is to mirror WHATWG's "Living Standard" approach (see + http://wiki.whatwg.org/wiki/FAQ#What_does_.22Living_Standard.22_mean.3F) - + except right now Matrix is more in the process of being born than actually being + living! + +Introduction +============ + +Matrix is a new set of open APIs for open-federated Instant Messaging and VoIP +functionality, designed to create and support a new global real-time +communication ecosystem on the internet. This specification is the ongoing +result of standardising the APIs used by the various components of the Matrix +ecosystem to communicate with one another. + +The principles that Matrix attempts to follow are: + + - Pragmatic Web-friendly APIs (i.e. JSON over REST) + - Keep It Simple & Stupid + - provide a simple architecture with minimal third-party dependencies. + - Fully open: + - Fully open federation - anyone should be able to participate in the global Matrix network + - Fully open standard - publicly documented standard with no IP or patent licensing encumbrances + - Fully open source reference implementation - liberally-licensed example implementations + with no IP or patent licensing encumbrances + - Empowering the end-user + - The user should be able to choose the server and clients they use + - The user should be control how private their communication is + - The user should know precisely where their data is stored + - Fully decentralised - no single points of control over conversations or the network as a whole + - Learning from history to avoid repeating it + - Trying to take the best aspects of XMPP, SIP, IRC, SMTP, IMAP and NNTP whilst trying to avoid their failings + +The functionality that Matrix provides includes: + + - Creation and management of fully distributed chat rooms with no + single points of control or failure + - Eventually-consistent cryptographically secure synchronisation of room + state across a global open network of federated servers and services + - Sending and receiving extensible messages in a room with (optional) + end-to-end encryption + - Extensible user management (inviting, joining, leaving, kicking, banning) + mediated by a power-level based user privilege system. + - Extensible room state management (room naming, aliasing, topics, bans) + - Extensible user profile management (avatars, 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 +messages, VoIP call setups, or any other objects that need to be reliably and +persistently pushed from A to B in an interoperable and federated manner. + Architecture ============ @@ -28,38 +90,43 @@ other directly. | |<--------( HTTP )-----------| | +------------------+ Federation +------------------+ -A "Client" is an end-user, typically a human using a web application or mobile app. Clients use the -"Client-to-Server" (C-S) API to communicate with their home server. A single Client is usually -responsible for a single user account. A user account is represented by their "User ID". This ID is -namespaced to the home server which allocated the account and looks like:: +A "Client" typically represents a human using a web application or mobile app. Clients use the +"Client-to-Server" (C-S) API to communicate with their home server, which stores their profile data and +their record of the conversations in which they participate. Each client is associated with a user account +(and may optionally support multiple user accounts). A user account is represented by a unique "User ID". This +ID is namespaced to the home server which allocated the account and looks like:: @localpart:domain The ``localpart`` of a user ID may be a user name, or an opaque ID identifying this user. They are case-insensitive. +.. TODO + - Need to specify precise grammar for Matrix IDs + A "Home Server" is a server which provides C-S APIs and has the ability to federate with other HSes. It is typically responsible for multiple clients. "Federation" is the term used to describe the sharing of data between two or more home servers. -Data in Matrix is encapsulated in an "Event". An event is an action within the system. Typically each -action (e.g. sending a message) correlates with exactly one event. Each event has a ``type`` which is -used to differentiate different kinds of data. ``type`` values SHOULD be namespaced according to standard -Java package naming conventions, e.g. ``com.example.myapp.event``. Events are usually sent in the context -of a "Room". +Data in Matrix is encapsulated in an "event". An event is an action within the system. Typically each +action (e.g. sending a message) correlates with exactly one event. Each event has a ``type`` which is used +to differentiate different kinds of data. ``type`` values MUST be uniquely globally namespaced following +Java's `package naming conventions `, +e.g. ``com.example.myapp.event``. The special top-level namespace ``m.`` is reserved for events defined +in the Matrix specification. Events are usually sent in the context of a "Room". Room structure -------------- A room is a conceptual place where users can send and receive events. Rooms can be created, joined and left. Events are sent to a room, and all -participants in that room will receive the event. Rooms are uniquely -identified via a "Room ID", which look like:: +participants in that room with sufficient access will receive the event. Rooms are uniquely +identified internally via a "Room ID", which look like:: !opaque_id:domain There is exactly one room ID for each room. Whilst the room ID does contain a -domain, it is simply for namespacing room IDs. The room does NOT reside on the +domain, it is simply for globally namespacing room IDs. The room does NOT reside on the domain specified. Room IDs are not meant to be human readable. They ARE case-sensitive. @@ -101,9 +168,12 @@ Each room can also have multiple "Room Aliases", which looks like:: #room_alias:domain -A room alias "points" to a room ID. The room ID the alias is pointing to can be obtained -by visiting the domain specified. Room aliases are designed to be human readable strings -which can be used to publicise rooms. They are case-insensitive. Note that the mapping + .. TODO + - Need to specify precise grammar for Room IDs + +A room alias "points" to a room ID and is the human-readable label by which rooms are +publicised and discovered. The room ID the alias is pointing to can be obtained +by visiting the domain specified. They are case-insensitive. Note that the mapping from a room alias to a room ID is not fixed, and may change over time to point to a different room ID. For this reason, Clients SHOULD resolve the room alias to a room ID once and then use that ID on subsequent requests. @@ -122,12 +192,16 @@ once and then use that ID on subsequent requests. | #bike >> !4rguxf:matrix.org | |________________________________| +.. TODO kegan + - show the actual API rather than pseudo-API? + Identity -------- -Users in Matrix are identified via their user ID. However, existing ID namespaces -can also be used in order to identify Matrix users. A Matrix "Identity" describes -both the user ID and any other existing ID namespaces *linked* to their account. + +Users in Matrix are identified via their user ID. However, existing ID namespaces can also +be used in order to identify Matrix users. A Matrix "Identity" describes both the user ID +and any other existing IDs from third party namespaces *linked* to their account. Matrix users can *link* third-party IDs (3PIDs) such as email addresses, social network accounts and phone numbers to their @@ -135,10 +209,10 @@ user ID. Linking 3PIDs creates a mapping from a 3PID to a user ID. This mapping can then be used by other Matrix users in order to discover other users, according to a strict set of privacy permissions. -In order to ensure that the mapping from 3PID to user ID is genuine, dedicated -trusted servers called "Identity Servers" (IS) are used to perform authentication -of the 3PID. Identity servers are also used to preserve the mapping indefinitely, -by replicating the mappings across multiple ISes. +In order to ensure that the mapping from 3PID to user ID is genuine, a globally federated +cluster of trusted "Identity Servers" (IS) are used to perform authentication of the 3PID. +Identity servers are also used to preserve the mapping indefinitely, by replicating the +mappings across multiple ISes. Usage of an IS is not required in order for a client application to be part of the Matrix ecosystem. However, by not using an IS, discovery of users is greatly @@ -146,8 +220,28 @@ impacted. API Standards ------------- -All communication in Matrix is performed over HTTP[S] using a Content-Type of ``application/json``. -In addition, all strings MUST be encoded as UTF-8. Any errors which occur on the Matrix API level + +The mandatory baseline for communication in Matrix is exchanging JSON objects over RESTful +HTTP APIs. HTTPS is mandated as the baseline for server-server (federation) communication. +HTTPS is recommended for client-server communication, although HTTP may be supported as a +fallback to support basic HTTP clients. More efficient optional transports for +client-server communication will in future be supported as optional extensions - e.g. a +packed binary encoding over stream-cipher encrypted TCP socket for +low-bandwidth/low-roundtrip mobile usage. + +.. TODO + We need to specify capability negotiation for extensible transports + +For the default HTTP transport, all API calls use a Content-Type of ``application/json``. +In addition, all strings MUST be encoded as UTF-8. + +Clients are authenticated using opaque ``access_token`` strings (see `Registration and +Login`_ for details), passed as a querystring parameter on all requests. + +.. TODO + Need to specify any HMAC or access_token lifetime/ratcheting tricks + +Any errors which occur on the Matrix API level MUST return a "standard error response". This is a JSON object which looks like:: { @@ -199,46 +293,53 @@ Some requests have unique error codes: :``M_LOGIN_EMAIL_URL_NOT_YET``: Encountered when polling for an email link which has not been clicked yet. -The C-S API typically uses ``HTTP POST`` to submit requests. This means these requests -are not idempotent. The C-S API also allows ``HTTP PUT`` to make requests idempotent. -In order to use a ``PUT``, paths should be suffixed with ``/{txnId}``. ``{txnId}`` is a -client-generated transaction ID which identifies the request. Crucially, it **only** -serves to identify new requests from retransmits. After the request has finished, the -``{txnId}`` value should be changed (how is not specified, it could be a monotonically -increasing integer, etc). It is preferable to use ``HTTP PUT`` to make sure requests to -send messages do not get sent more than once should clients need to retransmit requests. +The C-S API typically uses ``HTTP POST`` to submit requests. This means these requests are +not idempotent. The C-S API also allows ``HTTP PUT`` to make requests idempotent. In order +to use a ``PUT``, paths should be suffixed with ``/{txnId}``. ``{txnId}`` is a +unique client-generated transaction ID which identifies the request, and is scoped to a given +Client (identified by that client's ``access_token``). Crucially, it **only** serves to +identify new requests from retransmits. After the request has finished, the ``{txnId}`` +value should be changed (how is not specified; a monotonically increasing integer is +recommended). It is preferable to use ``HTTP PUT`` to make sure requests to send messages +do not get sent more than once should clients need to retransmit requests. Valid requests look like:: - POST /some/path/here + POST /some/path/here?access_token=secret { "key": "This is a post." } - PUT /some/path/here/11 + PUT /some/path/here/11?access_token=secret { "key": "This is a put with a txnId of 11." } In contrast, these are invalid requests:: - POST /some/path/here/11 + POST /some/path/here/11?access_token=secret { "key": "This is a post, but it has a txnId." } - PUT /some/path/here + PUT /some/path/here?access_token=secret { "key": "This is a put but it is missing a txnId." } Receiving live updates on a client ---------------------------------- + Clients can receive new events by long-polling the home server. This will hold open the HTTP connection for a short period of time waiting for new events, returning early if an -event occurs. This is called the `Event Stream`_. All events which the client is authorised -to view will appear in the event stream. When the stream is closed, an ``end`` token is -returned. This token can be used in the next request to continue where the client left off. +event occurs. This is called the `Event Stream`_. All events which are visible to the +client and match the client's query will appear in the event stream. When the request +returns, an ``end`` token is included in the response. This token can be used in the next +request to continue where the client left off. + +.. TODO + Do we ever return multiple events in a single request? Do we ever support streaming + requests? Why not websockets? When the client first logs in, they will need to initially synchronise with their home server. This is achieved via the |initialSync|_ API. This API also returns an ``end`` @@ -1475,6 +1576,11 @@ SRV Records .. TODO - Why it is needed +VoIP +==== +.. NOTE:: +This section is a work in progress. + Security ======== .. NOTE:: -- cgit 1.5.1 From dcbdfcc9d2c7b2d5bf469addf8009a272010267c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 2 Sep 2014 21:16:59 +0100 Subject: only need one voip section :) --- docs/specification.rst | 5 ----- 1 file changed, 5 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 50bf716952..563126fdca 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -1576,11 +1576,6 @@ SRV Records .. TODO - Why it is needed -VoIP -==== -.. NOTE:: -This section is a work in progress. - Security ======== .. NOTE:: -- cgit 1.5.1 From 0aacab43caecd884040f7cbc588cefa400913673 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 21:17:29 +0100 Subject: Added Qs which should be answered in the marked TODOs --- docs/specification.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 563126fdca..07b57ef2ab 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -781,7 +781,7 @@ prefixed with ``m.`` Example: TODO Description: - TODO + TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what ``m.room.invite_join`` Summary: @@ -793,7 +793,7 @@ prefixed with ``m.`` Example: TODO Description: - TODO + 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: @@ -805,7 +805,7 @@ prefixed with ``m.`` Example: TODO Description: - TODO + TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what ``m.room.power_levels`` Summary: @@ -817,7 +817,7 @@ prefixed with ``m.`` Example: TODO Description: - TODO + TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what ``m.room.add_state_level`` Summary: @@ -829,7 +829,7 @@ prefixed with ``m.`` Example: TODO Description: - TODO + TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what ``m.room.send_event_level`` Summary: @@ -841,7 +841,7 @@ prefixed with ``m.`` Example: TODO Description: - TODO + TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what ``m.room.ops_levels`` Summary: @@ -853,7 +853,7 @@ prefixed with ``m.`` Example: TODO Description: - TODO + TODO : What it represents, What are the valid keys / values and what they represent, When is this event emitted and by what ``m.room.message`` Summary: -- cgit 1.5.1 From 70aa4b9231d8b1412fbff91a83d31a468c5d7d87 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 2 Sep 2014 21:45:36 +0100 Subject: Edited room creation section to mention all the events created when the room is. --- docs/specification.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 07b57ef2ab..20e7a0d85f 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -351,7 +351,6 @@ Rooms Creation -------- .. TODO kegan - - TODO: This creates a room creation event which serves as the root of the PDU graph for this room. - TODO: Key for invite these users? To create a room, a client has to use the |createRoom|_ API. There are various options @@ -412,6 +411,22 @@ Example:: "topic": "All about happy hour" } +The home server will create a ``m.room.create`` event when the room is +created, which serves as the root of the PDU graph for this room. This +event also has a ``creator`` key which contains the user ID of the room +creator. It will also generate several other events in order to manage +permissions in this room. This includes: + + - ``m.room.power_levels`` : Sets the authority of the room creator. + - ``m.room.join_rules`` : Whether the room is "invite-only" or not. + - ``m.room.add_state_level`` + - ``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 + ban a user from the room. + +See `Room Events`_ for more information on these events. + Modifying aliases ----------------- .. NOTE:: -- cgit 1.5.1 From 2b9afa775eabfe6cef1757ff4885fada8f41741e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 2 Sep 2014 21:18:00 +0100 Subject: more critique --- docs/specification.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 20e7a0d85f..5381e0db51 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -338,7 +338,8 @@ returns, an ``end`` token is included in the response. This token can be used in request to continue where the client left off. .. TODO - Do we ever return multiple events in a single request? Do we ever support streaming + Do we ever return multiple events in a single request? Don't we get lots of request + setup RTT latency if we only do one event per request? Do we ever support streaming requests? Why not websockets? When the client first logs in, they will need to initially synchronise with their home -- cgit 1.5.1 From 9fae76107f3c928f1e082b9a7d3352a6f0ca6cbd Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 3 Sep 2014 04:30:51 +0100 Subject: fix rst --- docs/specification.rst | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) (limited to 'docs') diff --git a/docs/specification.rst b/docs/specification.rst index 5381e0db51..fdd5f07917 100644 --- a/docs/specification.rst +++ b/docs/specification.rst @@ -4,19 +4,21 @@ Matrix Specification WARNING ======= -.. NOTE:: +.. WARNING:: The Matrix specification is still very much evolving: the API is not yet frozen and this document is in places incomplete, stale, and may contain security issues. Needless to say, we have made every effort to highlight the problem areas that we're aware of. - + We're publishing it at this point because it's complete enough to be more than useful and provide a canonical reference to how Matrix is evolving. Our end - goal is to mirror WHATWG's "Living Standard" approach (see - http://wiki.whatwg.org/wiki/FAQ#What_does_.22Living_Standard.22_mean.3F) - - except right now Matrix is more in the process of being born than actually being + goal is to mirror WHATWG's `Living Standard `_ + approach except right now Matrix is more in the process of being born than actually being living! +.. contents:: Table of Contents +.. sectnum:: + Introduction ============ @@ -30,19 +32,26 @@ The principles that Matrix attempts to follow are: - Pragmatic Web-friendly APIs (i.e. JSON over REST) - Keep It Simple & Stupid - - provide a simple architecture with minimal third-party dependencies. + + + provide a simple architecture with minimal third-party dependencies. + - Fully open: - - Fully open federation - anyone should be able to participate in the global Matrix network - - Fully open standard - publicly documented standard with no IP or patent licensing encumbrances - - Fully open source reference implementation - liberally-licensed example implementations - with no IP or patent licensing encumbrances + + + Fully open federation - anyone should be able to participate in the global Matrix network + + Fully open standard - publicly documented standard with no IP or patent licensing encumbrances + + Fully open source reference implementation - liberally-licensed example implementations with no + IP or patent licensing encumbrances + - Empowering the end-user - - The user should be able to choose the server and clients they use - - The user should be control how private their communication is - - The user should know precisely where their data is stored + + + The user should be able to choose the server and clients they use + + The user should be control how private their communication is + + The user should know precisely where their data is stored + - Fully decentralised - no single points of control over conversations or the network as a whole - Learning from history to avoid repeating it - - Trying to take the best aspects of XMPP, SIP, IRC, SMTP, IMAP and NNTP whilst trying to avoid their failings + + + 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: @@ -60,8 +69,9 @@ The functionality that Matrix provides includes: - 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 + + + 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 8c793e0704caaf3e96a407d59cc33897b1cf2001 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 3 Sep 2014 09:14:16 +0100 Subject: howto: Link jsfiddles correctly. Hide ugly TODOs. --- docs/client-server/howto.rst | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'docs') diff --git a/docs/client-server/howto.rst b/docs/client-server/howto.rst index 54b80e7dea..c02ea8d897 100644 --- a/docs/client-server/howto.rst +++ b/docs/client-server/howto.rst @@ -1,7 +1,8 @@ -TODO(kegan): Room config (specifically: message history, -public rooms). /register seems super simplistic compared to /login, maybe it -would be better if /register used the same technique as /login? /register should -be "user" not "user_id". +.. TODO kegan + Room config (specifically: message history, + public rooms). /register seems super simplistic compared to /login, maybe it + would be better if /register used the same technique as /login? /register should + be "user" not "user_id". How to use the client-server API @@ -21,7 +22,9 @@ Accounts Before you can send and receive messages, you must **register** for an account. If you already have an account, you must **login** into it. -**Try out the fiddle: http://jsfiddle.net/4q2jyxng/** +`Try out the fiddle`__ + +.. __: http://jsfiddle.net/4q2jyxng/ Registration ------------ @@ -82,7 +85,9 @@ Communicating In order to communicate with another user, you must **create a room** with that user and **send a message** to that room. -**Try out the fiddle: http://jsfiddle.net/zL3zto9g/** +`Try out the fiddle`__ + +.. __: http://jsfiddle.net/zL3zto9g/ Creating a room --------------- @@ -100,7 +105,8 @@ The "room alias" is a human-readable string which can be shared with other users so they can join a room, rather than the room ID which is a randomly generated string. You can have multiple room aliases per room. -TODO(kegan): How to add/remove aliases from an existing room. +.. TODO(kegan) + How to add/remove aliases from an existing room. Sending messages @@ -129,7 +135,9 @@ these rules may specify if you require an **invitation** from someone already in the room in order to **join the room**. In addition, you may also be able to join a room **via a room alias** if one was set up. -**Try out the fiddle: http://jsfiddle.net/7fhotf1b/** +`Try out the fiddle`__ + +.. __: http://jsfiddle.net/7fhotf1b/ Inviting a user to a room ------------------------- @@ -173,7 +181,9 @@ An event is some interesting piece of data that a client may be interested in. It can be a message in a room, a room invite, etc. There are many different ways of getting events, depending on what the client already knows. -**Try out the fiddle: http://jsfiddle.net/vw11mg37/** +`Try out the fiddle`__ + +.. __: http://jsfiddle.net/vw11mg37/ Getting all state ----------------- @@ -621,4 +631,6 @@ creating and joining rooms, sending messages, getting member lists and getting historical messages for a room. This covers most functionality of a messaging application. -**Try out the fiddle: http://jsfiddle.net/uztL3yme/** +`Try out the fiddle`__ + +.. __: http://jsfiddle.net/uztL3yme/ -- cgit 1.5.1 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