Supporting-docs now in matrix.org repo.
This commit is contained in:
parent
17af66105d
commit
e7772af5c3
211 changed files with 3 additions and 6075 deletions
10
README.rst
10
README.rst
|
@ -1,9 +1,7 @@
|
|||
This repository contains the documentation for Matrix.
|
||||
This repository contains the Matrix specification.
|
||||
|
||||
Primarily, that means the Matrix protocol specifcation, but this repo also
|
||||
comtains a lot of supporting documents, including some introductions to Matrix,
|
||||
and, notably, a list of projects using Matrix which is visible on the
|
||||
`matrix.org website <https://matrix.org/docs/projects/try-matrix-now.html>`_.
|
||||
Note that the Matrix Project lists, which were previously kept in this
|
||||
repository, are now in https://github.com/matrix-org/matrix.org.
|
||||
|
||||
Structure of this repository
|
||||
============================
|
||||
|
@ -24,8 +22,6 @@ Structure of this repository
|
|||
- ``scripts``: scripts to generate formatted versions of the
|
||||
documentation, typically HTML.
|
||||
- ``specification``: the specification split up into sections.
|
||||
- ``supporting-docs``: additional documents which explain design
|
||||
decisions, examples, use cases, etc.
|
||||
- ``templating``: the templates and templating system used to
|
||||
generate the spec.
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@ mkdir -p assets
|
|||
# and the swagger
|
||||
./scripts/dump-swagger.py -o assets/spec/client_server/unstable.json
|
||||
|
||||
# also need the supporting-docs, which become the jekyll posts.
|
||||
cp -rT supporting-docs assets/jekyll-posts
|
||||
|
||||
# create a tarball of the assets. Exclude the spec index for now, as
|
||||
# we want to leave it pointing at the release versions of the specs.
|
||||
# (XXX: how to maintain this?)
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
Application Services
|
||||
====================
|
||||
|
||||
This file contains examples of some application service
|
||||
|
||||
IRC Bridge
|
||||
----------
|
||||
Pre-conditions:
|
||||
- Server admin stores the AS token "T_a" on the homeserver.
|
||||
- Homeserver has a token "T_h".
|
||||
- Homeserver has the domain "hsdomain.com"
|
||||
|
||||
1. Application service registration
|
||||
|
||||
::
|
||||
|
||||
AS -> HS: Registers itself with the homeserver
|
||||
POST /register
|
||||
{
|
||||
url: "https://someapp.com/matrix",
|
||||
as_token: "T_a",
|
||||
namespaces: {
|
||||
users: [
|
||||
{
|
||||
"exclusive": true,
|
||||
"regex": "@irc\.freenode\.net/.*"
|
||||
}
|
||||
],
|
||||
aliases: [
|
||||
{
|
||||
"exclusive": true,
|
||||
"regex": "#irc\.freenode\.net/.*"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Returns 200 OK:
|
||||
{
|
||||
hs_token: "T_h"
|
||||
}
|
||||
|
||||
2. IRC user "Bob" says "hello?" on "#matrix" at timestamp 1421416883133:
|
||||
|
||||
::
|
||||
|
||||
- AS stores message as potential scrollback.
|
||||
- Nothing happens as no Matrix users are in the room.
|
||||
|
||||
3. Matrix user "@alice:hsdomain.com" wants to join "#matrix":
|
||||
|
||||
::
|
||||
|
||||
User -> HS: Request to join "#irc.freenode.net/#matrix:hsdomain.com"
|
||||
|
||||
HS -> AS: Room Query "#irc.freenode.net/#matrix:hsdomain.com"
|
||||
GET /rooms/%23irc.freenode.net%2F%23matrix%3Ahsdomain.com?access_token=T_h
|
||||
[Starts blocking]
|
||||
AS -> HS: Creates room. Gets room ID "!aasaasasa:hsdomain.com".
|
||||
AS -> HS: Sets room name to "#matrix".
|
||||
AS -> HS: Sends message as ""@irc.freenode.net/Bob:hsdomain.com"
|
||||
PUT /rooms/%21aasaasasa%3Ahsdomain.com/send/m.room.message
|
||||
?access_token=T_a
|
||||
&user_id=%40irc.freenode.net%2FBob%3Ahsdomain.com
|
||||
&ts=1421416883133
|
||||
{
|
||||
body: "hello?"
|
||||
msgtype: "m.text"
|
||||
}
|
||||
HS -> AS: User Query "@irc.freenode.net/Bob:hsdomain.com"
|
||||
GET /users/%40irc.freenode.net%2FBob%3Ahsdomain.com?access_token=T_h
|
||||
[Starts blocking]
|
||||
AS -> HS: Creates user using CS API extension.
|
||||
POST /register?access_token=T_a
|
||||
{
|
||||
type: "m.login.application_service",
|
||||
user: "irc.freenode.net/Bob"
|
||||
}
|
||||
AS -> HS: Set user display name to "Bob".
|
||||
[Finishes blocking]
|
||||
[Finished blocking]
|
||||
|
||||
- HS sends room information back to client.
|
||||
|
||||
4. @alice:hsdomain.com says "hi!" in this room:
|
||||
|
||||
::
|
||||
|
||||
User -> HS: Send message "hi!" in room !aasaasasa:hsdomain.com
|
||||
|
||||
- HS sends message.
|
||||
- HS sees the room ID is in the AS namespace and pushes it to the AS.
|
||||
|
||||
HS -> AS: Push event
|
||||
PUT /transactions/1?access_token=T_h
|
||||
{
|
||||
events: [
|
||||
{
|
||||
content: {
|
||||
body: "hi!",
|
||||
msgtype: "m.text"
|
||||
},
|
||||
origin_server_ts: <generated by hs>,
|
||||
user_id: "@alice:hsdomain.com",
|
||||
room_id: "!aasaasasa:hsdomain.com",
|
||||
type: "m.room.message"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
- AS passes this through to IRC.
|
||||
|
||||
|
||||
5. IRC user "Bob" says "what's up?" on "#matrix" at timestamp 1421418084816:
|
||||
|
||||
::
|
||||
|
||||
IRC -> AS: "what's up?"
|
||||
AS -> HS: Send message via CS API extension
|
||||
PUT /rooms/%21aasaasasa%3Ahsdomain.com/send/m.room.message
|
||||
?access_token=T_a
|
||||
&user_id=%40irc.freenode.net%2FBob%3Ahsdomain.com
|
||||
&ts=1421418084816
|
||||
{
|
||||
body: "what's up?"
|
||||
msgtype: "m.text"
|
||||
}
|
||||
|
||||
- HS modifies the user_id and origin_server_ts on the event and sends it.
|
|
@ -1,141 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
title: Getting involved
|
||||
categories: guides
|
||||
---
|
||||
|
||||
# How can I get involved?
|
||||
Matrix is an ecosystem consisting of several apps written by lots of people. We at Matrix.org have written one server and a few clients, and people in the community have also written several clients, servers, and Application Services. We are collecting [a list of all known Matrix-apps](https://matrix.org/blog/try-matrix-now/).
|
||||
|
||||
|
|
||||
|
||||
You have a few options when it comes to getting involved: if you just want to use Matrix, you can [register an account on a public server using a public webclient](#reg). If you have a virtual private server (VPS) or similar, you might want to [run a server and/or client yourself](#run). If you want to look under the hood, you can [checkout the code and modify it - or write your own client or server](#checkout). Or you can write an [Application Service](#as), for example a bridge to an existing ecosystem.
|
||||
|
||||
|
|
||||
|
||||
We very much welcome [contributions](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.rst) to any of our projects, which you can find in our [github space](https://github.com/matrix-org/).
|
||||
|
||||
|
|
||||
|
||||
<a class="anchor" id="reg"></a>
|
||||
|
||||
## Access Matrix via a public webclient/server
|
||||
|
||||
The easiest thing to do if you want to just have a play, is to use the [Riot.im
|
||||
webclient](https://riot.im). You can use it as a guest, or register for an
|
||||
account. For details of other clients, see
|
||||
[https://matrix.org/blog/try-matrix-now](https://matrix.org/blog/try-matrix-now).
|
||||
|
||||
<a class="anchor" id="run"></a>
|
||||
|
||||
## Run a server and/or client yourself
|
||||
|
||||
You can clone our open source projects and run clients and servers yourself. Here is how:
|
||||
|
||||
### Running your own client:
|
||||
|
||||
You can run your own Matrix client; there are [numerous clients
|
||||
available](https://matrix.org/blog/try-matrix-now/). You can easily [run your
|
||||
own copy](https://github.com/vector-im/vector-web#getting-started) of the
|
||||
Riot.im web client.
|
||||
|
||||
### Running your own homeserver:
|
||||
|
||||
One of the core features of Matrix is that anyone can run a homeserver and join the federated network on equal terms (there is no hierarchy). If you want to set up your own homeserver, please see the relevant docs of the server you want to run. If you want to run Matrix.org's reference homeserver, please consult the [readme of the Synapse project](https://github.com/matrix-org/synapse/blob/master/README.rst).
|
||||
|
||||
|
|
||||
|
||||
Note that Synapse comes with a bundled Matrix.org webclient - but you can tell it to use your [development checkout snapshot instead](https://github.com/matrix-org/matrix-angular-sdk#matrix-angular-sdk) (or to not run a webclient at all via the "web_client: false" config option).
|
||||
|
||||
|
|
||||
|
||||
<a class="anchor" id="checkout"></a>
|
||||
|
||||
## Checkout our code - or write your own
|
||||
|
||||
As described above, you can clone our code and [run a server and/or client yourself](#run). Infact, all the code that we at Matrix.org write is available from [our github](http://github.com/matrix-org) - and other servers and clients may also be open sourced - see [our list of all known Matrix-apps](https://matrix.org/blog/try-matrix-now/).
|
||||
|
||||
|
|
||||
|
||||
You can also implement your own client or server - after all, Matrix is at its core "just" a specification of a protocol.
|
||||
|
||||
|
|
||||
|
||||
### Write your own client:
|
||||
|
||||
The [client-server API
|
||||
spec](http://matrix.org/docs/spec/client_server/latest.html) describes what API
|
||||
calls are available to clients, and there is a [HOWTO
|
||||
guide](http://matrix.org/docs/guides/client-server.html) which provides an
|
||||
introduction to using the API along with some common operations. A quick
|
||||
step-by-step guide would include:
|
||||
|
||||
|
|
||||
|
||||
1. Get a user either by registering your user in an existing client or running the [new-user script](https://github.com/matrix-org/synapse/blob/master/scripts/register_new_matrix_user) if you are running your own Synapse homeserver.
|
||||
|
||||
2. Assuming the homeserver you are using allows logins by password, log in via the login API:
|
||||
|
||||
```
|
||||
curl -XPOST -d '{"type":"m.login.password", "user":"example", "password":"wordpass"}' "http://localhost:8008/_matrix/client/api/v1/login"
|
||||
```
|
||||
|
||||
3. If successful, this returns the following, including an `access_token`:
|
||||
|
||||
{
|
||||
"access_token": "QGV4YW1wbGU6bG9jYWxob3N0.vRDLTgxefmKWQEtgGd",
|
||||
"home_server": "localhost",
|
||||
"user_id": "@example:localhost"
|
||||
}
|
||||
|
||||
4. This ``access_token`` will be used for authentication for the rest of your API calls. Potentially the next step you want is to make a call to the sync API and get the last few events from each room your user is in:
|
||||
|
||||
```
|
||||
curl -XGET "http://localhost:8008/_matrix/client/r0/sync?access_token=YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
5. The above will return something like this:
|
||||
|
||||
{
|
||||
"next_batch": "s72595_4483_1934",
|
||||
"rooms": {
|
||||
"join": {
|
||||
"!726s6s6q:example.com": {
|
||||
"state": {
|
||||
"events": [
|
||||
...
|
||||
]
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
...
|
||||
]
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
You can then use the "next_batch" token to start listening for new events like so:
|
||||
|
||||
```
|
||||
curl -XGET "http://localhost:8008/_matrix/client/r0/sync?access_token=YOUR_ACCESS_TOKEN&since=s72595_4483_1934"
|
||||
```
|
||||
|
||||
6. This request will block waiting for an incoming event, timing out after several seconds if there is no event. This ensures that you only get new events. Now you have the initial room states, and a stream of events - a good client should be able to process all these events and present them to the user. And potentially you might want to add functionality to generate events as well (such as messages from the user, for example)!
|
||||
|
||||
### Write your own server:
|
||||
|
||||
We are still working on the server-server spec, so the best thing to do if you are interested in writing a server, is to come talk to us in [#matrix:matrix.org](https://matrix.to/#/#matrix:matrix.org).
|
||||
|
||||
If you are interested in how federation works, please see the [Server-Server API spec](http://matrix.org/docs/spec/server_server/unstable.html).
|
||||
|
||||
|
|
||||
|
||||
<a class="anchor" id="as"></a>
|
||||
|
||||
## Write an Application Service:
|
||||
|
||||
Information about Application services and how they can be used can be found in the [Application services](./application_services.html) document! (This is based on Kegan's excellent blog posts, but now lives here so it can be kept up-to-date!)
|
|
@ -1,691 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
title: FAQ
|
||||
date: 2015-08-19 16:58:07
|
||||
categories: guides
|
||||
---
|
||||
<link href="/docs/css/faq.css" type="text/css" rel="stylesheet" />
|
||||
|
||||
# FAQ
|
||||
{:.no_toc}
|
||||
|
||||
Categories
|
||||
----------
|
||||
{:.no_toc}
|
||||
|
||||
[General](#general)
|
||||
|
||||
[Quick Start](#quick-start)
|
||||
|
||||
[Standard](#standard)
|
||||
|
||||
[Servers](#servers)
|
||||
|
||||
[Clients](#clients)
|
||||
|
||||
|
|
||||
|
||||
FAQ Content
|
||||
-----------
|
||||
{:.no_toc}
|
||||
|
||||
|
||||
* TOC
|
||||
{:toc .toc}
|
||||
|
||||
### General
|
||||
|
||||
##### What is Matrix?
|
||||
|
||||
Matrix is an open standard for interoperable, decentralised,
|
||||
real-time communication over IP. It can be used to power Instant
|
||||
Messaging, VoIP/WebRTC signalling, Internet of Things communication - or anywhere
|
||||
you need a standard HTTP API for publishing and subscribing to
|
||||
data whilst tracking the conversation history.
|
||||
|
||||
|
|
||||
|
||||
Matrix defines the standard, and provides open source reference implementations
|
||||
of Matrix-compatible Servers, Clients, Client SDKs and Application Services
|
||||
to help you create new communication solutions or extend the capabilities
|
||||
and reach of existing ones.
|
||||
|
||||
##### What is Matrix's Mission?
|
||||
|
||||
Matrix's initial goal is to fix the problem of fragmented IP communications:
|
||||
letting users message and call each other without having to care what app
|
||||
the other user is on - making it as easy as sending an email.
|
||||
|
||||
|
|
||||
|
||||
The longer term goal is for Matrix to act as a generic HTTP messaging and data
|
||||
synchronisation system for the whole web - allowing people, services and devices
|
||||
to easily communicate with each other, empowering users to own and control their
|
||||
data and select the services and vendors they want to use.
|
||||
|
||||
##### What does Matrix provide?
|
||||
|
||||
Matrix provides:
|
||||
|
||||
- [Open Standard](/docs/spec) HTTP APIs for transferring JSON messages (e.g. instant messages, WebRTC signalling), including:
|
||||
- [Client\<-\>Server API](/docs/spec#client-server-api-v1) - defines how Matrix compatible clients communicate with Matrix homeservers.
|
||||
- [Server\<-\>Server API](/docs/spec#federation-api) - defines how Matrix homeservers exchange messages and synchronise history with each other.
|
||||
- [Application Service API](/docs/spec/#application-service-api) - defines how to extend the functionality of Matrix with 'integrations' and bridge to other networks.
|
||||
- [Modules](/docs/spec/#modules) - specifies features that must be implemented by particular classes of clients.
|
||||
- Open source reference implementations of:
|
||||
- Clients (Web (React), iOS, Android)
|
||||
- Client SDKs (Javascript, Web (React), iOS, Android)
|
||||
- Homeservers (Synapse)
|
||||
- Application Services (bridges to IRC, Slack, Skype, Lync and more...)
|
||||
- The actual ecosystem and community of everyone running Matrix servers and services
|
||||
- Loads of 3rd party contributions of clients, SDKs, servers and services.
|
||||
|
||||
You can find the full list of Matrix enabled projects at [https://matrix.org/blog/try-matrix-now](https://matrix.org/blog/try-matrix-now).
|
||||
|
||||
##### What does this mean for users?
|
||||
|
||||
The aim is to provide an analogous ecosystem to email - one where you
|
||||
can communicate with pretty much anyone, without caring what app or
|
||||
server they are using, using whichever app & server you chose to use,
|
||||
and use a neutral identity system like an e-mail address or phone
|
||||
number to discover people to talk to.
|
||||
|
||||
##### What kind of company is Matrix.org?
|
||||
|
||||
Matrix.org is an open initiative which acts as a neutral and independent custodian
|
||||
of the Matrix standard. As of Sept 2017 we are finally in the process of incorporating
|
||||
it as a dedicated non-profit entity (most likely a limited by guarantee UK private company
|
||||
called the Matrix.org Foundation).
|
||||
|
||||
##### Who is funding Matrix.org?
|
||||
|
||||
Matrix.org is currently (Sept 2017) funded by the community, through a
|
||||
combination of community support (via
|
||||
[Patreon](https://patreon.com/matrixdotorg),
|
||||
[Liberapay](https://liberapay.com/matrixdotorg), Bitcoin and Ethereum),
|
||||
corporate sponsorship, and grant funding. Current Elliptic-level supporters on
|
||||
Patreon and corporate sponsors can be found on our [supporters
|
||||
page](https://matrix.org/blog/supporters). If you would like to support the core
|
||||
Matrix team as a member of the community, please visit our
|
||||
[Patreon](https://patreon.com/matrixdotorg) or
|
||||
[Liberapay](https://liberapay.com/matrixdotorg) pages, or you can send us
|
||||
Bitcoin at 1LxowEgsquZ3UPZ68wHf8v2MDZw82dVmAE or Ethereum at ETH
|
||||
0xA5f9a4f9E024F6D727f7afdA9257e22329A97485. If you would like to sponsor the
|
||||
team as a corporation, or are interested in paying for prioritised or custom
|
||||
development, please [get in touch](mailto:matthew@matrix.org).
|
||||
|
||||
For the first three years of Matrix's development (2014-2017), most of the core
|
||||
contributors worked for [Amdocs](https://www.amdocs.com), who paid for them to
|
||||
work fulltime on Matrix. In July 2017, Amdocs considered the project to be
|
||||
sufficiently successful that it could now self-support and so stopped funding.
|
||||
The majority of the core team is now employed by New Vector, an independent company
|
||||
set up to hire the team and support Matrix's development. Other contributors
|
||||
are funded by their own employers or donate their own time to the project.
|
||||
|
||||
##### Who is building Matrix?
|
||||
|
||||
The core team is ~12 people with extensive experience in building custom
|
||||
VoIP and Messaging apps for mobile network operators. Most of us work for New Vector,
|
||||
but there are an increasing number of contributors from other companies and
|
||||
folks all over the internet.
|
||||
|
||||
##### Why are you called Matrix?
|
||||
|
||||
We are called Matrix because we provide a structure in which all
|
||||
communication can be matrixed together.
|
||||
|
||||
|
|
||||
|
||||
No, it's nothing to do with the film (although you could go and build virtual
|
||||
worlds on top of Matrix if you wanted :)
|
||||
|
||||
##### Why have you released this as open source?
|
||||
|
||||
We believe that any open standard defining interoperable communication
|
||||
needs to be justified, demonstrated and validated with transparent open
|
||||
source implementations. For Matrix to achieve its mission of making all
|
||||
communications services interoperable we believe it needs to be truly
|
||||
open, giving people access to take all the code we produce and to use
|
||||
and build on top of it.
|
||||
|
||||
##### What do you mean by open?
|
||||
|
||||
Matrix is an open standard, meaning that we have freely published the
|
||||
details for how to communicate interoperably using the Matrix set of
|
||||
HTTP APIs. We encourage anyone and everyone to use the APIs and build
|
||||
their own projects which implement them and so benefit from
|
||||
interoperability with the rest of the Matrix ecosystem. We also
|
||||
ensure the standard is not encumbered by any known patent licensing
|
||||
requirements.
|
||||
|
||||
|
|
||||
|
||||
Matrix is also open source, meaning that we have released the source
|
||||
code of the reference servers, clients and services to the public domain
|
||||
under the [Apache Licence v2](http://www.apache.org/licenses/LICENSE-2.0.html), to
|
||||
encourage anyone and everyone to run their own servers and clients, and
|
||||
enhance them and contribute their enhancements as they see fit.
|
||||
|
||||
##### What does federated mean?
|
||||
|
||||
Federation allows separate deployments of a communication service to
|
||||
communicate with each other - for instance a mail server run by Google
|
||||
federates with a mail server run by Microsoft when you send email from
|
||||
@gmail.com to @hotmail.com.
|
||||
|
||||
|
|
||||
|
||||
Federation is different to interoperability, as interoperable clients
|
||||
may simply be running on the same deployment - whereas in federation the
|
||||
deployments themselves are exchanging data in a compatible manner.
|
||||
|
||||
|
|
||||
|
||||
Matrix provides open federation - meaning that anyone on the internet
|
||||
can join into the Matrix ecosystem by deploying their own server.
|
||||
|
||||
##### How is this like e-mail?
|
||||
|
||||
When email was first set up in the early ‘80s, companies like Compuserve
|
||||
and AT&T and Sprint set up isolated email communities which only allowed
|
||||
you to exchange mail with users on the same system. If you got your
|
||||
email from one service and your friend from another, then you couldn't
|
||||
message each other. This is basically the situation we're in today with
|
||||
VoIP and IM.
|
||||
|
||||
##### Why has no-one done this before?
|
||||
|
||||
There have been several attempts before including SIP, XMPP and RCS.
|
||||
All of these have had some level of success, but many different
|
||||
technological/usability/economic factors have ended up limiting their
|
||||
success. Unfortunately, we've not ended up in a world where everyone
|
||||
has a SIP URI or Jabber ID on their business card, or a phone that
|
||||
actually uses RCS.
|
||||
|
||||
##### What is the difference between Matrix and IRC?
|
||||
|
||||
We love IRC. In fact, as of today the core Matrix team still uses it as
|
||||
our primary communication tool. Between us we've written IRCds, IRC bots
|
||||
and admined dreamforge, UnrealIRCd, epona, ircservices and several
|
||||
others. That said, it has some limitations that Matrix seeks to improve
|
||||
on:
|
||||
|
||||
- Text only
|
||||
- No history
|
||||
- No multiple-device support
|
||||
- No presence support
|
||||
- Fragmented identity model
|
||||
- No open federation
|
||||
- No standard APIs, just a rather limited TCP line protocol
|
||||
- Non-standardised federation protocol
|
||||
- No built-in end-to-end encryption
|
||||
- Disruptive net-splits
|
||||
- Non-extensible
|
||||
|
||||
[IRCv3](http://ircv3.net) exists and is addressing some of these issues;
|
||||
this is great news and we wish them well. It's almost a contradiction
|
||||
in terms to get competitive between openly interoperable communication
|
||||
projects - we look forward to increasing the richness of Matrix\<-\>IRC
|
||||
bridges as the project progresses.
|
||||
|
||||
##### What is the difference between Matrix and XMPP?
|
||||
|
||||
The Matrix team used XMPP (Openfire, ejabberd, spectrum, asmack,
|
||||
XMPPFramework) for IM before starting to experiment with open HTTP APIs
|
||||
as an alternative in around 2012. The main issues with XMPP that
|
||||
drove us in this direction **as of 2012** were:
|
||||
|
||||
- Not particularly web-friendly - you can't easily speak XMPP from a
|
||||
web browser. *N.B. Nowadays you have options like XMPP-FTW and
|
||||
Stanza.io that help loads with letting browsers talk XMPP*
|
||||
- Single logical server per MUC is a single point of control and
|
||||
availability. *MUCs can be distributed over multiple physical
|
||||
servers, but they still sit behind a single logical JID and domain.
|
||||
FMUC improves this with a similar approach to Matrix, but as of Oct
|
||||
2015 there are no open source implementations. The MIX XMPP extension
|
||||
also aims to address this limitation*.
|
||||
- History synchronisation is very much a second class citizen feature
|
||||
- Bridging to other protocols and defragmenting existing communication
|
||||
apps and networks is very much a second class citizen feature
|
||||
- Stanzas aren't framed or reliably delivered without extensions. *See
|
||||
[wiki.xmpp.org](http://wiki.xmpp.org/web/Myths#Myth_Four:_XMPP_is_unreliable_without_a_bunch_of_extensions.)
|
||||
for an XMPP take on this*
|
||||
- Multiple device support is limited. *Carbons and MAM aim to resolve this*
|
||||
- Baseline feature set is so minimal that fragmentation of features
|
||||
between clients and servers is common, especially as interoperability
|
||||
profiles for features have fallen behind (as of July 2015)
|
||||
- No strong identity system (i.e. no standard E2E PKI, unless you
|
||||
count X.509 certs, which [are
|
||||
questionable](http://www.thoughtcrime.org/blog/ssl-and-the-future-of-authenticity/))
|
||||
- Not particularly well designed for mobile use cases: push;
|
||||
bandwidth-efficient transports. *Since the time of writing a [Push
|
||||
XEP has appeared](http://xmpp.org/extensions/xep-0357.html), and
|
||||
[wiki.xmpp.org](http://wiki.xmpp.org/web/Myths#Myth_Three:_It.27s_too_bandwidth-inefficient_for_mobile.)
|
||||
states that XMPP is usable over a 9600bps + 30s latency link.*
|
||||
|
||||
This said, the whole area of XMPP vs Matrix is quite subjective.
|
||||
Rather than fighting over which open interoperable communication
|
||||
standard works the best, we should just collaborate and bridge everything
|
||||
together. The more federation and interoperability the better.
|
||||
|
||||
|
|
||||
|
||||
We think of Matrix and XMPP as being quite different; at its core
|
||||
Matrix can be thought of as an eventually consistent global JSON db with
|
||||
an HTTP API and pubsub semantics - whilst XMPP can be thought of as a
|
||||
message passing protocol. You can use them both to build chat systems;
|
||||
you can use them both to build pubsub systems; each comes with different
|
||||
tradeoffs. Matrix has a deliberately extensive 'kitchen sink' baseline
|
||||
of functionality; XMPP has a deliberately minimal baseline set of
|
||||
functionality. If XMPP does what you need it to do, then we're genuinely
|
||||
happy for you :) Meanwhile, rather than competing, an XMPP Bridge like
|
||||
[Skaverat's xmpptrix beta](https://github.com/SkaveRat/xmpptrix) or
|
||||
[jfred's matrix-xmpp-bridge](https://github.com/jfrederickson/matrix-xmpp-bridge)
|
||||
or Matrix.org's own [purple-matrix](https://github.com/matrix-org/purple-matrix/)
|
||||
has potential to let both environments coexist and make the most of each
|
||||
other's benefits.
|
||||
|
||||
##### What is the difference between Matrix and PSYC?
|
||||
|
||||
PSYC is a open federated messaging protocol loosely inspired by IRC. In
|
||||
version 1 it was a standalone protocol, and in version 2 it is being
|
||||
reutilised as a messaging layer on top of GNUnet. We honestly don't
|
||||
know that much about it, beyond trying to use psycd as an XMPP\<-\>IRC
|
||||
bridge in 2010. Matrix differentiates primarily by providing simple HTTP
|
||||
APIs rather than the more exotic compact line protocol in PSYC v1 or the
|
||||
comprehensive GNUnet stack in v2, and Matrix focuses more on decentralised
|
||||
conversation history rather than just decentralised chat servers.
|
||||
On the other hand, Matrix doesn't provide the metadata protection
|
||||
guarantees that GNUnet/PSYC aims for.
|
||||
|
||||
|
|
||||
|
||||
See [http://about.psyc.eu/Matrix](http://about.psyc.eu/Matrix) for
|
||||
PSYC's views on Matrix.
|
||||
|
||||
##### What is the difference between Matrix and Tox?
|
||||
|
||||
Tox.chat looks to be a very cool clone of Skype - a fully decentralised
|
||||
peer-to-peer network. Matrix is deliberately not a 'pure' peer-to-peer
|
||||
system; instead each user has a well-defined homeserver which stores
|
||||
his data and that he can depend upon. Matrix provides HTTP APIs;
|
||||
Tox.chat provides C APIs. As of October 2015 Tox doesn't seem to have an
|
||||
answer yet for decentralised conversation history storage.
|
||||
|
||||
##### How does Matrix compare with something like Trillian or Pidgin?
|
||||
|
||||
Trillian and Pidgin and similar aggregating IM clients merge all your IM
|
||||
activity into a single app. However, your history and
|
||||
identity is still fragmented across the networks. People can't find you
|
||||
easily, and your history is fragmented (other than on the device
|
||||
where the client runs). And rather than being able to chose the right
|
||||
app for the job when communicating with people, you are pushed towards
|
||||
relying on a specific aggregation app.
|
||||
|
||||
Matrix lets you get the best of both worlds by linking to all the
|
||||
different networks (XMPP, AIM, ICQ, Lync, Skype etc) on the serverside,
|
||||
using bridges which can be run by anyone. Matrix then provides a simple
|
||||
standard HTTP API to access any of these networks, and lets you choose
|
||||
whichever client you prefer (either as a 'native' Matrix client or using
|
||||
a non-Matrix client from one of the networks which has been bridged in).
|
||||
|
||||
##### What Matrix compliant apps are there?
|
||||
|
||||
Quite a few, ranging from the glossy mass-market to the geeky command-line. There's even an emacs macro. Check out [https://matrix.org/blog/try-matrix-now](https://matrix.org/blog/try-matrix-now) for the current
|
||||
list of Matrix enabled projects.
|
||||
|
||||
##### What bridges to other networks are available?
|
||||
|
||||
The number of 'bridges' which integrate existing communication networks into
|
||||
Matrix are growing on a daily basis - both written by the Matrix core team
|
||||
and contributed by the wider community. The full list can be seen at
|
||||
[https://matrix.org/blog/try-matrix-now](https://matrix.org/blog/try-matrix-now), but the core ones as of Oct 2015 include:
|
||||
|
||||
* [matrix-appservice-irc](https://github.com/matrix-org/matrix-appservice-irc) - an increasingly comprehensive Matrix\<-\>IRC bridge
|
||||
* [matrix-appservice-verto](https://github.com/matrix-org/matrix-appservice-verto) - links from Matrix to FreeSWITCH via the Verto protocol
|
||||
* [matrix-appservice-slack](https://github.com/matrix-org/matrix-appservice-slack) - a basic bridge to Slack
|
||||
* [node-purple](https://github.com/matrix-org/node-purple) - lets you access any of the 20+ protocols supported by
|
||||
[libpurple](https://developer.pidgin.im/wiki/WhatIsLibpurple), including
|
||||
Skype, Lync, XMPP, etc)
|
||||
* [matrix-appservice-bridge](https://github.com/matrix-org/matrix-appservice-bridge) - a general NodeJS framework for writing bridges
|
||||
|
||||
Writing new bridges is incredibly fun and easy - see the [matrix-appservice-bridge HOWTO](https://github.com/matrix-org/matrix-appservice-bridge/blob/master/HOWTO.md)
|
||||
for an example of how to write a fully functional Slack bridge in less than 100 lines of code!
|
||||
|
||||
##### Why do you think existing apps will ever join this officially?
|
||||
|
||||
We firmly believe it is what is right for the consumer. As people begin
|
||||
to use interoperable communications tools, service providers will see the
|
||||
benefit and compete on quality of service, security and features rather
|
||||
than relying on locking people into their walled garden. We believe as
|
||||
soon as users see the availability and benefits of interoperable
|
||||
services they will demand it.
|
||||
|
||||
##### Why aren't you doing this through the IETF? or W3C? or 3GPP?
|
||||
|
||||
We do recognise the advantages of working with existing standards
|
||||
bodies. We have been focused on writing code and getting it out, and the standard has been evolving rapidly since initial release in September 2014.
|
||||
Once the standard has matured sufficiently it may well be appropriate to work with an official
|
||||
standard body to maintain it going forwards.
|
||||
|
||||
### Quick Start
|
||||
|
||||
##### How do I get an account and get started?
|
||||
|
||||
The quickest way is to pick a client from [https://matrix.org/blog/try-matrix-now](https://matrix.org/blog/try-matrix-now) and sign up.
|
||||
Please note that you can point clients to access any homeserver - you don't have to use matrix.org,
|
||||
although as of day 1, matrix.org is the only communal homeserver
|
||||
available.
|
||||
|
||||
##### What can I actually do with this?
|
||||
|
||||
A typical client provides a simple chatroom interface to Matrix -
|
||||
letting the user interact with users and rooms anywhere within the
|
||||
Matrix federation. Text and image messages are supported, and basic
|
||||
voice-only VoIP calling via WebRTC is supported in one-to-one rooms.
|
||||
(As of October 2015, experimental multi-way calling is also available
|
||||
on Riot.im).
|
||||
|
||||
##### How do I connect my homeserver to the public Matrix network?
|
||||
|
||||
See
|
||||
[http://github.com/matrix-org/synapse](http://github.com/matrix-org/synapse)
|
||||
for details
|
||||
|
||||
##### How do I Matrix-enable my existing app?
|
||||
|
||||
If your app doesn't have any communication capability already, you'll want
|
||||
to use one of the Matrix client SDKs to add it in. These come in different
|
||||
levels of sophistication - ranging from a simple HTTP API wrapper (like matrix-js-sdk, matrix-ios-sdk or matrix-android-sdk)
|
||||
through to reusable UI components (like matrix-react-sdk and matrix-ios-kit). Pick
|
||||
the one for your platform, or a 3rd party one if none of the above work for you,
|
||||
and get plugging it in. You'll probably also want to read the [Client-Server API
|
||||
HOWTO](http://matrix.org/docs/howtos/client-server.html) too.
|
||||
|
||||
If you already have communication infrastructure set up (XMPP, custom HTTP, or whatever),
|
||||
then you'll want to run a bridge to expose it to the wider Matrix ecosystem.
|
||||
See [matrix-appservice-bridge HOWTO](https://github.com/matrix-org/matrix-appservice-bridge/blob/master/HOWTO.md) for a
|
||||
guide of how to write bridges using the matrix-appservice-bridge framework, or co-opt one
|
||||
from the list at [https://matrix.org/blog/try-matrix-now](https://matrix.org/blog/try-matrix-now).
|
||||
[Application Service API](/docs/spec/#application-service-api) gives the details of the API
|
||||
that bridges have to implement.
|
||||
|
||||
##### How can I write a client on Matrix?
|
||||
|
||||
See the [Client-Server API
|
||||
HOWTO](http://matrix.org/docs/howtos/client-server.html) and the [API
|
||||
docs](/docs/api) and [the Spec](/docs/spec) for all the details you need
|
||||
to write a client.
|
||||
|
||||
##### How can I help out with this?
|
||||
|
||||
Come say hi on [\#matrix:matrix.org](https://matrix.to/#/#matrix:matrix.org)! Install synapse and tell us how you get on. Critique the spec. Write
|
||||
clients. Write bridges! Run bridges! Nose around in [Jira](https://matrix.org/jira) and
|
||||
send us some pull requests on github to fix some bugs or add some features! You could even
|
||||
try to write a homeserver (but be warned, Matrix's architecture makes homeservers orders of
|
||||
magnitude harder than clients or bridges.)
|
||||
|
||||
See [CONTRIBUTING.rst](http://github.com/matrix-org/synapse/tree/master/CONTRIBUTING.rst) for
|
||||
full details on how to contribute to the project. All are welcome!
|
||||
|
||||
##### Where can I get support?
|
||||
|
||||
[\#matrix:matrix.org](https://matrix.to/#/#matrix:matrix.org) aka \#matrix on irc.freenode.is your best bet.
|
||||
|
||||
##### How do I register custom matrix event types?
|
||||
|
||||
We're not yet managing a registry of custom matrix event types. If you
|
||||
have any particularly good ones you want to tell the world about, please
|
||||
let us know on #matrix-dev:matrix.org.
|
||||
|
||||
##### How mature is this?
|
||||
|
||||
We started working on Matrix in July 2014, and opened it to the
|
||||
public in September 2014. We got all the core features in place in December 2014
|
||||
and entered beta, and since then have been iterating away on the beta refining the
|
||||
architecture and APIs, fixing bugs and scalability, and adding new features, clients,
|
||||
bridges etc.
|
||||
|
||||
As of October 2015 (synapse 0.10) it's good for serious experimentation and
|
||||
non-production services and can absolutely be used in the real world. However, we're
|
||||
still in beta and we'll want to freeze the spec and implement clustering and other
|
||||
nice features before we really declare it ready for production.
|
||||
|
||||
### Standard
|
||||
|
||||
##### What is a client?
|
||||
|
||||
Users in Matrix use one or more clients to communicate. This could be any combination of a web client, a command line client, a mobile client - or embedded clients built into existing apps. It could even be a piece of hardware (e.g. a drone) that is Matrix enabled.
|
||||
|
||||
##### Can I use Matrix without installing a Matrix client?
|
||||
|
||||
Sure. An ever increasing number of protocols are being bridged into Matrix, so if you use something like IRC on Freenode you may well be indirectly benefiting from Matrix, as others may be connected into the IRC channel via Matrix.
|
||||
|
||||
##### What is a home server?
|
||||
|
||||
A user's clients connect to a single homeserver, which stores the communication history and account information for that user, and shares data with the wider Matrix ecosystem by synchronising communication history with other homeservers.
|
||||
|
||||
##### What is a MXID?
|
||||
|
||||
Matrix user IDs (MXID) are unique user IDs. They are in the format ```@username:homeserver.tld``` (this format is used to avoid confusing them with email addresses). They are intended to be fairly hidden (although right now they are not) - instead you will find and identify other users via 3PIDs.
|
||||
|
||||
##### What is a 3PID?
|
||||
|
||||
Third-party IDs (3PIDs) are IDs from other systems or contexts, such as email addresses, social network accounts and phone numbers.
|
||||
|
||||
##### What is an identity server?
|
||||
|
||||
Users in Matrix are identified internally via their matrix user ID (MXID). However, existing 3rd party ID (3PID) namespaces such as email addresses or phone numbers should be used publically to identify Matrix users, at least for invitation purposes. A Matrix "Identity" describes both the user ID and any other existing IDs from third party namespaces linked to their account.
|
||||
|
||||
|
|
||||
|
||||
Matrix users can link third-party IDs (3PIDs) to their user ID. Linking 3PIDs creates a mapping from a 3PID to a user ID. This mapping can then be used by Matrix users in order to discover the MXIDs of their contacts.
|
||||
|
||||
|
|
||||
|
||||
In order to ensure that the mapping from 3PID to user ID is genuine, a globally federated cluster of trusted "Identity Servers" (IS) are used to verify the 3PID and persist and replicate the mappings.
|
||||
Usage of an IS is not required in order for a client application to be part of the Matrix ecosystem. However, without one clients will not be able to look up user IDs using 3PIDs.
|
||||
|
||||
|
|
||||
|
||||
The precise architecture of identity servers is currently in flux and subject to change as we work to fully decentralise them.
|
||||
|
||||
##### Where do my conversations get stored?
|
||||
|
||||
Each homeserver stores the communication history and account information for all of its clients, and shares data with the wider Matrix ecosystem by synchronising communication history with other homeservers and their clients. Clients typically communicate with each other by emitting events in the context of a virtual room. Room data is replicated across all of the homeservers *whose users are participating in a given room*.
|
||||
|
||||
##### What are redactions?
|
||||
|
||||
Since events are extensible it is possible for malicious users and/or servers to add keys that are, for example offensive or illegal. Since some events cannot be simply deleted (e.g. membership events) we instead 'redact' events, essentially stripping the event of all keys that are not required by the protocol. Redacting an event cannot be undone, allowing server owners to also delete the offending content from the databases.
|
||||
|
||||
##### How do you do VoIP calls on Matrix?
|
||||
|
||||
Voice (and video) over Matrix uses the WebRTC 1.0 standard to transfer call media (i.e. the actual voice and video traffic). Matrix is used to signal the establishment and termination of the call by sending call events, like any other event.
|
||||
|
||||
##### Are VoIP calls encrypted?
|
||||
|
||||
WebRTC encrypts the media that's being sent. The signalling events that set up (and end) the call are encrypted if the room they were sent in has enabled encryption.
|
||||
|
||||
##### Do I need a TURN server?
|
||||
|
||||
VoIP calls should work if both parties are on public networks. However, in practice one (or both) devices are often behind NAT, and so having a [TURN](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT) server is important to help set up the call.
|
||||
|
||||
See [this guide](https://github.com/matrix-org/synapse/blob/master/docs/turn-howto.rst) for setting up a TURN server with Synapse.
|
||||
|
||||
##### Can I log into other homeservers with my username and password?
|
||||
|
||||
Currently, no. We are looking at options for decentralising or migrating user accounts between multiple servers, and might add this feature at a later stage.
|
||||
|
||||
##### Why Apache Licence?
|
||||
|
||||
The Apache Licence is a permissive licence. We want the Matrix protocol itself to be free and open, but people are free to create both free and commercial apps and services that uses the protocol. In our opinion, any Matrix-service only enhances the Matrix ecosystem.
|
||||
|
||||
##### Can I write a Matrix homeserver?
|
||||
|
||||
Yes. Matrix is just a spec, so implementations of the spec are very welcome! It should be noted that as of October 2015, changes are still being made to the spec, so if you want to write a Matrix homeserver, it is strongly recommended that you chat to the Matrix.org devs in [\#matrix:matrix.org](https://matrix.to/#/#matrix:matrix.org) first! You can also read about the [Federation API here](https://matrix.org/docs/spec/server_server/unstable.html).
|
||||
|
||||
##### How secure is this?
|
||||
|
||||
Server-server traffic is mandatorily TLS from the outset. Server-client traffic mandates transport layer encryption other than for tinkering. Servers maintain a public/private key pair, and sign the integrity of all messages in the context of the historical conversation, preventing tampering. Server keys are distributed using a [Perspectives](https://perspectives-project.org/)-style system.
|
||||
|
||||
End-to-end encryption is now available in the various [Riot.im](https://Riot.im) builds! This allows you to encrypt both 1:1 and group chats to protect user data stored on servers, using the [Olm](https://matrix.org/git/olm) cryptographic ratchet implementation. Read more on the [blog post](https://matrix.org/blog/2016/11/21/matrixs-olm-end-to-end-encryption-security-assessment-released-and-implemented-cross-platform-on-riot-at-last/) that announced the feature!
|
||||
|
||||
Privacy of metadata is not currently protected from server administrators - a malicious homeserver administrator can see who is talking to who and when, but not what is being said (once E2E encryption is enabled). See [this presentation from Jardin Entropique](http://matrix.org/~matthew/2015-06-26%20Matrix%20Jardin%20Entropique.pdf) for a more comprehensive discussion of privacy in Matrix.
|
||||
|
||||
##### What is Perspectives?
|
||||
|
||||
Rather than relying on Certificate Authorities (CAs) as in traditional SSL, a [Perspectives](https://perspectives-project.org/)-style system uses a more decentralized model for verifying keys. Perspectives uses notary servers to verify that the same key is seen across the network, making a man-in-the-middle attack much harder since an attacker must insert itself into multiple places. For federation in Matrix, each Home Server acts as a notary. When one Home Server connects to another Home Server that uses a key that it doesn't recognize, it contacts other Home Servers to ensure that they all see the same key from that Home Server.
|
||||
|
||||
##### Why HTTP? Doesn't HTTP suck? Why don't you use websockets/CoAP/HTTP2/etc?
|
||||
|
||||
HTTP is indeed not the most efficient transport, but it is ubiquitous, very well understood and has numerous implementations on almost every platform and language. It also has a simple upgrade path to HTTP/2, which is relatively bandwidth and round-trip efficient.
|
||||
|
||||
It has thus been chosen as the mandatory baseline of the exchange, but it is still entirely possible to use more fancy protocols for communication between clients and server (see for example this [websocket transport draft](https://github.com/matrix-org/matrix-doc/blob/master/drafts/websockets.rst)), and it's also possible in the future that negotiation of more efficient protocols will be added for the federation between servers, with HTTP+JSON remaining as the compability baseline.
|
||||
|
||||
### Servers
|
||||
|
||||
##### What is Synapse?
|
||||
|
||||
Synapse is a reference "homeserver" implementation of Matrix from the core development team at matrix.org, written in Python 2/Twisted. It is intended to showcase the concept of Matrix and let folks see the spec in the context of a codebase and let you run your own homeserver and generally help bootstrap the ecosystem.
|
||||
|
||||
##### How do I join the global Matrix federation?
|
||||
|
||||
You can download and run one of the available Matrix servers - please see [this guide](http://matrix.org/docs/guides/getting_involved.html#run) for details!
|
||||
|
||||
##### What ports do I have to open up to join the global Matrix federation?
|
||||
|
||||
We recommend servers use port 8448 for server\<-\>server HTTPS traffic. Look at ["Setting up Federation"](https://github.com/matrix-org/synapse#setting-up-federation) in the Synapse readme file for details.
|
||||
|
||||
Client\<-\>Server traffic can talk directly to Synapse via port 8448, but as by default Synapse creates a self-signed TLS certificate this can cause problems for clients which can't easily trust self-signed certificates (e.g. most web browsers). Instead, you can proxy access to Synapse's HTTP listener on port 8008 via an existing HTTPS proxy with a valid certificate (e.g. an nginx listening on port 443), or you can point Synapse at a valid X.509 signed TLS certificate. In future, Synapse will probably use letsencrypt to autogenerate valid certificates rather than self-signed ones during installation, simplifying this process enormously.
|
||||
|
||||
You can also put Synapse entirely behind an existing TLS load balancer and not expose port 8448 at all. In this situation, Synapse will need to be configured to share the same *public* TLS certificate as the load balancer (as Synapse uses the public certificate for identity in other areas too, and it has to match the certificate that other servers see when they connect).
|
||||
|
||||
##### How do I run my own homeserver?
|
||||
|
||||
Follow the instructions for the homeserver you want to run. If you want to run Synapse, the reference homeserver from Matrix.org, follow [these instructions](https://github.com/matrix-org/synapse#synapse-installation).
|
||||
|
||||
##### Can I run my own identity server?
|
||||
|
||||
Yes - the reference implementation is
|
||||
[sydent](https://github.com/matrix-org/sydent) and you can run your own ID server cluster that tracks 3rd party to Matrix ID mappings. This won't be very useful right now, though, and we don't recommend it.
|
||||
|
||||
If you want your server to participate in the global replicated Matrix ID
|
||||
service then please get in touch with us. Meanwhile, we are looking at
|
||||
ways of decentralising the 'official' Matrix identity service so that
|
||||
identity servers are 100% decentralised and can openly federate with
|
||||
each other. **N.B. that you can use Matrix without ever using the
|
||||
identity service - it exists only to map 3rd party IDs (e.g. email
|
||||
addresses) to matrix IDs to aid user discovery**.
|
||||
|
||||
##### What are Synapse's platform requirements?
|
||||
|
||||
Synapse will use as much RAM as you give it in order to cache conversations in RAM to avoid hitting the database. For small deployments (<50 active users) around 512MB of RAM is probably okay. You can configure the amount of RAM used by synapse with the event_cache_size config parameter - the more events in the cache, the more RAM required. Synapse itself requires relatively little diskspace other than for logging (which as of October 2015 is quite verbose for debugging purposes), but as it caches the content of all the file attachments (images, videos etc) viewed by its users, you may need to size storage appropriately. Synapse is currently effectively single threaded, and will never use more than 1 core.
|
||||
|
||||
|
|
||||
|
||||
For better performance, one should back Synapse with a Postgres database rather than the default SQLite - see [https://github.com/matrix-org/synapse/tree/master/README.rst#using-postgresql](https://github.com/matrix-org/synapse/tree/master/README.rst#using-postgresql) for details.
|
||||
|
||||
##### Why is Synapse in Python/Twisted?
|
||||
|
||||
This is because both provide a mature and well known event-driven async IO framework for writing serverside code. Whilst this has been okay for our initial experimentation and proof of concept, it's likely that future homeserver work will be written in a more strongly typed language (e.g. Go).
|
||||
|
||||
##### Why aren't you using an ORM layer like SqlAlchemy in Synapse?
|
||||
|
||||
Synapse is *very* database dependent (as of Oct 2015; this is improving in the near future however), and we like having the flexibility to sculpt our own queries.
|
||||
|
||||
##### Will Synapse share my chat data with other servers in the federation?
|
||||
|
||||
Data is only shared between servers of participating users of a room. If all users in a room are on your server, no data is shared with other servers.
|
||||
|
||||
##### Why can't I rename my homeserver?
|
||||
|
||||
Currently, the homeserver name is assumed never to change. This means that if you rename your server, other servers will think it's a different server.
|
||||
|
||||
Perhaps in the future we will add an API for changing the homeserver name, but for now this is not supported.
|
||||
|
||||
### Clients
|
||||
|
||||
##### Where can I find a mobile app?
|
||||
|
||||
Riot is available for Android and iOS.
|
||||
|
||||
The iOS version can be downloaded from the [Apple store](https://itunes.apple.com/us/app/vector.im/id1083446067).
|
||||
|
||||
The Android version can be downloaded from the [Google Play store](https://play.google.com/store/apps/details?id=im.vector.alpha) or [F-Droid](https://f-droid.org/repository/browse/?fdid=im.vector.alpha). If you are not sure which one to choose, install Riot from the [Google Play store](https://play.google.com/store/apps/details?id=im.vector.alpha).
|
||||
|
||||
For the Android app, you can also install the latest development version
|
||||
built by [Jenkins](http://matrix.org/jenkins/job/VectorAndroidDevelop). Use it at your own risk and only if you know what you are doing.
|
||||
|
||||
##### I installed Riot via F-Droid, why is it draining my battery?
|
||||
|
||||
The F-Droid release of Riot does not use [Google Cloud Messaging](https://developers.google.com/cloud-messaging/). This allows users that do not have or want Google Services installed to use Riot.
|
||||
|
||||
The drawback is that Riot has to pull for new messages, which can drain your battery. To counter this, you can change the delay between polls in the settings. Higher delay means better battery life (but may delay receiving messages). You can also disable the background sync entirely (which means that you won't get any notifications at all).
|
||||
|
||||
If you don't mind using Google Services, you might be better off installing the [Google Play store](https://play.google.com/store/apps/details?id=im.vector.alpha) version.
|
||||
|
||||
##### Where can I find a web app?
|
||||
|
||||
You can use [Riot.im](https://Riot.im) - a glossy web client written on top of [matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk).
|
||||
|
||||
You can also run Vector, the code that Riot.im uses, on your own server. It's a static web application, just download the [last release](https://github.com/vector-im/vector-web/) and unpack it.
|
||||
|
||||
##### Where can I find a desktop client?
|
||||
|
||||
You can use the desktop build of [Riot.im](https://riot.im/desktop.html).
|
||||
|
||||
There are also other desktop clients - check the list of clients on [matrix.org](http://matrix.org/docs/projects/try-matrix-now.html#clients).
|
||||
|
||||
##### Why can't end-to-end encryption be turned off?
|
||||
|
||||
When encryption is enabled in a room, a flag is set in the room state, so that
|
||||
all clients know to encrypt any messages they send. The room state stores
|
||||
information about the room like the topic, the avatar, and the membership list.
|
||||
|
||||
Imagine if encryption could be turned off the same way as it is turned
|
||||
on. Anyone with admin rights in the room could clear the flag and then messages
|
||||
would start being transmitted unencrypted. It would be very easy for a user to
|
||||
miss the change in configuration, and accidentally send a sensitive message
|
||||
without encryption.
|
||||
|
||||
Worse yet, anyone with sysadmin access to a server could also clear the flag
|
||||
(remember that the main reason for using e2e encryption is that we don't trust
|
||||
the sysadmins), and could then easily read any sensitive content which was
|
||||
sent.
|
||||
|
||||
The solution we have taken for now is to make clients ignore any requests to
|
||||
disable encryption. We might experiment with ways to improve this in the future
|
||||
- for instance, by alerting the user next time they try to send a message in
|
||||
the room if encryption has been disabled.
|
||||
|
||||
##### Why isn't end-to-end encryption enabled by default?
|
||||
|
||||
We are deliberately keeping E2E opt-in during the beta as there is a small risk of undecryptable messages, and we don’t want to lull folks into a false sense of security. As soon as we are out of beta, we will turn E2E on for any room with private history by default. Another consideration is to give other clients a chance to catch up with E2E support before it's used by default.
|
||||
|
||||
|
|
||||
|
||||
### QUESTIONS TO BE ANSWERED!
|
||||
|
||||
This FAQ is a constant work in progress - patches and pull requests are *very* welcome to help us improve it. Some of the frequent questions where we need to write an answer include:
|
||||
|
||||
* How do I change the TLS key of my server?
|
||||
* How do I maintain my synapse's DB (e.g. prune old conversations)?
|
||||
* How do I maintain my synapse's content repository (e.g. prune old content)?
|
||||
* Why is the spec so big, especially relative to the XMPP baseline spec?
|
||||
* How do I contribute to the spec?
|
||||
* What is the privacy policy on Matrix.org?
|
||||
* How precisely does E2E work?
|
||||
* How does Matrix actually work architecturally?
|
||||
* What IOT use cases are there for Matrix?
|
||||
* Why is are the Matrix reference implementations written in so many different languages?
|
||||
* How does push work?
|
||||
* What's on the roadmap?
|
||||
* How can I use Matrix to talk on Freenode or other IRC networks?
|
||||
* Where can I learn more about Matrix? (link to PDFs of other presentations etc)
|
||||
* Why is synapse so resource intensive immediately after federating for the first time?
|
||||
* \[your question goes here...\]
|
||||
|
||||
|
|
||||
|
||||
Any other questions? Please contact us in
|
||||
[\#matrix:matrix.org](https://matrix.to/#/#matrix:matrix.org).
|
|
@ -1,146 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
title: Application services
|
||||
categories: guides
|
||||
---
|
||||
|
||||
# Application services
|
||||
|
||||
Application services are distinct modules which which sit alongside a homeserver providing arbitrary extensible functionality decoupled from the homeserver implementation. Just like the rest of Matrix, they communicate via HTTP using JSON. Application services function in a very similar way to traditional clients, but they are given much more power than a normal client. They can reserve entire namespaces of room aliases and user IDs for their own purposes. They can silently monitor events in rooms, or any events directed at any user ID. This power allows application services to have extremely useful abilities which overall enhance the end user experience.
|
||||
|
||||
|
|
||||
|
||||
One of the main use cases for application services is protocol bridges. Our Matrix server on Matrix.org links in to various IRC channels and networks. This functionality was initially implemented as a simple bot which resided as a user on the Matrix rooms we wanted to link to freenode channels (#matrix, #matrix-dev, #openwebrtc and #vuc etc). There was nothing special about this bot; it is just treated as a client. However, as we started to rely on it more and more though, we realised that there were things that were impossible for simple client-side bots to do by themselves - for example, the bot could not reserve the virtual user IDs it wanted to create, and could not lazily bridge arbitrary IRC rooms on-the-fly - and this spurred the development of Application Services.
|
||||
|
||||
|
|
||||
|
||||
### Some of the features of the IRC application service we have since implemented include:
|
||||
|
||||
- Specific channel-to-matrix room bridging : This is what the original IRC bot did. You can specify specific channels and specific room IDs, and messages will be bridged.
|
||||
- Dynamic channel-to-matrix room bridging : This allows Matrix users to join any channel on an IRC network, rather than being forced to use one of the specific channels configured.
|
||||
- Two-way PM support : IRC users can PM the virtual "M-" users and private Matrix rooms will be created. Likewise, Matrix users can invite the virtual "@irc_Nick:domain" user IDs to a room and a PM to the IRC nick will be made.
|
||||
- IRC nick changing support: Matrix users are no longer forced to use "M-" nicks and can change them by sending "!nick" messages directly to the bridge.
|
||||
- Ident support: This allows usernames to be authenticated for virtual IRC clients, which means IRC bans can be targeted at the Matrix user rather than the entire application service.
|
||||
|
||||
|
|
||||
|
||||
### The use of the Application Services API means:
|
||||
|
||||
- The bot can reserve user IDs. This prevents humans from registering for @irc_... user IDs which would then clash with the operation of the bot.
|
||||
- The bot can reserve room aliases. This prevents humans from register for #irc_... aliases which would then clash with the operation of the bot.
|
||||
- The bot can trivially manage hundreds of users. Events are pushed to the application service directly. If you tried to do this as a client-side bot, you would need one event stream connection per virtual user.
|
||||
- The bot can lazily create rooms on demand. This means Matrix users can join non-existent room aliases and have the application service quickly track an IRC channel and create a room with that alias, allowing the join request to succeed.
|
||||
|
||||
|
|
||||
|
||||
### Implementation details:
|
||||
|
||||
- Written in Node.js, designed to be run using <code>forever</code>.
|
||||
- Built on the generic <a href="http://github.com/matrix-org/matrix-appservice-node">matrix-appservice-node</a> framework.
|
||||
- Supports sending metrics in statsd format.
|
||||
- Uses matrix-appservice-node to provide a standardised interface when writing application services, rather than an explicit web framework (though under the hood matrix-appservice-node is using Express).
|
||||
|
||||
|
|
||||
|
||||
At present, the IRC application service is in beta, and is being run on #matrix and #matrix-dev. If you want to give it a go, <a title="Matrix-IRC Application Service" href="https://github.com/matrix-org/matrix-appservice-irc">check it out on Github</a>!
|
||||
|
||||
|
|
||||
|
||||
# What Application services can do for you
|
||||
Application services have enormous potential for creating new and exciting ways to transform and enhance the core Matrix protocol. For example, you could aggregate information from multiple rooms into a summary room, or create throwaway virtual user accounts to proxy messages for a fixed user ID on-the-fly. As you may expect, all of this power assumes a high degree of trust between application services and homeservers. Only homeserver admins can allow an application service to link up with their homeserver, and the application service is in no way federated to other homeservers. You can think of application services as additional logic on the homeserver itself, without messing around with the book-keeping that homeservers have to do. This makes adding useful functionality very easy.
|
||||
|
||||
|
|
||||
|
||||
### Example
|
||||
|
||||
The application service (AS) API itself uses webhooks to communicate from the homeserver to the AS:
|
||||
|
||||
- Room Alias Query API : The homeserver hits a URL on your application server to see if a room alias exists.
|
||||
- User Query API : The homeserver hits a URL on your application server to see if a user ID exists.
|
||||
- Push API : The homeserver hits a URL on your application server to notify you of new events for your users and rooms.
|
||||
|
||||
A very basic application service may want to log all messages in rooms which have an alias starting with "#logged_" (side note: logging won't work if these rooms are using end-to-end encryption).
|
||||
|
||||
Here's an example of a very basic application service using Python (with Flask and Requests) which logs room activity:
|
||||
|
||||
# app_service.py:
|
||||
|
||||
import json, requests # we will use this later
|
||||
from flask import Flask, jsonify, request
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/transactions/<transaction>", methods=["PUT"])
|
||||
def on_receive_events(transaction):
|
||||
events = request.get_json()["events"]
|
||||
for event in events:
|
||||
print "User: %s Room: %s" % (event["user_id"], event["room_id"])
|
||||
print "Event Type: %s" % event["type"]
|
||||
print "Content: %s" % event["content"]
|
||||
return jsonify({})
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
|
||||
Set your new application service running on port 5000 with:
|
||||
|
||||
python app_service.py
|
||||
|
||||
The homeserver needs to know that the application service exists before it will send requests to it. This is done via a registration YAML file which is specified in Synapse's main config file e.g. <code>homeserver.yaml</code>. The server admin needs to add the application service registration configuration file as an entry to this file.
|
||||
|
||||
# homeserver.yaml
|
||||
app_service_config_files:
|
||||
- "/path/to/appservice/registration.yaml"
|
||||
|
||||
NB: Note the "-" at the start; this indicates a list element. The registration file <code>registration.yaml</code> should look like:
|
||||
|
||||
# registration.yaml
|
||||
|
||||
# An ID which is unique across all application services on your homeserver. This should never be changed once set.
|
||||
id: "something-good"
|
||||
|
||||
# this is the base URL of the application service
|
||||
url: "http://localhost:5000"
|
||||
|
||||
# This is the token that the AS should use as its access_token when using the Client-Server API
|
||||
# This can be anything you want.
|
||||
as_token: wfghWEGh3wgWHEf3478sHFWE
|
||||
|
||||
# This is the token that the HS will use when sending requests to the AS.
|
||||
# This can be anything you want.
|
||||
hs_token: ugw8243igya57aaABGFfgeyu
|
||||
|
||||
# this is the local part of the desired user ID for this AS (in this case @logging:localhost)
|
||||
sender_localpart: logging
|
||||
namespaces:
|
||||
users: []
|
||||
rooms: []
|
||||
aliases:
|
||||
- exclusive: false
|
||||
regex: "#logged_.*"
|
||||
|
||||
**You will need to restart the homeserver after editing the config file before it will take effect.**
|
||||
|
||||
|
|
||||
|
||||
To test everything is working correctly, go ahead and explicitly create a room with the alias "#logged_test:localhost" and send a message into the room: the HS will relay the message to the AS by PUTing to /transactions/<tid> and you should see your AS print the event on the terminal. This will monitor any room which has an alias prefix of "#logged_", but it won't lazily create room aliases if they don't already exist. This means it will only log messages in the room you created before: #logged_test:localhost. Try joining the room "#logged_test2:localhost" without creating it, and it will fail. Let's fix that and add in lazy room creation:
|
||||
|
||||
@app.route("/rooms/<alias>")
|
||||
def query_alias(alias):
|
||||
alias_localpart = alias.split(":")[0][1:]
|
||||
requests.post(
|
||||
# NB: "TOKEN" is the as_token referred to in registration.yaml
|
||||
"http://localhost:8008/_matrix/client/api/v1/createRoom?access_token=TOKEN",
|
||||
json.dumps({
|
||||
"room_alias_name": alias_localpart
|
||||
}),
|
||||
headers={"Content-Type":"application/json"}
|
||||
)
|
||||
return jsonify({})
|
||||
|
||||
This makes the application service lazily create a room with the requested alias whenever the HS queries the AS for the existence of that alias (when users try to join that room), allowing any room with the alias prefix #logged_ to be sent to the AS. Now try joining the room "#logged_test2:localhost" and it will work as you'd expect. You can see that if this were a real bridge, the AS would have checked for the existence of #logged_test2 in the remote network, and then lazily-created it in Matrix as required.
|
||||
|
||||
|
|
||||
|
||||
Application services are powerful components which extend the functionality of homeservers, but they are limited. They can only ever function in a "passive" way. For example, you cannot implement an application service which censors swear words in rooms, because there is no way to prevent the event from being sent. Aside from the fact that censoring will not work when using end-to-end encryption, all federated homeservers would also need to reject the event in order to stop developing an inconsistent event graph. To "actively" monitor events, another component called a "Policy Server" is required, which is beyond the scope of this post. Also, Application Services can result in a performance bottleneck, as all events on the homeserver must be ordered and sent to the registered application services. If you are bridging huge amounts of traffic, you may be better off having your bridge directly talk the Server-Server federation API rather than the simpler Application Service API.
|
||||
|
||||
I hope this demonstrates how easy it is to create an application service, along with a few ideas of the kinds of things you can do with them. Obvious uses include build protocol bridges, search engines, invisible bots, etc. For more information on the AS HTTP API, check out the new <a href="http://matrix.org/docs/spec/#application-service-api">Application Service API</a> section in the spec, or the raw drafts and spec in <a href="https://github.com/matrix-org/matrix-doc/" target="_blank">https://github.com/matrix-org/matrix-doc/</a>.
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
categories: guides
|
||||
---
|
||||
<div class="home">
|
||||
|
||||
<h1>Guides</h1>
|
||||
|
||||
<p>Here is a collection of guides that might help you get involved with Matrix.</p>
|
||||
<p>First, there is the <a href="./getting_involved.html" title="Getting Involved">Getting Involved</a> guide, which explains various ways of getting started with Matrix, and the <a href="./faq.html" title="FAQ">FAQ</a>, which tries to answer all your questions relating to Matrix.</p>
|
||||
<p>The <a href="/docs/guides/client-server.html" title="Client-Server API">Client-Server API</a> guide explains in detail how to use the CS API, which is useful if you want to write a client (or modify an existing one) - or if you're just interested in how it works "under the hood".</p>
|
||||
<p>If you were using the old v1 CS API, there is also the <a href="/docs/guides/client-server-migrating-from-v1.html">v1 migration guide</a> which justs lists the changes from v1 to r0.</p>
|
||||
<p><a href="./lets-encrypt.html">Let's Encrypt Matrix</a> explains how to use Let's Encrypt's certificates with your Synapse installation. This guide was written by William A Stevens.</p>
|
||||
<p>The <a href="./application_services.html" title="Application services">Application services</a> guide introduces and explains Application services, and what they can be used for.</p>
|
||||
<p><a href="./types-of-bridging.html">Types of Bridging</a> should be read by all bridge developers to ensure everyone has the same mental map of terminology when implementing bridges.</p>
|
||||
<p>The <a href="./e2e_implementation.html">End-to-end Encryption Implementation Guide</a> is intended for client developers who wish to add support for end-to-end encryption.</p>
|
||||
|
||||
</div>
|
|
@ -1,85 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
version: v1.0
|
||||
title: Code of Conduct
|
||||
categories: guides
|
||||
---
|
||||
<link href="/docs/css/faq.css" type="text/css" rel="stylesheet" />
|
||||
|
||||
|
||||
# Matrix Code of Conduct
|
||||
|
||||
This code of conduct outlines our expectations for participants within the Matrix community, as well as steps for reporting unacceptable behaviour. We are committed to providing a welcoming and inspiring community for all, and expect our code of conduct to be honoured. Anyone who violates this code of conduct may be banned from the community.
|
||||
|
||||
This applies to conversation in the #matrix* rooms (#matrix:matrix.org, #matrix-dev:matrix.org, #matrix-spam:matrix.org) and commits and comments relating to any project in the [matrix-org](https://github.com/matrix-org) github space.
|
||||
|
||||
Our open source community strives to:
|
||||
|
||||
* **Be friendly and patient.**
|
||||
* **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
|
||||
* **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
|
||||
* **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behaviour and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one.
|
||||
* **Be careful in the words that we choose**: Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behaviour aren't acceptable.
|
||||
* **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
|
||||
|
||||
|
|
||||
|
||||
## Definitions
|
||||
|
||||
Harassment includes, but is not limited to:
|
||||
|
||||
- Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, age, regional discrimination, political or religious affiliation
|
||||
- Unwelcome comments regarding a person’s lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment
|
||||
- Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a person's gender identity. You must address people by the name they give you when not addressing them by their username or handle
|
||||
- Physical contact and simulated physical contact (eg, textual descriptions like “*hug*” or “*backrub*”) without consent or after a request to stop
|
||||
- Threats of violence, both physical and psychological
|
||||
- Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm
|
||||
- Deliberate intimidation
|
||||
- Stalking or following
|
||||
- Harassing photography or recording, including logging online activity for harassment purposes
|
||||
- Sustained disruption of discussion
|
||||
- Unwelcome sexual attention, including gratuitous or off-topic sexual images or behaviour
|
||||
- Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others
|
||||
- Continued one-on-one communication after requests to cease
|
||||
- Deliberate “outing” of any aspect of a person’s identity without their consent except as necessary to protect others from intentional abuse
|
||||
- Publication of non-harassing private communication
|
||||
|
||||
|
|
||||
|
||||
We will not act on complaints regarding:
|
||||
|
||||
- Good faith and non-malicious conduct whose object is to ameliorate the conditions of disadvantaged individuals or groups including those that are disadvantaged because of race, national or ethnic origin, colour, religion, sex, age or mental or physical disability.
|
||||
- Reasonable communication of boundaries, such as “leave me alone,” “go away,” or “I’m not discussing this with you”
|
||||
- Refusal to explain or debate social justice concepts
|
||||
- Communicating in a ‘tone’ you don’t find congenial
|
||||
- Criticizing racist, sexist, cissexist, or otherwise oppressive behaviour or assumptions
|
||||
|
||||
|
|
||||
|
||||
### Diversity Statement
|
||||
|
||||
We encourage everyone to participate and are committed to building a community for all. Although we will fail at times, we seek to treat everyone both as fairly and equally as possible. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.
|
||||
|
||||
Although this list cannot be exhaustive, we explicitly honour diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected
|
||||
characteristics above, including participants with disabilities.
|
||||
|
||||
|
|
||||
|
||||
### Reporting Issues
|
||||
|
||||
If you experience or witness unacceptable behaviour — or have any other concerns — please report it by contacting us via abuse@matrix.org. All reports will be handled with discretion. In your report please include:
|
||||
|
||||
- Your contact information.
|
||||
- Names (usernames and nicks, real names, and/or pseudonyms) of any individuals involved. If there are additional witnesses, please
|
||||
include them as well. Your account of what occurred, and if you believe the incident is ongoing.
|
||||
- The date and time of the incident (or start of incident).
|
||||
- Any additional information that may be helpful.
|
||||
|
||||
After filing a report, a representative will contact you personally, review the incident, follow up with any additional questions, and make a decision as to how to respond. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. If the complaint originates from a member of the response team, it will be handled by a different member of the response team. We will respect confidentiality requests for the purpose of protecting victims of abuse.
|
||||
|
||||
|
|
||||
|
||||
### Attribution & Acknowledgements
|
||||
|
||||
This Code of Conduct is based on the [TODO Group](https://twitter.com/todogroup)'s [Open Code of Conduct template](https://github.com/todogroup/opencodeofconduct), but with some modifications.
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
title: Let's Encrypt Matrix
|
||||
categories: guides
|
||||
---
|
||||
|
||||
====================
|
||||
Let's Encrypt Matrix
|
||||
====================
|
||||
|
||||
Let's Encrypt is a free Certificate Authority that makes it easy to secure your server's internet traffic. This makes it really easy to secure your Matrix homeserver, and this guide will explain exactly how you do this. Guide written by William A Stevens - thanks!
|
||||
|
||||
0: Prerequisites
|
||||
================
|
||||
* Install Synapse_.
|
||||
* Install (or Download) certbot_
|
||||
|
||||
1: Get certificates
|
||||
===================
|
||||
When executing the Let's Encrypt client, it will ask for the domain name of your server, and your email address. The domain list can include multiple names and should include any domain you want to access the server from.
|
||||
|
||||
Also, the certificates will be in a folder under /etc/letsencrypt (see below) and owned by root.
|
||||
|
||||
::
|
||||
|
||||
# certbot certonly --standalone
|
||||
|
||||
A note about renewal
|
||||
--------------------
|
||||
These certificates will expire in 3 months. To renew certificates, run ```certbot renew```. It is recommended to create a cronjob, which attempts renewal twice a day. Depending on your distribution, that could be already configured.
|
||||
|
||||
2: Install Certificates
|
||||
=======================
|
||||
At the top of your homeserver.yaml there should be two keys, ```tls_certificate_path``` and ```tls_private_key_path```. These should be changed so that instead of pointing to the default keys, they now point to the Let's Encrypt keys. ```tls_certificate_path``` should point to ```/etc/letsencrypt/live/(your domain name)/fullchain.pem```. ```tls_private_key_path``` should point to ```/etc/letsencrypt/live/(your domain name)/privkey.pem```. ```tls_dh_params_path``` can stay the same as before.
|
||||
|
||||
.. _Synapse: https://github.com/matrix-org/synapse/blob/master/README.rst#synapse-installation
|
||||
.. _certbot: https://certbot.eff.org/
|
|
@ -1,114 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
title: Migrating from Client Server API v1
|
||||
categories: guides
|
||||
---
|
||||
|
||||
Migrating from client-server API v1
|
||||
===================================
|
||||
|
||||
This guide assists developers of API clients that target the ``v1`` version of
|
||||
the API to migrate their code to the later ``r0``. It does not aim to introduce
|
||||
new concepts that were added in ``r0`` except where these replace things that
|
||||
were removed since ``v1``.
|
||||
|
||||
Updated Version In Path
|
||||
=======================
|
||||
|
||||
The new version of the API is ``r0``; this should be used in paths where
|
||||
``v1`` used to appear. Additionally, the ``/api`` path component has now been
|
||||
removed. API endpoint paths are now::
|
||||
|
||||
POST /_matrix/client/r0/register
|
||||
GET /_matrix/client/r0/login
|
||||
etc...
|
||||
|
||||
New Registration and Login Endpoints
|
||||
====================================
|
||||
|
||||
The ``r0`` version of the ``/register`` and ``/login`` endpoints is different
|
||||
to the ``v1`` version. See the updated API documentation for details on how the
|
||||
new API works. In brief, the changes are that the new version returns extra
|
||||
information in the form of the ``params`` object, and that a sequence of
|
||||
multiple calls may be statefully chained together by the ``session`` parameter.
|
||||
|
||||
Additionally, whereas in ``v1`` the client performed a ``GET`` request to
|
||||
discover the list of supported flows for ``/register``, in ``r0`` this is done
|
||||
by sending a ``POST`` request with an empty data body. The ``/login`` endpoint
|
||||
continues to use the ``GET`` method as before.
|
||||
|
||||
Deprecated Endpoints
|
||||
====================
|
||||
|
||||
The following endpoints are now deprecated and replaced by the ``/sync`` API::
|
||||
|
||||
/initialSync
|
||||
/events
|
||||
/rooms/:roomId/initialSync
|
||||
|
||||
The new ``/sync`` API takes an optional ``since`` parameter to distinguish the
|
||||
initial sync from subsequent updates for more events.
|
||||
|
||||
The return value takes a different structure to that from the previous
|
||||
``/initialSync`` API. For full details see the API documentation, but the
|
||||
following summary may be useful to compare with ``v1``:
|
||||
|
||||
* ``/initialSync`` returned a ``state`` key containing the most recent state
|
||||
in the room, whereas the new ``/sync`` API's ``state`` corresponds to the
|
||||
room state at the start of the returned timeline. This makes it easier for
|
||||
clients to represent state changes that occur within the region of returned
|
||||
timeline.
|
||||
|
||||
* In ``/events``, if more events occurred since the ``since`` token than the
|
||||
``limit`` parameter allowed, then events from the start of this range were
|
||||
returned and the client had to perform another fetch to incrementally obtain
|
||||
more of them. In the ``/sync`` API the result always contains the most
|
||||
recent events, creating a gap if this would be more events than the
|
||||
requested limit. If this occurs then the client can use the ``prev_batch``
|
||||
token as a reference to obtaining more.
|
||||
|
||||
* The ``state`` contained in the response to a ``/sync`` request that has a
|
||||
``since`` parameter will contain only keys that have changed since the
|
||||
basis given in the ``since`` parameter, rather than containing a full set
|
||||
values.
|
||||
|
||||
The ``/initialSync`` API allowed a parameter called ``limit`` to limit the
|
||||
number of events returned. To apply this limit to the new ``/sync`` API, you
|
||||
can supply an ad-hoc filter::
|
||||
|
||||
GET .../sync?filter={"room":{"timeline":{"limit:$limit}}}
|
||||
|
||||
There is no direct replacement for the per-room ``/rooms/:roomId/initialSync``
|
||||
endpoint, but the behaviour can be recreated by applying an ad-hoc filter using
|
||||
the ``filter`` parameter to ``/sync`` that selects only the required room ID::
|
||||
|
||||
GET .../sync?filter={"room":{"rooms":[$room_id]}}
|
||||
|
||||
However, the way that the new ``/sync`` API works should remove any need to do
|
||||
this kind of query, in the situations where the ``v1`` API needed it.
|
||||
Specifically, on joining a new room the initial information about that room is
|
||||
sent in the next ``/sync`` batch, so it should not be necessary to query that
|
||||
one room specially.
|
||||
|
||||
The following endpoint is deprecated and has no direct replacement::
|
||||
|
||||
/events/:eventId
|
||||
|
||||
However, if the client knows the room ID of the room that the event is in, it
|
||||
can use the ``/rooms/:roomId/context/:eventId`` request to fetch the event
|
||||
itself. By giving the ``limit`` parameter of ``0`` the client can save using
|
||||
extra bandwidth by actually returning additional context events around the
|
||||
requested one.
|
||||
|
||||
Removed POST Endpoint
|
||||
=====================
|
||||
|
||||
The room message sending API endpoint in ``v1`` accepted both ``PUT`` and
|
||||
``POST`` methods, where the client could specify a message ID in the ``PUT``
|
||||
path for de-duplication purposes, or have the server allocate one during
|
||||
``POST``. In ``r0`` this latter form no longer exists. Clients will now have
|
||||
to generate these IDs locally.
|
||||
|
||||
The following URLs have therefore been removed::
|
||||
|
||||
POST .../rooms/:roomId/send/:messageType
|
|
@ -1,394 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
title: Client Server API
|
||||
categories: guides
|
||||
---
|
||||
|
||||
|
||||
.. TODO kegan
|
||||
Room config (specifically: message history,
|
||||
public rooms).
|
||||
|
||||
How to use the client-server API
|
||||
================================
|
||||
|
||||
.. NOTE::
|
||||
The git version of this document is ``{% project_version %}``
|
||||
|
||||
This guide focuses on how the client-server APIs *provided by the reference
|
||||
homeserver* can be used. Since this is specific to a homeserver
|
||||
implementation, there may be variations in relation to registering/logging in
|
||||
which are not covered in extensive detail in this guide.
|
||||
|
||||
If you haven't already, get a homeserver up and running on
|
||||
``https://localhost:8448``.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
.. NOTE::
|
||||
`Try out the fiddle`__
|
||||
|
||||
.. __: http://jsfiddle.net/gh/get/jquery/1.8.3/matrix-org/matrix-doc/tree/master/supporting-docs/howtos/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 '{"username":"example", "password":"wordpass", "auth": {"type":"m.login.dummy"}}' "https://localhost:8448/_matrix/client/r0/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 homeserver uses a username/password to authenticate user,
|
||||
but other homeservers may use different methods. This is why you need to
|
||||
specify the ``type`` of method.
|
||||
|
||||
Login
|
||||
-----
|
||||
The aim when logging in is to get an access token for your existing user ID::
|
||||
|
||||
curl -XGET "https://localhost:8448/_matrix/client/r0/login"
|
||||
|
||||
{
|
||||
"flows": [
|
||||
{
|
||||
"type": "m.login.password"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
curl -XPOST -d '{"type":"m.login.password", "user":"example", "password":"wordpass"}' "https://localhost:8448/_matrix/client/r0/login"
|
||||
|
||||
{
|
||||
"access_token": "QGV4YW1wbGU6bG9jYWxob3N0.vRDLTgxefmKWQEtgGd",
|
||||
"home_server": "localhost",
|
||||
"user_id": "@example:localhost"
|
||||
}
|
||||
|
||||
Implementation note: Different homeservers may implement different methods for
|
||||
logging in to an existing account. In order to check that you know how to login
|
||||
to this homeserver, you must perform a ``GET`` first and make sure you
|
||||
recognise the login type. If you do not know how to login, you can
|
||||
``GET /login/fallback`` which will return a basic webpage which you can use to
|
||||
login. The reference homeserver implementation support username/password login,
|
||||
but other homeservers 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.
|
||||
|
||||
.. NOTE::
|
||||
`Try out the fiddle`__
|
||||
|
||||
.. __: http://jsfiddle.net/gh/get/jquery/1.8.3/matrix-org/matrix-doc/tree/master/supporting-docs/howtos/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"}' "https://localhost:8448/_matrix/client/r0/createRoom?access_token=YOUR_ACCESS_TOKEN"
|
||||
|
||||
{
|
||||
"room_alias": "#tutorial:localhost",
|
||||
"room_id": "!asfLdzLnOdGRkdPZWu: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"}' "https://localhost:8448/_matrix/client/r0/rooms/%21asfLdzLnOdGRkdPZWu:localhost/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.
|
||||
|
||||
.. NOTE::
|
||||
`Try out the fiddle`__
|
||||
|
||||
.. __: http://jsfiddle.net/gh/get/jquery/1.8.3/matrix-org/matrix-doc/tree/master/supporting-docs/howtos/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"}' "https://localhost:8448/_matrix/client/r0/rooms/%21asfLdzLnOdGRkdPZWu:localhost/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 '{}' "https://localhost:8448/_matrix/client/r0/rooms/%21asfLdzLnOdGRkdPZWu:localhost/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 '{}' "https://localhost:8448/_matrix/client/r0/join/%21asfLdzLnOdGRkdPZWu:localhost?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.
|
||||
|
||||
.. NOTE::
|
||||
`Try out the fiddle`__
|
||||
|
||||
.. __: http://jsfiddle.net/gh/get/jquery/1.8.3/matrix-org/matrix-doc/tree/master/supporting-docs/howtos/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 "https://localhost:8448/_matrix/client/r0/sync?access_token=YOUR_ACCESS_TOKEN"
|
||||
|
||||
{
|
||||
"account_data": {
|
||||
"events": [
|
||||
{
|
||||
...
|
||||
}
|
||||
]
|
||||
},
|
||||
"next_batch": "s9_3_0_1_1_1",
|
||||
"presence": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"currently_active": true,
|
||||
"last_active_ago": 19,
|
||||
"presence": "online"
|
||||
},
|
||||
"sender": "@example:localhost",
|
||||
"type": "m.presence"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rooms": {
|
||||
"invite": {},
|
||||
"join": {
|
||||
"!asfLdzLnOdGRkdPZWu:localhost": {
|
||||
"account_data": {
|
||||
"events": []
|
||||
},
|
||||
"ephemeral": {
|
||||
"events": []
|
||||
},
|
||||
"state": {
|
||||
"events": []
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"creator": "@example:localhost"
|
||||
},
|
||||
"event_id": "$14606534990LhqHt:localhost",
|
||||
"origin_server_ts": 1460653499699,
|
||||
"sender": "@example:localhost",
|
||||
"state_key": "",
|
||||
"type": "m.room.create",
|
||||
"unsigned": {
|
||||
"age": 239192
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": null,
|
||||
"displayname": null,
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$14606534991nsZKk:localhost",
|
||||
"membership": "join",
|
||||
"origin_server_ts": 1460653499727,
|
||||
"sender": "@example:localhost",
|
||||
"state_key": "@example:localhost",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 239164
|
||||
}
|
||||
},
|
||||
...
|
||||
],
|
||||
"limited": false,
|
||||
"prev_batch": "s9_3_0_1_1_1"
|
||||
},
|
||||
"unread_notifications": {}
|
||||
}
|
||||
},
|
||||
"leave": {}
|
||||
}
|
||||
}
|
||||
|
||||
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 a filter that asks for a limit of 1 timeline event per room::
|
||||
|
||||
curl --globoff -XGET 'https://localhost:8448/_matrix/client/r0/sync?filter={"room":{"timeline":{"limit":1}}}&access_token=YOUR_ACCESS_TOKEN'
|
||||
|
||||
{
|
||||
...
|
||||
"rooms": {
|
||||
"invite": {},
|
||||
"join": {
|
||||
"!asfLdzLnOdGRkdPZWu:localhost": {
|
||||
...
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "hello",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$14606535757KCGXo:localhost",
|
||||
"origin_server_ts": 1460653575105,
|
||||
"sender": "@example:localhost",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 800348
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t8-8_7_0_1_1_1"
|
||||
},
|
||||
"unread_notifications": {}
|
||||
}
|
||||
},
|
||||
"leave": {}
|
||||
}
|
||||
}
|
||||
|
||||
(additionally we have to ask ``curl`` not to try to interpret any ``{}``
|
||||
characters in the URL, which is what the ``--globoff`` option is for)
|
||||
|
||||
Getting live state
|
||||
------------------
|
||||
In the response to this ``sync`` request the server includes a token that can
|
||||
be used to obtain updates since this point under the object key ``next_batch``.
|
||||
To use this token, specify its value as the ``since`` parameter to another
|
||||
``/sync`` request.::
|
||||
|
||||
curl -XGET "https://localhost:8448/_matrix/client/r0/sync?since=s9_7_0_1_1_1&access_token=YOUR_ACCESS_TOKEN"
|
||||
|
||||
{
|
||||
"account_data": {
|
||||
"events": []
|
||||
},
|
||||
"next_batch": "s9_9_0_1_1_1",
|
||||
"presence": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"currently_active": true,
|
||||
"last_active_ago": 12,
|
||||
"presence": "online"
|
||||
},
|
||||
"sender": "@example:localhost",
|
||||
"type": "m.presence"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rooms": {
|
||||
"invite": {},
|
||||
"join": {},
|
||||
"leave": {}
|
||||
}
|
||||
}
|
||||
|
||||
By default this request will not wait in the server, always returning a value
|
||||
even if nothing interesting happened. However, by applying the ``timeout``
|
||||
query parameter, which gives a duration in miliseconds, we can ask the server
|
||||
to wait for up to that amount of time before it returns. If no interesting
|
||||
events have happened since then, the response will be relatively empty.::
|
||||
|
||||
curl -XGET "https://localhost:8448/_matrix/client/r0/sync?since=s9_13_0_1_1_1&access_token=YOUR_ACCESS_TOKEN"
|
||||
{
|
||||
"account_data": {
|
||||
"events": []
|
||||
},
|
||||
"next_batch": "s9_13_0_1_1_1",
|
||||
"presence": {
|
||||
"events": []
|
||||
},
|
||||
"rooms": {
|
||||
"invite": {},
|
||||
"join": {},
|
||||
"leave": {}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
.. NOTE::
|
||||
`Try out the fiddle`__
|
||||
|
||||
.. __: http://jsfiddle.net/gh/get/jquery/1.8.3/matrix-org/matrix-doc/tree/master/supporting-docs/howtos/jsfiddles/example_app
|
|
@ -1,797 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
title: End-to-End Encryption implementation guide
|
||||
categories: guides
|
||||
---
|
||||
|
||||
Implementing End-to-End Encryption in Matrix clients
|
||||
====================================================
|
||||
|
||||
This guide is intended for authors of Matrix clients who wish to add
|
||||
support for end-to-end encryption. It is highly recommended that readers
|
||||
be familiar with the Matrix protocol and the use of access tokens before
|
||||
proceeding.
|
||||
|
||||
.. contents::
|
||||
|
||||
The libolm library
|
||||
------------------
|
||||
|
||||
End-to-end encryption in Matrix is based on the Olm and Megolm
|
||||
cryptographic ratchets. The recommended starting point for any client
|
||||
authors is with the `libolm <http://matrix.org/git/olm>`__ library,
|
||||
which contains implementations of all of the cryptographic primitives
|
||||
required. The library itself is written in C/C++, but is architected in
|
||||
a way which makes it easy to write wrappers for higher-level languages.
|
||||
|
||||
Devices
|
||||
-------
|
||||
|
||||
We have a particular meaning for “device”. As a user, I might have
|
||||
several devices (a desktop client, some web browsers, an Android device,
|
||||
an iPhone, etc). When I first use a client, it should register itself as
|
||||
a new device. If I log out and log in again as a different user, the
|
||||
client must register as a new device. Critically, the client must create
|
||||
a new set of keys (see below) for each “device”.
|
||||
|
||||
The longevity of devices will depend on the client. In the web client,
|
||||
we create a new device every single time you log in. In a mobile client,
|
||||
it might be acceptable to reuse the device if a login session expires,
|
||||
**provided** the user is the same. **Never** share keys between
|
||||
different users.
|
||||
|
||||
Devices are identified by their ``device_id`` (which is unique within
|
||||
the scope of a given user). By default, the ``/login`` and ``/register``
|
||||
endpoints will auto-generate a ``device_id`` and return it in the
|
||||
response; a client is also free to generate its own ``device_id`` or, as
|
||||
above, reuse a device, in which case the client should pass the
|
||||
``device_id`` in the request body.
|
||||
|
||||
The lifetime of devices and ``access_token``\ s are closely related. In
|
||||
the simple case where a new device is created each time you log in,
|
||||
there is a one-to-one mapping between a ``device_id`` and an
|
||||
``access_token``. If a client reuses a ``device_id`` when logging
|
||||
in, there will be several ``access_token``\ s associated with a
|
||||
given ``device_id`` - but still, we would expect only one of these to be
|
||||
active at once (though we do not currently enforce that in Synapse).
|
||||
|
||||
Keys used in End-to-End encryption
|
||||
----------------------------------
|
||||
|
||||
There are a number of keys involved in encrypted communication: a
|
||||
summary of them follows.
|
||||
|
||||
Ed25519 fingerprint key pair
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Ed25519 is a public-key cryptographic system for signing messages. In
|
||||
Matrix, each device has an Ed25519 key pair which serves to identify
|
||||
that device. The private part of the key pair should never leave the
|
||||
device, but the public part is published to the Matrix network.
|
||||
|
||||
Curve25519 identity key pair
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Curve25519 is a public-key cryptographic system which can be used to
|
||||
establish a shared secret. In Matrix, each device has a long-lived
|
||||
Curve25519 identity key which is used to establish Olm sessions with
|
||||
that device. Again, the private key should never leave the device, but
|
||||
the public part is signed with the Ed25519 fingerprint key and published
|
||||
to the network.
|
||||
|
||||
Theoretically we should rotate the Curve25519 identity key from time to
|
||||
time, but we haven't implemented this yet.
|
||||
|
||||
Curve25519 one-time keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As well as the identity key, each device creates a number of Curve25519
|
||||
key pairs which are also used to establish Olm sessions, but can only be
|
||||
used once. Once again, the private part remains on the device.
|
||||
|
||||
At startup, Alice creates a number of one-time key pairs, and publishes
|
||||
them to her homeserver. If Bob wants to establish an Olm session with
|
||||
Alice, he needs to claim one of Alice’s one-time keys, and creates a new
|
||||
one of his own. Those two keys, along with Alice’s and Bob’s identity
|
||||
keys, are used in establishing an Olm session between Alice and Bob.
|
||||
|
||||
Megolm encryption keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Megolm key is used to encrypt group messages (in fact it is used to
|
||||
derive an AES-256 key, and an HMAC-SHA-256 key). It is initialised with
|
||||
random data. Each time a message is sent, a hash calculation is done on
|
||||
the Megolm key to derive the key for the next message. It is therefore
|
||||
possible to share the current state of the Megolm key with a user,
|
||||
allowing them to decrypt future messages but not past messages.
|
||||
|
||||
Ed25519 Megolm signing key pair
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When a sender creates a Megolm session, he also creates another Ed25519
|
||||
signing key pair. This is used to sign messages sent via that Megolm
|
||||
session, to authenticate the sender. Once again, the private part of the
|
||||
key remains on the device. The public part is shared with other devices
|
||||
in the room alongside the encryption key.
|
||||
|
||||
Creating and registering device keys
|
||||
------------------------------------
|
||||
|
||||
This process only happens once, when a device first starts.
|
||||
|
||||
It must create the Ed25519 fingerprint key pair and the Curve25519
|
||||
identity key pair. This is done by calling ``olm_create_account`` in
|
||||
libolm. The (base64-encoded) keys are retrieved by calling
|
||||
``olm_account_identity_keys``. The account should be stored for future
|
||||
use.
|
||||
|
||||
It should then publish these keys to the homeserver. To do this, it
|
||||
should construct a JSON object as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"algorithms": ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
|
||||
"device_id": "<device_id>",
|
||||
"keys": {
|
||||
"curve25519:<device_id>": "<curve25519_key>",
|
||||
"ed25519:<device_id>": "<ed25519_key>"
|
||||
},
|
||||
"user_id: <user_id>"
|
||||
}
|
||||
|
||||
The object should be formatted as `Canonical
|
||||
JSON <http://matrix.org/docs/spec/server_server/unstable.html#canonical-json>`__,
|
||||
then signed with ``olm_account_sign``; the signature should be added to
|
||||
the JSON as ``signatures.<user_id>.ed25519:<device_id>``.
|
||||
|
||||
The signed JSON is then uploaded via
|
||||
``POST /_matrix/client/unstable/keys/upload``.
|
||||
|
||||
Creating and registering one-time keys
|
||||
--------------------------------------
|
||||
|
||||
At first start, and at regular intervals
|
||||
thereafter\ [#]_, the client should check how
|
||||
many one-time keys the homeserver has stored for it, and, if necessary,
|
||||
generate and upload some more.
|
||||
|
||||
.. [#] Every 10 minutes is suggested.
|
||||
|
||||
The number of one-time keys currently stored is returned by
|
||||
``POST /_matrix/client/unstable/keys/upload``. (Post an empty JSON object
|
||||
``{}`` if you don’t want to upload the device keys.)
|
||||
|
||||
The maximum number of active keys supported by libolm is returned by
|
||||
``olm_account_max_number_of_one_time_keys``. The client should try to
|
||||
maintain about half this number on the homeserver.
|
||||
|
||||
To generate new one-time keys:
|
||||
|
||||
* Call ``olm_account_generate_one_time_keys`` to generate new keys.
|
||||
|
||||
* Call ``olm_account_one_time_keys`` to retrieve the unpublished keys. This
|
||||
returns a JSON-formatted object with the single property ``curve25519``,
|
||||
which is itself an object mapping key id to base64-encoded Curve25519
|
||||
key. For example:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"curve25519": {
|
||||
"AAAAAA": "wo76WcYtb0Vk/pBOdmduiGJ0wIEjW4IBMbbQn7aSnTo",
|
||||
"AAAAAB": "LRvjo46L1X2vx69sS9QNFD29HWulxrmW11Up5AfAjgU"
|
||||
}
|
||||
}
|
||||
|
||||
* Each key should be signed with the account key. To do this:
|
||||
|
||||
* Construct a JSON object as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"key": "<curve25519_key>"
|
||||
}
|
||||
|
||||
* Call ``olm_account_sign`` to calculate the signature.
|
||||
|
||||
* Add the signature should be added to the JSON as
|
||||
``signatures.<user_id>.ed25519:<device_id>``.
|
||||
|
||||
* The complete key object should now look like:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"key": "wo76WcYtb0Vk/pBOdmduiGJ0wIEjW4IBMbbQn7aSnTo",
|
||||
"signatures": {
|
||||
"@alice:example.com": {
|
||||
"ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
* Aggregate all the signed one-time keys into a single JSON object as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"one_time_keys": {
|
||||
"signed_curve25519:<key_id>": {
|
||||
"key": "<curve25519_key>",
|
||||
"signatures": {
|
||||
"<user_id>": {
|
||||
"ed25519:<device_id>": "<signature>"
|
||||
}
|
||||
}
|
||||
},
|
||||
"signed_curve25519:<key_id>": {
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
* Upload the object via ``POST /_matrix/client/unstable/keys/upload``.
|
||||
|
||||
* Call ``olm_account_mark_keys_as_published`` to tell the olm library not to
|
||||
return the same keys from a future call to ``olm_account_one_time_keys``.
|
||||
|
||||
Configuring a room to use encryption
|
||||
------------------------------------
|
||||
|
||||
To enable encryption in a room, a client should send a state event of
|
||||
type ``m.room.encryption``, and content ``{ "algorithm":
|
||||
"m.megolm.v1.aes-sha2" }``.
|
||||
|
||||
.. |m.room.encryption| replace:: ``m.room.encryption``
|
||||
.. _`m.room.encryption`:
|
||||
|
||||
Handling an ``m.room.encryption`` state event
|
||||
---------------------------------------------
|
||||
|
||||
When a client receives an ``m.room.encryption`` event as above, it
|
||||
should set a flag to indicate that messages sent in the room should be
|
||||
encrypted.
|
||||
|
||||
This flag should **not** be cleared if a later ``m.room.encryption``
|
||||
event changes the configuration. This is to avoid a situation where a
|
||||
MITM can simply ask participants to disable encryption. In short: once
|
||||
encryption is enabled in a room, it can never be disabled.
|
||||
|
||||
The event should contain an ``algorithm`` property which defines which
|
||||
encryption algorithm should be used for encryption. Currently only
|
||||
``m.megolm.v1-aes-sha2`` is permitted here.
|
||||
|
||||
The event may also include other settings for how messages sent in the room
|
||||
should be encrypted (for example, ``rotation_period_ms`` to define how often
|
||||
the session should be replaced).
|
||||
|
||||
Handling an ``m.room.encrypted`` event
|
||||
--------------------------------------
|
||||
|
||||
Encrypted events have a type of ``m.room.encrypted``. They have a
|
||||
content property ``algorithm`` which gives the encryption algorithm in
|
||||
use, as well as other properties specific to the algorithm [#]_.
|
||||
|
||||
.. [#] Note that a redacted event will have an empty content, and hence the
|
||||
content will have no ``algorithm`` property. Thus a client should check
|
||||
whether an event is redacted before checking for the ``algorithm`` property.
|
||||
|
||||
The encrypted payload is a JSON object with the properties ``type``
|
||||
(giving the decrypted event type), and ``content`` (giving the decrypted
|
||||
content). Depending on the algorithm in use, the payload may contain
|
||||
additional keys.
|
||||
|
||||
There are currently two defined algorithms:
|
||||
|
||||
``m.olm.v1.curve25519-aes-sha2``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Encrypted events using this algorithm should have a ``sender_key`` and a
|
||||
``ciphertext`` property.
|
||||
|
||||
The ``sender_key`` property of the event content gives the Curve25519
|
||||
identity key of the sender. Clients should maintain a list of known Olm
|
||||
sessions for each device they speak to; it is recommended to index them
|
||||
by Curve25519 identity key.
|
||||
|
||||
Olm messages are encrypted separately for each recipient device.
|
||||
``ciphertext`` is an object mapping from the Curve25519 identity key for
|
||||
the recipient device. The receiving client should, of course, look for
|
||||
its own identity key in this object. (If it isn't listed, the message
|
||||
wasn't sent for it, and the client can't decrypt it; it should show an
|
||||
error instead, or similar).
|
||||
|
||||
This should result in an object with the properties ``type`` and
|
||||
``body``. Messages of type '0' are 'prekey' messages which are used to
|
||||
establish a new Olm session between two devices; type '1' are normal
|
||||
messages which are used once a message has been received on the session.
|
||||
|
||||
When a message (of either type) is received, a client should first
|
||||
attempt to decrypt it with each of the known sessions for that sender.
|
||||
There are two steps to this:
|
||||
|
||||
- If (and only if) ``type==0``, the client should call
|
||||
``olm_matches_inbound_session`` with the session and ``body``. This
|
||||
returns a flag indicating whether the message was encrypted using
|
||||
that session.
|
||||
|
||||
- The client calls ``olm_decrypt``, with the session, ``type``, and
|
||||
``body``. If this is successful, it returns the plaintext of the
|
||||
event.
|
||||
|
||||
If the client was unable to decrypt the message using any known sessions
|
||||
(or if there are no known sessions yet), **and** the message had type 0,
|
||||
**and** ``olm_matches_inbound_session`` wasn't true for any existing
|
||||
sessions, then the client can try establishing a new session. This is
|
||||
done as follows:
|
||||
|
||||
- Call ``olm_create_inbound_session_from`` using the olm account, and
|
||||
the ``sender_key`` and ``body`` of the message.
|
||||
|
||||
- If the session was established successfully:
|
||||
|
||||
- call ``olm_remove_one_time_keys`` to ensure that the same
|
||||
one-time-key cannot be reused.
|
||||
|
||||
- Call ``olm_decrypt`` with the new session
|
||||
|
||||
- Store the session for future use
|
||||
|
||||
At the end of this, the client will hopefully have successfully
|
||||
decrypted the payload.
|
||||
|
||||
As well as the ``type`` and ``content`` properties, the payload should
|
||||
contain a number of other properties. Each of these should be checked as
|
||||
follows [#]_.
|
||||
|
||||
``sender``
|
||||
The user ID of the sender. The client should check that this matches the
|
||||
``sender`` in the event.
|
||||
|
||||
``recipient``
|
||||
The user ID of the recipient. The client should check that this matches the
|
||||
local user ID.
|
||||
|
||||
``keys``
|
||||
an object with a property ``ed25519``, The client should check that the
|
||||
value of this property matches the sender's fingerprint key when `marking
|
||||
the event as verified`_\ .
|
||||
|
||||
``recipient_keys``
|
||||
an object with a property ``ed25519``. The client should check that the
|
||||
value of this property matches its own fingerprint key.
|
||||
|
||||
.. [#] These tests prevent an attacker publishing someone else's curve25519
|
||||
keys as their own and subsequently claiming to have sent messages which they
|
||||
didn't.
|
||||
|
||||
``m.megolm.v1.aes-sha2``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Encrypted events using this algorithm should have ``sender_key``,
|
||||
``session_id`` and ``ciphertext`` content properties. If the
|
||||
``room_id``, ``sender_key`` and ``session_id`` correspond to a known
|
||||
Megolm session (see `below`__), the ciphertext can be
|
||||
decrypted by passing the ciphertext into ``olm_group_decrypt``.
|
||||
|
||||
__ `m.room_key`_
|
||||
|
||||
In order to avoid replay attacks a client should remember the megolm
|
||||
``message_index`` returned by ``olm_group_decrypt`` of each event they decrypt
|
||||
for each session. If the client decrypts an event with the same
|
||||
``message_index`` as one that it has already received using that session then
|
||||
it should treat the message as invalid. However, care must be taken when an
|
||||
event is decrypted multiple times that it is not flagged as a replay attack.
|
||||
For example, this may happen when the client decrypts an event, the event gets
|
||||
purged from the client's cache, and then the client backfills and re-decrypts
|
||||
the event. One way to handle this case is to ensure that the record of
|
||||
``message_index``\ es is appropriately purged when the client's cache of events
|
||||
is purged. Another way is to remember the event's ``event_id`` and
|
||||
``origin_server_ts`` along with its ``message_index``. When the client decrypts
|
||||
an event with a ``message_index`` matching that of a previously-decrypted
|
||||
event, it can then compare the ``event_id`` and ``origin_server_ts`` that it
|
||||
remembered for that ``message_index``, and if those fields match, then the
|
||||
message should be decrypted as normal.
|
||||
|
||||
The client should check that the sender's fingerprint key matches the
|
||||
``keys.ed25519`` property of the event which established the Megolm session
|
||||
when `marking the event as verified`_.
|
||||
|
||||
.. _`m.room_key`:
|
||||
|
||||
Handling an ``m.room_key`` event
|
||||
--------------------------------
|
||||
|
||||
These events contain key data to allow decryption of other messages.
|
||||
They are sent to specific devices, so they appear in the ``to_device``
|
||||
section of the response to ``GET /_matrix/client/r0/sync``. They will
|
||||
also be encrypted, so will need decrypting as above before they can be
|
||||
seen. (These events are generated by other clients - see `starting a megolm
|
||||
session`_).
|
||||
|
||||
The event content will contain an 'algorithm' property, indicating the
|
||||
encryption algorithm the key data is to be used for. Currently, this
|
||||
will always be ``m.megolm.v1.aes-sha2``.
|
||||
|
||||
Room key events for Megolm will also have ``room_id``, ``session_id``, and
|
||||
``session_key`` keys. They are used to establish a Megolm session. The
|
||||
``room_id`` identifies which room the session will be used in. The ``room_id``,
|
||||
together with the ``sender_key`` of the ``room_key`` event before it was
|
||||
decrypted, and the ``session_id``, uniquely identify a Megolm session. If they
|
||||
do not represent a known session, the client should start a new inbound Megolm
|
||||
session by calling ``olm_init_inbound_group_session`` with the ``session_key``.
|
||||
|
||||
The client should remember the value of the keys property of the payload
|
||||
of the encrypted ``m.room_key`` event and store it with the inbound
|
||||
session. This is used as above when marking the event as verified.
|
||||
|
||||
.. _`download the device list`:
|
||||
|
||||
Downloading the device list for users in the room
|
||||
-------------------------------------------------
|
||||
|
||||
Before an encrypted message can be sent, it is necessary to retrieve the
|
||||
list of devices for each user in the room. This can be done proactively,
|
||||
or deferred until the first message is sent. The information is also
|
||||
required to allow users to `verify or block devices`__.
|
||||
|
||||
__ `blocking`_
|
||||
|
||||
The client should build a JSON query object as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"device_keys": {
|
||||
"<user_id>": {},
|
||||
[...]
|
||||
}
|
||||
}
|
||||
|
||||
Each member in the room should be included in the query. This is then
|
||||
sent via ``POST /_matrix/client/unstable/keys/query.``
|
||||
|
||||
The result includes, for each listed user id, a map from device ID to an
|
||||
object containing information on the device, as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"algorithms": [...],
|
||||
"device_id": "<device_id>",
|
||||
"keys": {
|
||||
"curve25519:<device_id>": "<curve25519_key>",
|
||||
"ed25519:<device_id>": "<ed25519_key>"
|
||||
},
|
||||
"signatures": {
|
||||
"<userId>": {
|
||||
"ed25519:<device_id>": "<signature>"
|
||||
},
|
||||
},
|
||||
"unsigned": {
|
||||
"device_display_name": "<display name>"
|
||||
},
|
||||
"user_id: <user_id>"
|
||||
}
|
||||
|
||||
The client should first check the signature on this object. To do this,
|
||||
it should remove the ``signatures`` and ``unsigned`` properties, format
|
||||
the remainder as Canonical JSON, and pass the result into
|
||||
``olm_ed25519_verify``, using the Ed25519 key for the ``key`` parameter,
|
||||
and the corresponding signature for the ``signature`` parameter. If the
|
||||
signature check fails, no further processing should be done on the
|
||||
device.
|
||||
|
||||
The client must also check that the ``user_id`` and ``device_id`` fields in the
|
||||
object match those in the top-level map [#]_.
|
||||
|
||||
The client should check if the ``user_id``/``device_id`` correspond to a device
|
||||
it had seen previously. If it did, the client **must** check that the Ed25519
|
||||
key hasn't changed. Again, if it has changed, no further processing should be
|
||||
done on the device.
|
||||
|
||||
Otherwise the client stores the information about this device.
|
||||
|
||||
.. [#] This prevents a malicious or compromised homeserver replacing the keys
|
||||
for the device with those of another.
|
||||
|
||||
Sending an encrypted event
|
||||
--------------------------
|
||||
|
||||
When sending a message in a room `configured to use encryption`__, a client
|
||||
first checks to see if it has an active outbound Megolm session. If not, it
|
||||
first `creates one as per below`__. If an outbound session exists, it should
|
||||
check if it is time to `rotate`__ it, and create a new one if so.
|
||||
|
||||
__ `Configuring a room to use encryption`_
|
||||
__ `Starting a Megolm session`_
|
||||
__ `Rotating Megolm sessions`_
|
||||
|
||||
The client then builds an encryption payload as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"type": "<event type>",
|
||||
"content": "<event content>",
|
||||
"room_id": "<id of destination room>"
|
||||
}
|
||||
|
||||
and calls ``olm_group_encrypt`` to encrypt the payload. This is then packaged
|
||||
into event content as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"sender_key": "<our curve25519 device key>",
|
||||
"ciphertext": "<encrypted payload>",
|
||||
"session_id": "<outbound group session id>",
|
||||
"device_id": "<our device ID>"
|
||||
}
|
||||
|
||||
Finally, the encrypted event is sent to the room with ``POST
|
||||
/_matrix/client/r0/rooms/<room_id>/send/m.room.encrypted/<txn_id>``.
|
||||
|
||||
Starting a Megolm session
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When a message is first sent in an encrypted room, the client should
|
||||
start a new outbound Megolm session. This should **not** be done
|
||||
proactively, to avoid proliferation of unnecessary Megolm sessions.
|
||||
|
||||
To create the session, the client should call
|
||||
``olm_init_outbound_group_session``, and store the details of the
|
||||
outbound session for future use.
|
||||
|
||||
The client should then call ``olm_outbound_group_session_id`` to get the
|
||||
unique ID of the new session, and ``olm_outbound_group_session_key`` to
|
||||
retrieve the current ratchet key and index. It should store these
|
||||
details as an inbound session, just as it would when `receiving them via
|
||||
an m.room_key event`__.
|
||||
|
||||
__ `m.room_key`_
|
||||
|
||||
The client must then share the keys for this session with each device in the
|
||||
room. It must therefore `download the device list`_ if it hasn't already done
|
||||
so, and for each device in the room which has not been `blocked`__, the client
|
||||
should:
|
||||
|
||||
__ `blocking`_
|
||||
|
||||
* Build a content object as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"room_id": "<id of destination room>",
|
||||
"session_id": "<session id>",
|
||||
"session_key": "<session_key>"
|
||||
}
|
||||
|
||||
- Encrypt the content as an ``m.room_key`` event using Olm, as below.
|
||||
|
||||
Once all of the key-sharing event contents have been assembled, the
|
||||
events should be sent to the corresponding devices via
|
||||
``PUT /_matrix/client/unstable/sendToDevice/m.room.encrypted/<txnId>``.
|
||||
|
||||
Rotating Megolm sessions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Megolm sessions may not be reused indefinitely.
|
||||
|
||||
The number of messages which can be sent before a session should be rotated is
|
||||
given by the ``rotation_period_msgs`` property of the |m.room.encryption|_
|
||||
event, or ``100`` if that property isn't present.
|
||||
|
||||
Similarly, the maximum age of a megolm session is given, in milliseconds, by
|
||||
the ``rotation_period_ms`` property of the ``m.room.encryption``
|
||||
event. ``604800000`` (a week) is the recommended default here.
|
||||
|
||||
Once either the message limit or time limit have been reached, the client
|
||||
should start a new session before sending any more messages.
|
||||
|
||||
|
||||
Encrypting an event with Olm
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Olm is not used for encrypting room events, as it requires a separate
|
||||
copy of the ciphertext for each device, and because the receiving device
|
||||
can only decrypt received messages once. However, it is used for
|
||||
encrypting key-sharing events for Megolm.
|
||||
|
||||
When encrypting an event using Olm, the client should:
|
||||
|
||||
- Build an encryption payload as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"type": "<event type>",
|
||||
"content": "<event content>",
|
||||
"sender": "<our user ID>",
|
||||
"sender_device": "<our device ID>",
|
||||
"keys": {
|
||||
"ed25519": "<our ed25519 fingerprint key>"
|
||||
},
|
||||
"recipient": "<recipient user ID>",
|
||||
"recipient_keys": {
|
||||
"ed25519": "<recipient's ed25519 fingerprint key>"
|
||||
},
|
||||
}
|
||||
|
||||
- Check if it has an existing Olm session; if it does not, `start a new
|
||||
one`__. If it has several (as may happen due to
|
||||
races when establishing sessions), it should use the one with the
|
||||
first session_id when sorted by their ASCII codepoints (ie, 'A'
|
||||
would be before 'Z', which would be before 'a').
|
||||
|
||||
__ `Starting an Olm session`_
|
||||
|
||||
- Encrypt the payload by calling ``olm_encrypt``.
|
||||
|
||||
- Package the payload into event content as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"algorithm": "m.olm.v1.curve25519-aes-sha2",
|
||||
"sender_key": "<our curve25519 identity key>",
|
||||
"ciphertext": "<encrypted payload>"
|
||||
}
|
||||
|
||||
Starting an Olm session
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To start a new Olm session with another device, a client must first
|
||||
claim one of the other device's one-time keys. To do this, it should
|
||||
create a query object as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"<user id>": {
|
||||
"<device_id>": "signed_curve25519",
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
|
||||
and send this via ``POST /_matrix/client/unstable/keys/claim``. Claims
|
||||
for multiple devices should be aggregated into a single request.
|
||||
|
||||
This will return a result as follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"one_time_keys": {
|
||||
"<user id>": {
|
||||
"<device_id>": {
|
||||
"signed_curve25519:<key_id>": {
|
||||
"key": "<curve25519_key>",
|
||||
"signatures": {
|
||||
"<user_id>": {
|
||||
"ed25519:<device_id>": "<signature>"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
The client should first check the signatures on the signed key objects. As with
|
||||
checking the signatures on the device keys, it should remove the ``signatures``
|
||||
and (if present) ``unsigned`` properties, format the remainder as Canonical
|
||||
JSON, and pass the result into ``olm_ed25519_verify``, using the Ed25519 device
|
||||
key for the ``key`` parameter.
|
||||
|
||||
Provided the key object passes verification, the client should then pass the
|
||||
key, along with the Curve25519 Identity key for the remote device, into
|
||||
``olm_create_outbound_session``.
|
||||
|
||||
Handling membership changes
|
||||
---------------------------
|
||||
|
||||
The client should monitor rooms which are configured to use encryption for
|
||||
membership changes.
|
||||
|
||||
When a member leaves a room, the client should invalidate any active outbound
|
||||
Megolm session, to ensure that a new session is used next time the user sends a
|
||||
message.
|
||||
|
||||
When a new member joins a room, the client should first `download the device
|
||||
list`_ for the new member, if it doesn't already have it.
|
||||
|
||||
After giving the user an opportunity to `block`__ any suspicious devices, the
|
||||
client should share the keys for the outbound Megolm session with all the new
|
||||
member's devices. This is done in the same way as `creating a new session`__,
|
||||
except that there is no need to start a new Megolm session: due to the design
|
||||
of the Megolm ratchet, the new user will only be able to decrypt messages
|
||||
starting from the current state. The recommended method is to maintain a list
|
||||
of members who are waiting for the session keys, and share them when the user
|
||||
next sends a message.
|
||||
|
||||
__ `blocking`_
|
||||
__ `Starting a Megolm session`_
|
||||
|
||||
Sending New Device announcements
|
||||
--------------------------------
|
||||
|
||||
When a user logs in on a new device, it is necessary to make sure that
|
||||
other devices in any rooms with encryption enabled are aware of the new
|
||||
device. This is done as follows.
|
||||
|
||||
Once the initial call to the ``/sync`` API completes, the client should
|
||||
iterate through each room where encryption is enabled. For each user
|
||||
(including the client's own user), it should build a content object as
|
||||
follows:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"device_id": "<our device ID>",
|
||||
"rooms": ["<shared room id 1>", "<room id 2>", ... ]
|
||||
}
|
||||
|
||||
Once all of these have been constructed, they should be sent to all of the
|
||||
relevant user's devices (using the wildcard ``*`` in place of the
|
||||
``device_id``) via ``PUT
|
||||
/_matrix/client/unstable/sendToDevice/m.new_device/<txnId>.``
|
||||
|
||||
Handling an ``m.new_device`` event
|
||||
----------------------------------
|
||||
|
||||
As with ``m.room_key`` events, these will appear in the ``to_device``
|
||||
section of the ``/sync`` response.
|
||||
|
||||
The client should `download the device list`_ of the sender, to get the details
|
||||
of the new device.
|
||||
|
||||
The event content will contain a ``rooms`` property, as well as the
|
||||
``device_id`` of the new device. For each room in the list, the client
|
||||
should check if encryption is enabled, and if the sender of the event is
|
||||
a member of that room. If so, the client should share the keys for the
|
||||
outbound Megolm session with the new device, in the same way as
|
||||
`handling a new user in the room`__.
|
||||
|
||||
__ `Handling membership changes`_
|
||||
|
||||
.. _`blocking`:
|
||||
|
||||
Blocking / Verifying devices
|
||||
----------------------------
|
||||
|
||||
It should be possible for a user to mark each device belonging to
|
||||
another user as 'Blocked' or 'Verified'.
|
||||
|
||||
When a user chooses to block a device, this means that no further
|
||||
encrypted messages should be shared with that device. In short, it
|
||||
should be excluded when sharing room keys when `starting a new Megolm
|
||||
session <#_p5d1esx6gkrc>`__. Any active outbound Megolm sessions whose
|
||||
keys have been shared with the device should also be invalidated so that
|
||||
no further messages are sent over them.
|
||||
|
||||
Verifying a device involves ensuring that the device belongs to the
|
||||
claimed user. Currently this must be done by showing the user the
|
||||
Ed25519 fingerprint key for the device, and prompting the user to verify
|
||||
out-of-band that it matches the key shown on the other user's device.
|
||||
|
||||
.. _`marking the event as verified`:
|
||||
|
||||
Marking events as 'verified'
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once a device has been verified, it is possible to verify that events
|
||||
have been sent from a particular device. See the section on `Handling an
|
||||
m.room.encrypted event`_ for notes on how to do this
|
||||
for each algorithm. Events sent from a verified device can be decorated
|
||||
in the UI to show that they have been sent from a verified device.
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
layout: post
|
||||
version: v1.0
|
||||
title: Types of Bridging
|
||||
categories: guides
|
||||
---
|
||||
<link href="/docs/css/faq.css" type="text/css" rel="stylesheet" />
|
||||
|
||||
# Types of bridging
|
||||
|
||||
Bridges come in many flavours, and we need consistent terminology within the Matrix community to ensure everyone (users, developers, core team) is on the same page. This post is primarily intended for bridge developers to refer to when building bridges.
|
||||
|
||||
*The most recent version of this document is [here](https://matrix.org/docs/guides/types-of-bridging.html) ([source](https://github.com/matrix-org/matrix-doc/blob/master/supporting-docs/guides/2017-03-11-types-of-bridging.md)) but we’re also posting it as a blog post for visibility.*
|
||||
|
||||
## Types of rooms
|
||||
|
||||
### Portal rooms
|
||||
|
||||
Bridges can register themselves as controlling chunks of room aliases namespace, letting Matrix users join remote rooms transparently if they /join #freenode_#wherever:matrix.org or similar. The resulting Matrix room is typically automatically bridged to the single target remote room. Access control for Matrix users is typically managed by the remote network’s side of the room. This is called a portal room, and is useful for jumping into remote rooms without any configuration needed whatsoever - using Matrix as a ‘bouncer’ for the remote network.
|
||||
|
||||
### Plumbed rooms
|
||||
|
||||
Alternatively, an existing Matrix room can be can plumbed into one or more specific remote rooms by configuring a bridge (which can be run by anyone). For instance, #matrix:matrix.org is plumbed into #matrix on Freenode, matrixdotorg/#matrix on Slack, etc. Access control for Matrix users is necessarily managed by the Matrix side of the room. This is useful for using Matrix to link together different communities.
|
||||
|
||||
Migrating rooms between a portal & plumbed room is currently a bit of a mess, as there’s not yet a way for users to remove portal rooms once they’re created, so you can end up with a mix of portal & plumbed users bridged into a room, which looks weird from both the Matrix and non-Matrix viewpoints. https://github.com/matrix-org/matrix-appservice-irc/issues/387 tracks this.
|
||||
|
||||
## Types of bridges (simplest first):
|
||||
|
||||
### Bridgebot-based bridges
|
||||
|
||||
The simplest way to exchange messages with a remote network is to have the bridge log into the network using one or more predefined users called bridge bots - typically called MatrixBridge or MatrixBridge[123] etc. These relay traffic on behalf of the users on the other side, but it’s a terrible experience as all the metadata about the messages and senders is lost. This is how the [telematrix](https://github.com/SijmenSchoon/telematrix) matrix<->telegram bridge currently works.
|
||||
|
||||
### Bot-API (aka Virtual user) based bridges
|
||||
|
||||
Some remote systems support the idea of injecting messages from ‘fake’ or ‘virtual’ users, which can be used to represent the Matrix-side users as unique entities in the remote network. For instance, Slack’s inbound webhooks lets remote bots be created on demand, letting Matrix users be shown cosmetically correctly in the timeline as virtual users. However, the resulting virtual users aren’t real users on the remote system, so don’t have presence/profile and can’t be tab-completed or direct-messaged etc. They also have no way to receive typing notifs or other richer info which may not be available via bot APIs. This is how the current [matrix-appservice-slack](https://github.com/matrix-org/matrix-appservice-slack) bridge works.
|
||||
|
||||
### Simple puppeted bridge
|
||||
|
||||
This is a richer form of bridging, where the bridge logs into the remote service as if it were a real 3rd party client for that service. As a result, the Matrix user has to already have a valid account on the remote system. In exchange, the Matrix user ‘puppets’ their remote user, such that other users on the remote system aren’t even aware they are speaking to a user via Matrix. The full semantics of the remote system are available to the bridge to expose into Matrix. However, the bridge has to handle the authentication process to log the user into the remote bridge.
|
||||
|
||||
This is essentially how the current [matrix-appservice-irc](https://github.com/matrix-org/matrix-appservice-irc) bridge works (if you configure it to log into the remote IRC network as your ‘real’ IRC nickname). [matrix-appservice-gitter](https://github.com/matrix-org/matrix-appservice-gitter) is being extended to support both puppeted and bridgebot-based operation. It’s how the experimental [matrix-appservice-tg](https://github.com/matrix-org/matrix-appservice-tg) bridge works.
|
||||
|
||||
Going forwards we’re aiming for all bridges to be at least simple puppeted, if not double-puppeted.
|
||||
|
||||
### Double-puppeted bridge
|
||||
|
||||
A simple ‘puppeted bridge’ allows the Matrix user to control their account on their remote network. However, ideally this puppeting should work in both directions, so if the user logs into (say) their native telegram client and starts conversations, sends messages etc, these should be reflected back into Matrix as if the user had done them there. This requires the bridge to be able to puppet the Matrix side of the bridge on behalf of the user.
|
||||
|
||||
This is the holy-grail of bridging because both the Matrix account and the third party account are accurately represented on their respective networks, with all user metadata intact. This is in contrast to a relaybot which would appear as a separate user from whom it represents.
|
||||
|
||||
Several obstacles exist to the proper implementation of double-puppeted bridges. On the Matrix side, we need an elegant way of having the bridge auth with Matrix as the matrix user (which requires some kind of scoped access_token delegation). On the third-party network, unique problems exist depending on the limitations of that particular network network. For example, many third party networks will lack the ability to represent other Matrix users than the one being puppeted (see hybrid relaybot).
|
||||
|
||||
[matrix-puppet-bridge](https://github.com/matrix-hacks/matrix-puppet-bridge) is a community project that tries to facilitate development of double-puppeted bridges, having done so, without a bridgebot feature, for [several networks](https://github.com/matrix-hacks/matrix-puppet-bridge#examples). A downside to their approach is the assumption that an individual will run the bridge on their own homeserver, thus working around the problem of sharing auth credentials on a shared homeserver.
|
||||
|
||||
### Hybrid Relaybot Puppet Bridge
|
||||
|
||||
This type of bridge is a combination single or double puppet bridge which tries to solve the problem of representing other users by means of the bridgebot technique. [matrix-appservice-gitter](https://github.com/matrix-org/matrix-appservice-gitter) works in this way.
|
||||
|
||||
### Server-to-server bridging
|
||||
|
||||
Some remote protocols (IRC, XMPP, SIP, SMTP, NNTP, GnuSocial etc) support federation - either open or closed. The most elegant way of bridging to these protocols would be to have the bridge participate in the federation as a server, directly bridging the entire namespace into Matrix.
|
||||
|
||||
We’re not aware of anyone who’s done this yet.
|
||||
|
||||
### One-way bridging
|
||||
|
||||
One-way bridging is rare, but can be used to represent a bridge that is bridging from the remote system into matrix. This is common when the remote system does not permit message posting, or is simply not capable of handling posting outside their system. The users bridged from the remote system often appear as virtual users in matrix, as is the case with [matrix-appservice-instagram](https://github.com/turt2live/matrix-appservice-instagram).
|
||||
|
||||
### Sidecar bridge
|
||||
|
||||
Finally: the types of bridging described above assume that you are synchronising the conversation history of the remote system into Matrix, so it may be decentralised and exposed to multiple users within the wider Matrix network.
|
||||
|
||||
This can cause problems where the remote system may have arbitrarily complicated permissions (ACLs) controlling access to the history, which will then need to be correctly synchronised with Matrix’s ACL model, without introducing security issues such as races. We already see some problems with this on the IRC bridge, where history visibility for +i and +k channels have to be carefully synchronised with the Matrix rooms.
|
||||
|
||||
You can also hit problems with other network-specific features not yet having equivalent representation in the Matrix protocol (e.g. ephemeral messages, or op-only messages - although arguably that’s a type of ACL).
|
||||
|
||||
One solution could be to support an entirely different architecture of bridging, where the Matrix client-server API is mapped directly to the remote service, meaning that ACL decisions are delegated to the remote service, and conversations are not exposed into the wider Matrix. This is effectively using the bridge purely as a 3rd party client for the network (similar to Bitlbee). The bridge is only available to a single user, and conversations cannot be shared with other Matrix users as they aren’t actually Matrix rooms. (Another solution could be to use Active Policy Servers at last as a way of centralising and delegating ACLs for a room)
|
||||
|
||||
This is essentially an entirely different product to the rest of Matrix, and whilst it could be a solution for some particularly painful ACL problems, we’re focusing on non-sidecar bridges for now.
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Try Matrix Now!
|
||||
categories: howtos
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=../guides/client-server.html" />
|
||||
</head>
|
||||
</html>
|
|
@ -1,17 +0,0 @@
|
|||
.loggedin {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-spacing:5px;
|
||||
}
|
||||
|
||||
th,td
|
||||
{
|
||||
padding:5px;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<div>
|
||||
<p>This room creation / message sending demo requires a homeserver to be running on http://localhost:8008</p>
|
||||
</div>
|
||||
<form class="loginForm">
|
||||
<input type="text" id="userLogin" placeholder="Username"></input>
|
||||
<input type="password" id="passwordLogin" placeholder="Password"></input>
|
||||
<input type="button" class="login" value="Login"></input>
|
||||
</form>
|
||||
<div class="loggedin">
|
||||
<form class="createRoomForm">
|
||||
<input type="text" id="roomAlias" placeholder="Room alias (optional)"></input>
|
||||
<input type="button" class="createRoom" value="Create Room"></input>
|
||||
</form>
|
||||
<form class="sendMessageForm">
|
||||
<input type="text" id="roomId" placeholder="Room ID"></input>
|
||||
<input type="text" id="messageBody" placeholder="Message body"></input>
|
||||
<input type="button" class="sendMessage" value="Send Message"></input>
|
||||
</form>
|
||||
<table id="rooms">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Room ID</th>
|
||||
<th>My state</th>
|
||||
<th>Room Alias</th>
|
||||
<th>Latest message</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
var accountInfo = {};
|
||||
|
||||
var showLoggedIn = function(data) {
|
||||
accountInfo = data;
|
||||
getCurrentRoomList();
|
||||
$(".loggedin").css({visibility: "visible"});
|
||||
};
|
||||
|
||||
$('.login').live('click', function() {
|
||||
var user = $("#userLogin").val();
|
||||
var password = $("#passwordLogin").val();
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/login",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({ user: user, password: password, type: "m.login.password" }),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
showLoggedIn(data);
|
||||
},
|
||||
error: function(err) {
|
||||
var errMsg = "To try this, you need a homeserver running!";
|
||||
var errJson = $.parseJSON(err.responseText);
|
||||
if (errJson) {
|
||||
errMsg = JSON.stringify(errJson);
|
||||
}
|
||||
alert(errMsg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var getCurrentRoomList = function() {
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/initialSync?access_token=" + accountInfo.access_token + "&limit=1";
|
||||
$.getJSON(url, function(data) {
|
||||
var rooms = data.rooms;
|
||||
for (var i=0; i<rooms.length; ++i) {
|
||||
rooms[i].latest_message = rooms[i].messages.chunk[0].content.body;
|
||||
addRoom(rooms[i]);
|
||||
}
|
||||
}).fail(function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
});
|
||||
};
|
||||
|
||||
$('.createRoom').live('click', function() {
|
||||
var roomAlias = $("#roomAlias").val();
|
||||
var data = {};
|
||||
if (roomAlias.length > 0) {
|
||||
data.room_alias_name = roomAlias;
|
||||
}
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/createRoom?access_token="+accountInfo.access_token,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
data.membership = "join"; // you are automatically joined into every room you make.
|
||||
data.latest_message = "";
|
||||
addRoom(data);
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var addRoom = function(data) {
|
||||
row = "<tr>" +
|
||||
"<td>"+data.room_id+"</td>" +
|
||||
"<td>"+data.membership+"</td>" +
|
||||
"<td>"+data.room_alias+"</td>" +
|
||||
"<td>"+data.latest_message+"</td>" +
|
||||
"</tr>";
|
||||
$("#rooms").append(row);
|
||||
};
|
||||
|
||||
$('.sendMessage').live('click', function() {
|
||||
var roomId = $("#roomId").val();
|
||||
var body = $("#messageBody").val();
|
||||
var msgId = $.now();
|
||||
|
||||
if (roomId.length === 0 || body.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/rooms/$roomid/send/m.room.message?access_token=$token";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$roomid", encodeURIComponent(roomId));
|
||||
|
||||
var data = {
|
||||
msgtype: "m.text",
|
||||
body: body
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
$("#messageBody").val("");
|
||||
// wipe the table and reload it. Using the event stream would be the best
|
||||
// solution but that is out of scope of this fiddle.
|
||||
$("#rooms").find("tr:gt(0)").remove();
|
||||
getCurrentRoomList();
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,17 +0,0 @@
|
|||
.loggedin {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-spacing:5px;
|
||||
}
|
||||
|
||||
th,td
|
||||
{
|
||||
padding:5px;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<div>
|
||||
<p>This event stream demo requires a homeserver to be running on http://localhost:8008</p>
|
||||
</div>
|
||||
<form class="loginForm">
|
||||
<input type="text" id="userLogin" placeholder="Username"></input>
|
||||
<input type="password" id="passwordLogin" placeholder="Password"></input>
|
||||
<input type="button" class="login" value="Login"></input>
|
||||
</form>
|
||||
<div class="loggedin">
|
||||
<form class="sendMessageForm">
|
||||
<input type="button" class="sendMessage" value="Send random message"></input>
|
||||
</form>
|
||||
<p id="streamErrorText"></p>
|
||||
<table id="rooms">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Room ID</th>
|
||||
<th>Latest message</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
var accountInfo = {};
|
||||
|
||||
var eventStreamInfo = {
|
||||
from: "END"
|
||||
};
|
||||
|
||||
var roomInfo = [];
|
||||
|
||||
var longpollEventStream = function() {
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/events?access_token=$token&from=$from";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$from", eventStreamInfo.from);
|
||||
|
||||
$.getJSON(url, function(data) {
|
||||
eventStreamInfo.from = data.end;
|
||||
|
||||
var hasNewLatestMessage = false;
|
||||
for (var i=0; i<data.chunk.length; ++i) {
|
||||
if (data.chunk[i].type === "m.room.message") {
|
||||
for (var j=0; j<roomInfo.length; ++j) {
|
||||
if (roomInfo[j].room_id === data.chunk[i].room_id) {
|
||||
roomInfo[j].latest_message = data.chunk[i].content.body;
|
||||
hasNewLatestMessage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNewLatestMessage) {
|
||||
setRooms(roomInfo);
|
||||
}
|
||||
$("#streamErrorText").text("");
|
||||
longpollEventStream();
|
||||
}).fail(function(err) {
|
||||
$("#streamErrorText").text("Event stream error: "+JSON.stringify($.parseJSON(err.responseText)));
|
||||
setTimeout(longpollEventStream, 5000);
|
||||
});
|
||||
};
|
||||
|
||||
var showLoggedIn = function(data) {
|
||||
accountInfo = data;
|
||||
longpollEventStream();
|
||||
getCurrentRoomList();
|
||||
$(".loggedin").css({visibility: "visible"});
|
||||
};
|
||||
|
||||
$('.login').live('click', function() {
|
||||
var user = $("#userLogin").val();
|
||||
var password = $("#passwordLogin").val();
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/login",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({ user: user, password: password, type: "m.login.password" }),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
$("#rooms").find("tr:gt(0)").remove();
|
||||
showLoggedIn(data);
|
||||
},
|
||||
error: function(err) {
|
||||
var errMsg = "To try this, you need a homeserver running!";
|
||||
var errJson = $.parseJSON(err.responseText);
|
||||
if (errJson) {
|
||||
errMsg = JSON.stringify(errJson);
|
||||
}
|
||||
alert(errMsg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var getCurrentRoomList = function() {
|
||||
$("#roomId").val("");
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/initialSync?access_token=" + accountInfo.access_token + "&limit=1";
|
||||
$.getJSON(url, function(data) {
|
||||
var rooms = data.rooms;
|
||||
for (var i=0; i<rooms.length; ++i) {
|
||||
if ("messages" in rooms[i]) {
|
||||
rooms[i].latest_message = rooms[i].messages.chunk[0].content.body;
|
||||
}
|
||||
}
|
||||
roomInfo = rooms;
|
||||
setRooms(roomInfo);
|
||||
}).fail(function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
});
|
||||
};
|
||||
|
||||
$('.sendMessage').live('click', function() {
|
||||
if (roomInfo.length === 0) {
|
||||
alert("There is no room to send a message to!");
|
||||
return;
|
||||
}
|
||||
|
||||
var index = Math.floor(Math.random() * roomInfo.length);
|
||||
|
||||
sendMessage(roomInfo[index].room_id);
|
||||
});
|
||||
|
||||
var sendMessage = function(roomId) {
|
||||
var body = "jsfiddle message @" + $.now();
|
||||
|
||||
if (roomId.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/rooms/$roomid/send/m.room.message?access_token=$token";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$roomid", encodeURIComponent(roomId));
|
||||
|
||||
var data = {
|
||||
msgtype: "m.text",
|
||||
body: body
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
$("#messageBody").val("");
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var setRooms = function(roomList) {
|
||||
// wipe existing entries
|
||||
$("#rooms").find("tr:gt(0)").remove();
|
||||
|
||||
var rows = "";
|
||||
for (var i=0; i<roomList.length; ++i) {
|
||||
row = "<tr>" +
|
||||
"<td>"+roomList[i].room_id+"</td>" +
|
||||
"<td>"+roomList[i].latest_message+"</td>" +
|
||||
"</tr>";
|
||||
rows += row;
|
||||
}
|
||||
|
||||
$("#rooms").append(rows);
|
||||
};
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
.roomListDashboard, .roomContents, .sendMessageForm {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.roomList {
|
||||
background-color: #909090;
|
||||
}
|
||||
|
||||
.messageWrapper {
|
||||
background-color: #EEEEEE;
|
||||
height: 400px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.membersWrapper {
|
||||
background-color: #EEEEEE;
|
||||
height: 200px;
|
||||
width: 50%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.textEntry {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-spacing:5px;
|
||||
}
|
||||
|
||||
th,td
|
||||
{
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.roomList tr:not(:first-child):hover {
|
||||
background-color: orange;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
name: Example Matrix Client
|
||||
description: Includes login, live event streaming, creating rooms, sending messages and viewing member lists.
|
||||
authors:
|
||||
- matrix.org
|
||||
resources:
|
||||
- http://matrix.org
|
||||
normalize_css: no
|
|
@ -1,56 +0,0 @@
|
|||
<div class="signUp">
|
||||
<p>Matrix example application: Requires a local homeserver running at http://localhost:8008</p>
|
||||
<form class="registrationForm">
|
||||
<p>No account? Register:</p>
|
||||
<input type="text" id="userReg" placeholder="Username"></input>
|
||||
<input type="password" id="passwordReg" placeholder="Password"></input>
|
||||
<input type="button" class="register" value="Register"></input>
|
||||
</form>
|
||||
<form class="loginForm">
|
||||
<p>Got an account? Login:</p>
|
||||
<input type="text" id="userLogin" placeholder="Username"></input>
|
||||
<input type="password" id="passwordLogin" placeholder="Password"></input>
|
||||
<input type="button" class="login" value="Login"></input>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="roomListDashboard">
|
||||
<form class="createRoomForm">
|
||||
<input type="text" id="roomAlias" placeholder="Room alias"></input>
|
||||
<input type="button" class="createRoom" value="Create Room"></input>
|
||||
</form>
|
||||
<table id="rooms" class="roomList">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Room</th>
|
||||
<th>My state</th>
|
||||
<th>Latest message</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="roomContents">
|
||||
<p id="roomName">Select a room</p>
|
||||
<div class="messageWrapper">
|
||||
<table id="messages">
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<form class="sendMessageForm">
|
||||
<input type="text" class="textEntry" id="body" placeholder="Enter text here..." onkeydown="javascript:if (event.keyCode == 13) document.getElementById('sendMsg').focus()"></input>
|
||||
<input type="button" class="sendMessage" id="sendMsg" value="Send"></input>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p>Member list:</p>
|
||||
<div class="membersWrapper">
|
||||
<table id="members">
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,327 +0,0 @@
|
|||
var accountInfo = {};
|
||||
|
||||
var eventStreamInfo = {
|
||||
from: "END"
|
||||
};
|
||||
|
||||
var roomInfo = [];
|
||||
var memberInfo = [];
|
||||
var viewingRoomId;
|
||||
|
||||
// ************** Event Streaming **************
|
||||
var longpollEventStream = function() {
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/events?access_token=$token&from=$from";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$from", eventStreamInfo.from);
|
||||
|
||||
$.getJSON(url, function(data) {
|
||||
eventStreamInfo.from = data.end;
|
||||
|
||||
var hasNewLatestMessage = false;
|
||||
var updatedMemberList = false;
|
||||
var i=0;
|
||||
var j=0;
|
||||
for (i=0; i<data.chunk.length; ++i) {
|
||||
if (data.chunk[i].type === "m.room.message") {
|
||||
console.log("Got new message: " + JSON.stringify(data.chunk[i]));
|
||||
if (viewingRoomId === data.chunk[i].room_id) {
|
||||
addMessage(data.chunk[i]);
|
||||
}
|
||||
|
||||
for (j=0; j<roomInfo.length; ++j) {
|
||||
if (roomInfo[j].room_id === data.chunk[i].room_id) {
|
||||
roomInfo[j].latest_message = data.chunk[i].content.body;
|
||||
hasNewLatestMessage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.chunk[i].type === "m.room.member") {
|
||||
if (viewingRoomId === data.chunk[i].room_id) {
|
||||
console.log("Got new member: " + JSON.stringify(data.chunk[i]));
|
||||
addMessage(data.chunk[i]);
|
||||
for (j=0; j<memberInfo.length; ++j) {
|
||||
if (memberInfo[j].state_key === data.chunk[i].state_key) {
|
||||
memberInfo[j] = data.chunk[i];
|
||||
updatedMemberList = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!updatedMemberList) {
|
||||
memberInfo.push(data.chunk[i]);
|
||||
updatedMemberList = true;
|
||||
}
|
||||
}
|
||||
if (data.chunk[i].state_key === accountInfo.user_id) {
|
||||
getCurrentRoomList(); // update our join/invite list
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("Discarding: " + JSON.stringify(data.chunk[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNewLatestMessage) {
|
||||
setRooms(roomInfo);
|
||||
}
|
||||
if (updatedMemberList) {
|
||||
$("#members").empty();
|
||||
for (i=0; i<memberInfo.length; ++i) {
|
||||
addMember(memberInfo[i]);
|
||||
}
|
||||
}
|
||||
longpollEventStream();
|
||||
}).fail(function(err) {
|
||||
setTimeout(longpollEventStream, 5000);
|
||||
});
|
||||
};
|
||||
|
||||
// ************** Registration and Login **************
|
||||
var onLoggedIn = function(data) {
|
||||
accountInfo = data;
|
||||
longpollEventStream();
|
||||
getCurrentRoomList();
|
||||
$(".roomListDashboard").css({visibility: "visible"});
|
||||
$(".roomContents").css({visibility: "visible"});
|
||||
$(".signUp").css({display: "none"});
|
||||
};
|
||||
|
||||
$('.login').live('click', function() {
|
||||
var user = $("#userLogin").val();
|
||||
var password = $("#passwordLogin").val();
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/login",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({ user: user, password: password, type: "m.login.password" }),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
onLoggedIn(data);
|
||||
},
|
||||
error: function(err) {
|
||||
alert("Unable to login: is the homeserver running?");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.register').live('click', function() {
|
||||
var user = $("#userReg").val();
|
||||
var password = $("#passwordReg").val();
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/register",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({ user: user, password: password, type: "m.login.password" }),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
onLoggedIn(data);
|
||||
},
|
||||
error: function(err) {
|
||||
var msg = "Is the homeserver running?";
|
||||
var errJson = $.parseJSON(err.responseText);
|
||||
if (errJson !== null) {
|
||||
msg = errJson.error;
|
||||
}
|
||||
alert("Unable to register: "+msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ************** Creating a room ******************
|
||||
$('.createRoom').live('click', function() {
|
||||
var roomAlias = $("#roomAlias").val();
|
||||
var data = {};
|
||||
if (roomAlias.length > 0) {
|
||||
data.room_alias_name = roomAlias;
|
||||
}
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/createRoom?access_token="+accountInfo.access_token,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
$("#roomAlias").val("");
|
||||
response.membership = "join"; // you are automatically joined into every room you make.
|
||||
response.latest_message = "";
|
||||
|
||||
roomInfo.push(response);
|
||||
setRooms(roomInfo);
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ************** Getting current state **************
|
||||
var getCurrentRoomList = function() {
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/initialSync?access_token=" + accountInfo.access_token + "&limit=1";
|
||||
$.getJSON(url, function(data) {
|
||||
var rooms = data.rooms;
|
||||
for (var i=0; i<rooms.length; ++i) {
|
||||
if ("messages" in rooms[i]) {
|
||||
rooms[i].latest_message = rooms[i].messages.chunk[0].content.body;
|
||||
}
|
||||
}
|
||||
roomInfo = rooms;
|
||||
setRooms(roomInfo);
|
||||
}).fail(function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
});
|
||||
};
|
||||
|
||||
var loadRoomContent = function(roomId) {
|
||||
console.log("loadRoomContent " + roomId);
|
||||
viewingRoomId = roomId;
|
||||
$("#roomName").text("Room: "+roomId);
|
||||
$(".sendMessageForm").css({visibility: "visible"});
|
||||
getMessages(roomId);
|
||||
getMemberList(roomId);
|
||||
};
|
||||
|
||||
var getMessages = function(roomId) {
|
||||
$("#messages").empty();
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/rooms/" +
|
||||
encodeURIComponent(roomId) + "/messages?access_token=" + accountInfo.access_token + "&from=END&dir=b&limit=10";
|
||||
$.getJSON(url, function(data) {
|
||||
for (var i=data.chunk.length-1; i>=0; --i) {
|
||||
addMessage(data.chunk[i]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var getMemberList = function(roomId) {
|
||||
$("#members").empty();
|
||||
memberInfo = [];
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/rooms/" +
|
||||
encodeURIComponent(roomId) + "/members?access_token=" + accountInfo.access_token;
|
||||
$.getJSON(url, function(data) {
|
||||
for (var i=0; i<data.chunk.length; ++i) {
|
||||
memberInfo.push(data.chunk[i]);
|
||||
addMember(data.chunk[i]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// ************** Sending messages **************
|
||||
$('.sendMessage').live('click', function() {
|
||||
if (viewingRoomId === undefined) {
|
||||
alert("There is no room to send a message to!");
|
||||
return;
|
||||
}
|
||||
var body = $("#body").val();
|
||||
sendMessage(viewingRoomId, body);
|
||||
});
|
||||
|
||||
var sendMessage = function(roomId, body) {
|
||||
var msgId = $.now();
|
||||
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/rooms/$roomid/send/m.room.message?access_token=$token";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$roomid", encodeURIComponent(roomId));
|
||||
|
||||
var data = {
|
||||
msgtype: "m.text",
|
||||
body: body
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
$("#body").val("");
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// ************** Navigation and DOM manipulation **************
|
||||
var setRooms = function(roomList) {
|
||||
// wipe existing entries
|
||||
$("#rooms").find("tr:gt(0)").remove();
|
||||
|
||||
var rows = "";
|
||||
for (var i=0; i<roomList.length; ++i) {
|
||||
row = "<tr>" +
|
||||
"<td>"+roomList[i].room_id+"</td>" +
|
||||
"<td>"+roomList[i].membership+"</td>" +
|
||||
"<td>"+roomList[i].latest_message+"</td>" +
|
||||
"</tr>";
|
||||
rows += row;
|
||||
}
|
||||
|
||||
$("#rooms").append(rows);
|
||||
|
||||
$('#rooms').find("tr").click(function(){
|
||||
var roomId = $(this).find('td:eq(0)').text();
|
||||
var membership = $(this).find('td:eq(1)').text();
|
||||
if (membership !== "join") {
|
||||
console.log("Joining room " + roomId);
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/rooms/$roomid/join?access_token=$token";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$roomid", encodeURIComponent(roomId));
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({membership: "join"}),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
loadRoomContent(roomId);
|
||||
getCurrentRoomList();
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadRoomContent(roomId);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var addMessage = function(data) {
|
||||
|
||||
var msg = data.content.body;
|
||||
if (data.type === "m.room.member") {
|
||||
if (data.content.membership === undefined) {
|
||||
return;
|
||||
}
|
||||
if (data.content.membership === "invite") {
|
||||
msg = "<em>invited " + data.state_key + " to the room</em>";
|
||||
}
|
||||
else if (data.content.membership === "join") {
|
||||
msg = "<em>joined the room</em>";
|
||||
}
|
||||
else if (data.content.membership === "leave") {
|
||||
msg = "<em>left the room</em>";
|
||||
}
|
||||
else if (data.content.membership === "ban") {
|
||||
msg = "<em>was banned from the room</em>";
|
||||
}
|
||||
}
|
||||
if (msg === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var row = "<tr>" +
|
||||
"<td>"+data.user_id+"</td>" +
|
||||
"<td>"+msg+"</td>" +
|
||||
"</tr>";
|
||||
$("#messages").append(row);
|
||||
};
|
||||
|
||||
var addMember = function(data) {
|
||||
var row = "<tr>" +
|
||||
"<td>"+data.state_key+"</td>" +
|
||||
"<td>"+data.content.membership+"</td>" +
|
||||
"</tr>";
|
||||
$("#members").append(row);
|
||||
};
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
.loggedin {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: monospace;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<div>
|
||||
<p>This registration/login demo requires a homeserver to be running on http://localhost:8008</p>
|
||||
</div>
|
||||
<form class="registrationForm">
|
||||
<input type="text" id="user" placeholder="Username"></input>
|
||||
<input type="password" id="password" placeholder="Password"></input>
|
||||
<input type="button" class="register" value="Register"></input>
|
||||
</form>
|
||||
<form class="loginForm">
|
||||
<input type="text" id="userLogin" placeholder="Username"></input>
|
||||
<input type="password" id="passwordLogin" placeholder="Password"></input>
|
||||
<input type="button" class="login" value="Login"></input>
|
||||
</form>
|
||||
<div class="loggedin">
|
||||
<p id="welcomeText"></p>
|
||||
<input type="button" class="testToken" value="Test token"></input>
|
||||
<input type="button" class="logout" value="Logout"></input>
|
||||
<p id="imSyncText"></p>
|
||||
</div>
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
var accountInfo = {};
|
||||
|
||||
var showLoggedIn = function(data) {
|
||||
accountInfo = data;
|
||||
$(".loggedin").css({visibility: "visible"});
|
||||
$("#welcomeText").text("Welcome " + accountInfo.user_id+". Your access token is: " +
|
||||
accountInfo.access_token);
|
||||
};
|
||||
|
||||
$('.register').live('click', function() {
|
||||
var user = $("#user").val();
|
||||
var password = $("#password").val();
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/register",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({ user: user, password: password, type: "m.login.password" }),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
showLoggedIn(data);
|
||||
},
|
||||
error: function(err) {
|
||||
var errMsg = "To try this, you need a homeserver running!";
|
||||
var errJson = $.parseJSON(err.responseText);
|
||||
if (errJson) {
|
||||
errMsg = JSON.stringify(errJson);
|
||||
}
|
||||
alert(errMsg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var login = function(user, password) {
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/login",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({ user: user, password: password, type: "m.login.password" }),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
showLoggedIn(data);
|
||||
},
|
||||
error: function(err) {
|
||||
var errMsg = "To try this, you need a homeserver running!";
|
||||
var errJson = $.parseJSON(err.responseText);
|
||||
if (errJson) {
|
||||
errMsg = JSON.stringify(errJson);
|
||||
}
|
||||
alert(errMsg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('.login').live('click', function() {
|
||||
var user = $("#userLogin").val();
|
||||
var password = $("#passwordLogin").val();
|
||||
$.getJSON("http://localhost:8008/_matrix/client/api/v1/login", function(data) {
|
||||
if (data.flows[0].type !== "m.login.password") {
|
||||
alert("I don't know how to login with this type: " + data.type);
|
||||
return;
|
||||
}
|
||||
login(user, password);
|
||||
});
|
||||
});
|
||||
|
||||
$('.logout').live('click', function() {
|
||||
accountInfo = {};
|
||||
$("#imSyncText").text("");
|
||||
$(".loggedin").css({visibility: "hidden"});
|
||||
});
|
||||
|
||||
$('.testToken').live('click', function() {
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/initialSync?access_token=" + accountInfo.access_token + "&limit=1";
|
||||
$.getJSON(url, function(data) {
|
||||
$("#imSyncText").text(JSON.stringify(data, undefined, 2));
|
||||
}).fail(function(err) {
|
||||
$("#imSyncText").text(JSON.stringify($.parseJSON(err.responseText)));
|
||||
});
|
||||
});
|
|
@ -1,17 +0,0 @@
|
|||
.loggedin {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-spacing:5px;
|
||||
}
|
||||
|
||||
th,td
|
||||
{
|
||||
padding:5px;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<div>
|
||||
<p>This room membership demo requires a homeserver to be running on http://localhost:8008</p>
|
||||
</div>
|
||||
<form class="loginForm">
|
||||
<input type="text" id="userLogin" placeholder="Username"></input>
|
||||
<input type="password" id="passwordLogin" placeholder="Password"></input>
|
||||
<input type="button" class="login" value="Login"></input>
|
||||
</form>
|
||||
<div class="loggedin">
|
||||
<form class="createRoomForm">
|
||||
<input type="button" class="createRoom" value="Create Room"></input>
|
||||
</form>
|
||||
<form class="changeMembershipForm">
|
||||
<input type="text" id="roomId" placeholder="Room ID"></input>
|
||||
<input type="text" id="targetUser" placeholder="Target User ID"></input>
|
||||
<select id="membership">
|
||||
<option value="invite">invite</option>
|
||||
<option value="join">join</option>
|
||||
<option value="leave">leave</option>
|
||||
</select>
|
||||
<input type="button" class="changeMembership" value="Change Membership"></input>
|
||||
</form>
|
||||
<form class="joinAliasForm">
|
||||
<input type="text" id="roomAlias" placeholder="Room Alias (#name:domain)"></input>
|
||||
<input type="button" class="joinAlias" value="Join via Alias"></input>
|
||||
</form>
|
||||
<table id="rooms">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Room ID</th>
|
||||
<th>My state</th>
|
||||
<th>Room Alias</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
var accountInfo = {};
|
||||
|
||||
var showLoggedIn = function(data) {
|
||||
accountInfo = data;
|
||||
getCurrentRoomList();
|
||||
$(".loggedin").css({visibility: "visible"});
|
||||
$("#membership").change(function() {
|
||||
if ($("#membership").val() === "invite") {
|
||||
$("#targetUser").css({visibility: "visible"});
|
||||
}
|
||||
else {
|
||||
$("#targetUser").css({visibility: "hidden"});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('.login').live('click', function() {
|
||||
var user = $("#userLogin").val();
|
||||
var password = $("#passwordLogin").val();
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/login",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({ user: user, password: password, type: "m.login.password" }),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
$("#rooms").find("tr:gt(0)").remove();
|
||||
showLoggedIn(data);
|
||||
},
|
||||
error: function(err) {
|
||||
var errMsg = "To try this, you need a homeserver running!";
|
||||
var errJson = $.parseJSON(err.responseText);
|
||||
if (errJson) {
|
||||
errMsg = JSON.stringify(errJson);
|
||||
}
|
||||
alert(errMsg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var getCurrentRoomList = function() {
|
||||
$("#roomId").val("");
|
||||
// wipe the table and reload it. Using the event stream would be the best
|
||||
// solution but that is out of scope of this fiddle.
|
||||
$("#rooms").find("tr:gt(0)").remove();
|
||||
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/initialSync?access_token=" + accountInfo.access_token + "&limit=1";
|
||||
$.getJSON(url, function(data) {
|
||||
var rooms = data.rooms;
|
||||
for (var i=0; i<rooms.length; ++i) {
|
||||
addRoom(rooms[i]);
|
||||
}
|
||||
}).fail(function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
});
|
||||
};
|
||||
|
||||
$('.createRoom').live('click', function() {
|
||||
var data = {};
|
||||
$.ajax({
|
||||
url: "http://localhost:8008/_matrix/client/api/v1/createRoom?access_token="+accountInfo.access_token,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
data.membership = "join"; // you are automatically joined into every room you make.
|
||||
data.latest_message = "";
|
||||
addRoom(data);
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var addRoom = function(data) {
|
||||
row = "<tr>" +
|
||||
"<td>"+data.room_id+"</td>" +
|
||||
"<td>"+data.membership+"</td>" +
|
||||
"<td>"+data.room_alias+"</td>" +
|
||||
"</tr>";
|
||||
$("#rooms").append(row);
|
||||
};
|
||||
|
||||
$('.changeMembership').live('click', function() {
|
||||
var roomId = $("#roomId").val();
|
||||
var member = $("#targetUser").val();
|
||||
var membership = $("#membership").val();
|
||||
|
||||
if (roomId.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/rooms/$roomid/$membership?access_token=$token";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$roomid", encodeURIComponent(roomId));
|
||||
url = url.replace("$membership", membership);
|
||||
|
||||
var data = {};
|
||||
|
||||
if (membership === "invite") {
|
||||
data = {
|
||||
user_id: member
|
||||
};
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
getCurrentRoomList();
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.joinAlias').live('click', function() {
|
||||
var roomAlias = $("#roomAlias").val();
|
||||
var url = "http://localhost:8008/_matrix/client/api/v1/join/$roomalias?access_token=$token";
|
||||
url = url.replace("$token", accountInfo.access_token);
|
||||
url = url.replace("$roomalias", encodeURIComponent(roomAlias));
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({}),
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
getCurrentRoomList();
|
||||
},
|
||||
error: function(err) {
|
||||
alert(JSON.stringify($.parseJSON(err.responseText)));
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Riot
|
||||
categories: projects client
|
||||
thumbnail: /docs/projects/images/riot-web-small.png
|
||||
author: Riot.im
|
||||
description: Riot is a glossy web client with an emphasis on performance and usability
|
||||
maturity: Released
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
[Riot](https://riot.im) is a glossy Matrix client built on top of [matrix-react-sdk](http://matrix.org/docs/projects/sdk/matrix.org-react-sdk.html) with an emphasis on performance and usability.
|
||||
|
||||
You can use it at [https://riot.im/app](https://riot.im/app), read more at [https://riot.im](https://riot.im) and get the source from [github](https://github.com/vector-im/vector-web)!
|
||||
|
||||
There is also a desktop version, which is available at [riot.im](https://riot.im/desktop.html). Taw has created RPM package builds for Fedora, CentOS, and Red Hat Enterprise Linux which are available via [GitHub](https://github.com/taw00/riot-rpm/) and [FedoraCorp](https://copr.fedorainfracloud.org/coprs/taw/Riot/).
|
||||
|
||||
Josué Tille has contributed a [Yunohost app](https://github.com/Josue-T/riot_ynh).
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Try Matrix Now!
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=./riot.html" />
|
||||
</head>
|
||||
</html>
|
|
@ -1,32 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Synapse
|
||||
categories: projects server
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/Screen-Shot-2015-04-29-at-00.28.25-400x284.png
|
||||
author: Matrix.org team
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org’s reference server – Synapse: [https://github.com/matrix-org/synapse](https://github.com/matrix-org/synapse)
|
||||
|
||||
Apt repo: [https://matrix.org/packages/debian/](https://matrix.org/packages/debian/)
|
||||
|
||||
Dockerfile from Silvio Fricke: [https://registry.hub.docker.com/u/silviof/docker-matrix/](https://registry.hub.docker.com/u/silviof/docker-matrix/)
|
||||
|
||||
ArchLinux package from Ivan Shapovalov: [https://www.archlinux.org/packages/community/any/matrix-synapse/](https://www.archlinux.org/packages/community/any/matrix-synapse/)
|
||||
|
||||
There is a FreeBSD package on [freshports.org](http://www.freshports.org/net/py-matrix-synapse/).
|
||||
|
||||
Martin Giess has created an auto-deployment process with vagrant/ansible, tested with VirtualBox/AWS/DigitalOcean – see [https://github.com/EMnify/matrix-synapse-auto-deploy](https://github.com/EMnify/matrix-synapse-auto-deploy) for details.
|
||||
|
||||
Synapse is also on the [Open Build Service](https://obs.infoserver.lv/project/show/matrix-synapse).
|
||||
|
||||
Synapse is available for the [Nix package manager](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/misc/matrix-synapse.nix).
|
||||
|
||||
You can get Synapse on [Yunohost](https://github.com/YunoHost-Apps/synapse_ynh)
|
||||
|
||||
There is also a [handy spreadsheet](http://matrix.org/docs/projects/other/hdd-space-calc-for-synapse.html) to calculate HDD space for your Synapse instance.
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: NEB (N. E. Bot)
|
||||
categories: projects other
|
||||
description: Our dear Matrix Bot
|
||||
author: Kegsay
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Kegsay's general-purpose Python Matrix Bot framework ([github](https://github.com/Kegsay/Matrix-NEB))
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org Android SDK
|
||||
categories: projects sdk
|
||||
author: Matrix.org team
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org's Android SDK ([github](https://github.com/matrix-org/matrix-android-sdk))
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org iOS SDK
|
||||
categories: projects sdk
|
||||
author: Matrix.org team
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org's iOS SDK ([github](https://github.com/matrix-org/matrix-ios-sdk))
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Pallium
|
||||
categories: projects server
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/pallium.png
|
||||
author: KoFish
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
KoFish’s homeserver written in Go – Pallium ([github](https://github.com/KoFish/pallium))
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org AngularJS SDK
|
||||
categories: projects sdk
|
||||
author: Matrix.org team
|
||||
maturity: DEPRECATED
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
AngularJS services from Matrix.org for building communication apps in Angular based on Matrix: [https://github.com/matrix-org/matrix-angular-sdk](https://github.com/matrix-org/matrix-angular-sdk)
|
||||
|
||||
These are no longer being actively maintained.
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Perl Matrix-IRC Bridge
|
||||
categories: projects other
|
||||
description: The first Matrix/IRC bridge
|
||||
author: Tom Molesworth / Paul Evans
|
||||
maturity: Beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
The first Matrix/IRC bridge, originally written by Tom Molesworth using Paul Evans' Net::Async::Matrix Perl client SDK and then later maintained by Paul Evans. Nowadays superceded by the [matrix-appservice-irc Node IRC bridge AS](../as/irc-bridge.html).
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: ivar2 Matrix/IRC Bot
|
||||
categories: projects other
|
||||
description: IRC bot with native Matrix support
|
||||
author: haste / Tor
|
||||
maturity: Beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
ivar2 is a very comprehensive IRC bot written in Lua which has native support for Matrix! [https://github.com/torhve/ivar2](https://github.com/torhve/ivar2)
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Try Matrix Now!
|
||||
categories: projects
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=./try-matrix-now.html" />
|
||||
</head>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org Python SDK
|
||||
categories: projects sdk
|
||||
author: Matrix.org team
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org's Python SDK ([github](https://github.com/matrix-org/matrix-python-sdk))
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: OpenMarket's SMS Gateway
|
||||
categories: projects as
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/omlogo-400x284.jpg
|
||||
author: OpenMarket
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
OpenMarket’s SMS Gateway is an Application Service that enables Matrix-users to send SMS. [More info here](http://matrix.org/blog/2015/02/26/welcoming-the-openmarket-matrix-gateway/).
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: WeeChat script
|
||||
categories: projects client
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/Screen-Shot-2015-04-22-at-21.43.01-400x284.png
|
||||
description: For fans of command line interfaces, a nice Matrix script for WeeChat, an IRSSI like CLI
|
||||
author: Tor
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
[WeeChat](http://weechat.org/) is a super powerful CLI chat client that is extensible in many languages to allow for new protocols like Matrix. @torhve contributed this great WeeChat script for Matrix which is getting a good feedback from more geeky users.
|
||||
|
||||
To use it, you will need to sign up for a Matrix account on a server using the [Console Web](./matrix-console.html) or [Vector](./vector.html) clients, as WeeChat doesn’t support registration yet.
|
||||
|
||||
To run it, grab the code from [@torhve's github repo](https://github.com/torhve/weechat-matrix-protocol-script).
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org AS Node SDK
|
||||
categories: projects as
|
||||
author: Matrix.org team
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
A framework from Matrix.org for building Application Services in Node.js/Express: [https://github.com/matrix-org/matrix-appservice-node](https://github.com/matrix-org/matrix-appservice-node)
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org JS SDK
|
||||
categories: projects sdk
|
||||
author: Matrix.org team
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org's JS SDK ([github](https://github.com/matrix-org/matrix-js-sdk))
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org IRC Bridge
|
||||
categories: projects as
|
||||
description:
|
||||
author: Matrix.org team
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
An application service gateway from Matrix.org for bridging between IRC networks and Matrix, written using [matrix-appservice-node](http://matrix.org/blog/project/matrix-appservice-node/). You can get the [code on github](https://github.com/matrix-org/matrix-appservice-irc).
|
||||
|
||||
Supports dynamically bridging IRC channels on demand; synchronised user-lists, and other goodness.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: redpill IRC bridge
|
||||
categories: projects as
|
||||
author: Tjgillies
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Kodo's IRC<->matrix GW written in Ruby ([github](https://github.com/tjgillies/redpill))
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: jSynapse
|
||||
categories: projects server
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/jsynapse2.png
|
||||
author: Swarmcom
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Swarmcom’s Java homeserver – jSynapse ([github](https://github.com/swarmcom/jSynapse/))
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: gomatrix IRC bridge
|
||||
categories: projects as
|
||||
author: Tor
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Tor's IRC<->Matrix bridge written in the Go language ([github](https://github.com/torhve/gomirc))
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org MatrixKit (iOS)
|
||||
categories: projects sdk
|
||||
author: Matrix.org team
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org's reusable UI interfaces for iOS ([github](https://github.com/matrix-org/matrix-ios-kit))
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Riot iOS
|
||||
categories: projects client
|
||||
thumbnail: /docs/projects/images/vector-iOS-small.png
|
||||
description: Riot is a glossy client with an emphasis on performance and usability
|
||||
author: Riot.im
|
||||
maturity: Released
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
The iOS version of the [Riot](https://matrix.org/docs/projects/client/riot.html) web client. Riot is a glossy client with focus on performance and usability.
|
||||
|
||||
The code is available from [github](https://github.com/vector-im/vector-ios), and the app is available from the Apple [app store](https://itunes.apple.com/gb/app/vector.im/id1083446067?mt=8).
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Try Matrix Now!
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=./riot-ios.html" />
|
||||
</head>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Project Clearwater / Matrix Gateway
|
||||
categories: projects as
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/clearwter-400x284.jpg
|
||||
author: Matt Williams
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Matt Williams’ IMS->Matrix gateway ([github](https://github.com/matt-williams/sprout/tree/matrix))
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: newlisp-matrix-client
|
||||
categories: projects sdk
|
||||
author: Ingo Hohmann
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Client SDK for newlisp available at [https://github.com/IngoHohmann/newlisp-matrix-client](https://github.com/IngoHohmann/newlisp-matrix-client)
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: matrix-erlang-sdk
|
||||
categories: projects sdk
|
||||
author: Andreas Hallberg
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Andreas Hallberg's client SDK for Erlang [https://github.com/anhallbe/matrix-erlang-sdk](https://github.com/anhallbe/matrix-erlang-sdk)
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Riot Android
|
||||
categories: projects client
|
||||
thumbnail: /docs/projects/images/vector-android-small.png
|
||||
description: Riot is a glossy client with an emphasis on performance and usability
|
||||
author: Riot.im
|
||||
maturity: Released
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
The Android version of the [Riot](https://matrix.org/docs/projects/client/riot.html) web client. Riot is a glossy client with focus on performance and usability.
|
||||
|
||||
The code is available from [github](https://github.com/vector-im/vector-android), and the app is available from the [Google Play store](https://play.google.com/store/apps/details?id=im.vector.alpha) and [F-Droid](https://f-droid.org/repository/browse/?fdfilter=vector&fdid=im.vector.alpha).
|
||||
|
||||
If you want to help test the app, you can download development versions from [Jenkins](https://matrix.org/jenkins/job/VectorAndroidDevelop/).
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Try Matrix Now!
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=./riot-android.html" />
|
||||
</head>
|
||||
</html>
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix.org React SDK
|
||||
categories: projects sdk
|
||||
author: Matrix.org team
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
[matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk) is our next-generation Web SDK for Matrix, providing both a large hierarchy of reusable UI components and a simple neutral reference application. It's suitable both for building standalone applications and embedding Matrix clients into existing web apps, irrespective of the host app's framework.
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Tensor
|
||||
categories: projects client
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/11/tensor1-400x284.png
|
||||
description: QML-based Matrix client
|
||||
author: David A Roberts
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Tensor is a cross-platform native Matrix client, based on QtQuick/QML and libqmatrixclient (formerly matrix-js-sdk). It has been tested on Desktop GNU/Linux, OS X, Windows, Android, SailfishOS and Ubuntu Touch. Get it from [github](https://github.com/davidar/tensor).
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Quaternion
|
||||
categories: projects client
|
||||
thumbnail: https://raw.githubusercontent.com/QMatrixClient/Quaternion/master/quaternion.png
|
||||
author: Felix Rohrbach, Kitsune Ral
|
||||
description: Quaternion is an IM client for the Matrix protocol
|
||||
maturity: Late alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Quaternion is a Qt/QML-based IM client for the Matrix protocol in development. ([github](https://github.com/QMatrixClient/Quaternion))
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: xmpptrix
|
||||
categories: projects as
|
||||
author: SkaveRat
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
XMPP<->Matrix gateway application service written in Node JS: [https://github.com/SkaveRat/xmpptrix](https://github.com/SkaveRat/xmpptrix).
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: matrix-appservice-bridge
|
||||
categories: projects as
|
||||
author: Kegsay
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
This library sits on top of the [core application service library](https://github.com/matrix-org/matrix-appservice-node) and provides an API for setting up bridges quickly.
|
||||
|
||||
Get it from [github](https://github.com/matrix-org/matrix-appservice-bridge) and have a look at the [HOW-TO](https://github.com/matrix-org/matrix-appservice-bridge/blob/master/HOWTO.md) for a step-by-step tutorial on setting up a new bridge!
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: matrix-appservice-respoke
|
||||
categories: projects as
|
||||
author: Matrix.org team
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
An incredibly hacky Matrix --> Asterisk bridge via chan_respoke.
|
||||
|
||||
Get it from [github](https://github.com/matrix-org/matrix-appservice-respoke)!
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Vertobridge
|
||||
categories: projects as
|
||||
author: Matthew / Kegan
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
A Matrix <--> Verto bridge, designed for conferencing via Freeswitch. [https://github.com/matrix-org/matrix-appservice-verto](https://github.com/matrix-org/matrix-appservice-verto)
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: bullettime
|
||||
categories: projects server
|
||||
author: Patrik Oldsberg
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
An experimental golang Matrix homeserver ([github](https://github.com/matrix-org/bullettime))
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: matrix-appservice-slack
|
||||
categories: projects as
|
||||
author: illicitonion
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
This project bridges [Slack](https://slack.com) to Matrix, all in a 100 lines of code! It's currently quite barebones, but at the same time it shows how quickly a bridge can be written.
|
||||
|
||||
Get it from [github](https://github.com/matrix-org/matrix-appservice-slack)!
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix-XMPP Bridge
|
||||
categories: projects as
|
||||
author: jfrederickson
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
This project creates a bridge between a Matrix room and an XMPP MUC: [https://github.com/jfrederickson/matrix-xmpp-bridge](https://github.com/jfrederickson/matrix-xmpp-bridge)
|
||||
|
||||
Update: there is also a forked and refactored version at [pztrn's GitHub space](https://github.com/pztrn/matrix-xmpp-bridge)
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: node-purple
|
||||
categories: projects as
|
||||
author: Matrix.org team / tjfontaine
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
[node-purple](https://github.com/tjfontaine/node-purple) provides basic FFI bindings for libpurple. In our fork, [appservice](https://github.com/matrix-org/node-purple/tree/master/appservice) connects node-purple to the AS API, so you can talk from Matrix to libpurple's connections.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: slackbridge
|
||||
categories: projects as
|
||||
author: illicitonion
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
illicitonion's early Slack bridge, written in Go.
|
||||
|
||||
Check it out on [github](https://github.com/illicitonion/slackbridge)
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: purple-matrix
|
||||
categories: projects client
|
||||
description: A plugin for libpurple
|
||||
author: Matrix.org team
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
This project is a plugin for [libpurple](https://developer.pidgin.im/wiki/WhatIsLibpurple) which adds the ability to communicate with matrix.org homeservers to any libpurple-based clients (such as [Pidgin](http://www.pidgin.im/)).
|
||||
|
||||
Get it at [github](https://github.com/matrix-org/purple-matrix/).
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Bender
|
||||
categories: projects other
|
||||
description: A simple/flexible bot framework
|
||||
author: Dylan Griffith
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Bender is a Matrix bot framework written in Elixir: [https://github.com/DylanGriffith/bender](https://github.com/DylanGriffith/bender)
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Mero
|
||||
categories: projects as
|
||||
description: NodeJS based XMPP facade bridge for matrix.org
|
||||
author: SkaveRat
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
NodeJS based XMPP facade bridge for matrix.org
|
||||
|
||||
This Matrix Application Server will pretend to be a XMPP (jabber) server and mirror all actions to and from Matrix.
|
||||
|
||||
Check it out on [github](https://github.com/SkaveRat/mero)
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: MatrixTool
|
||||
categories: projects other
|
||||
description: Commands to interact with a Matrix homeserver
|
||||
author: LeoNerd
|
||||
maturity: Alpha
|
||||
---
|
||||
# {{ page.title }}
|
||||
|
||||
The tool provides a wrapper around a number of sub-commands that provide useful interactions with a Matrix homeserver.
|
||||
|
||||
You can grab it from [CPAN](http://search.cpan.org/~pevans/App-MatrixTool/).
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Ruma
|
||||
categories: projects server
|
||||
author: Jimmy Cuadra
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
|
||||
# {{ page.title }}
|
||||
Ruma is a server written in Rust ([github](https://github.com/ruma/ruma))
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Hubot-Matrix
|
||||
categories: projects other
|
||||
description: A Matrix-adapter for Hubot
|
||||
author: David A Roberts
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
A Matrix-adapter for Hubot: [https://github.com/davidar/hubot-matrix/](https://github.com/davidar/hubot-matrix/)
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix Client SDK for GLib
|
||||
categories: projects sdk
|
||||
author: Gergely Polonkai
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
A Matrix.org client-server SDK for GLib >= 2.40. It contains both raw API calls and a signal based asynchronous client. Get it from [github](https://github.com/gergelypolonkai/matrix-glib-sdk)!
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Perpetually Talking Online (PTO)
|
||||
categories: projects client
|
||||
description: PTO is an IRC frontend to the federated Matrix network.
|
||||
author: tdfischer
|
||||
maturity: Abandoned
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Perpetually Talking Online (PTO) is an IRC frontend to the federated Matrix network. It aims to enable as many people as possible to use an existing Matrix homeserver with their existing IRC clients, and provides a radically expanded feature set for existing IRC communities looking to migrate to Matrix.
|
||||
|
||||
See [pto.im](http://pto.im) for more info - or grab the code from [GitHub](https://github.com/tdfischer/pto).
|
||||
|
||||
Unfortunately, it appears that this project is no longer being worked on. Check out [matrix-ircd](./matrix-ircd.html) instead!
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix Console iOS
|
||||
categories: projects client
|
||||
thumbnail: /docs/projects/images/matrix-console-ios-2016-02-16-cropped.png
|
||||
description: A neutral iOS client showcasing Matrix capabilities and implementation.
|
||||
author: Matrix.org team
|
||||
maturity: No longer maintained
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org's reference iOS client.
|
||||
|
||||
This client is meant to be a showcase of Matrix capabilities, a reference implementation of the Matrix standard and an easy entry to the Matrix ecosystem from iOS devices for less techy users, with a relatively neutral branding. This client is built using [MatrixKit](http://matrix.org/blog/project/matrix-ios-matrixkit/).
|
||||
|
||||
The code can be retrieved from [github](https://github.com/matrix-org/matrix-ios-console).
|
||||
|
||||
Also available from the Apple [app store](https://itunes.apple.com/gb/app/matrix-console/id970074271?mt=8).
|
|
@ -1,22 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix Console Android
|
||||
categories: projects client
|
||||
thumbnail: /docs/projects/images/matrix-console-android-2016-02-16-cropped.png
|
||||
description: A neutral Android client showcasing Matrix capabilities and implementation.
|
||||
author: Matrix.org team
|
||||
maturity: No longer maintained
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org’s reference Android client.
|
||||
|
||||
This client is meant to be a showcase of Matrix capabilities, a reference implementation of the Matrix standard and an easy entry to the Matrix ecosystem from Android devices for less techy users, with a relatively neutral branding.
|
||||
|
||||
The code can be retrieved from [github](https://github.com/matrix-org/matrix-android-console).
|
||||
|
||||
Also available from the [Google Play store](https://play.google.com/store/apps/details?id=org.matrix.androidsdk.alpha).
|
||||
|
||||
Folks wanting to live on the bleeding edge can also pull APKs of the develop (and master) branches straight out of the [Jenkins build server](http://matrix.org/jenkins/job/AndroidConsoleDevelop/).
|
|
@ -1,21 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix Console Web
|
||||
categories: projects client
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/syweb2-400x284.png
|
||||
description: Matrix.org’s legacy AngularJS web client.
|
||||
author: Matrix.org team
|
||||
maturity: No longer maintained
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Matrix.org’s original reference AngularJS webclient. The implementation has major performance issues and is not being actively maintained. Please see [Vector](https://matrix.org/blog/project/vector) and [matrix-react-sdk](https://matrix.org/blog/project/matrix-react-sdk) for better alternatives.
|
||||
|
||||
The code can be retrieved from [github](https://github.com/matrix-org/matrix-angular-sdk).
|
||||
|
||||
Public hosts running this client:
|
||||
|
||||
[https://matrix.org/beta](https://matrix.org/beta)
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Glowing Bear + WeeChat Script
|
||||
categories: projects client
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/Screen-Shot-2015-04-21-at-17.36.43-400x284.png
|
||||
author: glowing-bear.org
|
||||
description: A great IRC-style web interface to Matrix.
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
[Glowing Bear](http://glowing-bear.org/) combined with [@torhve’s Matrix script for WeeChat](./weechat.html) makes for a great IRC-style web interface to Matrix.
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Dendron
|
||||
categories: projects server
|
||||
author: Matrix.org team
|
||||
maturity: Obsolete
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Dendron was the start of an experimental Matrix homeserver written in Go, built as a 'strangler pattern' implementation on top of Synapse. It was discontinued in favour of Dendrite.
|
||||
|
||||
The code lives on at [github](https://github.com/matrix-org/dendron)!
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Rocket Chat Federation
|
||||
categories: projects as
|
||||
thumbnail: https://raw.githubusercontent.com/Sing-Li/bbug/master/images/rcsnynapse.png
|
||||
author: Rocket.Chat
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Rocket.Chat have written a bot called Freddie that pairs a Synapse server with a Rocket.Chat server ([github](https://github.com/RocketChat/Rocket.Chat.Federation/tree/develop/matrix.org/hubot-freddie))
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Unplug
|
||||
categories: projects client
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/unplug-0.1.5-400x284.png
|
||||
description: Experimental Kotlin client
|
||||
author: hrjet
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
hrjet's Kotlin/JVM client – unplug ([github](https://github.com/UprootLabs/unplug))
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: feedbot
|
||||
categories: projects other
|
||||
description: Connects to RSS and Twitter feeds
|
||||
author: Ryan Rix
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Connect to RSS and Twitter feeds via Ryan Rix's feedbot!
|
||||
|
||||
Check it out from [Ryan's git repo](https://fort.kickass.systems/git/rrix/matrix-feedbot)
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Lightrix
|
||||
categories: projects other
|
||||
description: Drive Adafruit Neopixels over Matrix
|
||||
author: Ryan Rix
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Control Adafruit Neopixels via Matrix!
|
||||
|
||||
Check it out from [Ryan's git repo](https://fort.kickass.systems/git/rrix/lightrix) or watch it in action on [YouTube](https://www.youtube.com/watch?v=4YG9Fk5aP24)
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: mcat
|
||||
categories: projects other
|
||||
description: Pipe to/from a Matrix room via the Python SDK
|
||||
author: Ryan Rix
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Pipe in to and out of a Matrix room using the [Matrix Python SDK](https://github.com/matrix-org/matrix-python-sdk).
|
||||
|
||||
Check it out from [Ryan's git repo](https://fort.kickass.systems/git/rrix/matrix-cat)
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Polynomial
|
||||
description: A Decentralized Webring
|
||||
categories: projects other
|
||||
author: Ryan Rix
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Webring software built on top of Matrix.org which means it doesn't have a central point of failure.
|
||||
|
||||
Check it out at [Ryan's blog](http://whatthefuck.computer/blog/2015/12/06/polynomial-a-decentralized-webring/) and grab the code from [Ryan's git repo](https://fort.kickass.systems/git/rrix/polynomial)
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: redpill
|
||||
categories: projects client
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/04/redpill0.7-400x284.png
|
||||
description: A Python2 CLI client
|
||||
author: oddvar
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Oddvar's Python2 CLI client – redpill ([github](https://github.com/oddvar/redpill))
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Headjack
|
||||
categories: projects client
|
||||
thumbnail: https://matrix.org/blog/wp-content/uploads/2015/05/headjack-400x284.png
|
||||
description: Experimental Chrome App client
|
||||
author: SkaveRat
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||

|
||||
|
||||
# {{ page.title }}
|
||||
Experimental Chrome App desktop client for Matrix, using [matrix-angular-sdk](https://github.com/matrix-org/matrix-angular-sdk). Available from [github](https://github.com/SkaveRat/headjack).
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Net::Async::Matrix (Perl)
|
||||
categories: projects sdk
|
||||
author: LeoNerd
|
||||
maturity: Late beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
LeoNerd's Net::Async::Matrix client SDK library for Perl: [https://metacpan.org/release/Net-Async-Matrix](https://metacpan.org/release/Net-Async-Matrix)
|
|
@ -1,216 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Try Matrix Now!
|
||||
categories: projects
|
||||
---
|
||||
|
||||
<div class='font18'>
|
||||
Matrix is a whole ecosystem of matrix-enabled clients, servers, gateways, application services, bots, etc.
|
||||
</div>
|
||||
|
||||
|
|
||||
|
||||
<div class='font18 bold'>
|
||||
The easiest way to get started is to pick a client that appeals and join #matrix:matrix.org:
|
||||
</div>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<table class='bigtable'>
|
||||
<tr>
|
||||
<td class='bigproject'>
|
||||
<a href='./client/weechat.html' class='font18 bold'>
|
||||
Weechat/Matrix
|
||||
</a><br />
|
||||
If you like command line clients, try the Weechat plugin.<br /><br />
|
||||
<a href='./client/weechat.html'>
|
||||
<img src='https://matrix.org/blog/wp-content/uploads/2015/04/Screen-Shot-2015-08-07-at-13.31.29-300x209.png' class='featured_screenshot'>
|
||||
</a>
|
||||
</td>
|
||||
<td class='bigproject'>
|
||||
<a href='./client/riot.html' class='font18 bold'>
|
||||
Riot
|
||||
</a><br />
|
||||
If you like glossy and feature-rich web clients, try Riot.<br /><br />
|
||||
<a href='./client/riot.html'>
|
||||
<img src='/docs/projects/images/riot-web-featured.png' class='featured_screenshot'>
|
||||
</a>
|
||||
</td>
|
||||
<td class='bigproject'>
|
||||
<a href='./client/riot-ios.html' class='font18 bold'>
|
||||
Riot iOS
|
||||
</a><br />
|
||||
You can also access Matrix on your iOS phone via Riot iOS.<br /><br />
|
||||
<a href='./client/riot-ios.html'>
|
||||
<img src='/docs/projects/images/vector-iOS-featured.png' class='featured_screenshot'>
|
||||
</a>
|
||||
</td>
|
||||
<td class='bigproject'>
|
||||
<a href='./client/riot-android.html' class='font18 bold'>
|
||||
Riot Android
|
||||
</a><br />
|
||||
Riot is also available on Android devices!<br /><br />
|
||||
<a href='./client/riot-android.html'>
|
||||
<img src='/docs/projects/images/vector-android-featured.png' class='featured_screenshot'>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
This page aims to collect all known Matrix projects - if you want to add a new one (or update an existing one), you can submit a PR to the [matrix-doc](https://github.com/matrix-org/matrix-doc) project on github - the existing projects can be found [here](https://github.com/matrix-org/matrix-doc/tree/master/supporting-docs/projects) - or just let us know in the #matrix:matrix.org room.
|
||||
|
||||
|
|
||||
|
||||
<div class='font18'>
|
||||
Projects using Matrix:
|
||||
</div>
|
||||
|
||||
* TOC
|
||||
{:toc .toc}
|
||||
|
||||
|
|
||||
|
||||
Clients
|
||||
=======
|
||||
|
||||
<table>
|
||||
{% assign post_nr = '0' %}
|
||||
{% for post in site.categories.client reversed limit:100 %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}<tr>{% endif %}
|
||||
<td class='project'>
|
||||
<a href='/docs{{ BASE_PATH }}{{ post.url }}'>
|
||||
<img class='thumbnail' src='{{ post.thumbnail }}'>
|
||||
</a>
|
||||
<br />
|
||||
<a href='/docs{{ BASE_PATH }}{{ post.url }}'>
|
||||
{{ post.title }}
|
||||
</a><br />
|
||||
<div style='margin-bottom: 8px;'>
|
||||
{{ post.description }}
|
||||
</div>
|
||||
Author: {{ post.author }}<br />
|
||||
Maturity: {{ post.maturity }}
|
||||
</td>
|
||||
{% assign post_nr = post_nr | plus: '1' %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}</tr>{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
||||
|
||||
Servers
|
||||
=======
|
||||
|
||||
<table>
|
||||
{% assign post_nr = '0' %}
|
||||
{% for post in site.categories.server reversed limit:100 %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}<tr>{% endif %}
|
||||
<td class='project'>
|
||||
<a href='/docs{{ BASE_PATH }}{{ post.url }}'>
|
||||
{{ post.title }}
|
||||
</a><br />
|
||||
<div style='margin-bottom: 8px;'>
|
||||
{{ post.description }}
|
||||
</div>
|
||||
Author: {{ post.author }}<br />
|
||||
Maturity: {{ post.maturity }}
|
||||
</td>
|
||||
{% assign post_nr = post_nr | plus: '1' %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}</tr>{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
|
||||
|
||||
Application Services
|
||||
====================
|
||||
|
||||
<table>
|
||||
{% assign post_nr = '0' %}
|
||||
{% for post in site.categories.as reversed limit:100 %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}<tr>{% endif %}
|
||||
<td class='project'>
|
||||
<a href='/docs{{ BASE_PATH }}{{ post.url }}'>
|
||||
{{ post.title }}
|
||||
</a><br />
|
||||
<div style='margin-bottom: 8px;'>
|
||||
{{ post.description }}
|
||||
</div>
|
||||
Author: {{ post.author }}<br />
|
||||
Maturity: {{ post.maturity }}
|
||||
</td>
|
||||
{% assign post_nr = post_nr | plus: '1' %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}</tr>{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
||||
|
||||
Client SDKs
|
||||
===========
|
||||
|
||||
<table>
|
||||
{% assign post_nr = '0' %}
|
||||
{% for post in site.categories.sdk reversed limit:100 %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}<tr>{% endif %}
|
||||
<td class='project'>
|
||||
<a href='/docs{{ BASE_PATH }}{{ post.url }}'>
|
||||
{{ post.title }}
|
||||
</a><br />
|
||||
<div style='margin-bottom: 8px;'>
|
||||
{{ post.description }}
|
||||
</div>
|
||||
Author: {{ post.author }}<br />
|
||||
Maturity: {{ post.maturity }}
|
||||
</td>
|
||||
{% assign post_nr = post_nr | plus: '1' %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}</tr>{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
||||
|
||||
Other
|
||||
=====
|
||||
|
||||
<table>
|
||||
{% assign post_nr = '0' %}
|
||||
{% for post in site.categories.other reversed limit:100 %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}<tr>{% endif %}
|
||||
<td class='project'>
|
||||
<a href='/docs{{ BASE_PATH }}{{ post.url }}'>
|
||||
{{ post.title }}
|
||||
</a><br />
|
||||
<div style='margin-bottom: 8px;'>
|
||||
{{ post.description }}
|
||||
</div>
|
||||
Author: {{ post.author }}<br />
|
||||
Maturity: {{ post.maturity }}
|
||||
</td>
|
||||
{% assign post_nr = post_nr | plus: '1' %}
|
||||
{% assign add_new_row_test = post_nr | modulo:6 %}
|
||||
{% if add_new_row_test == 0 %}</tr>{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Vector Desktop
|
||||
description: Desktop version of Vector
|
||||
author: Steven Hammerton
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Desktop version of the [Vector](./vector.html) web client. Basically it's Vector wrapped in an [Electron](https://github.com/atom/electron) app. Source here: [https://github.com/stevenhammerton/vector-desktop](https://github.com/stevenhammerton/vector-desktop)
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix Blog
|
||||
categories: projects client
|
||||
description: Read-only blog-style Matrix interface
|
||||
author: simeng
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
An example read-only blog-style interface to a Matrix room ([github](https://github.com/simeng/matrix-blog)).
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: matrix-appservice-gitter
|
||||
categories: projects as
|
||||
author: LeoNerd
|
||||
maturity: Early beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
This project bridges [Gitter](https://gitter.im) to Matrix, via the AS API on the Matrix side, and a Gitter user on the Gitter side.
|
||||
|
||||
Get it from [github](https://github.com/matrix-org/matrix-appservice-gitter).
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Matrix .NET SDK
|
||||
categories: projects sdk
|
||||
author: Half-Shot
|
||||
maturity: Alpha
|
||||
---
|
||||
# {{ page.title }}
|
||||
|
||||
The .NET SDK provides an object oriented library to interact with Matrix. It is currently mature enough to be used for simple clients and bots.
|
||||
|
||||
[Github](https://github.com/Half-Shot/matrix-dotnet-sdk)
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: MPD DJ
|
||||
categories: projects other
|
||||
description: A bot for controlling MPD over matrix.
|
||||
author: Half-Shot
|
||||
maturity: Alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
|
||||
Ever wanted to control a MPD instance over matrix? Now you can!
|
||||
|
||||
Supports a selection (with more coming soon) of mpd commands with the ability to play Youtube links.
|
||||
|
||||
Development is steadily ongoing at [Github](https://github.com/Half-Shot/matrix-mpd-dj)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: libqmatrixclient
|
||||
categories: projects sdk
|
||||
author: Kitsune Ral, Felix Rohrbach
|
||||
maturity: Late alpha
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
libqmatrixclient is a Qt-based library to make IM clients for the Matrix protocol. It is used by [Quaternion](https://matrix.org/docs/projects/client/quaternion.html) and is a part of the QMatrixClient project. Recent builds of [Tensor](https://matrix.org/docs/projects/client/tensor.html) are also made on top of libqmatrixclient.
|
||||
|
||||
The project lives in QMatrixClient [github space](https://github.com/QMatrixClient/libqmatrixclient).
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: project
|
||||
title: Concourse/Matrix notification resource
|
||||
categories: projects other
|
||||
thumbnail: /docs/projects/images/concourse-ci-logo.png
|
||||
description: Post notifications from Concourse CI jobs
|
||||
author: freelock
|
||||
maturity: beta
|
||||
---
|
||||
|
||||
# {{ page.title }}
|
||||
Create a Concourse custom resource type using [freelock/matrix-notification-resource](https://hub.docker.com/r/freelock/matrix-notification-resource/) from Docker Hub, or fork/contribute on [github](https://github.com/freelock/matrix-notification-resource)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue