Compare commits
247 Commits
dmr/storag
...
v1.50.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd05a3ed03 | ||
|
|
9d0098595e | ||
|
|
ab12c909a2 | ||
|
|
d93ec0a0ba | ||
|
|
4ec0a309cf | ||
|
|
3ba9389699 | ||
|
|
422e33fabf | ||
|
|
867443472c | ||
|
|
b602ba194b | ||
|
|
22abfca8d9 | ||
|
|
1b1aed38e3 | ||
|
|
2185b28184 | ||
|
|
7fe7c45438 | ||
|
|
e87540abb1 | ||
|
|
eec34b1f2a | ||
|
|
daea7bcc34 | ||
|
|
83acdb23fe | ||
|
|
877b45e812 | ||
|
|
102f4d3598 | ||
|
|
ffd71029ab | ||
|
|
5f98d8e6fd | ||
|
|
9be5aacc2d | ||
|
|
0fb3dd0830 | ||
|
|
eedb4527f1 | ||
|
|
0201c6371c | ||
|
|
7a1cefc6e3 | ||
|
|
84bfe47b01 | ||
|
|
84d790a32e | ||
|
|
7013e06e2f | ||
|
|
0715e77b06 | ||
|
|
79f6d3550a | ||
|
|
b38bdae3a2 | ||
|
|
878aa55293 | ||
|
|
2359ee3864 | ||
|
|
bd9821f7f1 | ||
|
|
8422a7f7f6 | ||
|
|
13c974ed35 | ||
|
|
cbd82d0b2d | ||
|
|
07a3b5daba | ||
|
|
2c7f5e74e5 | ||
|
|
f82d38ed2e | ||
|
|
f58b300d27 | ||
|
|
15bb1c8511 | ||
|
|
fcfe67578f | ||
|
|
66d7aa783a | ||
|
|
c500bf37d6 | ||
|
|
87da37374a | ||
|
|
144b9ede89 | ||
|
|
9ec46d6231 | ||
|
|
6b6dcdc338 | ||
|
|
aa874a1390 | ||
|
|
2bf31f7807 | ||
|
|
e6897e7383 | ||
|
|
b6102230a7 | ||
|
|
57ca8ab10f | ||
|
|
aa58e8a28a | ||
|
|
b9f2f6d3c4 | ||
|
|
2215954147 | ||
|
|
8c36d332d5 | ||
|
|
dd47788752 | ||
|
|
c3e38b88f2 | ||
|
|
60fa4935b5 | ||
|
|
8e4083e2f6 | ||
|
|
76aa5537ad | ||
|
|
3e0cfd447e | ||
|
|
7a7ca8f226 | ||
|
|
8ad39438fa | ||
|
|
8428ef66c7 | ||
|
|
1847d027e6 | ||
|
|
43f5cc7adc | ||
|
|
c7fe32edb4 | ||
|
|
f901f8b70e | ||
|
|
323151b787 | ||
|
|
17886d2603 | ||
|
|
ecfcd9bbbe | ||
|
|
0147b3de20 | ||
|
|
2519beaad2 | ||
|
|
70ca05373b | ||
|
|
a91698df90 | ||
|
|
4dd9ea8f4f | ||
|
|
92906e1b60 | ||
|
|
9f3c7e85a4 | ||
|
|
a4dce5b53d | ||
|
|
33abbc3278 | ||
|
|
ff6fd52160 | ||
|
|
eb39da6782 | ||
|
|
5305a5e881 | ||
|
|
1abfb15f07 | ||
|
|
6da8591f2e | ||
|
|
e5cdb9e233 | ||
|
|
aa8708ebed | ||
|
|
8391bd6ab5 | ||
|
|
fd2dadb815 | ||
|
|
f0562183e7 | ||
|
|
86e7a6d16e | ||
|
|
9562f0c2f1 | ||
|
|
3b8872299a | ||
|
|
0cc3bf97b4 | ||
|
|
941ebe49ff | ||
|
|
b47d10dc46 | ||
|
|
b3bcacf3c1 | ||
|
|
afa0a5e4fc | ||
|
|
d93362d87f | ||
|
|
7ecaa3b976 | ||
|
|
83a74d9350 | ||
|
|
365e9482fe | ||
|
|
ff7cc17b57 | ||
|
|
8541809cb9 | ||
|
|
d6fb96e056 | ||
|
|
158d73ebdd | ||
|
|
26b5d2320f | ||
|
|
bce4220f38 | ||
|
|
966b5d0fa0 | ||
|
|
088d748f2c | ||
|
|
14d593f72d | ||
|
|
2a3ec6facf | ||
|
|
eccc49d755 | ||
|
|
b1ecd19c5d | ||
|
|
9c55dedc8c | ||
|
|
2d42e586a8 | ||
|
|
2f053f3f82 | ||
|
|
a15a893df8 | ||
|
|
8b4b153c9e | ||
|
|
494ebd7347 | ||
|
|
a77c369897 | ||
|
|
4eb77965cd | ||
|
|
637df95de6 | ||
|
|
e5f426cd54 | ||
|
|
8cd68b8102 | ||
|
|
6cae125e20 | ||
|
|
7be88fbf48 | ||
|
|
b3fd99b74a | ||
|
|
f7ec6e7d9e | ||
|
|
5640992d17 | ||
|
|
d26808dd85 | ||
|
|
f91624a595 | ||
|
|
16d39a5490 | ||
|
|
8a4c296987 | ||
|
|
49e1356ee3 | ||
|
|
d2279f471b | ||
|
|
b50e39df57 | ||
|
|
858d80bf0f | ||
|
|
435f044807 | ||
|
|
f61462e1be | ||
|
|
a6f1a3abec | ||
|
|
84dc50e160 | ||
|
|
ed635d3285 | ||
|
|
7b62791e00 | ||
|
|
153194c771 | ||
|
|
f44d729d4c | ||
|
|
a265fbd397 | ||
|
|
b9fef1a7cd | ||
|
|
b0eb64ff7b | ||
|
|
f1795463bf | ||
|
|
70cbb1a5e3 | ||
|
|
42bf020463 | ||
|
|
379f2650cf | ||
|
|
7ff22d6da4 | ||
|
|
5a0b652d36 | ||
|
|
432a174bc1 | ||
|
|
b14f8a1baf | ||
|
|
28f5252c1f | ||
|
|
f13a8d1c69 | ||
|
|
a9481223d1 | ||
|
|
e713855dca | ||
|
|
f663426804 | ||
|
|
3d831415cc | ||
|
|
4bdad80de1 | ||
|
|
35b1900f00 | ||
|
|
e8ae94a223 | ||
|
|
fb58611d21 | ||
|
|
a4521ce0a8 | ||
|
|
d08ef6f155 | ||
|
|
9d1971a5c4 | ||
|
|
7564b8e118 | ||
|
|
a82b90ab32 | ||
|
|
9cd13c5f63 | ||
|
|
7b4e228e41 | ||
|
|
dc0a3cd596 | ||
|
|
aa457b625e | ||
|
|
776ad3e5e9 | ||
|
|
e5c5e213ea | ||
|
|
1b6691dce4 | ||
|
|
ffd858aa68 | ||
|
|
1d8b80b334 | ||
|
|
e2c300e7e4 | ||
|
|
c675a18071 | ||
|
|
c54c9df286 | ||
|
|
d4dcc0524f | ||
|
|
7862f821de | ||
|
|
b757b68454 | ||
|
|
946c102ac9 | ||
|
|
0d88c4f903 | ||
|
|
7f9841bdec | ||
|
|
f25c75d376 | ||
|
|
55669bd3de | ||
|
|
7cebaf9644 | ||
|
|
454c3d7694 | ||
|
|
fcb9441791 | ||
|
|
6a5dd485bd | ||
|
|
1035663833 | ||
|
|
3d893b8cf2 | ||
|
|
d9e9771d6b | ||
|
|
ea20937084 | ||
|
|
8fa83999d6 | ||
|
|
7ae559944a | ||
|
|
9c21a68995 | ||
|
|
8d4dcac7e9 | ||
|
|
97a402302c | ||
|
|
91f2bd0907 | ||
|
|
4d6d38ac2f | ||
|
|
5505da2109 | ||
|
|
eca7cffb73 | ||
|
|
e2e9bea1ce | ||
|
|
a6f7f84570 | ||
|
|
7ffddd819c | ||
|
|
92b75388f5 | ||
|
|
81b18fe5c0 | ||
|
|
5f81c0ce9c | ||
|
|
433ee159cb | ||
|
|
539e441399 | ||
|
|
4bd54b263e | ||
|
|
e2dabec996 | ||
|
|
84fac0f814 | ||
|
|
d993c3bb1e | ||
|
|
b76337fdf8 | ||
|
|
077b74929f | ||
|
|
0d86f6334a | ||
|
|
60ecb6b4d4 | ||
|
|
9f9d82aa84 | ||
|
|
319dcb955e | ||
|
|
0caf20883c | ||
|
|
88375beeaa | ||
|
|
7baa671dc8 | ||
|
|
729acd82c8 | ||
|
|
edcdc5fd82 | ||
|
|
dfa536490e | ||
|
|
7468723697 | ||
|
|
6e084b62b8 | ||
|
|
3a1462f7e0 | ||
|
|
24b61f379a | ||
|
|
0dda1a7968 | ||
|
|
e72135b9d3 | ||
|
|
9c59e117db | ||
|
|
b596a1eb80 | ||
|
|
4ad5ee9996 | ||
|
|
02742fd058 |
5
.github/workflows/docker.yml
vendored
5
.github/workflows/docker.yml
vendored
@@ -5,7 +5,7 @@ name: Build docker images
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
branches: [ master, main ]
|
||||
branches: [ master, main, develop ]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -38,6 +38,9 @@ jobs:
|
||||
id: set-tag
|
||||
run: |
|
||||
case "${GITHUB_REF}" in
|
||||
refs/heads/develop)
|
||||
tag=develop
|
||||
;;
|
||||
refs/heads/master|refs/heads/main)
|
||||
tag=latest
|
||||
;;
|
||||
|
||||
14
.github/workflows/tests.yml
vendored
14
.github/workflows/tests.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
|
||||
python-version: ["3.7", "3.8", "3.9", "3.10"]
|
||||
database: ["sqlite"]
|
||||
toxenv: ["py"]
|
||||
include:
|
||||
@@ -85,9 +85,9 @@ jobs:
|
||||
toxenv: "py-noextras"
|
||||
|
||||
# Oldest Python with PostgreSQL
|
||||
- python-version: "3.6"
|
||||
- python-version: "3.7"
|
||||
database: "postgres"
|
||||
postgres-version: "9.6"
|
||||
postgres-version: "10"
|
||||
toxenv: "py"
|
||||
|
||||
# Newest Python with newest PostgreSQL
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["pypy-3.6"]
|
||||
python-version: ["pypy-3.7"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -291,8 +291,8 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- python-version: "3.6"
|
||||
postgres-version: "9.6"
|
||||
- python-version: "3.7"
|
||||
postgres-version: "10"
|
||||
|
||||
- python-version: "3.10"
|
||||
postgres-version: "14"
|
||||
@@ -374,7 +374,7 @@ jobs:
|
||||
working-directory: complement/dockerfiles
|
||||
|
||||
# Run Complement
|
||||
- run: go test -v -tags synapse_blacklist,msc2403,msc2946,msc3083 ./tests/...
|
||||
- run: go test -v -tags synapse_blacklist,msc2403 ./tests/...
|
||||
env:
|
||||
COMPLEMENT_BASE_IMAGE: complement-synapse:latest
|
||||
working-directory: complement
|
||||
|
||||
406
CHANGES.md
406
CHANGES.md
@@ -1,3 +1,401 @@
|
||||
Synapse 1.50.1 (2022-01-18)
|
||||
===========================
|
||||
|
||||
This release fixes a bug in Synapse 1.50.0 that could prevent clients from being able to connect to Synapse if the `webclient` resource was enabled. Further details are available in [this issue](https://github.com/matrix-org/synapse/issues/11763).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix a bug introduced in Synapse 1.50.0rc1 that could cause Matrix clients to be unable to connect to Synapse instances with the `webclient` resource enabled. ([\#11764](https://github.com/matrix-org/synapse/issues/11764))
|
||||
|
||||
|
||||
Synapse 1.50.0 (2022-01-18)
|
||||
===========================
|
||||
|
||||
**This release contains a critical bug that may prevent clients from being able to connect.
|
||||
As such, it is not recommended to upgrade to 1.50.0. Instead, please upgrade straight to
|
||||
to 1.50.1. Further details are available in [this issue](https://github.com/matrix-org/synapse/issues/11763).**
|
||||
|
||||
Please note that we now only support Python 3.7+ and PostgreSQL 10+ (if applicable), because Python 3.6 and PostgreSQL 9.6 have reached end-of-life.
|
||||
|
||||
No significant changes since 1.50.0rc2.
|
||||
|
||||
|
||||
Synapse 1.50.0rc2 (2022-01-14)
|
||||
==============================
|
||||
|
||||
This release candidate fixes a federation-breaking regression introduced in Synapse 1.50.0rc1.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix a bug introduced in Synapse v1.0.0 whereby some device list updates would not be sent to remote homeservers if there were too many to send at once. ([\#11729](https://github.com/matrix-org/synapse/issues/11729))
|
||||
- Fix a bug introduced in Synapse v1.50.0rc1 whereby outbound federation could fail because too many EDUs were produced for device updates. ([\#11730](https://github.com/matrix-org/synapse/issues/11730))
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Document that now the minimum supported PostgreSQL version is 10. ([\#11725](https://github.com/matrix-org/synapse/issues/11725))
|
||||
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Fix a typechecker problem related to our (ab)use of `nacl.signing.SigningKey`s. ([\#11714](https://github.com/matrix-org/synapse/issues/11714))
|
||||
|
||||
|
||||
Synapse 1.50.0rc1 (2022-01-05)
|
||||
==============================
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Allow guests to send state events per [MSC3419](https://github.com/matrix-org/matrix-doc/pull/3419). ([\#11378](https://github.com/matrix-org/synapse/issues/11378))
|
||||
- Add experimental support for part of [MSC3202](https://github.com/matrix-org/matrix-doc/pull/3202): allowing application services to masquerade as specific devices. ([\#11538](https://github.com/matrix-org/synapse/issues/11538))
|
||||
- Add admin API to get users' account data. ([\#11664](https://github.com/matrix-org/synapse/issues/11664))
|
||||
- Include the room topic in the stripped state included with invites and knocking. ([\#11666](https://github.com/matrix-org/synapse/issues/11666))
|
||||
- Send and handle cross-signing messages using the stable prefix. ([\#10520](https://github.com/matrix-org/synapse/issues/10520))
|
||||
- Support unprefixed versions of fallback key property names. ([\#11541](https://github.com/matrix-org/synapse/issues/11541))
|
||||
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix a long-standing bug where relations from other rooms could be included in the bundled aggregations of an event. ([\#11516](https://github.com/matrix-org/synapse/issues/11516))
|
||||
- Fix a long-standing bug which could cause `AssertionError`s to be written to the log when Synapse was restarted after purging events from the database. ([\#11536](https://github.com/matrix-org/synapse/issues/11536), [\#11642](https://github.com/matrix-org/synapse/issues/11642))
|
||||
- Fix a bug introduced in Synapse 1.17.0 where a pusher created for an email with capital letters would fail to be created. ([\#11547](https://github.com/matrix-org/synapse/issues/11547))
|
||||
- Fix a long-standing bug where responses included bundled aggregations when they should not, per [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675). ([\#11592](https://github.com/matrix-org/synapse/issues/11592), [\#11623](https://github.com/matrix-org/synapse/issues/11623))
|
||||
- Fix a long-standing bug that some unknown endpoints would return HTML error pages instead of JSON `M_UNRECOGNIZED` errors. ([\#11602](https://github.com/matrix-org/synapse/issues/11602))
|
||||
- Fix a bug introduced in Synapse 1.19.3 which could sometimes cause `AssertionError`s when backfilling rooms over federation. ([\#11632](https://github.com/matrix-org/synapse/issues/11632))
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Update Synapse install command for FreeBSD as the package is now prefixed with `py38`. Contributed by @itchychips. ([\#11267](https://github.com/matrix-org/synapse/issues/11267))
|
||||
- Document the usage of refresh tokens. ([\#11427](https://github.com/matrix-org/synapse/issues/11427))
|
||||
- Add details for how to configure a TURN server when behind a NAT. Contibuted by @AndrewFerr. ([\#11553](https://github.com/matrix-org/synapse/issues/11553))
|
||||
- Add references for using Postgres to the Docker documentation. ([\#11640](https://github.com/matrix-org/synapse/issues/11640))
|
||||
- Fix the documentation link in newly-generated configuration files. ([\#11678](https://github.com/matrix-org/synapse/issues/11678))
|
||||
- Correct the documentation for `nginx` to use a case-sensitive url pattern. Fixes an error introduced in v1.21.0. ([\#11680](https://github.com/matrix-org/synapse/issues/11680))
|
||||
- Clarify SSO mapping provider documentation by writing `def` or `async def` before the names of methods, as appropriate. ([\#11681](https://github.com/matrix-org/synapse/issues/11681))
|
||||
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Replace `mock` package by its standard library version. ([\#11588](https://github.com/matrix-org/synapse/issues/11588))
|
||||
- Drop support for Python 3.6 and Ubuntu 18.04. ([\#11633](https://github.com/matrix-org/synapse/issues/11633))
|
||||
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Allow specific, experimental events to be created without `prev_events`. Used by [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716). ([\#11243](https://github.com/matrix-org/synapse/issues/11243))
|
||||
- A test helper (`wait_for_background_updates`) no longer depends on classes defining a `store` property. ([\#11331](https://github.com/matrix-org/synapse/issues/11331))
|
||||
- Add type hints to `synapse.appservice`. ([\#11360](https://github.com/matrix-org/synapse/issues/11360))
|
||||
- Add missing type hints to `synapse.config` module. ([\#11480](https://github.com/matrix-org/synapse/issues/11480))
|
||||
- Add test to ensure we share the same `state_group` across the whole historical batch when using the [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) `/batch_send` endpoint. ([\#11487](https://github.com/matrix-org/synapse/issues/11487))
|
||||
- Refactor `tests.util.setup_test_homeserver` and `tests.server.setup_test_homeserver`. ([\#11503](https://github.com/matrix-org/synapse/issues/11503))
|
||||
- Move `glob_to_regex` and `re_word_boundary` to `matrix-python-common`. ([\#11505](https://github.com/matrix-org/synapse/issues/11505), [\#11687](https://github.com/matrix-org/synapse/issues/11687))
|
||||
- Use `HTTPStatus` constants in place of literals in `tests.rest.client.test_auth`. ([\#11520](https://github.com/matrix-org/synapse/issues/11520))
|
||||
- Add a receipt types constant for `m.read`. ([\#11531](https://github.com/matrix-org/synapse/issues/11531))
|
||||
- Clean up `synapse.rest.admin`. ([\#11535](https://github.com/matrix-org/synapse/issues/11535))
|
||||
- Add missing `errcode` to `parse_string` and `parse_boolean`. ([\#11542](https://github.com/matrix-org/synapse/issues/11542))
|
||||
- Use `HTTPStatus` constants in place of literals in `synapse.http`. ([\#11543](https://github.com/matrix-org/synapse/issues/11543))
|
||||
- Add missing type hints to storage classes. ([\#11546](https://github.com/matrix-org/synapse/issues/11546), [\#11549](https://github.com/matrix-org/synapse/issues/11549), [\#11551](https://github.com/matrix-org/synapse/issues/11551), [\#11555](https://github.com/matrix-org/synapse/issues/11555), [\#11575](https://github.com/matrix-org/synapse/issues/11575), [\#11589](https://github.com/matrix-org/synapse/issues/11589), [\#11594](https://github.com/matrix-org/synapse/issues/11594), [\#11652](https://github.com/matrix-org/synapse/issues/11652), [\#11653](https://github.com/matrix-org/synapse/issues/11653), [\#11654](https://github.com/matrix-org/synapse/issues/11654), [\#11657](https://github.com/matrix-org/synapse/issues/11657))
|
||||
- Fix an inaccurate and misleading comment in the `/sync` code. ([\#11550](https://github.com/matrix-org/synapse/issues/11550))
|
||||
- Add missing type hints to `synapse.logging.context`. ([\#11556](https://github.com/matrix-org/synapse/issues/11556))
|
||||
- Stop populating unused database column `state_events.prev_state`. ([\#11558](https://github.com/matrix-org/synapse/issues/11558))
|
||||
- Minor efficiency improvements in event persistence. ([\#11560](https://github.com/matrix-org/synapse/issues/11560))
|
||||
- Add some safety checks that storage functions are used correctly. ([\#11564](https://github.com/matrix-org/synapse/issues/11564), [\#11580](https://github.com/matrix-org/synapse/issues/11580))
|
||||
- Make `get_device` return `None` if the device doesn't exist rather than raising an exception. ([\#11565](https://github.com/matrix-org/synapse/issues/11565))
|
||||
- Split the HTML parsing code from the URL preview resource code. ([\#11566](https://github.com/matrix-org/synapse/issues/11566))
|
||||
- Remove redundant `COALESCE()`s around `COUNT()`s in database queries. ([\#11570](https://github.com/matrix-org/synapse/issues/11570))
|
||||
- Add missing type hints to `synapse.http`. ([\#11571](https://github.com/matrix-org/synapse/issues/11571))
|
||||
- Add [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) and [MSC3030](https://github.com/matrix-org/matrix-doc/pull/3030) to `/versions` -> `unstable_features` to detect server support. ([\#11582](https://github.com/matrix-org/synapse/issues/11582))
|
||||
- Add type hints to `synapse/tests/rest/admin`. ([\#11590](https://github.com/matrix-org/synapse/issues/11590))
|
||||
- Drop end-of-life Python 3.6 and Postgres 9.6 from CI. ([\#11595](https://github.com/matrix-org/synapse/issues/11595))
|
||||
- Update black version and run it on all the files. ([\#11596](https://github.com/matrix-org/synapse/issues/11596))
|
||||
- Add opentracing type stubs and fix associated mypy errors. ([\#11603](https://github.com/matrix-org/synapse/issues/11603), [\#11622](https://github.com/matrix-org/synapse/issues/11622))
|
||||
- Improve OpenTracing support for requests which use a `ResponseCache`. ([\#11607](https://github.com/matrix-org/synapse/issues/11607))
|
||||
- Improve OpenTracing support for incoming HTTP requests. ([\#11618](https://github.com/matrix-org/synapse/issues/11618))
|
||||
- A number of improvements to opentracing support. ([\#11619](https://github.com/matrix-org/synapse/issues/11619))
|
||||
- Refactor the way that the `outlier` flag is set on events received over federation. ([\#11634](https://github.com/matrix-org/synapse/issues/11634))
|
||||
- Improve the error messages from `get_create_event_for_room`. ([\#11638](https://github.com/matrix-org/synapse/issues/11638))
|
||||
- Remove redundant `get_current_events_token` method. ([\#11643](https://github.com/matrix-org/synapse/issues/11643))
|
||||
- Convert `namedtuples` to `attrs`. ([\#11665](https://github.com/matrix-org/synapse/issues/11665), [\#11574](https://github.com/matrix-org/synapse/issues/11574))
|
||||
- Update the `/capabilities` response to include whether support for [MSC3440](https://github.com/matrix-org/matrix-doc/pull/3440) is available. ([\#11690](https://github.com/matrix-org/synapse/issues/11690))
|
||||
- Send the `Accept` header in HTTP requests made using `SimpleHttpClient.get_json`. ([\#11677](https://github.com/matrix-org/synapse/issues/11677))
|
||||
- Work around Mjolnir compatibility issue by adding an import for `glob_to_regex` in `synapse.util`, where it moved from. ([\#11696](https://github.com/matrix-org/synapse/issues/11696))
|
||||
|
||||
|
||||
Synapse 1.49.2 (2021-12-21)
|
||||
===========================
|
||||
|
||||
This release fixes a regression introduced in Synapse 1.49.0 which could cause `/sync` requests to take significantly longer. This would particularly affect "initial" syncs for users participating in a large number of rooms, and in extreme cases, could make it impossible for such users to log in on a new client.
|
||||
|
||||
**Note:** in line with our [deprecation policy](https://matrix-org.github.io/synapse/latest/deprecation_policy.html) for platform dependencies, this will be the last release to support Python 3.6 and PostgreSQL 9.6, both of which have now reached upstream end-of-life. Synapse will require Python 3.7+ and PostgreSQL 10+.
|
||||
|
||||
**Note:** We will also stop producing packages for Ubuntu 18.04 (Bionic Beaver) after this release, as it uses Python 3.6.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix a performance regression in `/sync` handling, introduced in 1.49.0. ([\#11583](https://github.com/matrix-org/synapse/issues/11583))
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Work around a build problem on Debian Buster. ([\#11625](https://github.com/matrix-org/synapse/issues/11625))
|
||||
|
||||
|
||||
Synapse 1.49.1 (2021-12-21)
|
||||
===========================
|
||||
|
||||
Not released due to problems building the debian packages.
|
||||
|
||||
|
||||
Synapse 1.49.0 (2021-12-14)
|
||||
===========================
|
||||
|
||||
No significant changes since version 1.49.0rc1.
|
||||
|
||||
|
||||
Support for Ubuntu 21.04 ends next month on the 20th of January
|
||||
---------------------------------------------------------------
|
||||
|
||||
For users of Ubuntu 21.04 (Hirsute Hippo), please be aware that [upstream support for this version of Ubuntu will end next month][Ubuntu2104EOL].
|
||||
We will stop producing packages for Ubuntu 21.04 after upstream support ends.
|
||||
|
||||
[Ubuntu2104EOL]: https://lists.ubuntu.com/archives/ubuntu-announce/2021-December/000275.html
|
||||
|
||||
|
||||
The wiki has been migrated to the documentation website
|
||||
-------------------------------------------------------
|
||||
|
||||
We've decided to move the existing, somewhat stagnant pages from the GitHub wiki
|
||||
to the [documentation website](https://matrix-org.github.io/synapse/latest/).
|
||||
|
||||
This was done for two reasons. The first was to ensure that changes are checked by
|
||||
multiple authors before being committed (everyone makes mistakes!) and the second
|
||||
was visibility of the documentation. Not everyone knows that Synapse has some very
|
||||
useful information hidden away in its GitHub wiki pages. Bringing them to the
|
||||
documentation website should help with visibility, as well as keep all Synapse documentation
|
||||
in one, easily-searchable location.
|
||||
|
||||
Note that contributions to the documentation website happen through [GitHub pull
|
||||
requests](https://github.com/matrix-org/synapse/pulls). Please visit [#synapse-dev:matrix.org](https://matrix.to/#/#synapse-dev:matrix.org)
|
||||
if you need help with the process!
|
||||
|
||||
|
||||
Synapse 1.49.0rc1 (2021-12-07)
|
||||
==============================
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Add [MSC3030](https://github.com/matrix-org/matrix-doc/pull/3030) experimental client and federation API endpoints to get the closest event to a given timestamp. ([\#9445](https://github.com/matrix-org/synapse/issues/9445))
|
||||
- Include bundled relation aggregations during a limited `/sync` request and `/relations` request, per [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675). ([\#11284](https://github.com/matrix-org/synapse/issues/11284), [\#11478](https://github.com/matrix-org/synapse/issues/11478))
|
||||
- Add plugin support for controlling database background updates. ([\#11306](https://github.com/matrix-org/synapse/issues/11306), [\#11475](https://github.com/matrix-org/synapse/issues/11475), [\#11479](https://github.com/matrix-org/synapse/issues/11479))
|
||||
- Support the stable API endpoints for [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946): the room `/hierarchy` endpoint. ([\#11329](https://github.com/matrix-org/synapse/issues/11329))
|
||||
- Add admin API to get some information about federation status with remote servers. ([\#11407](https://github.com/matrix-org/synapse/issues/11407))
|
||||
- Support expiry of refresh tokens and expiry of the overall session when refresh tokens are in use. ([\#11425](https://github.com/matrix-org/synapse/issues/11425))
|
||||
- Stabilise support for [MSC2918](https://github.com/matrix-org/matrix-doc/blob/main/proposals/2918-refreshtokens.md#msc2918-refresh-tokens) refresh tokens as they have now been merged into the Matrix specification. ([\#11435](https://github.com/matrix-org/synapse/issues/11435), [\#11522](https://github.com/matrix-org/synapse/issues/11522))
|
||||
- Update [MSC2918 refresh token](https://github.com/matrix-org/matrix-doc/blob/main/proposals/2918-refreshtokens.md#msc2918-refresh-tokens) support to confirm with the latest revision: accept the `refresh_tokens` parameter in the request body rather than in the URL parameters. ([\#11430](https://github.com/matrix-org/synapse/issues/11430))
|
||||
- Support configuring the lifetime of non-refreshable access tokens separately to refreshable access tokens. ([\#11445](https://github.com/matrix-org/synapse/issues/11445))
|
||||
- Expose `synapse_homeserver` and `synapse_worker` commands as entry points to run Synapse's main process and worker processes, respectively. Contributed by @Ma27. ([\#11449](https://github.com/matrix-org/synapse/issues/11449))
|
||||
- `synctl stop` will now wait for Synapse to exit before returning. ([\#11459](https://github.com/matrix-org/synapse/issues/11459), [\#11490](https://github.com/matrix-org/synapse/issues/11490))
|
||||
- Extend the "delete room" admin api to work correctly on rooms which have previously been partially deleted. ([\#11523](https://github.com/matrix-org/synapse/issues/11523))
|
||||
- Add support for the `/_matrix/client/v3/login/sso/redirect/{idpId}` API from Matrix v1.1. This endpoint was overlooked when support for v3 endpoints was added in Synapse 1.48.0rc1. ([\#11451](https://github.com/matrix-org/synapse/issues/11451))
|
||||
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix using [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) batch sending in combination with event persistence workers. Contributed by @tulir at Beeper. ([\#11220](https://github.com/matrix-org/synapse/issues/11220))
|
||||
- Fix a long-standing bug where all requests that read events from the database could get stuck as a result of losing the database connection, properly this time. Also fix a race condition introduced in the previous insufficient fix in Synapse 1.47.0. ([\#11376](https://github.com/matrix-org/synapse/issues/11376))
|
||||
- The `/send_join` response now includes the stable `event` field instead of the unstable field from [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083). ([\#11413](https://github.com/matrix-org/synapse/issues/11413))
|
||||
- Fix a bug introduced in Synapse 1.47.0 where `send_join` could fail due to an outdated `ijson` version. ([\#11439](https://github.com/matrix-org/synapse/issues/11439), [\#11441](https://github.com/matrix-org/synapse/issues/11441), [\#11460](https://github.com/matrix-org/synapse/issues/11460))
|
||||
- Fix a bug introduced in Synapse 1.36.0 which could cause problems fetching event-signing keys from trusted key servers. ([\#11440](https://github.com/matrix-org/synapse/issues/11440))
|
||||
- Fix a bug introduced in Synapse 1.47.1 where the media repository would fail to work if the media store path contained any symbolic links. ([\#11446](https://github.com/matrix-org/synapse/issues/11446))
|
||||
- Fix an `LruCache` corruption bug, introduced in Synapse 1.38.0, that would cause certain requests to fail until the next Synapse restart. ([\#11454](https://github.com/matrix-org/synapse/issues/11454))
|
||||
- Fix a long-standing bug where invites from ignored users were included in incremental syncs. ([\#11511](https://github.com/matrix-org/synapse/issues/11511))
|
||||
- Fix a regression in Synapse 1.48.0 where presence workers would not clear their presence updates over replication on shutdown. ([\#11518](https://github.com/matrix-org/synapse/issues/11518))
|
||||
- Fix a regression in Synapse 1.48.0 where the module API's `looping_background_call` method would spam errors to the logs when given a non-async function. ([\#11524](https://github.com/matrix-org/synapse/issues/11524))
|
||||
|
||||
|
||||
Updates to the Docker image
|
||||
---------------------------
|
||||
|
||||
- Update `Dockerfile-workers` to healthcheck all workers in the container. ([\#11429](https://github.com/matrix-org/synapse/issues/11429))
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Update the media repository documentation. ([\#11415](https://github.com/matrix-org/synapse/issues/11415))
|
||||
- Update section about backward extremities in the room DAG concepts doc to correct the misconception about backward extremities indicating whether we have fetched an events' `prev_events`. ([\#11469](https://github.com/matrix-org/synapse/issues/11469))
|
||||
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Add `Final` annotation to string constants in `synapse.api.constants` so that they get typed as `Literal`s. ([\#11356](https://github.com/matrix-org/synapse/issues/11356))
|
||||
- Add a check to ensure that users cannot start the Synapse master process when `worker_app` is set. ([\#11416](https://github.com/matrix-org/synapse/issues/11416))
|
||||
- Add a note about postgres memory management and hugepages to postgres doc. ([\#11467](https://github.com/matrix-org/synapse/issues/11467))
|
||||
- Add missing type hints to `synapse.config` module. ([\#11465](https://github.com/matrix-org/synapse/issues/11465))
|
||||
- Add missing type hints to `synapse.federation`. ([\#11483](https://github.com/matrix-org/synapse/issues/11483))
|
||||
- Add type annotations to `tests.storage.test_appservice`. ([\#11488](https://github.com/matrix-org/synapse/issues/11488), [\#11492](https://github.com/matrix-org/synapse/issues/11492))
|
||||
- Add type annotations to some of the configuration surrounding refresh tokens. ([\#11428](https://github.com/matrix-org/synapse/issues/11428))
|
||||
- Add type hints to `synapse/tests/rest/admin`. ([\#11501](https://github.com/matrix-org/synapse/issues/11501))
|
||||
- Add type hints to storage classes. ([\#11411](https://github.com/matrix-org/synapse/issues/11411))
|
||||
- Add wiki pages to documentation website. ([\#11402](https://github.com/matrix-org/synapse/issues/11402))
|
||||
- Clean up `tests.storage.test_main` to remove use of legacy code. ([\#11493](https://github.com/matrix-org/synapse/issues/11493))
|
||||
- Clean up `tests.test_visibility` to remove legacy code. ([\#11495](https://github.com/matrix-org/synapse/issues/11495))
|
||||
- Convert status codes to `HTTPStatus` in `synapse.rest.admin`. ([\#11452](https://github.com/matrix-org/synapse/issues/11452), [\#11455](https://github.com/matrix-org/synapse/issues/11455))
|
||||
- Extend the `scripts-dev/sign_json` script to support signing events. ([\#11486](https://github.com/matrix-org/synapse/issues/11486))
|
||||
- Improve internal types in push code. ([\#11409](https://github.com/matrix-org/synapse/issues/11409))
|
||||
- Improve type annotations in `synapse.module_api`. ([\#11029](https://github.com/matrix-org/synapse/issues/11029))
|
||||
- Improve type hints for `LruCache`. ([\#11453](https://github.com/matrix-org/synapse/issues/11453))
|
||||
- Preparation for database schema simplifications: disambiguate queries on `state_key`. ([\#11497](https://github.com/matrix-org/synapse/issues/11497))
|
||||
- Refactor `backfilled` into specific behavior function arguments (`_persist_events_and_state_updates` and downstream calls). ([\#11417](https://github.com/matrix-org/synapse/issues/11417))
|
||||
- Refactor `get_version_string` to fix-up types and duplicated code. ([\#11468](https://github.com/matrix-org/synapse/issues/11468))
|
||||
- Refactor various parts of the `/sync` handler. ([\#11494](https://github.com/matrix-org/synapse/issues/11494), [\#11515](https://github.com/matrix-org/synapse/issues/11515))
|
||||
- Remove unnecessary `json.dumps` from `tests.rest.admin`. ([\#11461](https://github.com/matrix-org/synapse/issues/11461))
|
||||
- Save the OpenID Connect session ID on login. ([\#11482](https://github.com/matrix-org/synapse/issues/11482))
|
||||
- Update and clean up recently ported documentation pages. ([\#11466](https://github.com/matrix-org/synapse/issues/11466))
|
||||
|
||||
|
||||
Synapse 1.48.0 (2021-11-30)
|
||||
===========================
|
||||
|
||||
This release removes support for the long-deprecated `trust_identity_server_for_password_resets` configuration flag.
|
||||
|
||||
This release also fixes some performance issues with some background database updates introduced in Synapse 1.47.0.
|
||||
|
||||
No significant changes since 1.48.0rc1.
|
||||
|
||||
Synapse 1.48.0rc1 (2021-11-25)
|
||||
==============================
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Experimental support for the thread relation defined in [MSC3440](https://github.com/matrix-org/matrix-doc/pull/3440). ([\#11161](https://github.com/matrix-org/synapse/issues/11161))
|
||||
- Support filtering by relation senders & types per [MSC3440](https://github.com/matrix-org/matrix-doc/pull/3440). ([\#11236](https://github.com/matrix-org/synapse/issues/11236))
|
||||
- Add support for the `/_matrix/client/v3` and `/_matrix/media/v3` APIs from Matrix v1.1. ([\#11318](https://github.com/matrix-org/synapse/issues/11318), [\#11371](https://github.com/matrix-org/synapse/issues/11371))
|
||||
- Support the stable version of [MSC2778](https://github.com/matrix-org/matrix-doc/pull/2778): the `m.login.application_service` login type. Contributed by @tulir. ([\#11335](https://github.com/matrix-org/synapse/issues/11335))
|
||||
- Add a new version of delete room admin API `DELETE /_synapse/admin/v2/rooms/<room_id>` to run it in the background. Contributed by @dklimpel. ([\#11223](https://github.com/matrix-org/synapse/issues/11223))
|
||||
- Allow the admin [Delete Room API](https://matrix-org.github.io/synapse/latest/admin_api/rooms.html#delete-room-api) to block a room without the need to join it. ([\#11228](https://github.com/matrix-org/synapse/issues/11228))
|
||||
- Add an admin API to un-shadow-ban a user. ([\#11347](https://github.com/matrix-org/synapse/issues/11347))
|
||||
- Add an admin API to run background database schema updates. ([\#11352](https://github.com/matrix-org/synapse/issues/11352))
|
||||
- Add an admin API for blocking a room. ([\#11324](https://github.com/matrix-org/synapse/issues/11324))
|
||||
- Update the JWT login type to support custom a `sub` claim. ([\#11361](https://github.com/matrix-org/synapse/issues/11361))
|
||||
- Store and allow querying of arbitrary event relations. ([\#11391](https://github.com/matrix-org/synapse/issues/11391))
|
||||
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix a long-standing bug wherein display names or avatar URLs containing null bytes cause an internal server error when stored in the DB. ([\#11230](https://github.com/matrix-org/synapse/issues/11230))
|
||||
- Prevent [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) historical state events from being pushed to an application service via `/transactions`. ([\#11265](https://github.com/matrix-org/synapse/issues/11265))
|
||||
- Fix a long-standing bug where uploading extremely thin images (e.g. 1000x1) would fail. Contributed by @Neeeflix. ([\#11288](https://github.com/matrix-org/synapse/issues/11288))
|
||||
- Fix a bug, introduced in Synapse 1.46.0, which caused the `check_3pid_auth` and `on_logged_out` callbacks in legacy password authentication provider modules to not be registered. Modules using the generic module interface were not affected. ([\#11340](https://github.com/matrix-org/synapse/issues/11340))
|
||||
- Fix a bug introduced in 1.41.0 where space hierarchy responses would be incorrectly reused if multiple users were to make the same request at the same time. ([\#11355](https://github.com/matrix-org/synapse/issues/11355))
|
||||
- Fix a bug introduced in 1.45.0 where the `read_templates` method of the module API would error. ([\#11377](https://github.com/matrix-org/synapse/issues/11377))
|
||||
- Fix an issue introduced in 1.47.0 which prevented servers re-joining rooms they had previously left, if their signing keys were replaced. ([\#11379](https://github.com/matrix-org/synapse/issues/11379))
|
||||
- Fix a bug introduced in 1.13.0 where creating and publishing a room could cause errors if `room_list_publication_rules` is configured. ([\#11392](https://github.com/matrix-org/synapse/issues/11392))
|
||||
- Improve performance of various background database updates. ([\#11421](https://github.com/matrix-org/synapse/issues/11421), [\#11422](https://github.com/matrix-org/synapse/issues/11422))
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Suggest users of the Debian packages add configuration to `/etc/matrix-synapse/conf.d/` to prevent, upon upgrade, being asked to choose between their configuration and the maintainer's. ([\#11281](https://github.com/matrix-org/synapse/issues/11281))
|
||||
- Fix typos in the documentation for the `username_available` admin API. Contributed by Stanislav Motylkov. ([\#11286](https://github.com/matrix-org/synapse/issues/11286))
|
||||
- Add Single Sign-On, SAML and CAS pages to the documentation. ([\#11298](https://github.com/matrix-org/synapse/issues/11298))
|
||||
- Change the word 'Home server' as one word 'homeserver' in documentation. ([\#11320](https://github.com/matrix-org/synapse/issues/11320))
|
||||
- Fix missing quotes for wildcard domains in `federation_certificate_verification_whitelist`. ([\#11381](https://github.com/matrix-org/synapse/issues/11381))
|
||||
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Remove deprecated `trust_identity_server_for_password_resets` configuration flag. ([\#11333](https://github.com/matrix-org/synapse/issues/11333), [\#11395](https://github.com/matrix-org/synapse/issues/11395))
|
||||
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Add type annotations to `synapse.metrics`. ([\#10847](https://github.com/matrix-org/synapse/issues/10847))
|
||||
- Split out federated PDU retrieval function into a non-cached version. ([\#11242](https://github.com/matrix-org/synapse/issues/11242))
|
||||
- Clean up code relating to to-device messages and sending ephemeral events to application services. ([\#11247](https://github.com/matrix-org/synapse/issues/11247))
|
||||
- Fix a small typo in the error response when a relation type other than 'm.annotation' is passed to `GET /rooms/{room_id}/aggregations/{event_id}`. ([\#11278](https://github.com/matrix-org/synapse/issues/11278))
|
||||
- Drop unused database tables `room_stats_historical` and `user_stats_historical`. ([\#11280](https://github.com/matrix-org/synapse/issues/11280))
|
||||
- Require all files in synapse/ and tests/ to pass mypy unless specifically excluded. ([\#11282](https://github.com/matrix-org/synapse/issues/11282), [\#11285](https://github.com/matrix-org/synapse/issues/11285), [\#11359](https://github.com/matrix-org/synapse/issues/11359))
|
||||
- Add missing type hints to `synapse.app`. ([\#11287](https://github.com/matrix-org/synapse/issues/11287))
|
||||
- Remove unused parameters on `FederationEventHandler._check_event_auth`. ([\#11292](https://github.com/matrix-org/synapse/issues/11292))
|
||||
- Add type hints to `synapse._scripts`. ([\#11297](https://github.com/matrix-org/synapse/issues/11297))
|
||||
- Fix an issue which prevented the `remove_deleted_devices_from_device_inbox` background database schema update from running when updating from a recent Synapse version. ([\#11303](https://github.com/matrix-org/synapse/issues/11303))
|
||||
- Add type hints to storage classes. ([\#11307](https://github.com/matrix-org/synapse/issues/11307), [\#11310](https://github.com/matrix-org/synapse/issues/11310), [\#11311](https://github.com/matrix-org/synapse/issues/11311), [\#11312](https://github.com/matrix-org/synapse/issues/11312), [\#11313](https://github.com/matrix-org/synapse/issues/11313), [\#11314](https://github.com/matrix-org/synapse/issues/11314), [\#11316](https://github.com/matrix-org/synapse/issues/11316), [\#11322](https://github.com/matrix-org/synapse/issues/11322), [\#11332](https://github.com/matrix-org/synapse/issues/11332), [\#11339](https://github.com/matrix-org/synapse/issues/11339), [\#11342](https://github.com/matrix-org/synapse/issues/11342))
|
||||
- Add type hints to `synapse.util`. ([\#11321](https://github.com/matrix-org/synapse/issues/11321), [\#11328](https://github.com/matrix-org/synapse/issues/11328))
|
||||
- Improve type annotations in Synapse's test suite. ([\#11323](https://github.com/matrix-org/synapse/issues/11323), [\#11330](https://github.com/matrix-org/synapse/issues/11330))
|
||||
- Test that room alias deletion works as intended. ([\#11327](https://github.com/matrix-org/synapse/issues/11327))
|
||||
- Add type annotations for some methods and properties in the module API. ([\#11341](https://github.com/matrix-org/synapse/issues/11341))
|
||||
- Fix running `scripts-dev/complement.sh`, which was broken in v1.47.0rc1. ([\#11368](https://github.com/matrix-org/synapse/issues/11368))
|
||||
- Rename internal functions for token generation to better reflect what they do. ([\#11369](https://github.com/matrix-org/synapse/issues/11369), [\#11370](https://github.com/matrix-org/synapse/issues/11370))
|
||||
- Add type hints to configuration classes. ([\#11377](https://github.com/matrix-org/synapse/issues/11377))
|
||||
- Publish a `develop` image to Docker Hub. ([\#11380](https://github.com/matrix-org/synapse/issues/11380))
|
||||
- Keep fallback key marked as used if it's re-uploaded. ([\#11382](https://github.com/matrix-org/synapse/issues/11382))
|
||||
- Use `auto_attribs` on the `attrs` class `RefreshTokenLookupResult`. ([\#11386](https://github.com/matrix-org/synapse/issues/11386))
|
||||
- Rename unstable `access_token_lifetime` configuration option to `refreshable_access_token_lifetime` to make it clear it only concerns refreshable access tokens. ([\#11388](https://github.com/matrix-org/synapse/issues/11388))
|
||||
- Do not run the broken MSC2716 tests when running `scripts-dev/complement.sh`. ([\#11389](https://github.com/matrix-org/synapse/issues/11389))
|
||||
- Remove dead code from supporting ACME. ([\#11393](https://github.com/matrix-org/synapse/issues/11393))
|
||||
- Refactor including the bundled relations when serializing an event. ([\#11408](https://github.com/matrix-org/synapse/issues/11408))
|
||||
|
||||
|
||||
Synapse 1.47.1 (2021-11-23)
|
||||
===========================
|
||||
|
||||
This release fixes a security issue in the media store, affecting all prior releases of Synapse. Server administrators are encouraged to update Synapse as soon as possible. We are not aware of these vulnerabilities being exploited in the wild.
|
||||
|
||||
Server administrators who are unable to update Synapse may use the workarounds described in the linked GitHub Security Advisory below.
|
||||
|
||||
Security advisory
|
||||
-----------------
|
||||
|
||||
The following issue is fixed in 1.47.1.
|
||||
|
||||
- **[GHSA-3hfw-x7gx-437c](https://github.com/matrix-org/synapse/security/advisories/GHSA-3hfw-x7gx-437c) / [CVE-2021-41281](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41281): Path traversal when downloading remote media.**
|
||||
|
||||
Synapse instances with the media repository enabled can be tricked into downloading a file from a remote server into an arbitrary directory, potentially outside the media store directory.
|
||||
|
||||
The last two directories and file name of the path are chosen randomly by Synapse and cannot be controlled by an attacker, which limits the impact.
|
||||
|
||||
Homeservers with the media repository disabled are unaffected. Homeservers configured with a federation whitelist are also unaffected.
|
||||
|
||||
Fixed by [91f2bd090](https://github.com/matrix-org/synapse/commit/91f2bd090).
|
||||
|
||||
|
||||
Synapse 1.47.0 (2021-11-17)
|
||||
===========================
|
||||
|
||||
No significant changes since 1.47.0rc3.
|
||||
|
||||
|
||||
Synapse 1.47.0rc3 (2021-11-16)
|
||||
==============================
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix a bug introduced in 1.47.0rc1 which caused worker processes to not halt startup in the presence of outstanding database migrations. ([\#11346](https://github.com/matrix-org/synapse/issues/11346))
|
||||
- Fix a bug introduced in 1.47.0rc1 which prevented the 'remove deleted devices from `device_inbox` column' background process from running when updating from a recent Synapse version. ([\#11303](https://github.com/matrix-org/synapse/issues/11303), [\#11353](https://github.com/matrix-org/synapse/issues/11353))
|
||||
|
||||
|
||||
Synapse 1.47.0rc2 (2021-11-10)
|
||||
==============================
|
||||
|
||||
@@ -8678,14 +9076,14 @@ General:
|
||||
|
||||
Federation:
|
||||
|
||||
- Add key distribution mechanisms for fetching public keys of unavailable remote home servers. See [Retrieving Server Keys](https://github.com/matrix-org/matrix-doc/blob/6f2698/specification/30_server_server_api.rst#retrieving-server-keys) in the spec.
|
||||
- Add key distribution mechanisms for fetching public keys of unavailable remote homeservers. See [Retrieving Server Keys](https://github.com/matrix-org/matrix-doc/blob/6f2698/specification/30_server_server_api.rst#retrieving-server-keys) in the spec.
|
||||
|
||||
Configuration:
|
||||
|
||||
- Add support for multiple config files.
|
||||
- Add support for dictionaries in config files.
|
||||
- Remove support for specifying config options on the command line, except for:
|
||||
- `--daemonize` - Daemonize the home server.
|
||||
- `--daemonize` - Daemonize the homeserver.
|
||||
- `--manhole` - Turn on the twisted telnet manhole service on the given port.
|
||||
- `--database-path` - The path to a sqlite database to use.
|
||||
- `--verbose` - The verbosity level.
|
||||
@@ -8890,7 +9288,7 @@ This version adds support for using a TURN server. See docs/turn-howto.rst on ho
|
||||
Homeserver:
|
||||
|
||||
- Add support for redaction of messages.
|
||||
- Fix bug where inviting a user on a remote home server could take up to 20-30s.
|
||||
- Fix bug where inviting a user on a remote homeserver could take up to 20-30s.
|
||||
- Implement a get current room state API.
|
||||
- Add support specifying and retrieving turn server configuration.
|
||||
|
||||
@@ -8980,7 +9378,7 @@ Changes in synapse 0.2.3 (2014-09-12)
|
||||
|
||||
Homeserver:
|
||||
|
||||
- Fix bug where we stopped sending events to remote home servers if a user from that home server left, even if there were some still in the room.
|
||||
- Fix bug where we stopped sending events to remote homeservers if a user from that homeserver left, even if there were some still in the room.
|
||||
- Fix bugs in the state conflict resolution where it was incorrectly rejecting events.
|
||||
|
||||
Webclient:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Add a new version of delete room admin API `DELETE /_synapse/admin/v2/rooms/<room_id>` to run it in background. Contributed by @dklimpel.
|
||||
@@ -1 +0,0 @@
|
||||
Allow the admin [Delete Room API](https://matrix-org.github.io/synapse/latest/admin_api/rooms.html#delete-room-api) to block a room without the need to join it.
|
||||
@@ -1,2 +0,0 @@
|
||||
Fix a long-standing bug wherein display names or avatar URLs containing null bytes cause an internal server error
|
||||
when stored in the DB.
|
||||
@@ -1 +0,0 @@
|
||||
Support filtering by relation senders & types per [MSC3440](https://github.com/matrix-org/matrix-doc/pull/3440).
|
||||
@@ -1 +0,0 @@
|
||||
Split out federated PDU retrieval function into a non-cached version.
|
||||
@@ -1 +0,0 @@
|
||||
Clean up code relating to to-device messages and sending ephemeral events to application services.
|
||||
@@ -1 +0,0 @@
|
||||
Fix a small typo in the error response when a relation type other than 'm.annotation' is passed to `GET /rooms/{room_id}/aggregations/{event_id}`.
|
||||
@@ -1 +0,0 @@
|
||||
Drop unused db tables `room_stats_historical` and `user_stats_historical`.
|
||||
@@ -1 +0,0 @@
|
||||
Suggest users of the Debian packages add configuration to `/etc/matrix-synapse/conf.d/` to prevent, upon upgrade, being asked to choose between their configuration and the maintainer's.
|
||||
@@ -1 +0,0 @@
|
||||
Require all files in synapse/ and tests/ to pass mypy unless specifically excluded.
|
||||
@@ -1 +0,0 @@
|
||||
Require all files in synapse/ and tests/ to pass mypy unless specifically excluded.
|
||||
@@ -1 +0,0 @@
|
||||
Fix typo in the word `available` and fix HTTP method (should be `GET`) for the `username_available` admin API. Contributed by Stanislav Motylkov.
|
||||
@@ -1 +0,0 @@
|
||||
Add missing type hints to `synapse.app`.
|
||||
@@ -1 +0,0 @@
|
||||
Fix a long-standing bug where uploading extremely thin images (e.g. 1000x1) would fail. Contributed by @Neeeflix.
|
||||
@@ -1 +0,0 @@
|
||||
Remove unused parameters on `FederationEventHandler._check_event_auth`.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to `synapse._scripts`.
|
||||
@@ -1 +0,0 @@
|
||||
Add Single Sign-On, SAML and CAS pages to the documentation.
|
||||
@@ -1 +0,0 @@
|
||||
Fix an issue which prevented the 'remove deleted devices from device_inbox column' background process from running when updating from a recent Synapse version.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to `synapse.util`.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Improve type annotations in Synapse's test suite.
|
||||
@@ -1 +0,0 @@
|
||||
Test that room alias deletion works as intended.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Support the stable version of [MSC2778](https://github.com/matrix-org/matrix-doc/pull/2778): the `m.login.application_service` login type. Contributed by @tulir.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -1 +0,0 @@
|
||||
Add type hints to storage classes.
|
||||
@@ -14,6 +14,7 @@ services:
|
||||
# failure
|
||||
restart: unless-stopped
|
||||
# See the readme for a full documentation of the environment settings
|
||||
# NOTE: You must edit homeserver.yaml to use postgres, it defaults to sqlite
|
||||
environment:
|
||||
- SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
|
||||
volumes:
|
||||
|
||||
78
debian/changelog
vendored
78
debian/changelog
vendored
@@ -1,3 +1,81 @@
|
||||
matrix-synapse-py3 (1.50.1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.50.1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 18 Jan 2022 16:06:26 +0000
|
||||
|
||||
matrix-synapse-py3 (1.50.0) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.50.0.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 18 Jan 2022 10:40:38 +0000
|
||||
|
||||
matrix-synapse-py3 (1.50.0~rc2) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.50.0~rc2.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Fri, 14 Jan 2022 11:18:06 +0000
|
||||
|
||||
matrix-synapse-py3 (1.50.0~rc1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.50.0~rc1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Wed, 05 Jan 2022 12:36:17 +0000
|
||||
|
||||
matrix-synapse-py3 (1.49.2) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.49.2.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 21 Dec 2021 17:31:03 +0000
|
||||
|
||||
matrix-synapse-py3 (1.49.1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.49.1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 21 Dec 2021 11:07:30 +0000
|
||||
|
||||
matrix-synapse-py3 (1.49.0) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.49.0.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 14 Dec 2021 12:39:46 +0000
|
||||
|
||||
matrix-synapse-py3 (1.49.0~rc1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.49.0~rc1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 07 Dec 2021 13:52:21 +0000
|
||||
|
||||
matrix-synapse-py3 (1.48.0) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.48.0.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 30 Nov 2021 11:24:15 +0000
|
||||
|
||||
matrix-synapse-py3 (1.48.0~rc1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.48.0~rc1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Thu, 25 Nov 2021 15:56:03 +0000
|
||||
|
||||
matrix-synapse-py3 (1.47.1) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.47.1.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Fri, 19 Nov 2021 13:44:32 +0000
|
||||
|
||||
matrix-synapse-py3 (1.47.0) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.47.0.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Wed, 17 Nov 2021 13:09:43 +0000
|
||||
|
||||
matrix-synapse-py3 (1.47.0~rc3) stable; urgency=medium
|
||||
|
||||
* New synapse release 1.47.0~rc3.
|
||||
|
||||
-- Synapse Packaging team <packages@matrix.org> Tue, 16 Nov 2021 14:32:47 +0000
|
||||
|
||||
matrix-synapse-py3 (1.47.0~rc2) stable; urgency=medium
|
||||
|
||||
[ Dan Callahan ]
|
||||
|
||||
@@ -16,7 +16,7 @@ ARG distro=""
|
||||
### Stage 0: build a dh-virtualenv
|
||||
###
|
||||
|
||||
# This is only really needed on bionic and focal, since other distributions we
|
||||
# This is only really needed on focal, since other distributions we
|
||||
# care about have a recent version of dh-virtualenv by default. Unfortunately,
|
||||
# it looks like focal is going to be with us for a while.
|
||||
#
|
||||
@@ -36,9 +36,8 @@ RUN env DEBIAN_FRONTEND=noninteractive apt-get install \
|
||||
wget
|
||||
|
||||
# fetch and unpack the package
|
||||
# TODO: Upgrade to 1.2.2 once bionic is dropped (1.2.2 requires debhelper 12; bionic has only 11)
|
||||
RUN mkdir /dh-virtualenv
|
||||
RUN wget -q -O /dh-virtualenv.tar.gz https://github.com/spotify/dh-virtualenv/archive/ac6e1b1.tar.gz
|
||||
RUN wget -q -O /dh-virtualenv.tar.gz https://github.com/spotify/dh-virtualenv/archive/refs/tags/1.2.2.tar.gz
|
||||
RUN tar -xv --strip-components=1 -C /dh-virtualenv -f /dh-virtualenv.tar.gz
|
||||
|
||||
# install its build deps. We do another apt-cache-update here, because we might
|
||||
@@ -86,12 +85,12 @@ RUN apt-get update -qq -o Acquire::Languages=none \
|
||||
libpq-dev \
|
||||
xmlsec1
|
||||
|
||||
COPY --from=builder /dh-virtualenv_1.2~dev-1_all.deb /
|
||||
COPY --from=builder /dh-virtualenv_1.2.2-1_all.deb /
|
||||
|
||||
# install dhvirtualenv. Update the apt cache again first, in case we got a
|
||||
# cached cache from docker the first time.
|
||||
RUN apt-get update -qq -o Acquire::Languages=none \
|
||||
&& apt-get install -yq /dh-virtualenv_1.2~dev-1_all.deb
|
||||
&& apt-get install -yq /dh-virtualenv_1.2.2-1_all.deb
|
||||
|
||||
WORKDIR /synapse/source
|
||||
ENTRYPOINT ["bash","/synapse/source/docker/build_debian.sh"]
|
||||
|
||||
@@ -21,3 +21,6 @@ VOLUME ["/data"]
|
||||
# files to run the desired worker configuration. Will start supervisord.
|
||||
COPY ./docker/configure_workers_and_start.py /configure_workers_and_start.py
|
||||
ENTRYPOINT ["/configure_workers_and_start.py"]
|
||||
|
||||
HEALTHCHECK --start-period=5s --interval=15s --timeout=5s \
|
||||
CMD /bin/sh /healthcheck.sh
|
||||
|
||||
@@ -68,6 +68,10 @@ The following environment variables are supported in `generate` mode:
|
||||
directories. If unset, and no user is set via `docker run --user`, defaults
|
||||
to `991`, `991`.
|
||||
|
||||
## Postgres
|
||||
|
||||
By default the config will use SQLite. See the [docs on using Postgres](https://github.com/matrix-org/synapse/blob/develop/docs/postgres.md) for more info on how to use Postgres. Until this section is improved [this issue](https://github.com/matrix-org/synapse/issues/8304) may provide useful information.
|
||||
|
||||
## Running synapse
|
||||
|
||||
Once you have a valid configuration file, you can start synapse as follows:
|
||||
|
||||
6
docker/conf-workers/healthcheck.sh.j2
Normal file
6
docker/conf-workers/healthcheck.sh.j2
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
# This healthcheck script is designed to return OK when every
|
||||
# host involved returns OK
|
||||
{%- for healthcheck_url in healthcheck_urls %}
|
||||
curl -fSs {{ healthcheck_url }} || exit 1
|
||||
{%- endfor %}
|
||||
@@ -148,14 +148,6 @@ bcrypt_rounds: 12
|
||||
allow_guest_access: {{ "True" if SYNAPSE_ALLOW_GUEST else "False" }}
|
||||
enable_group_creation: true
|
||||
|
||||
# The list of identity servers trusted to verify third party
|
||||
# identifiers by this server.
|
||||
#
|
||||
# Also defines the ID server which will be called when an account is
|
||||
# deactivated (one will be picked arbitrarily).
|
||||
trusted_third_party_id_servers:
|
||||
- matrix.org
|
||||
- vector.im
|
||||
|
||||
## Metrics ###
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ WORKERS_CONFIG = {
|
||||
"app": "synapse.app.user_dir",
|
||||
"listener_resources": ["client"],
|
||||
"endpoint_patterns": [
|
||||
"^/_matrix/client/(api/v1|r0|unstable)/user_directory/search$"
|
||||
"^/_matrix/client/(api/v1|r0|v3|unstable)/user_directory/search$"
|
||||
],
|
||||
"shared_extra_conf": {"update_user_directory": False},
|
||||
"worker_extra_conf": "",
|
||||
@@ -85,10 +85,10 @@ WORKERS_CONFIG = {
|
||||
"app": "synapse.app.generic_worker",
|
||||
"listener_resources": ["client"],
|
||||
"endpoint_patterns": [
|
||||
"^/_matrix/client/(v2_alpha|r0)/sync$",
|
||||
"^/_matrix/client/(api/v1|v2_alpha|r0)/events$",
|
||||
"^/_matrix/client/(api/v1|r0)/initialSync$",
|
||||
"^/_matrix/client/(api/v1|r0)/rooms/[^/]+/initialSync$",
|
||||
"^/_matrix/client/(v2_alpha|r0|v3)/sync$",
|
||||
"^/_matrix/client/(api/v1|v2_alpha|r0|v3)/events$",
|
||||
"^/_matrix/client/(api/v1|r0|v3)/initialSync$",
|
||||
"^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$",
|
||||
],
|
||||
"shared_extra_conf": {},
|
||||
"worker_extra_conf": "",
|
||||
@@ -146,11 +146,11 @@ WORKERS_CONFIG = {
|
||||
"app": "synapse.app.generic_worker",
|
||||
"listener_resources": ["client"],
|
||||
"endpoint_patterns": [
|
||||
"^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/redact",
|
||||
"^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/send",
|
||||
"^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/(join|invite|leave|ban|unban|kick)$",
|
||||
"^/_matrix/client/(api/v1|r0|unstable)/join/",
|
||||
"^/_matrix/client/(api/v1|r0|unstable)/profile/",
|
||||
"^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/redact",
|
||||
"^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/send",
|
||||
"^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/(join|invite|leave|ban|unban|kick)$",
|
||||
"^/_matrix/client/(api/v1|r0|v3|unstable)/join/",
|
||||
"^/_matrix/client/(api/v1|r0|v3|unstable)/profile/",
|
||||
],
|
||||
"shared_extra_conf": {},
|
||||
"worker_extra_conf": "",
|
||||
@@ -158,7 +158,7 @@ WORKERS_CONFIG = {
|
||||
"frontend_proxy": {
|
||||
"app": "synapse.app.frontend_proxy",
|
||||
"listener_resources": ["client", "replication"],
|
||||
"endpoint_patterns": ["^/_matrix/client/(api/v1|r0|unstable)/keys/upload"],
|
||||
"endpoint_patterns": ["^/_matrix/client/(api/v1|r0|v3|unstable)/keys/upload"],
|
||||
"shared_extra_conf": {},
|
||||
"worker_extra_conf": (
|
||||
"worker_main_http_uri: http://127.0.0.1:%d"
|
||||
@@ -474,10 +474,16 @@ def generate_worker_files(environ, config_path: str, data_dir: str):
|
||||
|
||||
# Determine the load-balancing upstreams to configure
|
||||
nginx_upstream_config = ""
|
||||
|
||||
# At the same time, prepare a list of internal endpoints to healthcheck
|
||||
# starting with the main process which exists even if no workers do.
|
||||
healthcheck_urls = ["http://localhost:8080/health"]
|
||||
|
||||
for upstream_worker_type, upstream_worker_ports in nginx_upstreams.items():
|
||||
body = ""
|
||||
for port in upstream_worker_ports:
|
||||
body += " server localhost:%d;\n" % (port,)
|
||||
healthcheck_urls.append("http://localhost:%d/health" % (port,))
|
||||
|
||||
# Add to the list of configured upstreams
|
||||
nginx_upstream_config += NGINX_UPSTREAM_CONFIG_BLOCK.format(
|
||||
@@ -510,6 +516,13 @@ def generate_worker_files(environ, config_path: str, data_dir: str):
|
||||
worker_config=supervisord_config,
|
||||
)
|
||||
|
||||
# healthcheck config
|
||||
convert(
|
||||
"/conf/healthcheck.sh.j2",
|
||||
"/healthcheck.sh",
|
||||
healthcheck_urls=healthcheck_urls,
|
||||
)
|
||||
|
||||
# Ensure the logging directory exists
|
||||
log_dir = data_dir + "/logs"
|
||||
if not os.path.exists(log_dir):
|
||||
|
||||
@@ -50,8 +50,10 @@ build the documentation with:
|
||||
mdbook build
|
||||
```
|
||||
|
||||
The rendered contents will be outputted to a new `book/` directory at the root of the repository. You can
|
||||
browse the book by opening `book/index.html` in a web browser.
|
||||
The rendered contents will be outputted to a new `book/` directory at the root of the repository. Please note that
|
||||
index.html is not built by default, it is created by copying over the file `welcome_and_overview.html` to `index.html`
|
||||
during deployment. Thus, when running `mdbook serve` locally the book will initially show a 404 in place of the index
|
||||
due to the above. Do not be alarmed!
|
||||
|
||||
You can also have mdbook host the docs on a local webserver with hot-reload functionality via:
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
- [SSO Mapping Providers](sso_mapping_providers.md)
|
||||
- [Password Auth Providers](password_auth_providers.md)
|
||||
- [JSON Web Tokens](jwt.md)
|
||||
- [Refresh Tokens](usage/configuration/user_authentication/refresh_tokens.md)
|
||||
- [Registration Captcha](CAPTCHA_SETUP.md)
|
||||
- [Application Services](application_services.md)
|
||||
- [Server Notices](server_notices.md)
|
||||
@@ -44,6 +45,7 @@
|
||||
- [Presence router callbacks](modules/presence_router_callbacks.md)
|
||||
- [Account validity callbacks](modules/account_validity_callbacks.md)
|
||||
- [Password auth provider callbacks](modules/password_auth_provider_callbacks.md)
|
||||
- [Background update controller callbacks](modules/background_update_controller_callbacks.md)
|
||||
- [Porting a legacy module to the new interface](modules/porting_legacy_module.md)
|
||||
- [Workers](workers.md)
|
||||
- [Using `synctl` with Workers](synctl_workers.md)
|
||||
@@ -64,9 +66,15 @@
|
||||
- [Statistics](admin_api/statistics.md)
|
||||
- [Users](admin_api/user_admin_api.md)
|
||||
- [Server Version](admin_api/version_api.md)
|
||||
- [Federation](usage/administration/admin_api/federation.md)
|
||||
- [Manhole](manhole.md)
|
||||
- [Monitoring](metrics-howto.md)
|
||||
- [Understanding Synapse Through Grafana Graphs](usage/administration/understanding_synapse_through_grafana_graphs.md)
|
||||
- [Useful SQL for Admins](usage/administration/useful_sql_for_admins.md)
|
||||
- [Database Maintenance Tools](usage/administration/database_maintenance_tools.md)
|
||||
- [State Groups](usage/administration/state_groups.md)
|
||||
- [Request log format](usage/administration/request_log.md)
|
||||
- [Admin FAQ](usage/administration/admin_faq.md)
|
||||
- [Scripts]()
|
||||
|
||||
# Development
|
||||
@@ -94,3 +102,4 @@
|
||||
|
||||
# Other
|
||||
- [Dependency Deprecation Policy](deprecation_policy.md)
|
||||
- [Running Synapse on a Single-Board Computer](other/running_synapse_on_single_board_computers.md)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
- [Room Details API](#room-details-api)
|
||||
- [Room Members API](#room-members-api)
|
||||
- [Room State API](#room-state-api)
|
||||
- [Block Room API](#block-room-api)
|
||||
- [Delete Room API](#delete-room-api)
|
||||
* [Version 1 (old version)](#version-1-old-version)
|
||||
* [Version 2 (new version)](#version-2-new-version)
|
||||
@@ -386,6 +387,83 @@ A response body like the following is returned:
|
||||
}
|
||||
```
|
||||
|
||||
# Block Room API
|
||||
The Block Room admin API allows server admins to block and unblock rooms,
|
||||
and query to see if a given room is blocked.
|
||||
This API can be used to pre-emptively block a room, even if it's unknown to this
|
||||
homeserver. Users will be prevented from joining a blocked room.
|
||||
|
||||
## Block or unblock a room
|
||||
|
||||
The API is:
|
||||
|
||||
```
|
||||
PUT /_synapse/admin/v1/rooms/<room_id>/block
|
||||
```
|
||||
|
||||
with a body of:
|
||||
|
||||
```json
|
||||
{
|
||||
"block": true
|
||||
}
|
||||
```
|
||||
|
||||
A response body like the following is returned:
|
||||
|
||||
```json
|
||||
{
|
||||
"block": true
|
||||
}
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
The following parameters should be set in the URL:
|
||||
|
||||
- `room_id` - The ID of the room.
|
||||
|
||||
The following JSON body parameters are available:
|
||||
|
||||
- `block` - If `true` the room will be blocked and if `false` the room will be unblocked.
|
||||
|
||||
**Response**
|
||||
|
||||
The following fields are possible in the JSON response body:
|
||||
|
||||
- `block` - A boolean. `true` if the room is blocked, otherwise `false`
|
||||
|
||||
## Get block status
|
||||
|
||||
The API is:
|
||||
|
||||
```
|
||||
GET /_synapse/admin/v1/rooms/<room_id>/block
|
||||
```
|
||||
|
||||
A response body like the following is returned:
|
||||
|
||||
```json
|
||||
{
|
||||
"block": true,
|
||||
"user_id": "<user_id>"
|
||||
}
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
The following parameters should be set in the URL:
|
||||
|
||||
- `room_id` - The ID of the room.
|
||||
|
||||
**Response**
|
||||
|
||||
The following fields are possible in the JSON response body:
|
||||
|
||||
- `block` - A boolean. `true` if the room is blocked, otherwise `false`
|
||||
- `user_id` - An optional string. If the room is blocked (`block` is `true`) shows
|
||||
the user who has add the room to blocking list. Otherwise it is not displayed.
|
||||
|
||||
# Delete Room API
|
||||
|
||||
The Delete Room admin API allows server admins to remove rooms from the server
|
||||
|
||||
@@ -480,6 +480,81 @@ The following fields are returned in the JSON response body:
|
||||
- `joined_rooms` - An array of `room_id`.
|
||||
- `total` - Number of rooms.
|
||||
|
||||
## Account Data
|
||||
Gets information about account data for a specific `user_id`.
|
||||
|
||||
The API is:
|
||||
|
||||
```
|
||||
GET /_synapse/admin/v1/users/<user_id>/accountdata
|
||||
```
|
||||
|
||||
A response body like the following is returned:
|
||||
|
||||
```json
|
||||
{
|
||||
"account_data": {
|
||||
"global": {
|
||||
"m.secret_storage.key.LmIGHTg5W": {
|
||||
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
|
||||
"iv": "fwjNZatxg==",
|
||||
"mac": "eWh9kNnLWZUNOgnc="
|
||||
},
|
||||
"im.vector.hide_profile": {
|
||||
"hide_profile": true
|
||||
},
|
||||
"org.matrix.preview_urls": {
|
||||
"disable": false
|
||||
},
|
||||
"im.vector.riot.breadcrumb_rooms": {
|
||||
"rooms": [
|
||||
"!LxcBDAsDUVAfJDEo:matrix.org",
|
||||
"!MAhRxqasbItjOqxu:matrix.org"
|
||||
]
|
||||
},
|
||||
"m.accepted_terms": {
|
||||
"accepted": [
|
||||
"https://example.org/somewhere/privacy-1.2-en.html",
|
||||
"https://example.org/somewhere/terms-2.0-en.html"
|
||||
]
|
||||
},
|
||||
"im.vector.setting.breadcrumbs": {
|
||||
"recent_rooms": [
|
||||
"!MAhRxqasbItqxuEt:matrix.org",
|
||||
"!ZtSaPCawyWtxiImy:matrix.org"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rooms": {
|
||||
"!GUdfZSHUJibpiVqHYd:matrix.org": {
|
||||
"m.fully_read": {
|
||||
"event_id": "$156334540fYIhZ:matrix.org"
|
||||
}
|
||||
},
|
||||
"!tOZwOOiqwCYQkLhV:matrix.org": {
|
||||
"m.fully_read": {
|
||||
"event_id": "$xjsIyp4_NaVl2yPvIZs_k1Jl8tsC_Sp23wjqXPno"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**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:
|
||||
|
||||
- `account_data` - A map containing the account data for the user
|
||||
- `global` - A map containing the global account data for the user
|
||||
- `rooms` - A map containing the account data per room for the user
|
||||
|
||||
## User media
|
||||
|
||||
### List media uploaded by a user
|
||||
@@ -948,7 +1023,7 @@ The following fields are returned in the JSON response body:
|
||||
See also the
|
||||
[Client-Server API Spec on pushers](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushers).
|
||||
|
||||
## Shadow-banning users
|
||||
## Controlling whether a user is shadow-banned
|
||||
|
||||
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,
|
||||
@@ -961,16 +1036,22 @@ 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:
|
||||
To shadow-ban a user the API is:
|
||||
|
||||
```
|
||||
POST /_synapse/admin/v1/users/<user_id>/shadow_ban
|
||||
```
|
||||
|
||||
To un-shadow-ban a user the API is:
|
||||
|
||||
```
|
||||
DELETE /_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](../usage/administration/admin_api)
|
||||
|
||||
An empty JSON dict is returned.
|
||||
An empty JSON dict is returned in both cases.
|
||||
|
||||
**Parameters**
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
## Server to Server Stack
|
||||
|
||||
To use the server to server stack, home servers should only need to
|
||||
To use the server to server stack, homeservers should only need to
|
||||
interact with the Messaging layer.
|
||||
|
||||
The server to server side of things is designed into 4 distinct layers:
|
||||
@@ -23,7 +23,7 @@ Server with a domain specific API.
|
||||
|
||||
1. **Messaging Layer**
|
||||
|
||||
This is what the rest of the Home Server hits to send messages, join rooms,
|
||||
This is what the rest of the homeserver hits to send messages, join rooms,
|
||||
etc. It also allows you to register callbacks for when it get's notified by
|
||||
lower levels that e.g. a new message has been received.
|
||||
|
||||
@@ -45,7 +45,7 @@ Server with a domain specific API.
|
||||
|
||||
For incoming PDUs, it has to check the PDUs it references to see
|
||||
if we have missed any. If we have go and ask someone (another
|
||||
home server) for it.
|
||||
homeserver) for it.
|
||||
|
||||
3. **Transaction Layer**
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ 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.
|
||||
documented at [https://endoflife.date/python](https://endoflife.date/python) and
|
||||
[https://endoflife.date/postgresql](https://endoflife.date/postgresql).
|
||||
|
||||
|
||||
Context
|
||||
|
||||
@@ -38,16 +38,15 @@ Most-recent-in-time events in the DAG which are not referenced by any other even
|
||||
The forward extremities of a room are used as the `prev_events` when the next event is sent.
|
||||
|
||||
|
||||
## Backwards extremity
|
||||
## Backward extremity
|
||||
|
||||
The current marker of where we have backfilled up to and will generally be the
|
||||
oldest-in-time events we know of in the DAG.
|
||||
`prev_events` of the oldest-in-time events we have in the DAG. This gives a starting point when
|
||||
backfilling history.
|
||||
|
||||
This is an event where we haven't fetched all of the `prev_events` for.
|
||||
|
||||
Once we have fetched all of its `prev_events`, it's unmarked as a backwards
|
||||
extremity (although we may have formed new backwards extremities from the prev
|
||||
events during the backfilling process).
|
||||
When we persist a non-outlier event, we clear it as a backward extremity and set
|
||||
all of its `prev_events` as the new backward extremities if they aren't already
|
||||
persisted in the `events` table.
|
||||
|
||||
|
||||
## Outliers
|
||||
@@ -56,8 +55,7 @@ We mark an event as an `outlier` when we haven't figured out the state for the
|
||||
room at that point in the DAG yet.
|
||||
|
||||
We won't *necessarily* have the `prev_events` of an `outlier` in the database,
|
||||
but it's entirely possible that we *might*. The status of whether we have all of
|
||||
the `prev_events` is marked as a [backwards extremity](#backwards-extremity).
|
||||
but it's entirely possible that we *might*.
|
||||
|
||||
For example, when we fetch the event auth chain or state for a given event, we
|
||||
mark all of those claimed auth events as outliers because we haven't done the
|
||||
|
||||
@@ -22,8 +22,9 @@ will be removed in a future version of Synapse.
|
||||
|
||||
The `token` field should include the JSON web token with the following claims:
|
||||
|
||||
* The `sub` (subject) claim is required and should encode the local part of the
|
||||
user ID.
|
||||
* A claim that encodes the local part of the user ID is required. By default,
|
||||
the `sub` (subject) claim is used, or a custom claim can be set in the
|
||||
configuration file.
|
||||
* The expiration time (`exp`), not before time (`nbf`), and issued at (`iat`)
|
||||
claims are optional, but validated if present.
|
||||
* The issuer (`iss`) claim is optional, but required and validated if configured.
|
||||
|
||||
@@ -2,29 +2,80 @@
|
||||
|
||||
*Synapse implementation-specific details for the media repository*
|
||||
|
||||
The media repository is where attachments and avatar photos are stored.
|
||||
It stores attachment content and thumbnails for media uploaded by local users.
|
||||
It caches attachment content and thumbnails for media uploaded by remote users.
|
||||
The media repository
|
||||
* stores avatars, attachments and their thumbnails for media uploaded by local
|
||||
users.
|
||||
* caches avatars, attachments and their thumbnails for media uploaded by remote
|
||||
users.
|
||||
* caches resources and thumbnails used for
|
||||
[URL previews](development/url_previews.md).
|
||||
|
||||
## Storage
|
||||
All media in Matrix can be identified by a unique
|
||||
[MXC URI](https://spec.matrix.org/latest/client-server-api/#matrix-content-mxc-uris),
|
||||
consisting of a server name and media ID:
|
||||
```
|
||||
mxc://<server-name>/<media-id>
|
||||
```
|
||||
|
||||
Each item of media is assigned a `media_id` when it is uploaded.
|
||||
The `media_id` is a randomly chosen, URL safe 24 character string.
|
||||
## Local Media
|
||||
Synapse generates 24 character media IDs for content uploaded by local users.
|
||||
These media IDs consist of upper and lowercase letters and are case-sensitive.
|
||||
Other homeserver implementations may generate media IDs differently.
|
||||
|
||||
Metadata such as the MIME type, upload time and length are stored in the
|
||||
sqlite3 database indexed by `media_id`.
|
||||
Local media is recorded in the `local_media_repository` table, which includes
|
||||
metadata such as MIME types, upload times and file sizes.
|
||||
Note that this table is shared by the URL cache, which has a different media ID
|
||||
scheme.
|
||||
|
||||
Content is stored on the filesystem under a `"local_content"` directory.
|
||||
### Paths
|
||||
A file with media ID `aabbcccccccccccccccccccc` and its `128x96` `image/jpeg`
|
||||
thumbnail, created by scaling, would be stored at:
|
||||
```
|
||||
local_content/aa/bb/cccccccccccccccccccc
|
||||
local_thumbnails/aa/bb/cccccccccccccccccccc/128-96-image-jpeg-scale
|
||||
```
|
||||
|
||||
Thumbnails are stored under a `"local_thumbnails"` directory.
|
||||
## Remote Media
|
||||
When media from a remote homeserver is requested from Synapse, it is assigned
|
||||
a local `filesystem_id`, with the same format as locally-generated media IDs,
|
||||
as described above.
|
||||
|
||||
The item with `media_id` `"aabbccccccccdddddddddddd"` is stored under
|
||||
`"local_content/aa/bb/ccccccccdddddddddddd"`. Its thumbnail with width
|
||||
`128` and height `96` and type `"image/jpeg"` is stored under
|
||||
`"local_thumbnails/aa/bb/ccccccccdddddddddddd/128-96-image-jpeg"`
|
||||
A record of remote media is stored in the `remote_media_cache` table, which
|
||||
can be used to map remote MXC URIs (server names and media IDs) to local
|
||||
`filesystem_id`s.
|
||||
|
||||
Remote content is cached under `"remote_content"` directory. Each item of
|
||||
remote content is assigned a local `"filesystem_id"` to ensure that the
|
||||
directory structure `"remote_content/server_name/aa/bb/ccccccccdddddddddddd"`
|
||||
is appropriate. Thumbnails for remote content are stored under
|
||||
`"remote_thumbnail/server_name/..."`
|
||||
### Paths
|
||||
A file from `matrix.org` with `filesystem_id` `aabbcccccccccccccccccccc` and its
|
||||
`128x96` `image/jpeg` thumbnail, created by scaling, would be stored at:
|
||||
```
|
||||
remote_content/matrix.org/aa/bb/cccccccccccccccccccc
|
||||
remote_thumbnail/matrix.org/aa/bb/cccccccccccccccccccc/128-96-image-jpeg-scale
|
||||
```
|
||||
Older thumbnails may omit the thumbnailing method:
|
||||
```
|
||||
remote_thumbnail/matrix.org/aa/bb/cccccccccccccccccccc/128-96-image-jpeg
|
||||
```
|
||||
|
||||
Note that `remote_thumbnail/` does not have an `s`.
|
||||
|
||||
## URL Previews
|
||||
See [URL Previews](development/url_previews.md) for documentation on the URL preview
|
||||
process.
|
||||
|
||||
When generating previews for URLs, Synapse may download and cache various
|
||||
resources, including images. These resources are assigned temporary media IDs
|
||||
of the form `yyyy-mm-dd_aaaaaaaaaaaaaaaa`, where `yyyy-mm-dd` is the current
|
||||
date and `aaaaaaaaaaaaaaaa` is a random sequence of 16 case-sensitive letters.
|
||||
|
||||
The metadata for these cached resources is stored in the
|
||||
`local_media_repository` and `local_media_repository_url_cache` tables.
|
||||
|
||||
Resources for URL previews are deleted after a few days.
|
||||
|
||||
### Paths
|
||||
The file with media ID `yyyy-mm-dd_aaaaaaaaaaaaaaaa` and its `128x96`
|
||||
`image/jpeg` thumbnail, created by scaling, would be stored at:
|
||||
```
|
||||
url_cache/yyyy-mm-dd/aaaaaaaaaaaaaaaa
|
||||
url_cache_thumbnails/yyyy-mm-dd/aaaaaaaaaaaaaaaa/128-96-image-jpeg-scale
|
||||
```
|
||||
|
||||
71
docs/modules/background_update_controller_callbacks.md
Normal file
71
docs/modules/background_update_controller_callbacks.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Background update controller callbacks
|
||||
|
||||
Background update controller callbacks allow module developers to control (e.g. rate-limit)
|
||||
how database background updates are run. A database background update is an operation
|
||||
Synapse runs on its database in the background after it starts. It's usually used to run
|
||||
database operations that would take too long if they were run at the same time as schema
|
||||
updates (which are run on startup) and delay Synapse's startup too much: populating a
|
||||
table with a big amount of data, adding an index on a big table, deleting superfluous data,
|
||||
etc.
|
||||
|
||||
Background update controller callbacks can be registered using the module API's
|
||||
`register_background_update_controller_callbacks` method. Only the first module (in order
|
||||
of appearance in Synapse's configuration file) calling this method can register background
|
||||
update controller callbacks, subsequent calls are ignored.
|
||||
|
||||
The available background update controller callbacks are:
|
||||
|
||||
### `on_update`
|
||||
|
||||
_First introduced in Synapse v1.49.0_
|
||||
|
||||
```python
|
||||
def on_update(update_name: str, database_name: str, one_shot: bool) -> AsyncContextManager[int]
|
||||
```
|
||||
|
||||
Called when about to do an iteration of a background update. The module is given the name
|
||||
of the update, the name of the database, and a flag to indicate whether the background
|
||||
update will happen in one go and may take a long time (e.g. creating indices). If this last
|
||||
argument is set to `False`, the update will be run in batches.
|
||||
|
||||
The module must return an async context manager. It will be entered before Synapse runs a
|
||||
background update; this should return the desired duration of the iteration, in
|
||||
milliseconds.
|
||||
|
||||
The context manager will be exited when the iteration completes. Note that the duration
|
||||
returned by the context manager is a target, and an iteration may take substantially longer
|
||||
or shorter. If the `one_shot` flag is set to `True`, the duration returned is ignored.
|
||||
|
||||
__Note__: Unlike most module callbacks in Synapse, this one is _synchronous_. This is
|
||||
because asynchronous operations are expected to be run by the async context manager.
|
||||
|
||||
This callback is required when registering any other background update controller callback.
|
||||
|
||||
### `default_batch_size`
|
||||
|
||||
_First introduced in Synapse v1.49.0_
|
||||
|
||||
```python
|
||||
async def default_batch_size(update_name: str, database_name: str) -> int
|
||||
```
|
||||
|
||||
Called before the first iteration of a background update, with the name of the update and
|
||||
of the database. The module must return the number of elements to process in this first
|
||||
iteration.
|
||||
|
||||
If this callback is not defined, Synapse will use a default value of 100.
|
||||
|
||||
### `min_batch_size`
|
||||
|
||||
_First introduced in Synapse v1.49.0_
|
||||
|
||||
```python
|
||||
async def min_batch_size(update_name: str, database_name: str) -> int
|
||||
```
|
||||
|
||||
Called before running a new batch for a background update, with the name of the update and
|
||||
of the database. The module must return an integer representing the minimum number of
|
||||
elements to process in this iteration. This number must be at least 1, and is used to
|
||||
ensure that progress is always made.
|
||||
|
||||
If this callback is not defined, Synapse will use a default value of 100.
|
||||
@@ -71,15 +71,15 @@ Modules **must** register their web resources in their `__init__` method.
|
||||
## Registering a callback
|
||||
|
||||
Modules can use Synapse's module API to register callbacks. Callbacks are functions that
|
||||
Synapse will call when performing specific actions. Callbacks must be asynchronous, and
|
||||
are split in categories. A single module may implement callbacks from multiple categories,
|
||||
and is under no obligation to implement all callbacks from the categories it registers
|
||||
callbacks for.
|
||||
Synapse will call when performing specific actions. Callbacks must be asynchronous (unless
|
||||
specified otherwise), and are split in categories. A single module may implement callbacks
|
||||
from multiple categories, and is under no obligation to implement all callbacks from the
|
||||
categories it registers callbacks for.
|
||||
|
||||
Modules can register callbacks using one of the module API's `register_[...]_callbacks`
|
||||
methods. The callback functions are passed to these methods as keyword arguments, with
|
||||
the callback name as the argument name and the function as its value. This is demonstrated
|
||||
in the example below. A `register_[...]_callbacks` method exists for each category.
|
||||
the callback name as the argument name and the function as its value. A
|
||||
`register_[...]_callbacks` method exists for each category.
|
||||
|
||||
Callbacks for each category can be found on their respective page of the
|
||||
[Synapse documentation website](https://matrix-org.github.io/synapse).
|
||||
@@ -83,7 +83,7 @@ oidc_providers:
|
||||
|
||||
### Dex
|
||||
|
||||
[Dex][dex-idp] is a simple, open-source, certified OpenID Connect Provider.
|
||||
[Dex][dex-idp] is a simple, open-source OpenID Connect Provider.
|
||||
Although it is designed to help building a full-blown provider with an
|
||||
external database, it can be configured with static passwords in a config file.
|
||||
|
||||
@@ -523,7 +523,7 @@ The synapse config will look like this:
|
||||
email_template: "{{ user.email }}"
|
||||
```
|
||||
|
||||
## Django OAuth Toolkit
|
||||
### Django OAuth Toolkit
|
||||
|
||||
[django-oauth-toolkit](https://github.com/jazzband/django-oauth-toolkit) is a
|
||||
Django application providing out of the box all the endpoints, data and logic
|
||||
|
||||
74
docs/other/running_synapse_on_single_board_computers.md
Normal file
74
docs/other/running_synapse_on_single_board_computers.md
Normal file
@@ -0,0 +1,74 @@
|
||||
## Summary of performance impact of running on resource constrained devices such as SBCs
|
||||
|
||||
I've been running my homeserver on a cubietruck at home now for some time and am often replying to statements like "you need loads of ram to join large rooms" with "it works fine for me". I thought it might be useful to curate a summary of the issues you're likely to run into to help as a scaling-down guide, maybe highlight these for development work or end up as documentation. It seems that once you get up to about 4x1.5GHz arm64 4GiB these issues are no longer a problem.
|
||||
|
||||
- **Platform**: 2x1GHz armhf 2GiB ram [Single-board computers](https://wiki.debian.org/CheapServerBoxHardware), SSD, postgres.
|
||||
|
||||
### Presence
|
||||
|
||||
This is the main reason people have a poor matrix experience on resource constrained homeservers. Element web will frequently be saying the server is offline while the python process will be pegged at 100% cpu. This feature is used to tell when other users are active (have a client app in the foreground) and therefore more likely to respond, but requires a lot of network activity to maintain even when nobody is talking in a room.
|
||||
|
||||

|
||||
|
||||
While synapse does have some performance issues with presence [#3971](https://github.com/matrix-org/synapse/issues/3971), the fundamental problem is that this is an easy feature to implement for a centralised service at nearly no overhead, but federation makes it combinatorial [#8055](https://github.com/matrix-org/synapse/issues/8055). There is also a client-side config option which disables the UI and idle tracking [enable_presence_by_hs_url] to blacklist the largest instances but I didn't notice much difference, so I recommend disabling the feature entirely at the server level as well.
|
||||
|
||||
[enable_presence_by_hs_url]: https://github.com/vector-im/element-web/blob/v1.7.8/config.sample.json#L45
|
||||
|
||||
### Joining
|
||||
|
||||
Joining a "large", federated room will initially fail with the below message in Element web, but waiting a while (10-60mins) and trying again will succeed without any issue. What counts as "large" is not message history, user count, connections to homeservers or even a simple count of the state events, it is instead how long the state resolution algorithm takes. However, each of those numbers are reasonable proxies, so we can use them as estimates since user count is one of the few things you see before joining.
|
||||
|
||||

|
||||
|
||||
This is [#1211](https://github.com/matrix-org/synapse/issues/1211) and will also hopefully be mitigated by peeking [matrix-org/matrix-doc#2753](https://github.com/matrix-org/matrix-doc/pull/2753) so at least you don't need to wait for a join to complete before finding out if it's the kind of room you want. Note that you should first disable presence, otherwise it'll just make the situation worse [#3120](https://github.com/matrix-org/synapse/issues/3120). There is a lot of database interaction too, so make sure you've [migrated your data](../postgres.md) from the default sqlite to postgresql. Personally, I recommend patience - once the initial join is complete there's rarely any issues with actually interacting with the room, but if you like you can just block "large" rooms entirely.
|
||||
|
||||
### Sessions
|
||||
|
||||
Anything that requires modifying the device list [#7721](https://github.com/matrix-org/synapse/issues/7721) will take a while to propagate, again taking the client "Offline" until it's complete. This includes signing in and out, editing the public name and verifying e2ee. The main mitigation I recommend is to keep long-running sessions open e.g. by using Firefox SSB "Use this site in App mode" or Chromium PWA "Install Element".
|
||||
|
||||
### Recommended configuration
|
||||
|
||||
Put the below in a new file at /etc/matrix-synapse/conf.d/sbc.yaml to override the defaults in homeserver.yaml.
|
||||
|
||||
```
|
||||
# Set to false to disable presence tracking on this homeserver.
|
||||
use_presence: false
|
||||
|
||||
# When this is enabled, the room "complexity" will be checked before a user
|
||||
# joins a new remote room. If it is above the complexity limit, the server will
|
||||
# disallow joining, or will instantly leave.
|
||||
limit_remote_rooms:
|
||||
# Uncomment to enable room complexity checking.
|
||||
#enabled: true
|
||||
complexity: 3.0
|
||||
|
||||
# Database configuration
|
||||
database:
|
||||
name: psycopg2
|
||||
args:
|
||||
user: matrix-synapse
|
||||
# Generate a long, secure one with a password manager
|
||||
password: hunter2
|
||||
database: matrix-synapse
|
||||
host: localhost
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
```
|
||||
|
||||
Currently the complexity is measured by [current_state_events / 500](https://github.com/matrix-org/synapse/blob/v1.20.1/synapse/storage/databases/main/events_worker.py#L986). You can find join times and your most complex rooms like this:
|
||||
|
||||
```
|
||||
admin@homeserver:~$ zgrep '/client/r0/join/' /var/log/matrix-synapse/homeserver.log* | awk '{print $18, $25}' | sort --human-numeric-sort
|
||||
29.922sec/-0.002sec /_matrix/client/r0/join/%23debian-fasttrack%3Apoddery.com
|
||||
182.088sec/0.003sec /_matrix/client/r0/join/%23decentralizedweb-general%3Amatrix.org
|
||||
911.625sec/-570.847sec /_matrix/client/r0/join/%23synapse%3Amatrix.org
|
||||
|
||||
admin@homeserver:~$ sudo --user postgres psql matrix-synapse --command 'select canonical_alias, joined_members, current_state_events from room_stats_state natural join room_stats_current where canonical_alias is not null order by current_state_events desc fetch first 5 rows only'
|
||||
canonical_alias | joined_members | current_state_events
|
||||
-------------------------------+----------------+----------------------
|
||||
#_oftc_#debian:matrix.org | 871 | 52355
|
||||
#matrix:matrix.org | 6379 | 10684
|
||||
#irc:matrix.org | 461 | 3751
|
||||
#decentralizedweb-general:matrix.org | 997 | 1509
|
||||
#whatsapp:maunium.net | 554 | 854
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
<h2 style="color:red">
|
||||
This page of the Synapse documentation is now deprecated. For up to date
|
||||
documentation on setting up or writing a password auth provider module, please see
|
||||
<a href="modules.md">this page</a>.
|
||||
<a href="modules/index.md">this page</a>.
|
||||
</h2>
|
||||
|
||||
# Password auth provider modules
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Using Postgres
|
||||
|
||||
Synapse supports PostgreSQL versions 9.6 or later.
|
||||
Synapse supports PostgreSQL versions 10 or later.
|
||||
|
||||
## Install postgres client libraries
|
||||
|
||||
@@ -118,6 +118,9 @@ performance:
|
||||
Note that the appropriate values for those fields depend on the amount
|
||||
of free memory the database host has available.
|
||||
|
||||
Additionally, admins of large deployments might want to consider using huge pages
|
||||
to help manage memory, especially when using large values of `shared_buffers`. You
|
||||
can read more about that [here](https://www.postgresql.org/docs/10/kernel-resources.html#LINUX-HUGE-PAGES).
|
||||
|
||||
## Porting from SQLite
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ server {
|
||||
|
||||
server_name matrix.example.com;
|
||||
|
||||
location ~* ^(\/_matrix|\/_synapse\/client) {
|
||||
location ~ ^(/_matrix|/_synapse/client) {
|
||||
# note: do not add a path (even a single /) after the port in `proxy_pass`,
|
||||
# otherwise nginx will canonicalise the URI and cause signature verification
|
||||
# errors.
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
# Server admins can expand Synapse's functionality with external modules.
|
||||
#
|
||||
# See https://matrix-org.github.io/synapse/latest/modules.html for more
|
||||
# See https://matrix-org.github.io/synapse/latest/modules/index.html for more
|
||||
# documentation on how to configure or create custom modules for Synapse.
|
||||
#
|
||||
modules:
|
||||
@@ -647,8 +647,8 @@ retention:
|
||||
#
|
||||
#federation_certificate_verification_whitelist:
|
||||
# - lon.example.com
|
||||
# - *.domain.com
|
||||
# - *.onion
|
||||
# - "*.domain.com"
|
||||
# - "*.onion"
|
||||
|
||||
# List of custom certificate authorities for federation traffic.
|
||||
#
|
||||
@@ -1209,6 +1209,44 @@ oembed:
|
||||
#
|
||||
#session_lifetime: 24h
|
||||
|
||||
# Time that an access token remains valid for, if the session is
|
||||
# using refresh tokens.
|
||||
# For more information about refresh tokens, please see the manual.
|
||||
# Note that this only applies to clients which advertise support for
|
||||
# refresh tokens.
|
||||
#
|
||||
# Note also that this is calculated at login time and refresh time:
|
||||
# changes are not applied to existing sessions until they are refreshed.
|
||||
#
|
||||
# By default, this is 5 minutes.
|
||||
#
|
||||
#refreshable_access_token_lifetime: 5m
|
||||
|
||||
# Time that a refresh token remains valid for (provided that it is not
|
||||
# exchanged for another one first).
|
||||
# This option can be used to automatically log-out inactive sessions.
|
||||
# Please see the manual for more information.
|
||||
#
|
||||
# Note also that this is calculated at login time and refresh time:
|
||||
# changes are not applied to existing sessions until they are refreshed.
|
||||
#
|
||||
# By default, this is infinite.
|
||||
#
|
||||
#refresh_token_lifetime: 24h
|
||||
|
||||
# Time that an access token remains valid for, if the session is NOT
|
||||
# using refresh tokens.
|
||||
# Please note that not all clients support refresh tokens, so setting
|
||||
# this to a short value may be inconvenient for some users who will
|
||||
# then be logged out frequently.
|
||||
#
|
||||
# Note also that this is calculated at login time: changes are not applied
|
||||
# retrospectively to existing sessions for users that have already logged in.
|
||||
#
|
||||
# By default, this is infinite.
|
||||
#
|
||||
#nonrefreshable_access_token_lifetime: 24h
|
||||
|
||||
# The user must provide all of the below types of 3PID when registering.
|
||||
#
|
||||
#registrations_require_3pid:
|
||||
@@ -1450,6 +1488,7 @@ room_prejoin_state:
|
||||
# - m.room.encryption
|
||||
# - m.room.name
|
||||
# - m.room.create
|
||||
# - m.room.topic
|
||||
#
|
||||
# Uncomment the following to disable these defaults (so that only the event
|
||||
# types listed in 'additional_event_types' are shared). Defaults to 'false'.
|
||||
@@ -2039,6 +2078,12 @@ sso:
|
||||
#
|
||||
#algorithm: "provided-by-your-issuer"
|
||||
|
||||
# Name of the claim containing a unique identifier for the user.
|
||||
#
|
||||
# Optional, defaults to `sub`.
|
||||
#
|
||||
#subject_claim: "sub"
|
||||
|
||||
# The issuer to validate the "iss" claim against.
|
||||
#
|
||||
# Optional, if provided the "iss" claim will be required and
|
||||
@@ -2360,8 +2405,8 @@ user_directory:
|
||||
# indexes were (re)built was before Synapse 1.44, you'll have to
|
||||
# rebuild the indexes in order to search through all known users.
|
||||
# These indexes are built the first time Synapse starts; admins can
|
||||
# manually trigger a rebuild following the instructions at
|
||||
# https://matrix-org.github.io/synapse/latest/user_directory.html
|
||||
# manually trigger a rebuild via API following the instructions at
|
||||
# https://matrix-org.github.io/synapse/latest/usage/administration/admin_api/background_updates.html#run
|
||||
#
|
||||
# Uncomment to return search results containing all known users, even if that
|
||||
# user does not share a room with the requester.
|
||||
|
||||
@@ -164,7 +164,7 @@ xbps-install -S synapse
|
||||
Synapse can be installed via FreeBSD Ports or Packages contributed by Brendan Molloy from:
|
||||
|
||||
- Ports: `cd /usr/ports/net-im/py-matrix-synapse && make install clean`
|
||||
- Packages: `pkg install py37-matrix-synapse`
|
||||
- Packages: `pkg install py38-matrix-synapse`
|
||||
|
||||
#### OpenBSD
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ comment these options out and use those specified by the module instead.
|
||||
|
||||
A custom mapping provider must specify the following methods:
|
||||
|
||||
* `__init__(self, parsed_config)`
|
||||
* `def __init__(self, parsed_config)`
|
||||
- Arguments:
|
||||
- `parsed_config` - A configuration object that is the return value of the
|
||||
`parse_config` method. You should set any configuration options needed by
|
||||
the module here.
|
||||
* `parse_config(config)`
|
||||
* `def parse_config(config)`
|
||||
- This method should have the `@staticmethod` decoration.
|
||||
- Arguments:
|
||||
- `config` - A `dict` representing the parsed content of the
|
||||
@@ -63,13 +63,13 @@ A custom mapping provider must specify the following methods:
|
||||
any option values they need here.
|
||||
- Whatever is returned will be passed back to the user mapping provider module's
|
||||
`__init__` method during construction.
|
||||
* `get_remote_user_id(self, userinfo)`
|
||||
* `def get_remote_user_id(self, userinfo)`
|
||||
- Arguments:
|
||||
- `userinfo` - A `authlib.oidc.core.claims.UserInfo` object to extract user
|
||||
information from.
|
||||
- This method must return a string, which is the unique, immutable identifier
|
||||
for the user. Commonly the `sub` claim of the response.
|
||||
* `map_user_attributes(self, userinfo, token, failures)`
|
||||
* `async def map_user_attributes(self, userinfo, token, failures)`
|
||||
- This method must be async.
|
||||
- Arguments:
|
||||
- `userinfo` - A `authlib.oidc.core.claims.UserInfo` object to extract user
|
||||
@@ -91,7 +91,7 @@ A custom mapping provider must specify the following methods:
|
||||
during a user's first login. Once a localpart has been associated with a
|
||||
remote user ID (see `get_remote_user_id`) it cannot be updated.
|
||||
- `displayname`: An optional string, the display name for the user.
|
||||
* `get_extra_attributes(self, userinfo, token)`
|
||||
* `async def get_extra_attributes(self, userinfo, token)`
|
||||
- This method must be async.
|
||||
- Arguments:
|
||||
- `userinfo` - A `authlib.oidc.core.claims.UserInfo` object to extract user
|
||||
@@ -125,15 +125,15 @@ comment these options out and use those specified by the module instead.
|
||||
|
||||
A custom mapping provider must specify the following methods:
|
||||
|
||||
* `__init__(self, parsed_config, module_api)`
|
||||
* `def __init__(self, parsed_config, module_api)`
|
||||
- Arguments:
|
||||
- `parsed_config` - A configuration object that is the return value of the
|
||||
`parse_config` method. You should set any configuration options needed by
|
||||
the module here.
|
||||
- `module_api` - a `synapse.module_api.ModuleApi` object which provides the
|
||||
stable API available for extension modules.
|
||||
* `parse_config(config)`
|
||||
- This method should have the `@staticmethod` decoration.
|
||||
* `def parse_config(config)`
|
||||
- **This method should have the `@staticmethod` decoration.**
|
||||
- Arguments:
|
||||
- `config` - A `dict` representing the parsed content of the
|
||||
`saml_config.user_mapping_provider.config` homeserver config option.
|
||||
@@ -141,15 +141,15 @@ A custom mapping provider must specify the following methods:
|
||||
any option values they need here.
|
||||
- Whatever is returned will be passed back to the user mapping provider module's
|
||||
`__init__` method during construction.
|
||||
* `get_saml_attributes(config)`
|
||||
- This method should have the `@staticmethod` decoration.
|
||||
* `def get_saml_attributes(config)`
|
||||
- **This method should have the `@staticmethod` decoration.**
|
||||
- Arguments:
|
||||
- `config` - A object resulting from a call to `parse_config`.
|
||||
- Returns a tuple of two sets. The first set equates to the SAML auth
|
||||
response attributes that are required for the module to function, whereas
|
||||
the second set consists of those attributes which can be used if available,
|
||||
but are not necessary.
|
||||
* `get_remote_user_id(self, saml_response, client_redirect_url)`
|
||||
* `def get_remote_user_id(self, saml_response, client_redirect_url)`
|
||||
- Arguments:
|
||||
- `saml_response` - A `saml2.response.AuthnResponse` object to extract user
|
||||
information from.
|
||||
@@ -157,7 +157,7 @@ A custom mapping provider must specify the following methods:
|
||||
redirected to.
|
||||
- This method must return a string, which is the unique, immutable identifier
|
||||
for the user. Commonly the `uid` claim of the response.
|
||||
* `saml_response_to_user_attributes(self, saml_response, failures, client_redirect_url)`
|
||||
* `def saml_response_to_user_attributes(self, saml_response, failures, client_redirect_url)`
|
||||
- Arguments:
|
||||
- `saml_response` - A `saml2.response.AuthnResponse` object to extract user
|
||||
information from.
|
||||
|
||||
@@ -71,7 +71,12 @@ Below are the templates Synapse will look for when generating the content of an
|
||||
* `sender_avatar_url`: the avatar URL (as a `mxc://` URL) for the event's
|
||||
sender
|
||||
* `sender_hash`: a hash of the user ID of the sender
|
||||
* `msgtype`: the type of the message
|
||||
* `body_text_html`: html representation of the message
|
||||
* `body_text_plain`: plaintext representation of the message
|
||||
* `image_url`: mxc url of an image, when "msgtype" is "m.image"
|
||||
* `link`: a `matrix.to` link to the room
|
||||
* `avator_url`: url to the room's avator
|
||||
* `reason`: information on the event that triggered the email to be sent. It's an
|
||||
object with the following attributes:
|
||||
* `room_id`: the ID of the room the event was sent in
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Overview
|
||||
|
||||
This document explains how to enable VoIP relaying on your Home Server with
|
||||
This document explains how to enable VoIP relaying on your homeserver with
|
||||
TURN.
|
||||
|
||||
The synapse Matrix Home Server supports integration with TURN server via the
|
||||
The synapse Matrix homeserver supports integration with TURN server via the
|
||||
[TURN server REST API](<https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00>). This
|
||||
allows the Home Server to generate credentials that are valid for use on the
|
||||
TURN server through the use of a secret shared between the Home Server and the
|
||||
allows the homeserver to generate credentials that are valid for use on the
|
||||
TURN server through the use of a secret shared between the homeserver and the
|
||||
TURN server.
|
||||
|
||||
The following sections describe how to install [coturn](<https://github.com/coturn/coturn>) (which implements the TURN REST API) and integrate it with synapse.
|
||||
@@ -15,8 +15,8 @@ The following sections describe how to install [coturn](<https://github.com/cotu
|
||||
|
||||
For TURN relaying with `coturn` to work, it must be hosted on a server/endpoint with a public IP.
|
||||
|
||||
Hosting TURN behind a NAT (even with appropriate port forwarding) is known to cause issues
|
||||
and to often not work.
|
||||
Hosting TURN behind NAT requires port forwaring and for the NAT gateway to have a public IP.
|
||||
However, even with appropriate configuration, NAT is known to cause issues and to often not work.
|
||||
|
||||
## `coturn` setup
|
||||
|
||||
@@ -103,7 +103,23 @@ This will install and start a systemd service called `coturn`.
|
||||
denied-peer-ip=192.168.0.0-192.168.255.255
|
||||
denied-peer-ip=172.16.0.0-172.31.255.255
|
||||
|
||||
# recommended additional local peers to block, to mitigate external access to internal services.
|
||||
# https://www.rtcsec.com/article/slack-webrtc-turn-compromise-and-bug-bounty/#how-to-fix-an-open-turn-relay-to-address-this-vulnerability
|
||||
no-multicast-peers
|
||||
denied-peer-ip=0.0.0.0-0.255.255.255
|
||||
denied-peer-ip=100.64.0.0-100.127.255.255
|
||||
denied-peer-ip=127.0.0.0-127.255.255.255
|
||||
denied-peer-ip=169.254.0.0-169.254.255.255
|
||||
denied-peer-ip=192.0.0.0-192.0.0.255
|
||||
denied-peer-ip=192.0.2.0-192.0.2.255
|
||||
denied-peer-ip=192.88.99.0-192.88.99.255
|
||||
denied-peer-ip=198.18.0.0-198.19.255.255
|
||||
denied-peer-ip=198.51.100.0-198.51.100.255
|
||||
denied-peer-ip=203.0.113.0-203.0.113.255
|
||||
denied-peer-ip=240.0.0.0-255.255.255.255
|
||||
|
||||
# special case the turn server itself so that client->TURN->TURN->client flows work
|
||||
# this should be one of the turn server's listening IPs
|
||||
allowed-peer-ip=10.0.0.1
|
||||
|
||||
# consider whether you want to limit the quota of relayed streams per user (or total) to avoid risk of DoS.
|
||||
@@ -123,7 +139,7 @@ This will install and start a systemd service called `coturn`.
|
||||
pkey=/path/to/privkey.pem
|
||||
```
|
||||
|
||||
In this case, replace the `turn:` schemes in the `turn_uri` settings below
|
||||
In this case, replace the `turn:` schemes in the `turn_uris` settings below
|
||||
with `turns:`.
|
||||
|
||||
We recommend that you only try to set up TLS/DTLS once you have set up a
|
||||
@@ -134,21 +150,33 @@ This will install and start a systemd service called `coturn`.
|
||||
traffic (remember to allow both TCP and UDP traffic), and ports 49152-65535
|
||||
for the UDP relay.)
|
||||
|
||||
1. We do not recommend running a TURN server behind NAT, and are not aware of
|
||||
anyone doing so successfully.
|
||||
|
||||
If you want to try it anyway, you will at least need to tell coturn its
|
||||
external IP address:
|
||||
1. If your TURN server is behind NAT, the NAT gateway must have an external,
|
||||
publicly-reachable IP address. You must configure coturn to advertise that
|
||||
address to connecting clients:
|
||||
|
||||
```
|
||||
external-ip=192.88.99.1
|
||||
external-ip=EXTERNAL_NAT_IPv4_ADDRESS
|
||||
```
|
||||
|
||||
... and your NAT gateway must forward all of the relayed ports directly
|
||||
(eg, port 56789 on the external IP must be always be forwarded to port
|
||||
56789 on the internal IP).
|
||||
You may optionally limit the TURN server to listen only on the local
|
||||
address that is mapped by NAT to the external address:
|
||||
|
||||
If you get this working, let us know!
|
||||
```
|
||||
listening-ip=INTERNAL_TURNSERVER_IPv4_ADDRESS
|
||||
```
|
||||
|
||||
If your NAT gateway is reachable over both IPv4 and IPv6, you may
|
||||
configure coturn to advertise each available address:
|
||||
|
||||
```
|
||||
external-ip=EXTERNAL_NAT_IPv4_ADDRESS
|
||||
external-ip=EXTERNAL_NAT_IPv6_ADDRESS
|
||||
```
|
||||
|
||||
When advertising an external IPv6 address, ensure that the firewall and
|
||||
network settings of the system running your TURN server are configured to
|
||||
accept IPv6 traffic, and that the TURN server is listening on the local
|
||||
IPv6 address that is mapped by NAT to the external IPv6 address.
|
||||
|
||||
1. (Re)start the turn server:
|
||||
|
||||
@@ -165,18 +193,18 @@ This will install and start a systemd service called `coturn`.
|
||||
|
||||
## Synapse setup
|
||||
|
||||
Your home server configuration file needs the following extra keys:
|
||||
Your homeserver configuration file needs the following extra keys:
|
||||
|
||||
1. "`turn_uris`": This needs to be a yaml list of public-facing URIs
|
||||
for your TURN server to be given out to your clients. Add separate
|
||||
entries for each transport your TURN server supports.
|
||||
2. "`turn_shared_secret`": This is the secret shared between your
|
||||
Home server and your TURN server, so you should set it to the same
|
||||
homeserver and your TURN server, so you should set it to the same
|
||||
string you used in turnserver.conf.
|
||||
3. "`turn_user_lifetime`": This is the amount of time credentials
|
||||
generated by your Home Server are valid for (in milliseconds).
|
||||
generated by your homeserver are valid for (in milliseconds).
|
||||
Shorter times offer less potential for abuse at the expense of
|
||||
increased traffic between web clients and your home server to
|
||||
increased traffic between web clients and your homeserver to
|
||||
refresh credentials. The TURN REST API specification recommends
|
||||
one day (86400000).
|
||||
4. "`turn_allow_guests`": Whether to allow guest users to use the
|
||||
@@ -216,11 +244,8 @@ connecting". Unfortunately, troubleshooting this can be tricky.
|
||||
|
||||
Here are a few things to try:
|
||||
|
||||
* Check that your TURN server is not behind NAT. As above, we're not aware of
|
||||
anyone who has successfully set this up.
|
||||
|
||||
* Check that you have opened your firewall to allow TCP and UDP traffic to the
|
||||
TURN ports (normally 3478 and 5479).
|
||||
TURN ports (normally 3478 and 5349).
|
||||
|
||||
* Check that you have opened your firewall to allow UDP traffic to the UDP
|
||||
relay ports (49152-65535 by default).
|
||||
@@ -234,6 +259,18 @@ Here are a few things to try:
|
||||
Try removing any AAAA records for your TURN server, so that it is only
|
||||
reachable over IPv4.
|
||||
|
||||
* If your TURN server is behind NAT:
|
||||
|
||||
* double-check that your NAT gateway is correctly forwarding all TURN
|
||||
ports (normally 3478 & 5349 for TCP & UDP TURN traffic, and 49152-65535 for the UDP
|
||||
relay) to the NAT-internal address of your TURN server. If advertising
|
||||
both IPv4 and IPv6 external addresses via the `external-ip` option, ensure
|
||||
that the NAT is forwarding both IPv4 and IPv6 traffic to the IPv4 and IPv6
|
||||
internal addresses of your TURN server. When in doubt, remove AAAA records
|
||||
for your TURN server and specify only an IPv4 address as your `external-ip`.
|
||||
|
||||
* ensure that your TURN server uses the NAT gateway as its default route.
|
||||
|
||||
* Enable more verbose logging in coturn via the `verbose` setting:
|
||||
|
||||
```
|
||||
|
||||
@@ -85,6 +85,17 @@ process, for example:
|
||||
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb
|
||||
```
|
||||
|
||||
# Upgrading to v1.50.0
|
||||
|
||||
## Dropping support for old Python and Postgres versions
|
||||
|
||||
In line with our [deprecation policy](deprecation_policy.md),
|
||||
we've dropped support for Python 3.6 and PostgreSQL 9.6, as they are no
|
||||
longer supported upstream.
|
||||
|
||||
This release of Synapse requires Python 3.7+ and PostgreSQL 10+.
|
||||
|
||||
|
||||
# Upgrading to v1.47.0
|
||||
|
||||
## Removal of old Room Admin API
|
||||
|
||||
@@ -42,7 +42,6 @@ For each update:
|
||||
`average_items_per_ms` how many items are processed per millisecond based on an exponential average.
|
||||
|
||||
|
||||
|
||||
## Enabled
|
||||
|
||||
This API allow pausing background updates.
|
||||
@@ -82,3 +81,29 @@ The API returns the `enabled` param.
|
||||
```
|
||||
|
||||
There is also a `GET` version which returns the `enabled` state.
|
||||
|
||||
|
||||
## Run
|
||||
|
||||
This API schedules a specific background update to run. The job starts immediately after calling the API.
|
||||
|
||||
|
||||
The API is:
|
||||
|
||||
```
|
||||
POST /_synapse/admin/v1/background_updates/start_job
|
||||
```
|
||||
|
||||
with the following body:
|
||||
|
||||
```json
|
||||
{
|
||||
"job_name": "populate_stats_process_rooms"
|
||||
}
|
||||
```
|
||||
|
||||
The following JSON body parameters are available:
|
||||
|
||||
- `job_name` - A string which job to run. Valid values are:
|
||||
- `populate_stats_process_rooms` - Recalculate the stats for all rooms.
|
||||
- `regenerate_directory` - Recalculate the [user directory](../../../user_directory.md) if it is stale or out of sync.
|
||||
|
||||
114
docs/usage/administration/admin_api/federation.md
Normal file
114
docs/usage/administration/admin_api/federation.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Federation API
|
||||
|
||||
This API allows a server administrator to manage Synapse's federation with other homeservers.
|
||||
|
||||
Note: This API is new, experimental and "subject to change".
|
||||
|
||||
## List of destinations
|
||||
|
||||
This API gets the current destination retry timing info for all remote servers.
|
||||
|
||||
The list contains all the servers with which the server federates,
|
||||
regardless of whether an error occurred or not.
|
||||
If an error occurs, it may take up to 20 minutes for the error to be displayed here,
|
||||
as a complete retry must have failed.
|
||||
|
||||
The API is:
|
||||
|
||||
A standard request with no filtering:
|
||||
|
||||
```
|
||||
GET /_synapse/admin/v1/federation/destinations
|
||||
```
|
||||
|
||||
A response body like the following is returned:
|
||||
|
||||
```json
|
||||
{
|
||||
"destinations":[
|
||||
{
|
||||
"destination": "matrix.org",
|
||||
"retry_last_ts": 1557332397936,
|
||||
"retry_interval": 3000000,
|
||||
"failure_ts": 1557329397936,
|
||||
"last_successful_stream_ordering": null
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
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 destinations
|
||||
to paginate through.
|
||||
|
||||
**Parameters**
|
||||
|
||||
The following query parameters are available:
|
||||
|
||||
- `from` - Offset in the returned list. Defaults to `0`.
|
||||
- `limit` - Maximum amount of destinations to return. Defaults to `100`.
|
||||
- `order_by` - The method in which to sort the returned list of destinations.
|
||||
Valid values are:
|
||||
- `destination` - Destinations are ordered alphabetically by remote server name.
|
||||
This is the default.
|
||||
- `retry_last_ts` - Destinations are ordered by time of last retry attempt in ms.
|
||||
- `retry_interval` - Destinations are ordered by how long until next retry in ms.
|
||||
- `failure_ts` - Destinations are ordered by when the server started failing in ms.
|
||||
- `last_successful_stream_ordering` - Destinations are ordered by the stream ordering
|
||||
of the most recent successfully-sent PDU.
|
||||
- `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`.
|
||||
|
||||
*Caution:* The database only has an index on the column `destination`.
|
||||
This means that if a different sort order is used,
|
||||
this can cause a large load on the database, especially for large environments.
|
||||
|
||||
**Response**
|
||||
|
||||
The following fields are returned in the JSON response body:
|
||||
|
||||
- `destinations` - An array of objects, each containing information about a destination.
|
||||
Destination objects contain the following fields:
|
||||
- `destination` - string - Name of the remote server to federate.
|
||||
- `retry_last_ts` - integer - The last time Synapse tried and failed to reach the
|
||||
remote server, in ms. This is `0` if the last attempt to communicate with the
|
||||
remote server was successful.
|
||||
- `retry_interval` - integer - How long since the last time Synapse tried to reach
|
||||
the remote server before trying again, in ms. This is `0` if no further retrying occuring.
|
||||
- `failure_ts` - nullable integer - The first time Synapse tried and failed to reach the
|
||||
remote server, in ms. This is `null` if communication with the remote server has never failed.
|
||||
- `last_successful_stream_ordering` - nullable integer - The stream ordering of the most
|
||||
recent successfully-sent [PDU](understanding_synapse_through_grafana_graphs.md#federation)
|
||||
to this destination, or `null` if this information has not been tracked yet.
|
||||
- `next_token`: string representing a positive integer - Indication for pagination. See above.
|
||||
- `total` - integer - Total number of destinations.
|
||||
|
||||
# Destination Details API
|
||||
|
||||
This API gets the retry timing info for a specific remote server.
|
||||
|
||||
The API is:
|
||||
|
||||
```
|
||||
GET /_synapse/admin/v1/federation/destinations/<destination>
|
||||
```
|
||||
|
||||
A response body like the following is returned:
|
||||
|
||||
```json
|
||||
{
|
||||
"destination": "matrix.org",
|
||||
"retry_last_ts": 1557332397936,
|
||||
"retry_interval": 3000000,
|
||||
"failure_ts": 1557329397936,
|
||||
"last_successful_stream_ordering": null
|
||||
}
|
||||
```
|
||||
|
||||
**Response**
|
||||
|
||||
The response fields are the same like in the `destinations` array in
|
||||
[List of destinations](#list-of-destinations) response.
|
||||
103
docs/usage/administration/admin_faq.md
Normal file
103
docs/usage/administration/admin_faq.md
Normal file
@@ -0,0 +1,103 @@
|
||||
## Admin FAQ
|
||||
|
||||
How do I become a server admin?
|
||||
---
|
||||
If your server already has an admin account you should use the user admin API to promote other accounts to become admins. See [User Admin API](../../admin_api/user_admin_api.md#Change-whether-a-user-is-a-server-administrator-or-not)
|
||||
|
||||
If you don't have any admin accounts yet you won't be able to use the admin API so you'll have to edit the database manually. Manually editing the database is generally not recommended so once you have an admin account, use the admin APIs to make further changes.
|
||||
|
||||
```sql
|
||||
UPDATE users SET admin = 1 WHERE name = '@foo:bar.com';
|
||||
```
|
||||
What servers are my server talking to?
|
||||
---
|
||||
Run this sql query on your db:
|
||||
```sql
|
||||
SELECT * FROM destinations;
|
||||
```
|
||||
|
||||
What servers are currently participating in this room?
|
||||
---
|
||||
Run this sql query on your db:
|
||||
```sql
|
||||
SELECT DISTINCT split_part(state_key, ':', 2)
|
||||
FROM current_state_events AS c
|
||||
INNER JOIN room_memberships AS m USING (room_id, event_id)
|
||||
WHERE room_id = '!cURbafjkfsMDVwdRDQ:matrix.org' AND membership = 'join';
|
||||
```
|
||||
|
||||
What users are registered on my server?
|
||||
---
|
||||
```sql
|
||||
SELECT NAME from users;
|
||||
```
|
||||
|
||||
Manually resetting passwords:
|
||||
---
|
||||
See https://github.com/matrix-org/synapse/blob/master/README.rst#password-reset
|
||||
|
||||
I have a problem with my server. Can I just delete my database and start again?
|
||||
---
|
||||
Deleting your database is unlikely to make anything better.
|
||||
|
||||
It's easy to make the mistake of thinking that you can start again from a clean slate by dropping your database, but things don't work like that in a federated network: lots of other servers have information about your server.
|
||||
|
||||
For example: other servers might think that you are in a room, your server will think that you are not, and you'll probably be unable to interact with that room in a sensible way ever again.
|
||||
|
||||
In general, there are better solutions to any problem than dropping the database. Come and seek help in https://matrix.to/#/#synapse:matrix.org.
|
||||
|
||||
There are two exceptions when it might be sensible to delete your database and start again:
|
||||
* You have *never* joined any rooms which are federated with other servers. For instance, a local deployment which the outside world can't talk to.
|
||||
* You are changing the `server_name` in the homeserver configuration. In effect this makes your server a completely new one from the point of view of the network, so in this case it makes sense to start with a clean database.
|
||||
(In both cases you probably also want to clear out the media_store.)
|
||||
|
||||
I've stuffed up access to my room, how can I delete it to free up the alias?
|
||||
---
|
||||
Using the following curl command:
|
||||
```
|
||||
curl -H 'Authorization: Bearer <access-token>' -X DELETE https://matrix.org/_matrix/client/r0/directory/room/<room-alias>
|
||||
```
|
||||
`<access-token>` - can be obtained in riot by looking in the riot settings, down the bottom is:
|
||||
Access Token:\<click to reveal\>
|
||||
|
||||
`<room-alias>` - the room alias, eg. #my_room:matrix.org this possibly needs to be URL encoded also, for example %23my_room%3Amatrix.org
|
||||
|
||||
How can I find the lines corresponding to a given HTTP request in my homeserver log?
|
||||
---
|
||||
|
||||
Synapse tags each log line according to the HTTP request it is processing. When it finishes processing each request, it logs a line containing the words `Processed request: `. For example:
|
||||
|
||||
```
|
||||
2019-02-14 22:35:08,196 - synapse.access.http.8008 - 302 - INFO - GET-37 - ::1 - 8008 - {@richvdh:localhost} Processed request: 0.173sec/0.001sec (0.002sec, 0.000sec) (0.027sec/0.026sec/2) 687B 200 "GET /_matrix/client/r0/sync HTTP/1.1" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" [0 dbevts]"
|
||||
```
|
||||
|
||||
Here we can see that the request has been tagged with `GET-37`. (The tag depends on the method of the HTTP request, so might start with `GET-`, `PUT-`, `POST-`, `OPTIONS-` or `DELETE-`.) So to find all lines corresponding to this request, we can do:
|
||||
|
||||
```
|
||||
grep 'GET-37' homeserver.log
|
||||
```
|
||||
|
||||
If you want to paste that output into a github issue or matrix room, please remember to surround it with triple-backticks (```) to make it legible (see https://help.github.com/en/articles/basic-writing-and-formatting-syntax#quoting-code).
|
||||
|
||||
|
||||
What do all those fields in the 'Processed' line mean?
|
||||
---
|
||||
See [Request log format](request_log.md).
|
||||
|
||||
|
||||
What are the biggest rooms on my server?
|
||||
---
|
||||
|
||||
```sql
|
||||
SELECT s.canonical_alias, g.room_id, count(*) AS num_rows
|
||||
FROM
|
||||
state_groups_state AS g,
|
||||
room_stats_state AS s
|
||||
WHERE g.room_id = s.room_id
|
||||
GROUP BY s.canonical_alias, g.room_id
|
||||
ORDER BY num_rows desc
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
You can also use the [List Room API](../../admin_api/rooms.md#list-room-api)
|
||||
and `order_by` `state_events`.
|
||||
18
docs/usage/administration/database_maintenance_tools.md
Normal file
18
docs/usage/administration/database_maintenance_tools.md
Normal file
@@ -0,0 +1,18 @@
|
||||
This blog post by Victor Berger explains how to use many of the tools listed on this page: https://levans.fr/shrink-synapse-database.html
|
||||
|
||||
# List of useful tools and scripts for maintenance Synapse database:
|
||||
|
||||
## [Purge Remote Media API](../../admin_api/media_admin_api.md#purge-remote-media-api)
|
||||
The purge remote media API allows server admins to purge old cached remote media.
|
||||
|
||||
## [Purge Local Media API](../../admin_api/media_admin_api.md#delete-local-media)
|
||||
This API deletes the *local* media from the disk of your own server.
|
||||
|
||||
## [Purge History API](../../admin_api/purge_history_api.md)
|
||||
The purge history API allows server admins to purge historic events from their database, reclaiming disk space.
|
||||
|
||||
## [synapse-compress-state](https://github.com/matrix-org/rust-synapse-compress-state)
|
||||
Tool for compressing (deduplicating) `state_groups_state` table.
|
||||
|
||||
## [SQL for analyzing Synapse PostgreSQL database stats](useful_sql_for_admins.md)
|
||||
Some easy SQL that reports useful stats about your Synapse database.
|
||||
25
docs/usage/administration/state_groups.md
Normal file
25
docs/usage/administration/state_groups.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# How do State Groups work?
|
||||
|
||||
As a general rule, I encourage people who want to understand the deepest darkest secrets of the database schema to drop by #synapse-dev:matrix.org and ask questions.
|
||||
|
||||
However, one question that comes up frequently is that of how "state groups" work, and why the `state_groups_state` table gets so big, so here's an attempt to answer that question.
|
||||
|
||||
We need to be able to relatively quickly calculate the state of a room at any point in that room's history. In other words, we need to know the state of the room at each event in that room. This is done as follows:
|
||||
|
||||
A sequence of events where the state is the same are grouped together into a `state_group`; the mapping is recorded in `event_to_state_groups`. (Technically speaking, since a state event usually changes the state in the room, we are recording the state of the room *after* the given event id: which is to say, to a handwavey simplification, the first event in a state group is normally a state event, and others in the same state group are normally non-state-events.)
|
||||
|
||||
`state_groups` records, for each state group, the id of the room that we're looking at, and also the id of the first event in that group. (I'm not sure if that event id is used much in practice.)
|
||||
|
||||
Now, if we stored all the room state for each `state_group`, that would be a huge amount of data. Instead, for each state group, we normally store the difference between the state in that group and some other state group, and only occasionally (every 100 state changes or so) record the full state.
|
||||
|
||||
So, most state groups have an entry in `state_group_edges` (don't ask me why it's not a column in `state_groups`) which records the previous state group in the room, and `state_groups_state` records the differences in state since that previous state group.
|
||||
|
||||
A full state group just records the event id for each piece of state in the room at that point.
|
||||
|
||||
## Known bugs with state groups
|
||||
|
||||
There are various reasons that we can end up creating many more state groups than we need: see https://github.com/matrix-org/synapse/issues/3364 for more details.
|
||||
|
||||
## Compression tool
|
||||
|
||||
There is a tool at https://github.com/matrix-org/rust-synapse-compress-state which can compress the `state_groups_state` on a room by-room basis (essentially, it reduces the number of "full" state groups). This can result in dramatic reductions of the storage used.
|
||||
@@ -0,0 +1,84 @@
|
||||
## Understanding Synapse through Grafana graphs
|
||||
|
||||
It is possible to monitor much of the internal state of Synapse using [Prometheus](https://prometheus.io)
|
||||
metrics and [Grafana](https://grafana.com/).
|
||||
A guide for configuring Synapse to provide metrics is available [here](../../metrics-howto.md)
|
||||
and information on setting up Grafana is [here](https://github.com/matrix-org/synapse/tree/master/contrib/grafana).
|
||||
In this setup, Prometheus will periodically scrape the information Synapse provides and
|
||||
store a record of it over time. Grafana is then used as an interface to query and
|
||||
present this information through a series of pretty graphs.
|
||||
|
||||
Once you have grafana set up, and assuming you're using [our grafana dashboard template](https://github.com/matrix-org/synapse/blob/master/contrib/grafana/synapse.json), look for the following graphs when debugging a slow/overloaded Synapse:
|
||||
|
||||
## Message Event Send Time
|
||||
|
||||

|
||||
|
||||
This, along with the CPU and Memory graphs, is a good way to check the general health of your Synapse instance. It represents how long it takes for a user on your homeserver to send a message.
|
||||
|
||||
## Transaction Count and Transaction Duration
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
These graphs show the database transactions that are occurring the most frequently, as well as those are that are taking the most amount of time to execute.
|
||||
|
||||

|
||||
|
||||
In the first graph, we can see obvious spikes corresponding to lots of `get_user_by_id` transactions. This would be useful information to figure out which part of the Synapse codebase is potentially creating a heavy load on the system. However, be sure to cross-reference this with Transaction Duration, which states that `get_users_by_id` is actually a very quick database transaction and isn't causing as much load as others, like `persist_events`:
|
||||
|
||||

|
||||
|
||||
Still, it's probably worth investigating why we're getting users from the database that often, and whether it's possible to reduce the amount of queries we make by adjusting our cache factor(s).
|
||||
|
||||
The `persist_events` transaction is responsible for saving new room events to the Synapse database, so can often show a high transaction duration.
|
||||
|
||||
## Federation
|
||||
|
||||
The charts in the "Federation" section show information about incoming and outgoing federation requests. Federation data can be divided into two basic types:
|
||||
|
||||
- PDU (Persistent Data Unit) - room events: messages, state events (join/leave), etc. These are permanently stored in the database.
|
||||
- EDU (Ephemeral Data Unit) - other data, which need not be stored permanently, such as read receipts, typing notifications.
|
||||
|
||||
The "Outgoing EDUs by type" chart shows the EDUs within outgoing federation requests by type: `m.device_list_update`, `m.direct_to_device`, `m.presence`, `m.receipt`, `m.typing`.
|
||||
|
||||
If you see a large number of `m.presence` EDUs and are having trouble with too much CPU load, you can disable `presence` in the Synapse config. See also [#3971](https://github.com/matrix-org/synapse/issues/3971).
|
||||
|
||||
## Caches
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
This is quite a useful graph. It shows how many times Synapse attempts to retrieve a piece of data from a cache which the cache did not contain, thus resulting in a call to the database. We can see here that the `_get_joined_profile_from_event_id` cache is being requested a lot, and often the data we're after is not cached.
|
||||
|
||||
Cross-referencing this with the Eviction Rate graph, which shows that entries are being evicted from `_get_joined_profile_from_event_id` quite often:
|
||||
|
||||

|
||||
|
||||
we should probably consider raising the size of that cache by raising its cache factor (a multiplier value for the size of an individual cache). Information on doing so is available [here](https://github.com/matrix-org/synapse/blob/ee421e524478c1ad8d43741c27379499c2f6135c/docs/sample_config.yaml#L608-L642) (note that the configuration of individual cache factors through the configuration file is available in Synapse v1.14.0+, whereas doing so through environment variables has been supported for a very long time). Note that this will increase Synapse's overall memory usage.
|
||||
|
||||
## Forward Extremities
|
||||
|
||||

|
||||
|
||||
Forward extremities are the leaf events at the end of a DAG in a room, aka events that have no children. The more that exist in a room, the more [state resolution](https://spec.matrix.org/v1.1/server-server-api/#room-state-resolution) that Synapse needs to perform (hint: it's an expensive operation). While Synapse has code to prevent too many of these existing at one time in a room, bugs can sometimes make them crop up again.
|
||||
|
||||
If a room has >10 forward extremities, it's worth checking which room is the culprit and potentially removing them using the SQL queries mentioned in [#1760](https://github.com/matrix-org/synapse/issues/1760).
|
||||
|
||||
## Garbage Collection
|
||||
|
||||

|
||||
|
||||
Large spikes in garbage collection times (bigger than shown here, I'm talking in the
|
||||
multiple seconds range), can cause lots of problems in Synapse performance. It's more an
|
||||
indicator of problems, and a symptom of other problems though, so check other graphs for what might be causing it.
|
||||
|
||||
## Final Thoughts
|
||||
|
||||
If you're still having performance problems with your Synapse instance and you've
|
||||
tried everything you can, it may just be a lack of system resources. Consider adding
|
||||
more CPU and RAM, and make use of [worker mode](../../workers.md)
|
||||
to make use of multiple CPU cores / multiple machines for your homeserver.
|
||||
|
||||
156
docs/usage/administration/useful_sql_for_admins.md
Normal file
156
docs/usage/administration/useful_sql_for_admins.md
Normal file
@@ -0,0 +1,156 @@
|
||||
## Some useful SQL queries for Synapse Admins
|
||||
|
||||
## Size of full matrix db
|
||||
`SELECT pg_size_pretty( pg_database_size( 'matrix' ) );`
|
||||
### Result example:
|
||||
```
|
||||
pg_size_pretty
|
||||
----------------
|
||||
6420 MB
|
||||
(1 row)
|
||||
```
|
||||
## Show top 20 larger rooms by state events count
|
||||
```sql
|
||||
SELECT r.name, s.room_id, s.current_state_events
|
||||
FROM room_stats_current s
|
||||
LEFT JOIN room_stats_state r USING (room_id)
|
||||
ORDER BY current_state_events DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
|
||||
and by state_group_events count:
|
||||
```sql
|
||||
SELECT rss.name, s.room_id, count(s.room_id) FROM state_groups_state s
|
||||
LEFT JOIN room_stats_state rss USING (room_id)
|
||||
GROUP BY s.room_id, rss.name
|
||||
ORDER BY count(s.room_id) DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
plus same, but with join removed for performance reasons:
|
||||
```sql
|
||||
SELECT s.room_id, count(s.room_id) FROM state_groups_state s
|
||||
GROUP BY s.room_id
|
||||
ORDER BY count(s.room_id) DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
|
||||
## Show top 20 larger tables by row count
|
||||
```sql
|
||||
SELECT relname, n_live_tup as rows
|
||||
FROM pg_stat_user_tables
|
||||
ORDER BY n_live_tup DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
This query is quick, but may be very approximate, for exact number of rows use `SELECT COUNT(*) FROM <table_name>`.
|
||||
### Result example:
|
||||
```
|
||||
state_groups_state - 161687170
|
||||
event_auth - 8584785
|
||||
event_edges - 6995633
|
||||
event_json - 6585916
|
||||
event_reference_hashes - 6580990
|
||||
events - 6578879
|
||||
received_transactions - 5713989
|
||||
event_to_state_groups - 4873377
|
||||
stream_ordering_to_exterm - 4136285
|
||||
current_state_delta_stream - 3770972
|
||||
event_search - 3670521
|
||||
state_events - 2845082
|
||||
room_memberships - 2785854
|
||||
cache_invalidation_stream - 2448218
|
||||
state_groups - 1255467
|
||||
state_group_edges - 1229849
|
||||
current_state_events - 1222905
|
||||
users_in_public_rooms - 364059
|
||||
device_lists_stream - 326903
|
||||
user_directory_search - 316433
|
||||
```
|
||||
|
||||
## Show top 20 rooms by new events count in last 1 day:
|
||||
```sql
|
||||
SELECT e.room_id, r.name, COUNT(e.event_id) cnt FROM events e
|
||||
LEFT JOIN room_stats_state r USING (room_id)
|
||||
WHERE e.origin_server_ts >= DATE_PART('epoch', NOW() - INTERVAL '1 day') * 1000 GROUP BY e.room_id, r.name ORDER BY cnt DESC LIMIT 20;
|
||||
```
|
||||
|
||||
## Show top 20 users on homeserver by sent events (messages) at last month:
|
||||
```sql
|
||||
SELECT user_id, SUM(total_events)
|
||||
FROM user_stats_historical
|
||||
WHERE TO_TIMESTAMP(end_ts/1000) AT TIME ZONE 'UTC' > date_trunc('day', now() - interval '1 month')
|
||||
GROUP BY user_id
|
||||
ORDER BY SUM(total_events) DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
|
||||
## Show last 100 messages from needed user, with room names:
|
||||
```sql
|
||||
SELECT e.room_id, r.name, e.event_id, e.type, e.content, j.json FROM events e
|
||||
LEFT JOIN event_json j USING (room_id)
|
||||
LEFT JOIN room_stats_state r USING (room_id)
|
||||
WHERE sender = '@LOGIN:example.com'
|
||||
AND e.type = 'm.room.message'
|
||||
ORDER BY stream_ordering DESC
|
||||
LIMIT 100;
|
||||
```
|
||||
|
||||
## Show top 20 larger tables by storage size
|
||||
```sql
|
||||
SELECT nspname || '.' || relname AS "relation",
|
||||
pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size"
|
||||
FROM pg_class C
|
||||
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
|
||||
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
|
||||
AND C.relkind <> 'i'
|
||||
AND nspname !~ '^pg_toast'
|
||||
ORDER BY pg_total_relation_size(C.oid) DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
### Result example:
|
||||
```
|
||||
public.state_groups_state - 27 GB
|
||||
public.event_json - 9855 MB
|
||||
public.events - 3675 MB
|
||||
public.event_edges - 3404 MB
|
||||
public.received_transactions - 2745 MB
|
||||
public.event_reference_hashes - 1864 MB
|
||||
public.event_auth - 1775 MB
|
||||
public.stream_ordering_to_exterm - 1663 MB
|
||||
public.event_search - 1370 MB
|
||||
public.room_memberships - 1050 MB
|
||||
public.event_to_state_groups - 948 MB
|
||||
public.current_state_delta_stream - 711 MB
|
||||
public.state_events - 611 MB
|
||||
public.presence_stream - 530 MB
|
||||
public.current_state_events - 525 MB
|
||||
public.cache_invalidation_stream - 466 MB
|
||||
public.receipts_linearized - 279 MB
|
||||
public.state_groups - 160 MB
|
||||
public.device_lists_remote_cache - 124 MB
|
||||
public.state_group_edges - 122 MB
|
||||
```
|
||||
|
||||
## Show rooms with names, sorted by events in this rooms
|
||||
`echo "select event_json.room_id,room_stats_state.name from event_json,room_stats_state where room_stats_state.room_id=event_json.room_id" | psql synapse | sort | uniq -c | sort -n`
|
||||
### Result example:
|
||||
```
|
||||
9459 !FPUfgzXYWTKgIrwKxW:matrix.org | This Week in Matrix
|
||||
9459 !FPUfgzXYWTKgIrwKxW:matrix.org | This Week in Matrix (TWIM)
|
||||
17799 !iDIOImbmXxwNngznsa:matrix.org | Linux in Russian
|
||||
18739 !GnEEPYXUhoaHbkFBNX:matrix.org | Riot Android
|
||||
23373 !QtykxKocfZaZOUrTwp:matrix.org | Matrix HQ
|
||||
39504 !gTQfWzbYncrtNrvEkB:matrix.org | ru.[matrix]
|
||||
43601 !iNmaIQExDMeqdITdHH:matrix.org | Riot
|
||||
43601 !iNmaIQExDMeqdITdHH:matrix.org | Riot Web/Desktop
|
||||
```
|
||||
|
||||
## Lookup room state info by list of room_id
|
||||
```sql
|
||||
SELECT rss.room_id, rss.name, rss.canonical_alias, rss.topic, rss.encryption, rsc.joined_members, rsc.local_users_in_room, rss.join_rules
|
||||
FROM room_stats_state rss
|
||||
LEFT JOIN room_stats_current rsc USING (room_id)
|
||||
WHERE room_id IN (WHERE room_id IN (
|
||||
'!OGEhHVWSdvArJzumhm:matrix.org',
|
||||
'!YTvKGNlinIzlkMTVRl:matrix.org'
|
||||
)
|
||||
```
|
||||
139
docs/usage/configuration/user_authentication/refresh_tokens.md
Normal file
139
docs/usage/configuration/user_authentication/refresh_tokens.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Refresh Tokens
|
||||
|
||||
Synapse supports refresh tokens since version 1.49 (some earlier versions had support for an earlier, experimental draft of [MSC2918] which is not compatible).
|
||||
|
||||
|
||||
[MSC2918]: https://github.com/matrix-org/matrix-doc/blob/main/proposals/2918-refreshtokens.md#msc2918-refresh-tokens
|
||||
|
||||
|
||||
## Background and motivation
|
||||
|
||||
Synapse users' sessions are identified by **access tokens**; access tokens are
|
||||
issued to users on login. Each session gets a unique access token which identifies
|
||||
it; the access token must be kept secret as it grants access to the user's account.
|
||||
|
||||
Traditionally, these access tokens were eternally valid (at least until the user
|
||||
explicitly chose to log out).
|
||||
|
||||
In some cases, it may be desirable for these access tokens to expire so that the
|
||||
potential damage caused by leaking an access token is reduced.
|
||||
On the other hand, forcing a user to re-authenticate (log in again) often might
|
||||
be too much of an inconvenience.
|
||||
|
||||
**Refresh tokens** are a mechanism to avoid some of this inconvenience whilst
|
||||
still getting most of the benefits of short access token lifetimes.
|
||||
Refresh tokens are also a concept present in OAuth 2 — further reading is available
|
||||
[here](https://datatracker.ietf.org/doc/html/rfc6749#section-1.5).
|
||||
|
||||
When refresh tokens are in use, both an access token and a refresh token will be
|
||||
issued to users on login. The access token will expire after a predetermined amount
|
||||
of time, but otherwise works in the same way as before. When the access token is
|
||||
close to expiring (or has expired), the user's client should present the homeserver
|
||||
(Synapse) with the refresh token.
|
||||
|
||||
The homeserver will then generate a new access token and refresh token for the user
|
||||
and return them. The old refresh token is invalidated and can not be used again*.
|
||||
|
||||
Finally, refresh tokens also make it possible for sessions to be logged out if they
|
||||
are inactive for too long, before the session naturally ends; see the configuration
|
||||
guide below.
|
||||
|
||||
|
||||
*To prevent issues if clients lose connection half-way through refreshing a token,
|
||||
the refresh token is only invalidated once the new access token has been used at
|
||||
least once. For all intents and purposes, the above simplification is sufficient.
|
||||
|
||||
|
||||
## Caveats
|
||||
|
||||
There are some caveats:
|
||||
|
||||
* If a third party gets both your access token and refresh token, they will be able to
|
||||
continue to enjoy access to your session.
|
||||
* This is still an improvement because you (the user) will notice when *your*
|
||||
session expires and you're not able to use your refresh token.
|
||||
That would be a giveaway that someone else has compromised your session.
|
||||
You would be able to log in again and terminate that session.
|
||||
Previously (with long-lived access tokens), a third party that has your access
|
||||
token could go undetected for a very long time.
|
||||
* Clients need to implement support for refresh tokens in order for them to be a
|
||||
useful mechanism.
|
||||
* It is up to homeserver administrators if they want to issue long-lived access
|
||||
tokens to clients not implementing refresh tokens.
|
||||
* For compatibility, it is likely that they should, at least until client support
|
||||
is widespread.
|
||||
* Users with clients that support refresh tokens will still benefit from the
|
||||
added security; it's not possible to downgrade a session to using long-lived
|
||||
access tokens so this effectively gives users the choice.
|
||||
* In a closed environment where all users use known clients, this may not be
|
||||
an issue as the homeserver administrator can know if the clients have refresh
|
||||
token support. In that case, the non-refreshable access token lifetime
|
||||
may be set to a short duration so that a similar level of security is provided.
|
||||
|
||||
|
||||
## Configuration Guide
|
||||
|
||||
The following configuration options, in the `registration` section, are related:
|
||||
|
||||
* `session_lifetime`: maximum length of a session, even if it's refreshed.
|
||||
In other words, the client must log in again after this time period.
|
||||
In most cases, this can be unset (infinite) or set to a long time (years or months).
|
||||
* `refreshable_access_token_lifetime`: lifetime of access tokens that are created
|
||||
by clients supporting refresh tokens.
|
||||
This should be short; a good value might be 5 minutes (`5m`).
|
||||
* `nonrefreshable_access_token_lifetime`: lifetime of access tokens that are created
|
||||
by clients which don't support refresh tokens.
|
||||
Make this short if you want to effectively force use of refresh tokens.
|
||||
Make this long if you don't want to inconvenience users of clients which don't
|
||||
support refresh tokens (by forcing them to frequently re-authenticate using
|
||||
login credentials).
|
||||
* `refresh_token_lifetime`: lifetime of refresh tokens.
|
||||
In other words, the client must refresh within this time period to maintain its session.
|
||||
Unless you want to log inactive sessions out, it is often fine to use a long
|
||||
value here or even leave it unset (infinite).
|
||||
Beware that making it too short will inconvenience clients that do not connect
|
||||
very often, including mobile clients and clients of infrequent users (by making
|
||||
it more difficult for them to refresh in time, which may force them to need to
|
||||
re-authenticate using login credentials).
|
||||
|
||||
**Note:** All four options above only apply when tokens are created (by logging in or refreshing).
|
||||
Changes to these settings do not apply retroactively.
|
||||
|
||||
|
||||
### Using refresh token expiry to log out inactive sessions
|
||||
|
||||
If you'd like to force sessions to be logged out upon inactivity, you can enable
|
||||
refreshable access token expiry and refresh token expiry.
|
||||
|
||||
This works because a client must refresh at least once within a period of
|
||||
`refresh_token_lifetime` in order to maintain valid credentials to access the
|
||||
account.
|
||||
|
||||
(It's suggested that `refresh_token_lifetime` should be longer than
|
||||
`refreshable_access_token_lifetime` and this section assumes that to be the case
|
||||
for simplicity.)
|
||||
|
||||
Note: this will only affect sessions using refresh tokens. You may wish to
|
||||
set a short `nonrefreshable_access_token_lifetime` to prevent this being bypassed
|
||||
by clients that do not support refresh tokens.
|
||||
|
||||
|
||||
#### Choosing values that guarantee permitting some inactivity
|
||||
|
||||
It may be desirable to permit some short periods of inactivity, for example to
|
||||
accommodate brief outages in client connectivity.
|
||||
|
||||
The following model aims to provide guidance for choosing `refresh_token_lifetime`
|
||||
and `refreshable_access_token_lifetime` to satisfy requirements of the form:
|
||||
|
||||
1. inactivity longer than `L` **MUST** cause the session to be logged out; and
|
||||
2. inactivity shorter than `S` **MUST NOT** cause the session to be logged out.
|
||||
|
||||
This model makes the weakest assumption that all active clients will refresh as
|
||||
needed to maintain an active access token, but no sooner.
|
||||
*In reality, clients may refresh more often than this model assumes, but the
|
||||
above requirements will still hold.*
|
||||
|
||||
To satisfy the above model,
|
||||
* `refresh_token_lifetime` should be set to `L`; and
|
||||
* `refreshable_access_token_lifetime` should be set to `L - S`.
|
||||
@@ -6,9 +6,9 @@ on this particular server - i.e. ones which your account shares a room with, or
|
||||
who are present in a publicly viewable room present on the server.
|
||||
|
||||
The directory info is stored in various tables, which can (typically after
|
||||
DB corruption) get stale or out of sync. If this happens, for now the
|
||||
solution to fix it is to execute the SQL [here](https://github.com/matrix-org/synapse/blob/master/synapse/storage/schema/main/delta/53/user_dir_populate.sql)
|
||||
and then restart synapse. This should then start a background task to
|
||||
DB corruption) get stale or out of sync. If this happens, for now the
|
||||
solution to fix it is to use the [admin API](usage/administration/admin_api/background_updates.md#run)
|
||||
and execute the job `regenerate_directory`. This should then start a background task to
|
||||
flush the current tables and regenerate the directory.
|
||||
|
||||
Data model
|
||||
|
||||
@@ -182,10 +182,10 @@ This worker can handle API requests matching the following regular
|
||||
expressions:
|
||||
|
||||
# Sync requests
|
||||
^/_matrix/client/(v2_alpha|r0)/sync$
|
||||
^/_matrix/client/(api/v1|v2_alpha|r0)/events$
|
||||
^/_matrix/client/(api/v1|r0)/initialSync$
|
||||
^/_matrix/client/(api/v1|r0)/rooms/[^/]+/initialSync$
|
||||
^/_matrix/client/(v2_alpha|r0|v3)/sync$
|
||||
^/_matrix/client/(api/v1|v2_alpha|r0|v3)/events$
|
||||
^/_matrix/client/(api/v1|r0|v3)/initialSync$
|
||||
^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$
|
||||
|
||||
# Federation requests
|
||||
^/_matrix/federation/v1/event/
|
||||
@@ -210,46 +210,46 @@ expressions:
|
||||
^/_matrix/federation/v1/get_groups_publicised$
|
||||
^/_matrix/key/v2/query
|
||||
^/_matrix/federation/unstable/org.matrix.msc2946/spaces/
|
||||
^/_matrix/federation/unstable/org.matrix.msc2946/hierarchy/
|
||||
^/_matrix/federation/(v1|unstable/org.matrix.msc2946)/hierarchy/
|
||||
|
||||
# Inbound federation transaction request
|
||||
^/_matrix/federation/v1/send/
|
||||
|
||||
# Client API requests
|
||||
^/_matrix/client/(api/v1|r0|unstable)/createRoom$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/publicRooms$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/joined_members$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/context/.*$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/members$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/state$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/createRoom$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/publicRooms$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/joined_members$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/context/.*$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/members$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/state$
|
||||
^/_matrix/client/unstable/org.matrix.msc2946/rooms/.*/spaces$
|
||||
^/_matrix/client/unstable/org.matrix.msc2946/rooms/.*/hierarchy$
|
||||
^/_matrix/client/(v1|unstable/org.matrix.msc2946)/rooms/.*/hierarchy$
|
||||
^/_matrix/client/unstable/im.nheko.summary/rooms/.*/summary$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/account/3pid$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/devices$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/keys/query$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/keys/changes$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/account/3pid$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/devices$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/keys/query$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/keys/changes$
|
||||
^/_matrix/client/versions$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/voip/turnServer$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/joined_groups$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/publicised_groups$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/publicised_groups/
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/event/
|
||||
^/_matrix/client/(api/v1|r0|unstable)/joined_rooms$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/search$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/voip/turnServer$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/joined_groups$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/publicised_groups$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/publicised_groups/
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/event/
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/joined_rooms$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/search$
|
||||
|
||||
# Registration/login requests
|
||||
^/_matrix/client/(api/v1|r0|unstable)/login$
|
||||
^/_matrix/client/(r0|unstable)/register$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/login$
|
||||
^/_matrix/client/(r0|v3|unstable)/register$
|
||||
^/_matrix/client/unstable/org.matrix.msc3231/register/org.matrix.msc3231.login.registration_token/validity$
|
||||
|
||||
# Event sending requests
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/redact
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/send
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/state/
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/(join|invite|leave|ban|unban|kick)$
|
||||
^/_matrix/client/(api/v1|r0|unstable)/join/
|
||||
^/_matrix/client/(api/v1|r0|unstable)/profile/
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/redact
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/send
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/state/
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/(join|invite|leave|ban|unban|kick)$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/join/
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/profile/
|
||||
|
||||
|
||||
Additionally, the following REST endpoints can be handled for GET requests:
|
||||
@@ -261,14 +261,14 @@ room must be routed to the same instance. Additionally, care must be taken to
|
||||
ensure that the purge history admin API is not used while pagination requests
|
||||
for the room are in flight:
|
||||
|
||||
^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/messages$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/messages$
|
||||
|
||||
Additionally, the following endpoints should be included if Synapse is configured
|
||||
to use SSO (you only need to include the ones for whichever SSO provider you're
|
||||
using):
|
||||
|
||||
# for all SSO providers
|
||||
^/_matrix/client/(api/v1|r0|unstable)/login/sso/redirect
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/login/sso/redirect
|
||||
^/_synapse/client/pick_idp$
|
||||
^/_synapse/client/pick_username
|
||||
^/_synapse/client/new_user_consent$
|
||||
@@ -281,7 +281,7 @@ using):
|
||||
^/_synapse/client/saml2/authn_response$
|
||||
|
||||
# CAS requests.
|
||||
^/_matrix/client/(api/v1|r0|unstable)/login/cas/ticket$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/login/cas/ticket$
|
||||
|
||||
Ensure that all SSO logins go to a single process.
|
||||
For multiple workers not handling the SSO endpoints properly, see
|
||||
@@ -465,7 +465,7 @@ Note that if a reverse proxy is used , then `/_matrix/media/` must be routed for
|
||||
Handles searches in the user directory. It can handle REST endpoints matching
|
||||
the following regular expressions:
|
||||
|
||||
^/_matrix/client/(api/v1|r0|unstable)/user_directory/search$
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/user_directory/search$
|
||||
|
||||
When using this worker you must also set `update_user_directory: False` in the
|
||||
shared configuration file to stop the main synapse running background
|
||||
@@ -477,12 +477,12 @@ Proxies some frequently-requested client endpoints to add caching and remove
|
||||
load from the main synapse. It can handle REST endpoints matching the following
|
||||
regular expressions:
|
||||
|
||||
^/_matrix/client/(api/v1|r0|unstable)/keys/upload
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/keys/upload
|
||||
|
||||
If `use_presence` is False in the homeserver config, it can also handle REST
|
||||
endpoints matching the following regular expressions:
|
||||
|
||||
^/_matrix/client/(api/v1|r0|unstable)/presence/[^/]+/status
|
||||
^/_matrix/client/(api/v1|r0|v3|unstable)/presence/[^/]+/status
|
||||
|
||||
This "stub" presence handler will pass through `GET` request but make the
|
||||
`PUT` effectively a no-op.
|
||||
|
||||
163
mypy.ini
163
mypy.ini
@@ -25,15 +25,9 @@ exclude = (?x)
|
||||
^(
|
||||
|synapse/storage/databases/__init__.py
|
||||
|synapse/storage/databases/main/__init__.py
|
||||
|synapse/storage/databases/main/account_data.py
|
||||
|synapse/storage/databases/main/cache.py
|
||||
|synapse/storage/databases/main/devices.py
|
||||
|synapse/storage/databases/main/e2e_room_keys.py
|
||||
|synapse/storage/databases/main/end_to_end_keys.py
|
||||
|synapse/storage/databases/main/event_federation.py
|
||||
|synapse/storage/databases/main/event_push_actions.py
|
||||
|synapse/storage/databases/main/events_bg_updates.py
|
||||
|synapse/storage/databases/main/events_worker.py
|
||||
|synapse/storage/databases/main/group_server.py
|
||||
|synapse/storage/databases/main/metrics.py
|
||||
|synapse/storage/databases/main/monthly_active_users.py
|
||||
@@ -41,12 +35,9 @@ exclude = (?x)
|
||||
|synapse/storage/databases/main/purge_events.py
|
||||
|synapse/storage/databases/main/push_rule.py
|
||||
|synapse/storage/databases/main/receipts.py
|
||||
|synapse/storage/databases/main/room.py
|
||||
|synapse/storage/databases/main/roommember.py
|
||||
|synapse/storage/databases/main/search.py
|
||||
|synapse/storage/databases/main/state.py
|
||||
|synapse/storage/databases/main/stats.py
|
||||
|synapse/storage/databases/main/transactions.py
|
||||
|synapse/storage/databases/main/user_directory.py
|
||||
|synapse/storage/schema/
|
||||
|
||||
@@ -87,9 +78,6 @@ exclude = (?x)
|
||||
|tests/push/test_presentable_names.py
|
||||
|tests/push/test_push_rule_evaluator.py
|
||||
|tests/rest/admin/test_admin.py
|
||||
|tests/rest/admin/test_device.py
|
||||
|tests/rest/admin/test_media.py
|
||||
|tests/rest/admin/test_server_notice.py
|
||||
|tests/rest/admin/test_user.py
|
||||
|tests/rest/admin/test_username_available.py
|
||||
|tests/rest/client/test_account.py
|
||||
@@ -111,8 +99,6 @@ exclude = (?x)
|
||||
|tests/server.py
|
||||
|tests/server_notices/test_resource_limits_server_notices.py
|
||||
|tests/state/test_v2.py
|
||||
|tests/storage/test_account_data.py
|
||||
|tests/storage/test_appservice.py
|
||||
|tests/storage/test_background_update.py
|
||||
|tests/storage/test_base.py
|
||||
|tests/storage/test_client_ips.py
|
||||
@@ -125,7 +111,6 @@ exclude = (?x)
|
||||
|tests/test_server.py
|
||||
|tests/test_state.py
|
||||
|tests/test_terms_auth.py
|
||||
|tests/test_visibility.py
|
||||
|tests/unittest.py
|
||||
|tests/util/caches/test_cached_call.py
|
||||
|tests/util/caches/test_deferred_cache.py
|
||||
@@ -151,15 +136,39 @@ disallow_untyped_defs = True
|
||||
[mypy-synapse.app.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.appservice.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.config._base]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.crypto.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.events.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.federation.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.federation.transport.client]
|
||||
disallow_untyped_defs = False
|
||||
|
||||
[mypy-synapse.handlers.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.http.server]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.logging.context]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.metrics.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.module_api.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.push.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
@@ -172,21 +181,48 @@ disallow_untyped_defs = True
|
||||
[mypy-synapse.state.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.account_data]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.client_ips]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.directory]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.e2e_room_keys]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.end_to_end_keys]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.event_push_actions]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.events_bg_updates]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.events_worker]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.room]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.room_batch]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.profile]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.stats]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.state_deltas]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.transactions]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.storage.databases.main.user_erasure_store]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
@@ -196,92 +232,11 @@ disallow_untyped_defs = True
|
||||
[mypy-synapse.streams.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.batching_queue]
|
||||
[mypy-synapse.util.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.caches.cached_call]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.caches.dictionary_cache]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.caches.lrucache]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.caches.response_cache]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.caches.stream_change_cache]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.caches.ttl_cache]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.daemonize]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.file_consumer]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.frozenutils]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.hash]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.httpresourcetree]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.iterutils]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.linked_list]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.logcontext]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.logformatter]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.macaroons]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.manhole]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.module_loader]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.msisdn]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.patch_inline_callbacks]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.ratelimitutils]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.retryutils]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.rlimit]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.stringutils]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.templates]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.threepids]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.wheel_timer]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-synapse.util.versionstring]
|
||||
disallow_untyped_defs = True
|
||||
[mypy-synapse.util.caches.treecache]
|
||||
disallow_untyped_defs = False
|
||||
|
||||
[mypy-tests.handlers.test_user_directory]
|
||||
disallow_untyped_defs = True
|
||||
@@ -292,9 +247,16 @@ disallow_untyped_defs = True
|
||||
[mypy-tests.storage.test_user_directory]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-tests.rest.admin.*]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-tests.rest.client.test_directory]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
[mypy-tests.federation.transport.test_client]
|
||||
disallow_untyped_defs = True
|
||||
|
||||
|
||||
;; Dependencies without annotations
|
||||
;; Before ignoring a module, check to see if type stubs are available.
|
||||
;; The `typeshed` project maintains stubs here:
|
||||
@@ -351,9 +313,6 @@ ignore_missing_imports = True
|
||||
[mypy-netaddr]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-opentracing]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-parameterized.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
showcontent = true
|
||||
|
||||
[tool.black]
|
||||
target-version = ['py36']
|
||||
target-version = ['py37', 'py38', 'py39', 'py310']
|
||||
exclude = '''
|
||||
|
||||
(
|
||||
|
||||
@@ -24,7 +24,6 @@ DISTS = (
|
||||
"debian:bullseye",
|
||||
"debian:bookworm",
|
||||
"debian:sid",
|
||||
"ubuntu:bionic", # 18.04 LTS (our EOL forced by Py36 on 2021-12-23)
|
||||
"ubuntu:focal", # 20.04 LTS (our EOL forced by Py38 on 2024-10-14)
|
||||
"ubuntu:hirsute", # 21.04 (EOL 2022-01-05)
|
||||
"ubuntu:impish", # 21.10 (EOL 2022-07)
|
||||
|
||||
@@ -42,8 +42,8 @@ echo "--------------------------"
|
||||
echo
|
||||
|
||||
matched=0
|
||||
for f in $(git diff --name-only FETCH_HEAD... -- changelog.d); do
|
||||
# check that any modified newsfiles on this branch end with a full stop.
|
||||
for f in $(git diff --diff-filter=d --name-only FETCH_HEAD... -- changelog.d); do
|
||||
# check that any added newsfiles on this branch end with a full stop.
|
||||
lastchar=$(tr -d '\n' < "$f" | tail -c 1)
|
||||
if [ "$lastchar" != '.' ] && [ "$lastchar" != '!' ]; then
|
||||
echo -e "\e[31mERROR: newsfragment $f does not end with a '.' or '!'\e[39m" >&2
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
set -e
|
||||
|
||||
# Change to the repository root
|
||||
cd "$(dirname "$0")/.."
|
||||
cd "$(dirname $0)/.."
|
||||
|
||||
# Check for a user-specified Complement checkout
|
||||
if [[ -z "$COMPLEMENT_DIR" ]]; then
|
||||
@@ -61,8 +61,8 @@ cd "$COMPLEMENT_DIR"
|
||||
EXTRA_COMPLEMENT_ARGS=""
|
||||
if [[ -n "$1" ]]; then
|
||||
# A test name regex has been set, supply it to Complement
|
||||
EXTRA_COMPLEMENT_ARGS=(-run "$1")
|
||||
EXTRA_COMPLEMENT_ARGS+="-run $1 "
|
||||
fi
|
||||
|
||||
# Run the tests!
|
||||
go test -v -tags synapse_blacklist,msc2946,msc3083,msc2403,msc2716 -count=1 "${EXTRA_COMPLEMENT_ARGS[@]}" ./tests/...
|
||||
go test -v -tags synapse_blacklist,msc2403 -count=1 $EXTRA_COMPLEMENT_ARGS ./tests/...
|
||||
|
||||
@@ -15,6 +15,25 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""
|
||||
Script for signing and sending federation requests.
|
||||
|
||||
Some tips on doing the join dance with this:
|
||||
|
||||
room_id=...
|
||||
user_id=...
|
||||
|
||||
# make_join
|
||||
federation_client.py "/_matrix/federation/v1/make_join/$room_id/$user_id?ver=5" > make_join.json
|
||||
|
||||
# sign
|
||||
jq -M .event make_join.json | sign_json --sign-event-room-version=$(jq -r .room_version make_join.json) -o signed-join.json
|
||||
|
||||
# send_join
|
||||
federation_client.py -X PUT "/_matrix/federation/v2/send_join/$room_id/x" --body $(<signed-join.json) > send_join.json
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
|
||||
@@ -22,6 +22,8 @@ import yaml
|
||||
from signedjson.key import read_signing_keys
|
||||
from signedjson.sign import sign_json
|
||||
|
||||
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
|
||||
from synapse.crypto.event_signing import add_hashes_and_signatures
|
||||
from synapse.util import json_encoder
|
||||
|
||||
|
||||
@@ -68,6 +70,16 @@ Example usage:
|
||||
),
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--sign-event-room-version",
|
||||
type=str,
|
||||
help=(
|
||||
"Sign the JSON as an event for the given room version, rather than raw JSON. "
|
||||
"This means that we will add a 'hashes' object, and redact the event before "
|
||||
"signing."
|
||||
),
|
||||
)
|
||||
|
||||
input_args = parser.add_mutually_exclusive_group()
|
||||
|
||||
input_args.add_argument("input_data", nargs="?", help="Raw JSON to be signed.")
|
||||
@@ -116,7 +128,17 @@ Example usage:
|
||||
print("Input json was not an object", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
sign_json(obj, args.server_name, keys[0])
|
||||
if args.sign_event_room_version:
|
||||
room_version = KNOWN_ROOM_VERSIONS.get(args.sign_event_room_version)
|
||||
if not room_version:
|
||||
print(
|
||||
f"Unknown room version {args.sign_event_room_version}", file=sys.stderr
|
||||
)
|
||||
sys.exit(1)
|
||||
add_hashes_and_signatures(room_version, obj, args.server_name, keys[0])
|
||||
else:
|
||||
sign_json(obj, args.server_name, keys[0])
|
||||
|
||||
for c in json_encoder.iterencode(obj):
|
||||
args.output.write(c)
|
||||
args.output.write("\n")
|
||||
|
||||
10
setup.py
10
setup.py
@@ -96,7 +96,7 @@ CONDITIONAL_REQUIREMENTS["all"] = list(ALL_OPTIONAL_REQUIREMENTS)
|
||||
# We pin black so that our tests don't start failing on new releases.
|
||||
CONDITIONAL_REQUIREMENTS["lint"] = [
|
||||
"isort==5.7.0",
|
||||
"black==21.6b0",
|
||||
"black==21.12b0",
|
||||
"flake8-comprehensions",
|
||||
"flake8-bugbear==21.3.2",
|
||||
"flake8",
|
||||
@@ -107,6 +107,7 @@ CONDITIONAL_REQUIREMENTS["mypy"] = [
|
||||
"mypy-zope==0.3.2",
|
||||
"types-bleach>=4.1.0",
|
||||
"types-jsonschema>=3.2.0",
|
||||
"types-opentracing>=2.4.2",
|
||||
"types-Pillow>=8.3.4",
|
||||
"types-pyOpenSSL>=20.0.7",
|
||||
"types-PyYAML>=5.4.10",
|
||||
@@ -150,12 +151,17 @@ setup(
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/x-rst",
|
||||
python_requires="~=3.6",
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"synapse_homeserver = synapse.app.homeserver:main",
|
||||
"synapse_worker = synapse.app.generic_worker:main",
|
||||
]
|
||||
},
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Topic :: Communications :: Chat",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
from typing import Any, List, Optional, Type, Union
|
||||
|
||||
from twisted.internet import protocol
|
||||
from twisted.internet.defer import Deferred
|
||||
|
||||
class RedisProtocol(protocol.Protocol):
|
||||
def publish(self, channel: str, message: bytes): ...
|
||||
async def ping(self) -> None: ...
|
||||
async def set(
|
||||
def ping(self) -> "Deferred[None]": ...
|
||||
def set(
|
||||
self,
|
||||
key: str,
|
||||
value: Any,
|
||||
@@ -29,8 +30,8 @@ class RedisProtocol(protocol.Protocol):
|
||||
pexpire: Optional[int] = None,
|
||||
only_if_not_exists: bool = False,
|
||||
only_if_exists: bool = False,
|
||||
) -> None: ...
|
||||
async def get(self, key: str) -> Any: ...
|
||||
) -> "Deferred[None]": ...
|
||||
def get(self, key: str) -> "Deferred[Any]": ...
|
||||
|
||||
class SubscriberProtocol(RedisProtocol):
|
||||
def __init__(self, *args, **kwargs): ...
|
||||
|
||||
@@ -47,7 +47,7 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
__version__ = "1.47.0rc2"
|
||||
__version__ = "1.50.1"
|
||||
|
||||
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
|
||||
# We import here so that we don't have to install a bunch of deps when
|
||||
|
||||
@@ -32,7 +32,7 @@ from synapse.appservice import ApplicationService
|
||||
from synapse.events import EventBase
|
||||
from synapse.http import get_request_user_agent
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.logging import opentracing as opentracing
|
||||
from synapse.logging.opentracing import active_span, force_tracing, start_active_span
|
||||
from synapse.storage.databases.main.registration import TokenLookupResult
|
||||
from synapse.types import Requester, StateMap, UserID, create_requester
|
||||
from synapse.util.caches.lrucache import LruCache
|
||||
@@ -149,13 +149,53 @@ class Auth:
|
||||
is invalid.
|
||||
AuthError if access is denied for the user in the access token
|
||||
"""
|
||||
parent_span = active_span()
|
||||
with start_active_span("get_user_by_req"):
|
||||
requester = await self._wrapped_get_user_by_req(
|
||||
request, allow_guest, rights, allow_expired
|
||||
)
|
||||
|
||||
if parent_span:
|
||||
if requester.authenticated_entity in self._force_tracing_for_users:
|
||||
# request tracing is enabled for this user, so we need to force it
|
||||
# tracing on for the parent span (which will be the servlet span).
|
||||
#
|
||||
# It's too late for the get_user_by_req span to inherit the setting,
|
||||
# so we also force it on for that.
|
||||
force_tracing()
|
||||
force_tracing(parent_span)
|
||||
parent_span.set_tag(
|
||||
"authenticated_entity", requester.authenticated_entity
|
||||
)
|
||||
parent_span.set_tag("user_id", requester.user.to_string())
|
||||
if requester.device_id is not None:
|
||||
parent_span.set_tag("device_id", requester.device_id)
|
||||
if requester.app_service is not None:
|
||||
parent_span.set_tag("appservice_id", requester.app_service.id)
|
||||
return requester
|
||||
|
||||
async def _wrapped_get_user_by_req(
|
||||
self,
|
||||
request: SynapseRequest,
|
||||
allow_guest: bool,
|
||||
rights: str,
|
||||
allow_expired: bool,
|
||||
) -> Requester:
|
||||
"""Helper for get_user_by_req
|
||||
|
||||
Once get_user_by_req has set up the opentracing span, this does the actual work.
|
||||
"""
|
||||
try:
|
||||
ip_addr = request.getClientIP()
|
||||
user_agent = get_request_user_agent(request)
|
||||
|
||||
access_token = self.get_access_token_from_request(request)
|
||||
|
||||
user_id, app_service = await self._get_appservice_user_id(request)
|
||||
(
|
||||
user_id,
|
||||
device_id,
|
||||
app_service,
|
||||
) = await self._get_appservice_user_id_and_device_id(request)
|
||||
if user_id and app_service:
|
||||
if ip_addr and self._track_appservice_user_ips:
|
||||
await self.store.insert_client_ip(
|
||||
@@ -163,18 +203,16 @@ class Auth:
|
||||
access_token=access_token,
|
||||
ip=ip_addr,
|
||||
user_agent=user_agent,
|
||||
device_id="dummy-device", # stubbed
|
||||
device_id="dummy-device"
|
||||
if device_id is None
|
||||
else device_id, # stubbed
|
||||
)
|
||||
|
||||
requester = create_requester(user_id, app_service=app_service)
|
||||
requester = create_requester(
|
||||
user_id, app_service=app_service, device_id=device_id
|
||||
)
|
||||
|
||||
request.requester = user_id
|
||||
if user_id in self._force_tracing_for_users:
|
||||
opentracing.force_tracing()
|
||||
opentracing.set_tag("authenticated_entity", user_id)
|
||||
opentracing.set_tag("user_id", user_id)
|
||||
opentracing.set_tag("appservice_id", app_service.id)
|
||||
|
||||
return requester
|
||||
|
||||
user_info = await self.get_user_by_access_token(
|
||||
@@ -232,13 +270,6 @@ class Auth:
|
||||
)
|
||||
|
||||
request.requester = requester
|
||||
if user_info.token_owner in self._force_tracing_for_users:
|
||||
opentracing.force_tracing()
|
||||
opentracing.set_tag("authenticated_entity", user_info.token_owner)
|
||||
opentracing.set_tag("user_id", user_info.user_id)
|
||||
if device_id:
|
||||
opentracing.set_tag("device_id", device_id)
|
||||
|
||||
return requester
|
||||
except KeyError:
|
||||
raise MissingClientTokenError()
|
||||
@@ -274,33 +305,81 @@ class Auth:
|
||||
403, "Application service has not registered this user (%s)" % user_id
|
||||
)
|
||||
|
||||
async def _get_appservice_user_id(
|
||||
async def _get_appservice_user_id_and_device_id(
|
||||
self, request: Request
|
||||
) -> Tuple[Optional[str], Optional[ApplicationService]]:
|
||||
) -> Tuple[Optional[str], Optional[str], Optional[ApplicationService]]:
|
||||
"""
|
||||
Given a request, reads the request parameters to determine:
|
||||
- whether it's an application service that's making this request
|
||||
- what user the application service should be treated as controlling
|
||||
(the user_id URI parameter allows an application service to masquerade
|
||||
any applicable user in its namespace)
|
||||
- what device the application service should be treated as controlling
|
||||
(the device_id[^1] URI parameter allows an application service to masquerade
|
||||
as any device that exists for the relevant user)
|
||||
|
||||
[^1] Unstable and provided by MSC3202.
|
||||
Must use `org.matrix.msc3202.device_id` in place of `device_id` for now.
|
||||
|
||||
Returns:
|
||||
3-tuple of
|
||||
(user ID?, device ID?, application service?)
|
||||
|
||||
Postconditions:
|
||||
- If an application service is returned, so is a user ID
|
||||
- A user ID is never returned without an application service
|
||||
- A device ID is never returned without a user ID or an application service
|
||||
- The returned application service, if present, is permitted to control the
|
||||
returned user ID.
|
||||
- The returned device ID, if present, has been checked to be a valid device ID
|
||||
for the returned user ID.
|
||||
"""
|
||||
DEVICE_ID_ARG_NAME = b"org.matrix.msc3202.device_id"
|
||||
|
||||
app_service = self.store.get_app_service_by_token(
|
||||
self.get_access_token_from_request(request)
|
||||
)
|
||||
if app_service is None:
|
||||
return None, None
|
||||
return None, None, None
|
||||
|
||||
if app_service.ip_range_whitelist:
|
||||
ip_address = IPAddress(request.getClientIP())
|
||||
if ip_address not in app_service.ip_range_whitelist:
|
||||
return None, None
|
||||
return None, None, None
|
||||
|
||||
# This will always be set by the time Twisted calls us.
|
||||
assert request.args is not None
|
||||
|
||||
if b"user_id" not in request.args:
|
||||
return app_service.sender, app_service
|
||||
if b"user_id" in request.args:
|
||||
effective_user_id = request.args[b"user_id"][0].decode("utf8")
|
||||
await self.validate_appservice_can_control_user_id(
|
||||
app_service, effective_user_id
|
||||
)
|
||||
else:
|
||||
effective_user_id = app_service.sender
|
||||
|
||||
user_id = request.args[b"user_id"][0].decode("utf8")
|
||||
await self.validate_appservice_can_control_user_id(app_service, user_id)
|
||||
effective_device_id: Optional[str] = None
|
||||
|
||||
if app_service.sender == user_id:
|
||||
return app_service.sender, app_service
|
||||
if (
|
||||
self.hs.config.experimental.msc3202_device_masquerading_enabled
|
||||
and DEVICE_ID_ARG_NAME in request.args
|
||||
):
|
||||
effective_device_id = request.args[DEVICE_ID_ARG_NAME][0].decode("utf8")
|
||||
# We only just set this so it can't be None!
|
||||
assert effective_device_id is not None
|
||||
device_opt = await self.store.get_device(
|
||||
effective_user_id, effective_device_id
|
||||
)
|
||||
if device_opt is None:
|
||||
# For now, use 400 M_EXCLUSIVE if the device doesn't exist.
|
||||
# This is an open thread of discussion on MSC3202 as of 2021-12-09.
|
||||
raise AuthError(
|
||||
400,
|
||||
f"Application service trying to use a device that doesn't exist ('{effective_device_id}' for {effective_user_id})",
|
||||
Codes.EXCLUSIVE,
|
||||
)
|
||||
|
||||
return user_id, app_service
|
||||
return effective_user_id, effective_device_id, app_service
|
||||
|
||||
async def get_user_by_access_token(
|
||||
self,
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
"""Contains constants from the specification."""
|
||||
|
||||
from typing_extensions import Final
|
||||
|
||||
# the max size of a (canonical-json-encoded) event
|
||||
MAX_PDU_SIZE = 65536
|
||||
|
||||
@@ -39,125 +41,125 @@ class Membership:
|
||||
|
||||
"""Represents the membership states of a user in a room."""
|
||||
|
||||
INVITE = "invite"
|
||||
JOIN = "join"
|
||||
KNOCK = "knock"
|
||||
LEAVE = "leave"
|
||||
BAN = "ban"
|
||||
LIST = (INVITE, JOIN, KNOCK, LEAVE, BAN)
|
||||
INVITE: Final = "invite"
|
||||
JOIN: Final = "join"
|
||||
KNOCK: Final = "knock"
|
||||
LEAVE: Final = "leave"
|
||||
BAN: Final = "ban"
|
||||
LIST: Final = (INVITE, JOIN, KNOCK, LEAVE, BAN)
|
||||
|
||||
|
||||
class PresenceState:
|
||||
"""Represents the presence state of a user."""
|
||||
|
||||
OFFLINE = "offline"
|
||||
UNAVAILABLE = "unavailable"
|
||||
ONLINE = "online"
|
||||
BUSY = "org.matrix.msc3026.busy"
|
||||
OFFLINE: Final = "offline"
|
||||
UNAVAILABLE: Final = "unavailable"
|
||||
ONLINE: Final = "online"
|
||||
BUSY: Final = "org.matrix.msc3026.busy"
|
||||
|
||||
|
||||
class JoinRules:
|
||||
PUBLIC = "public"
|
||||
KNOCK = "knock"
|
||||
INVITE = "invite"
|
||||
PRIVATE = "private"
|
||||
PUBLIC: Final = "public"
|
||||
KNOCK: Final = "knock"
|
||||
INVITE: Final = "invite"
|
||||
PRIVATE: Final = "private"
|
||||
# As defined for MSC3083.
|
||||
RESTRICTED = "restricted"
|
||||
RESTRICTED: Final = "restricted"
|
||||
|
||||
|
||||
class RestrictedJoinRuleTypes:
|
||||
"""Understood types for the allow rules in restricted join rules."""
|
||||
|
||||
ROOM_MEMBERSHIP = "m.room_membership"
|
||||
ROOM_MEMBERSHIP: Final = "m.room_membership"
|
||||
|
||||
|
||||
class LoginType:
|
||||
PASSWORD = "m.login.password"
|
||||
EMAIL_IDENTITY = "m.login.email.identity"
|
||||
MSISDN = "m.login.msisdn"
|
||||
RECAPTCHA = "m.login.recaptcha"
|
||||
TERMS = "m.login.terms"
|
||||
SSO = "m.login.sso"
|
||||
DUMMY = "m.login.dummy"
|
||||
REGISTRATION_TOKEN = "org.matrix.msc3231.login.registration_token"
|
||||
PASSWORD: Final = "m.login.password"
|
||||
EMAIL_IDENTITY: Final = "m.login.email.identity"
|
||||
MSISDN: Final = "m.login.msisdn"
|
||||
RECAPTCHA: Final = "m.login.recaptcha"
|
||||
TERMS: Final = "m.login.terms"
|
||||
SSO: Final = "m.login.sso"
|
||||
DUMMY: Final = "m.login.dummy"
|
||||
REGISTRATION_TOKEN: Final = "org.matrix.msc3231.login.registration_token"
|
||||
|
||||
|
||||
# This is used in the `type` parameter for /register when called by
|
||||
# an appservice to register a new user.
|
||||
APP_SERVICE_REGISTRATION_TYPE = "m.login.application_service"
|
||||
APP_SERVICE_REGISTRATION_TYPE: Final = "m.login.application_service"
|
||||
|
||||
|
||||
class EventTypes:
|
||||
Member = "m.room.member"
|
||||
Create = "m.room.create"
|
||||
Tombstone = "m.room.tombstone"
|
||||
JoinRules = "m.room.join_rules"
|
||||
PowerLevels = "m.room.power_levels"
|
||||
Aliases = "m.room.aliases"
|
||||
Redaction = "m.room.redaction"
|
||||
ThirdPartyInvite = "m.room.third_party_invite"
|
||||
RelatedGroups = "m.room.related_groups"
|
||||
Member: Final = "m.room.member"
|
||||
Create: Final = "m.room.create"
|
||||
Tombstone: Final = "m.room.tombstone"
|
||||
JoinRules: Final = "m.room.join_rules"
|
||||
PowerLevels: Final = "m.room.power_levels"
|
||||
Aliases: Final = "m.room.aliases"
|
||||
Redaction: Final = "m.room.redaction"
|
||||
ThirdPartyInvite: Final = "m.room.third_party_invite"
|
||||
RelatedGroups: Final = "m.room.related_groups"
|
||||
|
||||
RoomHistoryVisibility = "m.room.history_visibility"
|
||||
CanonicalAlias = "m.room.canonical_alias"
|
||||
Encrypted = "m.room.encrypted"
|
||||
RoomAvatar = "m.room.avatar"
|
||||
RoomEncryption = "m.room.encryption"
|
||||
GuestAccess = "m.room.guest_access"
|
||||
RoomHistoryVisibility: Final = "m.room.history_visibility"
|
||||
CanonicalAlias: Final = "m.room.canonical_alias"
|
||||
Encrypted: Final = "m.room.encrypted"
|
||||
RoomAvatar: Final = "m.room.avatar"
|
||||
RoomEncryption: Final = "m.room.encryption"
|
||||
GuestAccess: Final = "m.room.guest_access"
|
||||
|
||||
# These are used for validation
|
||||
Message = "m.room.message"
|
||||
Topic = "m.room.topic"
|
||||
Name = "m.room.name"
|
||||
Message: Final = "m.room.message"
|
||||
Topic: Final = "m.room.topic"
|
||||
Name: Final = "m.room.name"
|
||||
|
||||
ServerACL = "m.room.server_acl"
|
||||
Pinned = "m.room.pinned_events"
|
||||
ServerACL: Final = "m.room.server_acl"
|
||||
Pinned: Final = "m.room.pinned_events"
|
||||
|
||||
Retention = "m.room.retention"
|
||||
Retention: Final = "m.room.retention"
|
||||
|
||||
Dummy = "org.matrix.dummy_event"
|
||||
Dummy: Final = "org.matrix.dummy_event"
|
||||
|
||||
SpaceChild = "m.space.child"
|
||||
SpaceParent = "m.space.parent"
|
||||
SpaceChild: Final = "m.space.child"
|
||||
SpaceParent: Final = "m.space.parent"
|
||||
|
||||
MSC2716_INSERTION = "org.matrix.msc2716.insertion"
|
||||
MSC2716_BATCH = "org.matrix.msc2716.batch"
|
||||
MSC2716_MARKER = "org.matrix.msc2716.marker"
|
||||
MSC2716_INSERTION: Final = "org.matrix.msc2716.insertion"
|
||||
MSC2716_BATCH: Final = "org.matrix.msc2716.batch"
|
||||
MSC2716_MARKER: Final = "org.matrix.msc2716.marker"
|
||||
|
||||
|
||||
class ToDeviceEventTypes:
|
||||
RoomKeyRequest = "m.room_key_request"
|
||||
RoomKeyRequest: Final = "m.room_key_request"
|
||||
|
||||
|
||||
class DeviceKeyAlgorithms:
|
||||
"""Spec'd algorithms for the generation of per-device keys"""
|
||||
|
||||
ED25519 = "ed25519"
|
||||
CURVE25519 = "curve25519"
|
||||
SIGNED_CURVE25519 = "signed_curve25519"
|
||||
ED25519: Final = "ed25519"
|
||||
CURVE25519: Final = "curve25519"
|
||||
SIGNED_CURVE25519: Final = "signed_curve25519"
|
||||
|
||||
|
||||
class EduTypes:
|
||||
Presence = "m.presence"
|
||||
Presence: Final = "m.presence"
|
||||
|
||||
|
||||
class RejectedReason:
|
||||
AUTH_ERROR = "auth_error"
|
||||
AUTH_ERROR: Final = "auth_error"
|
||||
|
||||
|
||||
class RoomCreationPreset:
|
||||
PRIVATE_CHAT = "private_chat"
|
||||
PUBLIC_CHAT = "public_chat"
|
||||
TRUSTED_PRIVATE_CHAT = "trusted_private_chat"
|
||||
PRIVATE_CHAT: Final = "private_chat"
|
||||
PUBLIC_CHAT: Final = "public_chat"
|
||||
TRUSTED_PRIVATE_CHAT: Final = "trusted_private_chat"
|
||||
|
||||
|
||||
class ThirdPartyEntityKind:
|
||||
USER = "user"
|
||||
LOCATION = "location"
|
||||
USER: Final = "user"
|
||||
LOCATION: Final = "location"
|
||||
|
||||
|
||||
ServerNoticeMsgType = "m.server_notice"
|
||||
ServerNoticeLimitReached = "m.server_notice.usage_limit_reached"
|
||||
ServerNoticeMsgType: Final = "m.server_notice"
|
||||
ServerNoticeLimitReached: Final = "m.server_notice.usage_limit_reached"
|
||||
|
||||
|
||||
class UserTypes:
|
||||
@@ -165,91 +167,95 @@ class UserTypes:
|
||||
'admin' and 'guest' users should also be UserTypes. Normal users are type None
|
||||
"""
|
||||
|
||||
SUPPORT = "support"
|
||||
BOT = "bot"
|
||||
ALL_USER_TYPES = (SUPPORT, BOT)
|
||||
SUPPORT: Final = "support"
|
||||
BOT: Final = "bot"
|
||||
ALL_USER_TYPES: Final = (SUPPORT, BOT)
|
||||
|
||||
|
||||
class RelationTypes:
|
||||
"""The types of relations known to this server."""
|
||||
|
||||
ANNOTATION = "m.annotation"
|
||||
REPLACE = "m.replace"
|
||||
REFERENCE = "m.reference"
|
||||
THREAD = "io.element.thread"
|
||||
ANNOTATION: Final = "m.annotation"
|
||||
REPLACE: Final = "m.replace"
|
||||
REFERENCE: Final = "m.reference"
|
||||
THREAD: Final = "io.element.thread"
|
||||
|
||||
|
||||
class LimitBlockingTypes:
|
||||
"""Reasons that a server may be blocked"""
|
||||
|
||||
MONTHLY_ACTIVE_USER = "monthly_active_user"
|
||||
HS_DISABLED = "hs_disabled"
|
||||
MONTHLY_ACTIVE_USER: Final = "monthly_active_user"
|
||||
HS_DISABLED: Final = "hs_disabled"
|
||||
|
||||
|
||||
class EventContentFields:
|
||||
"""Fields found in events' content, regardless of type."""
|
||||
|
||||
# Labels for the event, cf https://github.com/matrix-org/matrix-doc/pull/2326
|
||||
LABELS = "org.matrix.labels"
|
||||
LABELS: Final = "org.matrix.labels"
|
||||
|
||||
# Timestamp to delete the event after
|
||||
# cf https://github.com/matrix-org/matrix-doc/pull/2228
|
||||
SELF_DESTRUCT_AFTER = "org.matrix.self_destruct_after"
|
||||
SELF_DESTRUCT_AFTER: Final = "org.matrix.self_destruct_after"
|
||||
|
||||
# cf https://github.com/matrix-org/matrix-doc/pull/1772
|
||||
ROOM_TYPE = "type"
|
||||
ROOM_TYPE: Final = "type"
|
||||
|
||||
# Whether a room can federate.
|
||||
FEDERATE = "m.federate"
|
||||
FEDERATE: Final = "m.federate"
|
||||
|
||||
# The creator of the room, as used in `m.room.create` events.
|
||||
ROOM_CREATOR = "creator"
|
||||
ROOM_CREATOR: Final = "creator"
|
||||
|
||||
# Used in m.room.guest_access events.
|
||||
GUEST_ACCESS = "guest_access"
|
||||
GUEST_ACCESS: Final = "guest_access"
|
||||
|
||||
# Used on normal messages to indicate they were historically imported after the fact
|
||||
MSC2716_HISTORICAL = "org.matrix.msc2716.historical"
|
||||
MSC2716_HISTORICAL: Final = "org.matrix.msc2716.historical"
|
||||
# For "insertion" events to indicate what the next batch ID should be in
|
||||
# order to connect to it
|
||||
MSC2716_NEXT_BATCH_ID = "org.matrix.msc2716.next_batch_id"
|
||||
MSC2716_NEXT_BATCH_ID: Final = "org.matrix.msc2716.next_batch_id"
|
||||
# Used on "batch" events to indicate which insertion event it connects to
|
||||
MSC2716_BATCH_ID = "org.matrix.msc2716.batch_id"
|
||||
MSC2716_BATCH_ID: Final = "org.matrix.msc2716.batch_id"
|
||||
# For "marker" events
|
||||
MSC2716_MARKER_INSERTION = "org.matrix.msc2716.marker.insertion"
|
||||
MSC2716_MARKER_INSERTION: Final = "org.matrix.msc2716.marker.insertion"
|
||||
|
||||
# The authorising user for joining a restricted room.
|
||||
AUTHORISING_USER = "join_authorised_via_users_server"
|
||||
AUTHORISING_USER: Final = "join_authorised_via_users_server"
|
||||
|
||||
|
||||
class RoomTypes:
|
||||
"""Understood values of the room_type field of m.room.create events."""
|
||||
|
||||
SPACE = "m.space"
|
||||
SPACE: Final = "m.space"
|
||||
|
||||
|
||||
class RoomEncryptionAlgorithms:
|
||||
MEGOLM_V1_AES_SHA2 = "m.megolm.v1.aes-sha2"
|
||||
DEFAULT = MEGOLM_V1_AES_SHA2
|
||||
MEGOLM_V1_AES_SHA2: Final = "m.megolm.v1.aes-sha2"
|
||||
DEFAULT: Final = MEGOLM_V1_AES_SHA2
|
||||
|
||||
|
||||
class AccountDataTypes:
|
||||
DIRECT = "m.direct"
|
||||
IGNORED_USER_LIST = "m.ignored_user_list"
|
||||
DIRECT: Final = "m.direct"
|
||||
IGNORED_USER_LIST: Final = "m.ignored_user_list"
|
||||
|
||||
|
||||
class HistoryVisibility:
|
||||
INVITED = "invited"
|
||||
JOINED = "joined"
|
||||
SHARED = "shared"
|
||||
WORLD_READABLE = "world_readable"
|
||||
INVITED: Final = "invited"
|
||||
JOINED: Final = "joined"
|
||||
SHARED: Final = "shared"
|
||||
WORLD_READABLE: Final = "world_readable"
|
||||
|
||||
|
||||
class GuestAccess:
|
||||
CAN_JOIN = "can_join"
|
||||
CAN_JOIN: Final = "can_join"
|
||||
# anything that is not "can_join" is considered "forbidden", but for completeness:
|
||||
FORBIDDEN = "forbidden"
|
||||
FORBIDDEN: Final = "forbidden"
|
||||
|
||||
|
||||
class ReceiptTypes:
|
||||
READ: Final = "m.read"
|
||||
|
||||
|
||||
class ReadReceiptEventFields:
|
||||
MSC2285_HIDDEN = "org.matrix.msc2285.hidden"
|
||||
MSC2285_HIDDEN: Final = "org.matrix.msc2285.hidden"
|
||||
|
||||
@@ -351,8 +351,7 @@ class Filter:
|
||||
True if the event matches the filter.
|
||||
"""
|
||||
# We usually get the full "events" as dictionaries coming through,
|
||||
# except for presence which actually gets passed around as its own
|
||||
# namedtuple type.
|
||||
# except for presence which actually gets passed around as its own type.
|
||||
if isinstance(event, UserPresenceState):
|
||||
user_id = event.user_id
|
||||
field_matchers = {
|
||||
|
||||
@@ -30,7 +30,8 @@ FEDERATION_UNSTABLE_PREFIX = FEDERATION_PREFIX + "/unstable"
|
||||
STATIC_PREFIX = "/_matrix/static"
|
||||
WEB_CLIENT_PREFIX = "/_matrix/client"
|
||||
SERVER_KEY_V2_PREFIX = "/_matrix/key/v2"
|
||||
MEDIA_PREFIX = "/_matrix/media/r0"
|
||||
MEDIA_R0_PREFIX = "/_matrix/media/r0"
|
||||
MEDIA_V3_PREFIX = "/_matrix/media/v3"
|
||||
LEGACY_MEDIA_PREFIX = "/_matrix/media/v1"
|
||||
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ from typing import (
|
||||
Iterable,
|
||||
List,
|
||||
NoReturn,
|
||||
Optional,
|
||||
Tuple,
|
||||
cast,
|
||||
)
|
||||
@@ -129,7 +130,7 @@ def start_worker_reactor(
|
||||
def start_reactor(
|
||||
appname: str,
|
||||
soft_file_limit: int,
|
||||
gc_thresholds: Tuple[int, int, int],
|
||||
gc_thresholds: Optional[Tuple[int, int, int]],
|
||||
pid_file: str,
|
||||
daemonize: bool,
|
||||
print_pidfile: bool,
|
||||
@@ -402,7 +403,7 @@ async def start(hs: "HomeServer") -> None:
|
||||
if hasattr(signal, "SIGHUP"):
|
||||
|
||||
@wrap_as_background_process("sighup")
|
||||
def handle_sighup(*args: Any, **kwargs: Any) -> None:
|
||||
async def handle_sighup(*args: Any, **kwargs: Any) -> None:
|
||||
# Tell systemd our state, if we're using it. This will silently fail if
|
||||
# we're not using systemd.
|
||||
sdnotify(b"RELOADING=1")
|
||||
|
||||
@@ -26,7 +26,8 @@ from synapse.api.urls import (
|
||||
CLIENT_API_PREFIX,
|
||||
FEDERATION_PREFIX,
|
||||
LEGACY_MEDIA_PREFIX,
|
||||
MEDIA_PREFIX,
|
||||
MEDIA_R0_PREFIX,
|
||||
MEDIA_V3_PREFIX,
|
||||
SERVER_KEY_V2_PREFIX,
|
||||
)
|
||||
from synapse.app import _base
|
||||
@@ -112,6 +113,7 @@ from synapse.storage.databases.main.monthly_active_users import (
|
||||
)
|
||||
from synapse.storage.databases.main.presence import PresenceStore
|
||||
from synapse.storage.databases.main.room import RoomWorkerStore
|
||||
from synapse.storage.databases.main.room_batch import RoomBatchStore
|
||||
from synapse.storage.databases.main.search import SearchStore
|
||||
from synapse.storage.databases.main.session import SessionStore
|
||||
from synapse.storage.databases.main.stats import StatsStore
|
||||
@@ -239,6 +241,7 @@ class GenericWorkerSlavedStore(
|
||||
SlavedEventStore,
|
||||
SlavedKeyStore,
|
||||
RoomWorkerStore,
|
||||
RoomBatchStore,
|
||||
DirectoryStore,
|
||||
SlavedApplicationServiceStore,
|
||||
SlavedRegistrationStore,
|
||||
@@ -338,7 +341,8 @@ class GenericWorkerServer(HomeServer):
|
||||
|
||||
resources.update(
|
||||
{
|
||||
MEDIA_PREFIX: media_repo,
|
||||
MEDIA_R0_PREFIX: media_repo,
|
||||
MEDIA_V3_PREFIX: media_repo,
|
||||
LEGACY_MEDIA_PREFIX: media_repo,
|
||||
"/_synapse/admin": admin_resource,
|
||||
}
|
||||
@@ -501,6 +505,10 @@ def start(config_options: List[str]) -> None:
|
||||
_base.start_worker_reactor("synapse-generic-worker", config)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def main() -> None:
|
||||
with LoggingContext("main"):
|
||||
start(sys.argv[1:])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -29,7 +29,8 @@ from synapse import events
|
||||
from synapse.api.urls import (
|
||||
FEDERATION_PREFIX,
|
||||
LEGACY_MEDIA_PREFIX,
|
||||
MEDIA_PREFIX,
|
||||
MEDIA_R0_PREFIX,
|
||||
MEDIA_V3_PREFIX,
|
||||
SERVER_KEY_V2_PREFIX,
|
||||
STATIC_PREFIX,
|
||||
WEB_CLIENT_PREFIX,
|
||||
@@ -193,6 +194,8 @@ class SynapseHomeServer(HomeServer):
|
||||
{
|
||||
"/_matrix/client/api/v1": client_resource,
|
||||
"/_matrix/client/r0": client_resource,
|
||||
"/_matrix/client/v1": client_resource,
|
||||
"/_matrix/client/v3": client_resource,
|
||||
"/_matrix/client/unstable": client_resource,
|
||||
"/_matrix/client/v2_alpha": client_resource,
|
||||
"/_matrix/client/versions": client_resource,
|
||||
@@ -244,7 +247,11 @@ class SynapseHomeServer(HomeServer):
|
||||
if self.config.server.enable_media_repo:
|
||||
media_repo = self.get_media_repository_resource()
|
||||
resources.update(
|
||||
{MEDIA_PREFIX: media_repo, LEGACY_MEDIA_PREFIX: media_repo}
|
||||
{
|
||||
MEDIA_R0_PREFIX: media_repo,
|
||||
MEDIA_V3_PREFIX: media_repo,
|
||||
LEGACY_MEDIA_PREFIX: media_repo,
|
||||
}
|
||||
)
|
||||
elif name == "media":
|
||||
raise ConfigError(
|
||||
@@ -351,6 +358,13 @@ def setup(config_options: List[str]) -> SynapseHomeServer:
|
||||
# generating config files and shouldn't try to continue.
|
||||
sys.exit(0)
|
||||
|
||||
if config.worker.worker_app:
|
||||
raise ConfigError(
|
||||
"You have specified `worker_app` in the config but are attempting to start a non-worker "
|
||||
"instance. Please use `python -m synapse.app.generic_worker` instead (or remove the option if this is the main process)."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
events.USE_FROZEN_DICTS = config.server.use_frozen_dicts
|
||||
synapse.util.caches.TRACK_MEMORY_USAGE = config.caches.track_memory_usage
|
||||
|
||||
|
||||
@@ -11,9 +11,14 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Iterable, List, Match, Optional
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Pattern
|
||||
|
||||
import attr
|
||||
from netaddr import IPSet
|
||||
|
||||
from synapse.api.constants import EventTypes
|
||||
from synapse.events import EventBase
|
||||
@@ -27,11 +32,18 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApplicationServiceState:
|
||||
class ApplicationServiceState(Enum):
|
||||
DOWN = "down"
|
||||
UP = "up"
|
||||
|
||||
|
||||
@attr.s(slots=True, frozen=True, auto_attribs=True)
|
||||
class Namespace:
|
||||
exclusive: bool
|
||||
group_id: Optional[str]
|
||||
regex: Pattern[str]
|
||||
|
||||
|
||||
class ApplicationService:
|
||||
"""Defines an application service. This definition is mostly what is
|
||||
provided to the /register AS API.
|
||||
@@ -49,17 +61,17 @@ class ApplicationService:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
token,
|
||||
hostname,
|
||||
id,
|
||||
sender,
|
||||
url=None,
|
||||
namespaces=None,
|
||||
hs_token=None,
|
||||
protocols=None,
|
||||
rate_limited=True,
|
||||
ip_range_whitelist=None,
|
||||
supports_ephemeral=False,
|
||||
token: str,
|
||||
hostname: str,
|
||||
id: str,
|
||||
sender: str,
|
||||
url: Optional[str] = None,
|
||||
namespaces: Optional[JsonDict] = None,
|
||||
hs_token: Optional[str] = None,
|
||||
protocols: Optional[Iterable[str]] = None,
|
||||
rate_limited: bool = True,
|
||||
ip_range_whitelist: Optional[IPSet] = None,
|
||||
supports_ephemeral: bool = False,
|
||||
):
|
||||
self.token = token
|
||||
self.url = (
|
||||
@@ -84,27 +96,33 @@ class ApplicationService:
|
||||
|
||||
self.rate_limited = rate_limited
|
||||
|
||||
def _check_namespaces(self, namespaces):
|
||||
def _check_namespaces(
|
||||
self, namespaces: Optional[JsonDict]
|
||||
) -> Dict[str, List[Namespace]]:
|
||||
# Sanity check that it is of the form:
|
||||
# {
|
||||
# users: [ {regex: "[A-z]+.*", exclusive: true}, ...],
|
||||
# aliases: [ {regex: "[A-z]+.*", exclusive: true}, ...],
|
||||
# rooms: [ {regex: "[A-z]+.*", exclusive: true}, ...],
|
||||
# }
|
||||
if not namespaces:
|
||||
if namespaces is None:
|
||||
namespaces = {}
|
||||
|
||||
result: Dict[str, List[Namespace]] = {}
|
||||
|
||||
for ns in ApplicationService.NS_LIST:
|
||||
result[ns] = []
|
||||
|
||||
if ns not in namespaces:
|
||||
namespaces[ns] = []
|
||||
continue
|
||||
|
||||
if type(namespaces[ns]) != list:
|
||||
if not isinstance(namespaces[ns], list):
|
||||
raise ValueError("Bad namespace value for '%s'" % ns)
|
||||
for regex_obj in namespaces[ns]:
|
||||
if not isinstance(regex_obj, dict):
|
||||
raise ValueError("Expected dict regex for ns '%s'" % ns)
|
||||
if not isinstance(regex_obj.get("exclusive"), bool):
|
||||
exclusive = regex_obj.get("exclusive")
|
||||
if not isinstance(exclusive, bool):
|
||||
raise ValueError("Expected bool for 'exclusive' in ns '%s'" % ns)
|
||||
group_id = regex_obj.get("group_id")
|
||||
if group_id:
|
||||
@@ -125,22 +143,26 @@ class ApplicationService:
|
||||
)
|
||||
|
||||
regex = regex_obj.get("regex")
|
||||
if isinstance(regex, str):
|
||||
regex_obj["regex"] = re.compile(regex) # Pre-compile regex
|
||||
else:
|
||||
if not isinstance(regex, str):
|
||||
raise ValueError("Expected string for 'regex' in ns '%s'" % ns)
|
||||
return namespaces
|
||||
|
||||
def _matches_regex(self, test_string: str, namespace_key: str) -> Optional[Match]:
|
||||
for regex_obj in self.namespaces[namespace_key]:
|
||||
if regex_obj["regex"].match(test_string):
|
||||
return regex_obj
|
||||
# Pre-compile regex.
|
||||
result[ns].append(Namespace(exclusive, group_id, re.compile(regex)))
|
||||
|
||||
return result
|
||||
|
||||
def _matches_regex(
|
||||
self, namespace_key: str, test_string: str
|
||||
) -> Optional[Namespace]:
|
||||
for namespace in self.namespaces[namespace_key]:
|
||||
if namespace.regex.match(test_string):
|
||||
return namespace
|
||||
return None
|
||||
|
||||
def _is_exclusive(self, ns_key: str, test_string: str) -> bool:
|
||||
regex_obj = self._matches_regex(test_string, ns_key)
|
||||
if regex_obj:
|
||||
return regex_obj["exclusive"]
|
||||
def _is_exclusive(self, namespace_key: str, test_string: str) -> bool:
|
||||
namespace = self._matches_regex(namespace_key, test_string)
|
||||
if namespace:
|
||||
return namespace.exclusive
|
||||
return False
|
||||
|
||||
async def _matches_user(
|
||||
@@ -259,15 +281,15 @@ class ApplicationService:
|
||||
|
||||
def is_interested_in_user(self, user_id: str) -> bool:
|
||||
return (
|
||||
bool(self._matches_regex(user_id, ApplicationService.NS_USERS))
|
||||
bool(self._matches_regex(ApplicationService.NS_USERS, user_id))
|
||||
or user_id == self.sender
|
||||
)
|
||||
|
||||
def is_interested_in_alias(self, alias: str) -> bool:
|
||||
return bool(self._matches_regex(alias, ApplicationService.NS_ALIASES))
|
||||
return bool(self._matches_regex(ApplicationService.NS_ALIASES, alias))
|
||||
|
||||
def is_interested_in_room(self, room_id: str) -> bool:
|
||||
return bool(self._matches_regex(room_id, ApplicationService.NS_ROOMS))
|
||||
return bool(self._matches_regex(ApplicationService.NS_ROOMS, room_id))
|
||||
|
||||
def is_exclusive_user(self, user_id: str) -> bool:
|
||||
return (
|
||||
@@ -284,14 +306,14 @@ class ApplicationService:
|
||||
def is_exclusive_room(self, room_id: str) -> bool:
|
||||
return self._is_exclusive(ApplicationService.NS_ROOMS, room_id)
|
||||
|
||||
def get_exclusive_user_regexes(self):
|
||||
def get_exclusive_user_regexes(self) -> List[Pattern[str]]:
|
||||
"""Get the list of regexes used to determine if a user is exclusively
|
||||
registered by the AS
|
||||
"""
|
||||
return [
|
||||
regex_obj["regex"]
|
||||
for regex_obj in self.namespaces[ApplicationService.NS_USERS]
|
||||
if regex_obj["exclusive"]
|
||||
namespace.regex
|
||||
for namespace in self.namespaces[ApplicationService.NS_USERS]
|
||||
if namespace.exclusive
|
||||
]
|
||||
|
||||
def get_groups_for_user(self, user_id: str) -> Iterable[str]:
|
||||
@@ -304,15 +326,15 @@ class ApplicationService:
|
||||
An iterable that yields group_id strings.
|
||||
"""
|
||||
return (
|
||||
regex_obj["group_id"]
|
||||
for regex_obj in self.namespaces[ApplicationService.NS_USERS]
|
||||
if "group_id" in regex_obj and regex_obj["regex"].match(user_id)
|
||||
namespace.group_id
|
||||
for namespace in self.namespaces[ApplicationService.NS_USERS]
|
||||
if namespace.group_id and namespace.regex.match(user_id)
|
||||
)
|
||||
|
||||
def is_rate_limited(self) -> bool:
|
||||
return self.rate_limited
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
# copy dictionary and redact token fields so they don't get logged
|
||||
dict_copy = self.__dict__.copy()
|
||||
dict_copy["token"] = "<redacted>"
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import logging
|
||||
import urllib
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
import urllib.parse
|
||||
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple
|
||||
|
||||
from prometheus_client import Counter
|
||||
|
||||
@@ -53,7 +53,7 @@ HOUR_IN_MS = 60 * 60 * 1000
|
||||
APP_SERVICE_PREFIX = "/_matrix/app/unstable"
|
||||
|
||||
|
||||
def _is_valid_3pe_metadata(info):
|
||||
def _is_valid_3pe_metadata(info: JsonDict) -> bool:
|
||||
if "instances" not in info:
|
||||
return False
|
||||
if not isinstance(info["instances"], list):
|
||||
@@ -61,7 +61,7 @@ def _is_valid_3pe_metadata(info):
|
||||
return True
|
||||
|
||||
|
||||
def _is_valid_3pe_result(r, field):
|
||||
def _is_valid_3pe_result(r: JsonDict, field: str) -> bool:
|
||||
if not isinstance(r, dict):
|
||||
return False
|
||||
|
||||
@@ -93,9 +93,13 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
hs.get_clock(), "as_protocol_meta", timeout_ms=HOUR_IN_MS
|
||||
)
|
||||
|
||||
async def query_user(self, service, user_id):
|
||||
async def query_user(self, service: "ApplicationService", user_id: str) -> bool:
|
||||
if service.url is None:
|
||||
return False
|
||||
|
||||
# This is required by the configuration.
|
||||
assert service.hs_token is not None
|
||||
|
||||
uri = service.url + ("/users/%s" % urllib.parse.quote(user_id))
|
||||
try:
|
||||
response = await self.get_json(uri, {"access_token": service.hs_token})
|
||||
@@ -109,9 +113,13 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
logger.warning("query_user to %s threw exception %s", uri, ex)
|
||||
return False
|
||||
|
||||
async def query_alias(self, service, alias):
|
||||
async def query_alias(self, service: "ApplicationService", alias: str) -> bool:
|
||||
if service.url is None:
|
||||
return False
|
||||
|
||||
# This is required by the configuration.
|
||||
assert service.hs_token is not None
|
||||
|
||||
uri = service.url + ("/rooms/%s" % urllib.parse.quote(alias))
|
||||
try:
|
||||
response = await self.get_json(uri, {"access_token": service.hs_token})
|
||||
@@ -125,7 +133,13 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
logger.warning("query_alias to %s threw exception %s", uri, ex)
|
||||
return False
|
||||
|
||||
async def query_3pe(self, service, kind, protocol, fields):
|
||||
async def query_3pe(
|
||||
self,
|
||||
service: "ApplicationService",
|
||||
kind: str,
|
||||
protocol: str,
|
||||
fields: Dict[bytes, List[bytes]],
|
||||
) -> List[JsonDict]:
|
||||
if kind == ThirdPartyEntityKind.USER:
|
||||
required_field = "userid"
|
||||
elif kind == ThirdPartyEntityKind.LOCATION:
|
||||
@@ -205,11 +219,14 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
events: List[EventBase],
|
||||
ephemeral: List[JsonDict],
|
||||
txn_id: Optional[int] = None,
|
||||
):
|
||||
) -> bool:
|
||||
if service.url is None:
|
||||
return True
|
||||
|
||||
events = self._serialize(service, events)
|
||||
# This is required by the configuration.
|
||||
assert service.hs_token is not None
|
||||
|
||||
serialized_events = self._serialize(service, events)
|
||||
|
||||
if txn_id is None:
|
||||
logger.warning(
|
||||
@@ -221,9 +238,12 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
|
||||
# Never send ephemeral events to appservices that do not support it
|
||||
if service.supports_ephemeral:
|
||||
body = {"events": events, "de.sorunome.msc2409.ephemeral": ephemeral}
|
||||
body = {
|
||||
"events": serialized_events,
|
||||
"de.sorunome.msc2409.ephemeral": ephemeral,
|
||||
}
|
||||
else:
|
||||
body = {"events": events}
|
||||
body = {"events": serialized_events}
|
||||
|
||||
try:
|
||||
await self.put_json(
|
||||
@@ -231,17 +251,38 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
json_body=body,
|
||||
args={"access_token": service.hs_token},
|
||||
)
|
||||
if logger.isEnabledFor(logging.DEBUG):
|
||||
logger.debug(
|
||||
"push_bulk to %s succeeded! events=%s",
|
||||
uri,
|
||||
[event.get("event_id") for event in events],
|
||||
)
|
||||
sent_transactions_counter.labels(service.id).inc()
|
||||
sent_events_counter.labels(service.id).inc(len(events))
|
||||
sent_events_counter.labels(service.id).inc(len(serialized_events))
|
||||
return True
|
||||
except CodeMessageException as e:
|
||||
logger.warning("push_bulk to %s received %s", uri, e.code)
|
||||
logger.warning(
|
||||
"push_bulk to %s received code=%s msg=%s",
|
||||
uri,
|
||||
e.code,
|
||||
e.msg,
|
||||
exc_info=logger.isEnabledFor(logging.DEBUG),
|
||||
)
|
||||
except Exception as ex:
|
||||
logger.warning("push_bulk to %s threw exception %s", uri, ex)
|
||||
logger.warning(
|
||||
"push_bulk to %s threw exception(%s) %s args=%s",
|
||||
uri,
|
||||
type(ex).__name__,
|
||||
ex,
|
||||
ex.args,
|
||||
exc_info=logger.isEnabledFor(logging.DEBUG),
|
||||
)
|
||||
failed_transactions_counter.labels(service.id).inc()
|
||||
return False
|
||||
|
||||
def _serialize(self, service, events):
|
||||
def _serialize(
|
||||
self, service: "ApplicationService", events: Iterable[EventBase]
|
||||
) -> List[JsonDict]:
|
||||
time_now = self.clock.time_msec()
|
||||
return [
|
||||
serialize_event(
|
||||
|
||||
@@ -48,13 +48,19 @@ This is all tied together by the AppServiceScheduler which DIs the required
|
||||
components.
|
||||
"""
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Optional, Set
|
||||
|
||||
from synapse.appservice import ApplicationService, ApplicationServiceState
|
||||
from synapse.appservice.api import ApplicationServiceApi
|
||||
from synapse.events import EventBase
|
||||
from synapse.logging.context import run_in_background
|
||||
from synapse.metrics.background_process_metrics import run_as_background_process
|
||||
from synapse.storage.databases.main import DataStore
|
||||
from synapse.types import JsonDict
|
||||
from synapse.util import Clock
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from synapse.server import HomeServer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -72,7 +78,7 @@ class ApplicationServiceScheduler:
|
||||
case is a simple array.
|
||||
"""
|
||||
|
||||
def __init__(self, hs):
|
||||
def __init__(self, hs: "HomeServer"):
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
self.as_api = hs.get_application_service_api()
|
||||
@@ -80,7 +86,7 @@ class ApplicationServiceScheduler:
|
||||
self.txn_ctrl = _TransactionController(self.clock, self.store, self.as_api)
|
||||
self.queuer = _ServiceQueuer(self.txn_ctrl, self.clock)
|
||||
|
||||
async def start(self):
|
||||
async def start(self) -> None:
|
||||
logger.info("Starting appservice scheduler")
|
||||
|
||||
# check for any DOWN ASes and start recoverers for them.
|
||||
@@ -91,12 +97,14 @@ class ApplicationServiceScheduler:
|
||||
for service in services:
|
||||
self.txn_ctrl.start_recoverer(service)
|
||||
|
||||
def submit_event_for_as(self, service: ApplicationService, event: EventBase):
|
||||
def submit_event_for_as(
|
||||
self, service: ApplicationService, event: EventBase
|
||||
) -> None:
|
||||
self.queuer.enqueue_event(service, event)
|
||||
|
||||
def submit_ephemeral_events_for_as(
|
||||
self, service: ApplicationService, events: List[JsonDict]
|
||||
):
|
||||
) -> None:
|
||||
self.queuer.enqueue_ephemeral(service, events)
|
||||
|
||||
|
||||
@@ -108,16 +116,18 @@ class _ServiceQueuer:
|
||||
appservice at a given time.
|
||||
"""
|
||||
|
||||
def __init__(self, txn_ctrl, clock):
|
||||
self.queued_events = {} # dict of {service_id: [events]}
|
||||
self.queued_ephemeral = {} # dict of {service_id: [events]}
|
||||
def __init__(self, txn_ctrl: "_TransactionController", clock: Clock):
|
||||
# dict of {service_id: [events]}
|
||||
self.queued_events: Dict[str, List[EventBase]] = {}
|
||||
# dict of {service_id: [events]}
|
||||
self.queued_ephemeral: Dict[str, List[JsonDict]] = {}
|
||||
|
||||
# the appservices which currently have a transaction in flight
|
||||
self.requests_in_flight = set()
|
||||
self.requests_in_flight: Set[str] = set()
|
||||
self.txn_ctrl = txn_ctrl
|
||||
self.clock = clock
|
||||
|
||||
def _start_background_request(self, service):
|
||||
def _start_background_request(self, service: ApplicationService) -> None:
|
||||
# start a sender for this appservice if we don't already have one
|
||||
if service.id in self.requests_in_flight:
|
||||
return
|
||||
@@ -126,15 +136,17 @@ class _ServiceQueuer:
|
||||
"as-sender-%s" % (service.id,), self._send_request, service
|
||||
)
|
||||
|
||||
def enqueue_event(self, service: ApplicationService, event: EventBase):
|
||||
def enqueue_event(self, service: ApplicationService, event: EventBase) -> None:
|
||||
self.queued_events.setdefault(service.id, []).append(event)
|
||||
self._start_background_request(service)
|
||||
|
||||
def enqueue_ephemeral(self, service: ApplicationService, events: List[JsonDict]):
|
||||
def enqueue_ephemeral(
|
||||
self, service: ApplicationService, events: List[JsonDict]
|
||||
) -> None:
|
||||
self.queued_ephemeral.setdefault(service.id, []).extend(events)
|
||||
self._start_background_request(service)
|
||||
|
||||
async def _send_request(self, service: ApplicationService):
|
||||
async def _send_request(self, service: ApplicationService) -> None:
|
||||
# sanity-check: we shouldn't get here if this service already has a sender
|
||||
# running.
|
||||
assert service.id not in self.requests_in_flight
|
||||
@@ -168,20 +180,15 @@ class _TransactionController:
|
||||
if a transaction fails.
|
||||
|
||||
(Note we have only have one of these in the homeserver.)
|
||||
|
||||
Args:
|
||||
clock (synapse.util.Clock):
|
||||
store (synapse.storage.DataStore):
|
||||
as_api (synapse.appservice.api.ApplicationServiceApi):
|
||||
"""
|
||||
|
||||
def __init__(self, clock, store, as_api):
|
||||
def __init__(self, clock: Clock, store: DataStore, as_api: ApplicationServiceApi):
|
||||
self.clock = clock
|
||||
self.store = store
|
||||
self.as_api = as_api
|
||||
|
||||
# map from service id to recoverer instance
|
||||
self.recoverers = {}
|
||||
self.recoverers: Dict[str, "_Recoverer"] = {}
|
||||
|
||||
# for UTs
|
||||
self.RECOVERER_CLASS = _Recoverer
|
||||
@@ -191,7 +198,7 @@ class _TransactionController:
|
||||
service: ApplicationService,
|
||||
events: List[EventBase],
|
||||
ephemeral: Optional[List[JsonDict]] = None,
|
||||
):
|
||||
) -> None:
|
||||
try:
|
||||
txn = await self.store.create_appservice_txn(
|
||||
service=service, events=events, ephemeral=ephemeral or []
|
||||
@@ -207,7 +214,7 @@ class _TransactionController:
|
||||
logger.exception("Error creating appservice transaction")
|
||||
run_in_background(self._on_txn_fail, service)
|
||||
|
||||
async def on_recovered(self, recoverer):
|
||||
async def on_recovered(self, recoverer: "_Recoverer") -> None:
|
||||
logger.info(
|
||||
"Successfully recovered application service AS ID %s", recoverer.service.id
|
||||
)
|
||||
@@ -217,18 +224,18 @@ class _TransactionController:
|
||||
recoverer.service, ApplicationServiceState.UP
|
||||
)
|
||||
|
||||
async def _on_txn_fail(self, service):
|
||||
async def _on_txn_fail(self, service: ApplicationService) -> None:
|
||||
try:
|
||||
await self.store.set_appservice_state(service, ApplicationServiceState.DOWN)
|
||||
self.start_recoverer(service)
|
||||
except Exception:
|
||||
logger.exception("Error starting AS recoverer")
|
||||
|
||||
def start_recoverer(self, service):
|
||||
def start_recoverer(self, service: ApplicationService) -> None:
|
||||
"""Start a Recoverer for the given service
|
||||
|
||||
Args:
|
||||
service (synapse.appservice.ApplicationService):
|
||||
service:
|
||||
"""
|
||||
logger.info("Starting recoverer for AS ID %s", service.id)
|
||||
assert service.id not in self.recoverers
|
||||
@@ -257,7 +264,14 @@ class _Recoverer:
|
||||
callback (callable[_Recoverer]): called once the service recovers.
|
||||
"""
|
||||
|
||||
def __init__(self, clock, store, as_api, service, callback):
|
||||
def __init__(
|
||||
self,
|
||||
clock: Clock,
|
||||
store: DataStore,
|
||||
as_api: ApplicationServiceApi,
|
||||
service: ApplicationService,
|
||||
callback: Callable[["_Recoverer"], Awaitable[None]],
|
||||
):
|
||||
self.clock = clock
|
||||
self.store = store
|
||||
self.as_api = as_api
|
||||
@@ -265,8 +279,8 @@ class _Recoverer:
|
||||
self.callback = callback
|
||||
self.backoff_counter = 1
|
||||
|
||||
def recover(self):
|
||||
def _retry():
|
||||
def recover(self) -> None:
|
||||
def _retry() -> None:
|
||||
run_as_background_process(
|
||||
"as-recoverer-%s" % (self.service.id,), self.retry
|
||||
)
|
||||
@@ -275,13 +289,13 @@ class _Recoverer:
|
||||
logger.info("Scheduling retries on %s in %fs", self.service.id, delay)
|
||||
self.clock.call_later(delay, _retry)
|
||||
|
||||
def _backoff(self):
|
||||
def _backoff(self) -> None:
|
||||
# cap the backoff to be around 8.5min => (2^9) = 512 secs
|
||||
if self.backoff_counter < 9:
|
||||
self.backoff_counter += 1
|
||||
self.recover()
|
||||
|
||||
async def retry(self):
|
||||
async def retry(self) -> None:
|
||||
logger.info("Starting retries on %s", self.service.id)
|
||||
try:
|
||||
while True:
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from synapse.config._base import ConfigError
|
||||
from synapse.config.homeserver import HomeServerConfig
|
||||
|
||||
|
||||
def main(args):
|
||||
def main(args: List[str]) -> None:
|
||||
action = args[1] if len(args) > 1 and args[1] == "read" else None
|
||||
# If we're reading a key in the config file, then `args[1]` will be `read` and `args[2]`
|
||||
# will be the key to read.
|
||||
|
||||
@@ -20,7 +20,18 @@ import os
|
||||
from collections import OrderedDict
|
||||
from hashlib import sha256
|
||||
from textwrap import dedent
|
||||
from typing import Any, Iterable, List, MutableMapping, Optional, Union
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
MutableMapping,
|
||||
Optional,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
)
|
||||
|
||||
import attr
|
||||
import jinja2
|
||||
@@ -78,7 +89,7 @@ CONFIG_FILE_HEADER = """\
|
||||
"""
|
||||
|
||||
|
||||
def path_exists(file_path):
|
||||
def path_exists(file_path: str) -> bool:
|
||||
"""Check if a file exists
|
||||
|
||||
Unlike os.path.exists, this throws an exception if there is an error
|
||||
@@ -86,7 +97,7 @@ def path_exists(file_path):
|
||||
the parent dir).
|
||||
|
||||
Returns:
|
||||
bool: True if the file exists; False if not.
|
||||
True if the file exists; False if not.
|
||||
"""
|
||||
try:
|
||||
os.stat(file_path)
|
||||
@@ -102,15 +113,15 @@ class Config:
|
||||
A configuration section, containing configuration keys and values.
|
||||
|
||||
Attributes:
|
||||
section (str): The section title of this config object, such as
|
||||
section: The section title of this config object, such as
|
||||
"tls" or "logger". This is used to refer to it on the root
|
||||
logger (for example, `config.tls.some_option`). Must be
|
||||
defined in subclasses.
|
||||
"""
|
||||
|
||||
section = None
|
||||
section: str
|
||||
|
||||
def __init__(self, root_config=None):
|
||||
def __init__(self, root_config: "RootConfig" = None):
|
||||
self.root = root_config
|
||||
|
||||
# Get the path to the default Synapse template directory
|
||||
@@ -119,7 +130,7 @@ class Config:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def parse_size(value):
|
||||
def parse_size(value: Union[str, int]) -> int:
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
sizes = {"K": 1024, "M": 1024 * 1024}
|
||||
@@ -162,15 +173,15 @@ class Config:
|
||||
return int(value) * size
|
||||
|
||||
@staticmethod
|
||||
def abspath(file_path):
|
||||
def abspath(file_path: str) -> str:
|
||||
return os.path.abspath(file_path) if file_path else file_path
|
||||
|
||||
@classmethod
|
||||
def path_exists(cls, file_path):
|
||||
def path_exists(cls, file_path: str) -> bool:
|
||||
return path_exists(file_path)
|
||||
|
||||
@classmethod
|
||||
def check_file(cls, file_path, config_name):
|
||||
def check_file(cls, file_path: Optional[str], config_name: str) -> str:
|
||||
if file_path is None:
|
||||
raise ConfigError("Missing config for %s." % (config_name,))
|
||||
try:
|
||||
@@ -183,7 +194,7 @@ class Config:
|
||||
return cls.abspath(file_path)
|
||||
|
||||
@classmethod
|
||||
def ensure_directory(cls, dir_path):
|
||||
def ensure_directory(cls, dir_path: str) -> str:
|
||||
dir_path = cls.abspath(dir_path)
|
||||
os.makedirs(dir_path, exist_ok=True)
|
||||
if not os.path.isdir(dir_path):
|
||||
@@ -191,7 +202,7 @@ class Config:
|
||||
return dir_path
|
||||
|
||||
@classmethod
|
||||
def read_file(cls, file_path, config_name):
|
||||
def read_file(cls, file_path: Any, config_name: str) -> str:
|
||||
"""Deprecated: call read_file directly"""
|
||||
return read_file(file_path, (config_name,))
|
||||
|
||||
@@ -284,6 +295,9 @@ class Config:
|
||||
return [env.get_template(filename) for filename in filenames]
|
||||
|
||||
|
||||
TRootConfig = TypeVar("TRootConfig", bound="RootConfig")
|
||||
|
||||
|
||||
class RootConfig:
|
||||
"""
|
||||
Holder of an application's configuration.
|
||||
@@ -308,7 +322,9 @@ class RootConfig:
|
||||
raise Exception("Failed making %s: %r" % (config_class.section, e))
|
||||
setattr(self, config_class.section, conf)
|
||||
|
||||
def invoke_all(self, func_name: str, *args, **kwargs) -> MutableMapping[str, Any]:
|
||||
def invoke_all(
|
||||
self, func_name: str, *args: Any, **kwargs: Any
|
||||
) -> MutableMapping[str, Any]:
|
||||
"""
|
||||
Invoke a function on all instantiated config objects this RootConfig is
|
||||
configured to use.
|
||||
@@ -317,6 +333,7 @@ class RootConfig:
|
||||
func_name: Name of function to invoke
|
||||
*args
|
||||
**kwargs
|
||||
|
||||
Returns:
|
||||
ordered dictionary of config section name and the result of the
|
||||
function from it.
|
||||
@@ -332,7 +349,7 @@ class RootConfig:
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def invoke_all_static(cls, func_name: str, *args, **kwargs):
|
||||
def invoke_all_static(cls, func_name: str, *args: Any, **kwargs: any) -> None:
|
||||
"""
|
||||
Invoke a static function on config objects this RootConfig is
|
||||
configured to use.
|
||||
@@ -341,6 +358,7 @@ class RootConfig:
|
||||
func_name: Name of function to invoke
|
||||
*args
|
||||
**kwargs
|
||||
|
||||
Returns:
|
||||
ordered dictionary of config section name and the result of the
|
||||
function from it.
|
||||
@@ -351,16 +369,16 @@ class RootConfig:
|
||||
|
||||
def generate_config(
|
||||
self,
|
||||
config_dir_path,
|
||||
data_dir_path,
|
||||
server_name,
|
||||
generate_secrets=False,
|
||||
report_stats=None,
|
||||
open_private_ports=False,
|
||||
listeners=None,
|
||||
tls_certificate_path=None,
|
||||
tls_private_key_path=None,
|
||||
):
|
||||
config_dir_path: str,
|
||||
data_dir_path: str,
|
||||
server_name: str,
|
||||
generate_secrets: bool = False,
|
||||
report_stats: Optional[bool] = None,
|
||||
open_private_ports: bool = False,
|
||||
listeners: Optional[List[dict]] = None,
|
||||
tls_certificate_path: Optional[str] = None,
|
||||
tls_private_key_path: Optional[str] = None,
|
||||
) -> str:
|
||||
"""
|
||||
Build a default configuration file
|
||||
|
||||
@@ -368,27 +386,27 @@ class RootConfig:
|
||||
(eg with --generate_config).
|
||||
|
||||
Args:
|
||||
config_dir_path (str): The path where the config files are kept. Used to
|
||||
config_dir_path: The path where the config files are kept. Used to
|
||||
create filenames for things like the log config and the signing key.
|
||||
|
||||
data_dir_path (str): The path where the data files are kept. Used to create
|
||||
data_dir_path: The path where the data files are kept. Used to create
|
||||
filenames for things like the database and media store.
|
||||
|
||||
server_name (str): The server name. Used to initialise the server_name
|
||||
server_name: The server name. Used to initialise the server_name
|
||||
config param, but also used in the names of some of the config files.
|
||||
|
||||
generate_secrets (bool): True if we should generate new secrets for things
|
||||
generate_secrets: True if we should generate new secrets for things
|
||||
like the macaroon_secret_key. If False, these parameters will be left
|
||||
unset.
|
||||
|
||||
report_stats (bool|None): Initial setting for the report_stats setting.
|
||||
report_stats: Initial setting for the report_stats setting.
|
||||
If None, report_stats will be left unset.
|
||||
|
||||
open_private_ports (bool): True to leave private ports (such as the non-TLS
|
||||
open_private_ports: True to leave private ports (such as the non-TLS
|
||||
HTTP listener) open to the internet.
|
||||
|
||||
listeners (list(dict)|None): A list of descriptions of the listeners
|
||||
synapse should start with each of which specifies a port (str), a list of
|
||||
listeners: A list of descriptions of the listeners synapse should
|
||||
start with each of which specifies a port (int), a list of
|
||||
resources (list(str)), tls (bool) and type (str). For example:
|
||||
[{
|
||||
"port": 8448,
|
||||
@@ -403,16 +421,12 @@ class RootConfig:
|
||||
"type": "http",
|
||||
}],
|
||||
|
||||
tls_certificate_path: The path to the tls certificate.
|
||||
|
||||
database (str|None): The database type to configure, either `psycog2`
|
||||
or `sqlite3`.
|
||||
|
||||
tls_certificate_path (str|None): The path to the tls certificate.
|
||||
|
||||
tls_private_key_path (str|None): The path to the tls private key.
|
||||
tls_private_key_path: The path to the tls private key.
|
||||
|
||||
Returns:
|
||||
str: the yaml config file
|
||||
The yaml config file
|
||||
"""
|
||||
|
||||
return CONFIG_FILE_HEADER + "\n\n".join(
|
||||
@@ -432,12 +446,15 @@ class RootConfig:
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def load_config(cls, description, argv):
|
||||
def load_config(
|
||||
cls: Type[TRootConfig], description: str, argv: List[str]
|
||||
) -> TRootConfig:
|
||||
"""Parse the commandline and config files
|
||||
|
||||
Doesn't support config-file-generation: used by the worker apps.
|
||||
|
||||
Returns: Config object.
|
||||
Returns:
|
||||
Config object.
|
||||
"""
|
||||
config_parser = argparse.ArgumentParser(description=description)
|
||||
cls.add_arguments_to_parser(config_parser)
|
||||
@@ -446,7 +463,7 @@ class RootConfig:
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
def add_arguments_to_parser(cls, config_parser):
|
||||
def add_arguments_to_parser(cls, config_parser: argparse.ArgumentParser) -> None:
|
||||
"""Adds all the config flags to an ArgumentParser.
|
||||
|
||||
Doesn't support config-file-generation: used by the worker apps.
|
||||
@@ -454,7 +471,7 @@ class RootConfig:
|
||||
Used for workers where we want to add extra flags/subcommands.
|
||||
|
||||
Args:
|
||||
config_parser (ArgumentParser): App description
|
||||
config_parser: App description
|
||||
"""
|
||||
|
||||
config_parser.add_argument(
|
||||
@@ -477,7 +494,9 @@ class RootConfig:
|
||||
cls.invoke_all_static("add_arguments", config_parser)
|
||||
|
||||
@classmethod
|
||||
def load_config_with_parser(cls, parser, argv):
|
||||
def load_config_with_parser(
|
||||
cls: Type[TRootConfig], parser: argparse.ArgumentParser, argv: List[str]
|
||||
) -> Tuple[TRootConfig, argparse.Namespace]:
|
||||
"""Parse the commandline and config files with the given parser
|
||||
|
||||
Doesn't support config-file-generation: used by the worker apps.
|
||||
@@ -485,13 +504,12 @@ class RootConfig:
|
||||
Used for workers where we want to add extra flags/subcommands.
|
||||
|
||||
Args:
|
||||
parser (ArgumentParser)
|
||||
argv (list[str])
|
||||
parser
|
||||
argv
|
||||
|
||||
Returns:
|
||||
tuple[HomeServerConfig, argparse.Namespace]: Returns the parsed
|
||||
config object and the parsed argparse.Namespace object from
|
||||
`parser.parse_args(..)`
|
||||
Returns the parsed config object and the parsed argparse.Namespace
|
||||
object from parser.parse_args(..)`
|
||||
"""
|
||||
|
||||
obj = cls()
|
||||
@@ -520,12 +538,15 @@ class RootConfig:
|
||||
return obj, config_args
|
||||
|
||||
@classmethod
|
||||
def load_or_generate_config(cls, description, argv):
|
||||
def load_or_generate_config(
|
||||
cls: Type[TRootConfig], description: str, argv: List[str]
|
||||
) -> Optional[TRootConfig]:
|
||||
"""Parse the commandline and config files
|
||||
|
||||
Supports generation of config files, so is used for the main homeserver app.
|
||||
|
||||
Returns: Config object, or None if --generate-config or --generate-keys was set
|
||||
Returns:
|
||||
Config object, or None if --generate-config or --generate-keys was set
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument(
|
||||
@@ -680,16 +701,21 @@ class RootConfig:
|
||||
|
||||
return obj
|
||||
|
||||
def parse_config_dict(self, config_dict, config_dir_path=None, data_dir_path=None):
|
||||
def parse_config_dict(
|
||||
self,
|
||||
config_dict: Dict[str, Any],
|
||||
config_dir_path: Optional[str] = None,
|
||||
data_dir_path: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Read the information from the config dict into this Config object.
|
||||
|
||||
Args:
|
||||
config_dict (dict): Configuration data, as read from the yaml
|
||||
config_dict: Configuration data, as read from the yaml
|
||||
|
||||
config_dir_path (str): The path where the config files are kept. Used to
|
||||
config_dir_path: The path where the config files are kept. Used to
|
||||
create filenames for things like the log config and the signing key.
|
||||
|
||||
data_dir_path (str): The path where the data files are kept. Used to create
|
||||
data_dir_path: The path where the data files are kept. Used to create
|
||||
filenames for things like the database and media store.
|
||||
"""
|
||||
self.invoke_all(
|
||||
@@ -699,17 +725,20 @@ class RootConfig:
|
||||
data_dir_path=data_dir_path,
|
||||
)
|
||||
|
||||
def generate_missing_files(self, config_dict, config_dir_path):
|
||||
def generate_missing_files(
|
||||
self, config_dict: Dict[str, Any], config_dir_path: str
|
||||
) -> None:
|
||||
self.invoke_all("generate_files", config_dict, config_dir_path)
|
||||
|
||||
|
||||
def read_config_files(config_files):
|
||||
def read_config_files(config_files: Iterable[str]) -> Dict[str, Any]:
|
||||
"""Read the config files into a dict
|
||||
|
||||
Args:
|
||||
config_files (iterable[str]): A list of the config files to read
|
||||
config_files: A list of the config files to read
|
||||
|
||||
Returns: dict
|
||||
Returns:
|
||||
The configuration dictionary.
|
||||
"""
|
||||
specified_config = {}
|
||||
for config_file in config_files:
|
||||
@@ -733,17 +762,17 @@ def read_config_files(config_files):
|
||||
return specified_config
|
||||
|
||||
|
||||
def find_config_files(search_paths):
|
||||
def find_config_files(search_paths: List[str]) -> List[str]:
|
||||
"""Finds config files using a list of search paths. If a path is a file
|
||||
then that file path is added to the list. If a search path is a directory
|
||||
then all the "*.yaml" files in that directory are added to the list in
|
||||
sorted order.
|
||||
|
||||
Args:
|
||||
search_paths(list(str)): A list of paths to search.
|
||||
search_paths: A list of paths to search.
|
||||
|
||||
Returns:
|
||||
list(str): A list of file paths.
|
||||
A list of file paths.
|
||||
"""
|
||||
|
||||
config_files = []
|
||||
@@ -777,7 +806,7 @@ def find_config_files(search_paths):
|
||||
return config_files
|
||||
|
||||
|
||||
@attr.s
|
||||
@attr.s(auto_attribs=True)
|
||||
class ShardedWorkerHandlingConfig:
|
||||
"""Algorithm for choosing which instance is responsible for handling some
|
||||
sharded work.
|
||||
@@ -787,7 +816,7 @@ class ShardedWorkerHandlingConfig:
|
||||
below).
|
||||
"""
|
||||
|
||||
instances = attr.ib(type=List[str])
|
||||
instances: List[str]
|
||||
|
||||
def should_handle(self, instance_name: str, key: str) -> bool:
|
||||
"""Whether this instance is responsible for handling the given key."""
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
from typing import Any, Iterable, List, Optional
|
||||
import argparse
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
MutableMapping,
|
||||
Optional,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
)
|
||||
|
||||
import jinja2
|
||||
|
||||
from synapse.config import (
|
||||
account_validity,
|
||||
@@ -19,6 +33,7 @@ from synapse.config import (
|
||||
logger,
|
||||
metrics,
|
||||
modules,
|
||||
oembed,
|
||||
oidc,
|
||||
password_auth_providers,
|
||||
push,
|
||||
@@ -27,6 +42,7 @@ from synapse.config import (
|
||||
registration,
|
||||
repository,
|
||||
retention,
|
||||
room,
|
||||
room_directory,
|
||||
saml2,
|
||||
server,
|
||||
@@ -51,7 +67,9 @@ MISSING_REPORT_STATS_CONFIG_INSTRUCTIONS: str
|
||||
MISSING_REPORT_STATS_SPIEL: str
|
||||
MISSING_SERVER_NAME: str
|
||||
|
||||
def path_exists(file_path: str): ...
|
||||
def path_exists(file_path: str) -> bool: ...
|
||||
|
||||
TRootConfig = TypeVar("TRootConfig", bound="RootConfig")
|
||||
|
||||
class RootConfig:
|
||||
server: server.ServerConfig
|
||||
@@ -61,6 +79,7 @@ class RootConfig:
|
||||
logging: logger.LoggingConfig
|
||||
ratelimiting: ratelimiting.RatelimitConfig
|
||||
media: repository.ContentRepositoryConfig
|
||||
oembed: oembed.OembedConfig
|
||||
captcha: captcha.CaptchaConfig
|
||||
voip: voip.VoipConfig
|
||||
registration: registration.RegistrationConfig
|
||||
@@ -80,6 +99,7 @@ class RootConfig:
|
||||
authproviders: password_auth_providers.PasswordAuthProviderConfig
|
||||
push: push.PushConfig
|
||||
spamchecker: spam_checker.SpamCheckerConfig
|
||||
room: room.RoomConfig
|
||||
groups: groups.GroupsConfig
|
||||
userdirectory: user_directory.UserDirectoryConfig
|
||||
consent: consent.ConsentConfig
|
||||
@@ -87,72 +107,85 @@ class RootConfig:
|
||||
servernotices: server_notices.ServerNoticesConfig
|
||||
roomdirectory: room_directory.RoomDirectoryConfig
|
||||
thirdpartyrules: third_party_event_rules.ThirdPartyRulesConfig
|
||||
tracer: tracer.TracerConfig
|
||||
tracing: tracer.TracerConfig
|
||||
redis: redis.RedisConfig
|
||||
modules: modules.ModulesConfig
|
||||
caches: cache.CacheConfig
|
||||
federation: federation.FederationConfig
|
||||
retention: retention.RetentionConfig
|
||||
|
||||
config_classes: List = ...
|
||||
config_classes: List[Type["Config"]] = ...
|
||||
def __init__(self) -> None: ...
|
||||
def invoke_all(self, func_name: str, *args: Any, **kwargs: Any): ...
|
||||
def invoke_all(
|
||||
self, func_name: str, *args: Any, **kwargs: Any
|
||||
) -> MutableMapping[str, Any]: ...
|
||||
@classmethod
|
||||
def invoke_all_static(cls, func_name: str, *args: Any, **kwargs: Any) -> None: ...
|
||||
def __getattr__(self, item: str): ...
|
||||
def parse_config_dict(
|
||||
self,
|
||||
config_dict: Any,
|
||||
config_dir_path: Optional[Any] = ...,
|
||||
data_dir_path: Optional[Any] = ...,
|
||||
config_dict: Dict[str, Any],
|
||||
config_dir_path: Optional[str] = ...,
|
||||
data_dir_path: Optional[str] = ...,
|
||||
) -> None: ...
|
||||
read_config: Any = ...
|
||||
def generate_config(
|
||||
self,
|
||||
config_dir_path: str,
|
||||
data_dir_path: str,
|
||||
server_name: str,
|
||||
generate_secrets: bool = ...,
|
||||
report_stats: Optional[str] = ...,
|
||||
report_stats: Optional[bool] = ...,
|
||||
open_private_ports: bool = ...,
|
||||
listeners: Optional[Any] = ...,
|
||||
database_conf: Optional[Any] = ...,
|
||||
tls_certificate_path: Optional[str] = ...,
|
||||
tls_private_key_path: Optional[str] = ...,
|
||||
): ...
|
||||
) -> str: ...
|
||||
@classmethod
|
||||
def load_or_generate_config(cls, description: Any, argv: Any): ...
|
||||
def load_or_generate_config(
|
||||
cls: Type[TRootConfig], description: str, argv: List[str]
|
||||
) -> Optional[TRootConfig]: ...
|
||||
@classmethod
|
||||
def load_config(cls, description: Any, argv: Any): ...
|
||||
def load_config(
|
||||
cls: Type[TRootConfig], description: str, argv: List[str]
|
||||
) -> TRootConfig: ...
|
||||
@classmethod
|
||||
def add_arguments_to_parser(cls, config_parser: Any) -> None: ...
|
||||
def add_arguments_to_parser(
|
||||
cls, config_parser: argparse.ArgumentParser
|
||||
) -> None: ...
|
||||
@classmethod
|
||||
def load_config_with_parser(cls, parser: Any, argv: Any): ...
|
||||
def load_config_with_parser(
|
||||
cls: Type[TRootConfig], parser: argparse.ArgumentParser, argv: List[str]
|
||||
) -> Tuple[TRootConfig, argparse.Namespace]: ...
|
||||
def generate_missing_files(
|
||||
self, config_dict: dict, config_dir_path: str
|
||||
) -> None: ...
|
||||
|
||||
class Config:
|
||||
root: RootConfig
|
||||
default_template_dir: str
|
||||
def __init__(self, root_config: Optional[RootConfig] = ...) -> None: ...
|
||||
def __getattr__(self, item: str, from_root: bool = ...): ...
|
||||
@staticmethod
|
||||
def parse_size(value: Any): ...
|
||||
def parse_size(value: Union[str, int]) -> int: ...
|
||||
@staticmethod
|
||||
def parse_duration(value: Any): ...
|
||||
def parse_duration(value: Union[str, int]) -> int: ...
|
||||
@staticmethod
|
||||
def abspath(file_path: Optional[str]): ...
|
||||
def abspath(file_path: Optional[str]) -> str: ...
|
||||
@classmethod
|
||||
def path_exists(cls, file_path: str): ...
|
||||
def path_exists(cls, file_path: str) -> bool: ...
|
||||
@classmethod
|
||||
def check_file(cls, file_path: str, config_name: str): ...
|
||||
def check_file(cls, file_path: str, config_name: str) -> str: ...
|
||||
@classmethod
|
||||
def ensure_directory(cls, dir_path: str): ...
|
||||
def ensure_directory(cls, dir_path: str) -> str: ...
|
||||
@classmethod
|
||||
def read_file(cls, file_path: str, config_name: str): ...
|
||||
def read_file(cls, file_path: str, config_name: str) -> str: ...
|
||||
def read_template(self, filenames: str) -> jinja2.Template: ...
|
||||
def read_templates(
|
||||
self,
|
||||
filenames: List[str],
|
||||
custom_template_directories: Optional[Iterable[str]] = None,
|
||||
) -> List[jinja2.Template]: ...
|
||||
|
||||
def read_config_files(config_files: List[str]): ...
|
||||
def find_config_files(search_paths: List[str]): ...
|
||||
def read_config_files(config_files: Iterable[str]) -> Dict[str, Any]: ...
|
||||
def find_config_files(search_paths: List[str]) -> List[str]: ...
|
||||
|
||||
class ShardedWorkerHandlingConfig:
|
||||
instances: List[str]
|
||||
|
||||
@@ -107,6 +107,8 @@ _DEFAULT_PREJOIN_STATE_TYPES = [
|
||||
EventTypes.Name,
|
||||
# Per MSC1772.
|
||||
EventTypes.Create,
|
||||
# Per MSC3173.
|
||||
EventTypes.Topic,
|
||||
]
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user