Compare commits
170 Commits
shhs
...
hawkowl/fs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36e6be9294 | ||
|
|
e5eddea699 | ||
|
|
0b6fbb28a8 | ||
|
|
e9906b0772 | ||
|
|
f218705d2a | ||
|
|
2546f32b90 | ||
|
|
9d9cf3583b | ||
|
|
2bec3a4953 | ||
|
|
3de6cc245f | ||
|
|
156a461cbd | ||
|
|
c9456193d3 | ||
|
|
fb86217553 | ||
|
|
41546f946e | ||
|
|
a7f0161276 | ||
|
|
107ad133fc | ||
|
|
b15a4ab405 | ||
|
|
af9f1c0764 | ||
|
|
d1b5b055be | ||
|
|
edeae53221 | ||
|
|
c32d359094 | ||
|
|
bf4db42920 | ||
|
|
977fa4a717 | ||
|
|
6881f21f3e | ||
|
|
8ed9e63432 | ||
|
|
d55bc4a8bf | ||
|
|
5d018d23f0 | ||
|
|
93fd3cbc7a | ||
|
|
3c076c79c5 | ||
|
|
a8f40a8302 | ||
|
|
55a0c98d16 | ||
|
|
0b36decfb6 | ||
|
|
da378af445 | ||
|
|
d2e3d5b9db | ||
|
|
76a58fdcce | ||
|
|
58af30a6c7 | ||
|
|
0f632f3a57 | ||
|
|
ad167c3849 | ||
|
|
f25f638c35 | ||
|
|
3ff3dfe5a3 | ||
|
|
f4a30d286f | ||
|
|
bc35503528 | ||
|
|
a4a9ded4d0 | ||
|
|
e5a0224837 | ||
|
|
dc4d74e44a | ||
|
|
c5288e9984 | ||
|
|
2e697d3013 | ||
|
|
0eefb76fa1 | ||
|
|
cf89266b98 | ||
|
|
02735e140f | ||
|
|
f31d4cb7a2 | ||
|
|
72167fb394 | ||
|
|
58a755cdc3 | ||
|
|
8fde611a8c | ||
|
|
8f15832950 | ||
|
|
9fe6ad5fef | ||
|
|
fe2f2fc530 | ||
|
|
6be336c0d8 | ||
|
|
3b7a35a59a | ||
|
|
a9bcae9f50 | ||
|
|
d4f91e7e9f | ||
|
|
4037d3220a | ||
|
|
123c04daa7 | ||
|
|
62a2d60d72 | ||
|
|
958d69f300 | ||
|
|
15056ca208 | ||
|
|
f92d05e254 | ||
|
|
7a48d0bab8 | ||
|
|
b4d5ff0af7 | ||
|
|
e23ab7f41a | ||
|
|
1ec7d656dd | ||
|
|
458e51df7a | ||
|
|
63eb4a1b62 | ||
|
|
8c97f6414c | ||
|
|
5c3eecc70f | ||
|
|
4e97eb89e5 | ||
|
|
448bcfd0f9 | ||
|
|
e6a6c4fbab | ||
|
|
c9964ba600 | ||
|
|
865077f1d1 | ||
|
|
aecae8f397 | ||
|
|
7c8c3b8437 | ||
|
|
3e013b7c8e | ||
|
|
2a12d76646 | ||
|
|
97a8b4caf7 | ||
|
|
df3a5db629 | ||
|
|
85b0bd8fe0 | ||
|
|
105e7f6ed3 | ||
|
|
3b476f5767 | ||
|
|
d94916852f | ||
|
|
84c6ea1af8 | ||
|
|
45df38e61b | ||
|
|
fa87004bc1 | ||
|
|
bd083a5fcf | ||
|
|
244953be3f | ||
|
|
08352d44f8 | ||
|
|
d74595e2ca | ||
|
|
1a93daf353 | ||
|
|
97bf307755 | ||
|
|
2e9cf7dda5 | ||
|
|
14c24c9037 | ||
|
|
1cad8d7b6f | ||
|
|
26d742fed6 | ||
|
|
618bd1ee76 | ||
|
|
f16aa3a44b | ||
|
|
baf081cd3b | ||
|
|
2276936bac | ||
|
|
f30a71a67b | ||
|
|
c159803067 | ||
|
|
0c4a99607e | ||
|
|
62921fb53e | ||
|
|
32768e96d4 | ||
|
|
418635e68a | ||
|
|
adcd5368b0 | ||
|
|
73bbaf2bc6 | ||
|
|
3641784e8c | ||
|
|
65afc535a6 | ||
|
|
4806651744 | ||
|
|
fadfde9aaa | ||
|
|
18a466b84e | ||
|
|
3db1377b26 | ||
|
|
841b12867e | ||
|
|
73bf452666 | ||
|
|
22d2338ace | ||
|
|
1883223a01 | ||
|
|
4f6984aa88 | ||
|
|
cda4460d99 | ||
|
|
39e594b765 | ||
|
|
cf0006719d | ||
|
|
b2a629ef49 | ||
|
|
d9ea9881d2 | ||
|
|
c96322c8d2 | ||
|
|
0d0f6d12bc | ||
|
|
17c27df6ea | ||
|
|
80cfad233e | ||
|
|
720d30469f | ||
|
|
79f689e6c2 | ||
|
|
c560b791e1 | ||
|
|
8e513e7afc | ||
|
|
22e862304a | ||
|
|
0cb72812f9 | ||
|
|
f477ce4b1a | ||
|
|
66f5ff72fd | ||
|
|
2017369f7d | ||
|
|
5ea773c505 | ||
|
|
f337d2f0f0 | ||
|
|
0fd171770a | ||
|
|
f99554b15d | ||
|
|
dc7cf81267 | ||
|
|
f214bff0c0 | ||
|
|
dcca56baba | ||
|
|
c7095be913 | ||
|
|
7704873cb8 | ||
|
|
d7bd9651bc | ||
|
|
5c07c97c09 | ||
|
|
7b8bc61834 | ||
|
|
ced4fdaa84 | ||
|
|
2410335507 | ||
|
|
bd2e1a2aa8 | ||
|
|
ebc5ed1296 | ||
|
|
5c05ae7ba0 | ||
|
|
b73ce4ba81 | ||
|
|
356ed0438e | ||
|
|
6a85cb5ef7 | ||
|
|
dd2851d576 | ||
|
|
10523241d8 | ||
|
|
89c885909a | ||
|
|
8e1ada9e6f | ||
|
|
059d8c1a4e | ||
|
|
c618a5d348 | ||
|
|
6de09e07a6 |
@@ -2,7 +2,7 @@
|
||||
|
||||
set -ex
|
||||
|
||||
if [[ "$BUILDKITE_BRANCH" =~ ^(develop|master|dinsic|shhs-.*|release-.*)$ ]]; then
|
||||
if [[ "$BUILDKITE_BRANCH" =~ ^(develop|master|dinsic|shhs|release-.*)$ ]]; then
|
||||
echo "Not merging forward, as this is a release branch"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -31,7 +31,7 @@ steps:
|
||||
- "python -m pip install tox"
|
||||
- "scripts-dev/check-newsfragment"
|
||||
label: ":newspaper: Newsfile"
|
||||
branches: "!master !develop !release-* !shhs-v*"
|
||||
branches: "!master !develop !release-*"
|
||||
plugins:
|
||||
- docker#v3.0.1:
|
||||
image: "python:3.6"
|
||||
@@ -47,16 +47,17 @@ steps:
|
||||
|
||||
- wait
|
||||
|
||||
|
||||
- command:
|
||||
- "python -m pip install tox"
|
||||
- "apt-get update && apt-get install -y python3.5 python3.5-dev python3-pip libxml2-dev libxslt-dev zlib1g-dev"
|
||||
- "python3.5 -m pip install tox"
|
||||
- "tox -e py35-old,codecov"
|
||||
label: ":python: 3.5 / SQLite / Old Deps"
|
||||
branches: "!shhs !shhs-*"
|
||||
env:
|
||||
TRIAL_FLAGS: "-j 2"
|
||||
plugins:
|
||||
- docker#v3.0.1:
|
||||
image: "python:3.5"
|
||||
image: "ubuntu:xenial" # We use xenail to get an old sqlite and python
|
||||
propagate-environment: true
|
||||
retry:
|
||||
automatic:
|
||||
@@ -69,7 +70,6 @@ steps:
|
||||
- "python -m pip install tox"
|
||||
- "tox -e py35,codecov"
|
||||
label: ":python: 3.5 / SQLite"
|
||||
branches: "!shhs !shhs-*"
|
||||
env:
|
||||
TRIAL_FLAGS: "-j 2"
|
||||
plugins:
|
||||
@@ -87,7 +87,6 @@ steps:
|
||||
- "python -m pip install tox"
|
||||
- "tox -e py36,codecov"
|
||||
label: ":python: 3.6 / SQLite"
|
||||
branches: "!shhs !shhs-*"
|
||||
env:
|
||||
TRIAL_FLAGS: "-j 2"
|
||||
plugins:
|
||||
@@ -119,9 +118,10 @@ steps:
|
||||
limit: 2
|
||||
|
||||
- label: ":python: 3.5 / :postgres: 9.5"
|
||||
branches: "!shhs !shhs-*"
|
||||
agents:
|
||||
queue: "medium"
|
||||
env:
|
||||
TRIAL_FLAGS: "-j 4"
|
||||
TRIAL_FLAGS: "-j 8"
|
||||
command:
|
||||
- "bash -c 'python -m pip install tox && python -m tox -e py35-postgres,codecov'"
|
||||
plugins:
|
||||
@@ -137,9 +137,10 @@ steps:
|
||||
limit: 2
|
||||
|
||||
- label: ":python: 3.7 / :postgres: 9.5"
|
||||
branches: "!shhs !shhs-*"
|
||||
agents:
|
||||
queue: "medium"
|
||||
env:
|
||||
TRIAL_FLAGS: "-j 4"
|
||||
TRIAL_FLAGS: "-j 8"
|
||||
command:
|
||||
- "bash -c 'python -m pip install tox && python -m tox -e py37-postgres,codecov'"
|
||||
plugins:
|
||||
@@ -155,8 +156,10 @@ steps:
|
||||
limit: 2
|
||||
|
||||
- label: ":python: 3.7 / :postgres: 11"
|
||||
agents:
|
||||
queue: "medium"
|
||||
env:
|
||||
TRIAL_FLAGS: "-j 4"
|
||||
TRIAL_FLAGS: "-j 8"
|
||||
command:
|
||||
- "bash -c 'python -m pip install tox && python -m tox -e py37-postgres,codecov'"
|
||||
plugins:
|
||||
@@ -173,7 +176,6 @@ steps:
|
||||
|
||||
|
||||
- label: "SyTest - :python: 3.5 / SQLite / Monolith"
|
||||
branches: "!shhs !shhs-*"
|
||||
agents:
|
||||
queue: "medium"
|
||||
command:
|
||||
@@ -214,14 +216,15 @@ steps:
|
||||
limit: 2
|
||||
|
||||
- label: "SyTest - :python: 3.5 / :postgres: 9.6 / Workers"
|
||||
branches: "!shhs !shhs-*"
|
||||
agents:
|
||||
queue: "medium"
|
||||
env:
|
||||
POSTGRES: "1"
|
||||
WORKERS: "1"
|
||||
BLACKLIST: "synapse-blacklist-with-workers"
|
||||
command:
|
||||
- "bash .buildkite/merge_base_branch.sh"
|
||||
- "bash -c 'cat /src/sytest-blacklist /src/.buildkite/worker-blacklist > /src/synapse-blacklist-with-workers'"
|
||||
- "bash /synapse_sytest.sh"
|
||||
plugins:
|
||||
- docker#v3.0.1:
|
||||
@@ -229,22 +232,9 @@ steps:
|
||||
propagate-environment: true
|
||||
always-pull: true
|
||||
workdir: "/src"
|
||||
soft_fail: true
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: -1
|
||||
limit: 2
|
||||
- exit_status: 2
|
||||
limit: 2
|
||||
|
||||
- wait
|
||||
|
||||
- label: ":docker: x86_64"
|
||||
agents:
|
||||
queue: "release"
|
||||
branches: "shhs-*"
|
||||
command:
|
||||
- "docker build -f docker/Dockerfile --build-arg PYTHON_VERSION=3.7.4 . -t matrixdotorg/synapse:${BUILDKITE_TAG}"
|
||||
- "docker save matrixdotorg/synapse:${BUILDKITE_TAG} | gzip -9 > docker.tar.gz"
|
||||
artifact_paths:
|
||||
- "docker.tar.gz"
|
||||
30
.buildkite/worker-blacklist
Normal file
30
.buildkite/worker-blacklist
Normal file
@@ -0,0 +1,30 @@
|
||||
# This file serves as a blacklist for SyTest tests that we expect will fail in
|
||||
# Synapse when run under worker mode. For more details, see sytest-blacklist.
|
||||
|
||||
Message history can be paginated
|
||||
|
||||
Can re-join room if re-invited
|
||||
|
||||
/upgrade creates a new room
|
||||
|
||||
The only membership state included in an initial sync is for all the senders in the timeline
|
||||
|
||||
Local device key changes get to remote servers
|
||||
|
||||
If remote user leaves room we no longer receive device updates
|
||||
|
||||
Forgotten room messages cannot be paginated
|
||||
|
||||
Inbound federation can get public room list
|
||||
|
||||
Members from the gap are included in gappy incr LL sync
|
||||
|
||||
Leaves are present in non-gapped incremental syncs
|
||||
|
||||
Old leaves are present in gapped incremental syncs
|
||||
|
||||
User sees updates to presence from other users in the incremental sync.
|
||||
|
||||
Gapped incremental syncs include all state changes
|
||||
|
||||
Old members are included in gappy incr LL sync if they start speaking
|
||||
33
.circleci/config.yml
Normal file
33
.circleci/config.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
version: 2
|
||||
jobs:
|
||||
dockerhubuploadrelease:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run: docker build -f docker/Dockerfile --label gitsha1=${CIRCLE_SHA1} -t matrixdotorg/synapse:${CIRCLE_TAG} -t matrixdotorg/synapse:${CIRCLE_TAG}-py3 .
|
||||
- run: docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_PASSWORD
|
||||
- run: docker push matrixdotorg/synapse:${CIRCLE_TAG}
|
||||
- run: docker push matrixdotorg/synapse:${CIRCLE_TAG}-py3
|
||||
dockerhubuploadlatest:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run: docker build -f docker/Dockerfile --label gitsha1=${CIRCLE_SHA1} -t matrixdotorg/synapse:latest -t matrixdotorg/synapse:latest-py3 .
|
||||
- run: docker login --username $DOCKER_HUB_USERNAME --password $DOCKER_HUB_PASSWORD
|
||||
- run: docker push matrixdotorg/synapse:latest
|
||||
- run: docker push matrixdotorg/synapse:latest-py3
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build:
|
||||
jobs:
|
||||
- dockerhubuploadrelease:
|
||||
filters:
|
||||
tags:
|
||||
only: /v[0-9].[0-9]+.[0-9]+.*/
|
||||
branches:
|
||||
ignore: /.*/
|
||||
- dockerhubuploadlatest:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
@@ -1,5 +1,4 @@
|
||||
comment:
|
||||
layout: "diff"
|
||||
comment: off
|
||||
|
||||
coverage:
|
||||
status:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,10 +16,10 @@ _trial_temp*/
|
||||
/*.log
|
||||
/*.log.config
|
||||
/*.pid
|
||||
/.python-version
|
||||
/*.signing.key
|
||||
/env/
|
||||
/homeserver*.yaml
|
||||
/logs
|
||||
/media_store/
|
||||
/uploads
|
||||
|
||||
@@ -38,3 +38,4 @@ _trial_temp*/
|
||||
/docs/build/
|
||||
/htmlcov
|
||||
/pip-wheel-metadata/
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ This release includes *four* security fixes:
|
||||
|
||||
- Prevent an attack where a federated server could send redactions for arbitrary events in v1 and v2 rooms. ([\#5767](https://github.com/matrix-org/synapse/issues/5767))
|
||||
- Prevent a denial-of-service attack where cycles of redaction events would make Synapse spin infinitely. Thanks to `@lrizika:matrix.org` for identifying and responsibly disclosing this issue. ([0f2ecb961](https://github.com/matrix-org/synapse/commit/0f2ecb961))
|
||||
- Prevent an attack where users could be joined or parted from public rooms without their consent. Thanks to @Dylanger for identifying and responsibly disclosing this issue. ([\#5744](https://github.com/matrix-org/synapse/issues/5744))
|
||||
- Prevent an attack where users could be joined or parted from public rooms without their consent. Thanks to @dylangerdaly for identifying and responsibly disclosing this issue. ([\#5744](https://github.com/matrix-org/synapse/issues/5744))
|
||||
- Fix a vulnerability where a federated server could spoof read-receipts from
|
||||
users on other servers. Thanks to @Dylanger for identifying this issue too. ([\#5743](https://github.com/matrix-org/synapse/issues/5743))
|
||||
users on other servers. Thanks to @dylangerdaly for identifying this issue too. ([\#5743](https://github.com/matrix-org/synapse/issues/5743))
|
||||
|
||||
Additionally, the following fix was in Synapse **1.2.0**, but was not correctly
|
||||
identified during the original release:
|
||||
|
||||
@@ -7,7 +7,6 @@ include demo/README
|
||||
include demo/demo.tls.dh
|
||||
include demo/*.py
|
||||
include demo/*.sh
|
||||
include sytest-blacklist
|
||||
|
||||
recursive-include synapse/storage/schema *.sql
|
||||
recursive-include synapse/storage/schema *.sql.postgres
|
||||
@@ -34,6 +33,7 @@ exclude Dockerfile
|
||||
exclude .dockerignore
|
||||
exclude test_postgresql.sh
|
||||
exclude .editorconfig
|
||||
exclude sytest-blacklist
|
||||
|
||||
include pyproject.toml
|
||||
recursive-include changelog.d *
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Synapse can now be configured to not join remote rooms of a given "complexity" (currently, state events). This option can be used to prevent adverse performance on resource-constrained homeservers.
|
||||
@@ -1 +0,0 @@
|
||||
Python 2 has been removed from the CI.
|
||||
1
changelog.d/5678.removal
Normal file
1
changelog.d/5678.removal
Normal file
@@ -0,0 +1 @@
|
||||
Synapse now no longer accepts the `-v`/`--verbose`, `-f`/`--log-file`, or `--log-config` command line flags, and removes the deprecated `verbose` and `log_file` configuration file options. Users of these options should migrate their options into the dedicated log configuration.
|
||||
1
changelog.d/5686.feature
Normal file
1
changelog.d/5686.feature
Normal file
@@ -0,0 +1 @@
|
||||
Use `M_USER_DEACTIVATED` instead of `M_UNKNOWN` for errcode when a deactivated user attempts to login.
|
||||
1
changelog.d/5693.bugfix
Normal file
1
changelog.d/5693.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix UISIs during homeserver outage.
|
||||
1
changelog.d/5694.misc
Normal file
1
changelog.d/5694.misc
Normal file
@@ -0,0 +1 @@
|
||||
Make Jaeger fully configurable.
|
||||
1
changelog.d/5695.misc
Normal file
1
changelog.d/5695.misc
Normal file
@@ -0,0 +1 @@
|
||||
Add precautionary measures to prevent future abuse of `window.opener` in default welcome page.
|
||||
1
changelog.d/5706.misc
Normal file
1
changelog.d/5706.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5713.misc
Normal file
1
changelog.d/5713.misc
Normal file
@@ -0,0 +1 @@
|
||||
Improve caching when fetching `get_filtered_current_state_ids`.
|
||||
1
changelog.d/5715.misc
Normal file
1
changelog.d/5715.misc
Normal file
@@ -0,0 +1 @@
|
||||
Don't accept opentracing data from clients.
|
||||
1
changelog.d/5717.misc
Normal file
1
changelog.d/5717.misc
Normal file
@@ -0,0 +1 @@
|
||||
Speed up PostgreSQL unit tests in CI.
|
||||
1
changelog.d/5719.misc
Normal file
1
changelog.d/5719.misc
Normal file
@@ -0,0 +1 @@
|
||||
Update the coding style document.
|
||||
1
changelog.d/5720.misc
Normal file
1
changelog.d/5720.misc
Normal file
@@ -0,0 +1 @@
|
||||
Improve database query performance when recording retry intervals for remote hosts.
|
||||
1
changelog.d/5722.misc
Normal file
1
changelog.d/5722.misc
Normal file
@@ -0,0 +1 @@
|
||||
Add a set of opentracing utils.
|
||||
1
changelog.d/5724.bugfix
Normal file
1
changelog.d/5724.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix stack overflow in server key lookup code.
|
||||
1
changelog.d/5725.bugfix
Normal file
1
changelog.d/5725.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
start.sh no longer uses deprecated cli option.
|
||||
1
changelog.d/5729.removal
Normal file
1
changelog.d/5729.removal
Normal file
@@ -0,0 +1 @@
|
||||
Synapse now no longer accepts the `-v`/`--verbose`, `-f`/`--log-file`, or `--log-config` command line flags, and removes the deprecated `verbose` and `log_file` configuration file options. Users of these options should migrate their options into the dedicated log configuration.
|
||||
1
changelog.d/5730.misc
Normal file
1
changelog.d/5730.misc
Normal file
@@ -0,0 +1 @@
|
||||
Cache result of get_version_string to reduce overhead of `/version` federation requests.
|
||||
1
changelog.d/5731.misc
Normal file
1
changelog.d/5731.misc
Normal file
@@ -0,0 +1 @@
|
||||
Return 'user_type' in admin API user endpoints results.
|
||||
1
changelog.d/5732.feature
Normal file
1
changelog.d/5732.feature
Normal file
@@ -0,0 +1 @@
|
||||
Add sd_notify hooks to ease systemd integration and allows usage of Type=Notify.
|
||||
1
changelog.d/5733.misc
Normal file
1
changelog.d/5733.misc
Normal file
@@ -0,0 +1 @@
|
||||
Don't package the sytest test blacklist file.
|
||||
1
changelog.d/5736.misc
Normal file
1
changelog.d/5736.misc
Normal file
@@ -0,0 +1 @@
|
||||
Replace uses of returnValue with plain return, as returnValue is not needed on Python 3.
|
||||
1
changelog.d/5738.misc
Normal file
1
changelog.d/5738.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5740.misc
Normal file
1
changelog.d/5740.misc
Normal file
@@ -0,0 +1 @@
|
||||
Blacklist some flakey tests in worker mode.
|
||||
1
changelog.d/5743.bugfix
Normal file
1
changelog.d/5743.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Log when we receive an event receipt from an unexpected origin.
|
||||
1
changelog.d/5746.misc
Normal file
1
changelog.d/5746.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5749.misc
Normal file
1
changelog.d/5749.misc
Normal file
@@ -0,0 +1 @@
|
||||
Fix some error cases in the caching layer.
|
||||
1
changelog.d/5750.misc
Normal file
1
changelog.d/5750.misc
Normal file
@@ -0,0 +1 @@
|
||||
Add a prometheus metric for pending cache lookups.
|
||||
1
changelog.d/5752.misc
Normal file
1
changelog.d/5752.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5753.misc
Normal file
1
changelog.d/5753.misc
Normal file
@@ -0,0 +1 @@
|
||||
Stop trying to fetch events with event_id=None.
|
||||
1
changelog.d/5754.feature
Normal file
1
changelog.d/5754.feature
Normal file
@@ -0,0 +1 @@
|
||||
Synapse will no longer serve any media repo admin endpoints when `enable_media_repo` is set to False in the configuration. If a media repo worker is used, the admin APIs relating to the media repo will be served from it instead.
|
||||
1
changelog.d/5768.misc
Normal file
1
changelog.d/5768.misc
Normal file
@@ -0,0 +1 @@
|
||||
Convert RedactionTestCase to modern test style.
|
||||
1
changelog.d/5770.misc
Normal file
1
changelog.d/5770.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5774.misc
Normal file
1
changelog.d/5774.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5775.bugfix
Normal file
1
changelog.d/5775.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix debian packaging scripts to correctly build sid packages.
|
||||
1
changelog.d/5780.misc
Normal file
1
changelog.d/5780.misc
Normal file
@@ -0,0 +1 @@
|
||||
Allow looping calls to be given arguments.
|
||||
1
changelog.d/5782.removal
Normal file
1
changelog.d/5782.removal
Normal file
@@ -0,0 +1 @@
|
||||
Remove non-functional 'expire_access_token' setting.
|
||||
1
changelog.d/5783.feature
Normal file
1
changelog.d/5783.feature
Normal file
@@ -0,0 +1 @@
|
||||
Synapse can now be configured to not join remote rooms of a given "complexity" (currently, state events) over federation. This option can be used to prevent adverse performance on resource-constrained homeservers.
|
||||
1
changelog.d/5785.misc
Normal file
1
changelog.d/5785.misc
Normal file
@@ -0,0 +1 @@
|
||||
Set the logs emitted when checking typing and presence timeouts to DEBUG level, not INFO.
|
||||
1
changelog.d/5787.misc
Normal file
1
changelog.d/5787.misc
Normal file
@@ -0,0 +1 @@
|
||||
Remove DelayedCall debugging from the test suite, as it is no longer required in the vast majority of Synapse's tests.
|
||||
1
changelog.d/5788.bugfix
Normal file
1
changelog.d/5788.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Correctly handle redactions of redactions.
|
||||
1
changelog.d/5789.bugfix
Normal file
1
changelog.d/5789.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix UISIs during homeserver outage.
|
||||
1
changelog.d/5790.misc
Normal file
1
changelog.d/5790.misc
Normal file
@@ -0,0 +1 @@
|
||||
Remove some spurious exceptions from the logs where we failed to talk to a remote server.
|
||||
1
changelog.d/5792.misc
Normal file
1
changelog.d/5792.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5793.misc
Normal file
1
changelog.d/5793.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce database IO usage by optimising queries for current membership.
|
||||
1
changelog.d/5794.misc
Normal file
1
changelog.d/5794.misc
Normal file
@@ -0,0 +1 @@
|
||||
Improve performance when making `.well-known` requests by sharing the SSL options between requests.
|
||||
1
changelog.d/5796.misc
Normal file
1
changelog.d/5796.misc
Normal file
@@ -0,0 +1 @@
|
||||
Disable codecov GitHub comments on PRs.
|
||||
1
changelog.d/5798.bugfix
Normal file
1
changelog.d/5798.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Return 404 instead of 403 when accessing /rooms/{roomId}/event/{eventId} for an event without the appropriate permissions.
|
||||
1
changelog.d/5801.misc
Normal file
1
changelog.d/5801.misc
Normal file
@@ -0,0 +1 @@
|
||||
Don't allow clients to send tombstone events that reference the room it's sent in.
|
||||
1
changelog.d/5802.misc
Normal file
1
changelog.d/5802.misc
Normal file
@@ -0,0 +1 @@
|
||||
Deny redactions of events sent in a different room.
|
||||
1
changelog.d/5804.bugfix
Normal file
1
changelog.d/5804.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix check that tombstone is a state event in push rules.
|
||||
1
changelog.d/5805.misc
Normal file
1
changelog.d/5805.misc
Normal file
@@ -0,0 +1 @@
|
||||
Deny sending well known state types as non-state events.
|
||||
1
changelog.d/5806.bugfix
Normal file
1
changelog.d/5806.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix error when trying to login as a deactivated user when using a worker to handle login.
|
||||
1
changelog.d/5807.feature
Normal file
1
changelog.d/5807.feature
Normal file
@@ -0,0 +1 @@
|
||||
Allow defining HTML templates to serve the user on account renewal attempt when using the account validity feature.
|
||||
1
changelog.d/5808.misc
Normal file
1
changelog.d/5808.misc
Normal file
@@ -0,0 +1 @@
|
||||
Handle incorrectly encoded query params correctly by returning a 400.
|
||||
1
changelog.d/5810.misc
Normal file
1
changelog.d/5810.misc
Normal file
@@ -0,0 +1 @@
|
||||
Return 502 not 500 when failing to reach any remote server.
|
||||
1
changelog.d/5825.bugfix
Normal file
1
changelog.d/5825.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix bug where user `/sync` stream could get wedged in rare circumstances.
|
||||
1
changelog.d/5826.misc
Normal file
1
changelog.d/5826.misc
Normal file
@@ -0,0 +1 @@
|
||||
Reduce global pauses in the events stream caused by expensive state resolution during persistence.
|
||||
1
changelog.d/5836.misc
Normal file
1
changelog.d/5836.misc
Normal file
@@ -0,0 +1 @@
|
||||
Add a lower bound to well-known lookup cache time to avoid repeated lookups.
|
||||
1
changelog.d/5839.bugfix
Normal file
1
changelog.d/5839.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
The purge_remote_media.sh script was fixed.
|
||||
1
changelog.d/5843.misc
Normal file
1
changelog.d/5843.misc
Normal file
@@ -0,0 +1 @@
|
||||
Whitelist history visbility sytests in worker mode tests.
|
||||
@@ -51,4 +51,4 @@ TOKEN=$(sql "SELECT token FROM access_tokens WHERE user_id='$ADMIN' ORDER BY id
|
||||
# finally start pruning media:
|
||||
###############################################################################
|
||||
set -x # for debugging the generated string
|
||||
curl --header "Authorization: Bearer $TOKEN" -v POST "$API_URL/admin/purge_media_cache/?before_ts=$UNIX_TIMESTAMP"
|
||||
curl --header "Authorization: Bearer $TOKEN" -X POST "$API_URL/admin/purge_media_cache/?before_ts=$UNIX_TIMESTAMP"
|
||||
|
||||
@@ -4,7 +4,8 @@ After=matrix-synapse.service
|
||||
BindsTo=matrix-synapse.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Type=notify
|
||||
NotifyAccess=main
|
||||
User=matrix-synapse
|
||||
WorkingDirectory=/var/lib/matrix-synapse
|
||||
EnvironmentFile=/etc/default/matrix-synapse
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
Description=Synapse Matrix Homeserver
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Type=notify
|
||||
NotifyAccess=main
|
||||
User=matrix-synapse
|
||||
WorkingDirectory=/var/lib/matrix-synapse
|
||||
EnvironmentFile=/etc/default/matrix-synapse
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
Description=Synapse Matrix homeserver
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Type=notify
|
||||
NotifyAccess=main
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
Restart=on-abort
|
||||
|
||||
User=synapse
|
||||
|
||||
@@ -29,7 +29,7 @@ for port in 8080 8081 8082; do
|
||||
|
||||
if ! grep -F "Customisation made by demo/start.sh" -q $DIR/etc/$port.config; then
|
||||
printf '\n\n# Customisation made by demo/start.sh\n' >> $DIR/etc/$port.config
|
||||
|
||||
|
||||
echo 'enable_registration: true' >> $DIR/etc/$port.config
|
||||
|
||||
# Warning, this heredoc depends on the interaction of tabs and spaces. Please don't
|
||||
@@ -43,7 +43,7 @@ for port in 8080 8081 8082; do
|
||||
tls: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
|
||||
|
||||
- port: $port
|
||||
tls: false
|
||||
bind_addresses: ['::1', '127.0.0.1']
|
||||
@@ -68,7 +68,7 @@ for port in 8080 8081 8082; do
|
||||
|
||||
# Generate tls keys
|
||||
openssl req -x509 -newkey rsa:4096 -keyout $DIR/etc/localhost\:$https_port.tls.key -out $DIR/etc/localhost\:$https_port.tls.crt -days 365 -nodes -subj "/O=matrix"
|
||||
|
||||
|
||||
# Ignore keys from the trusted keys server
|
||||
echo '# Ignore keys from the trusted keys server' >> $DIR/etc/$port.config
|
||||
echo 'trusted_key_servers:' >> $DIR/etc/$port.config
|
||||
@@ -120,7 +120,6 @@ for port in 8080 8081 8082; do
|
||||
python3 -m synapse.app.homeserver \
|
||||
--config-path "$DIR/etc/$port.config" \
|
||||
-D \
|
||||
-vv \
|
||||
|
||||
popd
|
||||
done
|
||||
|
||||
@@ -42,6 +42,11 @@ RUN cd dh-virtualenv-1.1 && dpkg-buildpackage -us -uc -b
|
||||
###
|
||||
FROM ${distro}
|
||||
|
||||
# Get the distro we want to pull from as a dynamic build variable
|
||||
# (We need to define it in each build stage)
|
||||
ARG distro=""
|
||||
ENV distro ${distro}
|
||||
|
||||
# Install the build dependencies
|
||||
#
|
||||
# NB: keep this list in sync with the list of build-deps in debian/control
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
set -ex
|
||||
|
||||
DIST=`lsb_release -c -s`
|
||||
# Get the codename from distro env
|
||||
DIST=`cut -d ':' -f2 <<< $distro`
|
||||
|
||||
# we get a read-only copy of the source: make a writeable copy
|
||||
cp -aT /synapse/source /synapse/build
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# Code Style
|
||||
Code Style
|
||||
==========
|
||||
|
||||
Formatting tools
|
||||
----------------
|
||||
|
||||
The Synapse codebase uses a number of code formatting tools in order to
|
||||
quickly and automatically check for formatting (and sometimes logical) errors
|
||||
@@ -6,20 +10,20 @@ in code.
|
||||
|
||||
The necessary tools are detailed below.
|
||||
|
||||
## Formatting tools
|
||||
- **black**
|
||||
|
||||
The Synapse codebase uses [black](https://pypi.org/project/black/) as an
|
||||
opinionated code formatter, ensuring all comitted code is properly
|
||||
formatted.
|
||||
The Synapse codebase uses `black <https://pypi.org/project/black/>`_ as an
|
||||
opinionated code formatter, ensuring all comitted code is properly
|
||||
formatted.
|
||||
|
||||
First install ``black`` with::
|
||||
First install ``black`` with::
|
||||
|
||||
pip install --upgrade black
|
||||
pip install --upgrade black
|
||||
|
||||
Have ``black`` auto-format your code (it shouldn't change any
|
||||
functionality) with::
|
||||
Have ``black`` auto-format your code (it shouldn't change any functionality)
|
||||
with::
|
||||
|
||||
black . --exclude="\.tox|build|env"
|
||||
black . --exclude="\.tox|build|env"
|
||||
|
||||
- **flake8**
|
||||
|
||||
@@ -54,17 +58,16 @@ functionality is supported in your editor for a more convenient development
|
||||
workflow. It is not, however, recommended to run ``flake8`` on save as it
|
||||
takes a while and is very resource intensive.
|
||||
|
||||
## General rules
|
||||
General rules
|
||||
-------------
|
||||
|
||||
- **Naming**:
|
||||
|
||||
- Use camel case for class and type names
|
||||
- Use underscores for functions and variables.
|
||||
|
||||
- Use double quotes ``"foo"`` rather than single quotes ``'foo'``.
|
||||
|
||||
- **Comments**: should follow the `google code style
|
||||
<http://google.github.io/styleguide/pyguide.html?showone=Comments#Comments>`_.
|
||||
- **Docstrings**: should follow the `google code style
|
||||
<https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings>`_.
|
||||
This is so that we can generate documentation with `sphinx
|
||||
<http://sphinxcontrib-napoleon.readthedocs.org/en/latest/>`_. See the
|
||||
`examples
|
||||
@@ -73,6 +76,8 @@ takes a while and is very resource intensive.
|
||||
|
||||
- **Imports**:
|
||||
|
||||
- Imports should be sorted by ``isort`` as described above.
|
||||
|
||||
- Prefer to import classes and functions rather than packages or modules.
|
||||
|
||||
Example::
|
||||
@@ -92,25 +97,84 @@ takes a while and is very resource intensive.
|
||||
This goes against the advice in the Google style guide, but it means that
|
||||
errors in the name are caught early (at import time).
|
||||
|
||||
- Multiple imports from the same package can be combined onto one line::
|
||||
|
||||
from synapse.types import GroupID, RoomID, UserID
|
||||
|
||||
An effort should be made to keep the individual imports in alphabetical
|
||||
order.
|
||||
|
||||
If the list becomes long, wrap it with parentheses and split it over
|
||||
multiple lines.
|
||||
|
||||
- As per `PEP-8 <https://www.python.org/dev/peps/pep-0008/#imports>`_,
|
||||
imports should be grouped in the following order, with a blank line between
|
||||
each group:
|
||||
|
||||
1. standard library imports
|
||||
2. related third party imports
|
||||
3. local application/library specific imports
|
||||
|
||||
- Imports within each group should be sorted alphabetically by module name.
|
||||
|
||||
- Avoid wildcard imports (``from synapse.types import *``) and relative
|
||||
imports (``from .types import UserID``).
|
||||
|
||||
Configuration file format
|
||||
-------------------------
|
||||
|
||||
The `sample configuration file <./sample_config.yaml>`_ acts as a reference to
|
||||
Synapse's configuration options for server administrators. Remember that many
|
||||
readers will be unfamiliar with YAML and server administration in general, so
|
||||
that it is important that the file be as easy to understand as possible, which
|
||||
includes following a consistent format.
|
||||
|
||||
Some guidelines follow:
|
||||
|
||||
* Sections should be separated with a heading consisting of a single line
|
||||
prefixed and suffixed with ``##``. There should be **two** blank lines
|
||||
before the section header, and **one** after.
|
||||
|
||||
* Each option should be listed in the file with the following format:
|
||||
|
||||
* A comment describing the setting. Each line of this comment should be
|
||||
prefixed with a hash (``#``) and a space.
|
||||
|
||||
The comment should describe the default behaviour (ie, what happens if
|
||||
the setting is omitted), as well as what the effect will be if the
|
||||
setting is changed.
|
||||
|
||||
Often, the comment end with something like "uncomment the
|
||||
following to \<do action>".
|
||||
|
||||
* A line consisting of only ``#``.
|
||||
|
||||
* A commented-out example setting, prefixed with only ``#``.
|
||||
|
||||
For boolean (on/off) options, convention is that this example should be
|
||||
the *opposite* to the default (so the comment will end with "Uncomment
|
||||
the following to enable [or disable] \<feature\>." For other options,
|
||||
the example should give some non-default value which is likely to be
|
||||
useful to the reader.
|
||||
|
||||
* There should be a blank line between each option.
|
||||
|
||||
* Where several settings are grouped into a single dict, *avoid* the
|
||||
convention where the whole block is commented out, resulting in comment
|
||||
lines starting ``# #``, as this is hard to read and confusing to
|
||||
edit. Instead, leave the top-level config option uncommented, and follow
|
||||
the conventions above for sub-options. Ensure that your code correctly
|
||||
handles the top-level option being set to ``None`` (as it will be if no
|
||||
sub-options are enabled).
|
||||
|
||||
* Lines should be wrapped at 80 characters.
|
||||
|
||||
Example::
|
||||
|
||||
## Frobnication ##
|
||||
|
||||
# The frobnicator will ensure that all requests are fully frobnicated.
|
||||
# To enable it, uncomment the following.
|
||||
#
|
||||
#frobnicator_enabled: true
|
||||
|
||||
# By default, the frobnicator will frobnicate with the default frobber.
|
||||
# The following will make it use an alternative frobber.
|
||||
#
|
||||
#frobincator_frobber: special_frobber
|
||||
|
||||
# Settings for the frobber
|
||||
#
|
||||
frobber:
|
||||
# frobbing speed. Defaults to 1.
|
||||
#
|
||||
#speed: 10
|
||||
|
||||
# frobbing distance. Defaults to 1000.
|
||||
#
|
||||
#distance: 100
|
||||
|
||||
Note that the sample configuration is generated from the synapse code and is
|
||||
maintained by a script, ``scripts-dev/generate_sample_config``. Making sure
|
||||
that the output from this script matches the desired format is left as an
|
||||
exercise for the reader!
|
||||
|
||||
332
docs/federation_side_bus.md
Normal file
332
docs/federation_side_bus.md
Normal file
@@ -0,0 +1,332 @@
|
||||
%%%
|
||||
title = "The Federation Side Bus"
|
||||
abbrev = "federation-side-bus"
|
||||
docName = "federation-side-bus"
|
||||
ipr = "none"
|
||||
workgroup = "Synapse"
|
||||
|
||||
[seriesInfo]
|
||||
name = "RFC"
|
||||
stream = "IETF"
|
||||
status = "informational"
|
||||
value = "federation-side-bus"
|
||||
|
||||
[pi]
|
||||
toc = "yes"
|
||||
topblock = "yes"
|
||||
|
||||
[[author]]
|
||||
initials = "A."
|
||||
surname = "Brown"
|
||||
fullname = "Amber Brown"
|
||||
organization = "New Vector"
|
||||
[author.address]
|
||||
email = "amberb@matrix.org"
|
||||
%%%
|
||||
|
||||
.# Abstract
|
||||
|
||||
Proposal for the "Federation Side Bus" project. Proposed refactoring of federation transport code as well as externally communicating code. Proposed implementation of a message-bus style system for external communication. Proposed implementation of a prioritisation system covering different remote hosts based on liveliness as well as prioritisation of outgoing requests when experiencing backpressure.
|
||||
|
||||
{mainmatter}
|
||||
|
||||
# Introduction
|
||||
|
||||
On smaller machines, Synapse has problems when interacting with the federation in large rooms. Existing experience had pointed at state resolution being the performance killer, but further research with small homeservers has revealed the performance problems when communicating with many servers. The linear characteristics of having more servers in federation turns into a significant cliff in the realm of 200 or more servers on low-powered hardware, causing a "meltdown" and causing cascading failures as the server's non-responsiveness causes timeouts to clients and other servers.
|
||||
|
||||
## Terminology
|
||||
|
||||
The keywords **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **MAY**, and **OPTIONAL**, when they appear in this document, are to be interpreted as described in [@!RFC2119].
|
||||
|
||||
Additionally, the key words "**MIGHT**", "**COULD**", "**MAY WISH TO**", "**WOULD PROBABLY**", "**SHOULD CONSIDER**", and "**MUST (BUT WE KNOW YOU WON'T)**" in this document are to interpreted as described in [@!RFC6919].
|
||||
|
||||
The keywords **PDU**, **EDU**, and **QUERY** in this document are to be interpreted as described in the Matrix Server to Server Specification [@!s2sapi].
|
||||
|
||||
**EXTERNAL COMMUNICATION** is defined as outgoing communication with another logical service, such as a web server or chat bot. Communication with the configured database, the filesystem, or with workers is not included in this definition.
|
||||
|
||||
**FEDERATION REQUESTS** are defined as any HTTP API call in the Matrix Server-to-Server specification, including PDUs, EDUs, or queries.
|
||||
|
||||
**DEFERRED** can mean either the literal Twisted Deferred, or a native coroutine that can await Deferreds. Which is used in the code depends on its use of native coroutines. APIs SHOULD try and implement native coroutines where possible, but they are described as "Deferreds" for brevity.
|
||||
|
||||
# The Status Quo
|
||||
|
||||
Synapse currently performs poorly under the following situations:
|
||||
|
||||
- Joining a room with many servers, where the presence storm can cause Synapse to lock up and time out the room join to the client, making it seem as if joining the room "failed" when it did not
|
||||
- Sending a message in a room with many servers (sending PDUs) causes CPU and RAM spikes
|
||||
- Presence and typing in a room with many servers (sending EDUs) causes CPU and RAM spikes
|
||||
- Viewing the user list of a large room, causing many concurrent profile fetches
|
||||
- Many users doing queries about remote users
|
||||
|
||||
This can be attributed to the following fundamental issues:
|
||||
|
||||
- Synapse's use of the network is unintelligent and is not aware of resource constraints (e.g. connection limits),
|
||||
- Synapse does not leverage persistent network connections and pipelining/HTTP 2.0,
|
||||
- Synapse does not gracefully degrade under pressure situations, but shows total system failure.
|
||||
|
||||
In addition, the following issues make it more difficult to fix the above without a comprehensive approach:
|
||||
|
||||
- Synapse does not assign a priority to hosts, meaning that any naive rate limiting (such as the transaction queue on `atleastfornow.net`) can cause a poor user experience as misbehaving/timing out hosts can take up a slot that a well-behaved server or servers with users that are being actively communicated with could use
|
||||
- Synapse does not assign a priority to requests, making a rudimentary rate limiting system difficult
|
||||
- Large parts of the codebase can make external requests independently
|
||||
- Synapse uses conventional HTTP clients that are poorly suited to the "message bus" style of usage that is required.
|
||||
|
||||
For large servers with workers, this can be mitigated somewhat by just throwing more hardware at the problem. For smaller ones, especially on constrained hardware (think ARM or shared hosting), this lack of rate limiting can cause hard spinning, swamping of resources, and total system failure.
|
||||
|
||||
## The Status Quo
|
||||
|
||||
Currently, Synapse talks over to other servers in the following places:
|
||||
|
||||
- Keyring (perspectives and origin), for fetching server keys
|
||||
- TransportLayerClient:
|
||||
- s.federation.federation_client
|
||||
- general federation queries
|
||||
- client key query
|
||||
- user device query
|
||||
- backfill
|
||||
- individual PDU collection
|
||||
- fetching remote room state
|
||||
- sending joins
|
||||
- sending invites
|
||||
- sending leaves
|
||||
- getting public rooms
|
||||
- querying auth chain
|
||||
- getting missing events
|
||||
- room complexity
|
||||
- s.federation.sender.transaction_manager
|
||||
- sending transactions
|
||||
- s.groups.attestations
|
||||
- fetching attestations
|
||||
- s.groups.groups_server
|
||||
- inviting and removing from group
|
||||
- s.groups.groups_client
|
||||
- fetching groups
|
||||
- fetching users from groups
|
||||
- Media Repo
|
||||
- download_remote_file (linearised)
|
||||
- Appservices
|
||||
- Identity services
|
||||
|
||||
TODO: More detail?
|
||||
|
||||
Furthermore, profiles and room directory use the general query API.
|
||||
|
||||
# Proposing The Federation Side Bus
|
||||
|
||||
The Federation Side Bus project remodels how Synapse approaches external communication. It draws naming parallels with the system bus design of personal computers and servers from the 1990s and 2000s, where the Front Side Bus was used to describe the communication interface between the CPU and its I/O systems (where the "back side bus" was instead between CPUs).
|
||||
|
||||
The core of the proposal is the definition of the "southbridge" (named for the I/O controller hub on a computer's FSB). The Southbridge is the only place where external communication is allowed to occur, and has a small but versatile interface for invoking said communication. This abstraction allows the Southbridge to be more intelligent about the use of network resources, as it can control all outbound data.
|
||||
|
||||
There are also additional abstractions and reworking of existing ones to make the internal logic more consistent. This is mostly focused on the reorganisation of the Federation code and the shifting of the Media Repo logic from being in REST servlets to handlers of their own. A reworking of ".well-known" resolution as well as hostname resolution in general is also proposed, with the end goal of increasing reliability and reducing the amount of code that needs to consider SRV/.well-known solving.
|
||||
|
||||
The Federation Side Bus will not alter Synapse's interaction with any of the Matrix standards, but will present the foundation for the future implementation of transports other than HTTP. HTTP/1.1 over TLS is targeted as the primary transport for Federation for this proposal, although HTTP/2.0 can be considered a "stretch goal" and desirable for its multiplexing and long-concurrent-connection qualities that would further reduce resource usage.
|
||||
|
||||
# Architecture
|
||||
|
||||
## The Southbridge
|
||||
|
||||
The Southbridge fully encapsulates all external communication (apart from DNS resolution). It consists of a number of queues, connection pools, and associated prioritisation and batching systems.
|
||||
|
||||
### Initial Federation Queue
|
||||
|
||||
Zero-length queue that routes Federation requests through to the host ranker.
|
||||
|
||||
### Host Ranker
|
||||
|
||||
Tracks the performance of outbound requests and routes new requests through the different queues based on Matrix host.
|
||||
|
||||
### Priority-Aware Federation Queue
|
||||
|
||||
A queue that enqueues events based on the Matrix host and requests a connection from the pool. When it has acquired a connection, it sends the events it has. If there is network pressure, the queue is responsible for giving up the connection based on a deadline. It is aware of federation semantics, and can intelligently collapse or discard EDUs or queries.
|
||||
|
||||
### The Request Queue
|
||||
|
||||
Holds HTTP requests and requests a connection from the connection pool to send them on. Used for general purpose queries (for example, .well-known lookups or URL previews).
|
||||
|
||||
### The Connection Pool
|
||||
|
||||
Holds open HTTP connections and is responsible for establishing new ones. Operates on a callback basis with the queues. Hands over a connection to the queue requesting it, and is told when the queue is done with it. Assigns deadlines for the queues to follow (e.g. time spent processing) to ensure fairness.
|
||||
|
||||
## Federation Subsystem
|
||||
|
||||
The Federation Subsystem sees a number of changes, mostly revolving around refactoring the existing code and formalising interfaces.
|
||||
|
||||
### Federation Resolver
|
||||
|
||||
Translates a Matrix homeserver hostname into "real" addresses that it can be contacted on. It is considered authoritive to the rest of the system.
|
||||
|
||||
### Externaliser
|
||||
|
||||
Queues a Federation request in the Message Queue after attaching the "real address" information.
|
||||
|
||||
### Controllers
|
||||
|
||||
Shifting of Federation logic into more logically separated modules, such as separating by purpose (messages, queries, presence, etc) for clarity.
|
||||
|
||||
## Media Subsystem
|
||||
|
||||
The functionality of the Media Repository REST APIs refactored into a handler.
|
||||
|
||||
## DNS Resolver
|
||||
|
||||
Resolves domain names to DNS records. Although informally implemented in Synapse, this new subsystem would centralise a lot of the functionality of the various DNS resolvers used.
|
||||
|
||||
# Implementation Plan
|
||||
|
||||
The implementation plan has three phases -- cleanup, plumbing, and optimising.
|
||||
|
||||
Cleanup focuses on shifting about existing code to fit the new model better. This involves implementing the Federation Resolver and cleaning up the media APIs.
|
||||
|
||||
Plumbing involves laying the groundwork for the changes. This involves writing a more controllable HTTP client, implementing the queueing and connection pool, and hooking it up to the existing Federation abstraction. The development of other queues and pools (like for URL previews, well-known lookups, etc) will also be done here, although can be done concurrently.
|
||||
|
||||
Optimising involves using these abstractions to allow Synapse to operate with network activity restrictions. This includes adding rate limiting, EDU collapsing,
|
||||
|
||||
## Decouple the Media APIs from the REST APIs
|
||||
|
||||
This should all be moved out into a handler of its own, instead of existing in the REST APIs.
|
||||
|
||||
## Implement the Federation Resolver
|
||||
|
||||
The base of the Federation Resolver can be implemented and placed in Synapse without much disruption.
|
||||
|
||||
Requirements:
|
||||
|
||||
- A ResolvedFederationAddress object which can encapsulate the results.
|
||||
- Simple, one-function-call API to fetch the information about the "real host".
|
||||
- Inputs:
|
||||
- Matrix server name.
|
||||
- Outputs:
|
||||
- Hostname to verify the TLS certificate against (which might not be the Matrix server name if .well-known is in use)
|
||||
- A list of IP addresses to contact the Matrix service by. This SHOULD contain priority and weight data to allow the connection pool to connect to preferred hosts, but MAY just be ordered in rank of preference without any priority or weight information.
|
||||
- MUST be encapsulated in a ResolvedFederationAddress object.
|
||||
|
||||
## Implement the HTTP/1.1 Transport
|
||||
|
||||
Implement in the current MatrixFederationAgent and SimpleHTTPClient, with a basic connection pool.
|
||||
|
||||
The justification for this is that the current HTTP client libraries rely on controlling the connection itself, while we want to operate on a lower level and control the connection ourselves, and give it to the client instead. It represents an inversion of the concerns, which is why we have to provide this part ourselves.
|
||||
|
||||
This is not a large asking, as the h11 library implements all the logic (and is a much more solid HTTP state machine than Twisted's current HTTP Agent implementation). If it implements IAgent, we may wish to contribute this up to Twisted.
|
||||
|
||||
Requirements:
|
||||
|
||||
- A HTTP/1.1 compliant transport.
|
||||
- SHOULD utilise the h11 library.
|
||||
- MUST support HTTP/1.1 keep-alive, but MUST NOT send multiple requests at once (pipelining).
|
||||
- SHOULD implement Twisted's IAgent/IResponse interface.
|
||||
- MUST take a TCP connection as an argument. The client MUST NOT instantiate the connection itself.
|
||||
- A basic connection pool.
|
||||
- MUST implement a method to request a connection from the ResolvedFederationAddress object that returns a Deferred resolving to the TCP connection.
|
||||
- MAY use the first IP listed in the ResolvedFederationAddress (matching current behaviour).
|
||||
- MUST verify the TLS matches the hostname in the ResolvedFederationAddress when the connection is made.
|
||||
- MUST return an error to the connection requests if the TLS connection fails.
|
||||
- SHOULD keep connections around until they time out, and serve them to subsequent requests if they are alive.
|
||||
- SHOULD NOT implement any form of rate limiting, as that will be implemented later.
|
||||
- MatrixFederationClient MUST use this connection pool and transport in place of treq.
|
||||
- MatrixFederationClient MUST query the Federation Resolver for the ResolvedFederationAddress to use.
|
||||
- Users of the MatrixFederationClient MUST NOT call the FederationResolver before making the request.
|
||||
|
||||
Questions:
|
||||
|
||||
- Do we need to support HTTP/1.0?
|
||||
- I don't think it's realistically required, and is expensive. The specification lists "HTTP/1.1" specifically in the examples, but does not call out HTTP/1.1 as the minimum supported version.
|
||||
|
||||
## Implement the Federation Queue
|
||||
|
||||
Implement the Federation Queue API. This Queue is not used at this stage.
|
||||
|
||||
Requirements:
|
||||
|
||||
- FederationResponse object
|
||||
- MUST be the root interface for the purposes of typing.
|
||||
- MUST have a common "status code" attribute with the numerical code and description.
|
||||
- FederationErrorResponse object
|
||||
- MUST implement FederationResponse
|
||||
- MUST have errcode and error from the JSON body as attributes, and all other keys in an 'other' mapping.
|
||||
- FederationQueryResponse object
|
||||
- MUST implement FederationResponse
|
||||
- MAY have further subclasses that implement particular responses to queries.
|
||||
- MUST have the JSON response as an attribute.
|
||||
- FederationTransactionResponse object
|
||||
- MUST implement FederationResponse
|
||||
- MUST have the PDU processing results as an attribute.
|
||||
|
||||
- OutgoingEDU object
|
||||
- MUST have edu_type and content as attributes.
|
||||
- MUST have the time that it was created.
|
||||
- OutgoingPDU object
|
||||
- MUST have a content attribute which contains the PDU data.
|
||||
- OutgoingQuery object
|
||||
- MUST have a template of the path.
|
||||
- MUST NOT add query or body parameters to the path.
|
||||
- MUST store the path, query, and JSON body arguments.
|
||||
- MUST implement a method that returns the fully resolved path with query arguments and the body as a dictionary, for consumption by the Queue.
|
||||
- MAY have subclasses that create more usable instantiators based on the particular query.
|
||||
|
||||
- The base FederationQueue
|
||||
- MUST request a connection from the ConnectionPool to send requests.
|
||||
- MUST return the connection to the Connection Pool when it has sent its requests.
|
||||
- MUST NOT send more requests than were initially in its queue when the connection was granted from the Pool.
|
||||
- MUST create a HTTP Transport for its uses. It MUST destroy it after the connection is returned.
|
||||
- MUST be able to encode JSON bodies and create requests.
|
||||
- MUST be able to create a transaction from the EDUs/PDUs in the queue when it has a connection.
|
||||
- MAY collapse EDUs based on their time of creation or "cancelling out".
|
||||
- MAY remove EDUs from the queue when under queue pressure.
|
||||
- SHOULD send PDUs and EDUs in the order they were given. Future implementations MAY prioritise certain PDUs over others (e.g. direct messages).
|
||||
- MUST remove EDUs/PDUs that have been sent in a transaction from the queue.
|
||||
- MUST remove queries that have been given a response from the queue.
|
||||
- MAY retry queries that fail with transient errors instead of delivering the real error to the querier.
|
||||
- MUST remove queries from the queue that have passed their wall-clock timeout and return a FederationErrorResponse, even if they have not been sent.
|
||||
- An API to add a EDU/PDU onto the Queue.
|
||||
- MUST require a ResolvedFederationAddress.
|
||||
- MUST take a OutgoingPDU or OutgoingEDU object.
|
||||
- An API to make a Federation query.
|
||||
- MUST require a ResolvedFederationAddress.
|
||||
- MUST list an acceptable timeout. This MAY be 0 to mean that the query should be retried forever.
|
||||
- MUST return a Deferred that fires with a FederationResponse.
|
||||
|
||||
Questions:
|
||||
|
||||
- Typing on interfaces -- there's a mypy zope.interface plugin?
|
||||
- What to do with backpressure on down hosts? Do we discard the queue?
|
||||
|
||||
## Handle Transactions and Queries via the Federation Queue
|
||||
|
||||
Move the FederationSender code to use the Federation Queue.
|
||||
|
||||
Requirements:
|
||||
|
||||
- Externaliser
|
||||
- Takes Queries/EDUs/PDUs and queries the Federation Resolver for the real host information, and then forwards it to the queue.
|
||||
- Synapse MUST instantiate the Externaliser, Federation Queue, and the Federation Connection Pool on startup.
|
||||
- synapse.federation.sender.FederationSender MUST send events to the Externaliser.
|
||||
- ... more words here...
|
||||
|
||||
## Implement the General Purpose Queue
|
||||
|
||||
A Queue that takes general HTTP requests and forwards them to a pool.
|
||||
|
||||
## Handle General Purpose External Communication Via the General Purpose Queue
|
||||
|
||||
Move the URL previewer, well-known lookup to use the General Purpose Queue
|
||||
|
||||
## Implement Queuing and Pooling for Pushers, Appservices, and Identity Servers
|
||||
|
||||
Questions:
|
||||
|
||||
- Is this really needed? Fitting with the existing abstraction is useful, even if it will never rate limit the pool, and we'll get the benefits of the smarter connection pooling
|
||||
|
||||
## TODO: Lay out the optimising section
|
||||
|
||||
{backmatter}
|
||||
|
||||
|
||||
<reference anchor='s2sapi' target='https://matrix.org/docs/spec/server_server/latest'>
|
||||
<front>
|
||||
<title>Federation API</title>
|
||||
<author>
|
||||
<organization>Matrix.org Foundation C.I.C.</organization>
|
||||
</author>
|
||||
<date year='2019'/>
|
||||
</front>
|
||||
</reference>
|
||||
@@ -148,7 +148,7 @@ call any other functions.
|
||||
d = more_stuff()
|
||||
result = yield d # also fine, of course
|
||||
|
||||
defer.returnValue(result)
|
||||
return result
|
||||
|
||||
def nonInlineCallbacksFun():
|
||||
logger.debug("just a wrapper really")
|
||||
|
||||
@@ -280,14 +280,20 @@ listeners:
|
||||
|
||||
# Resource-constrained Homeserver Settings
|
||||
#
|
||||
# If limit_large_remote_room_joins is True, the room complexity will be
|
||||
# If limit_remote_rooms.enabled is True, the room complexity will be
|
||||
# checked before a user joins a new remote room. If it is above
|
||||
# limit_large_remote_room_complexity, it will disallow joining or
|
||||
# limit_remote_rooms.complexity, it will disallow joining or
|
||||
# instantly leave.
|
||||
#
|
||||
# limit_remote_rooms.complexity_error can be set to customise the text
|
||||
# displayed to the user when a room above the complexity threshold has
|
||||
# its join cancelled.
|
||||
#
|
||||
# Uncomment the below lines to enable:
|
||||
#limit_large_remote_room_joins: True
|
||||
#limit_large_remote_room_complexity: 1.0
|
||||
#limit_remote_rooms:
|
||||
# enabled: True
|
||||
# complexity: 1.0
|
||||
# complexity_error: "This room is too complex."
|
||||
|
||||
# Whether to require a user to be in the room to add an alias to it.
|
||||
# Defaults to 'true'.
|
||||
@@ -559,6 +565,13 @@ log_config: "CONFDIR/SERVERNAME.log.config"
|
||||
|
||||
|
||||
|
||||
## Media Store ##
|
||||
|
||||
# Enable the media store service in the Synapse master. Uncomment the
|
||||
# following if you are using a separate media store worker.
|
||||
#
|
||||
#enable_media_repo: false
|
||||
|
||||
# Directory where uploaded images and attachments are stored.
|
||||
#
|
||||
media_store_path: "DATADIR/media_store"
|
||||
@@ -796,6 +809,16 @@ uploads_path: "DATADIR/uploads"
|
||||
# period: 6w
|
||||
# renew_at: 1w
|
||||
# renew_email_subject: "Renew your %(app)s account"
|
||||
# # Directory in which Synapse will try to find the HTML files to serve to the
|
||||
# # user when trying to renew an account. Optional, defaults to
|
||||
# # synapse/res/templates.
|
||||
# template_dir: "res/templates"
|
||||
# # HTML to be displayed to the user after they successfully renewed their
|
||||
# # account. Optional.
|
||||
# account_renewed_html_path: "account_renewed.html"
|
||||
# # HTML to be displayed when the user tries to renew an account with an invalid
|
||||
# # renewal token. Optional.
|
||||
# invalid_token_html_path: "invalid_token.html"
|
||||
|
||||
# Time that a user's session remains valid for, after they log in.
|
||||
#
|
||||
@@ -936,10 +959,6 @@ uploads_path: "DATADIR/uploads"
|
||||
#
|
||||
# macaroon_secret_key: <PRIVATE STRING>
|
||||
|
||||
# Used to enable access token expiration.
|
||||
#
|
||||
#expire_access_token: False
|
||||
|
||||
# a secret which is used to calculate HMACs for form values, to stop
|
||||
# falsification of values. Must be specified for the User Consent
|
||||
# forms to work.
|
||||
@@ -1441,3 +1460,19 @@ opentracing:
|
||||
#
|
||||
#homeserver_whitelist:
|
||||
# - ".*"
|
||||
|
||||
# Jaeger can be configured to sample traces at different rates.
|
||||
# All configuration options provided by Jaeger can be set here.
|
||||
# Jaeger's configuration mostly related to trace sampling which
|
||||
# is documented here:
|
||||
# https://www.jaegertracing.io/docs/1.13/sampling/.
|
||||
#
|
||||
#jaeger_config:
|
||||
# sampler:
|
||||
# type: const
|
||||
# param: 1
|
||||
|
||||
# Logging whether spans were started and reported
|
||||
#
|
||||
# logging:
|
||||
# false
|
||||
|
||||
@@ -206,6 +206,13 @@ Handles the media repository. It can handle all endpoints starting with::
|
||||
|
||||
/_matrix/media/
|
||||
|
||||
And the following regular expressions matching media-specific administration
|
||||
APIs::
|
||||
|
||||
^/_synapse/admin/v1/purge_media_cache$
|
||||
^/_synapse/admin/v1/room/.*/media$
|
||||
^/_synapse/admin/v1/quarantine_media/.*$
|
||||
|
||||
You should also set ``enable_media_repo: False`` in the shared configuration
|
||||
file to stop the main synapse running background jobs related to managing the
|
||||
media repository.
|
||||
|
||||
@@ -128,7 +128,7 @@ class Auth(object):
|
||||
)
|
||||
|
||||
self._check_joined_room(member, user_id, room_id)
|
||||
defer.returnValue(member)
|
||||
return member
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def check_user_was_in_room(self, room_id, user_id):
|
||||
@@ -156,13 +156,13 @@ class Auth(object):
|
||||
if forgot:
|
||||
raise AuthError(403, "User %s not in room %s" % (user_id, room_id))
|
||||
|
||||
defer.returnValue(member)
|
||||
return member
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def check_host_in_room(self, room_id, host):
|
||||
with Measure(self.clock, "check_host_in_room"):
|
||||
latest_event_ids = yield self.store.is_host_joined(room_id, host)
|
||||
defer.returnValue(latest_event_ids)
|
||||
return latest_event_ids
|
||||
|
||||
def _check_joined_room(self, member, user_id, room_id):
|
||||
if not member or member.membership != Membership.JOIN:
|
||||
@@ -219,9 +219,7 @@ class Auth(object):
|
||||
device_id="dummy-device", # stubbed
|
||||
)
|
||||
|
||||
defer.returnValue(
|
||||
synapse.types.create_requester(user_id, app_service=app_service)
|
||||
)
|
||||
return synapse.types.create_requester(user_id, app_service=app_service)
|
||||
|
||||
user_info = yield self.get_user_by_access_token(access_token, rights)
|
||||
user = user_info["user"]
|
||||
@@ -262,10 +260,8 @@ class Auth(object):
|
||||
|
||||
request.authenticated_entity = user.to_string()
|
||||
|
||||
defer.returnValue(
|
||||
synapse.types.create_requester(
|
||||
user, token_id, is_guest, device_id, app_service=app_service
|
||||
)
|
||||
return synapse.types.create_requester(
|
||||
user, token_id, is_guest, device_id, app_service=app_service
|
||||
)
|
||||
except KeyError:
|
||||
raise MissingClientTokenError()
|
||||
@@ -276,25 +272,25 @@ class Auth(object):
|
||||
self.get_access_token_from_request(request)
|
||||
)
|
||||
if app_service is None:
|
||||
defer.returnValue((None, None))
|
||||
return (None, None)
|
||||
|
||||
if app_service.ip_range_whitelist:
|
||||
ip_address = IPAddress(self.hs.get_ip_from_request(request))
|
||||
if ip_address not in app_service.ip_range_whitelist:
|
||||
defer.returnValue((None, None))
|
||||
return (None, None)
|
||||
|
||||
if b"user_id" not in request.args:
|
||||
defer.returnValue((app_service.sender, app_service))
|
||||
return (app_service.sender, app_service)
|
||||
|
||||
user_id = request.args[b"user_id"][0].decode("utf8")
|
||||
if app_service.sender == user_id:
|
||||
defer.returnValue((app_service.sender, app_service))
|
||||
return (app_service.sender, app_service)
|
||||
|
||||
if not app_service.is_interested_in_user(user_id):
|
||||
raise AuthError(403, "Application service cannot masquerade as this user.")
|
||||
if not (yield self.store.get_user_by_id(user_id)):
|
||||
raise AuthError(403, "Application service has not registered this user")
|
||||
defer.returnValue((user_id, app_service))
|
||||
return (user_id, app_service)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def get_user_by_access_token(self, token, rights="access"):
|
||||
@@ -330,7 +326,7 @@ class Auth(object):
|
||||
msg="Access token has expired", soft_logout=True
|
||||
)
|
||||
|
||||
defer.returnValue(r)
|
||||
return r
|
||||
|
||||
# otherwise it needs to be a valid macaroon
|
||||
try:
|
||||
@@ -378,7 +374,7 @@ class Auth(object):
|
||||
}
|
||||
else:
|
||||
raise RuntimeError("Unknown rights setting %s", rights)
|
||||
defer.returnValue(ret)
|
||||
return ret
|
||||
except (
|
||||
_InvalidMacaroonException,
|
||||
pymacaroons.exceptions.MacaroonException,
|
||||
@@ -414,21 +410,16 @@ class Auth(object):
|
||||
try:
|
||||
user_id = self.get_user_id_from_macaroon(macaroon)
|
||||
|
||||
has_expiry = False
|
||||
guest = False
|
||||
for caveat in macaroon.caveats:
|
||||
if caveat.caveat_id.startswith("time "):
|
||||
has_expiry = True
|
||||
elif caveat.caveat_id == "guest = true":
|
||||
if caveat.caveat_id == "guest = true":
|
||||
guest = True
|
||||
|
||||
self.validate_macaroon(
|
||||
macaroon, rights, self.hs.config.expire_access_token, user_id=user_id
|
||||
)
|
||||
self.validate_macaroon(macaroon, rights, user_id=user_id)
|
||||
except (pymacaroons.exceptions.MacaroonException, TypeError, ValueError):
|
||||
raise InvalidClientTokenError("Invalid macaroon passed.")
|
||||
|
||||
if not has_expiry and rights == "access":
|
||||
if rights == "access":
|
||||
self.token_cache[token] = (user_id, guest)
|
||||
|
||||
return user_id, guest
|
||||
@@ -454,7 +445,7 @@ class Auth(object):
|
||||
return caveat.caveat_id[len(user_prefix) :]
|
||||
raise InvalidClientTokenError("No user caveat in macaroon")
|
||||
|
||||
def validate_macaroon(self, macaroon, type_string, verify_expiry, user_id):
|
||||
def validate_macaroon(self, macaroon, type_string, user_id):
|
||||
"""
|
||||
validate that a Macaroon is understood by and was signed by this server.
|
||||
|
||||
@@ -462,7 +453,6 @@ class Auth(object):
|
||||
macaroon(pymacaroons.Macaroon): The macaroon to validate
|
||||
type_string(str): The kind of token required (e.g. "access",
|
||||
"delete_pusher")
|
||||
verify_expiry(bool): Whether to verify whether the macaroon has expired.
|
||||
user_id (str): The user_id required
|
||||
"""
|
||||
v = pymacaroons.Verifier()
|
||||
@@ -475,19 +465,7 @@ class Auth(object):
|
||||
v.satisfy_exact("type = " + type_string)
|
||||
v.satisfy_exact("user_id = %s" % user_id)
|
||||
v.satisfy_exact("guest = true")
|
||||
|
||||
# verify_expiry should really always be True, but there exist access
|
||||
# tokens in the wild which expire when they should not, so we can't
|
||||
# enforce expiry yet (so we have to allow any caveat starting with
|
||||
# 'time < ' in access tokens).
|
||||
#
|
||||
# On the other hand, short-term login tokens (as used by CAS login, for
|
||||
# example) have an expiry time which we do want to enforce.
|
||||
|
||||
if verify_expiry:
|
||||
v.satisfy_general(self._verify_expiry)
|
||||
else:
|
||||
v.satisfy_general(lambda c: c.startswith("time < "))
|
||||
v.satisfy_general(self._verify_expiry)
|
||||
|
||||
# access_tokens include a nonce for uniqueness: any value is acceptable
|
||||
v.satisfy_general(lambda c: c.startswith("nonce = "))
|
||||
@@ -506,7 +484,7 @@ class Auth(object):
|
||||
def _look_up_user_by_access_token(self, token):
|
||||
ret = yield self.store.get_user_by_access_token(token)
|
||||
if not ret:
|
||||
defer.returnValue(None)
|
||||
return None
|
||||
|
||||
# we use ret.get() below because *lots* of unit tests stub out
|
||||
# get_user_by_access_token in a way where it only returns a couple of
|
||||
@@ -518,7 +496,7 @@ class Auth(object):
|
||||
"device_id": ret.get("device_id"),
|
||||
"valid_until_ms": ret.get("valid_until_ms"),
|
||||
}
|
||||
defer.returnValue(user_info)
|
||||
return user_info
|
||||
|
||||
def get_appservice_by_req(self, request):
|
||||
token = self.get_access_token_from_request(request)
|
||||
@@ -543,7 +521,7 @@ class Auth(object):
|
||||
@defer.inlineCallbacks
|
||||
def compute_auth_events(self, event, current_state_ids, for_verification=False):
|
||||
if event.type == EventTypes.Create:
|
||||
defer.returnValue([])
|
||||
return []
|
||||
|
||||
auth_ids = []
|
||||
|
||||
@@ -604,7 +582,7 @@ class Auth(object):
|
||||
if member_event.content["membership"] == Membership.JOIN:
|
||||
auth_ids.append(member_event.event_id)
|
||||
|
||||
defer.returnValue(auth_ids)
|
||||
return auth_ids
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def check_can_change_room_list(self, room_id, user):
|
||||
@@ -618,7 +596,7 @@ class Auth(object):
|
||||
|
||||
is_admin = yield self.is_server_admin(user)
|
||||
if is_admin:
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
|
||||
user_id = user.to_string()
|
||||
yield self.check_joined_room(room_id, user_id)
|
||||
@@ -712,7 +690,7 @@ class Auth(object):
|
||||
# * The user is a guest user, and has joined the room
|
||||
# else it will throw.
|
||||
member_event = yield self.check_user_was_in_room(room_id, user_id)
|
||||
defer.returnValue((member_event.membership, member_event.event_id))
|
||||
return (member_event.membership, member_event.event_id)
|
||||
except AuthError:
|
||||
visibility = yield self.state.get_current_state(
|
||||
room_id, EventTypes.RoomHistoryVisibility, ""
|
||||
@@ -721,7 +699,7 @@ class Auth(object):
|
||||
visibility
|
||||
and visibility.content["history_visibility"] == "world_readable"
|
||||
):
|
||||
defer.returnValue((Membership.JOIN, None))
|
||||
return (Membership.JOIN, None)
|
||||
return
|
||||
raise AuthError(
|
||||
403, "Guest access not allowed", errcode=Codes.GUEST_ACCESS_FORBIDDEN
|
||||
|
||||
@@ -61,6 +61,7 @@ class Codes(object):
|
||||
INCOMPATIBLE_ROOM_VERSION = "M_INCOMPATIBLE_ROOM_VERSION"
|
||||
WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
|
||||
EXPIRED_ACCOUNT = "ORG_MATRIX_EXPIRED_ACCOUNT"
|
||||
USER_DEACTIVATED = "M_USER_DEACTIVATED"
|
||||
|
||||
|
||||
class CodeMessageException(RuntimeError):
|
||||
@@ -151,7 +152,7 @@ class UserDeactivatedError(SynapseError):
|
||||
msg (str): The human-readable error message
|
||||
"""
|
||||
super(UserDeactivatedError, self).__init__(
|
||||
code=http_client.FORBIDDEN, msg=msg, errcode=Codes.UNKNOWN
|
||||
code=http_client.FORBIDDEN, msg=msg, errcode=Codes.USER_DEACTIVATED
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ class Filtering(object):
|
||||
@defer.inlineCallbacks
|
||||
def get_user_filter(self, user_localpart, filter_id):
|
||||
result = yield self.store.get_user_filter(user_localpart, filter_id)
|
||||
defer.returnValue(FilterCollection(result))
|
||||
return FilterCollection(result)
|
||||
|
||||
def add_user_filter(self, user_localpart, user_filter):
|
||||
self.check_valid_filter(user_filter)
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
|
||||
import gc
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import sdnotify
|
||||
from daemonize import Daemonize
|
||||
|
||||
from twisted.internet import defer, error, reactor
|
||||
@@ -242,9 +244,16 @@ def start(hs, listeners=None):
|
||||
if hasattr(signal, "SIGHUP"):
|
||||
|
||||
def handle_sighup(*args, **kwargs):
|
||||
# Tell systemd our state, if we're using it. This will silently fail if
|
||||
# we're not using systemd.
|
||||
sd_channel = sdnotify.SystemdNotifier()
|
||||
sd_channel.notify("RELOADING=1")
|
||||
|
||||
for i in _sighup_callbacks:
|
||||
i(hs)
|
||||
|
||||
sd_channel.notify("READY=1")
|
||||
|
||||
signal.signal(signal.SIGHUP, handle_sighup)
|
||||
|
||||
register_sighup(refresh_certificate)
|
||||
@@ -260,6 +269,7 @@ def start(hs, listeners=None):
|
||||
hs.get_datastore().start_profiling()
|
||||
|
||||
setup_sentry(hs)
|
||||
setup_sdnotify(hs)
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
reactor = hs.get_reactor()
|
||||
@@ -292,6 +302,25 @@ def setup_sentry(hs):
|
||||
scope.set_tag("worker_name", name)
|
||||
|
||||
|
||||
def setup_sdnotify(hs):
|
||||
"""Adds process state hooks to tell systemd what we are up to.
|
||||
"""
|
||||
|
||||
# Tell systemd our state, if we're using it. This will silently fail if
|
||||
# we're not using systemd.
|
||||
sd_channel = sdnotify.SystemdNotifier()
|
||||
|
||||
hs.get_reactor().addSystemEventTrigger(
|
||||
"after",
|
||||
"startup",
|
||||
lambda: sd_channel.notify("READY=1\nMAINPID=%s" % (os.getpid())),
|
||||
)
|
||||
|
||||
hs.get_reactor().addSystemEventTrigger(
|
||||
"before", "shutdown", lambda: sd_channel.notify("STOPPING=1")
|
||||
)
|
||||
|
||||
|
||||
def install_dns_limiter(reactor, max_dns_requests_in_flight=100):
|
||||
"""Replaces the resolver with one that limits the number of in flight DNS
|
||||
requests.
|
||||
|
||||
@@ -168,7 +168,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ps.setup()
|
||||
reactor.callWhenRunning(_base.start, ps, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ps, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-appservice", config)
|
||||
|
||||
|
||||
@@ -194,7 +194,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-client-reader", config)
|
||||
|
||||
|
||||
@@ -193,7 +193,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-event-creator", config)
|
||||
|
||||
|
||||
@@ -175,7 +175,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-federation-reader", config)
|
||||
|
||||
|
||||
@@ -198,7 +198,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-federation-sender", config)
|
||||
|
||||
|
||||
@@ -70,12 +70,12 @@ class PresenceStatusStubServlet(RestServlet):
|
||||
except HttpResponseException as e:
|
||||
raise e.to_synapse_error()
|
||||
|
||||
defer.returnValue((200, result))
|
||||
return (200, result)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, user_id):
|
||||
yield self.auth.get_user_by_req(request)
|
||||
defer.returnValue((200, {}))
|
||||
return (200, {})
|
||||
|
||||
|
||||
class KeyUploadServlet(RestServlet):
|
||||
@@ -126,11 +126,11 @@ class KeyUploadServlet(RestServlet):
|
||||
self.main_uri + request.uri.decode("ascii"), body, headers=headers
|
||||
)
|
||||
|
||||
defer.returnValue((200, result))
|
||||
return (200, result)
|
||||
else:
|
||||
# Just interested in counts.
|
||||
result = yield self.store.count_e2e_one_time_keys(user_id, device_id)
|
||||
defer.returnValue((200, {"one_time_key_counts": result}))
|
||||
return (200, {"one_time_key_counts": result})
|
||||
|
||||
|
||||
class FrontendProxySlavedStore(
|
||||
@@ -247,7 +247,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-frontend-proxy", config)
|
||||
|
||||
|
||||
4
synapse/app/homeserver.py
Executable file → Normal file
4
synapse/app/homeserver.py
Executable file → Normal file
@@ -406,7 +406,7 @@ def setup(config_options):
|
||||
if provision:
|
||||
yield acme.provision_certificate()
|
||||
|
||||
defer.returnValue(provision)
|
||||
return provision
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def reprovision_acme():
|
||||
@@ -447,7 +447,7 @@ def setup(config_options):
|
||||
reactor.stop()
|
||||
sys.exit(1)
|
||||
|
||||
reactor.callWhenRunning(start)
|
||||
reactor.addSystemEventTrigger("before", "startup", start)
|
||||
|
||||
return hs
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ from synapse.app import _base
|
||||
from synapse.config._base import ConfigError
|
||||
from synapse.config.homeserver import HomeServerConfig
|
||||
from synapse.config.logger import setup_logging
|
||||
from synapse.http.server import JsonResource
|
||||
from synapse.http.site import SynapseSite
|
||||
from synapse.logging.context import LoggingContext
|
||||
from synapse.metrics import METRICS_PREFIX, MetricsResource, RegistryProxy
|
||||
@@ -35,6 +36,7 @@ from synapse.replication.slave.storage.client_ips import SlavedClientIpStore
|
||||
from synapse.replication.slave.storage.registration import SlavedRegistrationStore
|
||||
from synapse.replication.slave.storage.transactions import SlavedTransactionStore
|
||||
from synapse.replication.tcp.client import ReplicationClientHandler
|
||||
from synapse.rest.admin import register_servlets_for_media_repo
|
||||
from synapse.rest.media.v0.content_repository import ContentRepoResource
|
||||
from synapse.server import HomeServer
|
||||
from synapse.storage.engines import create_engine
|
||||
@@ -71,6 +73,12 @@ class MediaRepositoryServer(HomeServer):
|
||||
resources[METRICS_PREFIX] = MetricsResource(RegistryProxy)
|
||||
elif name == "media":
|
||||
media_repo = self.get_media_repository_resource()
|
||||
|
||||
# We need to serve the admin servlets for media on the
|
||||
# worker.
|
||||
admin_resource = JsonResource(self, canonical_json=False)
|
||||
register_servlets_for_media_repo(self, admin_resource)
|
||||
|
||||
resources.update(
|
||||
{
|
||||
MEDIA_PREFIX: media_repo,
|
||||
@@ -78,6 +86,7 @@ class MediaRepositoryServer(HomeServer):
|
||||
CONTENT_REPO_PREFIX: ContentRepoResource(
|
||||
self, self.config.uploads_path
|
||||
),
|
||||
"/_synapse/admin": admin_resource,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -161,7 +170,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-media-repository", config)
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ def start(config_options):
|
||||
_base.start(ps, config.worker_listeners)
|
||||
ps.get_pusherpool().start()
|
||||
|
||||
reactor.callWhenRunning(start)
|
||||
reactor.addSystemEventTrigger("before", "startup", start)
|
||||
|
||||
_base.start_worker_reactor("synapse-pusher", config)
|
||||
|
||||
|
||||
@@ -451,7 +451,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-synchrotron", config)
|
||||
|
||||
|
||||
@@ -224,7 +224,9 @@ def start(config_options):
|
||||
)
|
||||
|
||||
ss.setup()
|
||||
reactor.callWhenRunning(_base.start, ss, config.worker_listeners)
|
||||
reactor.addSystemEventTrigger(
|
||||
"before", "startup", _base.start, ss, config.worker_listeners
|
||||
)
|
||||
|
||||
_base.start_worker_reactor("synapse-user-dir", config)
|
||||
|
||||
|
||||
@@ -175,21 +175,21 @@ class ApplicationService(object):
|
||||
@defer.inlineCallbacks
|
||||
def _matches_user(self, event, store):
|
||||
if not event:
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
|
||||
if self.is_interested_in_user(event.sender):
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
# also check m.room.member state key
|
||||
if event.type == EventTypes.Member and self.is_interested_in_user(
|
||||
event.state_key
|
||||
):
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
|
||||
if not store:
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
|
||||
does_match = yield self._matches_user_in_member_list(event.room_id, store)
|
||||
defer.returnValue(does_match)
|
||||
return does_match
|
||||
|
||||
@cachedInlineCallbacks(num_args=1, cache_context=True)
|
||||
def _matches_user_in_member_list(self, room_id, store, cache_context):
|
||||
@@ -200,8 +200,8 @@ class ApplicationService(object):
|
||||
# check joined member events
|
||||
for user_id in member_list:
|
||||
if self.is_interested_in_user(user_id):
|
||||
defer.returnValue(True)
|
||||
defer.returnValue(False)
|
||||
return True
|
||||
return False
|
||||
|
||||
def _matches_room_id(self, event):
|
||||
if hasattr(event, "room_id"):
|
||||
@@ -211,13 +211,13 @@ class ApplicationService(object):
|
||||
@defer.inlineCallbacks
|
||||
def _matches_aliases(self, event, store):
|
||||
if not store or not event:
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
|
||||
alias_list = yield store.get_aliases_for_room(event.room_id)
|
||||
for alias in alias_list:
|
||||
if self.is_interested_in_alias(alias):
|
||||
defer.returnValue(True)
|
||||
defer.returnValue(False)
|
||||
return True
|
||||
return False
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def is_interested(self, event, store=None):
|
||||
@@ -231,15 +231,15 @@ class ApplicationService(object):
|
||||
"""
|
||||
# Do cheap checks first
|
||||
if self._matches_room_id(event):
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
|
||||
if (yield self._matches_aliases(event, store)):
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
|
||||
if (yield self._matches_user(event, store)):
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
|
||||
def is_interested_in_user(self, user_id):
|
||||
return (
|
||||
|
||||
@@ -97,40 +97,40 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
@defer.inlineCallbacks
|
||||
def query_user(self, service, user_id):
|
||||
if service.url is None:
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
uri = service.url + ("/users/%s" % urllib.parse.quote(user_id))
|
||||
response = None
|
||||
try:
|
||||
response = yield self.get_json(uri, {"access_token": service.hs_token})
|
||||
if response is not None: # just an empty json object
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
except CodeMessageException as e:
|
||||
if e.code == 404:
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
return
|
||||
logger.warning("query_user to %s received %s", uri, e.code)
|
||||
except Exception as ex:
|
||||
logger.warning("query_user to %s threw exception %s", uri, ex)
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def query_alias(self, service, alias):
|
||||
if service.url is None:
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
uri = service.url + ("/rooms/%s" % urllib.parse.quote(alias))
|
||||
response = None
|
||||
try:
|
||||
response = yield self.get_json(uri, {"access_token": service.hs_token})
|
||||
if response is not None: # just an empty json object
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
except CodeMessageException as e:
|
||||
logger.warning("query_alias to %s received %s", uri, e.code)
|
||||
if e.code == 404:
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
return
|
||||
except Exception as ex:
|
||||
logger.warning("query_alias to %s threw exception %s", uri, ex)
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def query_3pe(self, service, kind, protocol, fields):
|
||||
@@ -141,7 +141,7 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
else:
|
||||
raise ValueError("Unrecognised 'kind' argument %r to query_3pe()", kind)
|
||||
if service.url is None:
|
||||
defer.returnValue([])
|
||||
return []
|
||||
|
||||
uri = "%s%s/thirdparty/%s/%s" % (
|
||||
service.url,
|
||||
@@ -155,7 +155,7 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
logger.warning(
|
||||
"query_3pe to %s returned an invalid response %r", uri, response
|
||||
)
|
||||
defer.returnValue([])
|
||||
return []
|
||||
|
||||
ret = []
|
||||
for r in response:
|
||||
@@ -166,14 +166,14 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
"query_3pe to %s returned an invalid result %r", uri, r
|
||||
)
|
||||
|
||||
defer.returnValue(ret)
|
||||
return ret
|
||||
except Exception as ex:
|
||||
logger.warning("query_3pe to %s threw exception %s", uri, ex)
|
||||
defer.returnValue([])
|
||||
return []
|
||||
|
||||
def get_3pe_protocol(self, service, protocol):
|
||||
if service.url is None:
|
||||
defer.returnValue({})
|
||||
return {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _get():
|
||||
@@ -189,7 +189,7 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
logger.warning(
|
||||
"query_3pe_protocol to %s did not return a" " valid result", uri
|
||||
)
|
||||
defer.returnValue(None)
|
||||
return None
|
||||
|
||||
for instance in info.get("instances", []):
|
||||
network_id = instance.get("network_id", None)
|
||||
@@ -198,10 +198,10 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
service.id, network_id
|
||||
).to_string()
|
||||
|
||||
defer.returnValue(info)
|
||||
return info
|
||||
except Exception as ex:
|
||||
logger.warning("query_3pe_protocol to %s threw exception %s", uri, ex)
|
||||
defer.returnValue(None)
|
||||
return None
|
||||
|
||||
key = (service.id, protocol)
|
||||
return self.protocol_meta_cache.wrap(key, _get)
|
||||
@@ -209,7 +209,7 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
@defer.inlineCallbacks
|
||||
def push_bulk(self, service, events, txn_id=None):
|
||||
if service.url is None:
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
|
||||
events = self._serialize(events)
|
||||
|
||||
@@ -229,14 +229,14 @@ class ApplicationServiceApi(SimpleHttpClient):
|
||||
)
|
||||
sent_transactions_counter.labels(service.id).inc()
|
||||
sent_events_counter.labels(service.id).inc(len(events))
|
||||
defer.returnValue(True)
|
||||
return True
|
||||
return
|
||||
except CodeMessageException as e:
|
||||
logger.warning("push_bulk to %s received %s", uri, e.code)
|
||||
except Exception as ex:
|
||||
logger.warning("push_bulk to %s threw exception %s", uri, ex)
|
||||
failed_transactions_counter.labels(service.id).inc()
|
||||
defer.returnValue(False)
|
||||
return False
|
||||
|
||||
def _serialize(self, events):
|
||||
time_now = self.clock.time_msec()
|
||||
|
||||
@@ -193,7 +193,7 @@ class _TransactionController(object):
|
||||
@defer.inlineCallbacks
|
||||
def _is_service_up(self, service):
|
||||
state = yield self.store.get_appservice_state(service)
|
||||
defer.returnValue(state == ApplicationServiceState.UP or state is None)
|
||||
return state == ApplicationServiceState.UP or state is None
|
||||
|
||||
|
||||
class _Recoverer(object):
|
||||
@@ -208,7 +208,7 @@ class _Recoverer(object):
|
||||
r.service.id,
|
||||
)
|
||||
r.recover()
|
||||
defer.returnValue(recoverers)
|
||||
return recoverers
|
||||
|
||||
def __init__(self, clock, store, as_api, service, callback):
|
||||
self.clock = clock
|
||||
|
||||
@@ -116,8 +116,6 @@ class KeyConfig(Config):
|
||||
seed = bytes(self.signing_key[0])
|
||||
self.macaroon_secret_key = hashlib.sha256(seed).digest()
|
||||
|
||||
self.expire_access_token = config.get("expire_access_token", False)
|
||||
|
||||
# a secret which is used to calculate HMACs for form values, to stop
|
||||
# falsification of values
|
||||
self.form_secret = config.get("form_secret", None)
|
||||
@@ -144,10 +142,6 @@ class KeyConfig(Config):
|
||||
#
|
||||
%(macaroon_secret_key)s
|
||||
|
||||
# Used to enable access token expiration.
|
||||
#
|
||||
#expire_access_token: False
|
||||
|
||||
# a secret which is used to calculate HMACs for form values, to stop
|
||||
# falsification of values. Must be specified for the User Consent
|
||||
# forms to work.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user