mirror of
https://github.com/element-hq/synapse.git
synced 2025-12-09 01:30:18 +00:00
Compare commits
71 Commits
anoa/log_e
...
v1.52.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cdd491310 | ||
|
|
7d56b6c083 | ||
|
|
b7282fe7d1 | ||
|
|
a35e9db9be | ||
|
|
901b264c0c | ||
|
|
0da2301b21 | ||
|
|
02755c3188 | ||
|
|
7eb198ddc8 | ||
|
|
bf60da1a60 | ||
|
|
6d482ba259 | ||
|
|
57e4786e90 | ||
|
|
fd65139714 | ||
|
|
ec07062e31 | ||
|
|
cef0d5d90a | ||
|
|
2d3bd9aa67 | ||
|
|
2897fb6b4f | ||
|
|
d8df8e6c14 | ||
|
|
c5815567a4 | ||
|
|
95b3f952fa | ||
|
|
74e4419eb4 | ||
|
|
b8bf600700 | ||
|
|
6a72c910f1 | ||
|
|
0938f32e93 | ||
|
|
1d5f7b2cc6 | ||
|
|
b59d285f7c | ||
|
|
fc8598bc87 | ||
|
|
4210143f53 | ||
|
|
6911604a0f | ||
|
|
8e45dfbe25 | ||
|
|
b500fcbc0c | ||
|
|
105fbce55c | ||
|
|
0d6cfea9b8 | ||
|
|
343d4f13d8 | ||
|
|
6e9e923ed5 | ||
|
|
874365fc05 | ||
|
|
15c2a6a106 | ||
|
|
2d327d25bf | ||
|
|
02d99f044e | ||
|
|
ec2271ac50 | ||
|
|
807efd26ae | ||
|
|
c3040dd5cc | ||
|
|
36f37acf53 | ||
|
|
df54c8485a | ||
|
|
8ff465d206 | ||
|
|
14b45b25dd | ||
|
|
dc671d3ea7 | ||
|
|
9006ee36d1 | ||
|
|
f8cf02b200 | ||
|
|
ffc61d1b69 | ||
|
|
2d295a4be9 | ||
|
|
2aa37a4250 | ||
|
|
ea579a478a | ||
|
|
266df5c908 | ||
|
|
7a11509d17 | ||
|
|
b784299cbc | ||
|
|
9f2016e96e | ||
|
|
2277275485 | ||
|
|
c027bc0e4b | ||
|
|
4c2096599c | ||
|
|
e83520cc42 | ||
|
|
bfe6d5553a | ||
|
|
d09099642e | ||
|
|
121b9e2475 | ||
|
|
7bf2d6c268 | ||
|
|
56834ab779 | ||
|
|
91221b6961 | ||
|
|
f160fe18e3 | ||
|
|
fa583c2198 | ||
|
|
af13a3be29 | ||
|
|
5572e6cc4b | ||
|
|
c072c0b829 |
@@ -1,12 +1,14 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
# this script is run by GitHub Actions in a plain `focal` container; it installs the
|
||||||
# this script is run by GitHub Actions in a plain `bionic` container; it installs the
|
|
||||||
# minimal requirements for tox and hands over to the py3-old tox environment.
|
# minimal requirements for tox and hands over to the py3-old tox environment.
|
||||||
|
|
||||||
|
# Prevent tzdata from asking for user input
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y python3 python3-dev python3-pip libxml2-dev libxslt-dev xmlsec1 zlib1g-dev tox
|
apt-get install -y python3 python3-dev python3-pip libxml2-dev libxslt-dev xmlsec1 zlib1g-dev tox libjpeg-dev libwebp-dev
|
||||||
|
|
||||||
export LANG="C.UTF-8"
|
export LANG="C.UTF-8"
|
||||||
|
|
||||||
|
|||||||
14
.github/workflows/docker.yml
vendored
14
.github/workflows/docker.yml
vendored
@@ -34,6 +34,8 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
# TODO: consider using https://github.com/docker/metadata-action instead of this
|
||||||
|
# custom magic
|
||||||
- name: Calculate docker image tag
|
- name: Calculate docker image tag
|
||||||
id: set-tag
|
id: set-tag
|
||||||
run: |
|
run: |
|
||||||
@@ -53,18 +55,6 @@ jobs:
|
|||||||
esac
|
esac
|
||||||
echo "::set-output name=tag::$tag"
|
echo "::set-output name=tag::$tag"
|
||||||
|
|
||||||
# for release builds, we want to get the amd64 image out asap, so first
|
|
||||||
# we do an amd64-only build, before following up with a multiarch build.
|
|
||||||
- name: Build and push amd64
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
if: "${{ startsWith(github.ref, 'refs/tags/v') }}"
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
labels: "gitsha1=${{ github.sha }}"
|
|
||||||
tags: "matrixdotorg/synapse:${{ steps.set-tag.outputs.tag }}"
|
|
||||||
file: "docker/Dockerfile"
|
|
||||||
platforms: linux/amd64
|
|
||||||
|
|
||||||
- name: Build and push all platforms
|
- name: Build and push all platforms
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
36
.github/workflows/tests.yml
vendored
36
.github/workflows/tests.yml
vendored
@@ -141,7 +141,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Test with old deps
|
- name: Test with old deps
|
||||||
uses: docker://ubuntu:bionic # For old python and sqlite
|
uses: docker://ubuntu:focal # For old python and sqlite
|
||||||
with:
|
with:
|
||||||
workdir: /github/workspace
|
workdir: /github/workspace
|
||||||
entrypoint: .ci/scripts/test_old_deps.sh
|
entrypoint: .ci/scripts/test_old_deps.sh
|
||||||
@@ -213,15 +213,15 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- sytest-tag: bionic
|
- sytest-tag: focal
|
||||||
|
|
||||||
- sytest-tag: bionic
|
- sytest-tag: focal
|
||||||
postgres: postgres
|
postgres: postgres
|
||||||
|
|
||||||
- sytest-tag: testing
|
- sytest-tag: testing
|
||||||
postgres: postgres
|
postgres: postgres
|
||||||
|
|
||||||
- sytest-tag: bionic
|
- sytest-tag: focal
|
||||||
postgres: multi-postgres
|
postgres: multi-postgres
|
||||||
workers: workers
|
workers: workers
|
||||||
|
|
||||||
@@ -323,17 +323,22 @@ jobs:
|
|||||||
if: ${{ !failure() && !cancelled() }}
|
if: ${{ !failure() && !cancelled() }}
|
||||||
needs: linting-done
|
needs: linting-done
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
|
||||||
# https://github.com/matrix-org/complement/blob/master/dockerfiles/ComplementCIBuildkite.Dockerfile
|
|
||||||
image: matrixdotorg/complement:latest
|
|
||||||
env:
|
|
||||||
CI: true
|
|
||||||
ports:
|
|
||||||
- 8448:8448
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
# The path is set via a file given by $GITHUB_PATH. We need both Go 1.17 and GOPATH on the path to run Complement.
|
||||||
|
# See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path
|
||||||
|
- name: "Set Go Version"
|
||||||
|
run: |
|
||||||
|
# Add Go 1.17 to the PATH: see https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md#environment-variables-2
|
||||||
|
echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH
|
||||||
|
# Add the Go path to the PATH: We need this so we can call gotestfmt
|
||||||
|
echo "~/go/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: "Install Complement Dependencies"
|
||||||
|
run: |
|
||||||
|
sudo apt-get update && sudo apt-get install -y libolm3 libolm-dev
|
||||||
|
go get -v github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest
|
||||||
|
|
||||||
- name: Run actions/checkout@v2 for synapse
|
- name: Run actions/checkout@v2 for synapse
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
@@ -376,8 +381,11 @@ jobs:
|
|||||||
working-directory: complement/dockerfiles
|
working-directory: complement/dockerfiles
|
||||||
|
|
||||||
# Run Complement
|
# Run Complement
|
||||||
- run: set -o pipefail && go test -v -json -tags synapse_blacklist,msc2403 ./tests/... 2>&1 | gotestfmt
|
- run: |
|
||||||
|
set -o pipefail
|
||||||
|
go test -v -json -tags synapse_blacklist,msc2403 ./tests/... 2>&1 | gotestfmt
|
||||||
shell: bash
|
shell: bash
|
||||||
|
name: Run Complement Tests
|
||||||
env:
|
env:
|
||||||
COMPLEMENT_BASE_IMAGE: complement-synapse:latest
|
COMPLEMENT_BASE_IMAGE: complement-synapse:latest
|
||||||
working-directory: complement
|
working-directory: complement
|
||||||
|
|||||||
2
.github/workflows/twisted_trunk.yml
vendored
2
.github/workflows/twisted_trunk.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
- run: sudo apt-get -qq install xmlsec1
|
- run: sudo apt-get -qq install xmlsec1
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.6
|
python-version: 3.7
|
||||||
- run: .ci/patch_for_twisted_trunk.sh
|
- run: .ci/patch_for_twisted_trunk.sh
|
||||||
- run: pip install tox
|
- run: pip install tox
|
||||||
- run: tox -e py
|
- run: tox -e py
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -52,5 +52,5 @@ __pycache__/
|
|||||||
book/
|
book/
|
||||||
|
|
||||||
# complement
|
# complement
|
||||||
/complement-master
|
/complement-*
|
||||||
/master.tar.gz
|
/master.tar.gz
|
||||||
|
|||||||
175
CHANGES.md
175
CHANGES.md
@@ -1,3 +1,178 @@
|
|||||||
|
Synapse 1.52.0 (2022-02-08)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
No significant changes since 1.52.0rc1.
|
||||||
|
|
||||||
|
During the making of this release, the developers of Twisted have released
|
||||||
|
[Twisted 22.1.0](https://github.com/twisted/twisted/releases/tag/twisted-22.1.0), which
|
||||||
|
fixes [a security issue](https://github.com/twisted/twisted/security/advisories/GHSA-92x2-jw7w-xvvx)
|
||||||
|
within Twisted. We do not believe Synapse to be vulnerable to any security problem caused
|
||||||
|
by this issue, though we advise server administrators to update their local version of
|
||||||
|
Twisted if they can.
|
||||||
|
|
||||||
|
|
||||||
|
Synapse 1.52.0rc1 (2022-02-01)
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Remove account data (including client config, push rules and ignored users) upon user deactivation. ([\#11621](https://github.com/matrix-org/synapse/issues/11621), [\#11788](https://github.com/matrix-org/synapse/issues/11788), [\#11789](https://github.com/matrix-org/synapse/issues/11789))
|
||||||
|
- Add an admin API to reset connection timeouts for remote server. ([\#11639](https://github.com/matrix-org/synapse/issues/11639))
|
||||||
|
- Add an admin API to get a list of rooms that federate with a given remote homeserver. ([\#11658](https://github.com/matrix-org/synapse/issues/11658))
|
||||||
|
- Add a config flag to inhibit `M_USER_IN_USE` during registration. ([\#11743](https://github.com/matrix-org/synapse/issues/11743))
|
||||||
|
- Add a module callback to set username at registration. ([\#11790](https://github.com/matrix-org/synapse/issues/11790))
|
||||||
|
- Allow configuring a maximum file size as well as a list of allowed content types for avatars. ([\#11846](https://github.com/matrix-org/synapse/issues/11846))
|
||||||
|
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Include the bundled aggregations in the `/sync` response, per [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675). ([\#11612](https://github.com/matrix-org/synapse/issues/11612))
|
||||||
|
- Fix a long-standing bug when previewing Reddit URLs which do not contain an image. ([\#11767](https://github.com/matrix-org/synapse/issues/11767))
|
||||||
|
- Fix a long-standing bug that media streams could cause long-lived connections when generating URL previews. ([\#11784](https://github.com/matrix-org/synapse/issues/11784))
|
||||||
|
- Include a `prev_content` field in state events sent to Application Services. Contributed by @totallynotvaishnav. ([\#11798](https://github.com/matrix-org/synapse/issues/11798))
|
||||||
|
- Fix a bug introduced in Synapse 0.33.3 causing requests to sometimes log strings such as `HTTPStatus.OK` instead of integer status codes. ([\#11827](https://github.com/matrix-org/synapse/issues/11827))
|
||||||
|
|
||||||
|
|
||||||
|
Improved Documentation
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- Update pypi installation docs to indicate that we now support Python 3.10. ([\#11820](https://github.com/matrix-org/synapse/issues/11820))
|
||||||
|
- Add missing steps to the contribution submission process in the documentation. Contributed by @sequentialread. ([\#11821](https://github.com/matrix-org/synapse/issues/11821))
|
||||||
|
- Remove not needed old table of contents in documentation. ([\#11860](https://github.com/matrix-org/synapse/issues/11860))
|
||||||
|
- Consolidate the `access_token` information at the top of each relevant page in the Admin API documentation. ([\#11861](https://github.com/matrix-org/synapse/issues/11861))
|
||||||
|
|
||||||
|
|
||||||
|
Deprecations and Removals
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- Drop support for Python 3.6, which is EOL. ([\#11683](https://github.com/matrix-org/synapse/issues/11683))
|
||||||
|
- Remove the `experimental_msc1849_support_enabled` flag as the features are now stable. ([\#11843](https://github.com/matrix-org/synapse/issues/11843))
|
||||||
|
|
||||||
|
|
||||||
|
Internal Changes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
- Preparation for database schema simplifications: add `state_key` and `rejection_reason` columns to `events` table. ([\#11792](https://github.com/matrix-org/synapse/issues/11792))
|
||||||
|
- Add `FrozenEvent.get_state_key` and use it in a couple of places. ([\#11793](https://github.com/matrix-org/synapse/issues/11793))
|
||||||
|
- Preparation for database schema simplifications: stop reading from `event_reference_hashes`. ([\#11794](https://github.com/matrix-org/synapse/issues/11794))
|
||||||
|
- Drop unused table `public_room_list_stream`. ([\#11795](https://github.com/matrix-org/synapse/issues/11795))
|
||||||
|
- Preparation for reducing Postgres serialization errors: allow setting transaction isolation level. Contributed by Nick @ Beeper. ([\#11799](https://github.com/matrix-org/synapse/issues/11799), [\#11847](https://github.com/matrix-org/synapse/issues/11847))
|
||||||
|
- Docker: skip the initial amd64-only build and go straight to multiarch. ([\#11810](https://github.com/matrix-org/synapse/issues/11810))
|
||||||
|
- Run Complement on the Github Actions VM and not inside a Docker container. ([\#11811](https://github.com/matrix-org/synapse/issues/11811))
|
||||||
|
- Log module names at startup. ([\#11813](https://github.com/matrix-org/synapse/issues/11813))
|
||||||
|
- Improve type safety of bundled aggregations code. ([\#11815](https://github.com/matrix-org/synapse/issues/11815))
|
||||||
|
- Correct a type annotation in the event validation logic. ([\#11817](https://github.com/matrix-org/synapse/issues/11817), [\#11830](https://github.com/matrix-org/synapse/issues/11830))
|
||||||
|
- Minor updates and documentation for database schema delta files. ([\#11823](https://github.com/matrix-org/synapse/issues/11823))
|
||||||
|
- Workaround a type annotation problem in `prometheus_client` 0.13.0. ([\#11834](https://github.com/matrix-org/synapse/issues/11834))
|
||||||
|
- Minor performance improvement in room state lookup. ([\#11836](https://github.com/matrix-org/synapse/issues/11836))
|
||||||
|
- Fix some indentation inconsistencies in the sample config. ([\#11838](https://github.com/matrix-org/synapse/issues/11838))
|
||||||
|
- Add type hints to `tests/rest/admin`. ([\#11851](https://github.com/matrix-org/synapse/issues/11851))
|
||||||
|
|
||||||
|
|
||||||
|
Synapse 1.51.0 (2022-01-25)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
No significant changes since 1.51.0rc2.
|
||||||
|
|
||||||
|
Synapse 1.51.0 deprecates `webclient` listeners and non-HTTP(S) `web_client_location`s. Support for these will be removed in Synapse 1.53.0, at which point Synapse will not be capable of directly serving a web client for Matrix. See the [upgrade notes](https://matrix-org.github.io/synapse/develop/upgrade#upgrading-to-v1510).
|
||||||
|
|
||||||
|
Synapse 1.51.0rc2 (2022-01-24)
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Fix a bug introduced in Synapse 1.40.0 that caused Synapse to fail to process incoming federation traffic after handling a large amount of events in a v1 room. ([\#11806](https://github.com/matrix-org/synapse/issues/11806))
|
||||||
|
|
||||||
|
|
||||||
|
Synapse 1.50.2 (2022-01-24)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
This release includes the same bugfix as Synapse 1.51.0rc2.
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Fix a bug introduced in Synapse 1.40.0 that caused Synapse to fail to process incoming federation traffic after handling a large amount of events in a v1 room. ([\#11806](https://github.com/matrix-org/synapse/issues/11806))
|
||||||
|
|
||||||
|
|
||||||
|
Synapse 1.51.0rc1 (2022-01-21)
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Add `track_puppeted_user_ips` config flag to record client IP addresses against puppeted users, and include the puppeted users in monthly active user counts. ([\#11561](https://github.com/matrix-org/synapse/issues/11561), [\#11749](https://github.com/matrix-org/synapse/issues/11749), [\#11757](https://github.com/matrix-org/synapse/issues/11757))
|
||||||
|
- Include whether the requesting user has participated in a thread when generating a summary for [MSC3440](https://github.com/matrix-org/matrix-doc/pull/3440). ([\#11577](https://github.com/matrix-org/synapse/issues/11577))
|
||||||
|
- Return an `M_FORBIDDEN` error code instead of `M_UNKNOWN` when a spam checker module prevents a user from creating a room. ([\#11672](https://github.com/matrix-org/synapse/issues/11672))
|
||||||
|
- Add a flag to the `synapse_review_recent_signups` script to ignore and filter appservice users. ([\#11675](https://github.com/matrix-org/synapse/issues/11675), [\#11770](https://github.com/matrix-org/synapse/issues/11770))
|
||||||
|
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Fix a long-standing issue which could cause Synapse to incorrectly accept data in the unsigned field of events
|
||||||
|
received over federation. ([\#11530](https://github.com/matrix-org/synapse/issues/11530))
|
||||||
|
- Fix a long-standing bug where Synapse wouldn't cache a response indicating that a remote user has no devices. ([\#11587](https://github.com/matrix-org/synapse/issues/11587))
|
||||||
|
- Fix an error that occurs whilst trying to get the federation status of a destination server that was working normally. This admin API was newly introduced in Synapse v1.49.0. ([\#11593](https://github.com/matrix-org/synapse/issues/11593))
|
||||||
|
- Fix bundled aggregations not being included in the `/sync` response, per [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675). ([\#11612](https://github.com/matrix-org/synapse/issues/11612), [\#11659](https://github.com/matrix-org/synapse/issues/11659), [\#11791](https://github.com/matrix-org/synapse/issues/11791))
|
||||||
|
- Fix the `/_matrix/client/v1/room/{roomId}/hierarchy` endpoint returning incorrect fields which have been present since Synapse 1.49.0. ([\#11667](https://github.com/matrix-org/synapse/issues/11667))
|
||||||
|
- Fix preview of some GIF URLs (like tenor.com). Contributed by Philippe Daouadi. ([\#11669](https://github.com/matrix-org/synapse/issues/11669))
|
||||||
|
- Fix a bug where only the first 50 rooms from a space were returned from the `/hierarchy` API. This has existed since the introduction of the API in Synapse v1.41.0. ([\#11695](https://github.com/matrix-org/synapse/issues/11695))
|
||||||
|
- Fix a bug introduced in Synapse v1.18.0 where password reset and address validation emails would not be sent if their subject was configured to use the 'app' template variable. Contributed by @br4nnigan. ([\#11710](https://github.com/matrix-org/synapse/issues/11710), [\#11745](https://github.com/matrix-org/synapse/issues/11745))
|
||||||
|
- Make the 'List Rooms' Admin API sort stable. Contributed by Daniël Sonck. ([\#11737](https://github.com/matrix-org/synapse/issues/11737))
|
||||||
|
- Fix a long-standing bug where space hierarchy over federation would only work correctly some of the time. ([\#11775](https://github.com/matrix-org/synapse/issues/11775))
|
||||||
|
- Fix a bug introduced in Synapse v1.46.0 that prevented `on_logged_out` module callbacks from being correctly awaited by Synapse. ([\#11786](https://github.com/matrix-org/synapse/issues/11786))
|
||||||
|
|
||||||
|
|
||||||
|
Improved Documentation
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- Warn against using a Let's Encrypt certificate for TLS/DTLS TURN server client connections, and suggest using ZeroSSL certificate instead. This works around client-side connectivity errors caused by WebRTC libraries that reject Let's Encrypt certificates. Contibuted by @AndrewFerr. ([\#11686](https://github.com/matrix-org/synapse/issues/11686))
|
||||||
|
- Document the new `SYNAPSE_TEST_PERSIST_SQLITE_DB` environment variable in the contributing guide. ([\#11715](https://github.com/matrix-org/synapse/issues/11715))
|
||||||
|
- Document that the minimum supported PostgreSQL version is now 10. ([\#11725](https://github.com/matrix-org/synapse/issues/11725))
|
||||||
|
- Fix typo in demo docs: differnt. ([\#11735](https://github.com/matrix-org/synapse/issues/11735))
|
||||||
|
- Update room spec URL in config files. ([\#11739](https://github.com/matrix-org/synapse/issues/11739))
|
||||||
|
- Mention `python3-venv` and `libpq-dev` dependencies in the contribution guide. ([\#11740](https://github.com/matrix-org/synapse/issues/11740))
|
||||||
|
- Update documentation for configuring login with Facebook. ([\#11755](https://github.com/matrix-org/synapse/issues/11755))
|
||||||
|
- Update installation instructions to note that Python 3.6 is no longer supported. ([\#11781](https://github.com/matrix-org/synapse/issues/11781))
|
||||||
|
|
||||||
|
|
||||||
|
Deprecations and Removals
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- Remove the unstable `/send_relation` endpoint. ([\#11682](https://github.com/matrix-org/synapse/issues/11682))
|
||||||
|
- Remove `python_twisted_reactor_pending_calls` Prometheus metric. ([\#11724](https://github.com/matrix-org/synapse/issues/11724))
|
||||||
|
- Remove the `password_hash` field from the response dictionaries of the [Users Admin API](https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html). ([\#11576](https://github.com/matrix-org/synapse/issues/11576))
|
||||||
|
- **Deprecate support for `webclient` listeners and non-HTTP(S) `web_client_location` configuration. ([\#11774](https://github.com/matrix-org/synapse/issues/11774), [\#11783](https://github.com/matrix-org/synapse/issues/11783))**
|
||||||
|
|
||||||
|
|
||||||
|
Internal Changes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
- Run `pyupgrade --py37-plus --keep-percent-format` on Synapse. ([\#11685](https://github.com/matrix-org/synapse/issues/11685))
|
||||||
|
- Use buildkit's cache feature to speed up docker builds. ([\#11691](https://github.com/matrix-org/synapse/issues/11691))
|
||||||
|
- Use `auto_attribs` and native type hints for attrs classes. ([\#11692](https://github.com/matrix-org/synapse/issues/11692), [\#11768](https://github.com/matrix-org/synapse/issues/11768))
|
||||||
|
- Remove debug logging for #4422, which has been closed since Synapse 0.99. ([\#11693](https://github.com/matrix-org/synapse/issues/11693))
|
||||||
|
- Remove fallback code for Python 2. ([\#11699](https://github.com/matrix-org/synapse/issues/11699))
|
||||||
|
- Add a test for [an edge case](https://github.com/matrix-org/synapse/pull/11532#discussion_r769104461) in the `/sync` logic. ([\#11701](https://github.com/matrix-org/synapse/issues/11701))
|
||||||
|
- Add the option to write SQLite test dbs to disk when running tests. ([\#11702](https://github.com/matrix-org/synapse/issues/11702))
|
||||||
|
- Improve Complement test output for Gitub Actions. ([\#11707](https://github.com/matrix-org/synapse/issues/11707))
|
||||||
|
- Fix docstring on `add_account_data_for_user`. ([\#11716](https://github.com/matrix-org/synapse/issues/11716))
|
||||||
|
- Complement environment variable name change and update `.gitignore`. ([\#11718](https://github.com/matrix-org/synapse/issues/11718))
|
||||||
|
- Simplify calculation of Prometheus metrics for garbage collection. ([\#11723](https://github.com/matrix-org/synapse/issues/11723))
|
||||||
|
- Improve accuracy of `python_twisted_reactor_tick_time` Prometheus metric. ([\#11724](https://github.com/matrix-org/synapse/issues/11724), [\#11771](https://github.com/matrix-org/synapse/issues/11771))
|
||||||
|
- Minor efficiency improvements when inserting many values into the database. ([\#11742](https://github.com/matrix-org/synapse/issues/11742))
|
||||||
|
- Invite PR authors to give themselves credit in the changelog. ([\#11744](https://github.com/matrix-org/synapse/issues/11744))
|
||||||
|
- Add optional debugging to investigate [issue 8631](https://github.com/matrix-org/synapse/issues/8631). ([\#11760](https://github.com/matrix-org/synapse/issues/11760))
|
||||||
|
- Remove `log_function` utility function and its uses. ([\#11761](https://github.com/matrix-org/synapse/issues/11761))
|
||||||
|
- Add a unit test that checks both `client` and `webclient` resources will function when simultaneously enabled. ([\#11765](https://github.com/matrix-org/synapse/issues/11765))
|
||||||
|
- Allow overriding complement commit using `COMPLEMENT_REF`. ([\#11766](https://github.com/matrix-org/synapse/issues/11766))
|
||||||
|
- Add some comments and type annotations for `_update_outliers_txn`. ([\#11776](https://github.com/matrix-org/synapse/issues/11776))
|
||||||
|
|
||||||
|
|
||||||
Synapse 1.50.1 (2022-01-18)
|
Synapse 1.50.1 (2022-01-18)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
Fix a long-standing issue which could cause Synapse to incorrectly accept data in the unsigned field of events
|
|
||||||
received over federation.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Add `track_puppeted_user_ips` config flag to record client IP addresses against puppeted users, and include the puppeted users in monthly active user counts.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Remove the `"password_hash"` field from the response dictionaries of the [Users Admin API](https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html).
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Include whether the requesting user has participated in a thread when generating a summary for [MSC3440](https://github.com/matrix-org/matrix-doc/pull/3440).
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix a long-standing bug where Synapse wouldn't cache a response indicating that a remote user has no devices.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix an error in to get federation status of a destination server even if no error has occurred. This admin API was new introduced in Synapse 1.49.0.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Avoid database access in the JSON serialization process.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Include the bundled aggregations in the `/sync` response, per [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675).
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix `/_matrix/client/v1/room/{roomId}/hierarchy` endpoint returning incorrect fields which have been present since Synapse 1.49.0.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix preview of some gif URLs (like tenor.com). Contributed by Philippe Daouadi.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Return an `M_FORBIDDEN` error code instead of `M_UNKNOWN` when a spam checker module prevents a user from creating a room.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Add a flag to the `synapse_review_recent_signups` script to ignore and filter appservice users.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Remove the unstable `/send_relation` endpoint.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Run `pyupgrade --py37-plus --keep-percent-format` on Synapse.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Warn against using a Let's Encrypt certificate for TLS/DTLS TURN server client connections, and suggest using ZeroSSL certificate instead. This bypasses client-side connectivity errors caused by WebRTC libraries that reject Let's Encrypt certificates. Contibuted by @AndrewFerr.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Use buildkit's cache feature to speed up docker builds.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Use `auto_attribs` and native type hints for attrs classes.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Remove debug logging for #4422, which has been closed since Synapse 0.99.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix a bug where the only the first 50 rooms from a space were returned from the `/hierarchy` API. This has existed since the introduction of the API in Synapse v1.41.0.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Remove fallback code for Python 2.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Add a test for [an edge case](https://github.com/matrix-org/synapse/pull/11532#discussion_r769104461) in the `/sync` logic.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Add the option to write sqlite test dbs to disk when running tests.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Improve Complement test output for Gitub Actions.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix a bug introduced in Synapse v1.18.0 where password reset and address validation emails would not be sent if their subject was configured to use the 'app' template variable. Contributed by @br4nnigan.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix a typechecker problem related to our (ab)use of `nacl.signing.SigningKey`s.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Document the new `SYNAPSE_TEST_PERSIST_SQLITE_DB` environment variable in the contributing guide.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix docstring on `add_account_data_for_user`.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Complement environment variable name change and update `.gitignore`.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Simplify calculation of prometheus metrics for garbage collection.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Improve accuracy of `python_twisted_reactor_tick_time` prometheus metric.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Remove `python_twisted_reactor_pending_calls` prometheus metric.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Document that now the minimum supported PostgreSQL version is 10.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix typo in demo docs: differnt.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Make the list rooms admin api sort stable. Contributed by Daniël Sonck.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Update room spec url in config files.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Mention python3-venv and libpq-dev dependencies in contribution guide.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Minor efficiency improvements when inserting many values into the database.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Invite PR authors to give themselves credit in the changelog.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Fix a bug introduced in Synapse v1.18.0 where password reset and address validation emails would not be sent if their subject was configured to use the 'app' template variable. Contributed by @br4nnigan.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Add `track_puppeted_user_ips` config flag to record client IP addresses against puppeted users, and include the puppeted users in monthly active user counts.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Update documentation for configuring login with facebook.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Add `track_puppeted_user_ips` config flag to record client IP addresses against puppeted users, and include the puppeted users in monthly active user counts.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Remove `log_function` utility function and its uses.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Use `auto_attribs` and native type hints for attrs classes.
|
|
||||||
36
debian/changelog
vendored
36
debian/changelog
vendored
@@ -1,3 +1,39 @@
|
|||||||
|
matrix-synapse-py3 (1.52.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* New synapse release 1.52.0.
|
||||||
|
|
||||||
|
-- Synapse Packaging team <packages@matrix.org> Tue, 08 Feb 2022 11:34:54 +0000
|
||||||
|
|
||||||
|
matrix-synapse-py3 (1.52.0~rc1) stable; urgency=medium
|
||||||
|
|
||||||
|
* New synapse release 1.52.0~rc1.
|
||||||
|
|
||||||
|
-- Synapse Packaging team <packages@matrix.org> Tue, 01 Feb 2022 11:04:09 +0000
|
||||||
|
|
||||||
|
matrix-synapse-py3 (1.51.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* New synapse release 1.51.0.
|
||||||
|
|
||||||
|
-- Synapse Packaging team <packages@matrix.org> Tue, 25 Jan 2022 11:28:51 +0000
|
||||||
|
|
||||||
|
matrix-synapse-py3 (1.51.0~rc2) stable; urgency=medium
|
||||||
|
|
||||||
|
* New synapse release 1.51.0~rc2.
|
||||||
|
|
||||||
|
-- Synapse Packaging team <packages@matrix.org> Mon, 24 Jan 2022 12:25:00 +0000
|
||||||
|
|
||||||
|
matrix-synapse-py3 (1.51.0~rc1) stable; urgency=medium
|
||||||
|
|
||||||
|
* New synapse release 1.51.0~rc1.
|
||||||
|
|
||||||
|
-- Synapse Packaging team <packages@matrix.org> Fri, 21 Jan 2022 10:46:02 +0000
|
||||||
|
|
||||||
|
matrix-synapse-py3 (1.50.2) stable; urgency=medium
|
||||||
|
|
||||||
|
* New synapse release 1.50.2.
|
||||||
|
|
||||||
|
-- Synapse Packaging team <packages@matrix.org> Mon, 24 Jan 2022 13:37:11 +0000
|
||||||
|
|
||||||
matrix-synapse-py3 (1.50.1) stable; urgency=medium
|
matrix-synapse-py3 (1.50.1) stable; urgency=medium
|
||||||
|
|
||||||
* New synapse release 1.50.1.
|
* New synapse release 1.50.1.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Use the Sytest image that comes with a lot of the build dependencies
|
# Use the Sytest image that comes with a lot of the build dependencies
|
||||||
# pre-installed
|
# pre-installed
|
||||||
FROM matrixdotorg/sytest:bionic
|
FROM matrixdotorg/sytest:focal
|
||||||
|
|
||||||
# The Sytest image doesn't come with python, so install that
|
# The Sytest image doesn't come with python, so install that
|
||||||
RUN apt-get update && apt-get -qq install -y python3 python3-dev python3-pip
|
RUN apt-get update && apt-get -qq install -y python3 python3-dev python3-pip
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ sudo -u postgres /usr/lib/postgresql/10/bin/pg_ctl -w -D /var/lib/postgresql/dat
|
|||||||
# Run the tests
|
# Run the tests
|
||||||
cd /src
|
cd /src
|
||||||
export TRIAL_FLAGS="-j 4"
|
export TRIAL_FLAGS="-j 4"
|
||||||
tox --workdir=./.tox-pg-container -e py36-postgres "$@"
|
tox --workdir=./.tox-pg-container -e py37-postgres "$@"
|
||||||
|
|||||||
@@ -44,27 +44,6 @@ For more details and context on the release of the r0.1 Server/Server API and
|
|||||||
imminent Matrix 1.0 release, you can also see our
|
imminent Matrix 1.0 release, you can also see our
|
||||||
[main talk from FOSDEM 2019](https://matrix.org/blog/2019/02/04/matrix-at-fosdem-2019/).
|
[main talk from FOSDEM 2019](https://matrix.org/blog/2019/02/04/matrix-at-fosdem-2019/).
|
||||||
|
|
||||||
## Contents
|
|
||||||
* Timeline
|
|
||||||
* Configuring certificates for compatibility with Synapse 1.0
|
|
||||||
* FAQ
|
|
||||||
* Synapse 0.99.0 has just been released, what do I need to do right now?
|
|
||||||
* How do I upgrade?
|
|
||||||
* What will happen if I do not set up a valid federation certificate
|
|
||||||
immediately?
|
|
||||||
* What will happen if I do nothing at all?
|
|
||||||
* When do I need a SRV record or .well-known URI?
|
|
||||||
* Can I still use an SRV record?
|
|
||||||
* I have created a .well-known URI. Do I still need an SRV record?
|
|
||||||
* It used to work just fine, why are you breaking everything?
|
|
||||||
* Can I manage my own certificates rather than having Synapse renew
|
|
||||||
certificates itself?
|
|
||||||
* Do you still recommend against using a reverse proxy on the federation port?
|
|
||||||
* Do I still need to give my TLS certificates to Synapse if I am using a
|
|
||||||
reverse proxy?
|
|
||||||
* Do I need the same certificate for the client and federation port?
|
|
||||||
* How do I tell Synapse to reload my keys/certificates after I replace them?
|
|
||||||
|
|
||||||
## Timeline
|
## Timeline
|
||||||
|
|
||||||
**5th Feb 2019 - Synapse 0.99.0 is released.**
|
**5th Feb 2019 - Synapse 0.99.0 is released.**
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ This API allows a server administrator to manage the validity of an account. To
|
|||||||
use it, you must enable the account validity feature (under
|
use it, you must enable the account validity feature (under
|
||||||
`account_validity`) in Synapse's configuration.
|
`account_validity`) in Synapse's configuration.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
## Renew account
|
## Renew account
|
||||||
|
|
||||||
This API extends the validity of an account by as much time as configured in the
|
This API extends the validity of an account by as much time as configured in the
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ This API lets a server admin delete a local group. Doing so will kick all
|
|||||||
users out of the group so that their clients will correctly handle the group
|
users out of the group so that their clients will correctly handle the group
|
||||||
being deleted.
|
being deleted.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
The API is:
|
The API is:
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /_synapse/admin/v1/delete_group/<group_id>
|
POST /_synapse/admin/v1/delete_group/<group_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
This API returns information about reported events.
|
This API returns information about reported events.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
The api is:
|
The api is:
|
||||||
```
|
```
|
||||||
GET /_synapse/admin/v1/event_reports?from=0&limit=10
|
GET /_synapse/admin/v1/event_reports?from=0&limit=10
|
||||||
```
|
```
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
@@ -94,8 +95,6 @@ The api is:
|
|||||||
```
|
```
|
||||||
GET /_synapse/admin/v1/event_reports/<report_id>
|
GET /_synapse/admin/v1/event_reports/<report_id>
|
||||||
```
|
```
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,10 @@
|
|||||||
# Contents
|
|
||||||
- [Querying media](#querying-media)
|
|
||||||
* [List all media in a room](#list-all-media-in-a-room)
|
|
||||||
* [List all media uploaded by a user](#list-all-media-uploaded-by-a-user)
|
|
||||||
- [Quarantine media](#quarantine-media)
|
|
||||||
* [Quarantining media by ID](#quarantining-media-by-id)
|
|
||||||
* [Remove media from quarantine by ID](#remove-media-from-quarantine-by-id)
|
|
||||||
* [Quarantining media in a room](#quarantining-media-in-a-room)
|
|
||||||
* [Quarantining all media of a user](#quarantining-all-media-of-a-user)
|
|
||||||
* [Protecting media from being quarantined](#protecting-media-from-being-quarantined)
|
|
||||||
* [Unprotecting media from being quarantined](#unprotecting-media-from-being-quarantined)
|
|
||||||
- [Delete local media](#delete-local-media)
|
|
||||||
* [Delete a specific local media](#delete-a-specific-local-media)
|
|
||||||
* [Delete local media by date or size](#delete-local-media-by-date-or-size)
|
|
||||||
* [Delete media uploaded by a user](#delete-media-uploaded-by-a-user)
|
|
||||||
- [Purge Remote Media API](#purge-remote-media-api)
|
|
||||||
|
|
||||||
# Querying media
|
# Querying media
|
||||||
|
|
||||||
These APIs allow extracting media information from the homeserver.
|
These APIs allow extracting media information from the homeserver.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
## List all media in a room
|
## List all media in a room
|
||||||
|
|
||||||
This API gets a list of known media in a room.
|
This API gets a list of known media in a room.
|
||||||
@@ -28,8 +14,6 @@ The API is:
|
|||||||
```
|
```
|
||||||
GET /_synapse/admin/v1/room/<room_id>/media
|
GET /_synapse/admin/v1/room/<room_id>/media
|
||||||
```
|
```
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|
||||||
The API returns a JSON body like the following:
|
The API returns a JSON body like the following:
|
||||||
```json
|
```json
|
||||||
@@ -317,8 +301,5 @@ The following fields are returned in the JSON response body:
|
|||||||
|
|
||||||
* `deleted`: integer - The number of media items successfully deleted
|
* `deleted`: integer - The number of media items successfully deleted
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|
||||||
If the user re-requests purged remote media, synapse will re-request the media
|
If the user re-requests purged remote media, synapse will re-request the media
|
||||||
from the originating server.
|
from the originating server.
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ paginate further back in the room from the point being purged from.
|
|||||||
Note that Synapse requires at least one message in each room, so it will never
|
Note that Synapse requires at least one message in each room, so it will never
|
||||||
delete the last message in a room.
|
delete the last message in a room.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
The API is:
|
The API is:
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /_synapse/admin/v1/purge_history/<room_id>[/<event_id>]
|
POST /_synapse/admin/v1/purge_history/<room_id>[/<event_id>]
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
By default, events sent by local users are not deleted, as they may represent
|
By default, events sent by local users are not deleted, as they may represent
|
||||||
the only copies of this content in existence. (Events sent by remote users are
|
the only copies of this content in existence. (Events sent by remote users are
|
||||||
deleted.)
|
deleted.)
|
||||||
@@ -57,9 +57,6 @@ It is possible to poll for updates on recent purges with a second API;
|
|||||||
GET /_synapse/admin/v1/purge_history_status/<purge_id>
|
GET /_synapse/admin/v1/purge_history_status/<purge_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
Again, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin.
|
|
||||||
|
|
||||||
This API returns a JSON body like the following:
|
This API returns a JSON body like the following:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ to a room with a given `room_id_or_alias`. You can only modify the membership of
|
|||||||
local users. The server administrator must be in the room and have permission to
|
local users. The server administrator must be in the room and have permission to
|
||||||
invite users.
|
invite users.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
The following parameters are available:
|
The following parameters are available:
|
||||||
@@ -23,9 +26,6 @@ POST /_synapse/admin/v1/join/<room_id_or_alias>
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|
||||||
Response:
|
Response:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -1,24 +1,12 @@
|
|||||||
# Contents
|
|
||||||
- [List Room API](#list-room-api)
|
|
||||||
- [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)
|
|
||||||
* [Status of deleting rooms](#status-of-deleting-rooms)
|
|
||||||
* [Undoing room shutdowns](#undoing-room-shutdowns)
|
|
||||||
- [Make Room Admin API](#make-room-admin-api)
|
|
||||||
- [Forward Extremities Admin API](#forward-extremities-admin-api)
|
|
||||||
- [Event Context API](#event-context-api)
|
|
||||||
|
|
||||||
# List Room API
|
# List Room API
|
||||||
|
|
||||||
The List Room admin API allows server admins to get a list of rooms on their
|
The List Room admin API allows server admins to get a list of rooms on their
|
||||||
server. There are various parameters available that allow for filtering and
|
server. There are various parameters available that allow for filtering and
|
||||||
sorting the returned list. This API supports pagination.
|
sorting the returned list. This API supports pagination.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
The following query parameters are available:
|
The following query parameters are available:
|
||||||
@@ -493,9 +481,6 @@ several minutes or longer.
|
|||||||
The local server will only have the power to move local user and room aliases to
|
The local server will only have the power to move local user and room aliases to
|
||||||
the new room. Users on other servers will be unaffected.
|
the new room. Users on other servers will be unaffected.
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an ``access_token`` for a
|
|
||||||
server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|
||||||
## Version 1 (old version)
|
## Version 1 (old version)
|
||||||
|
|
||||||
This version works synchronously. That means you only get the response once the server has
|
This version works synchronously. That means you only get the response once the server has
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
Returns information about all local media usage of users. Gives the
|
Returns information about all local media usage of users. Gives the
|
||||||
possibility to filter them by time and user.
|
possibility to filter them by time and user.
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
The API is:
|
The API is:
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /_synapse/admin/v1/statistics/users/media
|
GET /_synapse/admin/v1/statistics/users/media
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token`
|
|
||||||
for a server admin: see [Admin API](../usage/administration/admin_api).
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# User Admin API
|
# User Admin API
|
||||||
|
|
||||||
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
|
for a server admin: see [Admin API](../usage/administration/admin_api).
|
||||||
|
|
||||||
## Query User Account
|
## Query User Account
|
||||||
|
|
||||||
This API returns information about a specific user account.
|
This API returns information about a specific user account.
|
||||||
@@ -10,9 +13,6 @@ The api is:
|
|||||||
GET /_synapse/admin/v2/users/<user_id>
|
GET /_synapse/admin/v2/users/<user_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
@@ -104,9 +104,6 @@ with a body of:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
Returns HTTP status code:
|
Returns HTTP status code:
|
||||||
- `201` - When a new user object was created.
|
- `201` - When a new user object was created.
|
||||||
- `200` - When a user was modified.
|
- `200` - When a user was modified.
|
||||||
@@ -156,9 +153,6 @@ By default, the response is ordered by ascending user ID.
|
|||||||
GET /_synapse/admin/v2/users?from=0&limit=10&guests=false
|
GET /_synapse/admin/v2/users?from=0&limit=10&guests=false
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -278,9 +272,6 @@ GET /_matrix/client/r0/admin/whois/<userId>
|
|||||||
See also: [Client Server
|
See also: [Client Server
|
||||||
API Whois](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid).
|
API Whois](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid).
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -335,9 +326,6 @@ with a body of:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
The erase parameter is optional and defaults to `false`.
|
The erase parameter is optional and defaults to `false`.
|
||||||
An empty body may be passed for backwards compatibility.
|
An empty body may be passed for backwards compatibility.
|
||||||
|
|
||||||
@@ -353,6 +341,11 @@ The following actions are performed when deactivating an user:
|
|||||||
- Remove the user from the user directory
|
- Remove the user from the user directory
|
||||||
- Reject all pending invites
|
- Reject all pending invites
|
||||||
- Remove all account validity information related to the user
|
- Remove all account validity information related to the user
|
||||||
|
- Remove the arbitrary data store known as *account data*. For example, this includes:
|
||||||
|
- list of ignored users;
|
||||||
|
- push rules;
|
||||||
|
- secret storage keys; and
|
||||||
|
- cross-signing keys.
|
||||||
|
|
||||||
The following additional actions are performed during deactivation if `erase`
|
The following additional actions are performed during deactivation if `erase`
|
||||||
is set to `true`:
|
is set to `true`:
|
||||||
@@ -366,7 +359,6 @@ The following actions are **NOT** performed. The list may be incomplete.
|
|||||||
- Remove mappings of SSO IDs
|
- Remove mappings of SSO IDs
|
||||||
- [Delete media uploaded](#delete-media-uploaded-by-a-user) by user (included avatar images)
|
- [Delete media uploaded](#delete-media-uploaded-by-a-user) by user (included avatar images)
|
||||||
- Delete sent and received messages
|
- Delete sent and received messages
|
||||||
- Delete E2E cross-signing keys
|
|
||||||
- Remove the user's creation (registration) timestamp
|
- Remove the user's creation (registration) timestamp
|
||||||
- [Remove rate limit overrides](#override-ratelimiting-for-users)
|
- [Remove rate limit overrides](#override-ratelimiting-for-users)
|
||||||
- Remove from monthly active users
|
- Remove from monthly active users
|
||||||
@@ -390,9 +382,6 @@ with a body of:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
The parameter `new_password` is required.
|
The parameter `new_password` is required.
|
||||||
The parameter `logout_devices` is optional and defaults to `true`.
|
The parameter `logout_devices` is optional and defaults to `true`.
|
||||||
|
|
||||||
@@ -405,9 +394,6 @@ The api is:
|
|||||||
GET /_synapse/admin/v1/users/<user_id>/admin
|
GET /_synapse/admin/v1/users/<user_id>/admin
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -435,10 +421,6 @@ with a body of:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
|
|
||||||
## List room memberships of a user
|
## List room memberships of a user
|
||||||
|
|
||||||
Gets a list of all `room_id` that a specific `user_id` is member.
|
Gets a list of all `room_id` that a specific `user_id` is member.
|
||||||
@@ -449,9 +431,6 @@ The API is:
|
|||||||
GET /_synapse/admin/v1/users/<user_id>/joined_rooms
|
GET /_synapse/admin/v1/users/<user_id>/joined_rooms
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -570,9 +549,6 @@ The API is:
|
|||||||
GET /_synapse/admin/v1/users/<user_id>/media
|
GET /_synapse/admin/v1/users/<user_id>/media
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -687,9 +663,6 @@ The API is:
|
|||||||
DELETE /_synapse/admin/v1/users/<user_id>/media
|
DELETE /_synapse/admin/v1/users/<user_id>/media
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -762,9 +735,6 @@ The API is:
|
|||||||
GET /_synapse/admin/v2/users/<user_id>/devices
|
GET /_synapse/admin/v2/users/<user_id>/devices
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -830,9 +800,6 @@ POST /_synapse/admin/v2/users/<user_id>/delete_devices
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
@@ -854,9 +821,6 @@ The API is:
|
|||||||
GET /_synapse/admin/v2/users/<user_id>/devices/<device_id>
|
GET /_synapse/admin/v2/users/<user_id>/devices/<device_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -902,9 +866,6 @@ PUT /_synapse/admin/v2/users/<user_id>/devices/<device_id>
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
@@ -931,9 +892,6 @@ DELETE /_synapse/admin/v2/users/<user_id>/devices/<device_id>
|
|||||||
{}
|
{}
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
@@ -952,9 +910,6 @@ The API is:
|
|||||||
GET /_synapse/admin/v1/users/<user_id>/pushers
|
GET /_synapse/admin/v1/users/<user_id>/pushers
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -1049,9 +1004,6 @@ To un-shadow-ban a user the API is:
|
|||||||
DELETE /_synapse/admin/v1/users/<user_id>/shadow_ban
|
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 in both cases.
|
An empty JSON dict is returned in both cases.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
@@ -1074,9 +1026,6 @@ The API is:
|
|||||||
GET /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
GET /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -1116,9 +1065,6 @@ The API is:
|
|||||||
POST /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
POST /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -1161,9 +1107,6 @@ The API is:
|
|||||||
DELETE /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
DELETE /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -1192,7 +1135,5 @@ The API is:
|
|||||||
GET /_synapse/admin/v1/username_available?username=$localpart
|
GET /_synapse/admin/v1/username_available?username=$localpart
|
||||||
```
|
```
|
||||||
|
|
||||||
The request and response format is the same as the [/_matrix/client/r0/register/available](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-register-available) API.
|
The request and response format is the same as the
|
||||||
|
[/_matrix/client/r0/register/available](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-register-available) API.
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
|
||||||
server admin: [Admin API](../usage/administration/admin_api)
|
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ It returns a JSON body like the following:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"server_version": "0.99.2rc1 (b=develop, abcdef123)",
|
"server_version": "0.99.2rc1 (b=develop, abcdef123)",
|
||||||
"python_version": "3.6.8"
|
"python_version": "3.7.8"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ setup a *virtualenv*, as follows:
|
|||||||
cd path/where/you/have/cloned/the/repository
|
cd path/where/you/have/cloned/the/repository
|
||||||
python3 -m venv ./env
|
python3 -m venv ./env
|
||||||
source ./env/bin/activate
|
source ./env/bin/activate
|
||||||
|
pip install wheel
|
||||||
pip install -e ".[all,dev]"
|
pip install -e ".[all,dev]"
|
||||||
pip install tox
|
pip install tox
|
||||||
```
|
```
|
||||||
@@ -116,7 +117,7 @@ The linters look at your code and do two things:
|
|||||||
- ensure that your code follows the coding style adopted by the project;
|
- ensure that your code follows the coding style adopted by the project;
|
||||||
- catch a number of errors in your code.
|
- catch a number of errors in your code.
|
||||||
|
|
||||||
They're pretty fast, don't hesitate!
|
The linter takes no time at all to run as soon as you've [downloaded the dependencies into your python virtual environment](#4-install-the-dependencies).
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
source ./env/bin/activate
|
source ./env/bin/activate
|
||||||
|
|||||||
@@ -96,6 +96,60 @@ Ensure postgres is installed, then run:
|
|||||||
NB at the time of writing, this script predates the split into separate `state`/`main`
|
NB at the time of writing, this script predates the split into separate `state`/`main`
|
||||||
databases so will require updates to handle that correctly.
|
databases so will require updates to handle that correctly.
|
||||||
|
|
||||||
|
## Delta files
|
||||||
|
|
||||||
|
Delta files define the steps required to upgrade the database from an earlier version.
|
||||||
|
They can be written as either a file containing a series of SQL statements, or a Python
|
||||||
|
module.
|
||||||
|
|
||||||
|
Synapse remembers which delta files it has applied to a database (they are stored in the
|
||||||
|
`applied_schema_deltas` table) and will not re-apply them (even if a given file is
|
||||||
|
subsequently updated).
|
||||||
|
|
||||||
|
Delta files should be placed in a directory named `synapse/storage/schema/<database>/delta/<version>/`.
|
||||||
|
They are applied in alphanumeric order, so by convention the first two characters
|
||||||
|
of the filename should be an integer such as `01`, to put the file in the right order.
|
||||||
|
|
||||||
|
### SQL delta files
|
||||||
|
|
||||||
|
These should be named `*.sql`, or — for changes which should only be applied for a
|
||||||
|
given database engine — `*.sql.posgres` or `*.sql.sqlite`. For example, a delta which
|
||||||
|
adds a new column to the `foo` table might be called `01add_bar_to_foo.sql`.
|
||||||
|
|
||||||
|
Note that our SQL parser is a bit simple - it understands comments (`--` and `/*...*/`),
|
||||||
|
but complex statements which require a `;` in the middle of them (such as `CREATE
|
||||||
|
TRIGGER`) are beyond it and you'll have to use a Python delta file.
|
||||||
|
|
||||||
|
### Python delta files
|
||||||
|
|
||||||
|
For more flexibility, a delta file can take the form of a python module. These should
|
||||||
|
be named `*.py`. Note that database-engine-specific modules are not supported here –
|
||||||
|
instead you can write `if isinstance(database_engine, PostgresEngine)` or similar.
|
||||||
|
|
||||||
|
A Python delta module should define either or both of the following functions:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import synapse.config.homeserver
|
||||||
|
import synapse.storage.engines
|
||||||
|
import synapse.storage.types
|
||||||
|
|
||||||
|
|
||||||
|
def run_create(
|
||||||
|
cur: synapse.storage.types.Cursor,
|
||||||
|
database_engine: synapse.storage.engines.BaseDatabaseEngine,
|
||||||
|
) -> None:
|
||||||
|
"""Called whenever an existing or new database is to be upgraded"""
|
||||||
|
...
|
||||||
|
|
||||||
|
def run_upgrade(
|
||||||
|
cur: synapse.storage.types.Cursor,
|
||||||
|
database_engine: synapse.storage.engines.BaseDatabaseEngine,
|
||||||
|
config: synapse.config.homeserver.HomeServerConfig,
|
||||||
|
) -> None:
|
||||||
|
"""Called whenever an existing database is to be upgraded."""
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
## Boolean columns
|
## Boolean columns
|
||||||
|
|
||||||
Boolean columns require special treatment, since SQLite treats booleans the
|
Boolean columns require special treatment, since SQLite treats booleans the
|
||||||
|
|||||||
@@ -105,6 +105,68 @@ device ID), and the (now deactivated) access token.
|
|||||||
|
|
||||||
If multiple modules implement this callback, Synapse runs them all in order.
|
If multiple modules implement this callback, Synapse runs them all in order.
|
||||||
|
|
||||||
|
### `get_username_for_registration`
|
||||||
|
|
||||||
|
_First introduced in Synapse v1.52.0_
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def get_username_for_registration(
|
||||||
|
uia_results: Dict[str, Any],
|
||||||
|
params: Dict[str, Any],
|
||||||
|
) -> Optional[str]
|
||||||
|
```
|
||||||
|
|
||||||
|
Called when registering a new user. The module can return a username to set for the user
|
||||||
|
being registered by returning it as a string, or `None` if it doesn't wish to force a
|
||||||
|
username for this user. If a username is returned, it will be used as the local part of a
|
||||||
|
user's full Matrix ID (e.g. it's `alice` in `@alice:example.com`).
|
||||||
|
|
||||||
|
This callback is called once [User-Interactive Authentication](https://spec.matrix.org/latest/client-server-api/#user-interactive-authentication-api)
|
||||||
|
has been completed by the user. It is not called when registering a user via SSO. It is
|
||||||
|
passed two dictionaries, which include the information that the user has provided during
|
||||||
|
the registration process.
|
||||||
|
|
||||||
|
The first dictionary contains the results of the [User-Interactive Authentication](https://spec.matrix.org/latest/client-server-api/#user-interactive-authentication-api)
|
||||||
|
flow followed by the user. Its keys are the identifiers of every step involved in the flow,
|
||||||
|
associated with either a boolean value indicating whether the step was correctly completed,
|
||||||
|
or additional information (e.g. email address, phone number...). A list of most existing
|
||||||
|
identifiers can be found in the [Matrix specification](https://spec.matrix.org/v1.1/client-server-api/#authentication-types).
|
||||||
|
Here's an example featuring all currently supported keys:
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"m.login.dummy": True, # Dummy authentication
|
||||||
|
"m.login.terms": True, # User has accepted the terms of service for the homeserver
|
||||||
|
"m.login.recaptcha": True, # User has completed the recaptcha challenge
|
||||||
|
"m.login.email.identity": { # User has provided and verified an email address
|
||||||
|
"medium": "email",
|
||||||
|
"address": "alice@example.com",
|
||||||
|
"validated_at": 1642701357084,
|
||||||
|
},
|
||||||
|
"m.login.msisdn": { # User has provided and verified a phone number
|
||||||
|
"medium": "msisdn",
|
||||||
|
"address": "33123456789",
|
||||||
|
"validated_at": 1642701357084,
|
||||||
|
},
|
||||||
|
"org.matrix.msc3231.login.registration_token": "sometoken", # User has registered through the flow described in MSC3231
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The second dictionary contains the parameters provided by the user's client in the request
|
||||||
|
to `/_matrix/client/v3/register`. See the [Matrix specification](https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3register)
|
||||||
|
for a complete list of these parameters.
|
||||||
|
|
||||||
|
If the module cannot, or does not wish to, generate a username for this user, it must
|
||||||
|
return `None`.
|
||||||
|
|
||||||
|
If multiple modules implement this callback, they will be considered in order. If a
|
||||||
|
callback returns `None`, Synapse falls through to the next one. The value of the first
|
||||||
|
callback that does not return `None` will be used. If this happens, Synapse will not call
|
||||||
|
any of the subsequent implementations of this callback. If every callback return `None`,
|
||||||
|
the username provided by the user is used, if any (otherwise one is automatically
|
||||||
|
generated).
|
||||||
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
The example module below implements authentication checkers for two different login types:
|
The example module below implements authentication checkers for two different login types:
|
||||||
|
|||||||
@@ -41,11 +41,11 @@
|
|||||||
# documentation on how to configure or create custom modules for Synapse.
|
# documentation on how to configure or create custom modules for Synapse.
|
||||||
#
|
#
|
||||||
modules:
|
modules:
|
||||||
# - module: my_super_module.MySuperClass
|
#- module: my_super_module.MySuperClass
|
||||||
# config:
|
# config:
|
||||||
# do_thing: true
|
# do_thing: true
|
||||||
# - module: my_other_super_module.SomeClass
|
#- module: my_other_super_module.SomeClass
|
||||||
# config: {}
|
# config: {}
|
||||||
|
|
||||||
|
|
||||||
## Server ##
|
## Server ##
|
||||||
@@ -74,13 +74,7 @@ server_name: "SERVERNAME"
|
|||||||
#
|
#
|
||||||
pid_file: DATADIR/homeserver.pid
|
pid_file: DATADIR/homeserver.pid
|
||||||
|
|
||||||
# The absolute URL to the web client which /_matrix/client will redirect
|
# The absolute URL to the web client which / will redirect to.
|
||||||
# to if 'webclient' is configured under the 'listeners' configuration.
|
|
||||||
#
|
|
||||||
# This option can be also set to the filesystem path to the web client
|
|
||||||
# which will be served at /_matrix/client/ if 'webclient' is configured
|
|
||||||
# under the 'listeners' configuration, however this is a security risk:
|
|
||||||
# https://github.com/matrix-org/synapse#security-note
|
|
||||||
#
|
#
|
||||||
#web_client_location: https://riot.example.com/
|
#web_client_location: https://riot.example.com/
|
||||||
|
|
||||||
@@ -310,8 +304,6 @@ presence:
|
|||||||
# static: static resources under synapse/static (/_matrix/static). (Mostly
|
# static: static resources under synapse/static (/_matrix/static). (Mostly
|
||||||
# useful for 'fallback authentication'.)
|
# useful for 'fallback authentication'.)
|
||||||
#
|
#
|
||||||
# webclient: A web client. Requires web_client_location to be set.
|
|
||||||
#
|
|
||||||
listeners:
|
listeners:
|
||||||
# TLS-enabled listener: for when matrix traffic is sent directly to synapse.
|
# TLS-enabled listener: for when matrix traffic is sent directly to synapse.
|
||||||
#
|
#
|
||||||
@@ -479,6 +471,20 @@ limit_remote_rooms:
|
|||||||
#
|
#
|
||||||
#allow_per_room_profiles: false
|
#allow_per_room_profiles: false
|
||||||
|
|
||||||
|
# The largest allowed file size for a user avatar. Defaults to no restriction.
|
||||||
|
#
|
||||||
|
# Note that user avatar changes will not work if this is set without
|
||||||
|
# using Synapse's media repository.
|
||||||
|
#
|
||||||
|
#max_avatar_size: 10M
|
||||||
|
|
||||||
|
# The MIME types allowed for user avatars. Defaults to no restriction.
|
||||||
|
#
|
||||||
|
# Note that user avatar changes will not work if this is set without
|
||||||
|
# using Synapse's media repository.
|
||||||
|
#
|
||||||
|
#allowed_avatar_mimetypes: ["image/png", "image/jpeg", "image/gif"]
|
||||||
|
|
||||||
# How long to keep redacted events in unredacted form in the database. After
|
# How long to keep redacted events in unredacted form in the database. After
|
||||||
# this period redacted events get replaced with their redacted form in the DB.
|
# this period redacted events get replaced with their redacted form in the DB.
|
||||||
#
|
#
|
||||||
@@ -1436,6 +1442,16 @@ account_threepid_delegates:
|
|||||||
#
|
#
|
||||||
#auto_join_rooms_for_guests: false
|
#auto_join_rooms_for_guests: false
|
||||||
|
|
||||||
|
# Whether to inhibit errors raised when registering a new account if the user ID
|
||||||
|
# already exists. If turned on, that requests to /register/available will always
|
||||||
|
# show a user ID as available, and Synapse won't raise an error when starting
|
||||||
|
# a registration with a user ID that already exists. However, Synapse will still
|
||||||
|
# raise an error if the registration completes and the username conflicts.
|
||||||
|
#
|
||||||
|
# Defaults to false.
|
||||||
|
#
|
||||||
|
#inhibit_user_in_use_error: true
|
||||||
|
|
||||||
|
|
||||||
## Metrics ###
|
## Metrics ###
|
||||||
|
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ When following this route please make sure that the [Platform-specific prerequis
|
|||||||
System requirements:
|
System requirements:
|
||||||
|
|
||||||
- POSIX-compliant system (tested on Linux & OS X)
|
- POSIX-compliant system (tested on Linux & OS X)
|
||||||
- Python 3.6 or later, up to Python 3.9.
|
- Python 3.7 or later, up to Python 3.10.
|
||||||
- At least 1GB of free RAM if you want to join large public rooms like #matrix:matrix.org
|
- At least 1GB of free RAM if you want to join large public rooms like #matrix:matrix.org
|
||||||
|
|
||||||
To install the Synapse homeserver run:
|
To install the Synapse homeserver run:
|
||||||
|
|||||||
@@ -85,6 +85,28 @@ process, for example:
|
|||||||
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb
|
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Upgrading to v1.52.0
|
||||||
|
|
||||||
|
## Twisted security release
|
||||||
|
|
||||||
|
During the making of this release, the developers of Twisted have released
|
||||||
|
[Twisted 22.1.0](https://github.com/twisted/twisted/releases/tag/twisted-22.1.0), which
|
||||||
|
fixes [a security issue](https://github.com/twisted/twisted/security/advisories/GHSA-92x2-jw7w-xvvx)
|
||||||
|
within Twisted. We do not believe Synapse to be vulnerable to any security problem caused
|
||||||
|
by this issue, though we advise server administrators to update their local version of
|
||||||
|
Twisted if they can.
|
||||||
|
|
||||||
|
# Upgrading to v1.51.0
|
||||||
|
|
||||||
|
## Deprecation of `webclient` listeners and non-HTTP(S) `web_client_location`
|
||||||
|
|
||||||
|
Listeners of type `webclient` are deprecated and scheduled to be removed in
|
||||||
|
Synapse v1.53.0.
|
||||||
|
|
||||||
|
Similarly, a non-HTTP(S) `web_client_location` configuration is deprecated and
|
||||||
|
will become a configuration error in Synapse v1.53.0.
|
||||||
|
|
||||||
|
|
||||||
# Upgrading to v1.50.0
|
# Upgrading to v1.50.0
|
||||||
|
|
||||||
## Dropping support for old Python and Postgres versions
|
## Dropping support for old Python and Postgres versions
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ The following fields are returned in the JSON response body:
|
|||||||
- `next_token`: string representing a positive integer - Indication for pagination. See above.
|
- `next_token`: string representing a positive integer - Indication for pagination. See above.
|
||||||
- `total` - integer - Total number of destinations.
|
- `total` - integer - Total number of destinations.
|
||||||
|
|
||||||
# Destination Details API
|
## Destination Details API
|
||||||
|
|
||||||
This API gets the retry timing info for a specific remote server.
|
This API gets the retry timing info for a specific remote server.
|
||||||
|
|
||||||
@@ -108,7 +108,105 @@ A response body like the following is returned:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
The following parameters should be set in the URL:
|
||||||
|
|
||||||
|
- `destination` - Name of the remote server.
|
||||||
|
|
||||||
**Response**
|
**Response**
|
||||||
|
|
||||||
The response fields are the same like in the `destinations` array in
|
The response fields are the same like in the `destinations` array in
|
||||||
[List of destinations](#list-of-destinations) response.
|
[List of destinations](#list-of-destinations) response.
|
||||||
|
|
||||||
|
## Destination rooms
|
||||||
|
|
||||||
|
This API gets the rooms that federate with a specific remote server.
|
||||||
|
|
||||||
|
The API is:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /_synapse/admin/v1/federation/destinations/<destination>/rooms
|
||||||
|
```
|
||||||
|
|
||||||
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rooms":[
|
||||||
|
{
|
||||||
|
"room_id": "!OGEhHVWSdvArJzumhm:matrix.org",
|
||||||
|
"stream_ordering": 8326
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"room_id": "!xYvNcQPhnkrdUmYczI:matrix.org",
|
||||||
|
"stream_ordering": 93534
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To paginate, check for `next_token` and if present, call the endpoint again
|
||||||
|
with `from` set to the value of `next_token`. This will return a new page.
|
||||||
|
|
||||||
|
If the endpoint does not return a `next_token` then there are no more destinations
|
||||||
|
to paginate through.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
The following parameters should be set in the URL:
|
||||||
|
|
||||||
|
- `destination` - Name of the remote server.
|
||||||
|
|
||||||
|
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`.
|
||||||
|
- `dir` - Direction of room order by `room_id`. Either `f` for forwards or `b` for
|
||||||
|
backwards. Defaults to `f`.
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
The following fields are returned in the JSON response body:
|
||||||
|
|
||||||
|
- `rooms` - An array of objects, each containing information about a room.
|
||||||
|
Room objects contain the following fields:
|
||||||
|
- `room_id` - string - The ID of the room.
|
||||||
|
- `stream_ordering` - integer - The stream ordering of the most recent
|
||||||
|
successfully-sent [PDU](understanding_synapse_through_grafana_graphs.md#federation)
|
||||||
|
to this destination in this room.
|
||||||
|
- `next_token`: string representing a positive integer - Indication for pagination. See above.
|
||||||
|
- `total` - integer - Total number of destinations.
|
||||||
|
|
||||||
|
## Reset connection timeout
|
||||||
|
|
||||||
|
Synapse makes federation requests to other homeservers. If a federation request fails,
|
||||||
|
Synapse will mark the destination homeserver as offline, preventing any future requests
|
||||||
|
to that server for a "cooldown" period. This period grows over time if the server
|
||||||
|
continues to fail its responses
|
||||||
|
([exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)).
|
||||||
|
|
||||||
|
Admins can cancel the cooldown period with this API.
|
||||||
|
|
||||||
|
This API resets the retry timing for a specific remote server and tries to connect to
|
||||||
|
the remote server again. It does not wait for the next `retry_interval`.
|
||||||
|
The connection must have previously run into an error and `retry_last_ts`
|
||||||
|
([Destination Details API](#destination-details-api)) must not be equal to `0`.
|
||||||
|
|
||||||
|
The connection attempt is carried out in the background and can take a while
|
||||||
|
even if the API already returns the http status 200.
|
||||||
|
|
||||||
|
The API is:
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /_synapse/admin/v1/federation/destinations/<destination>/reset_connection
|
||||||
|
|
||||||
|
{}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
The following parameters should be set in the URL:
|
||||||
|
|
||||||
|
- `destination` - Name of the remote server.
|
||||||
|
|||||||
3
mypy.ini
3
mypy.ini
@@ -77,9 +77,6 @@ exclude = (?x)
|
|||||||
|tests/push/test_http.py
|
|tests/push/test_http.py
|
||||||
|tests/push/test_presentable_names.py
|
|tests/push/test_presentable_names.py
|
||||||
|tests/push/test_push_rule_evaluator.py
|
|tests/push/test_push_rule_evaluator.py
|
||||||
|tests/rest/admin/test_admin.py
|
|
||||||
|tests/rest/admin/test_user.py
|
|
||||||
|tests/rest/admin/test_username_available.py
|
|
||||||
|tests/rest/client/test_account.py
|
|tests/rest/client/test_account.py
|
||||||
|tests/rest/client/test_events.py
|
|tests/rest/client/test_events.py
|
||||||
|tests/rest/client/test_filter.py
|
|tests/rest/client/test_filter.py
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
# By default the script will fetch the latest Complement master branch and
|
# By default the script will fetch the latest Complement master branch and
|
||||||
# run tests with that. This can be overridden to use a custom Complement
|
# run tests with that. This can be overridden to use a custom Complement
|
||||||
# checkout by setting the COMPLEMENT_DIR environment variable to the
|
# checkout by setting the COMPLEMENT_DIR environment variable to the
|
||||||
# filepath of a local Complement checkout.
|
# filepath of a local Complement checkout or by setting the COMPLEMENT_REF
|
||||||
|
# environment variable to pull a different branch or commit.
|
||||||
#
|
#
|
||||||
# By default Synapse is run in monolith mode. This can be overridden by
|
# By default Synapse is run in monolith mode. This can be overridden by
|
||||||
# setting the WORKERS environment variable.
|
# setting the WORKERS environment variable.
|
||||||
@@ -31,11 +32,12 @@ cd "$(dirname $0)/.."
|
|||||||
|
|
||||||
# Check for a user-specified Complement checkout
|
# Check for a user-specified Complement checkout
|
||||||
if [[ -z "$COMPLEMENT_DIR" ]]; then
|
if [[ -z "$COMPLEMENT_DIR" ]]; then
|
||||||
echo "COMPLEMENT_DIR not set. Fetching the latest Complement checkout..."
|
COMPLEMENT_REF=${COMPLEMENT_REF:-master}
|
||||||
wget -Nq https://github.com/matrix-org/complement/archive/master.tar.gz
|
echo "COMPLEMENT_DIR not set. Fetching Complement checkout from ${COMPLEMENT_REF}..."
|
||||||
tar -xzf master.tar.gz
|
wget -Nq https://github.com/matrix-org/complement/archive/${COMPLEMENT_REF}.tar.gz
|
||||||
COMPLEMENT_DIR=complement-master
|
tar -xzf ${COMPLEMENT_REF}.tar.gz
|
||||||
echo "Checkout available at 'complement-master'"
|
COMPLEMENT_DIR=complement-${COMPLEMENT_REF}
|
||||||
|
echo "Checkout available at 'complement-${COMPLEMENT_REF}'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build the base Synapse image from the local checkout
|
# Build the base Synapse image from the local checkout
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -150,7 +150,7 @@ setup(
|
|||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/x-rst",
|
long_description_content_type="text/x-rst",
|
||||||
python_requires="~=3.6",
|
python_requires="~=3.7",
|
||||||
entry_points={
|
entry_points={
|
||||||
"console_scripts": [
|
"console_scripts": [
|
||||||
"synapse_homeserver = synapse.app.homeserver:main",
|
"synapse_homeserver = synapse.app.homeserver:main",
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Check that we're not running on an unsupported Python version.
|
# Check that we're not running on an unsupported Python version.
|
||||||
if sys.version_info < (3, 6):
|
if sys.version_info < (3, 7):
|
||||||
print("Synapse requires Python 3.6 or above.")
|
print("Synapse requires Python 3.7 or above.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Twisted and canonicaljson will fail to import when this file is executed to
|
# Twisted and canonicaljson will fail to import when this file is executed to
|
||||||
@@ -47,7 +47,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
__version__ = "1.50.1"
|
__version__ = "1.52.0"
|
||||||
|
|
||||||
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
|
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
|
# We import here so that we don't have to install a bunch of deps when
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import atexit
|
|||||||
import gc
|
import gc
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import signal
|
import signal
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
@@ -436,7 +435,8 @@ async def start(hs: "HomeServer") -> None:
|
|||||||
# before we start the listeners.
|
# before we start the listeners.
|
||||||
module_api = hs.get_module_api()
|
module_api = hs.get_module_api()
|
||||||
for module, config in hs.config.modules.loaded_modules:
|
for module, config in hs.config.modules.loaded_modules:
|
||||||
module(config=config, api=module_api)
|
m = module(config=config, api=module_api)
|
||||||
|
logger.info("Loaded module %s", m)
|
||||||
|
|
||||||
load_legacy_spam_checkers(hs)
|
load_legacy_spam_checkers(hs)
|
||||||
load_legacy_third_party_event_rules(hs)
|
load_legacy_third_party_event_rules(hs)
|
||||||
@@ -468,15 +468,13 @@ async def start(hs: "HomeServer") -> None:
|
|||||||
# everything currently allocated are things that will be used for the
|
# everything currently allocated are things that will be used for the
|
||||||
# rest of time. Doing so means less work each GC (hopefully).
|
# rest of time. Doing so means less work each GC (hopefully).
|
||||||
#
|
#
|
||||||
# This only works on Python 3.7
|
# PyPy does not (yet?) implement gc.freeze()
|
||||||
if platform.python_implementation() == "CPython" and sys.version_info >= (3, 7):
|
if hasattr(gc, "freeze"):
|
||||||
gc.collect()
|
gc.collect()
|
||||||
gc.freeze()
|
gc.freeze()
|
||||||
|
|
||||||
# Speed up shutdowns by freezing all allocated objects. This moves everything
|
# Speed up shutdowns by freezing all allocated objects. This moves everything
|
||||||
# into the permanent generation and excludes them from the final GC.
|
# into the permanent generation and excludes them from the final GC.
|
||||||
# Unfortunately only works on Python 3.7
|
|
||||||
if platform.python_implementation() == "CPython" and sys.version_info >= (3, 7):
|
|
||||||
atexit.register(gc.freeze)
|
atexit.register(gc.freeze)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -131,9 +131,18 @@ class SynapseHomeServer(HomeServer):
|
|||||||
resources.update(self._module_web_resources)
|
resources.update(self._module_web_resources)
|
||||||
self._module_web_resources_consumed = True
|
self._module_web_resources_consumed = True
|
||||||
|
|
||||||
# try to find something useful to redirect '/' to
|
# Try to find something useful to serve at '/':
|
||||||
if WEB_CLIENT_PREFIX in resources:
|
#
|
||||||
root_resource: Resource = RootOptionsRedirectResource(WEB_CLIENT_PREFIX)
|
# 1. Redirect to the web client if it is an HTTP(S) URL.
|
||||||
|
# 2. Redirect to the web client served via Synapse.
|
||||||
|
# 3. Redirect to the static "Synapse is running" page.
|
||||||
|
# 4. Do not redirect and use a blank resource.
|
||||||
|
if self.config.server.web_client_location_is_redirect:
|
||||||
|
root_resource: Resource = RootOptionsRedirectResource(
|
||||||
|
self.config.server.web_client_location
|
||||||
|
)
|
||||||
|
elif WEB_CLIENT_PREFIX in resources:
|
||||||
|
root_resource = RootOptionsRedirectResource(WEB_CLIENT_PREFIX)
|
||||||
elif STATIC_PREFIX in resources:
|
elif STATIC_PREFIX in resources:
|
||||||
root_resource = RootOptionsRedirectResource(STATIC_PREFIX)
|
root_resource = RootOptionsRedirectResource(STATIC_PREFIX)
|
||||||
else:
|
else:
|
||||||
@@ -262,15 +271,15 @@ class SynapseHomeServer(HomeServer):
|
|||||||
resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)
|
resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)
|
||||||
|
|
||||||
if name == "webclient":
|
if name == "webclient":
|
||||||
|
# webclient listeners are deprecated as of Synapse v1.51.0, remove it
|
||||||
|
# in > v1.53.0.
|
||||||
webclient_loc = self.config.server.web_client_location
|
webclient_loc = self.config.server.web_client_location
|
||||||
|
|
||||||
if webclient_loc is None:
|
if webclient_loc is None:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Not enabling webclient resource, as web_client_location is unset."
|
"Not enabling webclient resource, as web_client_location is unset."
|
||||||
)
|
)
|
||||||
elif webclient_loc.startswith("http://") or webclient_loc.startswith(
|
elif self.config.server.web_client_location_is_redirect:
|
||||||
"https://"
|
|
||||||
):
|
|
||||||
resources[WEB_CLIENT_PREFIX] = RootRedirect(webclient_loc)
|
resources[WEB_CLIENT_PREFIX] = RootRedirect(webclient_loc)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ class ExperimentalConfig(Config):
|
|||||||
def read_config(self, config: JsonDict, **kwargs):
|
def read_config(self, config: JsonDict, **kwargs):
|
||||||
experimental = config.get("experimental_features") or {}
|
experimental = config.get("experimental_features") or {}
|
||||||
|
|
||||||
# Whether to enable experimental MSC1849 (aka relations) support
|
|
||||||
self.msc1849_enabled = config.get("experimental_msc1849_support_enabled", True)
|
|
||||||
# MSC3440 (thread relation)
|
# MSC3440 (thread relation)
|
||||||
self.msc3440_enabled: bool = experimental.get("msc3440_enabled", False)
|
self.msc3440_enabled: bool = experimental.get("msc3440_enabled", False)
|
||||||
|
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ class ModulesConfig(Config):
|
|||||||
# documentation on how to configure or create custom modules for Synapse.
|
# documentation on how to configure or create custom modules for Synapse.
|
||||||
#
|
#
|
||||||
modules:
|
modules:
|
||||||
# - module: my_super_module.MySuperClass
|
#- module: my_super_module.MySuperClass
|
||||||
# config:
|
# config:
|
||||||
# do_thing: true
|
# do_thing: true
|
||||||
# - module: my_other_super_module.SomeClass
|
#- module: my_other_super_module.SomeClass
|
||||||
# config: {}
|
# config: {}
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -190,6 +190,8 @@ class RegistrationConfig(Config):
|
|||||||
# The success template used during fallback auth.
|
# The success template used during fallback auth.
|
||||||
self.fallback_success_template = self.read_template("auth_success.html")
|
self.fallback_success_template = self.read_template("auth_success.html")
|
||||||
|
|
||||||
|
self.inhibit_user_in_use_error = config.get("inhibit_user_in_use_error", False)
|
||||||
|
|
||||||
def generate_config_section(self, generate_secrets=False, **kwargs):
|
def generate_config_section(self, generate_secrets=False, **kwargs):
|
||||||
if generate_secrets:
|
if generate_secrets:
|
||||||
registration_shared_secret = 'registration_shared_secret: "%s"' % (
|
registration_shared_secret = 'registration_shared_secret: "%s"' % (
|
||||||
@@ -446,6 +448,16 @@ class RegistrationConfig(Config):
|
|||||||
# Defaults to true.
|
# Defaults to true.
|
||||||
#
|
#
|
||||||
#auto_join_rooms_for_guests: false
|
#auto_join_rooms_for_guests: false
|
||||||
|
|
||||||
|
# Whether to inhibit errors raised when registering a new account if the user ID
|
||||||
|
# already exists. If turned on, that requests to /register/available will always
|
||||||
|
# show a user ID as available, and Synapse won't raise an error when starting
|
||||||
|
# a registration with a user ID that already exists. However, Synapse will still
|
||||||
|
# raise an error if the registration completes and the username conflicts.
|
||||||
|
#
|
||||||
|
# Defaults to false.
|
||||||
|
#
|
||||||
|
#inhibit_user_in_use_error: true
|
||||||
"""
|
"""
|
||||||
% locals()
|
% locals()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -259,7 +259,6 @@ class ServerConfig(Config):
|
|||||||
raise ConfigError(str(e))
|
raise ConfigError(str(e))
|
||||||
|
|
||||||
self.pid_file = self.abspath(config.get("pid_file"))
|
self.pid_file = self.abspath(config.get("pid_file"))
|
||||||
self.web_client_location = config.get("web_client_location", None)
|
|
||||||
self.soft_file_limit = config.get("soft_file_limit", 0)
|
self.soft_file_limit = config.get("soft_file_limit", 0)
|
||||||
self.daemonize = config.get("daemonize")
|
self.daemonize = config.get("daemonize")
|
||||||
self.print_pidfile = config.get("print_pidfile")
|
self.print_pidfile = config.get("print_pidfile")
|
||||||
@@ -490,6 +489,19 @@ class ServerConfig(Config):
|
|||||||
# events with profile information that differ from the target's global profile.
|
# events with profile information that differ from the target's global profile.
|
||||||
self.allow_per_room_profiles = config.get("allow_per_room_profiles", True)
|
self.allow_per_room_profiles = config.get("allow_per_room_profiles", True)
|
||||||
|
|
||||||
|
# The maximum size an avatar can have, in bytes.
|
||||||
|
self.max_avatar_size = config.get("max_avatar_size")
|
||||||
|
if self.max_avatar_size is not None:
|
||||||
|
self.max_avatar_size = self.parse_size(self.max_avatar_size)
|
||||||
|
|
||||||
|
# The MIME types allowed for an avatar.
|
||||||
|
self.allowed_avatar_mimetypes = config.get("allowed_avatar_mimetypes")
|
||||||
|
if self.allowed_avatar_mimetypes and not isinstance(
|
||||||
|
self.allowed_avatar_mimetypes,
|
||||||
|
list,
|
||||||
|
):
|
||||||
|
raise ConfigError("allowed_avatar_mimetypes must be a list")
|
||||||
|
|
||||||
self.listeners = [parse_listener_def(x) for x in config.get("listeners", [])]
|
self.listeners = [parse_listener_def(x) for x in config.get("listeners", [])]
|
||||||
|
|
||||||
# no_tls is not really supported any more, but let's grandfather it in
|
# no_tls is not really supported any more, but let's grandfather it in
|
||||||
@@ -506,8 +518,17 @@ class ServerConfig(Config):
|
|||||||
l2.append(listener)
|
l2.append(listener)
|
||||||
self.listeners = l2
|
self.listeners = l2
|
||||||
|
|
||||||
if not self.web_client_location:
|
self.web_client_location = config.get("web_client_location", None)
|
||||||
_warn_if_webclient_configured(self.listeners)
|
self.web_client_location_is_redirect = self.web_client_location and (
|
||||||
|
self.web_client_location.startswith("http://")
|
||||||
|
or self.web_client_location.startswith("https://")
|
||||||
|
)
|
||||||
|
# A non-HTTP(S) web client location is deprecated.
|
||||||
|
if self.web_client_location and not self.web_client_location_is_redirect:
|
||||||
|
logger.warning(NO_MORE_NONE_HTTP_WEB_CLIENT_LOCATION_WARNING)
|
||||||
|
|
||||||
|
# Warn if webclient is configured for a worker.
|
||||||
|
_warn_if_webclient_configured(self.listeners)
|
||||||
|
|
||||||
self.gc_thresholds = read_gc_thresholds(config.get("gc_thresholds", None))
|
self.gc_thresholds = read_gc_thresholds(config.get("gc_thresholds", None))
|
||||||
self.gc_seconds = self.read_gc_intervals(config.get("gc_min_interval", None))
|
self.gc_seconds = self.read_gc_intervals(config.get("gc_min_interval", None))
|
||||||
@@ -793,13 +814,7 @@ class ServerConfig(Config):
|
|||||||
#
|
#
|
||||||
pid_file: %(pid_file)s
|
pid_file: %(pid_file)s
|
||||||
|
|
||||||
# The absolute URL to the web client which /_matrix/client will redirect
|
# The absolute URL to the web client which / will redirect to.
|
||||||
# to if 'webclient' is configured under the 'listeners' configuration.
|
|
||||||
#
|
|
||||||
# This option can be also set to the filesystem path to the web client
|
|
||||||
# which will be served at /_matrix/client/ if 'webclient' is configured
|
|
||||||
# under the 'listeners' configuration, however this is a security risk:
|
|
||||||
# https://github.com/matrix-org/synapse#security-note
|
|
||||||
#
|
#
|
||||||
#web_client_location: https://riot.example.com/
|
#web_client_location: https://riot.example.com/
|
||||||
|
|
||||||
@@ -1011,8 +1026,6 @@ class ServerConfig(Config):
|
|||||||
# static: static resources under synapse/static (/_matrix/static). (Mostly
|
# static: static resources under synapse/static (/_matrix/static). (Mostly
|
||||||
# useful for 'fallback authentication'.)
|
# useful for 'fallback authentication'.)
|
||||||
#
|
#
|
||||||
# webclient: A web client. Requires web_client_location to be set.
|
|
||||||
#
|
|
||||||
listeners:
|
listeners:
|
||||||
# TLS-enabled listener: for when matrix traffic is sent directly to synapse.
|
# TLS-enabled listener: for when matrix traffic is sent directly to synapse.
|
||||||
#
|
#
|
||||||
@@ -1168,6 +1181,20 @@ class ServerConfig(Config):
|
|||||||
#
|
#
|
||||||
#allow_per_room_profiles: false
|
#allow_per_room_profiles: false
|
||||||
|
|
||||||
|
# The largest allowed file size for a user avatar. Defaults to no restriction.
|
||||||
|
#
|
||||||
|
# Note that user avatar changes will not work if this is set without
|
||||||
|
# using Synapse's media repository.
|
||||||
|
#
|
||||||
|
#max_avatar_size: 10M
|
||||||
|
|
||||||
|
# The MIME types allowed for user avatars. Defaults to no restriction.
|
||||||
|
#
|
||||||
|
# Note that user avatar changes will not work if this is set without
|
||||||
|
# using Synapse's media repository.
|
||||||
|
#
|
||||||
|
#allowed_avatar_mimetypes: ["image/png", "image/jpeg", "image/gif"]
|
||||||
|
|
||||||
# How long to keep redacted events in unredacted form in the database. After
|
# How long to keep redacted events in unredacted form in the database. After
|
||||||
# this period redacted events get replaced with their redacted form in the DB.
|
# this period redacted events get replaced with their redacted form in the DB.
|
||||||
#
|
#
|
||||||
@@ -1349,9 +1376,15 @@ def parse_listener_def(listener: Any) -> ListenerConfig:
|
|||||||
return ListenerConfig(port, bind_addresses, listener_type, tls, http_config)
|
return ListenerConfig(port, bind_addresses, listener_type, tls, http_config)
|
||||||
|
|
||||||
|
|
||||||
|
NO_MORE_NONE_HTTP_WEB_CLIENT_LOCATION_WARNING = """
|
||||||
|
Synapse no longer supports serving a web client. To remove this warning,
|
||||||
|
configure 'web_client_location' with an HTTP(S) URL.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
NO_MORE_WEB_CLIENT_WARNING = """
|
NO_MORE_WEB_CLIENT_WARNING = """
|
||||||
Synapse no longer includes a web client. To enable a web client, configure
|
Synapse no longer includes a web client. To redirect the root resource to a web client, configure
|
||||||
web_client_location. To remove this warning, remove 'webclient' from the 'listeners'
|
'web_client_location'. To remove this warning, remove 'webclient' from the 'listeners'
|
||||||
configuration.
|
configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -315,10 +315,11 @@ class EventBase(metaclass=abc.ABCMeta):
|
|||||||
redacts: DefaultDictProperty[Optional[str]] = DefaultDictProperty("redacts", None)
|
redacts: DefaultDictProperty[Optional[str]] = DefaultDictProperty("redacts", None)
|
||||||
room_id: DictProperty[str] = DictProperty("room_id")
|
room_id: DictProperty[str] = DictProperty("room_id")
|
||||||
sender: DictProperty[str] = DictProperty("sender")
|
sender: DictProperty[str] = DictProperty("sender")
|
||||||
# TODO state_key should be Optional[str], this is generally asserted in Synapse
|
# TODO state_key should be Optional[str]. This is generally asserted in Synapse
|
||||||
# by calling is_state() first (which ensures this), but it is hard (not possible?)
|
# by calling is_state() first (which ensures it is not None), but it is hard (not possible?)
|
||||||
# to properly annotate that calling is_state() asserts that state_key exists
|
# to properly annotate that calling is_state() asserts that state_key exists
|
||||||
# and is non-None.
|
# and is non-None. It would be better to replace such direct references with
|
||||||
|
# get_state_key() (and a check for None).
|
||||||
state_key: DictProperty[str] = DictProperty("state_key")
|
state_key: DictProperty[str] = DictProperty("state_key")
|
||||||
type: DictProperty[str] = DictProperty("type")
|
type: DictProperty[str] = DictProperty("type")
|
||||||
user_id: DictProperty[str] = DictProperty("sender")
|
user_id: DictProperty[str] = DictProperty("sender")
|
||||||
@@ -332,7 +333,11 @@ class EventBase(metaclass=abc.ABCMeta):
|
|||||||
return self.content["membership"]
|
return self.content["membership"]
|
||||||
|
|
||||||
def is_state(self) -> bool:
|
def is_state(self) -> bool:
|
||||||
return hasattr(self, "state_key") and self.state_key is not None
|
return self.get_state_key() is not None
|
||||||
|
|
||||||
|
def get_state_key(self) -> Optional[str]:
|
||||||
|
"""Get the state key of this event, or None if it's not a state event"""
|
||||||
|
return self._dict.get("state_key")
|
||||||
|
|
||||||
def get_dict(self) -> JsonDict:
|
def get_dict(self) -> JsonDict:
|
||||||
d = dict(self._dict)
|
d = dict(self._dict)
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class EventContext:
|
|||||||
return {
|
return {
|
||||||
"prev_state_id": prev_state_id,
|
"prev_state_id": prev_state_id,
|
||||||
"event_type": event.type,
|
"event_type": event.type,
|
||||||
"event_state_key": event.state_key if event.is_state() else None,
|
"event_state_key": event.get_state_key(),
|
||||||
"state_group": self._state_group,
|
"state_group": self._state_group,
|
||||||
"state_group_before_event": self.state_group_before_event,
|
"state_group_before_event": self.state_group_before_event,
|
||||||
"rejected": self.rejected,
|
"rejected": self.rejected,
|
||||||
|
|||||||
@@ -14,7 +14,17 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import collections.abc
|
import collections.abc
|
||||||
import re
|
import re
|
||||||
from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Union
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
Iterable,
|
||||||
|
List,
|
||||||
|
Mapping,
|
||||||
|
Optional,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
from frozendict import frozendict
|
from frozendict import frozendict
|
||||||
|
|
||||||
@@ -26,6 +36,10 @@ from synapse.util.frozenutils import unfreeze
|
|||||||
|
|
||||||
from . import EventBase
|
from . import EventBase
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from synapse.storage.databases.main.relations import BundledAggregations
|
||||||
|
|
||||||
|
|
||||||
# Split strings on "." but not "\." This uses a negative lookbehind assertion for '\'
|
# Split strings on "." but not "\." This uses a negative lookbehind assertion for '\'
|
||||||
# (?<!stuff) matches if the current position in the string is not preceded
|
# (?<!stuff) matches if the current position in the string is not preceded
|
||||||
# by a match for 'stuff'.
|
# by a match for 'stuff'.
|
||||||
@@ -376,7 +390,7 @@ class EventClientSerializer:
|
|||||||
event: Union[JsonDict, EventBase],
|
event: Union[JsonDict, EventBase],
|
||||||
time_now: int,
|
time_now: int,
|
||||||
*,
|
*,
|
||||||
bundle_aggregations: Optional[Dict[str, JsonDict]] = None,
|
bundle_aggregations: Optional[Dict[str, "BundledAggregations"]] = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> JsonDict:
|
) -> JsonDict:
|
||||||
"""Serializes a single event.
|
"""Serializes a single event.
|
||||||
@@ -402,7 +416,7 @@ class EventClientSerializer:
|
|||||||
if bundle_aggregations:
|
if bundle_aggregations:
|
||||||
event_aggregations = bundle_aggregations.get(event.event_id)
|
event_aggregations = bundle_aggregations.get(event.event_id)
|
||||||
if event_aggregations:
|
if event_aggregations:
|
||||||
self._injected_bundled_aggregations(
|
self._inject_bundled_aggregations(
|
||||||
event,
|
event,
|
||||||
time_now,
|
time_now,
|
||||||
bundle_aggregations[event.event_id],
|
bundle_aggregations[event.event_id],
|
||||||
@@ -411,11 +425,11 @@ class EventClientSerializer:
|
|||||||
|
|
||||||
return serialized_event
|
return serialized_event
|
||||||
|
|
||||||
def _injected_bundled_aggregations(
|
def _inject_bundled_aggregations(
|
||||||
self,
|
self,
|
||||||
event: EventBase,
|
event: EventBase,
|
||||||
time_now: int,
|
time_now: int,
|
||||||
aggregations: JsonDict,
|
aggregations: "BundledAggregations",
|
||||||
serialized_event: JsonDict,
|
serialized_event: JsonDict,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Potentially injects bundled aggregations into the unsigned portion of the serialized event.
|
"""Potentially injects bundled aggregations into the unsigned portion of the serialized event.
|
||||||
@@ -427,13 +441,18 @@ class EventClientSerializer:
|
|||||||
serialized_event: The serialized event which may be modified.
|
serialized_event: The serialized event which may be modified.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Make a copy in-case the object is cached.
|
serialized_aggregations = {}
|
||||||
aggregations = aggregations.copy()
|
|
||||||
|
|
||||||
if RelationTypes.REPLACE in aggregations:
|
if aggregations.annotations:
|
||||||
|
serialized_aggregations[RelationTypes.ANNOTATION] = aggregations.annotations
|
||||||
|
|
||||||
|
if aggregations.references:
|
||||||
|
serialized_aggregations[RelationTypes.REFERENCE] = aggregations.references
|
||||||
|
|
||||||
|
if aggregations.replace:
|
||||||
# If there is an edit replace the content, preserving existing
|
# If there is an edit replace the content, preserving existing
|
||||||
# relations.
|
# relations.
|
||||||
edit = aggregations[RelationTypes.REPLACE]
|
edit = aggregations.replace
|
||||||
|
|
||||||
# Ensure we take copies of the edit content, otherwise we risk modifying
|
# Ensure we take copies of the edit content, otherwise we risk modifying
|
||||||
# the original event.
|
# the original event.
|
||||||
@@ -451,24 +470,28 @@ class EventClientSerializer:
|
|||||||
else:
|
else:
|
||||||
serialized_event["content"].pop("m.relates_to", None)
|
serialized_event["content"].pop("m.relates_to", None)
|
||||||
|
|
||||||
aggregations[RelationTypes.REPLACE] = {
|
serialized_aggregations[RelationTypes.REPLACE] = {
|
||||||
"event_id": edit.event_id,
|
"event_id": edit.event_id,
|
||||||
"origin_server_ts": edit.origin_server_ts,
|
"origin_server_ts": edit.origin_server_ts,
|
||||||
"sender": edit.sender,
|
"sender": edit.sender,
|
||||||
}
|
}
|
||||||
|
|
||||||
# If this event is the start of a thread, include a summary of the replies.
|
# If this event is the start of a thread, include a summary of the replies.
|
||||||
if RelationTypes.THREAD in aggregations:
|
if aggregations.thread:
|
||||||
# Serialize the latest thread event.
|
serialized_aggregations[RelationTypes.THREAD] = {
|
||||||
latest_thread_event = aggregations[RelationTypes.THREAD]["latest_event"]
|
# Don't bundle aggregations as this could recurse forever.
|
||||||
|
"latest_event": self.serialize_event(
|
||||||
# Don't bundle aggregations as this could recurse forever.
|
aggregations.thread.latest_event, time_now, bundle_aggregations=None
|
||||||
aggregations[RelationTypes.THREAD]["latest_event"] = self.serialize_event(
|
),
|
||||||
latest_thread_event, time_now, bundle_aggregations=None
|
"count": aggregations.thread.count,
|
||||||
)
|
"current_user_participated": aggregations.thread.current_user_participated,
|
||||||
|
}
|
||||||
|
|
||||||
# Include the bundled aggregations in the event.
|
# Include the bundled aggregations in the event.
|
||||||
serialized_event["unsigned"].setdefault("m.relations", {}).update(aggregations)
|
if serialized_aggregations:
|
||||||
|
serialized_event["unsigned"].setdefault("m.relations", {}).update(
|
||||||
|
serialized_aggregations
|
||||||
|
)
|
||||||
|
|
||||||
def serialize_events(
|
def serialize_events(
|
||||||
self, events: Iterable[Union[JsonDict, EventBase]], time_now: int, **kwargs: Any
|
self, events: Iterable[Union[JsonDict, EventBase]], time_now: int, **kwargs: Any
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import collections.abc
|
import collections.abc
|
||||||
from typing import Iterable, Union
|
from typing import Iterable, Type, Union
|
||||||
|
|
||||||
import jsonschema
|
import jsonschema
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ POWER_LEVELS_SCHEMA = {
|
|||||||
|
|
||||||
# This could return something newer than Draft 7, but that's the current "latest"
|
# This could return something newer than Draft 7, but that's the current "latest"
|
||||||
# validator.
|
# validator.
|
||||||
def _create_power_level_validator() -> jsonschema.Draft7Validator:
|
def _create_power_level_validator() -> Type[jsonschema.Draft7Validator]:
|
||||||
validator = jsonschema.validators.validator_for(POWER_LEVELS_SCHEMA)
|
validator = jsonschema.validators.validator_for(POWER_LEVELS_SCHEMA)
|
||||||
|
|
||||||
# by default jsonschema does not consider a frozendict to be an object so
|
# by default jsonschema does not consider a frozendict to be an object so
|
||||||
|
|||||||
@@ -118,7 +118,8 @@ class FederationClient(FederationBase):
|
|||||||
# It is a map of (room ID, suggested-only) -> the response of
|
# It is a map of (room ID, suggested-only) -> the response of
|
||||||
# get_room_hierarchy.
|
# get_room_hierarchy.
|
||||||
self._get_room_hierarchy_cache: ExpiringCache[
|
self._get_room_hierarchy_cache: ExpiringCache[
|
||||||
Tuple[str, bool], Tuple[JsonDict, Sequence[JsonDict], Sequence[str]]
|
Tuple[str, bool],
|
||||||
|
Tuple[JsonDict, Sequence[JsonDict], Sequence[JsonDict], Sequence[str]],
|
||||||
] = ExpiringCache(
|
] = ExpiringCache(
|
||||||
cache_name="get_room_hierarchy_cache",
|
cache_name="get_room_hierarchy_cache",
|
||||||
clock=self._clock,
|
clock=self._clock,
|
||||||
@@ -1333,7 +1334,7 @@ class FederationClient(FederationBase):
|
|||||||
destinations: Iterable[str],
|
destinations: Iterable[str],
|
||||||
room_id: str,
|
room_id: str,
|
||||||
suggested_only: bool,
|
suggested_only: bool,
|
||||||
) -> Tuple[JsonDict, Sequence[JsonDict], Sequence[str]]:
|
) -> Tuple[JsonDict, Sequence[JsonDict], Sequence[JsonDict], Sequence[str]]:
|
||||||
"""
|
"""
|
||||||
Call other servers to get a hierarchy of the given room.
|
Call other servers to get a hierarchy of the given room.
|
||||||
|
|
||||||
@@ -1348,7 +1349,8 @@ class FederationClient(FederationBase):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A tuple of:
|
A tuple of:
|
||||||
The room as a JSON dictionary.
|
The room as a JSON dictionary, without a "children_state" key.
|
||||||
|
A list of `m.space.child` state events.
|
||||||
A list of children rooms, as JSON dictionaries.
|
A list of children rooms, as JSON dictionaries.
|
||||||
A list of inaccessible children room IDs.
|
A list of inaccessible children room IDs.
|
||||||
|
|
||||||
@@ -1363,7 +1365,7 @@ class FederationClient(FederationBase):
|
|||||||
|
|
||||||
async def send_request(
|
async def send_request(
|
||||||
destination: str,
|
destination: str,
|
||||||
) -> Tuple[JsonDict, Sequence[JsonDict], Sequence[str]]:
|
) -> Tuple[JsonDict, Sequence[JsonDict], Sequence[JsonDict], Sequence[str]]:
|
||||||
try:
|
try:
|
||||||
res = await self.transport_layer.get_room_hierarchy(
|
res = await self.transport_layer.get_room_hierarchy(
|
||||||
destination=destination,
|
destination=destination,
|
||||||
@@ -1392,7 +1394,7 @@ class FederationClient(FederationBase):
|
|||||||
raise InvalidResponseError("'room' must be a dict")
|
raise InvalidResponseError("'room' must be a dict")
|
||||||
|
|
||||||
# Validate children_state of the room.
|
# Validate children_state of the room.
|
||||||
children_state = room.get("children_state", [])
|
children_state = room.pop("children_state", [])
|
||||||
if not isinstance(children_state, Sequence):
|
if not isinstance(children_state, Sequence):
|
||||||
raise InvalidResponseError("'room.children_state' must be a list")
|
raise InvalidResponseError("'room.children_state' must be a list")
|
||||||
if any(not isinstance(e, dict) for e in children_state):
|
if any(not isinstance(e, dict) for e in children_state):
|
||||||
@@ -1421,7 +1423,7 @@ class FederationClient(FederationBase):
|
|||||||
"Invalid room ID in 'inaccessible_children' list"
|
"Invalid room ID in 'inaccessible_children' list"
|
||||||
)
|
)
|
||||||
|
|
||||||
return room, children, inaccessible_children
|
return room, children_state, children, inaccessible_children
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await self._try_destination_list(
|
result = await self._try_destination_list(
|
||||||
@@ -1469,8 +1471,6 @@ class FederationClient(FederationBase):
|
|||||||
if event.room_id == room_id:
|
if event.room_id == room_id:
|
||||||
children_events.append(event.data)
|
children_events.append(event.data)
|
||||||
children_room_ids.add(event.state_key)
|
children_room_ids.add(event.state_key)
|
||||||
# And add them under the requested room.
|
|
||||||
requested_room["children_state"] = children_events
|
|
||||||
|
|
||||||
# Find the children rooms.
|
# Find the children rooms.
|
||||||
children = []
|
children = []
|
||||||
@@ -1480,7 +1480,7 @@ class FederationClient(FederationBase):
|
|||||||
|
|
||||||
# It isn't clear from the response whether some of the rooms are
|
# It isn't clear from the response whether some of the rooms are
|
||||||
# not accessible.
|
# not accessible.
|
||||||
result = (requested_room, children, ())
|
result = (requested_room, children_events, children, ())
|
||||||
|
|
||||||
# Cache the result to avoid fetching data over federation every time.
|
# Cache the result to avoid fetching data over federation every time.
|
||||||
self._get_room_hierarchy_cache[(room_id, suggested_only)] = result
|
self._get_room_hierarchy_cache[(room_id, suggested_only)] = result
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ if TYPE_CHECKING:
|
|||||||
import synapse.server
|
import synapse.server
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
issue_8631_logger = logging.getLogger("synapse.8631_debug")
|
||||||
|
|
||||||
last_pdu_ts_metric = Gauge(
|
last_pdu_ts_metric = Gauge(
|
||||||
"synapse_federation_last_sent_pdu_time",
|
"synapse_federation_last_sent_pdu_time",
|
||||||
@@ -124,6 +125,17 @@ class TransactionManager:
|
|||||||
len(pdus),
|
len(pdus),
|
||||||
len(edus),
|
len(edus),
|
||||||
)
|
)
|
||||||
|
if issue_8631_logger.isEnabledFor(logging.DEBUG):
|
||||||
|
DEVICE_UPDATE_EDUS = {"m.device_list_update", "m.signing_key_update"}
|
||||||
|
device_list_updates = [
|
||||||
|
edu.content for edu in edus if edu.edu_type in DEVICE_UPDATE_EDUS
|
||||||
|
]
|
||||||
|
if device_list_updates:
|
||||||
|
issue_8631_logger.debug(
|
||||||
|
"about to send txn [%s] including device list updates: %s",
|
||||||
|
transaction.transaction_id,
|
||||||
|
device_list_updates,
|
||||||
|
)
|
||||||
|
|
||||||
# Actually send the transaction
|
# Actually send the transaction
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Iterable, List, Optional, Tuple, Type
|
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple, Type
|
||||||
|
|
||||||
from typing_extensions import Literal
|
from typing_extensions import Literal
|
||||||
|
|
||||||
@@ -36,17 +36,19 @@ from synapse.http.servlet import (
|
|||||||
parse_integer_from_args,
|
parse_integer_from_args,
|
||||||
parse_string_from_args,
|
parse_string_from_args,
|
||||||
)
|
)
|
||||||
from synapse.server import HomeServer
|
|
||||||
from synapse.types import JsonDict, ThirdPartyInstanceID
|
from synapse.types import JsonDict, ThirdPartyInstanceID
|
||||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TransportLayerServer(JsonResource):
|
class TransportLayerServer(JsonResource):
|
||||||
"""Handles incoming federation HTTP requests"""
|
"""Handles incoming federation HTTP requests"""
|
||||||
|
|
||||||
def __init__(self, hs: HomeServer, servlet_groups: Optional[List[str]] = None):
|
def __init__(self, hs: "HomeServer", servlet_groups: Optional[List[str]] = None):
|
||||||
"""Initialize the TransportLayerServer
|
"""Initialize the TransportLayerServer
|
||||||
|
|
||||||
Will by default register all servlets. For custom behaviour, pass in
|
Will by default register all servlets. For custom behaviour, pass in
|
||||||
@@ -113,7 +115,7 @@ class PublicRoomList(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
@@ -203,7 +205,7 @@ class FederationGroupsRenewAttestaionServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
@@ -251,7 +253,7 @@ class OpenIdUserInfo(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
@@ -297,7 +299,7 @@ DEFAULT_SERVLET_GROUPS: Dict[str, Iterable[Type[BaseFederationServlet]]] = {
|
|||||||
|
|
||||||
|
|
||||||
def register_servlets(
|
def register_servlets(
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
resource: HttpServer,
|
resource: HttpServer,
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Any, Awaitable, Callable, Optional, Tuple, cast
|
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Optional, Tuple, cast
|
||||||
|
|
||||||
from synapse.api.errors import Codes, FederationDeniedError, SynapseError
|
from synapse.api.errors import Codes, FederationDeniedError, SynapseError
|
||||||
from synapse.api.urls import FEDERATION_V1_PREFIX
|
from synapse.api.urls import FEDERATION_V1_PREFIX
|
||||||
@@ -29,11 +29,13 @@ from synapse.logging.opentracing import (
|
|||||||
start_active_span_follows_from,
|
start_active_span_follows_from,
|
||||||
whitelisted_homeserver,
|
whitelisted_homeserver,
|
||||||
)
|
)
|
||||||
from synapse.server import HomeServer
|
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict
|
||||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||||
from synapse.util.stringutils import parse_and_validate_server_name
|
from synapse.util.stringutils import parse_and_validate_server_name
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ class NoAuthenticationError(AuthenticationError):
|
|||||||
|
|
||||||
|
|
||||||
class Authenticator:
|
class Authenticator:
|
||||||
def __init__(self, hs: HomeServer):
|
def __init__(self, hs: "HomeServer"):
|
||||||
self._clock = hs.get_clock()
|
self._clock = hs.get_clock()
|
||||||
self.keyring = hs.get_keyring()
|
self.keyring = hs.get_keyring()
|
||||||
self.server_name = hs.hostname
|
self.server_name = hs.hostname
|
||||||
@@ -114,11 +116,11 @@ class Authenticator:
|
|||||||
# alive
|
# alive
|
||||||
retry_timings = await self.store.get_destination_retry_timings(origin)
|
retry_timings = await self.store.get_destination_retry_timings(origin)
|
||||||
if retry_timings and retry_timings.retry_last_ts:
|
if retry_timings and retry_timings.retry_last_ts:
|
||||||
run_in_background(self._reset_retry_timings, origin)
|
run_in_background(self.reset_retry_timings, origin)
|
||||||
|
|
||||||
return origin
|
return origin
|
||||||
|
|
||||||
async def _reset_retry_timings(self, origin: str) -> None:
|
async def reset_retry_timings(self, origin: str) -> None:
|
||||||
try:
|
try:
|
||||||
logger.info("Marking origin %r as up", origin)
|
logger.info("Marking origin %r as up", origin)
|
||||||
await self.store.set_destination_retry_timings(origin, None, 0, 0)
|
await self.store.set_destination_retry_timings(origin, None, 0, 0)
|
||||||
@@ -227,7 +229,7 @@ class BaseFederationServlet:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
|
|||||||
@@ -12,7 +12,17 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, List, Mapping, Optional, Sequence, Tuple, Type, Union
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Dict,
|
||||||
|
List,
|
||||||
|
Mapping,
|
||||||
|
Optional,
|
||||||
|
Sequence,
|
||||||
|
Tuple,
|
||||||
|
Type,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
from typing_extensions import Literal
|
from typing_extensions import Literal
|
||||||
|
|
||||||
@@ -30,12 +40,15 @@ from synapse.http.servlet import (
|
|||||||
parse_string_from_args,
|
parse_string_from_args,
|
||||||
parse_strings_from_args,
|
parse_strings_from_args,
|
||||||
)
|
)
|
||||||
from synapse.server import HomeServer
|
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict
|
||||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||||
from synapse.util.versionstring import get_version_string
|
from synapse.util.versionstring import get_version_string
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
issue_8631_logger = logging.getLogger("synapse.8631_debug")
|
||||||
|
|
||||||
|
|
||||||
class BaseFederationServerServlet(BaseFederationServlet):
|
class BaseFederationServerServlet(BaseFederationServlet):
|
||||||
@@ -46,7 +59,7 @@ class BaseFederationServerServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
@@ -95,6 +108,20 @@ class FederationSendServlet(BaseFederationServerServlet):
|
|||||||
len(transaction_data.get("edus", [])),
|
len(transaction_data.get("edus", [])),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if issue_8631_logger.isEnabledFor(logging.DEBUG):
|
||||||
|
DEVICE_UPDATE_EDUS = {"m.device_list_update", "m.signing_key_update"}
|
||||||
|
device_list_updates = [
|
||||||
|
edu.content
|
||||||
|
for edu in transaction_data.get("edus", [])
|
||||||
|
if edu.edu_type in DEVICE_UPDATE_EDUS
|
||||||
|
]
|
||||||
|
if device_list_updates:
|
||||||
|
issue_8631_logger.debug(
|
||||||
|
"received transaction [%s] including device list updates: %s",
|
||||||
|
transaction_id,
|
||||||
|
device_list_updates,
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
return 400, {"error": "Invalid transaction"}
|
return 400, {"error": "Invalid transaction"}
|
||||||
@@ -581,7 +608,7 @@ class FederationSpaceSummaryServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
@@ -655,7 +682,7 @@ class FederationRoomHierarchyServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
@@ -691,7 +718,7 @@ class RoomComplexityServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
from typing import Dict, List, Tuple, Type
|
from typing import TYPE_CHECKING, Dict, List, Tuple, Type
|
||||||
|
|
||||||
from synapse.api.errors import SynapseError
|
from synapse.api.errors import SynapseError
|
||||||
from synapse.federation.transport.server._base import (
|
from synapse.federation.transport.server._base import (
|
||||||
@@ -19,10 +19,12 @@ from synapse.federation.transport.server._base import (
|
|||||||
BaseFederationServlet,
|
BaseFederationServlet,
|
||||||
)
|
)
|
||||||
from synapse.handlers.groups_local import GroupsLocalHandler
|
from synapse.handlers.groups_local import GroupsLocalHandler
|
||||||
from synapse.server import HomeServer
|
|
||||||
from synapse.types import JsonDict, get_domain_from_id
|
from synapse.types import JsonDict, get_domain_from_id
|
||||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
|
|
||||||
class BaseGroupsLocalServlet(BaseFederationServlet):
|
class BaseGroupsLocalServlet(BaseFederationServlet):
|
||||||
"""Abstract base class for federation servlet classes which provides a groups local handler.
|
"""Abstract base class for federation servlet classes which provides a groups local handler.
|
||||||
@@ -32,7 +34,7 @@ class BaseGroupsLocalServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
from typing import Dict, List, Tuple, Type
|
from typing import TYPE_CHECKING, Dict, List, Tuple, Type
|
||||||
|
|
||||||
from typing_extensions import Literal
|
from typing_extensions import Literal
|
||||||
|
|
||||||
@@ -22,10 +22,12 @@ from synapse.federation.transport.server._base import (
|
|||||||
BaseFederationServlet,
|
BaseFederationServlet,
|
||||||
)
|
)
|
||||||
from synapse.http.servlet import parse_string_from_args
|
from synapse.http.servlet import parse_string_from_args
|
||||||
from synapse.server import HomeServer
|
|
||||||
from synapse.types import JsonDict, get_domain_from_id
|
from synapse.types import JsonDict, get_domain_from_id
|
||||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
|
|
||||||
class BaseGroupsServerServlet(BaseFederationServlet):
|
class BaseGroupsServerServlet(BaseFederationServlet):
|
||||||
"""Abstract base class for federation servlet classes which provides a groups server handler.
|
"""Abstract base class for federation servlet classes which provides a groups server handler.
|
||||||
@@ -35,7 +37,7 @@ class BaseGroupsServerServlet(BaseFederationServlet):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hs: HomeServer,
|
hs: "HomeServer",
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
ratelimiter: FederationRateLimiter,
|
ratelimiter: FederationRateLimiter,
|
||||||
server_name: str,
|
server_name: str,
|
||||||
|
|||||||
@@ -2060,6 +2060,10 @@ CHECK_AUTH_CALLBACK = Callable[
|
|||||||
Optional[Tuple[str, Optional[Callable[["LoginResponse"], Awaitable[None]]]]]
|
Optional[Tuple[str, Optional[Callable[["LoginResponse"], Awaitable[None]]]]]
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
|
GET_USERNAME_FOR_REGISTRATION_CALLBACK = Callable[
|
||||||
|
[JsonDict, JsonDict],
|
||||||
|
Awaitable[Optional[str]],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class PasswordAuthProvider:
|
class PasswordAuthProvider:
|
||||||
@@ -2072,6 +2076,9 @@ class PasswordAuthProvider:
|
|||||||
# lists of callbacks
|
# lists of callbacks
|
||||||
self.check_3pid_auth_callbacks: List[CHECK_3PID_AUTH_CALLBACK] = []
|
self.check_3pid_auth_callbacks: List[CHECK_3PID_AUTH_CALLBACK] = []
|
||||||
self.on_logged_out_callbacks: List[ON_LOGGED_OUT_CALLBACK] = []
|
self.on_logged_out_callbacks: List[ON_LOGGED_OUT_CALLBACK] = []
|
||||||
|
self.get_username_for_registration_callbacks: List[
|
||||||
|
GET_USERNAME_FOR_REGISTRATION_CALLBACK
|
||||||
|
] = []
|
||||||
|
|
||||||
# Mapping from login type to login parameters
|
# Mapping from login type to login parameters
|
||||||
self._supported_login_types: Dict[str, Iterable[str]] = {}
|
self._supported_login_types: Dict[str, Iterable[str]] = {}
|
||||||
@@ -2086,6 +2093,9 @@ class PasswordAuthProvider:
|
|||||||
auth_checkers: Optional[
|
auth_checkers: Optional[
|
||||||
Dict[Tuple[str, Tuple[str, ...]], CHECK_AUTH_CALLBACK]
|
Dict[Tuple[str, Tuple[str, ...]], CHECK_AUTH_CALLBACK]
|
||||||
] = None,
|
] = None,
|
||||||
|
get_username_for_registration: Optional[
|
||||||
|
GET_USERNAME_FOR_REGISTRATION_CALLBACK
|
||||||
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
# Register check_3pid_auth callback
|
# Register check_3pid_auth callback
|
||||||
if check_3pid_auth is not None:
|
if check_3pid_auth is not None:
|
||||||
@@ -2130,6 +2140,11 @@ class PasswordAuthProvider:
|
|||||||
# Add the new method to the list of auth_checker_callbacks for this login type
|
# Add the new method to the list of auth_checker_callbacks for this login type
|
||||||
self.auth_checker_callbacks.setdefault(login_type, []).append(callback)
|
self.auth_checker_callbacks.setdefault(login_type, []).append(callback)
|
||||||
|
|
||||||
|
if get_username_for_registration is not None:
|
||||||
|
self.get_username_for_registration_callbacks.append(
|
||||||
|
get_username_for_registration,
|
||||||
|
)
|
||||||
|
|
||||||
def get_supported_login_types(self) -> Mapping[str, Iterable[str]]:
|
def get_supported_login_types(self) -> Mapping[str, Iterable[str]]:
|
||||||
"""Get the login types supported by this password provider
|
"""Get the login types supported by this password provider
|
||||||
|
|
||||||
@@ -2281,7 +2296,50 @@ class PasswordAuthProvider:
|
|||||||
# call all of the on_logged_out callbacks
|
# call all of the on_logged_out callbacks
|
||||||
for callback in self.on_logged_out_callbacks:
|
for callback in self.on_logged_out_callbacks:
|
||||||
try:
|
try:
|
||||||
callback(user_id, device_id, access_token)
|
await callback(user_id, device_id, access_token)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("Failed to run module API callback %s: %s", callback, e)
|
logger.warning("Failed to run module API callback %s: %s", callback, e)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
async def get_username_for_registration(
|
||||||
|
self,
|
||||||
|
uia_results: JsonDict,
|
||||||
|
params: JsonDict,
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""Defines the username to use when registering the user, using the credentials
|
||||||
|
and parameters provided during the UIA flow.
|
||||||
|
|
||||||
|
Stops at the first callback that returns a string.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uia_results: The credentials provided during the UIA flow.
|
||||||
|
params: The parameters provided by the registration request.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The localpart to use when registering this user, or None if no module
|
||||||
|
returned a localpart.
|
||||||
|
"""
|
||||||
|
for callback in self.get_username_for_registration_callbacks:
|
||||||
|
try:
|
||||||
|
res = await callback(uia_results, params)
|
||||||
|
|
||||||
|
if isinstance(res, str):
|
||||||
|
return res
|
||||||
|
elif res is not None:
|
||||||
|
# mypy complains that this line is unreachable because it assumes the
|
||||||
|
# data returned by the module fits the expected type. We just want
|
||||||
|
# to make sure this is the case.
|
||||||
|
logger.warning( # type: ignore[unreachable]
|
||||||
|
"Ignoring non-string value returned by"
|
||||||
|
" get_username_for_registration callback %s: %s",
|
||||||
|
callback,
|
||||||
|
res,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(
|
||||||
|
"Module raised an exception in get_username_for_registration: %s",
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
raise SynapseError(code=500, msg="Internal Server Error")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|||||||
@@ -157,6 +157,9 @@ class DeactivateAccountHandler:
|
|||||||
# Mark the user as deactivated.
|
# Mark the user as deactivated.
|
||||||
await self.store.set_user_deactivated_status(user_id, True)
|
await self.store.set_user_deactivated_status(user_id, True)
|
||||||
|
|
||||||
|
# Remove account data (including ignored users and push rules).
|
||||||
|
await self.store.purge_account_data_for_user(user_id)
|
||||||
|
|
||||||
return identity_server_supports_unbinding
|
return identity_server_supports_unbinding
|
||||||
|
|
||||||
async def _reject_pending_invites_for_user(self, user_id: str) -> None:
|
async def _reject_pending_invites_for_user(self, user_id: str) -> None:
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ from synapse.types import (
|
|||||||
create_requester,
|
create_requester,
|
||||||
get_domain_from_id,
|
get_domain_from_id,
|
||||||
)
|
)
|
||||||
|
from synapse.util.caches.descriptors import cached
|
||||||
|
from synapse.util.stringutils import parse_and_validate_mxc_uri
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from synapse.server import HomeServer
|
from synapse.server import HomeServer
|
||||||
@@ -64,6 +66,11 @@ class ProfileHandler:
|
|||||||
self.user_directory_handler = hs.get_user_directory_handler()
|
self.user_directory_handler = hs.get_user_directory_handler()
|
||||||
self.request_ratelimiter = hs.get_request_ratelimiter()
|
self.request_ratelimiter = hs.get_request_ratelimiter()
|
||||||
|
|
||||||
|
self.max_avatar_size = hs.config.server.max_avatar_size
|
||||||
|
self.allowed_avatar_mimetypes = hs.config.server.allowed_avatar_mimetypes
|
||||||
|
|
||||||
|
self.server_name = hs.config.server.server_name
|
||||||
|
|
||||||
if hs.config.worker.run_background_tasks:
|
if hs.config.worker.run_background_tasks:
|
||||||
self.clock.looping_call(
|
self.clock.looping_call(
|
||||||
self._update_remote_profile_cache, self.PROFILE_UPDATE_MS
|
self._update_remote_profile_cache, self.PROFILE_UPDATE_MS
|
||||||
@@ -286,6 +293,9 @@ class ProfileHandler:
|
|||||||
400, "Avatar URL is too long (max %i)" % (MAX_AVATAR_URL_LEN,)
|
400, "Avatar URL is too long (max %i)" % (MAX_AVATAR_URL_LEN,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not await self.check_avatar_size_and_mime_type(new_avatar_url):
|
||||||
|
raise SynapseError(403, "This avatar is not allowed", Codes.FORBIDDEN)
|
||||||
|
|
||||||
avatar_url_to_set: Optional[str] = new_avatar_url
|
avatar_url_to_set: Optional[str] = new_avatar_url
|
||||||
if new_avatar_url == "":
|
if new_avatar_url == "":
|
||||||
avatar_url_to_set = None
|
avatar_url_to_set = None
|
||||||
@@ -307,6 +317,63 @@ class ProfileHandler:
|
|||||||
|
|
||||||
await self._update_join_states(requester, target_user)
|
await self._update_join_states(requester, target_user)
|
||||||
|
|
||||||
|
@cached()
|
||||||
|
async def check_avatar_size_and_mime_type(self, mxc: str) -> bool:
|
||||||
|
"""Check that the size and content type of the avatar at the given MXC URI are
|
||||||
|
within the configured limits.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mxc: The MXC URI at which the avatar can be found.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A boolean indicating whether the file can be allowed to be set as an avatar.
|
||||||
|
"""
|
||||||
|
if not self.max_avatar_size and not self.allowed_avatar_mimetypes:
|
||||||
|
return True
|
||||||
|
|
||||||
|
server_name, _, media_id = parse_and_validate_mxc_uri(mxc)
|
||||||
|
|
||||||
|
if server_name == self.server_name:
|
||||||
|
media_info = await self.store.get_local_media(media_id)
|
||||||
|
else:
|
||||||
|
media_info = await self.store.get_cached_remote_media(server_name, media_id)
|
||||||
|
|
||||||
|
if media_info is None:
|
||||||
|
# Both configuration options need to access the file's metadata, and
|
||||||
|
# retrieving remote avatars just for this becomes a bit of a faff, especially
|
||||||
|
# if e.g. the file is too big. It's also generally safe to assume most files
|
||||||
|
# used as avatar are uploaded locally, or if the upload didn't happen as part
|
||||||
|
# of a PUT request on /avatar_url that the file was at least previewed by the
|
||||||
|
# user locally (and therefore downloaded to the remote media cache).
|
||||||
|
logger.warning("Forbidding avatar change to %s: avatar not on server", mxc)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.max_avatar_size:
|
||||||
|
# Ensure avatar does not exceed max allowed avatar size
|
||||||
|
if media_info["media_length"] > self.max_avatar_size:
|
||||||
|
logger.warning(
|
||||||
|
"Forbidding avatar change to %s: %d bytes is above the allowed size "
|
||||||
|
"limit",
|
||||||
|
mxc,
|
||||||
|
media_info["media_length"],
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.allowed_avatar_mimetypes:
|
||||||
|
# Ensure the avatar's file type is allowed
|
||||||
|
if (
|
||||||
|
self.allowed_avatar_mimetypes
|
||||||
|
and media_info["media_type"] not in self.allowed_avatar_mimetypes
|
||||||
|
):
|
||||||
|
logger.warning(
|
||||||
|
"Forbidding avatar change to %s: mimetype %s not allowed",
|
||||||
|
mxc,
|
||||||
|
media_info["media_type"],
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
async def on_profile_query(self, args: JsonDict) -> JsonDict:
|
async def on_profile_query(self, args: JsonDict) -> JsonDict:
|
||||||
"""Handles federation profile query requests."""
|
"""Handles federation profile query requests."""
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ class RegistrationHandler:
|
|||||||
localpart: str,
|
localpart: str,
|
||||||
guest_access_token: Optional[str] = None,
|
guest_access_token: Optional[str] = None,
|
||||||
assigned_user_id: Optional[str] = None,
|
assigned_user_id: Optional[str] = None,
|
||||||
|
inhibit_user_in_use_error: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
if types.contains_invalid_mxid_characters(localpart):
|
if types.contains_invalid_mxid_characters(localpart):
|
||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
@@ -171,21 +172,22 @@ class RegistrationHandler:
|
|||||||
|
|
||||||
users = await self.store.get_users_by_id_case_insensitive(user_id)
|
users = await self.store.get_users_by_id_case_insensitive(user_id)
|
||||||
if users:
|
if users:
|
||||||
if not guest_access_token:
|
if not inhibit_user_in_use_error and not guest_access_token:
|
||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
400, "User ID already taken.", errcode=Codes.USER_IN_USE
|
400, "User ID already taken.", errcode=Codes.USER_IN_USE
|
||||||
)
|
)
|
||||||
user_data = await self.auth.get_user_by_access_token(guest_access_token)
|
if guest_access_token:
|
||||||
if (
|
user_data = await self.auth.get_user_by_access_token(guest_access_token)
|
||||||
not user_data.is_guest
|
if (
|
||||||
or UserID.from_string(user_data.user_id).localpart != localpart
|
not user_data.is_guest
|
||||||
):
|
or UserID.from_string(user_data.user_id).localpart != localpart
|
||||||
raise AuthError(
|
):
|
||||||
403,
|
raise AuthError(
|
||||||
"Cannot register taken user ID without valid guest "
|
403,
|
||||||
"credentials for that user.",
|
"Cannot register taken user ID without valid guest "
|
||||||
errcode=Codes.FORBIDDEN,
|
"credentials for that user.",
|
||||||
)
|
errcode=Codes.FORBIDDEN,
|
||||||
|
)
|
||||||
|
|
||||||
if guest_access_token is None:
|
if guest_access_token is None:
|
||||||
try:
|
try:
|
||||||
@@ -979,18 +981,16 @@ class RegistrationHandler:
|
|||||||
if (
|
if (
|
||||||
self.hs.config.email.email_enable_notifs
|
self.hs.config.email.email_enable_notifs
|
||||||
and self.hs.config.email.email_notif_for_new_users
|
and self.hs.config.email.email_notif_for_new_users
|
||||||
|
and token
|
||||||
):
|
):
|
||||||
# Pull the ID of the access token back out of the db
|
# Pull the ID of the access token back out of the db
|
||||||
# It would really make more sense for this to be passed
|
# It would really make more sense for this to be passed
|
||||||
# up when the access token is saved, but that's quite an
|
# up when the access token is saved, but that's quite an
|
||||||
# invasive change I'd rather do separately.
|
# invasive change I'd rather do separately.
|
||||||
if token:
|
user_tuple = await self.store.get_user_by_access_token(token)
|
||||||
user_tuple = await self.store.get_user_by_access_token(token)
|
# The token better still exist.
|
||||||
# The token better still exist.
|
assert user_tuple
|
||||||
assert user_tuple
|
token_id = user_tuple.token_id
|
||||||
token_id = user_tuple.token_id
|
|
||||||
else:
|
|
||||||
token_id = None
|
|
||||||
|
|
||||||
await self.pusher_pool.add_pusher(
|
await self.pusher_pool.add_pusher(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from typing import (
|
|||||||
Tuple,
|
Tuple,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import attr
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict
|
||||||
|
|
||||||
from synapse.api.constants import (
|
from synapse.api.constants import (
|
||||||
@@ -60,6 +61,7 @@ from synapse.events.utils import copy_power_levels_contents
|
|||||||
from synapse.federation.federation_client import InvalidResponseError
|
from synapse.federation.federation_client import InvalidResponseError
|
||||||
from synapse.handlers.federation import get_domains_from_state
|
from synapse.handlers.federation import get_domains_from_state
|
||||||
from synapse.rest.admin._base import assert_user_is_admin
|
from synapse.rest.admin._base import assert_user_is_admin
|
||||||
|
from synapse.storage.databases.main.relations import BundledAggregations
|
||||||
from synapse.storage.state import StateFilter
|
from synapse.storage.state import StateFilter
|
||||||
from synapse.streams import EventSource
|
from synapse.streams import EventSource
|
||||||
from synapse.types import (
|
from synapse.types import (
|
||||||
@@ -90,6 +92,17 @@ id_server_scheme = "https://"
|
|||||||
FIVE_MINUTES_IN_MS = 5 * 60 * 1000
|
FIVE_MINUTES_IN_MS = 5 * 60 * 1000
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s(slots=True, frozen=True, auto_attribs=True)
|
||||||
|
class EventContext:
|
||||||
|
events_before: List[EventBase]
|
||||||
|
event: EventBase
|
||||||
|
events_after: List[EventBase]
|
||||||
|
state: List[EventBase]
|
||||||
|
aggregations: Dict[str, BundledAggregations]
|
||||||
|
start: str
|
||||||
|
end: str
|
||||||
|
|
||||||
|
|
||||||
class RoomCreationHandler:
|
class RoomCreationHandler:
|
||||||
def __init__(self, hs: "HomeServer"):
|
def __init__(self, hs: "HomeServer"):
|
||||||
self.store = hs.get_datastore()
|
self.store = hs.get_datastore()
|
||||||
@@ -1119,7 +1132,7 @@ class RoomContextHandler:
|
|||||||
limit: int,
|
limit: int,
|
||||||
event_filter: Optional[Filter],
|
event_filter: Optional[Filter],
|
||||||
use_admin_priviledge: bool = False,
|
use_admin_priviledge: bool = False,
|
||||||
) -> Optional[JsonDict]:
|
) -> Optional[EventContext]:
|
||||||
"""Retrieves events, pagination tokens and state around a given event
|
"""Retrieves events, pagination tokens and state around a given event
|
||||||
in a room.
|
in a room.
|
||||||
|
|
||||||
@@ -1167,38 +1180,28 @@ class RoomContextHandler:
|
|||||||
results = await self.store.get_events_around(
|
results = await self.store.get_events_around(
|
||||||
room_id, event_id, before_limit, after_limit, event_filter
|
room_id, event_id, before_limit, after_limit, event_filter
|
||||||
)
|
)
|
||||||
|
events_before = results.events_before
|
||||||
|
events_after = results.events_after
|
||||||
|
|
||||||
if event_filter:
|
if event_filter:
|
||||||
results["events_before"] = await event_filter.filter(
|
events_before = await event_filter.filter(events_before)
|
||||||
results["events_before"]
|
events_after = await event_filter.filter(events_after)
|
||||||
)
|
|
||||||
results["events_after"] = await event_filter.filter(results["events_after"])
|
|
||||||
|
|
||||||
results["events_before"] = await filter_evts(results["events_before"])
|
events_before = await filter_evts(events_before)
|
||||||
results["events_after"] = await filter_evts(results["events_after"])
|
events_after = await filter_evts(events_after)
|
||||||
# filter_evts can return a pruned event in case the user is allowed to see that
|
# filter_evts can return a pruned event in case the user is allowed to see that
|
||||||
# there's something there but not see the content, so use the event that's in
|
# there's something there but not see the content, so use the event that's in
|
||||||
# `filtered` rather than the event we retrieved from the datastore.
|
# `filtered` rather than the event we retrieved from the datastore.
|
||||||
results["event"] = filtered[0]
|
event = filtered[0]
|
||||||
|
|
||||||
# Fetch the aggregations.
|
# Fetch the aggregations.
|
||||||
aggregations = await self.store.get_bundled_aggregations(
|
aggregations = await self.store.get_bundled_aggregations(
|
||||||
[results["event"]], user.to_string()
|
itertools.chain(events_before, (event,), events_after),
|
||||||
|
user.to_string(),
|
||||||
)
|
)
|
||||||
aggregations.update(
|
|
||||||
await self.store.get_bundled_aggregations(
|
|
||||||
results["events_before"], user.to_string()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
aggregations.update(
|
|
||||||
await self.store.get_bundled_aggregations(
|
|
||||||
results["events_after"], user.to_string()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
results["aggregations"] = aggregations
|
|
||||||
|
|
||||||
if results["events_after"]:
|
if events_after:
|
||||||
last_event_id = results["events_after"][-1].event_id
|
last_event_id = events_after[-1].event_id
|
||||||
else:
|
else:
|
||||||
last_event_id = event_id
|
last_event_id = event_id
|
||||||
|
|
||||||
@@ -1206,9 +1209,9 @@ class RoomContextHandler:
|
|||||||
state_filter = StateFilter.from_lazy_load_member_list(
|
state_filter = StateFilter.from_lazy_load_member_list(
|
||||||
ev.sender
|
ev.sender
|
||||||
for ev in itertools.chain(
|
for ev in itertools.chain(
|
||||||
results["events_before"],
|
events_before,
|
||||||
(results["event"],),
|
(event,),
|
||||||
results["events_after"],
|
events_after,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -1226,21 +1229,23 @@ class RoomContextHandler:
|
|||||||
if event_filter:
|
if event_filter:
|
||||||
state_events = await event_filter.filter(state_events)
|
state_events = await event_filter.filter(state_events)
|
||||||
|
|
||||||
results["state"] = await filter_evts(state_events)
|
|
||||||
|
|
||||||
# We use a dummy token here as we only care about the room portion of
|
# We use a dummy token here as we only care about the room portion of
|
||||||
# the token, which we replace.
|
# the token, which we replace.
|
||||||
token = StreamToken.START
|
token = StreamToken.START
|
||||||
|
|
||||||
results["start"] = await token.copy_and_replace(
|
return EventContext(
|
||||||
"room_key", results["start"]
|
events_before=events_before,
|
||||||
).to_string(self.store)
|
event=event,
|
||||||
|
events_after=events_after,
|
||||||
results["end"] = await token.copy_and_replace(
|
state=await filter_evts(state_events),
|
||||||
"room_key", results["end"]
|
aggregations=aggregations,
|
||||||
).to_string(self.store)
|
start=await token.copy_and_replace("room_key", results.start).to_string(
|
||||||
|
self.store
|
||||||
return results
|
),
|
||||||
|
end=await token.copy_and_replace("room_key", results.end).to_string(
|
||||||
|
self.store
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TimestampLookupHandler:
|
class TimestampLookupHandler:
|
||||||
|
|||||||
@@ -590,6 +590,12 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
|||||||
errcode=Codes.BAD_JSON,
|
errcode=Codes.BAD_JSON,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if "avatar_url" in content:
|
||||||
|
if not await self.profile_handler.check_avatar_size_and_mime_type(
|
||||||
|
content["avatar_url"],
|
||||||
|
):
|
||||||
|
raise SynapseError(403, "This avatar is not allowed", Codes.FORBIDDEN)
|
||||||
|
|
||||||
# The event content should *not* include the authorising user as
|
# The event content should *not* include the authorising user as
|
||||||
# it won't be properly signed. Strip it out since it might come
|
# it won't be properly signed. Strip it out since it might come
|
||||||
# back from a client updating a display name / avatar.
|
# back from a client updating a display name / avatar.
|
||||||
|
|||||||
@@ -780,6 +780,7 @@ class RoomSummaryHandler:
|
|||||||
try:
|
try:
|
||||||
(
|
(
|
||||||
room_response,
|
room_response,
|
||||||
|
children_state_events,
|
||||||
children,
|
children,
|
||||||
inaccessible_children,
|
inaccessible_children,
|
||||||
) = await self._federation_client.get_room_hierarchy(
|
) = await self._federation_client.get_room_hierarchy(
|
||||||
@@ -804,7 +805,7 @@ class RoomSummaryHandler:
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
_RoomEntry(room_id, room_response, room_response.pop("children_state", ())),
|
_RoomEntry(room_id, room_response, children_state_events),
|
||||||
children_by_room_id,
|
children_by_room_id,
|
||||||
set(inaccessible_children),
|
set(inaccessible_children),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -361,36 +361,37 @@ class SearchHandler:
|
|||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"Context for search returned %d and %d events",
|
"Context for search returned %d and %d events",
|
||||||
len(res["events_before"]),
|
len(res.events_before),
|
||||||
len(res["events_after"]),
|
len(res.events_after),
|
||||||
)
|
)
|
||||||
|
|
||||||
res["events_before"] = await filter_events_for_client(
|
events_before = await filter_events_for_client(
|
||||||
self.storage, user.to_string(), res["events_before"]
|
self.storage, user.to_string(), res.events_before
|
||||||
)
|
)
|
||||||
|
|
||||||
res["events_after"] = await filter_events_for_client(
|
events_after = await filter_events_for_client(
|
||||||
self.storage, user.to_string(), res["events_after"]
|
self.storage, user.to_string(), res.events_after
|
||||||
)
|
)
|
||||||
|
|
||||||
res["start"] = await now_token.copy_and_replace(
|
context = {
|
||||||
"room_key", res["start"]
|
"events_before": events_before,
|
||||||
).to_string(self.store)
|
"events_after": events_after,
|
||||||
|
"start": await now_token.copy_and_replace(
|
||||||
res["end"] = await now_token.copy_and_replace(
|
"room_key", res.start
|
||||||
"room_key", res["end"]
|
).to_string(self.store),
|
||||||
).to_string(self.store)
|
"end": await now_token.copy_and_replace(
|
||||||
|
"room_key", res.end
|
||||||
|
).to_string(self.store),
|
||||||
|
}
|
||||||
|
|
||||||
if include_profile:
|
if include_profile:
|
||||||
senders = {
|
senders = {
|
||||||
ev.sender
|
ev.sender
|
||||||
for ev in itertools.chain(
|
for ev in itertools.chain(events_before, [event], events_after)
|
||||||
res["events_before"], [event], res["events_after"]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if res["events_after"]:
|
if events_after:
|
||||||
last_event_id = res["events_after"][-1].event_id
|
last_event_id = events_after[-1].event_id
|
||||||
else:
|
else:
|
||||||
last_event_id = event.event_id
|
last_event_id = event.event_id
|
||||||
|
|
||||||
@@ -402,7 +403,7 @@ class SearchHandler:
|
|||||||
last_event_id, state_filter
|
last_event_id, state_filter
|
||||||
)
|
)
|
||||||
|
|
||||||
res["profile_info"] = {
|
context["profile_info"] = {
|
||||||
s.state_key: {
|
s.state_key: {
|
||||||
"displayname": s.content.get("displayname", None),
|
"displayname": s.content.get("displayname", None),
|
||||||
"avatar_url": s.content.get("avatar_url", None),
|
"avatar_url": s.content.get("avatar_url", None),
|
||||||
@@ -411,7 +412,7 @@ class SearchHandler:
|
|||||||
if s.type == EventTypes.Member and s.state_key in senders
|
if s.type == EventTypes.Member and s.state_key in senders
|
||||||
}
|
}
|
||||||
|
|
||||||
contexts[event.event_id] = res
|
contexts[event.event_id] = context
|
||||||
else:
|
else:
|
||||||
contexts = {}
|
contexts = {}
|
||||||
|
|
||||||
@@ -421,10 +422,10 @@ class SearchHandler:
|
|||||||
|
|
||||||
for context in contexts.values():
|
for context in contexts.values():
|
||||||
context["events_before"] = self._event_serializer.serialize_events(
|
context["events_before"] = self._event_serializer.serialize_events(
|
||||||
context["events_before"], time_now
|
context["events_before"], time_now # type: ignore[arg-type]
|
||||||
)
|
)
|
||||||
context["events_after"] = self._event_serializer.serialize_events(
|
context["events_after"] = self._event_serializer.serialize_events(
|
||||||
context["events_after"], time_now
|
context["events_after"], time_now # type: ignore[arg-type]
|
||||||
)
|
)
|
||||||
|
|
||||||
state_results = {}
|
state_results = {}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user