Document not found (404)
+This URL is invalid, sorry. Please use the navigation bar or search to continue.
+ +diff --git a/latest/.nojekyll b/latest/.nojekyll new file mode 100644 index 0000000000..f17311098f --- /dev/null +++ b/latest/.nojekyll @@ -0,0 +1 @@ +This file makes sure that Github Pages doesn't process mdBook's output. diff --git a/latest/.sample_config_header.yaml b/latest/.sample_config_header.yaml new file mode 100644 index 0000000000..8c9b31acdb --- /dev/null +++ b/latest/.sample_config_header.yaml @@ -0,0 +1,25 @@ +# This file is maintained as an up-to-date snapshot of the default +# homeserver.yaml configuration generated by Synapse. +# +# It is intended to act as a reference for the default configuration, +# helping admins keep track of new options and other changes, and compare +# their configs with the current default. As such, many of the actual +# config values shown are placeholders. +# +# It is *not* intended to be copied and used as the basis for a real +# homeserver.yaml. Instead, if you are starting from scratch, please generate +# a fresh config using Synapse by following the instructions in INSTALL.md. + +# Configuration options that take a time period can be set using a number +# followed by a letter. Letters have the following meanings: +# s = second +# m = minute +# h = hour +# d = day +# w = week +# y = year +# For example, setting redaction_retention_period: 5m would remove redacted +# messages from the database after 5 minutes, rather than 5 months. + +################################################################################ + diff --git a/latest/404.html b/latest/404.html new file mode 100644 index 0000000000..82ee0b83a9 --- /dev/null +++ b/latest/404.html @@ -0,0 +1,239 @@ + + +
+ + +This URL is invalid, sorry. Please use the navigation bar or search to continue.
+ +A captcha can be enabled on your homeserver to help prevent bots from registering +accounts. Synapse currently uses Google's reCAPTCHA service which requires API keys +from Google.
+public_baseurl
+in homeserver.yaml
, to the list of authorized domains. If you have not set
+public_baseurl
, use server_name
.homeserver.yaml
+configuration file
+recaptcha_public_key: YOUR_SITE_KEY
+recaptcha_private_key: YOUR_SECRET_KEY
+
+enable_registration_captcha: true
+
+The reCAPTCHA API requires that the IP address of the user who solved the
+CAPTCHA is sent. If the client is connecting through a proxy or load balancer,
+it may be required to use the X-Forwarded-For
(XFF) header instead of the origin
+IP address. This can be configured using the x_forwarded
directive in the
+listeners section of the homeserver.yaml
configuration file.
This document was originally written to guide server admins through the upgrade +path towards Synapse 1.0. Specifically, +MSC1711 +required that all servers present valid TLS certificates on their federation +API. Admins were encouraged to achieve compliance from version 0.99.0 (released +in February 2019) ahead of version 1.0 (released June 2019) enforcing the +certificate checks.
+Much of what follows is now outdated since most admins will have already +upgraded, however it may be of use to those with old installs returning to the +project.
+If you are setting up a server from scratch you almost certainly should look at +the installation guide instead.
+The goal of Synapse 0.99.0 is to act as a stepping stone to Synapse 1.0.0. It +supports the r0.1 release of the server to server specification, but is +compatible with both the legacy Matrix federation behaviour (pre-r0.1) as well +as post-r0.1 behaviour, in order to allow for a smooth upgrade across the +federation.
+The most important thing to know is that Synapse 1.0.0 will require a valid TLS +certificate on federation endpoints. Self signed certificates will not be +sufficient.
+Synapse 0.99.0 makes it easy to configure TLS certificates and will +interoperate with both >= 1.0.0 servers as well as existing servers yet to +upgrade.
+It is critical that all admins upgrade to 0.99.0 and configure a valid TLS +certificate. Admins will have 1 month to do so, after which 1.0.0 will be +released and those servers without a valid certificate will not longer be able +to federate with >= 1.0.0 servers.
+Full details on how to carry out this configuration change is given +below. A +timeline and some frequently asked questions are also given below.
+For more details and context on the release of the r0.1 Server/Server API and +imminent Matrix 1.0 release, you can also see our +main talk from FOSDEM 2019.
+5th Feb 2019 - Synapse 0.99.0 is released.
+All server admins are encouraged to upgrade.
+0.99.0:
+provides support for ACME to make setting up Let's Encrypt certs easy, as +well as .well-known support.
+does not enforce that a valid CA cert is present on the federation API, but +rather makes it easy to set one up.
+provides support for .well-known
+Admins should upgrade and configure a valid CA cert. Homeservers that require a +.well-known entry (see below), should retain their SRV record and use it +alongside their .well-known record.
+10th June 2019 - Synapse 1.0.0 is released
+1.0.0 is scheduled for release on 10th June. In +accordance with the the S2S spec +1.0.0 will enforce certificate validity. This means that any homeserver without a +valid certificate after this point will no longer be able to federate with +1.0.0 servers.
+In this case, your server_name
points to the host where your Synapse is
+running. There is no need to create a .well-known
URI or an SRV record, but
+you will need to give Synapse a valid, signed, certificate.
If you are using an SRV record, your matrix domain (server_name
) may not
+point to the same host that your Synapse is running on (the 'target
+domain'). (If it does, you can follow the recommendation above; otherwise, read
+on.)
Let's assume that your server_name
is example.com
, and your Synapse is
+hosted at a target domain of customer.example.net
. Currently you should have
+an SRV record which looks like:
_matrix._tcp.example.com. IN SRV 10 5 8000 customer.example.net.
+
+In this situation, you have three choices for how to proceed:
+Synapse 1.0 will expect your server to present a TLS certificate for your
+server_name
(example.com
in the above example). You can achieve this by acquiring a
+certificate for the server_name
yourself (for example, using certbot
), and giving it
+and the key to Synapse via tls_certificate_path
and tls_private_key_path
.
If you have an existing reverse proxy set up with correct TLS certificates for +your domain, you can simply route all traffic through the reverse proxy by +updating the SRV record appropriately (or removing it, if the proxy listens on +8448).
+See reverse_proxy.md for information on setting up a +reverse proxy.
+This will allow you to keep Synapse on a separate domain, without having to +give it a certificate for the matrix domain.
+You can do this with a .well-known
file as follows:
Keep the SRV record in place - it is needed for backwards compatibility +with Synapse 0.34 and earlier.
+Give Synapse a certificate corresponding to the target domain
+(customer.example.net
in the above example). You can do this by acquire a
+certificate for the target domain and giving it to Synapse via tls_certificate_path
+and tls_private_key_path
.
Restart Synapse to ensure the new certificate is loaded.
+Arrange for a .well-known
file at
+https://<server_name>/.well-known/matrix/server
with contents:
{"m.server": "<target server name>"}
+
+where the target server name is resolved as usual (i.e. SRV lookup, falling +back to talking to port 8448).
+In the above example, where synapse is listening on port 8000,
+https://example.com/.well-known/matrix/server
should have m.server
set to one of:
customer.example.net
─ with a SRV record on
+_matrix._tcp.customer.example.com
pointing to port 8000, or:
customer.example.net
─ updating synapse to listen on the default port
+8448, or:
customer.example.net:8000
─ ensuring that if there is a reverse proxy
+on customer.example.net:8000
it correctly handles HTTP requests with
+Host header set to customer.example.net:8000
.
Upgrade as soon as you can in preparation for Synapse 1.0.0, and update your +TLS certificates as above.
+Nothing initially, but once 1.0.0 is in the wild it will not be possible to +federate with 1.0.0 servers.
+If the admin takes no action at all, and remains on a Synapse < 0.99.0 then the +homeserver will be unable to federate with those who have implemented +.well-known. Then, as above, once the month upgrade window has expired the +homeserver will not be able to federate with any Synapse >= 1.0.0
+If your homeserver listens on the default federation port (8448), and your
+server_name
points to the host that your homeserver runs on, you do not need an
+SRV record or .well-known/matrix/server
URI.
For instance, if you registered example.com
and pointed its DNS A record at a
+fresh Upcloud VPS or similar, you could install Synapse 0.99 on that host,
+giving it a server_name of example.com
, and it would automatically generate a
+valid TLS certificate for you via Let's Encrypt and no SRV record or
+.well-known
URI would be needed.
This is the common case, although you can add an SRV record or
+.well-known/matrix/server
URI for completeness if you wish.
However, if your server does not listen on port 8448, or if your server_name
+does not point to the host that your homeserver runs on, you will need to let
+other servers know how to find it.
In this case, you should see "If you do have an SRV record +currently" above.
+Firstly, if you didn't need an SRV record before (because your server is +listening on port 8448 of your server_name), you certainly don't need one now: +the defaults are still the same.
+If you previously had an SRV record, you can keep using it provided you are +able to give Synapse a TLS certificate corresponding to your server name. For +example, suppose you had the following SRV record, which directs matrix traffic +for example.com to matrix.example.com:443:
+_matrix._tcp.example.com. IN SRV 10 5 443 matrix.example.com
+
+In this case, Synapse must be given a certificate for example.com - or be +configured to acquire one from Let's Encrypt.
+If you are unable to give Synapse a certificate for your server_name, you will +also need to use a .well-known URI instead. However, see also "I have created a +.well-known URI. Do I still need an SRV record?".
+As of Synapse 0.99, Synapse will first check for the existence of a .well-known
+URI and follow any delegation it suggests. It will only then check for the
+existence of an SRV record.
That means that the SRV record will often be redundant. However, you should
+remember that there may still be older versions of Synapse in the federation
+which do not understand .well-known
URIs, so if you removed your SRV record you
+would no longer be able to federate with them.
It is therefore best to leave the SRV record in place for now. Synapse 0.34 and +earlier will follow the SRV record (and not care about the invalid +certificate). Synapse 0.99 and later will follow the .well-known URI, with the +correct certificate chain.
+We have always wanted Matrix servers to be as easy to set up as possible, and +so back when we started federation in 2014 we didn't want admins to have to go +through the cumbersome process of buying a valid TLS certificate to run a +server. This was before Let's Encrypt came along and made getting a free and +valid TLS certificate straightforward. So instead, we adopted a system based on +Perspectives: an approach +where you check a set of "notary servers" (in practice, homeservers) to vouch +for the validity of a certificate rather than having it signed by a CA. As long +as enough different notaries agree on the certificate's validity, then it is +trusted.
+However, in practice this has never worked properly. Most people only use the +default notary server (matrix.org), leading to inadvertent centralisation which +we want to eliminate. Meanwhile, we never implemented the full consensus +algorithm to query the servers participating in a room to determine consensus +on whether a given certificate is valid. This is fiddly to get right +(especially in face of sybil attacks), and we found ourselves questioning +whether it was worth the effort to finish the work and commit to maintaining a +secure certificate validation system as opposed to focusing on core Matrix +development.
+Meanwhile, Let's Encrypt came along in 2016, and put the final nail in the +coffin of the Perspectives project (which was already pretty dead). So, the +Spec Core Team decided that a better approach would be to mandate valid TLS +certificates for federation alongside the rest of the Web. More details can be +found in +MSC1711.
+This results in a breaking change, which is disruptive, but absolutely critical +for the security model. However, the existence of Let's Encrypt as a trivial +way to replace the old self-signed certificates with valid CA-signed ones helps +smooth things over massively, especially as Synapse can now automate Let's +Encrypt certificate generation if needed.
+Yes, you are welcome to manage your certificates yourself. Synapse will only +attempt to obtain certificates from Let's Encrypt if you configure it to do +so.The only requirement is that there is a valid TLS cert present for +federation end points.
+We no longer actively recommend against using a reverse proxy. Many admins will +find it easier to direct federation traffic to a reverse proxy and manage their +own TLS certificates, and this is a supported configuration.
+See reverse_proxy.md for information on setting up a +reverse proxy.
+Practically speaking, this is no longer necessary.
+If you are using a reverse proxy for all of your TLS traffic, then you can set
+no_tls: True
. In that case, the only reason Synapse needs the certificate is
+to populate a legacy 'tls_fingerprints' field in the federation API. This is
+ignored by Synapse 0.99.0 and later, and the only time pre-0.99 Synapses will
+check it is when attempting to fetch the server keys - and generally this is
+delegated via matrix.org
, which is on 0.99.0.
However, there is a bug in Synapse 0.99.0 +4554 which prevents +Synapse from starting if you do not give it a TLS certificate. To work around +this, you can give it any TLS certificate at all. This will be fixed soon.
+No. There is nothing stopping you from using different certificates, +particularly if you are using a reverse proxy. However, Synapse will use the +same certificate on any ports where TLS is configured.
+Synapse will reload the keys and certificates when it receives a SIGHUP - for
+example kill -HUP $(cat homeserver.pid)
. Alternatively, simply restart
+Synapse, though this will result in downtime while it restarts.
This API allows a server administrator to manage the validity of an account. To
+use it, you must enable the account validity feature (under
+account_validity
) in Synapse's configuration.
This API extends the validity of an account by as much time as configured in the
+period
parameter from the account_validity
configuration.
The API is:
+POST /_synapse/admin/v1/account_validity/validity
+
+with the following body:
+{
+ "user_id": "<user ID for the account to renew>",
+ "expiration_ts": 0,
+ "enable_renewal_emails": true
+}
+
+expiration_ts
is an optional parameter and overrides the expiration date,
+which otherwise defaults to now + validity period.
enable_renewal_emails
is also an optional parameter and enables/disables
+sending renewal emails to the user. Defaults to true.
The API returns with the new expiration date for this account, as a timestamp in +milliseconds since epoch:
+{
+ "expiration_ts": 0
+}
+
+
+ This API lets a server admin delete a local group. Doing so will kick all +users out of the group so that their clients will correctly handle the group +being deleted.
+The API is:
+POST /_synapse/admin/v1/delete_group/<group_id>
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: see Admin API.
This API returns information about reported events.
+The api is:
+GET /_synapse/admin/v1/event_reports?from=0&limit=10
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: see Admin API.
It returns a JSON body like the following:
+{
+ "event_reports": [
+ {
+ "event_id": "$bNUFCwGzWca1meCGkjp-zwslF-GfVcXukvRLI1_FaVY",
+ "id": 2,
+ "reason": "foo",
+ "score": -100,
+ "received_ts": 1570897107409,
+ "canonical_alias": "#alias1:matrix.org",
+ "room_id": "!ERAgBpSOcCCuTJqQPk:matrix.org",
+ "name": "Matrix HQ",
+ "sender": "@foobar:matrix.org",
+ "user_id": "@foo:matrix.org"
+ },
+ {
+ "event_id": "$3IcdZsDaN_En-S1DF4EMCy3v4gNRKeOJs8W5qTOKj4I",
+ "id": 3,
+ "reason": "bar",
+ "score": -100,
+ "received_ts": 1598889612059,
+ "canonical_alias": "#alias2:matrix.org",
+ "room_id": "!eGvUQuTCkHGVwNMOjv:matrix.org",
+ "name": "Your room name here",
+ "sender": "@foobar:matrix.org",
+ "user_id": "@bar:matrix.org"
+ }
+ ],
+ "next_token": 2,
+ "total": 4
+}
+
+To paginate, check for next_token
and if present, call the endpoint again with from
+set to the value of next_token
. This will return a new page.
If the endpoint does not return a next_token
then there are no more reports to
+paginate through.
URL parameters:
+limit
: integer - Is optional but is used for pagination, denoting the maximum number
+of items to return in this call. Defaults to 100
.from
: integer - Is optional but used for pagination, denoting the offset in the
+returned results. This should be treated as an opaque value and not explicitly set to
+anything other than the return value of next_token
from a previous call. Defaults to 0
.dir
: string - Direction of event report order. Whether to fetch the most recent
+first (b
) or the oldest first (f
). Defaults to b
.user_id
: string - Is optional and filters to only return users with user IDs that
+contain this value. This is the user who reported the event and wrote the reason.room_id
: string - Is optional and filters to only return rooms with room IDs that
+contain this value.Response
+The following fields are returned in the JSON response body:
+id
: integer - ID of event report.received_ts
: integer - The timestamp (in milliseconds since the unix epoch) when this
+report was sent.room_id
: string - The ID of the room in which the event being reported is located.name
: string - The name of the room.event_id
: string - The ID of the reported event.user_id
: string - This is the user who reported the event and wrote the reason.reason
: string - Comment made by the user_id
in this report. May be blank or null
.score
: integer - Content is reported based upon a negative score, where -100 is
+"most offensive" and 0 is "inoffensive". May be null
.sender
: string - This is the ID of the user who sent the original message/event that
+was reported.canonical_alias
: string - The canonical alias of the room. null
if the room does not
+have a canonical alias set.next_token
: integer - Indication for pagination. See above.total
: integer - Total number of event reports related to the query
+(user_id
and room_id
).This API returns information about a specific event report.
+The api is:
+GET /_synapse/admin/v1/event_reports/<report_id>
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: see Admin API.
It returns a JSON body like the following:
+{
+ "event_id": "$bNUFCwGzWca1meCGkjp-zwslF-GfVcXukvRLI1_FaVY",
+ "event_json": {
+ "auth_events": [
+ "$YK4arsKKcc0LRoe700pS8DSjOvUT4NDv0HfInlMFw2M",
+ "$oggsNXxzPFRE3y53SUNd7nsj69-QzKv03a1RucHu-ws"
+ ],
+ "content": {
+ "body": "matrix.org: This Week in Matrix",
+ "format": "org.matrix.custom.html",
+ "formatted_body": "<strong>matrix.org</strong>:<br><a href=\"https://matrix.org/blog/\"><strong>This Week in Matrix</strong></a>",
+ "msgtype": "m.notice"
+ },
+ "depth": 546,
+ "hashes": {
+ "sha256": "xK1//xnmvHJIOvbgXlkI8eEqdvoMmihVDJ9J4SNlsAw"
+ },
+ "origin": "matrix.org",
+ "origin_server_ts": 1592291711430,
+ "prev_events": [
+ "$YK4arsKKcc0LRoe700pS8DSjOvUT4NDv0HfInlMFw2M"
+ ],
+ "prev_state": [],
+ "room_id": "!ERAgBpSOcCCuTJqQPk:matrix.org",
+ "sender": "@foobar:matrix.org",
+ "signatures": {
+ "matrix.org": {
+ "ed25519:a_JaEG": "cs+OUKW/iHx5pEidbWxh0UiNNHwe46Ai9LwNz+Ah16aWDNszVIe2gaAcVZfvNsBhakQTew51tlKmL2kspXk/Dg"
+ }
+ },
+ "type": "m.room.message",
+ "unsigned": {
+ "age_ts": 1592291711430,
+ }
+ },
+ "id": <report_id>,
+ "reason": "foo",
+ "score": -100,
+ "received_ts": 1570897107409,
+ "canonical_alias": "#alias1:matrix.org",
+ "room_id": "!ERAgBpSOcCCuTJqQPk:matrix.org",
+ "name": "Matrix HQ",
+ "sender": "@foobar:matrix.org",
+ "user_id": "@foo:matrix.org"
+}
+
+URL parameters:
+report_id
: string - The ID of the event report.Response
+The following fields are returned in the JSON response body:
+id
: integer - ID of event report.received_ts
: integer - The timestamp (in milliseconds since the unix epoch) when this
+report was sent.room_id
: string - The ID of the room in which the event being reported is located.name
: string - The name of the room.event_id
: string - The ID of the reported event.user_id
: string - This is the user who reported the event and wrote the reason.reason
: string - Comment made by the user_id
in this report. May be blank.score
: integer - Content is reported based upon a negative score, where -100 is
+"most offensive" and 0 is "inoffensive".sender
: string - This is the ID of the user who sent the original message/event that
+was reported.canonical_alias
: string - The canonical alias of the room. null
if the room does not
+have a canonical alias set.event_json
: object - Details of the original event that was reported.These APIs allow extracting media information from the homeserver.
+This API gets a list of known media in a room. +However, it only shows media from unencrypted events or rooms.
+The API is:
+GET /_synapse/admin/v1/room/<room_id>/media
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: see Admin API.
The API returns a JSON body like the following:
+{
+ "local": [
+ "mxc://localhost/xwvutsrqponmlkjihgfedcba",
+ "mxc://localhost/abcdefghijklmnopqrstuvwx"
+ ],
+ "remote": [
+ "mxc://matrix.org/xwvutsrqponmlkjihgfedcba",
+ "mxc://matrix.org/abcdefghijklmnopqrstuvwx"
+ ]
+}
+
+Listing all media that has been uploaded by a local user can be achieved through +the use of the List media of a user +Admin API.
+Quarantining media means that it is marked as inaccessible by users. It applies +to any local media, and any locally-cached copies of remote media.
+The media file itself (and any thumbnails) is not deleted from the server.
+This API quarantines a single piece of local or remote media.
+Request:
+POST /_synapse/admin/v1/media/quarantine/<server_name>/<media_id>
+
+{}
+
+Where server_name
is in the form of example.org
, and media_id
is in the
+form of abcdefg12345...
.
Response:
+{}
+
+This API removes a single piece of local or remote media from quarantine.
+Request:
+POST /_synapse/admin/v1/media/unquarantine/<server_name>/<media_id>
+
+{}
+
+Where server_name
is in the form of example.org
, and media_id
is in the
+form of abcdefg12345...
.
Response:
+{}
+
+This API quarantines all local and remote media in a room.
+Request:
+POST /_synapse/admin/v1/room/<room_id>/media/quarantine
+
+{}
+
+Where room_id
is in the form of !roomid12345:example.org
.
Response:
+{
+ "num_quarantined": 10
+}
+
+The following fields are returned in the JSON response body:
+num_quarantined
: integer - The number of media items successfully quarantinedNote that there is a legacy endpoint, POST /_synapse/admin/v1/quarantine_media/<room_id>
, that operates the same.
+However, it is deprecated and may be removed in a future release.
This API quarantines all local media that a local user has uploaded. That is to say, if +you would like to quarantine media uploaded by a user on a remote homeserver, you should +instead use one of the other APIs.
+Request:
+POST /_synapse/admin/v1/user/<user_id>/media/quarantine
+
+{}
+
+URL Parameters
+user_id
: string - User ID in the form of @bob:example.org
Response:
+{
+ "num_quarantined": 10
+}
+
+The following fields are returned in the JSON response body:
+num_quarantined
: integer - The number of media items successfully quarantinedThis API protects a single piece of local media from being quarantined using the +above APIs. This is useful for sticker packs and other shared media which you do +not want to get quarantined, especially when +quarantining media in a room.
+Request:
+POST /_synapse/admin/v1/media/protect/<media_id>
+
+{}
+
+Where media_id
is in the form of abcdefg12345...
.
Response:
+{}
+
+This API reverts the protection of a media.
+Request:
+POST /_synapse/admin/v1/media/unprotect/<media_id>
+
+{}
+
+Where media_id
is in the form of abcdefg12345...
.
Response:
+{}
+
+This API deletes the local media from the disk of your own server. +This includes any local thumbnails and copies of media downloaded from +remote homeservers. +This API will not affect media that has been uploaded to external +media repositories (e.g https://github.com/turt2live/matrix-media-repo/). +See also Purge Remote Media API.
+Delete a specific media_id
.
Request:
+DELETE /_synapse/admin/v1/media/<server_name>/<media_id>
+
+{}
+
+URL Parameters
+server_name
: string - The name of your local server (e.g matrix.org
)media_id
: string - The ID of the media (e.g abcdefghijklmnopqrstuvwx
)Response:
+{
+ "deleted_media": [
+ "abcdefghijklmnopqrstuvwx"
+ ],
+ "total": 1
+}
+
+The following fields are returned in the JSON response body:
+deleted_media
: an array of strings - List of deleted media_id
total
: integer - Total number of deleted media_id
Request:
+POST /_synapse/admin/v1/media/<server_name>/delete?before_ts=<before_ts>
+
+{}
+
+URL Parameters
+server_name
: string - The name of your local server (e.g matrix.org
).before_ts
: string representing a positive integer - Unix timestamp in ms.
+Files that were last used before this timestamp will be deleted. It is the timestamp of
+last access and not the timestamp creation. size_gt
: Optional - string representing a positive integer - Size of the media in bytes.
+Files that are larger will be deleted. Defaults to 0
.keep_profiles
: Optional - string representing a boolean - Switch to also delete files
+that are still used in image data (e.g user profile, room avatar).
+If false
these files will be deleted. Defaults to true
.Response:
+{
+ "deleted_media": [
+ "abcdefghijklmnopqrstuvwx",
+ "abcdefghijklmnopqrstuvwz"
+ ],
+ "total": 2
+}
+
+The following fields are returned in the JSON response body:
+deleted_media
: an array of strings - List of deleted media_id
total
: integer - Total number of deleted media_id
The purge remote media API allows server admins to purge old cached remote media.
+The API is:
+POST /_synapse/admin/v1/purge_media_cache?before_ts=<unix_timestamp_in_ms>
+
+{}
+
+URL Parameters
+unix_timestamp_in_ms
: string representing a positive integer - Unix timestamp in ms.
+All cached media that was last accessed before this timestamp will be removed.Response:
+{
+ "deleted": 10
+}
+
+The following fields are returned in the JSON response body:
+deleted
: integer - The number of media items successfully deletedTo use it, you will need to authenticate by providing an access_token
for a
+server admin: see Admin API.
If the user re-requests purged remote media, synapse will re-request the media +from the originating server.
+ +The purge history API allows server admins to purge historic events from their +database, reclaiming disk space.
+Depending on the amount of history being purged a call to the API may take +several minutes or longer. During this period users will not be able to +paginate further back in the room from the point being purged from.
+Note that Synapse requires at least one message in each room, so it will never +delete the last message in a room.
+The API is:
+POST /_synapse/admin/v1/purge_history/<room_id>[/<event_id>]
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
By default, events sent by local users are not deleted, as they may represent +the only copies of this content in existence. (Events sent by remote users are +deleted.)
+Room state data (such as joins, leaves, topic) is always preserved.
+To delete local message events as well, set delete_local_events
in the body:
{
+ "delete_local_events": true
+}
+
+The caller must specify the point in the room to purge up to. This can be
+specified by including an event_id in the URI, or by setting a
+purge_up_to_event_id
or purge_up_to_ts
in the request body. If an event
+id is given, that event (and others at the same graph depth) will be retained.
+If purge_up_to_ts
is given, it should be a timestamp since the unix epoch,
+in milliseconds.
The API starts the purge running, and returns immediately with a JSON body with +a purge id:
+{
+ "purge_id": "<opaque id>"
+}
+
+It is possible to poll for updates on recent purges with a second API;
+GET /_synapse/admin/v1/purge_history_status/<purge_id>
+
+Again, you will need to authenticate by providing an access_token
for a
+server admin.
This API returns a JSON body like the following:
+{
+ "status": "active"
+}
+
+The status will be one of active
, complete
, or failed
.
To reclaim the disk space and return it to the operating system, you need to run
+VACUUM FULL;
on the database.
The old Purge room API is deprecated and will be removed in a future release. +See the new Delete Room API for more details.
+This API will remove all trace of a room from your database.
+All local users must have left the room before it can be removed.
+The API is:
+POST /_synapse/admin/v1/purge_room
+
+{
+ "room_id": "!room:id"
+}
+
+You must authenticate using the access token of an admin user.
+ +This API allows for the creation of users in an administrative and +non-interactive way. This is generally used for bootstrapping a Synapse +instance with administrator accounts.
+To authenticate yourself to the server, you will need both the shared secret
+(registration_shared_secret
in the homeserver configuration), and a
+one-time nonce. If the registration shared secret is not configured, this API
+is not enabled.
To fetch the nonce, you need to request one from the API:
+> GET /_synapse/admin/v1/register
+
+< {"nonce": "thisisanonce"}
+
+Once you have the nonce, you can make a POST
to the same URL with a JSON
+body containing the nonce, username, password, whether they are an admin
+(optional, False by default), and a HMAC digest of the content. Also you can
+set the displayname (optional, username
by default).
As an example:
+> POST /_synapse/admin/v1/register
+> {
+ "nonce": "thisisanonce",
+ "username": "pepper_roni",
+ "displayname": "Pepper Roni",
+ "password": "pizza",
+ "admin": true,
+ "mac": "mac_digest_here"
+ }
+
+< {
+ "access_token": "token_here",
+ "user_id": "@pepper_roni:localhost",
+ "home_server": "test",
+ "device_id": "device_id_here"
+ }
+
+The MAC is the hex digest output of the HMAC-SHA1 algorithm, with the key being +the shared secret and the content being the nonce, user, password, either the +string "admin" or "notadmin", and optionally the user_type +each separated by NULs. For an example of generation in Python:
+import hmac, hashlib
+
+def generate_mac(nonce, user, password, admin=False, user_type=None):
+
+ mac = hmac.new(
+ key=shared_secret,
+ digestmod=hashlib.sha1,
+ )
+
+ mac.update(nonce.encode('utf8'))
+ mac.update(b"\x00")
+ mac.update(user.encode('utf8'))
+ mac.update(b"\x00")
+ mac.update(password.encode('utf8'))
+ mac.update(b"\x00")
+ mac.update(b"admin" if admin else b"notadmin")
+ if user_type:
+ mac.update(b"\x00")
+ mac.update(user_type.encode('utf8'))
+
+ return mac.hexdigest()
+
+
+ This API allows an administrator to join an user account with a given user_id
+to a room with a given room_id_or_alias
. You can only modify the membership of
+local users. The server administrator must be in the room and have permission to
+invite users.
The following parameters are available:
+user_id
- Fully qualified user: for example, @user:server.com
.room_id_or_alias
- The room identifier or alias to join: for example,
+!636q39766251:server.com
.POST /_synapse/admin/v1/join/<room_id_or_alias>
+
+{
+ "user_id": "@user:server.com"
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: see Admin API.
Response:
+{
+ "room_id": "!636q39766251:server.com"
+}
+
+
+ The List Room admin API allows server admins to get a list of rooms on their +server. There are various parameters available that allow for filtering and +sorting the returned list. This API supports pagination.
+The following query parameters are available:
+from
- Offset in the returned list. Defaults to 0
.limit
- Maximum amount of rooms to return. Defaults to 100
.order_by
- The method in which to sort the returned list of rooms. Valid values are:
+alphabetical
- Same as name
. This is deprecated.size
- Same as joined_members
. This is deprecated.name
- Rooms are ordered alphabetically by room name. This is the default.canonical_alias
- Rooms are ordered alphabetically by main alias address of the room.joined_members
- Rooms are ordered by the number of members. Largest to smallest.joined_local_members
- Rooms are ordered by the number of local members. Largest to smallest.version
- Rooms are ordered by room version. Largest to smallest.creator
- Rooms are ordered alphabetically by creator of the room.encryption
- Rooms are ordered alphabetically by the end-to-end encryption algorithm.federatable
- Rooms are ordered by whether the room is federatable.public
- Rooms are ordered by visibility in room list.join_rules
- Rooms are ordered alphabetically by join rules of the room.guest_access
- Rooms are ordered alphabetically by guest access option of the room.history_visibility
- Rooms are ordered alphabetically by visibility of history of the room.state_events
- Rooms are ordered by number of state events. Largest to smallest.dir
- Direction of room order. Either f
for forwards or b
for backwards. Setting
+this value to b
will reverse the above sort order. Defaults to f
.search_term
- Filter rooms by their room name. Search term can be contained in any
+part of the room name. Defaults to no filtering.The following fields are possible in the JSON response body:
+rooms
- An array of objects, each containing information about a room.
+room_id
- The ID of the room.name
- The name of the room.canonical_alias
- The canonical (main) alias address of the room.joined_members
- How many users are currently in the room.joined_local_members
- How many local users are currently in the room.version
- The version of the room as a string.creator
- The user_id
of the room creator.encryption
- Algorithm of end-to-end encryption of messages. Is null
if encryption is not active.federatable
- Whether users on other servers can join this room.public
- Whether the room is visible in room directory.join_rules
- The type of rules used for users wishing to join this room. One of: ["public", "knock", "invite", "private"].guest_access
- Whether guests can join the room. One of: ["can_join", "forbidden"].history_visibility
- Who can see the room history. One of: ["invited", "joined", "shared", "world_readable"].state_events
- Total number of state_events of a room. Complexity of the room.offset
- The current pagination offset in rooms. This parameter should be
+used instead of next_token
for room offset as next_token
is
+not intended to be parsed.total_rooms
- The total number of rooms this query can return. Using this
+and offset
, you have enough information to know the current
+progression through the list.next_batch
- If this field is present, we know that there are potentially
+more rooms on the server that did not all fit into this response.
+We can use next_batch
to get the "next page" of results. To do
+so, simply repeat your request, setting the from
parameter to
+the value of next_batch
.prev_batch
- If this field is present, it is possible to paginate backwards.
+Use prev_batch
for the from
value in the next request to
+get the "previous page" of results.A standard request with no filtering:
+GET /_synapse/admin/v1/rooms
+
+{}
+
+Response:
+{
+ "rooms": [
+ {
+ "room_id": "!OGEhHVWSdvArJzumhm:matrix.org",
+ "name": "Matrix HQ",
+ "canonical_alias": "#matrix:matrix.org",
+ "joined_members": 8326,
+ "joined_local_members": 2,
+ "version": "1",
+ "creator": "@foo:matrix.org",
+ "encryption": null,
+ "federatable": true,
+ "public": true,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 93534
+ },
+ ... (8 hidden items) ...
+ {
+ "room_id": "!xYvNcQPhnkrdUmYczI:matrix.org",
+ "name": "This Week In Matrix (TWIM)",
+ "canonical_alias": "#twim:matrix.org",
+ "joined_members": 314,
+ "joined_local_members": 20,
+ "version": "4",
+ "creator": "@foo:matrix.org",
+ "encryption": "m.megolm.v1.aes-sha2",
+ "federatable": true,
+ "public": false,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 8345
+ }
+ ],
+ "offset": 0,
+ "total_rooms": 10
+}
+
+Filtering by room name:
+GET /_synapse/admin/v1/rooms?search_term=TWIM
+
+{}
+
+Response:
+{
+ "rooms": [
+ {
+ "room_id": "!xYvNcQPhnkrdUmYczI:matrix.org",
+ "name": "This Week In Matrix (TWIM)",
+ "canonical_alias": "#twim:matrix.org",
+ "joined_members": 314,
+ "joined_local_members": 20,
+ "version": "4",
+ "creator": "@foo:matrix.org",
+ "encryption": "m.megolm.v1.aes-sha2",
+ "federatable": true,
+ "public": false,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 8
+ }
+ ],
+ "offset": 0,
+ "total_rooms": 1
+}
+
+Paginating through a list of rooms:
+GET /_synapse/admin/v1/rooms?order_by=size
+
+{}
+
+Response:
+{
+ "rooms": [
+ {
+ "room_id": "!OGEhHVWSdvArJzumhm:matrix.org",
+ "name": "Matrix HQ",
+ "canonical_alias": "#matrix:matrix.org",
+ "joined_members": 8326,
+ "joined_local_members": 2,
+ "version": "1",
+ "creator": "@foo:matrix.org",
+ "encryption": null,
+ "federatable": true,
+ "public": true,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 93534
+ },
+ ... (98 hidden items) ...
+ {
+ "room_id": "!xYvNcQPhnkrdUmYczI:matrix.org",
+ "name": "This Week In Matrix (TWIM)",
+ "canonical_alias": "#twim:matrix.org",
+ "joined_members": 314,
+ "joined_local_members": 20,
+ "version": "4",
+ "creator": "@foo:matrix.org",
+ "encryption": "m.megolm.v1.aes-sha2",
+ "federatable": true,
+ "public": false,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 8345
+ }
+ ],
+ "offset": 0,
+ "total_rooms": 150
+ "next_token": 100
+}
+
+The presence of the next_token
parameter tells us that there are more rooms
+than returned in this request, and we need to make another request to get them.
+To get the next batch of room results, we repeat our request, setting the from
+parameter to the value of next_token
.
GET /_synapse/admin/v1/rooms?order_by=size&from=100
+
+{}
+
+Response:
+{
+ "rooms": [
+ {
+ "room_id": "!mscvqgqpHYjBGDxNym:matrix.org",
+ "name": "Music Theory",
+ "canonical_alias": "#musictheory:matrix.org",
+ "joined_members": 127,
+ "joined_local_members": 2,
+ "version": "1",
+ "creator": "@foo:matrix.org",
+ "encryption": null,
+ "federatable": true,
+ "public": true,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 93534
+ },
+ ... (48 hidden items) ...
+ {
+ "room_id": "!twcBhHVdZlQWuuxBhN:termina.org.uk",
+ "name": "weechat-matrix",
+ "canonical_alias": "#weechat-matrix:termina.org.uk",
+ "joined_members": 137,
+ "joined_local_members": 20,
+ "version": "4",
+ "creator": "@foo:termina.org.uk",
+ "encryption": null,
+ "federatable": true,
+ "public": true,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 8345
+ }
+ ],
+ "offset": 100,
+ "prev_batch": 0,
+ "total_rooms": 150
+}
+
+Once the next_token
parameter is no longer present, we know we've reached the
+end of the list.
The Room Details admin API allows server admins to get all details of a room.
+The following fields are possible in the JSON response body:
+room_id
- The ID of the room.name
- The name of the room.topic
- The topic of the room.avatar
- The mxc
URI to the avatar of the room.canonical_alias
- The canonical (main) alias address of the room.joined_members
- How many users are currently in the room.joined_local_members
- How many local users are currently in the room.joined_local_devices
- How many local devices are currently in the room.version
- The version of the room as a string.creator
- The user_id
of the room creator.encryption
- Algorithm of end-to-end encryption of messages. Is null
if encryption is not active.federatable
- Whether users on other servers can join this room.public
- Whether the room is visible in room directory.join_rules
- The type of rules used for users wishing to join this room. One of: ["public", "knock", "invite", "private"].guest_access
- Whether guests can join the room. One of: ["can_join", "forbidden"].history_visibility
- Who can see the room history. One of: ["invited", "joined", "shared", "world_readable"].state_events
- Total number of state_events of a room. Complexity of the room.A standard request:
+GET /_synapse/admin/v1/rooms/<room_id>
+
+{}
+
+Response:
+{
+ "room_id": "!mscvqgqpHYjBGDxNym:matrix.org",
+ "name": "Music Theory",
+ "avatar": "mxc://matrix.org/AQDaVFlbkQoErdOgqWRgiGSV",
+ "topic": "Theory, Composition, Notation, Analysis",
+ "canonical_alias": "#musictheory:matrix.org",
+ "joined_members": 127,
+ "joined_local_members": 2,
+ "joined_local_devices": 2,
+ "version": "1",
+ "creator": "@foo:matrix.org",
+ "encryption": null,
+ "federatable": true,
+ "public": true,
+ "join_rules": "invite",
+ "guest_access": null,
+ "history_visibility": "shared",
+ "state_events": 93534
+}
+
+The Room Members admin API allows server admins to get a list of all members of a room.
+The response includes the following fields:
+members
- A list of all the members that are present in the room, represented by their ids.total
- Total number of members in the room.A standard request:
+GET /_synapse/admin/v1/rooms/<room_id>/members
+
+{}
+
+Response:
+{
+ "members": [
+ "@foo:matrix.org",
+ "@bar:matrix.org",
+ "@foobar:matrix.org"
+ ],
+ "total": 3
+}
+
+The Room State admin API allows server admins to get a list of all state events in a room.
+The response includes the following fields:
+state
- The current state of the room at the time of request.A standard request:
+GET /_synapse/admin/v1/rooms/<room_id>/state
+
+{}
+
+Response:
+{
+ "state": [
+ {"type": "m.room.create", "state_key": "", "etc": true},
+ {"type": "m.room.power_levels", "state_key": "", "etc": true},
+ {"type": "m.room.name", "state_key": "", "etc": true}
+ ]
+}
+
+The Delete Room admin API allows server admins to remove rooms from server +and block these rooms.
+Shuts down a room. Moves all local users and room aliases automatically to a
+new room if new_room_user_id
is set. Otherwise local users only
+leave the room without any information.
The new room will be created with the user specified by the new_room_user_id
parameter
+as room administrator and will contain a message explaining what happened. Users invited
+to the new room will have power level -10
by default, and thus be unable to speak.
If block
is True
it prevents new joins to the old room.
This API will remove all trace of the old room from your database after removing
+all local users. If purge
is true
(the default), all traces of the old room will
+be removed from your database after removing all local users. If you do not want
+this to happen, set purge
to false
.
+Depending on the amount of history being purged a call to the API may take
+several minutes or longer.
The local server will only have the power to move local user and room aliases to +the new room. Users on other servers will be unaffected.
+The API is:
+DELETE /_synapse/admin/v1/rooms/<room_id>
+
+with a body of:
+{
+ "new_room_user_id": "@someuser:example.com",
+ "room_name": "Content Violation Notification",
+ "message": "Bad Room has been shutdown due to content violations on this server. Please review our Terms of Service.",
+ "block": true,
+ "purge": true
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: see Admin API.
A response body like the following is returned:
+{
+ "kicked_users": [
+ "@foobar:example.com"
+ ],
+ "failed_to_kick_users": [],
+ "local_aliases": [
+ "#badroom:example.com",
+ "#evilsaloon:example.com"
+ ],
+ "new_room_id": "!newroomid:example.com"
+}
+
+The following parameters should be set in the URL:
+room_id
- The ID of the room.The following JSON body parameters are available:
+new_room_user_id
- Optional. If set, a new room will be created with this user ID
+as the creator and admin, and all users in the old room will be moved into that
+room. If not set, no new room will be created and the users will just be removed
+from the old room. The user ID must be on the local server, but does not necessarily
+have to belong to a registered user.room_name
- Optional. A string representing the name of the room that new users will be
+invited to. Defaults to Content Violation Notification
message
- Optional. A string containing the first message that will be sent as
+new_room_user_id
in the new room. Ideally this will clearly convey why the
+original room was shut down. Defaults to Sharing illegal content on this server is not permitted and rooms in violation will be blocked.
block
- Optional. If set to true
, this room will be added to a blocking list, preventing
+future attempts to join the room. Defaults to false
.purge
- Optional. If set to true
, it will remove all traces of the room from your database.
+Defaults to true
.force_purge
- Optional, and ignored unless purge
is true
. If set to true
, it
+will force a purge to go ahead even if there are local users still in the room. Do not
+use this unless a regular purge
operation fails, as it could leave those users'
+clients in a confused state.The JSON body must not be empty. The body must be at least {}
.
The following fields are returned in the JSON response body:
+kicked_users
- An array of users (user_id
) that were kicked.failed_to_kick_users
- An array of users (user_id
) that that were not kicked.local_aliases
- An array of strings representing the local aliases that were migrated from
+the old room to the new.new_room_id
- A string representing the room ID of the new room.Note: This guide may be outdated by the time you read it. By nature of room shutdowns being performed at the database level, +the structure can and does change without notice.
+First, it's important to understand that a room shutdown is very destructive. Undoing a shutdown is not as simple as pretending it +never happened - work has to be done to move forward instead of resetting the past. In fact, in some cases it might not be possible +to recover at all:
+With all that being said, if you still want to try and recover the room:
+DELETE FROM blocked_rooms WHERE room_id = '!example:example.org';
+BEGIN; DELETE ...;
, verify you got 1 result, then COMMIT;
.You will have to manually handle, if you so choose, the following:
+The previous deprecated API will be removed in a future release, it was:
+POST /_synapse/admin/v1/rooms/<room_id>/delete
+
+It behaves the same way than the current endpoint except the path and the method.
+Grants another user the highest power available to a local user who is in the room. +If the user is not in the room, and it is not publicly joinable, then invite the user.
+By default the server admin (the caller) is granted power, but another user can +optionally be specified, e.g.:
+ POST /_synapse/admin/v1/rooms/<room_id_or_alias>/make_room_admin
+ {
+ "user_id": "@foo:example.com"
+ }
+
+Enables querying and deleting forward extremities from rooms. When a lot of forward +extremities accumulate in a room, performance can become degraded. For details, see +#1760.
+To check the status of forward extremities for a room:
+ GET /_synapse/admin/v1/rooms/<room_id_or_alias>/forward_extremities
+
+A response as follows will be returned:
+{
+ "count": 1,
+ "results": [
+ {
+ "event_id": "$M5SP266vsnxctfwFgFLNceaCo3ujhRtg_NiiHabcdefgh",
+ "state_group": 439,
+ "depth": 123,
+ "received_ts": 1611263016761
+ }
+ ]
+}
+
+WARNING: Please ensure you know what you're doing and have read +the related issue #1760. +Under no situations should this API be executed as an automated maintenance task!
+If a room has lots of forward extremities, the extra can be +deleted as follows:
+ DELETE /_synapse/admin/v1/rooms/<room_id_or_alias>/forward_extremities
+
+A response as follows will be returned, indicating the amount of forward extremities +that were deleted.
+{
+ "deleted": 1
+}
+
+This API lets a client find the context of an event. This is designed primarily to investigate abuse reports.
+GET /_synapse/admin/v1/rooms/<room_id>/context/<event_id>
+
+This API mimmicks GET /_matrix/client/r0/rooms/{roomId}/context/{eventId}. Please refer to the link for all details on parameters and reseponse.
+Example response:
+{
+ "end": "t29-57_2_0_2",
+ "events_after": [
+ {
+ "content": {
+ "body": "This is an example text message",
+ "msgtype": "m.text",
+ "format": "org.matrix.custom.html",
+ "formatted_body": "<b>This is an example text message</b>"
+ },
+ "type": "m.room.message",
+ "event_id": "$143273582443PhrSn:example.org",
+ "room_id": "!636q39766251:example.com",
+ "sender": "@example:example.org",
+ "origin_server_ts": 1432735824653,
+ "unsigned": {
+ "age": 1234
+ }
+ }
+ ],
+ "event": {
+ "content": {
+ "body": "filename.jpg",
+ "info": {
+ "h": 398,
+ "w": 394,
+ "mimetype": "image/jpeg",
+ "size": 31037
+ },
+ "url": "mxc://example.org/JWEIFJgwEIhweiWJE",
+ "msgtype": "m.image"
+ },
+ "type": "m.room.message",
+ "event_id": "$f3h4d129462ha:example.com",
+ "room_id": "!636q39766251:example.com",
+ "sender": "@example:example.org",
+ "origin_server_ts": 1432735824653,
+ "unsigned": {
+ "age": 1234
+ }
+ },
+ "events_before": [
+ {
+ "content": {
+ "body": "something-important.doc",
+ "filename": "something-important.doc",
+ "info": {
+ "mimetype": "application/msword",
+ "size": 46144
+ },
+ "msgtype": "m.file",
+ "url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
+ },
+ "type": "m.room.message",
+ "event_id": "$143273582443PhrSn:example.org",
+ "room_id": "!636q39766251:example.com",
+ "sender": "@example:example.org",
+ "origin_server_ts": 1432735824653,
+ "unsigned": {
+ "age": 1234
+ }
+ }
+ ],
+ "start": "t27-54_2_0_2",
+ "state": [
+ {
+ "content": {
+ "creator": "@example:example.org",
+ "room_version": "1",
+ "m.federate": true,
+ "predecessor": {
+ "event_id": "$something:example.org",
+ "room_id": "!oldroom:example.org"
+ }
+ },
+ "type": "m.room.create",
+ "event_id": "$143273582443PhrSn:example.org",
+ "room_id": "!636q39766251:example.com",
+ "sender": "@example:example.org",
+ "origin_server_ts": 1432735824653,
+ "unsigned": {
+ "age": 1234
+ },
+ "state_key": ""
+ },
+ {
+ "content": {
+ "membership": "join",
+ "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
+ "displayname": "Alice Margatroid"
+ },
+ "type": "m.room.member",
+ "event_id": "$143273582443PhrSn:example.org",
+ "room_id": "!636q39766251:example.com",
+ "sender": "@example:example.org",
+ "origin_server_ts": 1432735824653,
+ "unsigned": {
+ "age": 1234
+ },
+ "state_key": "@alice:example.org"
+ }
+ ]
+}
+
+
+ The API to send notices is as follows:
+POST /_synapse/admin/v1/send_server_notice
+
+or:
+PUT /_synapse/admin/v1/send_server_notice/{txnId}
+
+You will need to authenticate with an access token for an admin user.
+When using the PUT
form, retransmissions with the same transaction ID will be
+ignored in the same way as with PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}
.
The request body should look something like the following:
+{
+ "user_id": "@target_user:server_name",
+ "content": {
+ "msgtype": "m.text",
+ "body": "This is my message"
+ }
+}
+
+You can optionally include the following additional parameters:
+type
: the type of event. Defaults to m.room.message
.state_key
: Setting this will result in a state event being sent.Once the notice has been sent, the API will return the following response:
+{
+ "event_id": "<event_id>"
+}
+
+Note that server notices must be enabled in homeserver.yaml
before this API
+can be used. See server_notices.md for more information.
The old Shutdown room API is deprecated and will be removed in a future release. +See the new Delete Room API for more details.
+Shuts down a room, preventing new joins and moves local users and room aliases automatically
+to a new room. The new room will be created with the user specified by the
+new_room_user_id
parameter as room administrator and will contain a message
+explaining what happened. Users invited to the new room will have power level
+-10 by default, and thus be unable to speak. The old room's power levels will be changed to
+disallow any further invites or joins.
The local server will only have the power to move local user and room aliases to +the new room. Users on other servers will be unaffected.
+You will need to authenticate with an access token for an admin user.
+POST /_synapse/admin/v1/shutdown_room/{room_id}
room_id
- The ID of the room (e.g !someroom:example.com
)new_room_user_id
- Required. A string representing the user ID of the user that will admin
+the new room that all users in the old room will be moved to.room_name
- Optional. A string representing the name of the room that new users will be
+invited to.message
- Optional. A string containing the first message that will be sent as
+new_room_user_id
in the new room. Ideally this will clearly convey why the
+original room was shut down.If not specified, the default value of room_name
is "Content Violation
+Notification". The default value of message
is "Sharing illegal content on
+othis server is not permitted and rooms in violation will be blocked."
kicked_users
- An integer number representing the number of users that
+were kicked.failed_to_kick_users
- An integer number representing the number of users
+that were not kicked.local_aliases
- An array of strings representing the local aliases that were migrated from
+the old room to the new.new_room_id
- A string representing the room ID of the new room.Request:
+POST /_synapse/admin/v1/shutdown_room/!somebadroom%3Aexample.com
+
+{
+ "new_room_user_id": "@someuser:example.com",
+ "room_name": "Content Violation Notification",
+ "message": "Bad Room has been shutdown due to content violations on this server. Please review our Terms of Service."
+}
+
+Response:
+{
+ "kicked_users": 5,
+ "failed_to_kick_users": 0,
+ "local_aliases": ["#badroom:example.com", "#evilsaloon:example.com],
+ "new_room_id": "!newroomid:example.com",
+},
+
+Note: This guide may be outdated by the time you read it. By nature of room shutdowns being performed at the database level, +the structure can and does change without notice.
+First, it's important to understand that a room shutdown is very destructive. Undoing a shutdown is not as simple as pretending it +never happened - work has to be done to move forward instead of resetting the past. In fact, in some cases it might not be possible +to recover at all:
+With all that being said, if you still want to try and recover the room:
+DELETE FROM blocked_rooms WHERE room_id = '!example:example.org';
+BEGIN; DELETE ...;
, verify you got 1 result, then COMMIT;
.You will have to manually handle, if you so choose, the following:
+Returns information about all local media usage of users. Gives the +possibility to filter them by time and user.
+The API is:
+GET /_synapse/admin/v1/statistics/users/media
+
+To use it, you will need to authenticate by providing an access_token
+for a server admin: see Admin API.
A response body like the following is returned:
+{
+ "users": [
+ {
+ "displayname": "foo_user_0",
+ "media_count": 2,
+ "media_length": 134,
+ "user_id": "@foo_user_0:test"
+ },
+ {
+ "displayname": "foo_user_1",
+ "media_count": 2,
+ "media_length": 134,
+ "user_id": "@foo_user_1:test"
+ }
+ ],
+ "next_token": 3,
+ "total": 10
+}
+
+To paginate, check for next_token
and if present, call the endpoint
+again with from
set to the value of next_token
. This will return a new page.
If the endpoint does not return a next_token
then there are no more
+reports to paginate through.
Parameters
+The following parameters should be set in the URL:
+limit
: string representing a positive integer - Is optional but is
+used for pagination, denoting the maximum number of items to return
+in this call. Defaults to 100
.from
: string representing a positive integer - Is optional but used for pagination,
+denoting the offset in the returned results. This should be treated as an opaque value
+and not explicitly set to anything other than the return value of next_token
from a
+previous call. Defaults to 0
.order_by
- string - The method in which to sort the returned list of users. Valid values are:
+user_id
- Users are ordered alphabetically by user_id
. This is the default.displayname
- Users are ordered alphabetically by displayname
.media_length
- Users are ordered by the total size of uploaded media in bytes.
+Smallest to largest.media_count
- Users are ordered by number of uploaded media. Smallest to largest.from_ts
- string representing a positive integer - Considers only
+files created at this timestamp or later. Unix timestamp in ms.until_ts
- string representing a positive integer - Considers only
+files created at this timestamp or earlier. Unix timestamp in ms.search_term
- string - Filter users by their user ID localpart or displayname.
+The search term can be found in any part of the string.
+Defaults to no filtering.dir
- string - Direction of order. Either f
for forwards or b
for backwards.
+Setting this value to b
will reverse the above sort order. Defaults to f
.Response
+The following fields are returned in the JSON response body:
+users
- An array of objects, each containing information
+about the user and their local media. Objects contain the following fields:
+displayname
- string - Displayname of this user.media_count
- integer - Number of uploaded media by this user.media_length
- integer - Size of uploaded media in bytes by this user.user_id
- string - Fully-qualified user ID (ex. @user:server.com
).next_token
- integer - Opaque value used for pagination. See above.total
- integer - Total number of users after filtering.This API returns information about a specific user account.
+The api is:
+GET /_synapse/admin/v2/users/<user_id>
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
It returns a JSON body like the following:
+{
+ "displayname": "User",
+ "threepids": [
+ {
+ "medium": "email",
+ "address": "<user_mail_1>"
+ },
+ {
+ "medium": "email",
+ "address": "<user_mail_2>"
+ }
+ ],
+ "avatar_url": "<avatar_url>",
+ "admin": 0,
+ "deactivated": 0,
+ "shadow_banned": 0,
+ "password_hash": "$2b$12$p9B4GkqYdRTPGD",
+ "creation_ts": 1560432506,
+ "appservice_id": null,
+ "consent_server_notice_sent": null,
+ "consent_version": null
+}
+
+URL parameters:
+user_id
: fully-qualified user id: for example, @user:server.com
.This API allows an administrator to create or modify a user account with a
+specific user_id
.
This api is:
+PUT /_synapse/admin/v2/users/<user_id>
+
+with a body of:
+{
+ "password": "user_password",
+ "displayname": "User",
+ "threepids": [
+ {
+ "medium": "email",
+ "address": "<user_mail_1>"
+ },
+ {
+ "medium": "email",
+ "address": "<user_mail_2>"
+ }
+ ],
+ "avatar_url": "<avatar_url>",
+ "admin": false,
+ "deactivated": false
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
URL parameters:
+user_id
: fully-qualified user id: for example, @user:server.com
.Body parameters:
+password
, optional. If provided, the user's password is updated and all
+devices are logged out.
displayname
, optional, defaults to the value of user_id
.
threepids
, optional, allows setting the third-party IDs (email, msisdn)
+belonging to a user.
avatar_url
, optional, must be a
+MXC URI.
admin
, optional, defaults to false
.
deactivated
, optional. If unspecified, deactivation state will be left
+unchanged on existing accounts and set to false
for new accounts.
+A user cannot be erased by deactivating with this API. For details on
+deactivating users see Deactivate Account.
If the user already exists then optional parameters default to the current value.
+In order to re-activate an account deactivated
must be set to false
. If
+users do not login via single-sign-on, a new password
must be provided.
This API returns all local user accounts. +By default, the response is ordered by ascending user ID.
+GET /_synapse/admin/v2/users?from=0&limit=10&guests=false
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "users": [
+ {
+ "name": "<user_id1>",
+ "is_guest": 0,
+ "admin": 0,
+ "user_type": null,
+ "deactivated": 0,
+ "shadow_banned": 0,
+ "displayname": "<User One>",
+ "avatar_url": null
+ }, {
+ "name": "<user_id2>",
+ "is_guest": 0,
+ "admin": 1,
+ "user_type": null,
+ "deactivated": 0,
+ "shadow_banned": 0,
+ "displayname": "<User Two>",
+ "avatar_url": "<avatar_url>"
+ }
+ ],
+ "next_token": "100",
+ "total": 200
+}
+
+To paginate, check for next_token
and if present, call the endpoint again
+with from
set to the value of next_token
. This will return a new page.
If the endpoint does not return a next_token
then there are no more users
+to paginate through.
Parameters
+The following parameters should be set in the URL:
+user_id
- Is optional and filters to only return users with user IDs
+that contain this value. This parameter is ignored when using the name
parameter.
name
- Is optional and filters to only return users with user ID localparts
+or displaynames that contain this value.
guests
- string representing a bool - Is optional and if false
will exclude guest users.
+Defaults to true
to include guest users.
deactivated
- string representing a bool - Is optional and if true
will include deactivated users.
+Defaults to false
to exclude deactivated users.
limit
- string representing a positive integer - Is optional but is used for pagination,
+denoting the maximum number of items to return in this call. Defaults to 100
.
from
- string representing a positive integer - Is optional but used for pagination,
+denoting the offset in the returned results. This should be treated as an opaque value and
+not explicitly set to anything other than the return value of next_token
from a previous call.
+Defaults to 0
.
order_by
- The method by which to sort the returned list of users.
+If the ordered field has duplicates, the second order is always by ascending name
,
+which guarantees a stable ordering. Valid values are:
name
- Users are ordered alphabetically by name
. This is the default.is_guest
- Users are ordered by is_guest
status.admin
- Users are ordered by admin
status.user_type
- Users are ordered alphabetically by user_type
.deactivated
- Users are ordered by deactivated
status.shadow_banned
- Users are ordered by shadow_banned
status.displayname
- Users are ordered alphabetically by displayname
.avatar_url
- Users are ordered alphabetically by avatar URL.dir
- Direction of media order. Either f
for forwards or b
for backwards.
+Setting this value to b
will reverse the above sort order. Defaults to f
.
Caution. The database only has indexes on the columns name
and created_ts
.
+This means that if a different sort order is used (is_guest
, admin
,
+user_type
, deactivated
, shadow_banned
, avatar_url
or displayname
),
+this can cause a large load on the database, especially for large environments.
Response
+The following fields are returned in the JSON response body:
+users
- An array of objects, each containing information about an user.
+User objects contain the following fields:
name
- string - Fully-qualified user ID (ex. @user:server.com
).is_guest
- bool - Status if that user is a guest account.admin
- bool - Status if that user is a server administrator.user_type
- string - Type of the user. Normal users are type None
.
+This allows user type specific behaviour. There are also types support
and bot
. deactivated
- bool - Status if that user has been marked as deactivated.shadow_banned
- bool - Status if that user has been marked as shadow banned.displayname
- string - The user's display name if they have set one.avatar_url
- string - The user's avatar URL if they have set one.next_token
: string representing a positive integer - Indication for pagination. See above.
total
- integer - Total number of media.
This API returns information about the active sessions for a specific user.
+The endpoints are:
+GET /_synapse/admin/v1/whois/<user_id>
+
+and:
+GET /_matrix/client/r0/admin/whois/<userId>
+
+See also: Client Server +API Whois.
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
It returns a JSON body like the following:
+{
+ "user_id": "<user_id>",
+ "devices": {
+ "": {
+ "sessions": [
+ {
+ "connections": [
+ {
+ "ip": "1.2.3.4",
+ "last_seen": 1417222374433,
+ "user_agent": "Mozilla/5.0 ..."
+ },
+ {
+ "ip": "1.2.3.10",
+ "last_seen": 1417222374500,
+ "user_agent": "Dalvik/2.1.0 ..."
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
+
+last_seen
is measured in milliseconds since the Unix epoch.
This API deactivates an account. It removes active access tokens, resets the +password, and deletes third-party IDs (to prevent the user requesting a +password reset).
+It can also mark the user as GDPR-erased. This means messages sent by the +user will still be visible by anyone that was in the room when these messages +were sent, but hidden from users joining the room afterwards.
+The api is:
+POST /_synapse/admin/v1/deactivate/<user_id>
+
+with a body of:
+{
+ "erase": true
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
The erase parameter is optional and defaults to false
.
+An empty body may be passed for backwards compatibility.
The following actions are performed when deactivating an user:
+The following additional actions are performed during deactivation if erase
+is set to true
:
Changes the password of another user. This will automatically log the user out of all their devices.
+The api is:
+POST /_synapse/admin/v1/reset_password/<user_id>
+
+with a body of:
+{
+ "new_password": "<secret>",
+ "logout_devices": true
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
The parameter new_password
is required.
+The parameter logout_devices
is optional and defaults to true
.
The api is:
+GET /_synapse/admin/v1/users/<user_id>/admin
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "admin": true
+}
+
+Note that you cannot demote yourself.
+The api is:
+PUT /_synapse/admin/v1/users/<user_id>/admin
+
+with a body of:
+{
+ "admin": true
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
Gets a list of all room_id
that a specific user_id
is member.
The API is:
+GET /_synapse/admin/v1/users/<user_id>/joined_rooms
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+ {
+ "joined_rooms": [
+ "!DuGcnbhHGaSZQoNQR:matrix.org",
+ "!ZtSaPCawyWtxfWiIy:matrix.org"
+ ],
+ "total": 2
+ }
+
+The server returns the list of rooms of which the user and the server +are member. If the user is local, all the rooms of which the user is +member are returned.
+Parameters
+The following parameters should be set in the URL:
+user_id
- fully qualified: for example, @user:server.com
.Response
+The following fields are returned in the JSON response body:
+joined_rooms
- An array of room_id
.total
- Number of rooms.Gets a list of all local media that a specific user_id
has created.
+By default, the response is ordered by descending creation date and ascending media ID.
+The newest media is on top. You can change the order with parameters
+order_by
and dir
.
The API is:
+GET /_synapse/admin/v1/users/<user_id>/media
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "media": [
+ {
+ "created_ts": 100400,
+ "last_access_ts": null,
+ "media_id": "qXhyRzulkwLsNHTbpHreuEgo",
+ "media_length": 67,
+ "media_type": "image/png",
+ "quarantined_by": null,
+ "safe_from_quarantine": false,
+ "upload_name": "test1.png"
+ },
+ {
+ "created_ts": 200400,
+ "last_access_ts": null,
+ "media_id": "FHfiSnzoINDatrXHQIXBtahw",
+ "media_length": 67,
+ "media_type": "image/png",
+ "quarantined_by": null,
+ "safe_from_quarantine": false,
+ "upload_name": "test2.png"
+ }
+ ],
+ "next_token": 3,
+ "total": 2
+}
+
+To paginate, check for next_token
and if present, call the endpoint again
+with from
set to the value of next_token
. This will return a new page.
If the endpoint does not return a next_token
then there are no more
+reports to paginate through.
Parameters
+The following parameters should be set in the URL:
+user_id
- string - fully qualified: for example, @user:server.com
.
limit
: string representing a positive integer - Is optional but is used for pagination,
+denoting the maximum number of items to return in this call. Defaults to 100
.
from
: string representing a positive integer - Is optional but used for pagination,
+denoting the offset in the returned results. This should be treated as an opaque value and
+not explicitly set to anything other than the return value of next_token
from a previous call.
+Defaults to 0
.
order_by
- The method by which to sort the returned list of media.
+If the ordered field has duplicates, the second order is always by ascending media_id
,
+which guarantees a stable ordering. Valid values are:
media_id
- Media are ordered alphabetically by media_id
.upload_name
- Media are ordered alphabetically by name the media was uploaded with.created_ts
- Media are ordered by when the content was uploaded in ms.
+Smallest to largest. This is the default.last_access_ts
- Media are ordered by when the content was last accessed in ms.
+Smallest to largest.media_length
- Media are ordered by length of the media in bytes.
+Smallest to largest.media_type
- Media are ordered alphabetically by MIME-type.quarantined_by
- Media are ordered alphabetically by the user ID that
+initiated the quarantine request for this media.safe_from_quarantine
- Media are ordered by the status if this media is safe
+from quarantining.dir
- Direction of media order. Either f
for forwards or b
for backwards.
+Setting this value to b
will reverse the above sort order. Defaults to f
.
If neither order_by
nor dir
is set, the default order is newest media on top
+(corresponds to order_by
= created_ts
and dir
= b
).
Caution. The database only has indexes on the columns media_id
,
+user_id
and created_ts
. This means that if a different sort order is used
+(upload_name
, last_access_ts
, media_length
, media_type
,
+quarantined_by
or safe_from_quarantine
), this can cause a large load on the
+database, especially for large environments.
Response
+The following fields are returned in the JSON response body:
+media
- An array of objects, each containing information about a media.
+Media objects contain the following fields:
created_ts
- integer - Timestamp when the content was uploaded in ms.
last_access_ts
- integer - Timestamp when the content was last accessed in ms.
media_id
- string - The id used to refer to the media.
media_length
- integer - Length of the media in bytes.
media_type
- string - The MIME-type of the media.
quarantined_by
- string - The user ID that initiated the quarantine request
+for this media.
safe_from_quarantine
- bool - Status if this media is safe from quarantining.
upload_name
- string - The name the media was uploaded with.
next_token
: integer - Indication for pagination. See above.
total
- integer - Total number of media.
Get an access token that can be used to authenticate as that user. Useful for +when admins wish to do actions on behalf of a user.
+The API is:
+POST /_synapse/admin/v1/users/<user_id>/login
+{}
+
+An optional valid_until_ms
field can be specified in the request body as an
+integer timestamp that specifies when the token should expire. By default tokens
+do not expire.
A response body like the following is returned:
+{
+ "access_token": "<opaque_access_token_string>"
+}
+
+This API does not generate a new device for the user, and so will not appear
+their /devices
list, and in general the target user should not be able to
+tell they have been logged in as.
To expire the token call the standard /logout
API with the token.
Note: The token will expire if the admin user calls /logout/all
from any
+of their devices, but the token will not expire if the target user does the
+same.
Gets information about all devices for a specific user_id
.
The API is:
+GET /_synapse/admin/v2/users/<user_id>/devices
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "devices": [
+ {
+ "device_id": "QBUAZIFURK",
+ "display_name": "android",
+ "last_seen_ip": "1.2.3.4",
+ "last_seen_ts": 1474491775024,
+ "user_id": "<user_id>"
+ },
+ {
+ "device_id": "AUIECTSRND",
+ "display_name": "ios",
+ "last_seen_ip": "1.2.3.5",
+ "last_seen_ts": 1474491775025,
+ "user_id": "<user_id>"
+ }
+ ],
+ "total": 2
+}
+
+Parameters
+The following parameters should be set in the URL:
+user_id
- fully qualified: for example, @user:server.com
.Response
+The following fields are returned in the JSON response body:
+devices
- An array of objects, each containing information about a device.
+Device objects contain the following fields:
device_id
- Identifier of device.display_name
- Display name set by the user for this device.
+Absent if no name has been set.last_seen_ip
- The IP address where this device was last seen.
+(May be a few minutes out of date, for efficiency reasons).last_seen_ts
- The timestamp (in milliseconds since the unix epoch) when this
+devices was last seen. (May be a few minutes out of date, for efficiency reasons).user_id
- Owner of device.total
- Total number of user's devices.
Deletes the given devices for a specific user_id
, and invalidates
+any access token associated with them.
The API is:
+POST /_synapse/admin/v2/users/<user_id>/delete_devices
+
+{
+ "devices": [
+ "QBUAZIFURK",
+ "AUIECTSRND"
+ ],
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
An empty JSON dict is returned.
+Parameters
+The following parameters should be set in the URL:
+user_id
- fully qualified: for example, @user:server.com
.The following fields are required in the JSON request body:
+devices
- The list of device IDs to delete.Gets information on a single device, by device_id
for a specific user_id
.
The API is:
+GET /_synapse/admin/v2/users/<user_id>/devices/<device_id>
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "device_id": "<device_id>",
+ "display_name": "android",
+ "last_seen_ip": "1.2.3.4",
+ "last_seen_ts": 1474491775024,
+ "user_id": "<user_id>"
+}
+
+Parameters
+The following parameters should be set in the URL:
+user_id
- fully qualified: for example, @user:server.com
.device_id
- The device to retrieve.Response
+The following fields are returned in the JSON response body:
+device_id
- Identifier of device.display_name
- Display name set by the user for this device.
+Absent if no name has been set.last_seen_ip
- The IP address where this device was last seen.
+(May be a few minutes out of date, for efficiency reasons).last_seen_ts
- The timestamp (in milliseconds since the unix epoch) when this
+devices was last seen. (May be a few minutes out of date, for efficiency reasons).user_id
- Owner of device.Updates the metadata on the given device_id
for a specific user_id
.
The API is:
+PUT /_synapse/admin/v2/users/<user_id>/devices/<device_id>
+
+{
+ "display_name": "My other phone"
+}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
An empty JSON dict is returned.
+Parameters
+The following parameters should be set in the URL:
+user_id
- fully qualified: for example, @user:server.com
.device_id
- The device to update.The following fields are required in the JSON request body:
+display_name
- The new display name for this device. If not given,
+the display name is unchanged.Deletes the given device_id
for a specific user_id
,
+and invalidates any access token associated with it.
The API is:
+DELETE /_synapse/admin/v2/users/<user_id>/devices/<device_id>
+
+{}
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
An empty JSON dict is returned.
+Parameters
+The following parameters should be set in the URL:
+user_id
- fully qualified: for example, @user:server.com
.device_id
- The device to delete.Gets information about all pushers for a specific user_id
.
The API is:
+GET /_synapse/admin/v1/users/<user_id>/pushers
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "pushers": [
+ {
+ "app_display_name":"HTTP Push Notifications",
+ "app_id":"m.http",
+ "data": {
+ "url":"example.com"
+ },
+ "device_display_name":"pushy push",
+ "kind":"http",
+ "lang":"None",
+ "profile_tag":"",
+ "pushkey":"a@example.com"
+ }
+ ],
+ "total": 1
+}
+
+Parameters
+The following parameters should be set in the URL:
+user_id
- fully qualified: for example, @user:server.com
.Response
+The following fields are returned in the JSON response body:
+pushers
- An array containing the current pushers for the user
app_display_name
- string - A string that will allow the user to identify
+what application owns this pusher.
app_id
- string - This is a reverse-DNS style identifier for the application.
+Max length, 64 chars.
data
- A dictionary of information for the pusher implementation itself.
url
- string - Required if kind
is http
. The URL to use to send
+notifications to.
format
- string - The format to use when sending notifications to the
+Push Gateway.
device_display_name
- string - A string that will allow the user to identify
+what device owns this pusher.
profile_tag
- string - This string determines which set of device specific rules
+this pusher executes.
kind
- string - The kind of pusher. "http" is a pusher that sends HTTP pokes.
lang
- string - The preferred language for receiving notifications
+(e.g. 'en' or 'en-US')
profile_tag
- string - This string determines which set of device specific rules
+this pusher executes.
pushkey
- string - This is a unique identifier for this pusher.
+Max length, 512 bytes.
total
- integer - Number of pushers.
See also the +Client-Server API Spec on pushers.
+Shadow-banning is a useful tool for moderating malicious or egregiously abusive users. +A shadow-banned users receives successful responses to their client-server API requests, +but the events are not propagated into rooms. This can be an effective tool as it +(hopefully) takes longer for the user to realise they are being moderated before +pivoting to another account.
+Shadow-banning a user should be used as a tool of last resort and may lead to confusing +or broken behaviour for the client. A shadow-banned user will not receive any +notification and it is generally more appropriate to ban or kick abusive users. +A shadow-banned user will be unable to contact anyone on the server.
+The API is:
+POST /_synapse/admin/v1/users/<user_id>/shadow_ban
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
An empty JSON dict is returned.
+Parameters
+The following parameters should be set in the URL:
+user_id
- The fully qualified MXID: for example, @user:server.com
. The user must
+be local.This API allows to override or disable ratelimiting for a specific user. +There are specific APIs to set, get and delete a ratelimit.
+The API is:
+GET /_synapse/admin/v1/users/<user_id>/override_ratelimit
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "messages_per_second": 0,
+ "burst_count": 0
+}
+
+Parameters
+The following parameters should be set in the URL:
+user_id
- The fully qualified MXID: for example, @user:server.com
. The user must
+be local.Response
+The following fields are returned in the JSON response body:
+messages_per_second
- integer - The number of actions that can
+be performed in a second. 0
mean that ratelimiting is disabled for this user.burst_count
- integer - How many actions that can be performed before
+being limited.If no custom ratelimit is set, an empty JSON dict is returned.
+{}
+
+The API is:
+POST /_synapse/admin/v1/users/<user_id>/override_ratelimit
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
A response body like the following is returned:
+{
+ "messages_per_second": 0,
+ "burst_count": 0
+}
+
+Parameters
+The following parameters should be set in the URL:
+user_id
- The fully qualified MXID: for example, @user:server.com
. The user must
+be local.Body parameters:
+messages_per_second
- positive integer, optional. The number of actions that can
+be performed in a second. Defaults to 0
.burst_count
- positive integer, optional. How many actions that can be performed
+before being limited. Defaults to 0
.To disable users' ratelimit set both values to 0
.
Response
+The following fields are returned in the JSON response body:
+messages_per_second
- integer - The number of actions that can
+be performed in a second.burst_count
- integer - How many actions that can be performed before
+being limited.The API is:
+DELETE /_synapse/admin/v1/users/<user_id>/override_ratelimit
+
+To use it, you will need to authenticate by providing an access_token
for a
+server admin: Admin API
An empty JSON dict is returned.
+{}
+
+Parameters
+The following parameters should be set in the URL:
+user_id
- The fully qualified MXID: for example, @user:server.com
. The user must
+be local.This API returns the running Synapse version and the Python version +on which Synapse is being run. This is useful when a Synapse instance +is behind a proxy that does not forward the 'Server' header (which also +contains Synapse version information).
+The api is:
+GET /_synapse/admin/v1/server_version
+
+It returns a JSON body like the following:
+{
+ "server_version": "0.99.2rc1 (b=develop, abcdef123)",
+ "python_version": "3.6.8"
+}
+
+
+ The registration of new application services depends on the homeserver used.
+In synapse, you need to create a new configuration file for your AS and add it
+to the list specified under the app_service_config_files
config
+option in your synapse config.
For example:
+app_service_config_files:
+- /home/matrix/.synapse/<your-AS>.yaml
+
+The format of the AS configuration file is as follows:
+url: <base url of AS>
+as_token: <token AS will add to requests to HS>
+hs_token: <token HS will add to requests to AS>
+sender_localpart: <localpart of AS user>
+namespaces:
+ users: # List of users we're interested in
+ - exclusive: <bool>
+ regex: <regex>
+ group_id: <group>
+ - ...
+ aliases: [] # List of aliases we're interested in
+ rooms: [] # List of room ids we're interested in
+
+exclusive
: If enabled, only this application service is allowed to register users in its namespace(s).
+group_id
: All users of this application service are dynamically joined to this group. This is useful for e.g user organisation or flairs.
See the spec for further details on how application services work.
+ +The auth chain difference algorithm is used by V2 state resolution, where a +naive implementation can be a significant source of CPU and DB usage.
+A state set is a set of state events; e.g. the input of a state resolution +algorithm is a collection of state sets.
+The auth chain of a set of events are all the events' auth events and their +auth events, recursively (i.e. the events reachable by walking the graph induced +by an event's auth events links).
+The auth chain difference of a collection of state sets is the union minus the +intersection of the sets of auth chains corresponding to the state sets, i.e an +event is in the auth chain difference if it is reachable by walking the auth +event graph from at least one of the state sets but not from all of the state +sets.
+A way of calculating the auth chain difference without calculating the full auth +chains for each state set is to do a parallel breadth first walk (ordered by +depth) of each state set's auth chain. By tracking which events are reachable +from each state set we can finish early if every pending event is reachable from +every state set.
+This can work well for state sets that have a small auth chain difference, but +can be very inefficient for larger differences. However, this algorithm is still +used if we don't have a chain cover index for the room (e.g. because we're in +the process of indexing it).
+Synapse computes auth chain differences by pre-computing a "chain cover" index
+for the auth chain in a room, allowing efficient reachability queries like "is
+event A in the auth chain of event B". This is done by assigning every event a
+chain ID and sequence number (e.g. (5,3)
), and having a map of links
+between chains (e.g. (5,3) -> (2,4)
) such that A is reachable by B (i.e. A
+is in the auth chain of B
) if and only if either:
A
's sequence number is less than B
's
+sequence number; orL
between B
's chain ID and A
's chain ID such that
+L.start_seq_no
<= B.seq_no
and A.seq_no
<= L.end_seq_no
.There are actually two potential implementations, one where we store links from
+each chain to every other reachable chain (the transitive closure of the links
+graph), and one where we remove redundant links (the transitive reduction of the
+links graph) e.g. if we have chains C3 -> C2 -> C1
then the link C3 -> C1
+would not be stored. Synapse uses the former implementations so that it doesn't
+need to recurse to test reachability between chains.
An example auth graph would look like the following, where chains have been
+formed based on type/state_key and are denoted by colour and are labelled with
+(chain ID, sequence number)
. Links are denoted by the arrows (links in grey
+are those that would be remove in the second implementation described above).
Note that we don't include all links between events and their auth events, as +most of those links would be redundant. For example, all events point to the +create event, but each chain only needs the one link from it's base to the +create event.
+This index can be used to calculate the auth chain difference of the state sets +by looking at the chain ID and sequence numbers reachable from each state set:
+Note that steps 2 is effectively calculating the auth chain for each state set +(in terms of chain IDs and sequence numbers), and step 3 is calculating the +difference between the union and intersection of the auth chains.
+For example, given the above graph, we can calculate the difference between +state sets consisting of:
+S1
: Alice's invite (4,1)
and Bob's second join (2,2)
; andS2
: Alice's second join (4,3)
and Bob's first join (2,1)
.Using the index we see that the following auth chains are reachable from each +state set:
+S1
: (1,1)
, (2,2)
, (3,1)
& (4,1)
S2
: (1,1)
, (2,1)
, (3,2)
& (4,3)
And so, for each the ranges that are in the auth chain difference:
+(1, 2]
(i.e. just 2
), as 1
is reachable by all state
+sets and the maximum reachable is 2
(corresponding to Bob's second join).(1, 2]
(corresponding to the second power
+level).(1, 3]
(corresponding to both of Alice's joins).So the final result is: Bob's second join (2,2)
, the second power level
+(3,2)
and both of Alice's joins (4,2)
& (4,3)
.
The Synapse codebase uses a number of code formatting tools in order to +quickly and automatically check for formatting (and sometimes logical) +errors in code.
+The necessary tools are detailed below.
+First install them with:
+pip install -e ".[lint,mypy]"
+
+black
+The Synapse codebase uses black +as an opinionated code formatter, ensuring all comitted code is +properly formatted.
+Have black
auto-format your code (it shouldn't change any
+functionality) with:
black . --exclude="\.tox|build|env"
+
+flake8
+flake8
is a code checking tool. We require code to pass flake8
+before being merged into the codebase.
Check all application and test code with:
+flake8 synapse tests
+
+isort
+isort
ensures imports are nicely formatted, and can suggest and
+auto-fix issues such as double-importing.
Auto-fix imports with:
+isort -rc synapse tests
+
+-rc
means to recursively search the given directories.
It's worth noting that modern IDEs and text editors can run these tools
+automatically on save. It may be worth looking into whether this
+functionality is supported in your editor for a more convenient
+development workflow. It is not, however, recommended to run flake8
on
+save as it takes a while and is very resource intensive.
Imports should be sorted by isort
as described above.
Prefer to import classes and functions rather than packages or +modules.
+Example:
+from synapse.types import UserID
+...
+user_id = UserID(local, server)
+
+is preferred over:
+from synapse import types
+...
+user_id = types.UserID(local, server)
+
+(or any other variant).
+This goes against the advice in the Google style guide, but it +means that errors in the name are caught early (at import time).
+Avoid wildcard imports (from synapse.types import *
) and
+relative imports (from .types import UserID
).
The sample configuration file acts as a +reference to Synapse's configuration options for server administrators. +Remember that many readers will be unfamiliar with YAML and server +administration in general, so that it is important that the file be as +easy to understand as possible, which includes following a consistent +format.
+Some guidelines follow:
+Sections should be separated with a heading consisting of a single
+line prefixed and suffixed with ##
. There should be two blank
+lines before the section header, and one after.
Each option should be listed in the file with the following format:
+A comment describing the setting. Each line of this comment
+should be prefixed with a hash (#
) and a space.
The comment should describe the default behaviour (ie, what +happens if the setting is omitted), as well as what the effect +will be if the setting is changed.
+Often, the comment end with something like "uncomment the
+following to
A line consisting of only #
.
A commented-out example setting, prefixed with only #
.
For boolean (on/off) options, convention is that this example
+should be the opposite to the default (so the comment will end
+with "Uncomment the following to enable [or disable]
+
There should be a blank line between each option.
+Where several settings are grouped into a single dict, avoid the
+convention where the whole block is commented out, resulting in
+comment lines starting # #
, as this is hard to read and confusing
+to edit. Instead, leave the top-level config option uncommented, and
+follow the conventions above for sub-options. Ensure that your code
+correctly handles the top-level option being set to None
(as it
+will be if no sub-options are enabled).
Lines should be wrapped at 80 characters.
+Use two-space indents.
+true
and false
are spelt thus (as opposed to True
, etc.)
Use single quotes ('
) rather than double-quotes ("
) or backticks
+(`
) to refer to configuration options.
Example:
+## Frobnication ##
+
+# The frobnicator will ensure that all requests are fully frobnicated.
+# To enable it, uncomment the following.
+#
+#frobnicator_enabled: true
+
+# By default, the frobnicator will frobnicate with the default frobber.
+# The following will make it use an alternative frobber.
+#
+#frobincator_frobber: special_frobber
+
+# Settings for the frobber
+#
+frobber:
+ # frobbing speed. Defaults to 1.
+ #
+ #speed: 10
+
+ # frobbing distance. Defaults to 1000.
+ #
+ #distance: 100
+
+Note that the sample configuration is generated from the synapse code
+and is maintained by a script, scripts-dev/generate_sample_config
.
+Making sure that the output from this script matches the desired format
+is left as an exercise for the reader!
Synapse 0.30 introduces support for tracking whether users have agreed to the +terms and conditions set by the administrator of a server - and blocking access +to the server until they have.
+There are several parts to this functionality; each requires some specific
+configuration in homeserver.yaml
to be enabled.
Note that various parts of the configuation and this document refer to the +"privacy policy": agreement with a privacy policy is one particular use of this +feature, but of course adminstrators can specify other terms and conditions +unrelated to "privacy" per se.
+Synapse can be configured to serve the user a simple policy form with an +"accept" button. Clicking "Accept" records the user's acceptance in the +database and shows a success page.
+To enable this, first create templates for the policy and success pages. +These should be stored on the local filesystem.
+These templates use the Jinja2 templating language, +and docs/privacy_policy_templates +gives examples of the sort of thing that can be done.
+Note that the templates must be stored under a name giving the language of the
+template - currently this must always be en
(for "English");
+internationalisation support is intended for the future.
The template for the policy itself should be versioned and named according to
+the version: for example 1.0.html
. The version of the policy which the user
+has agreed to is stored in the database.
Once the templates are in place, make the following changes to homeserver.yaml
:
Add a user_consent
section, which should look like:
user_consent:
+ template_dir: privacy_policy_templates
+ version: 1.0
+
+template_dir
points to the directory containing the policy
+templates. version
defines the version of the policy which will be served
+to the user. In the example above, Synapse will serve
+privacy_policy_templates/en/1.0.html
.
Add a form_secret
setting at the top level:
form_secret: "<unique secret>"
+
+This should be set to an arbitrary secret string (try pwgen -y 30
to
+generate suitable secrets).
More on what this is used for below.
+Add consent
wherever the client
resource is currently enabled in the
+listeners
configuration. For example:
listeners:
+ - port: 8008
+ resources:
+ - names:
+ - client
+ - consent
+
+Finally, ensure that jinja2
is installed. If you are using a virtualenv, this
+should be a matter of pip install Jinja2
. On debian, try apt-get install python-jinja2
.
Once this is complete, and the server has been restarted, try visiting
+https://<server>/_matrix/consent
. If correctly configured, this should give
+an error "Missing string query parameter 'u'". It is now possible to manually
+construct URIs where users can give their consent.
Add the following to your configuration:
+user_consent:
+ require_at_registration: true
+ policy_name: "Privacy Policy" # or whatever you'd like to call the policy
+
+In your consent templates, make use of the public_version
variable to
+see if an unauthenticated user is viewing the page. This is typically
+wrapped around the form that would be used to actually agree to the document:
{% if not public_version %}
+ <!-- The variables used here are only provided when the 'u' param is given to the homeserver -->
+ <form method="post" action="consent">
+ <input type="hidden" name="v" value="{{version}}"/>
+ <input type="hidden" name="u" value="{{user}}"/>
+ <input type="hidden" name="h" value="{{userhmac}}"/>
+ <input type="submit" value="Sure thing!"/>
+ </form>
+{% endif %}
+
+Restart Synapse to apply the changes.
+Visiting https://<server>/_matrix/consent
should now give you a view of the privacy
+document. This is what users will be able to see when registering for accounts.
It may be useful to manually construct the "consent URI" for a given user - for
+instance, in order to send them an email asking them to consent. To do this,
+take the base https://<server>/_matrix/consent
URL and add the following
+query parameters:
u
: the user id of the user. This can either be a full MXID
+(@user:server.com
) or just the localpart (user
).
h
: hex-encoded HMAC-SHA256 of u
using the form_secret
as a key. It is
+possible to calculate this on the commandline with something like:
echo -n '<user>' | openssl sha256 -hmac '<form_secret>'
+
+This should result in a URI which looks something like:
+https://<server>/_matrix/consent?u=<user>&h=68a152465a4d...
.
Note that not providing a u
parameter will be interpreted as wanting to view
+the document from an unauthenticated perspective, such as prior to registration.
+Therefore, the h
parameter is not required in this scenario. To enable this
+behaviour, set require_at_registration
to true
in your user_consent
config.
It is possible to configure Synapse to send a server +notice to anybody who has not yet agreed to the current +version of the policy. To do so:
+ensure that the consent resource is configured, as in the previous section
+ensure that server notices are configured, as in server_notices.md.
+Add server_notice_content
under user_consent
in homeserver.yaml
. For
+example:
user_consent:
+ server_notice_content:
+ msgtype: m.text
+ body: >-
+ Please give your consent to the privacy policy at %(consent_uri)s.
+
+Synapse automatically replaces the placeholder %(consent_uri)s
with the
+consent uri for that user.
ensure that public_baseurl
is set in homeserver.yaml
, and gives the base
+URI that clients use to connect to the server. (It is used to construct
+consent_uri
in the server notice.)
Synapse can be configured to block any attempts to join rooms or send messages +until the user has given their agreement to the policy. (Joining the server +notices room is exempted from this).
+To enable this, add block_events_error
under user_consent
. For example:
user_consent:
+ block_events_error: >-
+ You can't send any messages until you consent to the privacy policy at
+ %(consent_uri)s.
+
+Synapse automatically replaces the placeholder %(consent_uri)s
with the
+consent uri for that user.
ensure that public_baseurl
is set in homeserver.yaml
, and gives the base
+URI that clients use to connect to the server. (It is used to construct
+consent_uri
in the error.)
By default, other homeservers will expect to be able to reach yours via
+your server_name
, on port 8448. For example, if you set your server_name
+to example.com
(so that your user names look like @user:example.com
),
+other servers will try to connect to yours at https://example.com:8448/
.
Delegation is a Matrix feature allowing a homeserver admin to retain a
+server_name
of example.com
so that user IDs, room aliases, etc continue
+to look like *:example.com
, whilst having federation traffic routed
+to a different server and/or port (e.g. synapse.example.com:443
).
To use this method, you need to be able to alter the
+server_name
's https server to serve the /.well-known/matrix/server
+URL. Having an active server (with a valid TLS certificate) serving your
+server_name
domain is out of the scope of this documentation.
The URL https://<server_name>/.well-known/matrix/server
should
+return a JSON structure containing the key m.server
like so:
{
+ "m.server": "<synapse.server.name>[:<yourport>]"
+}
+
+In our example, this would mean that URL https://example.com/.well-known/matrix/server
+should return:
{
+ "m.server": "synapse.example.com:443"
+}
+
+Note, specifying a port is optional. If no port is specified, then it defaults +to 8448.
+With .well-known delegation, federating servers will check for a valid TLS
+certificate for the delegated hostname (in our example: synapse.example.com
).
It is also possible to do delegation using a SRV DNS record. However, that is
+considered an advanced topic since it's a bit complex to set up, and .well-known
+delegation is already enough in most cases.
However, if you really need it, you can find some documentation on how such a +record should look like and how Synapse will use it in the Matrix +specification.
+If your homeserver's APIs are accessible on the default federation port (8448)
+and the domain your server_name
points to, you do not need any delegation.
For instance, if you registered example.com
and pointed its DNS A record at a
+fresh server, you could install Synapse on that host, giving it a server_name
+of example.com
, and once a reverse proxy has been set up to proxy all requests
+sent to the port 8448
and serve TLS certificates for example.com
, you
+wouldn't need any delegation set up.
However, if your homeserver's APIs aren't accessible on port 8448 and on the
+domain server_name
points to, you will need to let other servers know how to
+find it using delegation.
We no longer actively recommend against using a reverse proxy. Many admins will +find it easier to direct federation traffic to a reverse proxy and manage their +own TLS certificates, and this is a supported configuration.
+See reverse_proxy.md for information on setting up a +reverse proxy.
+This is no longer necessary. If you are using a reverse proxy for all of your
+TLS traffic, then you can set no_tls: True
in the Synapse config.
In that case, the only reason Synapse needs the certificate is to populate a legacy
+tls_fingerprints
field in the federation API. This is ignored by Synapse 0.99.0
+and later, and the only time pre-0.99 Synapses will check it is when attempting to
+fetch the server keys - and generally this is delegated via matrix.org
, which
+is running a modern version of Synapse.
No. There is nothing stopping you from using different certificates, +particularly if you are using a reverse proxy.
+ +Synapse has a number of platform dependencies, including Python and PostgreSQL. +This document outlines the policy towards which versions we support, and when we +drop support for versions in the future.
+Synapse follows the upstream support life cycles for Python and PostgreSQL, +i.e. when a version reaches End of Life Synapse will withdraw support for that +version in future releases.
+Details on the upstream support life cycles for Python and PostgreSQL are +documented at https://endoflife.date/python and +https://endoflife.date/postgresql.
+It is important for system admins to have a clear understanding of the platform +requirements of Synapse and its deprecation policies so that they can +effectively plan upgrading their infrastructure ahead of time. This is +especially important in contexts where upgrading the infrastructure requires +auditing and approval from a security team, or where otherwise upgrading is a +long process.
+By following the upstream support life cycles Synapse can ensure that its +dependencies continue to get security patches, while not requiring system admins +to constantly update their platform dependencies to the latest versions.
+ +The django-mama-cas project is an +easy to run CAS implementation built on top of Django.
+python3 -m venv <your virtualenv>
source /path/to/your/virtualenv/bin/activate
python -m pip install "django<3" "django-mama-cas==2.4.0"
+
+django-admin startproject cas_test .
+
+python manage.py migrate
python manage.py createsuperuser
+
+python manage.py runserver
+
+You should now have a Django project configured to serve CAS authentication with +a single user created.
+homeserver.yaml
to enable CAS and point it to your locally
+running Django test server:
+cas_config:
+ enabled: true
+ server_url: "http://localhost:8000"
+ service_url: "http://localhost:8081"
+ #displayname_attribute: name
+ #required_attributes:
+ # name: value
+
+Note that the above configuration assumes the homeserver is running on port 8081 +and that the CAS server is on port 8000, both on localhost.
+Then in Element:
+createsuperuser
.If you want to repeat this process you'll need to manually logout first:
+In an ideal world, our git commit history would be a linear progression of
+commits each of which contains a single change building on what came
+before. Here, by way of an arbitrary example, is the top of git log --graph b2dba0607
:
Note how the commit comment explains clearly what is changing and why. Also +note the absence of merge commits, as well as the absence of commits called +things like (to pick a few culprits): +“pep8”, “fix broken +test”, +“oops”, +“typo”, or “Who's +the president?”.
+There are a number of reasons why keeping a clean commit history is a good +thing:
+From time to time, after a change lands, it turns out to be necessary to +revert it, or to backport it to a release branch. Those operations are +much easier when the change is contained in a single commit.
+Similarly, it's much easier to answer questions like “is the fix for
+/publicRooms
on the release branch?” if that change consists of a single
+commit.
Likewise: “what has changed on this branch in the last week?” is much +clearer without merges and “pep8” commits everywhere.
+Sometimes we need to figure out where a bug got introduced, or some
+behaviour changed. One way of doing that is with git bisect
: pick an
+arbitrary commit between the known good point and the known bad point, and
+see how the code behaves. However, that strategy fails if the commit you
+chose is the middle of someone's epic branch in which they broke the world
+before putting it back together again.
One counterargument is that it is sometimes useful to see how a PR evolved as +it went through review cycles. This is true, but that information is always +available via the GitHub UI (or via the little-known refs/pull +namespace).
+Of course, in reality, things are more complicated than that. We have release
+branches as well as develop
and master
, and we deliberately merge changes
+between them. Bugs often slip through and have to be fixed later. That's all
+fine: this not a cast-iron rule which must be obeyed, but an ideal to aim
+towards.
Ok, so that's what we'd like to achieve. How do we achieve it?
+The TL;DR is: when you come to merge a pull request, you probably want to +“squash and merge”:
+.
+(This applies whether you are merging your own PR, or that of another +contributor.)
+“Squash and merge”1 takes all of the changes in the
+PR, and bundles them into a single commit. GitHub gives you the opportunity to
+edit the commit message before you confirm, and normally you should do so,
+because the default will be useless (again: * woops typo
is not a useful
+thing to keep in the historical record).
The main problem with this approach comes when you have a series of pull +requests which build on top of one another: as soon as you squash-merge the +first PR, you'll end up with a stack of conflicts to resolve in all of the +others. In general, it's best to avoid this situation in the first place by +trying not to have multiple related PRs in flight at the same time. Still, +sometimes that's not possible and doing a regular merge is the lesser evil.
+Another occasion in which a regular merge makes more sense is a PR where you've +deliberately created a series of commits each of which makes sense in its own +right. For example: a PR which gradually propagates a refactoring operation +through the codebase, or a +PR which is the culmination of several other +PRs. In this case the ability +to figure out when a particular change/bug was introduced could be very useful.
+Ultimately: this is not a hard-and-fast-rule. If in doubt, ask yourself “do +each of the commits I am about to merge make sense in their own right”, but +remember that we're just doing our best to balance “keeping the commit history +clean” with other factors.
+A lot +of +words have been +written in the past about git branching models (no really, a +lot). I tend to +think the whole thing is overblown. Fundamentally, it's not that +complicated. Here's how we do it.
+Let's start with a picture:
+ +It looks complicated, but it's really not. There's one basic rule: anyone is +free to merge from any more-stable branch to any less-stable branch at +any time2. (The principle behind this is that if a +change is good enough for the more-stable branch, then it's also good enough go +put in a less-stable branch.)
+Meanwhile, merging (or squashing, as per the above) from a less-stable to a +more-stable branch is a deliberate action in which you want to publish a change +or a set of changes to (some subset of) the world: for example, this happens +when a PR is landed, or as part of our release process.
+So, what counts as a more- or less-stable branch? A little reflection will show +that our active branches are ordered thus, from more-stable to less-stable:
+master
(tracks our last release).release-vX.Y
(the branch where we prepare the next release)3.develop
(our "mainline" branch containing our bleeding-edge).The corollary is: if you have a bugfix that needs to land in both
+release-vX.Y
and develop
, then you should base your PR on
+release-vX.Y
, get it merged there, and then merge from release-vX.Y
to
+develop
. (If a fix lands in develop
and we later need it in a
+release-branch, we can of course cherry-pick it, but landing it in the release
+branch first helps reduce the chance of annoying conflicts.)
[1]: “Squash and merge” is GitHub's term for this +operation. Given that there is no merge involved, I'm not convinced it's the +most intuitive name. ^
+[2]: Well, anyone with commit access.^
+[3]: Very, very occasionally (I think this has happened once in
+the history of Synapse), we've had two releases in flight at once. Obviously,
+release-v1.2
is more-stable than release-v1.3
. ^
https://capriza.github.io/samling/samling.html (https://github.com/capriza/samling) is a great +resource for being able to tinker with the SAML options within Synapse without needing to +deploy and configure a complicated software stack.
+To make Synapse (and therefore Riot) use it:
+samling.xml
next to your homeserver.yaml
with
+the XML from step 2 as the contents.homeserver.yaml
to include:
+saml2_config:
+ sp_config:
+ allow_unknown_attributes: true # Works around a bug with AVA Hashes: https://github.com/IdentityPython/pysaml2/issues/388
+ metadata:
+ local: ["samling.xml"]
+
+homeserver.yaml
has a setting for public_baseurl
:
+public_baseurl: http://localhost:8080/
+
+apt-get install xmlsec1
and pip install --upgrade --force 'pysaml2>=4.5.0'
to ensure
+the dependencies are installed and ready to go.Then in Riot:
+uid=your_localpart
.
+The response must also be signed.If you try and repeat this process, you may be automatically logged in using the information you
+gave previously. To fix this, open your developer console (F12
or Ctrl+Shift+I
) while on the
+samling page and clear the site data. In Chrome, this will be a button on the Application tab.
Welcome to Synapse
+This document aims to get you started with contributing to this repo!
+Everyone is welcome to contribute code to matrix.org +projects, provided that they are willing to +license their contributions under the same license as the project itself. We +follow a simple 'inbound=outbound' model for contributions: the act of +submitting an 'inbound' contribution means that the contributor agrees to +license the code under the same terms as the project's overall 'outbound' +license - in our case, this is almost always Apache Software License v2 (see +LICENSE).
+The code of Synapse is written in Python 3. To do pretty much anything, you'll need a recent version of Python 3.
+The source code of Synapse is hosted on GitHub. You will also need a recent version of git.
+For some tests, you will need a recent version of Docker.
+The preferred and easiest way to contribute changes is to fork the relevant +project on GitHub, and then create a pull request to ask us to pull your +changes into our repo.
+Please base your changes on the develop
branch.
git clone git@github.com:YOUR_GITHUB_USER_NAME/synapse.git
+git checkout develop
+
+If you need help getting started with git, this is beyond the scope of the document, but you +can find many good git tutorials on the web.
+Once you have installed Python 3 and added the source, please open a terminal and +setup a virtualenv, as follows:
+cd path/where/you/have/cloned/the/repository
+python3 -m venv ./env
+source ./env/bin/activate
+pip install -e ".[all,lint,mypy,test]"
+pip install tox
+
+This will install the developer dependencies for the project.
+TBD
+Join our developer community on Matrix: #synapse-dev:matrix.org !
+Fix your favorite problem or perhaps find a Good First Issue +to work on.
+Synapse's code style is documented here. Please follow +it, including the conventions for the sample configuration +file.
+There is a growing amount of documentation located in the docs +directory. This documentation is intended primarily for sysadmins running their +own Synapse instance, as well as developers interacting externally with +Synapse. docs/dev exists primarily to house documentation for +Synapse developers. docs/admin_api houses documentation +regarding Synapse's Admin API, which is used mostly by sysadmins and external +service developers.
+If you add new files added to either of these folders, please use GitHub-Flavoured +Markdown.
+Some documentation also exists in Synapse's GitHub +Wiki, although this is primarily +contributed to by community authors.
+While you're developing and before submitting a patch, you'll +want to test your code.
+The linters look at your code and do two things:
+They're pretty fast, don't hesitate!
+source ./env/bin/activate
+./scripts-dev/lint.sh
+
+Note that this script will modify your files to fix styling errors. +Make sure that you have saved all your files.
+If you wish to restrict the linters to only the files changed since the last commit +(much faster!), you can instead run:
+source ./env/bin/activate
+./scripts-dev/lint.sh -d
+
+Or if you know exactly which files you wish to lint, you can instead run:
+source ./env/bin/activate
+./scripts-dev/lint.sh path/to/file1.py path/to/file2.py path/to/folder
+
+The unit tests run parts of Synapse, including your changes, to see if anything +was broken. They are slower than the linters but will typically catch more errors.
+source ./env/bin/activate
+trial tests
+
+If you wish to only run some unit tests, you may specify
+another module instead of tests
- or a test class or a method:
source ./env/bin/activate
+trial tests.rest.admin.test_room tests.handlers.test_admin.ExfiltrateData.test_invite
+
+If your tests fail, you may wish to look at the logs (the default log level is ERROR
):
less _trial_temp/test.log
+
+To increase the log level for the tests, set SYNAPSE_TEST_LOG_LEVEL
:
SYNAPSE_TEST_LOG_LEVEL=DEBUG trial tests
+
+The integration tests are a more comprehensive suite of tests. They +run a full version of Synapse, including your changes, to check if +anything was broken. They are slower than the unit tests but will +typically catch more errors.
+The following command will let you run the integration test with the most common +configuration:
+$ docker run --rm -it -v /path/where/you/have/cloned/the/repository\:/src:ro -v /path/to/where/you/want/logs\:/logs matrixdotorg/sytest-synapse:py37
+
+This configuration should generally cover your needs. For more details about other configurations, see documentation in the SyTest repo.
+Once you're happy with your patch, it's time to prepare a Pull Request.
+To prepare a Pull Request, please:
+git push
your commit to your fork of Synapse;matrix-org
, on GitHub, please request a review from matrix.org / Synapse Core
.All changes, even minor ones, need a corresponding changelog / newsfragment +entry. These are managed by Towncrier.
+To create a changelog entry, make a new file in the changelog.d
directory named
+in the format of PRnumber.type
. The type can be one of the following:
feature
bugfix
docker
(for updates to the Docker image)doc
(for updates to the documentation)removal
(also used for deprecations)misc
(for internal-only changes)This file will become part of our changelog at the next +release, so the content of the file should be a short description of your +change in the same style as the rest of the changelog. The file can contain Markdown +formatting, and should end with a full stop (.) or an exclamation mark (!) for +consistency.
+Adding credits to the changelog is encouraged, we value your +contributions and would like to have you shouted out in the release notes!
+For example, a fix in PR #1234 would have its changelog entry in
+changelog.d/1234.bugfix
, and contain content like:
++The security levels of Florbs are now validated when received +via the
+/federation/florb
endpoint. Contributed by Jane Matrix.
If there are multiple pull requests involved in a single bugfix/feature/etc,
+then the content for each changelog.d
file should be the same. Towncrier will
+merge the matching files together into a single changelog entry when we come to
+release.
Obviously, you don't know if you should call your newsfile
+1234.bugfix
or 5678.bugfix
until you create the PR, which leads to a
+chicken-and-egg problem.
There are two options for solving this:
+Open the PR without a changelog file, see what number you got, and then +add the changelog file to your branch (see Updating your pull +request), or:
+Look at the list of all +issues/PRs, add one to the +highest number you see, and quickly open the PR before somebody else claims +your number.
+This +script +might be helpful if you find yourself doing this a lot.
+Sorry, we know it's a bit fiddly, but it's really helpful for us when we come +to put together a release!
+Changes which affect the debian packaging files (in debian
) are an
+exception to the rule that all changes require a changelog.d
file.
In this case, you will need to add an entry to the debian changelog for the +next release. For this, run the following command:
+dch
+
+This will make up a new version number (if there isn't already an unreleased +version in flight), and open an editor where you can add a new changelog entry. +(Our release process will ensure that the version number and maintainer name is +corrected for the release.)
+If your change affects both the debian packaging and files outside the debian +directory, you will need both a regular newsfragment and an entry in the +debian changelog. (Though typically such changes should be submitted as two +separate pull requests.)
+In order to have a concrete record that your contribution is intentional +and you agree to license it under the same terms as the project's license, we've adopted the +same lightweight approach that the Linux Kernel +submitting patches process, +Docker, and many other +projects use: the DCO (Developer Certificate of Origin: +http://developercertificate.org/). This is a simple declaration that you wrote +the contribution or otherwise have the right to contribute it to Matrix:
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+If you agree to this for your contribution, then all that's needed is to +include the line in your commit or pull request comment:
+Signed-off-by: Your Name <your@email.example.org>
+
+We accept contributions under a legally identifiable name, such as +your name on government documentation or common-law names (names +claimed by legitimate usage or repute). Unfortunately, we cannot +accept anonymous contributions at this time.
+Git allows you to add this signoff automatically when using the -s
+flag to git commit
, which uses the name and email set in your
+user.name
and user.email
git configs.
Once the Pull Request is opened, you will see a few things:
+From this point, you should:
+Once both the CI and the developers are happy, the patch will be merged into Synapse and released shortly!
+By now, you know the drill!
+There are some notes for those with commit access to the project on how we +manage git here.
+That's it! Matrix is a very open and collaborative project as you might expect +given our obsession with open communication. If we're going to successfully +matrix together all the fragmented communication technologies out there we are +reliant on contributions and collaboration from the community to do so. So +please get involved - and we hope you have as much fun hacking on Matrix as we +do!
+ +Synapse's database schema is stored in the synapse.storage.schema
module.
Synapse supports splitting its datastore across multiple physical databases (which can +be useful for large installations), and the schema files are therefore split according +to the logical database they apply to.
+At the time of writing, the following "logical" databases are supported:
+state
- used to store Matrix room state (more specifically, state_groups
,
+their relationships and contents).main
- stores everything else.Additionally, the common
directory contains schema files for tables which must be
+present on all physical databases.
Synapse manages its database schema via "schema versions". These are mainly used to +help avoid confusion if the Synapse codebase is rolled back after the database is +updated. They work as follows:
+The Synapse codebase defines a constant synapse.storage.schema.SCHEMA_VERSION
+which represents the expectations made about the database by that version. For
+example, as of Synapse v1.36, this is 59
.
The database stores a "compatibility version" in
+schema_compat_version.compat_version
which defines the SCHEMA_VERSION
of the
+oldest version of Synapse which will work with the database. On startup, if
+compat_version
is found to be newer than SCHEMA_VERSION
, Synapse will refuse to
+start.
Synapse automatically updates this field from
+synapse.storage.schema.SCHEMA_COMPAT_VERSION
.
Whenever a backwards-incompatible change is made to the database format (normally
+via a delta
file), synapse.storage.schema.SCHEMA_COMPAT_VERSION
is also updated
+so that administrators can not accidentally roll back to a too-old version of Synapse.
Generally, the goal is to maintain compatibility with at least one or two previous +releases of Synapse, so any substantial change tends to require multiple releases and a +bit of forward-planning to get right.
+As a worked example: we want to remove the room_stats_historical
table. Here is how it
+might pan out.
Replace any code that reads from room_stats_historical
with alternative
+implementations, but keep writing to it in case of rollback to an earlier version.
+Also, increase synapse.storage.schema.SCHEMA_VERSION
. In this
+instance, there is no existing code which reads from room_stats_historical
, so
+our starting point is:
v1.36.0: SCHEMA_VERSION=59
, SCHEMA_COMPAT_VERSION=59
Next (say in Synapse v1.37.0): remove the code that writes to
+room_stats_historical
, but don’t yet remove the table in case of rollback to
+v1.36.0. Again, we increase synapse.storage.schema.SCHEMA_VERSION
, but
+because we have not broken compatibility with v1.36, we do not yet update
+SCHEMA_COMPAT_VERSION
. We now have:
v1.37.0: SCHEMA_VERSION=60
, SCHEMA_COMPAT_VERSION=59
.
Later (say in Synapse v1.38.0): we can remove the table altogether. This will
+break compatibility with v1.36.0, so we must update SCHEMA_COMPAT_VERSION
accordingly.
+There is no need to update synapse.storage.schema.SCHEMA_VERSION
, since there is no
+change to the Synapse codebase here. So we end up with:
v1.38.0: SCHEMA_VERSION=60
, SCHEMA_COMPAT_VERSION=60
.
If in doubt about whether to update SCHEMA_VERSION
or not, it is generally best to
+lean towards doing so.
In the full_schemas
directories, only the most recently-numbered snapshot is used
+(54
at the time of writing). Older snapshots (eg, 16
) are present for historical
+reference only.
If you want to recreate these schemas, they need to be made from a database that +has had all background updates run.
+To do so, use scripts-dev/make_full_schema.sh
. This will produce new
+full.sql.postgres
and full.sql.sqlite
files.
Ensure postgres is installed, then run:
+./scripts-dev/make_full_schema.sh -p postgres_username -o output_dir/
+
+NB at the time of writing, this script predates the split into separate state
/main
+databases so will require updates to handle that correctly.
Boolean columns require special treatment, since SQLite treats booleans the +same as integers.
+There are three separate aspects to this:
+Any new boolean column must be added to the BOOLEAN_COLUMNS
list in
+scripts/synapse_port_db
. This tells the port script to cast the integer
+value from SQLite to a boolean before writing the value to the postgres
+database.
Before SQLite 3.23, TRUE
and FALSE
were not recognised as constants by
+SQLite, and the IS [NOT] TRUE
/IS [NOT] FALSE
operators were not
+supported. This makes it necessary to avoid using TRUE
and FALSE
+constants in SQL commands.
For example, to insert a TRUE
value into the database, write:
txn.execute("INSERT INTO tbl(col) VALUES (?)", (True, ))
+
+Default values for new boolean columns present a particular +difficulty. Generally it is best to create separate schema files for +Postgres and SQLite. For example:
+# in 00delta.sql.postgres:
+ALTER TABLE tbl ADD COLUMN col BOOLEAN DEFAULT FALSE;
+
+# in 00delta.sql.sqlite:
+ALTER TABLE tbl ADD COLUMN col BOOLEAN DEFAULT 0;
+
+Note that there is a particularly insidious failure mode here: the Postgres
+flavour will be accepted by SQLite 3.22, but will give a column whose
+default value is the string "FALSE"
- which, when cast back to a boolean
+in Python, evaluates to True
.
This section covers implementation documentation for various parts of Synapse.
+If a developer is planning to make a change to a feature of Synapse, it can be useful for +general documentation of how that feature is implemented to be available. This saves the +developer time in place of needing to understand how the feature works by reading the +code.
+Documentation that would be more useful for the perspective of a system administrator, +rather than a developer who's intending to change to code, should instead be placed +under the Usage section of the documentation.
+ +Federation is the process by which users on different servers can participate +in the same room. For this to work, those other servers must be able to contact +yours to send messages.
+The server_name
configured in the Synapse configuration file (often
+homeserver.yaml
) defines how resources (users, rooms, etc.) will be
+identified (eg: @user:example.com
, #room:example.com
). By default,
+it is also the domain that other servers will use to try to reach your
+server (via port 8448). This is easy to set up and will work provided
+you set the server_name
to match your machine's public DNS hostname.
For this default configuration to work, you will need to listen for TLS +connections on port 8448. The preferred way to do that is by using a +reverse proxy: see reverse_proxy.md for instructions +on how to correctly set one up.
+In some cases you might not want to run Synapse on the machine that has
+the server_name
as its public DNS hostname, or you might want federation
+traffic to use a different port than 8448. For example, you might want to
+have your user names look like @user:example.com
, but you want to run
+Synapse on synapse.example.com
on port 443. This can be done using
+delegation, which allows an admin to control where federation traffic should
+be sent. See delegate.md for instructions on how to set this up.
Once federation has been configured, you should be able to join a room over
+federation. A good place to start is #synapse:matrix.org
- a room for
+Synapse admins.
You can use the federation tester
+to check if your homeserver is configured correctly. Alternatively try the
+JSON API used by the federation tester.
+Note that you'll have to modify this URL to replace DOMAIN
with your
+server_name
. Hitting the API directly provides extra detail.
The typical failure mode for federation is that when the server tries to join +a room, it is rejected with "401: Unauthorized". Generally this means that other +servers in the room could not access yours. (Joining a room over federation is +a complicated dance which requires connections in both directions).
+Another common problem is that people on other servers can't join rooms that +you invite them to. This can be caused by an incorrectly-configured reverse +proxy: see reverse_proxy.md for instructions on how to correctly +configure a reverse proxy.
+HTTP 308 Permanent Redirect
redirects are not followed: Due to missing features
+in the HTTP library used by Synapse, 308 redirects are currently not followed by
+federating servers, which can cause M_UNKNOWN
or 401 Unauthorized
errors. This
+may affect users who are redirecting apex-to-www (e.g. example.com
-> www.example.com
),
+and especially users of the Kubernetes Nginx Ingress module, which uses 308 redirect
+codes by default. For those Kubernetes users, this Stackoverflow post
+might be helpful. For other users, switching to a 301 Moved Permanently
code may be
+an option. 308 redirect codes will be supported properly in a future
+release of Synapse.
If you want to get up and running quickly with a trio of homeservers in a
+private federation, there is a script in the demo
directory. This is mainly
+useful just for development purposes. See demo/README.
Synapse comes with a non-standard login type to support +JSON Web Tokens. In general the +documentation for +the login endpoint +is still valid (and the mechanism works similarly to the +token based login).
+To log in using a JSON Web Token, clients should submit a /login
request as
+follows:
{
+ "type": "org.matrix.login.jwt",
+ "token": "<jwt>"
+}
+
+Note that the login type of m.login.jwt
is supported, but is deprecated. This
+will be removed in a future version of Synapse.
The token
field should include the JSON web token with the following claims:
sub
(subject) claim is required and should encode the local part of the
+user ID.exp
), not before time (nbf
), and issued at (iat
)
+claims are optional, but validated if present.iss
) claim is optional, but required and validated if configured.aud
) claim is optional, but required and validated if configured.
+Providing the audience claim when not configured will cause validation to fail.In the case that the token is not valid, the homeserver must respond with
+403 Forbidden
and an error code of M_FORBIDDEN
.
As with other login types, there are additional fields (e.g. device_id
and
+initial_device_display_name
) which can be included in the above request.
The JSON Web Token integration in Synapse uses the
+PyJWT
library, which must be installed
+as follows:
The relevant libraries are included in the Docker images and Debian packages
+provided by matrix.org
so no further action is needed.
If you installed Synapse into a virtualenv, run /path/to/env/bin/pip install synapse[pyjwt]
to install the necessary dependencies.
For other installation mechanisms, see the documentation provided by the +maintainer.
+To enable the JSON web token integration, you should then add an jwt_config
section
+to your configuration file (or uncomment the enabled: true
line in the
+existing section). See sample_config.yaml for some
+sample settings.
Although JSON Web Tokens are typically generated from an external server, the +examples below use PyJWT directly.
+Configure Synapse with JWT logins, note that this example uses a pre-shared +secret and an algorithm of HS256:
+jwt_config:
+ enabled: true
+ secret: "my-secret-token"
+ algorithm: "HS256"
+
+Generate a JSON web token:
+$ pyjwt --key=my-secret-token --alg=HS256 encode sub=test-user
+eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.Ag71GT8v01UO3w80aqRPTeuVPBIBZkYhNTJJ-_-zQIc
+
+Query for the login types and ensure org.matrix.login.jwt
is there:
curl http://localhost:8080/_matrix/client/r0/login
+
+Login used the generated JSON web token from above:
+$ curl http://localhost:8082/_matrix/client/r0/login -X POST \
+ --data '{"type":"org.matrix.login.jwt","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.Ag71GT8v01UO3w80aqRPTeuVPBIBZkYhNTJJ-_-zQIc"}'
+{
+ "access_token": "<access token>",
+ "device_id": "ACBDEFGHI",
+ "home_server": "localhost:8080",
+ "user_id": "@test-user:localhost:8480"
+}
+
+You should now be able to use the returned access token to query the client API.
+ +