Merge branch 'release-v0.4.0' of github.com:matrix-org/synapse into develop
This commit is contained in:
commit
f1ddbfaae4
13
CHANGES.rst
13
CHANGES.rst
|
@ -1,6 +1,13 @@
|
||||||
Changes in latest
|
Changes in synpase 0.4.0 (2014-10-17)
|
||||||
=================
|
=====================================
|
||||||
This breaks federation becuase of signing
|
This server includes changes to the federation protocol that is not backwards
|
||||||
|
compatible.
|
||||||
|
|
||||||
|
The Matrix specification has been moved to a seperate git repository.
|
||||||
|
|
||||||
|
Homeserver:
|
||||||
|
* Sign federation transactions.
|
||||||
|
* Rename timestamp keys in PDUs.
|
||||||
|
|
||||||
Changes in synapse 0.3.4 (2014-09-25)
|
Changes in synapse 0.3.4 (2014-09-25)
|
||||||
=====================================
|
=====================================
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
Upgrading to latest
|
|
||||||
===================
|
|
||||||
This breaks federation between old and new servers due to signing of
|
|
||||||
transactions.
|
|
||||||
|
|
||||||
Upgrading to v0.3.0
|
Upgrading to v0.3.0
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
All matrix-generic documentation now lives in its own project at
|
||||||
|
|
||||||
|
github.com/matrix-org/matrix-doc.git
|
||||||
|
|
||||||
|
Only Synapse implementation-specific documentation lives here now
|
||||||
|
(together with some older stuff will be shortly migrated over to matrix-doc)
|
|
@ -1,637 +0,0 @@
|
||||||
.. 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
|
|
||||||
================================
|
|
||||||
|
|
||||||
This guide focuses on how the client-server APIs *provided by the reference
|
|
||||||
home server* can be used. Since this is specific to a home server
|
|
||||||
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:8008``.
|
|
||||||
|
|
||||||
|
|
||||||
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/gh/get/jquery/1.8.3/matrix-org/synapse/tree/master/jsfiddles/register_login
|
|
||||||
|
|
||||||
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":"example", "password":"wordpass", "type":"m.login.password"}' "http://localhost:8008/_matrix/client/api/v1/register"
|
|
||||||
|
|
||||||
{
|
|
||||||
"access_token": "QGV4YW1wbGU6bG9jYWxob3N0.AqdSzFmFYrLrTmteXc",
|
|
||||||
"home_server": "localhost",
|
|
||||||
"user_id": "@example:localhost"
|
|
||||||
}
|
|
||||||
|
|
||||||
NB: If a ``user`` is not specified, one will be randomly generated for you.
|
|
||||||
If you do not specify a ``password``, you will be unable to login to the account
|
|
||||||
if you forget the ``access_token``.
|
|
||||||
|
|
||||||
Implementation note: The matrix specification does not enforce how users
|
|
||||||
register with a server. It just specifies the URL path and absolute minimum
|
|
||||||
keys. The reference home server uses a username/password to authenticate user,
|
|
||||||
but other home servers may use different methods. This is why you need to
|
|
||||||
specify the ``type`` of method.
|
|
||||||
|
|
||||||
Login
|
|
||||||
-----
|
|
||||||
The aim when logging in is to get an access token for your existing user ID::
|
|
||||||
|
|
||||||
curl -XGET "http://localhost:8008/_matrix/client/api/v1/login"
|
|
||||||
|
|
||||||
{
|
|
||||||
"flows": [
|
|
||||||
{
|
|
||||||
"type": "m.login.password"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
curl -XPOST -d '{"type":"m.login.password", "user":"example", "password":"wordpass"}' "http://localhost:8008/_matrix/client/api/v1/login"
|
|
||||||
|
|
||||||
{
|
|
||||||
"access_token": "QGV4YW1wbGU6bG9jYWxob3N0.vRDLTgxefmKWQEtgGd",
|
|
||||||
"home_server": "localhost",
|
|
||||||
"user_id": "@example:localhost"
|
|
||||||
}
|
|
||||||
|
|
||||||
Implementation note: Different home servers may implement different methods for
|
|
||||||
logging in to an existing account. In order to check that you know how to login
|
|
||||||
to this home server, you must perform a ``GET`` first and make sure you
|
|
||||||
recognise the login type. If you do not know how to login, you can
|
|
||||||
``GET /login/fallback`` which will return a basic webpage which you can use to
|
|
||||||
login. The reference home server implementation support username/password login,
|
|
||||||
but other home servers may support different login methods (e.g. OAuth2).
|
|
||||||
|
|
||||||
|
|
||||||
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/gh/get/jquery/1.8.3/matrix-org/synapse/tree/master/jsfiddles/create_room_send_msg
|
|
||||||
|
|
||||||
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:8008/_matrix/client/api/v1/createRoom?access_token=YOUR_ACCESS_TOKEN"
|
|
||||||
|
|
||||||
{
|
|
||||||
"room_alias": "#tutorial:localhost",
|
|
||||||
"room_id": "!CvcvRuDYDzTOzfKKgh:localhost"
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Sending messages
|
|
||||||
----------------
|
|
||||||
You can now send messages to this room::
|
|
||||||
|
|
||||||
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. 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
|
|
||||||
===============
|
|
||||||
|
|
||||||
Each room can be configured to allow or disallow certain rules. In particular,
|
|
||||||
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/gh/get/jquery/1.8.3/matrix-org/synapse/tree/master/jsfiddles/room_memberships
|
|
||||||
|
|
||||||
Inviting a user to a room
|
|
||||||
-------------------------
|
|
||||||
You can directly invite a user to a room like so::
|
|
||||||
|
|
||||||
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::
|
|
||||||
|
|
||||||
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"``. 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 -XPOST -d '{}' "http://localhost:8008/_matrix/client/api/v1/join/%23tutorial%3Alocalhost?access_token=YOUR_ACCESS_TOKEN"
|
|
||||||
|
|
||||||
{
|
|
||||||
"room_id": "!CvcvRuDYDzTOzfKKgh:localhost"
|
|
||||||
}
|
|
||||||
|
|
||||||
You will need to use the room ID when sending messages, not the room alias.
|
|
||||||
|
|
||||||
NB: If the room is configured to be an invite-only room, you will still require
|
|
||||||
an invite in order to join the room even though you know the room alias. As a
|
|
||||||
result, it is more common to see a room alias in relation to a public room,
|
|
||||||
which do not require invitations.
|
|
||||||
|
|
||||||
Getting events
|
|
||||||
==============
|
|
||||||
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/gh/get/jquery/1.8.3/matrix-org/synapse/tree/master/jsfiddles/event_stream
|
|
||||||
|
|
||||||
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:8008/_matrix/client/api/v1/initialSync?access_token=YOUR_ACCESS_TOKEN"
|
|
||||||
|
|
||||||
{
|
|
||||||
"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": {
|
|
||||||
"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": "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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
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:8008/_matrix/client/api/v1/initialSync?limit=1&access_token=YOUR_ACCESS_TOKEN"
|
|
||||||
|
|
||||||
{
|
|
||||||
"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": {
|
|
||||||
"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": "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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
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:8008/_matrix/client/api/v1/events?access_token=YOUR_ACCESS_TOKEN"
|
|
||||||
|
|
||||||
{
|
|
||||||
"chunk": [],
|
|
||||||
"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 ``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.
|
|
||||||
|
|
||||||
|
|
||||||
Example application
|
|
||||||
-------------------
|
|
||||||
The following example demonstrates registration and login, live event streaming,
|
|
||||||
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/gh/get/jquery/1.8.3/matrix-org/synapse/tree/master/jsfiddles/example_app
|
|
|
@ -1,46 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"swaggerVersion": "1.2",
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"path": "-login",
|
|
||||||
"description": "Login operations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "-registration",
|
|
||||||
"description": "Registration operations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "-rooms",
|
|
||||||
"description": "Room operations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "-profile",
|
|
||||||
"description": "Profile operations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "-presence",
|
|
||||||
"description": "Presence operations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "-events",
|
|
||||||
"description": "Event operations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "-directory",
|
|
||||||
"description": "Directory operations"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"authorizations": {
|
|
||||||
"token": {
|
|
||||||
"scopes": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"info": {
|
|
||||||
"title": "Matrix Client-Server API Reference",
|
|
||||||
"description": "This contains the client-server API for the reference implementation of the home server",
|
|
||||||
"termsOfServiceUrl": "http://matrix.org",
|
|
||||||
"license": "Apache 2.0",
|
|
||||||
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"swaggerVersion": "1.2",
|
|
||||||
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
|
||||||
"resourcePath": "/directory",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"path": "/directory/room/{roomAlias}",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"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": [
|
|
||||||
{
|
|
||||||
"name": "roomAlias",
|
|
||||||
"description": "The room alias.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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": [
|
|
||||||
{
|
|
||||||
"name": "roomAlias",
|
|
||||||
"description": "The room alias to set.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The room ID to set.",
|
|
||||||
"required": true,
|
|
||||||
"type": "RoomAliasRequest",
|
|
||||||
"paramType": "body"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "DELETE",
|
|
||||||
"summary": "Removes a mapping of room alias to room ID.",
|
|
||||||
"notes": "Only privileged users can perform this action.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "remove_room_alias",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomAlias",
|
|
||||||
"description": "The room alias to remove.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"models": {
|
|
||||||
"DirectoryResponse": {
|
|
||||||
"id": "DirectoryResponse",
|
|
||||||
"properties": {
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The fully-qualified room ID.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"servers": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "string"
|
|
||||||
},
|
|
||||||
"description": "A list of servers that know about this room.",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RoomAliasRequest": {
|
|
||||||
"id": "RoomAliasRequest",
|
|
||||||
"properties": {
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The room ID to map the alias to.",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,247 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"swaggerVersion": "1.2",
|
|
||||||
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
|
||||||
"resourcePath": "/events",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"path": "/events",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Listen on the event stream",
|
|
||||||
"notes": "This can only be done by the logged in user. This will block until an event is received, or until the timeout is reached.",
|
|
||||||
"type": "PaginationChunk",
|
|
||||||
"nickname": "get_event_stream",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "from",
|
|
||||||
"description": "The token to stream from.",
|
|
||||||
"required": false,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "timeout",
|
|
||||||
"description": "The maximum time in milliseconds to wait for an event.",
|
|
||||||
"required": false,
|
|
||||||
"type": "integer",
|
|
||||||
"paramType": "query"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Bad pagination token."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/events/{eventId}",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get information about a single event.",
|
|
||||||
"notes": "Get information about a single event.",
|
|
||||||
"type": "Event",
|
|
||||||
"nickname": "get_event",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "eventId",
|
|
||||||
"description": "The event ID to get.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"message": "Event not found."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/initialSync",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get this user's current state.",
|
|
||||||
"notes": "Get this user's current state.",
|
|
||||||
"type": "InitialSyncResponse",
|
|
||||||
"nickname": "initial_sync",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "limit",
|
|
||||||
"description": "The maximum number of messages to return for each room.",
|
|
||||||
"type": "integer",
|
|
||||||
"paramType": "query",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/publicRooms",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get a list of publicly visible rooms.",
|
|
||||||
"type": "PublicRoomsPaginationChunk",
|
|
||||||
"nickname": "get_public_room_list"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"models": {
|
|
||||||
"PaginationChunk": {
|
|
||||||
"id": "PaginationChunk",
|
|
||||||
"properties": {
|
|
||||||
"start": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A token which correlates to the first value in \"chunk\" for paginating.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A token which correlates to the last value in \"chunk\" for paginating.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"chunk": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "An array of events.",
|
|
||||||
"required": true,
|
|
||||||
"items": {
|
|
||||||
"$ref": "Event"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Event": {
|
|
||||||
"id": "Event",
|
|
||||||
"properties": {
|
|
||||||
"event_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "An ID which uniquely identifies this event.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The room in which this event occurred.",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PublicRoomInfo": {
|
|
||||||
"id": "PublicRoomInfo",
|
|
||||||
"properties": {
|
|
||||||
"aliases": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of room aliases for this room.",
|
|
||||||
"items": {
|
|
||||||
"$ref": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the room, as given by the m.room.name state event."
|
|
||||||
},
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The room ID for this public room.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"topic": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The topic of this room, as given by the m.room.topic state event."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PublicRoomsPaginationChunk": {
|
|
||||||
"id": "PublicRoomsPaginationChunk",
|
|
||||||
"properties": {
|
|
||||||
"start": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A token which correlates to the first value in \"chunk\" for paginating.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A token which correlates to the last value in \"chunk\" for paginating.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"chunk": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of public room data.",
|
|
||||||
"required": true,
|
|
||||||
"items": {
|
|
||||||
"$ref": "PublicRoomInfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"InitialSyncResponse": {
|
|
||||||
"id": "InitialSyncResponse",
|
|
||||||
"properties": {
|
|
||||||
"end": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A streaming token which can be used with /events to continue from this snapshot of data.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"presence": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of presence events.",
|
|
||||||
"items": {
|
|
||||||
"$ref": "Event"
|
|
||||||
},
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"rooms": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of initial sync room data.",
|
|
||||||
"required": false,
|
|
||||||
"items": {
|
|
||||||
"$ref": "InitialSyncRoomData"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"InitialSyncRoomData": {
|
|
||||||
"id": "InitialSyncRoomData",
|
|
||||||
"properties": {
|
|
||||||
"membership": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "This user's membership state in this room.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The ID of this room.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"messages": {
|
|
||||||
"type": "PaginationChunk",
|
|
||||||
"description": "The most recent messages for this room, governed by the limit parameter.",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of state events representing the current state of the room.",
|
|
||||||
"required": false,
|
|
||||||
"items": {
|
|
||||||
"$ref": "Event"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"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": "LoginFlows"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"nickname": "submit_login",
|
|
||||||
"notes": "If this is part of a multi-stage login, there MUST be a 'session' key.",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "A login submission",
|
|
||||||
"name": "body",
|
|
||||||
"paramType": "body",
|
|
||||||
"required": true,
|
|
||||||
"type": "LoginSubmission"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Bad login type"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Missing JSON keys"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"summary": "Submit a login action.",
|
|
||||||
"type": "LoginResult"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"path": "/login"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
|
||||||
"consumes": [
|
|
||||||
"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.",
|
|
||||||
"items": {
|
|
||||||
"$ref": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"description": "The login type that must be used when logging in.",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"LoginResult": {
|
|
||||||
"id": "LoginResult",
|
|
||||||
"properties": {
|
|
||||||
"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.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"session": {
|
|
||||||
"description": "Multi-stage login only: The session token to send when submitting the next login type.",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"LoginSubmission": {
|
|
||||||
"id": "LoginSubmission",
|
|
||||||
"properties": {
|
|
||||||
"type": {
|
|
||||||
"description": "The type of login being submitted.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"session": {
|
|
||||||
"description": "Multi-stage login only: The session token from an earlier login stage.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"_login_type_defined_keys_": {
|
|
||||||
"description": "Keys as defined by the specified login type, e.g. \"user\", \"password\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"resourcePath": "/login",
|
|
||||||
"swaggerVersion": "1.2"
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,164 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"swaggerVersion": "1.2",
|
|
||||||
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
|
||||||
"resourcePath": "/presence",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"path": "/presence/{userId}/status",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"summary": "Update this user's presence state.",
|
|
||||||
"notes": "This can only be done by the logged in user.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "update_presence",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The new presence state",
|
|
||||||
"required": true,
|
|
||||||
"type": "PresenceUpdate",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose presence to set.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get this user's presence state.",
|
|
||||||
"notes": "Get this user's presence state.",
|
|
||||||
"type": "PresenceUpdate",
|
|
||||||
"nickname": "get_presence",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose presence to get.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/presence/list/{userId}",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Retrieve a list of presences for all of this user's friends.",
|
|
||||||
"notes": "",
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "Presence"
|
|
||||||
},
|
|
||||||
"nickname": "get_presence_list",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose presence list to get.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Add or remove users from this presence list.",
|
|
||||||
"notes": "Add or remove users from this presence list.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "modify_presence_list",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose presence list is being modified.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The modifications to make to this presence list.",
|
|
||||||
"required": true,
|
|
||||||
"type": "PresenceListModifications",
|
|
||||||
"paramType": "body"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"models": {
|
|
||||||
"PresenceUpdate": {
|
|
||||||
"id": "PresenceUpdate",
|
|
||||||
"properties": {
|
|
||||||
"presence": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Enum: The presence state.",
|
|
||||||
"enum": [
|
|
||||||
"offline",
|
|
||||||
"unavailable",
|
|
||||||
"online",
|
|
||||||
"free_for_chat"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"status_msg": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The user-defined message associated with this presence state."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subTypes": [
|
|
||||||
"Presence"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Presence": {
|
|
||||||
"id": "Presence",
|
|
||||||
"properties": {
|
|
||||||
"last_active_ago": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64",
|
|
||||||
"description": "The last time this user performed an action on their home server."
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The fully qualified user ID"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PresenceListModifications": {
|
|
||||||
"id": "PresenceListModifications",
|
|
||||||
"properties": {
|
|
||||||
"invite": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of user IDs to add to the list.",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A fully qualified user ID."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"drop": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of user IDs to remove from the list.",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A fully qualified user ID."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"swaggerVersion": "1.2",
|
|
||||||
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
|
||||||
"resourcePath": "/profile",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"path": "/profile/{userId}/displayname",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"summary": "Set a display name.",
|
|
||||||
"notes": "This can only be done by the logged in user.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "set_display_name",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The new display name for this user.",
|
|
||||||
"required": true,
|
|
||||||
"type": "DisplayName",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose display name to set.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get a display name.",
|
|
||||||
"notes": "This can be done by anyone.",
|
|
||||||
"type": "DisplayName",
|
|
||||||
"nickname": "get_display_name",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose display name to get.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/profile/{userId}/avatar_url",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"summary": "Set an avatar URL.",
|
|
||||||
"notes": "This can only be done by the logged in user.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "set_avatar_url",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The new avatar url for this user.",
|
|
||||||
"required": true,
|
|
||||||
"type": "AvatarUrl",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose avatar url to set.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get an avatar url.",
|
|
||||||
"notes": "This can be done by anyone.",
|
|
||||||
"type": "AvatarUrl",
|
|
||||||
"nickname": "get_avatar_url",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose avatar url to get.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"models": {
|
|
||||||
"DisplayName": {
|
|
||||||
"id": "DisplayName",
|
|
||||||
"properties": {
|
|
||||||
"displayname": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The textual display name"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AvatarUrl": {
|
|
||||||
"id": "AvatarUrl",
|
|
||||||
"properties": {
|
|
||||||
"avatar_url": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A url to an image representing an avatar."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"nickname": "get_registration_info",
|
|
||||||
"notes": "All login stages MUST be mentioned if there is >1 login type.",
|
|
||||||
"summary": "Get the login mechanism to use when registering.",
|
|
||||||
"type": "RegistrationFlows"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"nickname": "submit_registration",
|
|
||||||
"notes": "If this is part of a multi-stage registration, there MUST be a 'session' key.",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "A registration submission",
|
|
||||||
"name": "body",
|
|
||||||
"paramType": "body",
|
|
||||||
"required": true,
|
|
||||||
"type": "RegistrationSubmission"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Bad login type"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Missing JSON keys"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"summary": "Submit a registration action.",
|
|
||||||
"type": "RegistrationResult"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"path": "/register"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"models": {
|
|
||||||
"RegistrationFlows": {
|
|
||||||
"id": "RegistrationFlows",
|
|
||||||
"properties": {
|
|
||||||
"flows": {
|
|
||||||
"description": "A list of valid registration flows.",
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "RegistrationInfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RegistrationInfo": {
|
|
||||||
"id": "RegistrationInfo",
|
|
||||||
"properties": {
|
|
||||||
"stages": {
|
|
||||||
"description": "Multi-stage registration only: An array of all the login types required to registration.",
|
|
||||||
"items": {
|
|
||||||
"$ref": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"description": "The first login type that must be used when logging in.",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RegistrationResult": {
|
|
||||||
"id": "RegistrationResult",
|
|
||||||
"properties": {
|
|
||||||
"access_token": {
|
|
||||||
"description": "The access token for this user's registration if this is the final stage of the registration process.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"description": "The user's fully-qualified user ID.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"next": {
|
|
||||||
"description": "Multi-stage registration only: The next registration type to submit.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"session": {
|
|
||||||
"description": "Multi-stage registration only: The session token to send when submitting the next registration type.",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RegistrationSubmission": {
|
|
||||||
"id": "RegistrationSubmission",
|
|
||||||
"properties": {
|
|
||||||
"type": {
|
|
||||||
"description": "The type of registration being submitted.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"session": {
|
|
||||||
"description": "Multi-stage registration only: The session token from an earlier registration stage.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"_registration_type_defined_keys_": {
|
|
||||||
"description": "Keys as defined by the specified registration type, e.g. \"user\", \"password\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"resourcePath": "/register",
|
|
||||||
"swaggerVersion": "1.2"
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,977 +0,0 @@
|
||||||
{
|
|
||||||
"apiVersion": "1.0.0",
|
|
||||||
"swaggerVersion": "1.2",
|
|
||||||
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
|
||||||
"resourcePath": "/rooms",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"authorizations": {
|
|
||||||
"token": []
|
|
||||||
},
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/send/{eventType}",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Send a generic non-state event to this room.",
|
|
||||||
"notes": "This operation can also be done as a PUT by suffixing /{txnId}.",
|
|
||||||
"type": "EventId",
|
|
||||||
"nickname": "send_non_state_event",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The event contents",
|
|
||||||
"required": true,
|
|
||||||
"type": "EventContent",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to send the message in.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "eventType",
|
|
||||||
"description": "The type of event to send.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/state/{eventType}/{stateKey}",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"summary": "Send a generic state event to this room.",
|
|
||||||
"notes": "The state key can be omitted, such that you can PUT to /rooms/{roomId}/state/{eventType}. The state key defaults to a 0 length string in this case.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "send_state_event",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The event contents",
|
|
||||||
"required": true,
|
|
||||||
"type": "EventContent",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to send the message in.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "eventType",
|
|
||||||
"description": "The type of event to send.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stateKey",
|
|
||||||
"description": "An identifier used to specify clobbering semantics. State events with the same (roomId, eventType, stateKey) will be replaced.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/send/m.room.message",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Send a message in this room.",
|
|
||||||
"notes": "This operation can also be done as a PUT by suffixing /{txnId}.",
|
|
||||||
"type": "EventId",
|
|
||||||
"nickname": "send_message",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The message contents",
|
|
||||||
"required": true,
|
|
||||||
"type": "Message",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to send the message in.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/state/m.room.topic",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"summary": "Set the topic for this room.",
|
|
||||||
"notes": "Set the topic for this room.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "set_topic",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The topic contents",
|
|
||||||
"required": true,
|
|
||||||
"type": "Topic",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to set the topic in.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get the topic for this room.",
|
|
||||||
"notes": "Get the topic for this room.",
|
|
||||||
"type": "Topic",
|
|
||||||
"nickname": "get_topic",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to get topic in.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"message": "Topic not found."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Send feedback to a message.",
|
|
||||||
"notes": "This operation can also be done as a PUT by suffixing /{txnId}.",
|
|
||||||
"type": "EventId",
|
|
||||||
"nickname": "send_feedback",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The feedback contents",
|
|
||||||
"required": true,
|
|
||||||
"type": "Feedback",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to send the feedback in.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Bad feedback type."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/invite",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Invite a user to this room.",
|
|
||||||
"notes": "This operation can also be done as a PUT by suffixing /{txnId}.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "invite",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room which has this user.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The user to invite.",
|
|
||||||
"required": true,
|
|
||||||
"type": "InviteRequest",
|
|
||||||
"paramType": "body"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/join",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Join this room.",
|
|
||||||
"notes": "This operation can also be done as a PUT by suffixing /{txnId}.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "join_room",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to join.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"required": true,
|
|
||||||
"type": "JoinRequest",
|
|
||||||
"paramType": "body"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/leave",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Leave this room.",
|
|
||||||
"notes": "This operation can also be done as a PUT by suffixing /{txnId}.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "leave",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to leave.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"required": true,
|
|
||||||
"type": "LeaveRequest",
|
|
||||||
"paramType": "body"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/ban",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Ban a user in the room.",
|
|
||||||
"notes": "This operation can also be done as a PUT by suffixing /{txnId}. The caller must have the required power level to do this operation.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "ban",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room which has the user to ban.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The user to ban.",
|
|
||||||
"required": true,
|
|
||||||
"type": "BanRequest",
|
|
||||||
"paramType": "body"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/state/m.room.member/{userId}",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"summary": "Change the membership state for a user in a room.",
|
|
||||||
"notes": "Change the membership state for a user in a room.",
|
|
||||||
"type": "void",
|
|
||||||
"nickname": "set_membership",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The new membership state",
|
|
||||||
"required": true,
|
|
||||||
"type": "Member",
|
|
||||||
"paramType": "body"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose membership is being changed.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room which has this user.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "No membership key."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Bad membership value."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 403,
|
|
||||||
"message": "When inviting: You are not in the room."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 403,
|
|
||||||
"message": "When inviting: <target> is already in the room."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 403,
|
|
||||||
"message": "When joining: Cannot force another user to join."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 403,
|
|
||||||
"message": "When joining: You are not invited to this room."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get the membership state of a user in a room.",
|
|
||||||
"notes": "Get the membership state of a user in a room.",
|
|
||||||
"type": "Member",
|
|
||||||
"nickname": "get_membership",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "userId",
|
|
||||||
"description": "The user whose membership state you want to get.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room which has this user.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"message": "Member not found."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/join/{roomAliasOrId}",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"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": "JoinRoomInfo",
|
|
||||||
"nickname": "join",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomAliasOrId",
|
|
||||||
"description": "The room alias or room ID to join.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Bad room alias."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/createRoom",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"summary": "Create a room.",
|
|
||||||
"notes": "Create a room.",
|
|
||||||
"type": "RoomInfo",
|
|
||||||
"nickname": "create_room",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"description": "The desired configuration for the room. This operation can also be done as a PUT by suffixing /{txnId}.",
|
|
||||||
"required": true,
|
|
||||||
"type": "RoomConfig",
|
|
||||||
"paramType": "body"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responseMessages": [
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Body must be JSON."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"message": "Room alias already taken."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/messages",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get a list of messages for this room.",
|
|
||||||
"notes": "Get a list of messages for this room.",
|
|
||||||
"type": "MessagePaginationChunk",
|
|
||||||
"nickname": "get_messages",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to get messages in.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "from",
|
|
||||||
"description": "The token to start getting results from.",
|
|
||||||
"required": false,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "to",
|
|
||||||
"description": "The token to stop getting results at.",
|
|
||||||
"required": false,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "limit",
|
|
||||||
"description": "The maximum number of messages to return.",
|
|
||||||
"required": false,
|
|
||||||
"type": "integer",
|
|
||||||
"paramType": "query"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/members",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get a list of members for this room.",
|
|
||||||
"notes": "Get a list of members for this room.",
|
|
||||||
"type": "MemberPaginationChunk",
|
|
||||||
"nickname": "get_members",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to get a list of members from.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "from",
|
|
||||||
"description": "The token to start getting results from.",
|
|
||||||
"required": false,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "to",
|
|
||||||
"description": "The token to stop getting results at.",
|
|
||||||
"required": false,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "limit",
|
|
||||||
"description": "The maximum number of members to return.",
|
|
||||||
"required": false,
|
|
||||||
"type": "integer",
|
|
||||||
"paramType": "query"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/state",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "Get a list of all the current state events for this room.",
|
|
||||||
"notes": "This is equivalent to the events returned under the 'state' key for this room in /initialSync.",
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "Event"
|
|
||||||
},
|
|
||||||
"nickname": "get_state_events",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to get a list of current state events from.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/rooms/{roomId}/initialSync",
|
|
||||||
"operations": [
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"summary": "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": [
|
|
||||||
{
|
|
||||||
"name": "roomId",
|
|
||||||
"description": "The room to get information for.",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"paramType": "path"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"models": {
|
|
||||||
"Topic": {
|
|
||||||
"id": "Topic",
|
|
||||||
"properties": {
|
|
||||||
"topic": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The topic text"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RoomName": {
|
|
||||||
"id": "RoomName",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The human-readable name for the room. Can contain spaces."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Message": {
|
|
||||||
"id": "Message",
|
|
||||||
"properties": {
|
|
||||||
"msgtype": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The type of message being sent, e.g. \"m.text\"",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"_msgtype_defined_keys_": {
|
|
||||||
"description": "Additional keys as defined by the msgtype, e.g. \"body\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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": {
|
|
||||||
"id": "Member",
|
|
||||||
"properties": {
|
|
||||||
"membership": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Enum: The membership state of this member.",
|
|
||||||
"enum": [
|
|
||||||
"invite",
|
|
||||||
"join",
|
|
||||||
"leave",
|
|
||||||
"ban"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RoomInfo": {
|
|
||||||
"id": "RoomInfo",
|
|
||||||
"properties": {
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The allocated room ID.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"room_alias": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The alias for the room.",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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": {
|
|
||||||
"visibility": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Enum: The room visibility.",
|
|
||||||
"required": false,
|
|
||||||
"enum": [
|
|
||||||
"public",
|
|
||||||
"private"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"room_alias_name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The alias to give the new room.",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Sets the name of the room. Send a m.room.name event after creating the room with the 'name' key specified.",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"topic": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Sets the topic for the room. Send a m.room.topic event after creating the room with the 'topic' key specified.",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PaginationRequest": {
|
|
||||||
"id": "PaginationRequest",
|
|
||||||
"properties": {
|
|
||||||
"from": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The token to start getting results from."
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The token to stop getting results at."
|
|
||||||
},
|
|
||||||
"limit": {
|
|
||||||
"type": "integer",
|
|
||||||
"description": "The maximum number of entries to return."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PaginationChunk": {
|
|
||||||
"id": "PaginationChunk",
|
|
||||||
"properties": {
|
|
||||||
"start": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A token which correlates to the first value in \"chunk\" for paginating.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A token which correlates to the last value in \"chunk\" for paginating.",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subTypes": [
|
|
||||||
"MessagePaginationChunk"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"MessagePaginationChunk": {
|
|
||||||
"id": "MessagePaginationChunk",
|
|
||||||
"properties": {
|
|
||||||
"chunk": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of message events.",
|
|
||||||
"items": {
|
|
||||||
"$ref": "MessageEvent"
|
|
||||||
},
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MemberPaginationChunk": {
|
|
||||||
"id": "MemberPaginationChunk",
|
|
||||||
"properties": {
|
|
||||||
"chunk": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of member events.",
|
|
||||||
"items": {
|
|
||||||
"$ref": "MemberEvent"
|
|
||||||
},
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Event": {
|
|
||||||
"id": "Event",
|
|
||||||
"properties": {
|
|
||||||
"event_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "An ID which uniquely identifies this event. This is automatically set by the server.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The room in which this event occurred. This is automatically set by the server.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The event type.",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subTypes": [
|
|
||||||
"MessageEvent"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"EventId": {
|
|
||||||
"id": "EventId",
|
|
||||||
"properties": {
|
|
||||||
"event_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The allocated event ID for this event.",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"EventContent": {
|
|
||||||
"id": "EventContent",
|
|
||||||
"properties": {
|
|
||||||
"__event_content_keys__": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Event-specific content keys and values.",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MessageEvent": {
|
|
||||||
"id": "MessageEvent",
|
|
||||||
"properties": {
|
|
||||||
"content": {
|
|
||||||
"type": "Message"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MemberEvent": {
|
|
||||||
"id": "MemberEvent",
|
|
||||||
"properties": {
|
|
||||||
"content": {
|
|
||||||
"type": "Member"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"InviteRequest": {
|
|
||||||
"id": "InviteRequest",
|
|
||||||
"properties": {
|
|
||||||
"user_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The fully-qualified user ID."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"JoinRequest": {
|
|
||||||
"id": "JoinRequest",
|
|
||||||
"properties": {}
|
|
||||||
},
|
|
||||||
"LeaveRequest": {
|
|
||||||
"id": "LeaveRequest",
|
|
||||||
"properties": {}
|
|
||||||
},
|
|
||||||
"BanRequest": {
|
|
||||||
"id": "BanRequest",
|
|
||||||
"properties": {
|
|
||||||
"user_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The fully-qualified user ID."
|
|
||||||
},
|
|
||||||
"reason": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The reason for the ban."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"InitialSyncRoomData": {
|
|
||||||
"id": "InitialSyncRoomData",
|
|
||||||
"properties": {
|
|
||||||
"membership": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "This user's membership state in this room.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"room_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The ID of this room.",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"messages": {
|
|
||||||
"type": "MessagePaginationChunk",
|
|
||||||
"description": "The most recent messages for this room, governed by the limit parameter.",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "A list of state events representing the current state of the room.",
|
|
||||||
"required": false,
|
|
||||||
"items": {
|
|
||||||
"$ref": "Event"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
Definitions
|
|
||||||
===========
|
|
||||||
|
|
||||||
# *Event* -- A JSON object that represents a piece of information to be
|
|
||||||
distributed to the the room. The object includes a payload and metadata,
|
|
||||||
including a `type` used to indicate what the payload is for and how to process
|
|
||||||
them. It also includes one or more references to previous events.
|
|
||||||
|
|
||||||
# *Event graph* -- Events and their references to previous events form a
|
|
||||||
directed acyclic graph. All events must be a descendant of the first event in a
|
|
||||||
room, except for a few special circumstances.
|
|
||||||
|
|
||||||
# *State event* -- A state event is an event that has a non-null string valued
|
|
||||||
`state_key` field. It may also include a `prev_state` key referencing exactly
|
|
||||||
one state event with the same type and state key, in the same event graph.
|
|
||||||
|
|
||||||
# *State tree* -- A state tree is a tree formed by a collection of state events
|
|
||||||
that have the same type and state key (all in the same event graph.
|
|
||||||
|
|
||||||
# *State resolution algorithm* -- An algorithm that takes a state tree as input
|
|
||||||
and selects a single leaf node.
|
|
||||||
|
|
||||||
# *Current state event* -- The leaf node of a given state tree that has been
|
|
||||||
selected by the state resolution algorithm.
|
|
||||||
|
|
||||||
# *Room state* / *state dictionary* / *current state* -- A mapping of the pair
|
|
||||||
(event type, state key) to the current state event for that pair.
|
|
||||||
|
|
||||||
# *Room* -- An event graph and its associated state dictionary. An event is in
|
|
||||||
the room if it is part of the event graph.
|
|
||||||
|
|
||||||
# *Topological ordering* -- The partial ordering that can be extracted from the
|
|
||||||
event graph due to it being a DAG.
|
|
||||||
|
|
||||||
(The state definitions are purposely slightly ill-defined, since if we allow
|
|
||||||
deleting events we might end up with multiple state trees for a given event
|
|
||||||
type and state key pair.)
|
|
||||||
|
|
||||||
Federation specific
|
|
||||||
-------------------
|
|
||||||
# *(Persistent data unit) PDU* -- An encoding of an event for distribution of
|
|
||||||
the server to server protocol.
|
|
||||||
|
|
||||||
# *(Ephemeral data unit) EDU* -- A piece of information that is sent between
|
|
||||||
servers and doesn't encode an event.
|
|
||||||
|
|
||||||
Client specific
|
|
||||||
---------------
|
|
||||||
# *Child events* -- Events that reference a single event in the same room
|
|
||||||
independently of the event graph.
|
|
||||||
|
|
||||||
# *Collapsed events* -- Events that have all child events that reference it
|
|
||||||
included in the JSON object.
|
|
|
@ -1,79 +0,0 @@
|
||||||
This document outlines the format for human-readable IDs within matrix.
|
|
||||||
|
|
||||||
Overview
|
|
||||||
--------
|
|
||||||
UTF-8 is quickly becoming the standard character encoding set on the web. As
|
|
||||||
such, Matrix requires that all strings MUST be encoded as UTF-8. However,
|
|
||||||
using Unicode as the character set for human-readable IDs is troublesome. There
|
|
||||||
are many different characters which appear identical to each other, but would
|
|
||||||
identify different users. In addition, there are non-printable characters which
|
|
||||||
cannot be rendered by the end-user. This opens up a security vulnerability with
|
|
||||||
phishing/spoofing of IDs, commonly known as a homograph attack.
|
|
||||||
|
|
||||||
Web browers encountered this problem when International Domain Names were
|
|
||||||
introduced. A variety of checks were put in place in order to protect users. If
|
|
||||||
an address failed the check, the raw punycode would be displayed to disambiguate
|
|
||||||
the address. Similar checks are performed by home servers in Matrix. However,
|
|
||||||
Matrix does not use punycode representations, and so does not show raw punycode
|
|
||||||
on a failed check. Instead, home servers must outright reject these misleading
|
|
||||||
IDs.
|
|
||||||
|
|
||||||
Types of human-readable IDs
|
|
||||||
---------------------------
|
|
||||||
There are two main human-readable IDs in question:
|
|
||||||
|
|
||||||
- Room aliases
|
|
||||||
- User IDs
|
|
||||||
|
|
||||||
Room aliases look like ``#localpart:domain``. These aliases point to opaque
|
|
||||||
non human-readable room IDs. These pointers can change, so there is already an
|
|
||||||
issue present with the same ID pointing to a different destination at a later
|
|
||||||
date.
|
|
||||||
|
|
||||||
User IDs look like ``@localpart:domain``. These represent actual end-users, and
|
|
||||||
unlike room aliases, there is no layer of indirection. This presents a much
|
|
||||||
greater concern with homograph attacks.
|
|
||||||
|
|
||||||
Checks
|
|
||||||
------
|
|
||||||
- Similar to web browsers.
|
|
||||||
- blacklisted chars (e.g. non-printable characters)
|
|
||||||
- mix of language sets from 'preferred' language not allowed.
|
|
||||||
- Language sets from CLDR dataset.
|
|
||||||
- Treated in segments (localpart, domain)
|
|
||||||
- Additional restrictions for ease of processing IDs.
|
|
||||||
- Room alias localparts MUST NOT have ``#`` or ``:``.
|
|
||||||
- User ID localparts MUST NOT have ``@`` or ``:``.
|
|
||||||
|
|
||||||
Rejecting
|
|
||||||
---------
|
|
||||||
- Home servers MUST reject room aliases which do not pass the check, both on
|
|
||||||
GETs and PUTs.
|
|
||||||
- Home servers MUST reject user ID localparts which do not pass the check, both
|
|
||||||
on creation and on events.
|
|
||||||
- Any home server whose domain does not pass this check, MUST use their punycode
|
|
||||||
domain name instead of the IDN, to prevent other home servers rejecting you.
|
|
||||||
- Error code is ``M_FAILED_HUMAN_ID_CHECK``. (generic enough for both failing
|
|
||||||
due to homograph attacks, and failing due to including ``:`` s, etc)
|
|
||||||
- Error message MAY go into further information about which characters were
|
|
||||||
rejected and why.
|
|
||||||
- Error message SHOULD contain a ``failed_keys`` key which contains an array
|
|
||||||
of strings which represent the keys which failed the check e.g::
|
|
||||||
|
|
||||||
failed_keys: [ user_id, room_alias ]
|
|
||||||
|
|
||||||
Other considerations
|
|
||||||
--------------------
|
|
||||||
- Basic security: Informational key on the event attached by HS to say "unsafe
|
|
||||||
ID". Problem: clients can just ignore it, and since it will appear only very
|
|
||||||
rarely, easy to forget when implementing clients.
|
|
||||||
- Moderate security: Requires client handshake. Forces clients to implement
|
|
||||||
a check, else they cannot communicate with the misleading ID. However, this is
|
|
||||||
extra overhead in both client implementations and round-trips.
|
|
||||||
- High security: Outright rejection of the ID at the point of creation /
|
|
||||||
receiving event. Point of creation rejection is preferable to avoid the ID
|
|
||||||
entering the system in the first place. However, malicious HSes can just allow
|
|
||||||
the ID. Hence, other home servers must reject them if they see them in events.
|
|
||||||
Client never sees the problem ID, provided the HS is correctly implemented.
|
|
||||||
- High security decided; client doesn't need to worry about it, no additional
|
|
||||||
protocol complexity aside from rejection of an event.
|
|
|
@ -1,43 +0,0 @@
|
||||||
===================
|
|
||||||
Documentation Style
|
|
||||||
===================
|
|
||||||
|
|
||||||
A brief single sentence to describe what this file contains; in this case a
|
|
||||||
description of the style to write documentation in.
|
|
||||||
|
|
||||||
|
|
||||||
Sections
|
|
||||||
========
|
|
||||||
|
|
||||||
Each section should be separated from the others by two blank lines. Headings
|
|
||||||
should be underlined using a row of equals signs (===). Paragraphs should be
|
|
||||||
separated by a single blank line, and wrap to no further than 80 columns.
|
|
||||||
|
|
||||||
[[TODO(username): if you want to leave some unanswered questions, notes for
|
|
||||||
further consideration, or other kinds of comment, use a TODO section. Make sure
|
|
||||||
to notate it with your name so we know who to ask about it!]]
|
|
||||||
|
|
||||||
Subsections
|
|
||||||
-----------
|
|
||||||
|
|
||||||
If required, subsections can use a row of dashes to underline their header. A
|
|
||||||
single blank line between subsections of a single section.
|
|
||||||
|
|
||||||
|
|
||||||
Bullet Lists
|
|
||||||
============
|
|
||||||
|
|
||||||
* Bullet lists can use asterisks with a single space either side.
|
|
||||||
|
|
||||||
* Another blank line between list elements.
|
|
||||||
|
|
||||||
|
|
||||||
Definition Lists
|
|
||||||
================
|
|
||||||
|
|
||||||
Terms:
|
|
||||||
Start in the first column, ending with a colon
|
|
||||||
|
|
||||||
Definitions:
|
|
||||||
Take a two space indent, following immediately from the term without a blank
|
|
||||||
line before it, but having a blank line afterwards.
|
|
|
@ -1,30 +0,0 @@
|
||||||
Matrix Specification NOTHAVEs
|
|
||||||
=============================
|
|
||||||
|
|
||||||
This document contains sections of the main specification that have been
|
|
||||||
temporarily removed, because they specify intentions or aspirations that have
|
|
||||||
in no way yet been implemented. Rather than outright-deleting them, they have
|
|
||||||
been moved here so as to stand as an initial version for such time as they
|
|
||||||
become extant.
|
|
||||||
|
|
||||||
|
|
||||||
Presence
|
|
||||||
========
|
|
||||||
|
|
||||||
Idle Time
|
|
||||||
---------
|
|
||||||
As well as the basic ``presence`` field, the presence information can also show
|
|
||||||
a sense of an "idle timer". This should be maintained individually by the
|
|
||||||
user's clients, and the home server can take the highest reported time as that
|
|
||||||
to report. When a user is offline, the home server can still report when the
|
|
||||||
user was last seen online.
|
|
||||||
|
|
||||||
Device Type
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Client devices that may limit the user experience somewhat (such as "mobile"
|
|
||||||
devices with limited ability to type on a real keyboard or read large amounts of
|
|
||||||
text) should report this to the home server, as this is also useful information
|
|
||||||
to report as "presence" if the user cannot be expected to provide a good typed
|
|
||||||
response to messages.
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,51 +0,0 @@
|
||||||
State Resolution
|
|
||||||
================
|
|
||||||
This section describes why we need state resolution and how it works.
|
|
||||||
|
|
||||||
|
|
||||||
Motivation
|
|
||||||
-----------
|
|
||||||
We want to be able to associate some shared state with rooms, e.g. a room name
|
|
||||||
or members list. This is done by having a current state dictionary that maps
|
|
||||||
from the pair event type and state key to an event.
|
|
||||||
|
|
||||||
However, since the servers involved in the room are distributed we need to be
|
|
||||||
able to handle the case when two (or more) servers try and update the state at
|
|
||||||
the same time. This is done via the state resolution algorithm.
|
|
||||||
|
|
||||||
|
|
||||||
State Tree
|
|
||||||
------------
|
|
||||||
State events contain a reference to the state it is trying to replace. These
|
|
||||||
relations form a tree where the current state is one of the leaf nodes.
|
|
||||||
|
|
||||||
Note that state events are events, and so are part of the PDU graph. Thus we
|
|
||||||
can be sure that (modulo the internet being particularly broken) we will see
|
|
||||||
all state events eventually.
|
|
||||||
|
|
||||||
|
|
||||||
Algorithm requirements
|
|
||||||
----------------------
|
|
||||||
We want the algorithm to have the following properties:
|
|
||||||
- Since we aren't guaranteed what order we receive state events in, except that
|
|
||||||
we see parents before children, the state resolution algorithm must not depend
|
|
||||||
on the order and must always come to the same result.
|
|
||||||
- If we receive a state event whose parent is the current state, then the
|
|
||||||
algorithm will select it.
|
|
||||||
- The algorithm does not depend on internal state, ensuring all servers should
|
|
||||||
come to the same decision.
|
|
||||||
|
|
||||||
These three properties mean it is enough to keep track of the current state and
|
|
||||||
compare it with any new proposed state, rather than having to keep track of all
|
|
||||||
the leafs of the tree and recomputing across the entire state tree.
|
|
||||||
|
|
||||||
|
|
||||||
Current Implementation
|
|
||||||
----------------------
|
|
||||||
The current implementation works as follows: Upon receipt of a newly proposed
|
|
||||||
state change we first find the common ancestor. Then we take the maximum
|
|
||||||
across each branch of the users' power levels, if one is higher then it is
|
|
||||||
selected as the current state. Otherwise, we check if one chain is longer than
|
|
||||||
the other, if so we choose that one. If that also fails, then we concatenate
|
|
||||||
all the pdu ids and take a SHA1 hash and compare them to select a common
|
|
||||||
ancestor.
|
|
4
setup.py
4
setup.py
|
@ -31,7 +31,7 @@ setup(
|
||||||
packages=find_packages(exclude=["tests"]),
|
packages=find_packages(exclude=["tests"]),
|
||||||
description="Reference Synapse Home Server",
|
description="Reference Synapse Home Server",
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"syutil==0.0.1",
|
"syutil==0.0.2",
|
||||||
"Twisted>=14.0.0",
|
"Twisted>=14.0.0",
|
||||||
"service_identity>=1.0.0",
|
"service_identity>=1.0.0",
|
||||||
"pyyaml",
|
"pyyaml",
|
||||||
|
@ -41,7 +41,7 @@ setup(
|
||||||
"py-bcrypt",
|
"py-bcrypt",
|
||||||
],
|
],
|
||||||
dependency_links=[
|
dependency_links=[
|
||||||
"git+ssh://git@github.com/matrix-org/syutil.git#egg=syutil-0.0.1",
|
"git+ssh://git@github.com/matrix-org/syutil.git#egg=syutil-0.0.2",
|
||||||
],
|
],
|
||||||
setup_requires=[
|
setup_requires=[
|
||||||
"setuptools_trial",
|
"setuptools_trial",
|
||||||
|
|
|
@ -16,4 +16,4 @@
|
||||||
""" This is a reference implementation of a synapse home server.
|
""" This is a reference implementation of a synapse home server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.3.4"
|
__version__ = "0.4.0"
|
||||||
|
|
|
@ -38,6 +38,7 @@ class Keyring(object):
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def verify_json_for_server(self, server_name, json_object):
|
def verify_json_for_server(self, server_name, json_object):
|
||||||
|
logger.debug("Verifying for %s", server_name)
|
||||||
key_ids = signature_ids(json_object, server_name)
|
key_ids = signature_ids(json_object, server_name)
|
||||||
if not key_ids:
|
if not key_ids:
|
||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
|
|
|
@ -238,6 +238,11 @@ class TransportLayer(object):
|
||||||
|
|
||||||
auth_headers = request.requestHeaders.getRawHeaders(b"Authorization")
|
auth_headers = request.requestHeaders.getRawHeaders(b"Authorization")
|
||||||
|
|
||||||
|
if not auth_headers:
|
||||||
|
raise SynapseError(
|
||||||
|
401, "Missing Authorization headers", Codes.UNAUTHORIZED,
|
||||||
|
)
|
||||||
|
|
||||||
for auth in auth_headers:
|
for auth in auth_headers:
|
||||||
if auth.startswith("X-Matrix"):
|
if auth.startswith("X-Matrix"):
|
||||||
(origin, key, sig) = parse_auth_header(auth)
|
(origin, key, sig) = parse_auth_header(auth)
|
||||||
|
@ -256,10 +261,14 @@ class TransportLayer(object):
|
||||||
def _with_authentication(self, handler):
|
def _with_authentication(self, handler):
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def new_handler(request, *args, **kwargs):
|
def new_handler(request, *args, **kwargs):
|
||||||
|
try:
|
||||||
(origin, content) = yield self._authenticate_request(request)
|
(origin, content) = yield self._authenticate_request(request)
|
||||||
response = yield handler(
|
response = yield handler(
|
||||||
origin, content, request.args, *args, **kwargs
|
origin, content, request.args, *args, **kwargs
|
||||||
)
|
)
|
||||||
|
except:
|
||||||
|
logger.exception("_authenticate_request failed")
|
||||||
|
raise
|
||||||
defer.returnValue(response)
|
defer.returnValue(response)
|
||||||
return new_handler
|
return new_handler
|
||||||
|
|
||||||
|
@ -392,9 +401,13 @@ class TransportLayer(object):
|
||||||
defer.returnValue((400, {"error": "Invalid transaction"}))
|
defer.returnValue((400, {"error": "Invalid transaction"}))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
code, response = yield self.received_handler.on_incoming_transaction(
|
code, response = yield self.received_handler.on_incoming_transaction(
|
||||||
transaction_data
|
transaction_data
|
||||||
)
|
)
|
||||||
|
except:
|
||||||
|
logger.exception("on_incoming_transaction failed")
|
||||||
|
raise
|
||||||
|
|
||||||
defer.returnValue((code, response))
|
defer.returnValue((code, response))
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ SCHEMAS = [
|
||||||
|
|
||||||
# Remember to update this number every time an incompatible change is made to
|
# Remember to update this number every time an incompatible change is made to
|
||||||
# database schema files, so the users will be informed on server restarts.
|
# database schema files, so the users will be informed on server restarts.
|
||||||
SCHEMA_VERSION = 5
|
SCHEMA_VERSION = 6
|
||||||
|
|
||||||
|
|
||||||
class _RollbackButIsFineException(Exception):
|
class _RollbackButIsFineException(Exception):
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* Copyright 2014 OpenMarket Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
CREATE TABLE IF NOT EXISTS server_tls_certificates(
|
||||||
|
server_name TEXT, -- Server name.
|
||||||
|
fingerprint TEXT, -- Certificate fingerprint.
|
||||||
|
from_server TEXT, -- Which key server the certificate was fetched from.
|
||||||
|
ts_added_ms INTEGER, -- When the certifcate was added.
|
||||||
|
tls_certificate BLOB, -- DER encoded x509 certificate.
|
||||||
|
CONSTRAINT uniqueness UNIQUE (server_name, fingerprint)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS server_signature_keys(
|
||||||
|
server_name TEXT, -- Server name.
|
||||||
|
key_id TEXT, -- Key version.
|
||||||
|
from_server TEXT, -- Which key server the key was fetched form.
|
||||||
|
ts_added_ms INTEGER, -- When the key was added.
|
||||||
|
verify_key BLOB, -- NACL verification key.
|
||||||
|
CONSTRAINT uniqueness UNIQUE (server_name, key_id)
|
||||||
|
);
|
Loading…
Reference in New Issue