mirror of
https://github.com/element-hq/synapse
synced 2024-09-19 07:05:15 +00:00
Merge branch 'madlittlemods/11850-migrate-to-opentelemetry' into madlittlemods/13356-messages-investigation-scratch-v1
This commit is contained in:
commit
c3f3e59cca
28 changed files with 213 additions and 176 deletions
1
changelog.d/13230.doc
Normal file
1
changelog.d/13230.doc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add steps describing how to elevate an existing user to administrator by manipulating the database.
|
1
changelog.d/13368.misc
Normal file
1
changelog.d/13368.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Instrument `/messages` for understandable traces in Jaeger.
|
1
changelog.d/13372.docker
Normal file
1
changelog.d/13372.docker
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Make docker images build on armv7 by installing cryptography dependencies in the "requirements" stage. Contributed by Jasper Spaans.
|
1
changelog.d/13374.bugfix
Normal file
1
changelog.d/13374.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix a bug introduced in Synapse 0.24.0 that would respond with the wrong error status code to `/joined_members` requests when the requester is not a current member of the room. Contributed by @andrewdoh.
|
1
changelog.d/13428.feature
Normal file
1
changelog.d/13428.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add a module API method to translate a room alias into a room ID.
|
1
changelog.d/13437.doc
Normal file
1
changelog.d/13437.doc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix wrong headline for `url_preview_accept_language` in documentation.
|
1
changelog.d/13438.doc
Normal file
1
changelog.d/13438.doc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Remove redundant 'Contents' section from the Configuration Manual. Contributed by @dklimpel.
|
1
changelog.d/13439.misc
Normal file
1
changelog.d/13439.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add some tracing to give more insight into local room joins.
|
1
changelog.d/13442.misc
Normal file
1
changelog.d/13442.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Rename class `RateLimitConfig` to `RatelimitSettings` and `FederationRateLimitConfig` to `FederationRatelimitSettings`.
|
1
changelog.d/13443.doc
Normal file
1
changelog.d/13443.doc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Update documentation for config setting `macaroon_secret_key`.
|
|
@ -40,7 +40,8 @@ FROM docker.io/python:${PYTHON_VERSION}-slim as requirements
|
||||||
RUN \
|
RUN \
|
||||||
--mount=type=cache,target=/var/cache/apt,sharing=locked \
|
--mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||||
apt-get update -qq && apt-get install -yqq git \
|
apt-get update -qq && apt-get install -yqq \
|
||||||
|
build-essential cargo git libffi-dev libssl-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# We install poetry in its own build stage to avoid its dependencies conflicting with
|
# We install poetry in its own build stage to avoid its dependencies conflicting with
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
# OpenTracing
|
# Tracing
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
OpenTracing is a semi-standard being adopted by a number of distributed
|
OpenTelemetry is a semi-standard being adopted by a number of distributed
|
||||||
tracing platforms. It is a common api for facilitating vendor-agnostic
|
tracing platforms. It is a common API for facilitating vendor-agnostic
|
||||||
tracing instrumentation. That is, we can use the OpenTracing api and
|
tracing instrumentation.
|
||||||
select one of a number of tracer implementations to do the heavy lifting
|
|
||||||
in the background. Our current selected implementation is Jaeger.
|
|
||||||
|
|
||||||
OpenTracing is a tool which gives an insight into the causal
|
Tracing is a tool which gives an insight into the causal
|
||||||
relationship of work done in and between servers. The servers each track
|
relationship of work done in and between servers. The servers each track
|
||||||
events and report them to a centralised server - in Synapse's case:
|
events and report them to a centralised server - in Synapse's case:
|
||||||
Jaeger. The basic unit used to represent events is the span. The span
|
Jaeger. The basic unit used to represent events is the span. The span
|
||||||
|
@ -22,7 +20,7 @@ finish.
|
||||||
Since this is undertaken in a distributed environment a request to
|
Since this is undertaken in a distributed environment a request to
|
||||||
another server, such as an RPC or a simple GET, can be considered a span
|
another server, such as an RPC or a simple GET, can be considered a span
|
||||||
(a unit or work) for the local server. This causal link is what
|
(a unit or work) for the local server. This causal link is what
|
||||||
OpenTracing aims to capture and visualise. In order to do this metadata
|
tracing aims to capture and visualise. In order to do this metadata
|
||||||
about the local server's span, i.e the 'span context', needs to be
|
about the local server's span, i.e the 'span context', needs to be
|
||||||
included with the request to the remote.
|
included with the request to the remote.
|
||||||
|
|
||||||
|
@ -30,15 +28,18 @@ It is up to the remote server to decide what it does with the spans it
|
||||||
creates. This is called the sampling policy and it can be configured
|
creates. This is called the sampling policy and it can be configured
|
||||||
through Jaeger's settings.
|
through Jaeger's settings.
|
||||||
|
|
||||||
For OpenTracing concepts see
|
For OpenTelemetry concepts, see
|
||||||
<https://opentracing.io/docs/overview/what-is-tracing/>.
|
<https://opentelemetry.io/docs/concepts/>.
|
||||||
|
|
||||||
For more information about Jaeger's implementation see
|
For more information about the Python implementation of OpenTelemetry we're using, see
|
||||||
|
<https://opentelemetry.io/docs/instrumentation/python/>
|
||||||
|
|
||||||
|
For more information about Jaeger, see
|
||||||
<https://www.jaegertracing.io/docs/>
|
<https://www.jaegertracing.io/docs/>
|
||||||
|
|
||||||
## Setting up OpenTracing
|
## Setting up tracing
|
||||||
|
|
||||||
To receive OpenTracing spans, start up a Jaeger server. This can be done
|
To receive tracing spans, start up a Jaeger server. This can be done
|
||||||
using docker like so:
|
using docker like so:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
@ -54,15 +55,15 @@ docker run -d --name jaeger \
|
||||||
Latest documentation is probably at
|
Latest documentation is probably at
|
||||||
https://www.jaegertracing.io/docs/latest/getting-started.
|
https://www.jaegertracing.io/docs/latest/getting-started.
|
||||||
|
|
||||||
## Enable OpenTracing in Synapse
|
## Enable tracing in Synapse
|
||||||
|
|
||||||
OpenTracing is not enabled by default. It must be enabled in the
|
Tracing is not enabled by default. It must be enabled in the
|
||||||
homeserver config by adding the `opentracing` option to your config file. You can find
|
homeserver config by adding the `tracing` option to your config file. You can find
|
||||||
documentation about how to do this in the [config manual under the header 'Opentracing'](usage/configuration/config_documentation.md#opentracing).
|
documentation about how to do this in the [config manual under the header 'Tracing'](usage/configuration/config_documentation.md#tracing).
|
||||||
See below for an example Opentracing configuration:
|
See below for an example tracing configuration:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
opentracing:
|
tracing:
|
||||||
enabled: true
|
enabled: true
|
||||||
homeserver_whitelist:
|
homeserver_whitelist:
|
||||||
- "mytrustedhomeserver.org"
|
- "mytrustedhomeserver.org"
|
||||||
|
@ -86,9 +87,4 @@ to two problems, namely:
|
||||||
- Sending servers can attach arbitrary data to spans, known as
|
- Sending servers can attach arbitrary data to spans, known as
|
||||||
'baggage'. For safety this has been disabled in Synapse but that
|
'baggage'. For safety this has been disabled in Synapse but that
|
||||||
doesn't prevent another server sending you baggage which will be
|
doesn't prevent another server sending you baggage which will be
|
||||||
logged to OpenTracing's logs.
|
logged in the trace.
|
||||||
|
|
||||||
## Configuring Jaeger
|
|
||||||
|
|
||||||
Sampling strategies can be set as in this document:
|
|
||||||
<https://www.jaegertracing.io/docs/latest/sampling/>.
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
Many of the API calls in the admin api will require an `access_token` for a
|
Many of the API calls in the admin api will require an `access_token` for a
|
||||||
server admin. (Note that a server admin is distinct from a room admin.)
|
server admin. (Note that a server admin is distinct from a room admin.)
|
||||||
|
|
||||||
A user can be marked as a server admin by updating the database directly, e.g.:
|
An existing user can be marked as a server admin by updating the database directly.
|
||||||
|
|
||||||
|
Check your [database settings](config_documentation.md#database) in the configuration file, connect to the correct database using either `psql [database name]` (if using PostgreSQL) or `sqlite3 path/to/your/database.db` (if using SQLite) and elevate the user `@foo:bar.com` to administrator.
|
||||||
```sql
|
```sql
|
||||||
UPDATE users SET admin = 1 WHERE name = '@foo:bar.com';
|
UPDATE users SET admin = 1 WHERE name = '@foo:bar.com';
|
||||||
```
|
```
|
||||||
|
|
|
@ -72,48 +72,6 @@ apply if you want your config file to be read properly. A few helpful things to
|
||||||
In addition, each setting has an example of its usage, with the proper indentation
|
In addition, each setting has an example of its usage, with the proper indentation
|
||||||
shown.
|
shown.
|
||||||
|
|
||||||
## Contents
|
|
||||||
[Modules](#modules)
|
|
||||||
|
|
||||||
[Server](#server)
|
|
||||||
|
|
||||||
[Homeserver Blocking](#homeserver-blocking)
|
|
||||||
|
|
||||||
[TLS](#tls)
|
|
||||||
|
|
||||||
[Federation](#federation)
|
|
||||||
|
|
||||||
[Caching](#caching)
|
|
||||||
|
|
||||||
[Database](#database)
|
|
||||||
|
|
||||||
[Logging](#logging)
|
|
||||||
|
|
||||||
[Ratelimiting](#ratelimiting)
|
|
||||||
|
|
||||||
[Media Store](#media-store)
|
|
||||||
|
|
||||||
[Captcha](#captcha)
|
|
||||||
|
|
||||||
[TURN](#turn)
|
|
||||||
|
|
||||||
[Registration](#registration)
|
|
||||||
|
|
||||||
[API Configuration](#api-configuration)
|
|
||||||
|
|
||||||
[Signing Keys](#signing-keys)
|
|
||||||
|
|
||||||
[Single Sign On Integration](#single-sign-on-integration)
|
|
||||||
|
|
||||||
[Push](#push)
|
|
||||||
|
|
||||||
[Rooms](#rooms)
|
|
||||||
|
|
||||||
[Tracing](#tracing)
|
|
||||||
|
|
||||||
[Workers](#workers)
|
|
||||||
|
|
||||||
[Background Updates](#background-updates)
|
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
|
@ -1859,7 +1817,7 @@ Example configuration:
|
||||||
max_spider_size: 8M
|
max_spider_size: 8M
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
### `url_preview_language`
|
### `url_preview_accept_language`
|
||||||
|
|
||||||
A list of values for the Accept-Language HTTP header used when
|
A list of values for the Accept-Language HTTP header used when
|
||||||
downloading webpages during URL preview generation. This allows
|
downloading webpages during URL preview generation. This allows
|
||||||
|
@ -2538,9 +2496,13 @@ track_appservice_user_ips: true
|
||||||
---
|
---
|
||||||
### `macaroon_secret_key`
|
### `macaroon_secret_key`
|
||||||
|
|
||||||
A secret which is used to sign access tokens. If none is specified,
|
A secret which is used to sign
|
||||||
the `registration_shared_secret` is used, if one is given; otherwise,
|
- access token for guest users,
|
||||||
a secret key is derived from the signing key.
|
- short-term login token used during SSO logins (OIDC or SAML2) and
|
||||||
|
- token used for unsubscribing from email notifications.
|
||||||
|
|
||||||
|
If none is specified, the `registration_shared_secret` is used, if one is given;
|
||||||
|
otherwise, a secret key is derived from the signing key.
|
||||||
|
|
||||||
Example configuration:
|
Example configuration:
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -3578,7 +3540,7 @@ OpenTelemetry.
|
||||||
Sub-options include:
|
Sub-options include:
|
||||||
* `enabled`: whether tracing is enabled. Set to true to enable. Disabled by default.
|
* `enabled`: whether tracing is enabled. Set to true to enable. Disabled by default.
|
||||||
* `homeserver_whitelist`: The list of homeservers we wish to send and receive span contexts and span baggage.
|
* `homeserver_whitelist`: The list of homeservers we wish to send and receive span contexts and span baggage.
|
||||||
See [here](../../tracing.md) for more.
|
See [here](../../tracing.md#homeserver-whitelisting) for more.
|
||||||
This is a list of regexes which are matched against the `server_name` of the homeserver.
|
This is a list of regexes which are matched against the `server_name` of the homeserver.
|
||||||
By default, it is empty, so no servers are matched.
|
By default, it is empty, so no servers are matched.
|
||||||
* `sample_rate`: The probability that a given span and subsequent child spans in the trace will be
|
* `sample_rate`: The probability that a given span and subsequent child spans in the trace will be
|
||||||
|
|
61
poetry.lock
generated
61
poetry.lock
generated
|
@ -1267,22 +1267,17 @@ telegram = ["requests"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "treq"
|
name = "treq"
|
||||||
version = "22.2.0"
|
version = "15.1.0"
|
||||||
description = "High-level Twisted HTTP Client API"
|
description = "A requests-like API built on top of twisted.web's Agent"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = "*"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
attrs = "*"
|
pyOpenSSL = {version = ">=0.15.1", markers = "python_version > \"3.0\""}
|
||||||
hyperlink = ">=21.0.0"
|
|
||||||
incremental = "*"
|
|
||||||
requests = ">=2.1.0"
|
requests = ">=2.1.0"
|
||||||
Twisted = {version = ">=18.7.0", extras = ["tls"]}
|
service_identity = ">=14.0.0"
|
||||||
|
Twisted = {version = ">=15.5.0", markers = "python_version > \"3.0\""}
|
||||||
[package.extras]
|
|
||||||
dev = ["pep8", "pyflakes", "httpbin (==0.5.0)"]
|
|
||||||
docs = ["sphinx (>=1.4.8)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "twine"
|
name = "twine"
|
||||||
|
@ -1305,41 +1300,46 @@ tqdm = ">=4.14"
|
||||||
urllib3 = ">=1.26.0"
|
urllib3 = ">=1.26.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "twisted"
|
name = "Twisted"
|
||||||
version = "22.4.0"
|
version = "22.4.0.post0"
|
||||||
description = "An asynchronous networking framework written in Python"
|
description = "An asynchronous networking framework written in Python"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6.7"
|
python-versions = ">=3.7.1"
|
||||||
|
develop = false
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
attrs = ">=19.2.0"
|
attrs = ">=19.2.0"
|
||||||
Automat = ">=0.8.0"
|
Automat = ">=0.8.0"
|
||||||
constantly = ">=15.1"
|
constantly = ">=15.1"
|
||||||
hyperlink = ">=17.1.1"
|
hyperlink = ">=17.1.1"
|
||||||
idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""}
|
|
||||||
incremental = ">=21.3.0"
|
incremental = ">=21.3.0"
|
||||||
pyopenssl = {version = ">=16.0.0", optional = true, markers = "extra == \"tls\""}
|
|
||||||
service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""}
|
|
||||||
twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""}
|
twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""}
|
||||||
typing-extensions = ">=3.6.5"
|
typing-extensions = ">=3.6.5"
|
||||||
"zope.interface" = ">=4.4.2"
|
"zope.interface" = ">=4.4.2"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
all_non_platform = ["cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=16.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
all_non_platform = ["cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
||||||
conch = ["pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)"]
|
conch = ["pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)"]
|
||||||
conch_nacl = ["pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pynacl"]
|
conch_nacl = ["pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pynacl"]
|
||||||
contextvars = ["contextvars (>=2.4,<3)"]
|
contextvars = ["contextvars (>=2.4,<3)"]
|
||||||
dev = ["towncrier (>=19.2,<20.0)", "sphinx-rtd-theme (>=0.5,<1.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=4.1.2,<6)", "pyflakes (>=2.2,<3.0)", "twistedchecker (>=0.7,<1.0)", "coverage (>=6b1,<7)", "python-subunit (>=1.4,<2.0)", "pydoctor (>=21.9.0,<21.10.0)"]
|
dev = ["towncrier (>=19.2,<20.0)", "pydoctor (>=22.7.0,<22.8.0)", "sphinx-rtd-theme (>=0.5,<1.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=4.1.2,<6)", "pyflakes (>=2.2,<3.0)", "twistedchecker (>=0.7,<1.0)", "coverage (>=6b1,<7)", "python-subunit (>=1.4,<2.0)"]
|
||||||
dev_release = ["towncrier (>=19.2,<20.0)", "sphinx-rtd-theme (>=0.5,<1.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=4.1.2,<6)", "pydoctor (>=21.9.0,<21.10.0)"]
|
dev_release = ["towncrier (>=19.2,<20.0)", "pydoctor (>=22.7.0,<22.8.0)", "sphinx-rtd-theme (>=0.5,<1.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=4.1.2,<6)"]
|
||||||
|
gtk_platform = ["pygobject", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
||||||
http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"]
|
http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"]
|
||||||
macos_platform = ["pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=16.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
macos_platform = ["pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
||||||
mypy = ["mypy (==0.930)", "mypy-zope (==0.3.4)", "types-setuptools", "types-pyopenssl", "towncrier (>=19.2,<20.0)", "sphinx-rtd-theme (>=0.5,<1.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=4.1.2,<6)", "pyflakes (>=2.2,<3.0)", "twistedchecker (>=0.7,<1.0)", "coverage (>=6b1,<7)", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=16.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pynacl", "pywin32 (!=226)", "python-subunit (>=1.4,<2.0)", "contextvars (>=2.4,<3)", "pydoctor (>=21.9.0,<21.10.0)"]
|
mypy = ["mypy (==0.930)", "mypy-zope (==0.3.4)", "types-setuptools", "types-pyopenssl", "towncrier (>=19.2,<20.0)", "pydoctor (>=22.7.0,<22.8.0)", "sphinx-rtd-theme (>=0.5,<1.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=4.1.2,<6)", "pyflakes (>=2.2,<3.0)", "twistedchecker (>=0.7,<1.0)", "coverage (>=6b1,<7)", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pynacl", "pywin32 (!=226)", "python-subunit (>=1.4,<2.0)", "contextvars (>=2.4,<3)"]
|
||||||
osx_platform = ["pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=16.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
osx_platform = ["pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
||||||
serial = ["pyserial (>=3.0)", "pywin32 (!=226)"]
|
serial = ["pyserial (>=3.0)", "pywin32 (!=226)"]
|
||||||
test = ["cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)"]
|
test = ["cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)"]
|
||||||
tls = ["pyopenssl (>=16.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)"]
|
tls = ["pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)"]
|
||||||
windows_platform = ["pywin32 (!=226)", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=16.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
windows_platform = ["pywin32 (!=226)", "cython-test-exception-raiser (>=1.0.2,<2)", "PyHamcrest (>=1.9.0)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)", "idna (>=2.4)", "pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pyserial (>=3.0)", "h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)", "pywin32 (!=226)", "contextvars (>=2.4,<3)"]
|
||||||
|
|
||||||
|
[package.source]
|
||||||
|
type = "git"
|
||||||
|
url = "https://github.com/twisted/twisted.git"
|
||||||
|
reference = "trunk"
|
||||||
|
resolved_reference = "ff2ea6181f7ca4887adbaf4158b2fe0891e17ef9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "twisted-iocpsupport"
|
name = "twisted-iocpsupport"
|
||||||
|
@ -1615,7 +1615,7 @@ url_preview = ["lxml"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.7.1"
|
python-versions = "^3.7.1"
|
||||||
content-hash = "06a9f9259d4aa587a48242adf571bbd1132eda149226c1d2819a8b7a05c7ce5c"
|
content-hash = "c2cfbb348a49e088c404148c1b682fc5af5abb6278cf4479c6a51fff1656328c"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
attrs = [
|
attrs = [
|
||||||
|
@ -2642,17 +2642,14 @@ tqdm = [
|
||||||
{file = "tqdm-4.63.0.tar.gz", hash = "sha256:1d9835ede8e394bb8c9dcbffbca02d717217113adc679236873eeaac5bc0b3cd"},
|
{file = "tqdm-4.63.0.tar.gz", hash = "sha256:1d9835ede8e394bb8c9dcbffbca02d717217113adc679236873eeaac5bc0b3cd"},
|
||||||
]
|
]
|
||||||
treq = [
|
treq = [
|
||||||
{file = "treq-22.2.0-py3-none-any.whl", hash = "sha256:27d95b07c5c14be3e7b280416139b036087617ad5595be913b1f9b3ce981b9b2"},
|
{file = "treq-15.1.0-py2.py3-none-any.whl", hash = "sha256:1ad1ba89ddc62ae877084b290bd327755b13f6e7bc7076dc4d8e2efb701bfd63"},
|
||||||
{file = "treq-22.2.0.tar.gz", hash = "sha256:df757e3f141fc782ede076a604521194ffcb40fa2645cf48e5a37060307f52ec"},
|
{file = "treq-15.1.0.tar.gz", hash = "sha256:425a47d5d52a993d51211028fb6ade252e5fbea094e878bb4b644096a7322de8"},
|
||||||
]
|
]
|
||||||
twine = [
|
twine = [
|
||||||
{file = "twine-3.8.0-py3-none-any.whl", hash = "sha256:d0550fca9dc19f3d5e8eadfce0c227294df0a2a951251a4385797c8a6198b7c8"},
|
{file = "twine-3.8.0-py3-none-any.whl", hash = "sha256:d0550fca9dc19f3d5e8eadfce0c227294df0a2a951251a4385797c8a6198b7c8"},
|
||||||
{file = "twine-3.8.0.tar.gz", hash = "sha256:8efa52658e0ae770686a13b675569328f1fba9837e5de1867bfe5f46a9aefe19"},
|
{file = "twine-3.8.0.tar.gz", hash = "sha256:8efa52658e0ae770686a13b675569328f1fba9837e5de1867bfe5f46a9aefe19"},
|
||||||
]
|
]
|
||||||
twisted = [
|
Twisted = []
|
||||||
{file = "Twisted-22.4.0-py3-none-any.whl", hash = "sha256:f9f7a91f94932477a9fc3b169d57f54f96c6e74a23d78d9ce54039a7f48928a2"},
|
|
||||||
{file = "Twisted-22.4.0.tar.gz", hash = "sha256:a047990f57dfae1e0bd2b7df2526d4f16dcdc843774dc108b78c52f2a5f13680"},
|
|
||||||
]
|
|
||||||
twisted-iocpsupport = [
|
twisted-iocpsupport = [
|
||||||
{file = "twisted-iocpsupport-1.0.2.tar.gz", hash = "sha256:72068b206ee809c9c596b57b5287259ea41ddb4774d86725b19f35bf56aa32a9"},
|
{file = "twisted-iocpsupport-1.0.2.tar.gz", hash = "sha256:72068b206ee809c9c596b57b5287259ea41ddb4774d86725b19f35bf56aa32a9"},
|
||||||
{file = "twisted_iocpsupport-1.0.2-cp310-cp310-win32.whl", hash = "sha256:985c06a33f5c0dae92c71a036d1ea63872ee86a21dd9b01e1f287486f15524b4"},
|
{file = "twisted_iocpsupport-1.0.2-cp310-cp310-win32.whl", hash = "sha256:985c06a33f5c0dae92c71a036d1ea63872ee86a21dd9b01e1f287486f15524b4"},
|
||||||
|
|
|
@ -119,7 +119,6 @@ signedjson = "^1.1.0"
|
||||||
service-identity = ">=18.1.0"
|
service-identity = ">=18.1.0"
|
||||||
# Twisted 18.9 introduces some logger improvements that the structured
|
# Twisted 18.9 introduces some logger improvements that the structured
|
||||||
# logger utilises
|
# logger utilises
|
||||||
Twisted = {extras = ["tls"], version = ">=18.9.0"}
|
|
||||||
treq = ">=15.1"
|
treq = ">=15.1"
|
||||||
# Twisted has required pyopenssl 16.0 since about Twisted 16.6.
|
# Twisted has required pyopenssl 16.0 since about Twisted 16.6.
|
||||||
pyOpenSSL = ">=16.0.0"
|
pyOpenSSL = ">=16.0.0"
|
||||||
|
@ -183,6 +182,7 @@ idna = { version = ">=2.5", optional = true }
|
||||||
opentelemetry-api = {version = "^1.11.1", optional = true}
|
opentelemetry-api = {version = "^1.11.1", optional = true}
|
||||||
opentelemetry-sdk = {version = "^1.11.1", optional = true}
|
opentelemetry-sdk = {version = "^1.11.1", optional = true}
|
||||||
opentelemetry-exporter-jaeger = {version = "^1.11.1", optional = true}
|
opentelemetry-exporter-jaeger = {version = "^1.11.1", optional = true}
|
||||||
|
twisted = {git = "https://github.com/twisted/twisted.git", rev = "trunk"}
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
# NB: Packages that should be part of `pip install matrix-synapse[all]` need to be specified
|
# NB: Packages that should be part of `pip install matrix-synapse[all]` need to be specified
|
||||||
|
|
|
@ -17,7 +17,7 @@ from collections import OrderedDict
|
||||||
from typing import Hashable, Optional, Tuple
|
from typing import Hashable, Optional, Tuple
|
||||||
|
|
||||||
from synapse.api.errors import LimitExceededError
|
from synapse.api.errors import LimitExceededError
|
||||||
from synapse.config.ratelimiting import RateLimitConfig
|
from synapse.config.ratelimiting import RatelimitSettings
|
||||||
from synapse.storage.databases.main import DataStore
|
from synapse.storage.databases.main import DataStore
|
||||||
from synapse.types import Requester
|
from synapse.types import Requester
|
||||||
from synapse.util import Clock
|
from synapse.util import Clock
|
||||||
|
@ -314,8 +314,8 @@ class RequestRatelimiter:
|
||||||
self,
|
self,
|
||||||
store: DataStore,
|
store: DataStore,
|
||||||
clock: Clock,
|
clock: Clock,
|
||||||
rc_message: RateLimitConfig,
|
rc_message: RatelimitSettings,
|
||||||
rc_admin_redaction: Optional[RateLimitConfig],
|
rc_admin_redaction: Optional[RatelimitSettings],
|
||||||
):
|
):
|
||||||
self.store = store
|
self.store = store
|
||||||
self.clock = clock
|
self.clock = clock
|
||||||
|
|
|
@ -21,7 +21,7 @@ from synapse.types import JsonDict
|
||||||
from ._base import Config
|
from ._base import Config
|
||||||
|
|
||||||
|
|
||||||
class RateLimitConfig:
|
class RatelimitSettings:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
config: Dict[str, float],
|
config: Dict[str, float],
|
||||||
|
@ -34,7 +34,7 @@ class RateLimitConfig:
|
||||||
|
|
||||||
|
|
||||||
@attr.s(auto_attribs=True)
|
@attr.s(auto_attribs=True)
|
||||||
class FederationRateLimitConfig:
|
class FederationRatelimitSettings:
|
||||||
window_size: int = 1000
|
window_size: int = 1000
|
||||||
sleep_limit: int = 10
|
sleep_limit: int = 10
|
||||||
sleep_delay: int = 500
|
sleep_delay: int = 500
|
||||||
|
@ -50,11 +50,11 @@ class RatelimitConfig(Config):
|
||||||
# Load the new-style messages config if it exists. Otherwise fall back
|
# Load the new-style messages config if it exists. Otherwise fall back
|
||||||
# to the old method.
|
# to the old method.
|
||||||
if "rc_message" in config:
|
if "rc_message" in config:
|
||||||
self.rc_message = RateLimitConfig(
|
self.rc_message = RatelimitSettings(
|
||||||
config["rc_message"], defaults={"per_second": 0.2, "burst_count": 10.0}
|
config["rc_message"], defaults={"per_second": 0.2, "burst_count": 10.0}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.rc_message = RateLimitConfig(
|
self.rc_message = RatelimitSettings(
|
||||||
{
|
{
|
||||||
"per_second": config.get("rc_messages_per_second", 0.2),
|
"per_second": config.get("rc_messages_per_second", 0.2),
|
||||||
"burst_count": config.get("rc_message_burst_count", 10.0),
|
"burst_count": config.get("rc_message_burst_count", 10.0),
|
||||||
|
@ -64,9 +64,9 @@ class RatelimitConfig(Config):
|
||||||
# Load the new-style federation config, if it exists. Otherwise, fall
|
# Load the new-style federation config, if it exists. Otherwise, fall
|
||||||
# back to the old method.
|
# back to the old method.
|
||||||
if "rc_federation" in config:
|
if "rc_federation" in config:
|
||||||
self.rc_federation = FederationRateLimitConfig(**config["rc_federation"])
|
self.rc_federation = FederationRatelimitSettings(**config["rc_federation"])
|
||||||
else:
|
else:
|
||||||
self.rc_federation = FederationRateLimitConfig(
|
self.rc_federation = FederationRatelimitSettings(
|
||||||
**{
|
**{
|
||||||
k: v
|
k: v
|
||||||
for k, v in {
|
for k, v in {
|
||||||
|
@ -80,17 +80,17 @@ class RatelimitConfig(Config):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.rc_registration = RateLimitConfig(config.get("rc_registration", {}))
|
self.rc_registration = RatelimitSettings(config.get("rc_registration", {}))
|
||||||
|
|
||||||
self.rc_registration_token_validity = RateLimitConfig(
|
self.rc_registration_token_validity = RatelimitSettings(
|
||||||
config.get("rc_registration_token_validity", {}),
|
config.get("rc_registration_token_validity", {}),
|
||||||
defaults={"per_second": 0.1, "burst_count": 5},
|
defaults={"per_second": 0.1, "burst_count": 5},
|
||||||
)
|
)
|
||||||
|
|
||||||
rc_login_config = config.get("rc_login", {})
|
rc_login_config = config.get("rc_login", {})
|
||||||
self.rc_login_address = RateLimitConfig(rc_login_config.get("address", {}))
|
self.rc_login_address = RatelimitSettings(rc_login_config.get("address", {}))
|
||||||
self.rc_login_account = RateLimitConfig(rc_login_config.get("account", {}))
|
self.rc_login_account = RatelimitSettings(rc_login_config.get("account", {}))
|
||||||
self.rc_login_failed_attempts = RateLimitConfig(
|
self.rc_login_failed_attempts = RatelimitSettings(
|
||||||
rc_login_config.get("failed_attempts", {})
|
rc_login_config.get("failed_attempts", {})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -101,20 +101,20 @@ class RatelimitConfig(Config):
|
||||||
rc_admin_redaction = config.get("rc_admin_redaction")
|
rc_admin_redaction = config.get("rc_admin_redaction")
|
||||||
self.rc_admin_redaction = None
|
self.rc_admin_redaction = None
|
||||||
if rc_admin_redaction:
|
if rc_admin_redaction:
|
||||||
self.rc_admin_redaction = RateLimitConfig(rc_admin_redaction)
|
self.rc_admin_redaction = RatelimitSettings(rc_admin_redaction)
|
||||||
|
|
||||||
self.rc_joins_local = RateLimitConfig(
|
self.rc_joins_local = RatelimitSettings(
|
||||||
config.get("rc_joins", {}).get("local", {}),
|
config.get("rc_joins", {}).get("local", {}),
|
||||||
defaults={"per_second": 0.1, "burst_count": 10},
|
defaults={"per_second": 0.1, "burst_count": 10},
|
||||||
)
|
)
|
||||||
self.rc_joins_remote = RateLimitConfig(
|
self.rc_joins_remote = RatelimitSettings(
|
||||||
config.get("rc_joins", {}).get("remote", {}),
|
config.get("rc_joins", {}).get("remote", {}),
|
||||||
defaults={"per_second": 0.01, "burst_count": 10},
|
defaults={"per_second": 0.01, "burst_count": 10},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Track the rate of joins to a given room. If there are too many, temporarily
|
# Track the rate of joins to a given room. If there are too many, temporarily
|
||||||
# prevent local joins and remote joins via this server.
|
# prevent local joins and remote joins via this server.
|
||||||
self.rc_joins_per_room = RateLimitConfig(
|
self.rc_joins_per_room = RatelimitSettings(
|
||||||
config.get("rc_joins_per_room", {}),
|
config.get("rc_joins_per_room", {}),
|
||||||
defaults={"per_second": 1, "burst_count": 10},
|
defaults={"per_second": 1, "burst_count": 10},
|
||||||
)
|
)
|
||||||
|
@ -124,31 +124,31 @@ class RatelimitConfig(Config):
|
||||||
# * For requests received over federation this is keyed by the origin.
|
# * For requests received over federation this is keyed by the origin.
|
||||||
#
|
#
|
||||||
# Note that this isn't exposed in the configuration as it is obscure.
|
# Note that this isn't exposed in the configuration as it is obscure.
|
||||||
self.rc_key_requests = RateLimitConfig(
|
self.rc_key_requests = RatelimitSettings(
|
||||||
config.get("rc_key_requests", {}),
|
config.get("rc_key_requests", {}),
|
||||||
defaults={"per_second": 20, "burst_count": 100},
|
defaults={"per_second": 20, "burst_count": 100},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.rc_3pid_validation = RateLimitConfig(
|
self.rc_3pid_validation = RatelimitSettings(
|
||||||
config.get("rc_3pid_validation") or {},
|
config.get("rc_3pid_validation") or {},
|
||||||
defaults={"per_second": 0.003, "burst_count": 5},
|
defaults={"per_second": 0.003, "burst_count": 5},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.rc_invites_per_room = RateLimitConfig(
|
self.rc_invites_per_room = RatelimitSettings(
|
||||||
config.get("rc_invites", {}).get("per_room", {}),
|
config.get("rc_invites", {}).get("per_room", {}),
|
||||||
defaults={"per_second": 0.3, "burst_count": 10},
|
defaults={"per_second": 0.3, "burst_count": 10},
|
||||||
)
|
)
|
||||||
self.rc_invites_per_user = RateLimitConfig(
|
self.rc_invites_per_user = RatelimitSettings(
|
||||||
config.get("rc_invites", {}).get("per_user", {}),
|
config.get("rc_invites", {}).get("per_user", {}),
|
||||||
defaults={"per_second": 0.003, "burst_count": 5},
|
defaults={"per_second": 0.003, "burst_count": 5},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.rc_invites_per_issuer = RateLimitConfig(
|
self.rc_invites_per_issuer = RatelimitSettings(
|
||||||
config.get("rc_invites", {}).get("per_issuer", {}),
|
config.get("rc_invites", {}).get("per_issuer", {}),
|
||||||
defaults={"per_second": 0.3, "burst_count": 10},
|
defaults={"per_second": 0.3, "burst_count": 10},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.rc_third_party_invite = RateLimitConfig(
|
self.rc_third_party_invite = RatelimitSettings(
|
||||||
config.get("rc_third_party_invite", {}),
|
config.get("rc_third_party_invite", {}),
|
||||||
defaults={
|
defaults={
|
||||||
"per_second": self.rc_message.per_second,
|
"per_second": self.rc_message.per_second,
|
||||||
|
|
|
@ -52,6 +52,7 @@ from synapse.events.builder import EventBuilder
|
||||||
from synapse.events.snapshot import EventContext
|
from synapse.events.snapshot import EventContext
|
||||||
from synapse.events.validator import EventValidator
|
from synapse.events.validator import EventValidator
|
||||||
from synapse.handlers.directory import DirectoryHandler
|
from synapse.handlers.directory import DirectoryHandler
|
||||||
|
from synapse.logging import tracing
|
||||||
from synapse.logging.context import make_deferred_yieldable, run_in_background
|
from synapse.logging.context import make_deferred_yieldable, run_in_background
|
||||||
from synapse.metrics.background_process_metrics import run_as_background_process
|
from synapse.metrics.background_process_metrics import run_as_background_process
|
||||||
from synapse.replication.http.send_event import ReplicationSendEventRestServlet
|
from synapse.replication.http.send_event import ReplicationSendEventRestServlet
|
||||||
|
@ -324,8 +325,10 @@ class MessageHandler:
|
||||||
room_id, user_id, allow_departed_users=True
|
room_id, user_id, allow_departed_users=True
|
||||||
)
|
)
|
||||||
if membership != Membership.JOIN:
|
if membership != Membership.JOIN:
|
||||||
raise NotImplementedError(
|
raise SynapseError(
|
||||||
"Getting joined members after leaving is not implemented"
|
code=403,
|
||||||
|
errcode=Codes.FORBIDDEN,
|
||||||
|
msg="Getting joined members while not being a current member of the room is forbidden.",
|
||||||
)
|
)
|
||||||
|
|
||||||
users_with_profile = await self.store.get_users_in_room_with_profiles(room_id)
|
users_with_profile = await self.store.get_users_in_room_with_profiles(room_id)
|
||||||
|
@ -1372,9 +1375,10 @@ class EventCreationHandler:
|
||||||
# and `state_groups` because they have `prev_events` that aren't persisted yet
|
# and `state_groups` because they have `prev_events` that aren't persisted yet
|
||||||
# (historical messages persisted in reverse-chronological order).
|
# (historical messages persisted in reverse-chronological order).
|
||||||
if not event.internal_metadata.is_historical():
|
if not event.internal_metadata.is_historical():
|
||||||
await self._bulk_push_rule_evaluator.action_for_event_by_user(
|
with tracing.start_active_span("calculate_push_actions"):
|
||||||
event, context
|
await self._bulk_push_rule_evaluator.action_for_event_by_user(
|
||||||
)
|
event, context
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# If we're a worker we need to hit out to the master.
|
# If we're a worker we need to hit out to the master.
|
||||||
|
@ -1461,9 +1465,10 @@ class EventCreationHandler:
|
||||||
state = await state_entry.get_state(
|
state = await state_entry.get_state(
|
||||||
self._storage_controllers.state, StateFilter.all()
|
self._storage_controllers.state, StateFilter.all()
|
||||||
)
|
)
|
||||||
joined_hosts = await self.store.get_joined_hosts(
|
with tracing.start_active_span("get_joined_hosts"):
|
||||||
event.room_id, state, state_entry
|
joined_hosts = await self.store.get_joined_hosts(
|
||||||
)
|
event.room_id, state, state_entry
|
||||||
|
)
|
||||||
|
|
||||||
# Note that the expiry times must be larger than the expiry time in
|
# Note that the expiry times must be larger than the expiry time in
|
||||||
# _external_cache_joined_hosts_updates.
|
# _external_cache_joined_hosts_updates.
|
||||||
|
|
|
@ -32,6 +32,7 @@ from synapse.event_auth import get_named_level, get_power_level_event
|
||||||
from synapse.events import EventBase
|
from synapse.events import EventBase
|
||||||
from synapse.events.snapshot import EventContext
|
from synapse.events.snapshot import EventContext
|
||||||
from synapse.handlers.profile import MAX_AVATAR_URL_LEN, MAX_DISPLAYNAME_LEN
|
from synapse.handlers.profile import MAX_AVATAR_URL_LEN, MAX_DISPLAYNAME_LEN
|
||||||
|
from synapse.logging import tracing
|
||||||
from synapse.module_api import NOT_SPAM
|
from synapse.module_api import NOT_SPAM
|
||||||
from synapse.storage.state import StateFilter
|
from synapse.storage.state import StateFilter
|
||||||
from synapse.types import (
|
from synapse.types import (
|
||||||
|
@ -428,14 +429,14 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||||
await self._join_rate_per_room_limiter.ratelimit(
|
await self._join_rate_per_room_limiter.ratelimit(
|
||||||
requester, key=room_id, update=False
|
requester, key=room_id, update=False
|
||||||
)
|
)
|
||||||
|
with tracing.start_active_span("handle_new_client_event"):
|
||||||
result_event = await self.event_creation_handler.handle_new_client_event(
|
result_event = await self.event_creation_handler.handle_new_client_event(
|
||||||
requester,
|
requester,
|
||||||
event,
|
event,
|
||||||
context,
|
context,
|
||||||
extra_users=[target],
|
extra_users=[target],
|
||||||
ratelimit=ratelimit,
|
ratelimit=ratelimit,
|
||||||
)
|
)
|
||||||
|
|
||||||
if event.membership == Membership.LEAVE:
|
if event.membership == Membership.LEAVE:
|
||||||
if prev_member_event_id:
|
if prev_member_event_id:
|
||||||
|
@ -564,25 +565,26 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||||
# by application services), and then by room ID.
|
# by application services), and then by room ID.
|
||||||
async with self.member_as_limiter.queue(as_id):
|
async with self.member_as_limiter.queue(as_id):
|
||||||
async with self.member_linearizer.queue(key):
|
async with self.member_linearizer.queue(key):
|
||||||
result = await self.update_membership_locked(
|
with tracing.start_active_span("update_membership_locked"):
|
||||||
requester,
|
result = await self.update_membership_locked(
|
||||||
target,
|
requester,
|
||||||
room_id,
|
target,
|
||||||
action,
|
room_id,
|
||||||
txn_id=txn_id,
|
action,
|
||||||
remote_room_hosts=remote_room_hosts,
|
txn_id=txn_id,
|
||||||
third_party_signed=third_party_signed,
|
remote_room_hosts=remote_room_hosts,
|
||||||
ratelimit=ratelimit,
|
third_party_signed=third_party_signed,
|
||||||
content=content,
|
ratelimit=ratelimit,
|
||||||
new_room=new_room,
|
content=content,
|
||||||
require_consent=require_consent,
|
new_room=new_room,
|
||||||
outlier=outlier,
|
require_consent=require_consent,
|
||||||
historical=historical,
|
outlier=outlier,
|
||||||
allow_no_prev_events=allow_no_prev_events,
|
historical=historical,
|
||||||
prev_event_ids=prev_event_ids,
|
allow_no_prev_events=allow_no_prev_events,
|
||||||
state_event_ids=state_event_ids,
|
prev_event_ids=prev_event_ids,
|
||||||
depth=depth,
|
state_event_ids=state_event_ids,
|
||||||
)
|
depth=depth,
|
||||||
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -649,6 +651,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
|
||||||
Returns:
|
Returns:
|
||||||
A tuple of the new event ID and stream ID.
|
A tuple of the new event ID and stream ID.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
content_specified = bool(content)
|
content_specified = bool(content)
|
||||||
if content is None:
|
if content is None:
|
||||||
content = {}
|
content = {}
|
||||||
|
|
|
@ -330,8 +330,10 @@ class LoggingContext:
|
||||||
@classmethod
|
@classmethod
|
||||||
def current_context(cls) -> LoggingContextOrSentinel:
|
def current_context(cls) -> LoggingContextOrSentinel:
|
||||||
"""Get the current logging context from thread local storage
|
"""Get the current logging context from thread local storage
|
||||||
|
|
||||||
This exists for backwards compatibility. ``current_context()`` should be
|
This exists for backwards compatibility. ``current_context()`` should be
|
||||||
called directly.
|
called directly.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
LoggingContext: the current logging context
|
LoggingContext: the current logging context
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1452,6 +1452,30 @@ class ModuleApi:
|
||||||
start_timestamp, end_timestamp
|
start_timestamp, end_timestamp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def lookup_room_alias(self, room_alias: str) -> Tuple[str, List[str]]:
|
||||||
|
"""
|
||||||
|
Get the room ID associated with a room alias.
|
||||||
|
|
||||||
|
Added in Synapse v1.65.0.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
room_alias: The alias to look up.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A tuple of:
|
||||||
|
The room ID (str).
|
||||||
|
Hosts likely to be participating in the room ([str]).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
SynapseError if room alias is invalid or could not be found.
|
||||||
|
"""
|
||||||
|
alias = RoomAlias.from_string(room_alias)
|
||||||
|
(room_id, hosts) = await self._hs.get_room_member_handler().lookup_room_alias(
|
||||||
|
alias
|
||||||
|
)
|
||||||
|
|
||||||
|
return room_id.to_string(), hosts
|
||||||
|
|
||||||
|
|
||||||
class PublicRoomListManager:
|
class PublicRoomListManager:
|
||||||
"""Contains methods for adding to, removing from and querying whether a room
|
"""Contains methods for adding to, removing from and querying whether a room
|
||||||
|
|
|
@ -33,7 +33,7 @@ from synapse.api.ratelimiting import Ratelimiter
|
||||||
from synapse.config import ConfigError
|
from synapse.config import ConfigError
|
||||||
from synapse.config.emailconfig import ThreepidBehaviour
|
from synapse.config.emailconfig import ThreepidBehaviour
|
||||||
from synapse.config.homeserver import HomeServerConfig
|
from synapse.config.homeserver import HomeServerConfig
|
||||||
from synapse.config.ratelimiting import FederationRateLimitConfig
|
from synapse.config.ratelimiting import FederationRatelimitSettings
|
||||||
from synapse.config.server import is_threepid_reserved
|
from synapse.config.server import is_threepid_reserved
|
||||||
from synapse.handlers.auth import AuthHandler
|
from synapse.handlers.auth import AuthHandler
|
||||||
from synapse.handlers.ui_auth import UIAuthSessionDataConstants
|
from synapse.handlers.ui_auth import UIAuthSessionDataConstants
|
||||||
|
@ -325,7 +325,7 @@ class UsernameAvailabilityRestServlet(RestServlet):
|
||||||
self.registration_handler = hs.get_registration_handler()
|
self.registration_handler = hs.get_registration_handler()
|
||||||
self.ratelimiter = FederationRateLimiter(
|
self.ratelimiter = FederationRateLimiter(
|
||||||
hs.get_clock(),
|
hs.get_clock(),
|
||||||
FederationRateLimitConfig(
|
FederationRatelimitSettings(
|
||||||
# Time window of 2s
|
# Time window of 2s
|
||||||
window_size=2000,
|
window_size=2000,
|
||||||
# Artificially delay requests if rate > sleep_limit/window_size
|
# Artificially delay requests if rate > sleep_limit/window_size
|
||||||
|
|
|
@ -21,6 +21,7 @@ from synapse.handlers.presence import PresenceEventSource
|
||||||
from synapse.handlers.receipts import ReceiptEventSource
|
from synapse.handlers.receipts import ReceiptEventSource
|
||||||
from synapse.handlers.room import RoomEventSource
|
from synapse.handlers.room import RoomEventSource
|
||||||
from synapse.handlers.typing import TypingNotificationEventSource
|
from synapse.handlers.typing import TypingNotificationEventSource
|
||||||
|
from synapse.logging.tracing import trace
|
||||||
from synapse.streams import EventSource
|
from synapse.streams import EventSource
|
||||||
from synapse.types import StreamToken
|
from synapse.types import StreamToken
|
||||||
|
|
||||||
|
@ -69,6 +70,7 @@ class EventSources:
|
||||||
)
|
)
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
@trace
|
||||||
async def get_current_token_for_pagination(self, room_id: str) -> StreamToken:
|
async def get_current_token_for_pagination(self, room_id: str) -> StreamToken:
|
||||||
"""Get the current token for a given room to be used to paginate
|
"""Get the current token for a given room to be used to paginate
|
||||||
events.
|
events.
|
||||||
|
|
|
@ -21,7 +21,7 @@ from typing import Any, DefaultDict, Iterator, List, Set
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.errors import LimitExceededError
|
from synapse.api.errors import LimitExceededError
|
||||||
from synapse.config.ratelimiting import FederationRateLimitConfig
|
from synapse.config.ratelimiting import FederationRatelimitSettings
|
||||||
from synapse.logging.context import (
|
from synapse.logging.context import (
|
||||||
PreserveLoggingContext,
|
PreserveLoggingContext,
|
||||||
make_deferred_yieldable,
|
make_deferred_yieldable,
|
||||||
|
@ -36,7 +36,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class FederationRateLimiter:
|
class FederationRateLimiter:
|
||||||
def __init__(self, clock: Clock, config: FederationRateLimitConfig):
|
def __init__(self, clock: Clock, config: FederationRatelimitSettings):
|
||||||
def new_limiter() -> "_PerHostRatelimiter":
|
def new_limiter() -> "_PerHostRatelimiter":
|
||||||
return _PerHostRatelimiter(clock=clock, config=config)
|
return _PerHostRatelimiter(clock=clock, config=config)
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class FederationRateLimiter:
|
||||||
|
|
||||||
|
|
||||||
class _PerHostRatelimiter:
|
class _PerHostRatelimiter:
|
||||||
def __init__(self, clock: Clock, config: FederationRateLimitConfig):
|
def __init__(self, clock: Clock, config: FederationRatelimitSettings):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
clock
|
clock
|
||||||
|
|
|
@ -139,10 +139,10 @@ class TracingTestCase(TestCase):
|
||||||
with start_active_span(
|
with start_active_span(
|
||||||
f"task{i}",
|
f"task{i}",
|
||||||
tracer=self._tracer,
|
tracer=self._tracer,
|
||||||
) as span1:
|
) as span:
|
||||||
self.assertEqual(opentelemetry.trace.get_current_span(), span1)
|
self.assertEqual(opentelemetry.trace.get_current_span(), span)
|
||||||
await clock.sleep(4)
|
await clock.sleep(4)
|
||||||
self.assertEqual(opentelemetry.trace.get_current_span(), span1)
|
self.assertEqual(opentelemetry.trace.get_current_span(), span)
|
||||||
|
|
||||||
async def root():
|
async def root():
|
||||||
with start_active_span("root_span", tracer=self._tracer) as root_span:
|
with start_active_span("root_span", tracer=self._tracer) as root_span:
|
||||||
|
@ -163,12 +163,12 @@ class TracingTestCase(TestCase):
|
||||||
self.assertEqual(opentelemetry.trace.get_current_span(), root_span)
|
self.assertEqual(opentelemetry.trace.get_current_span(), root_span)
|
||||||
|
|
||||||
# start the test off
|
# start the test off
|
||||||
d1 = defer.ensureDeferred(root())
|
root_defferred = defer.ensureDeferred(root())
|
||||||
|
|
||||||
# let the tasks complete
|
# let the tasks complete
|
||||||
reactor.pump((2,) * 8)
|
reactor.pump((2,) * 8)
|
||||||
|
|
||||||
self.successResultOf(d1)
|
self.successResultOf(root_defferred)
|
||||||
# Active span is unset now that we're outside of the `with` scopes
|
# Active span is unset now that we're outside of the `with` scopes
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
opentelemetry.trace.get_current_span(), opentelemetry.trace.INVALID_SPAN
|
opentelemetry.trace.get_current_span(), opentelemetry.trace.INVALID_SPAN
|
||||||
|
|
|
@ -635,6 +635,25 @@ class ModuleApiTestCase(HomeserverTestCase):
|
||||||
[{"set_tweak": "sound", "value": "default"}]
|
[{"set_tweak": "sound", "value": "default"}]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_lookup_room_alias(self) -> None:
|
||||||
|
"""Test that modules can resolve a room alias to a room ID."""
|
||||||
|
password = "password"
|
||||||
|
user_id = self.register_user("user", password)
|
||||||
|
access_token = self.login(user_id, password)
|
||||||
|
room_alias = "my-alias"
|
||||||
|
reference_room_id = self.helper.create_room_as(
|
||||||
|
tok=access_token, extra_content={"room_alias_name": room_alias}
|
||||||
|
)
|
||||||
|
self.assertIsNotNone(reference_room_id)
|
||||||
|
|
||||||
|
(room_id, _) = self.get_success(
|
||||||
|
self.module_api.lookup_room_alias(
|
||||||
|
f"#{room_alias}:{self.module_api.server_name}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(room_id, reference_room_id)
|
||||||
|
|
||||||
|
|
||||||
class ModuleApiWorkerTestCase(BaseMultiWorkerStreamTestCase):
|
class ModuleApiWorkerTestCase(BaseMultiWorkerStreamTestCase):
|
||||||
"""For testing ModuleApi functionality in a multi-worker setup"""
|
"""For testing ModuleApi functionality in a multi-worker setup"""
|
||||||
|
|
|
@ -1772,6 +1772,21 @@ class RoomTestCase(unittest.HomeserverTestCase):
|
||||||
tok=admin_user_tok,
|
tok=admin_user_tok,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_joined_members_after_leave_room(self) -> None:
|
||||||
|
"""Test that requesting room members after leaving the room raises a 403 error."""
|
||||||
|
|
||||||
|
# create the room
|
||||||
|
user = self.register_user("foo", "pass")
|
||||||
|
user_tok = self.login("foo", "pass")
|
||||||
|
room_id = self.helper.create_room_as(user, tok=user_tok)
|
||||||
|
self.helper.leave(room_id, user, tok=user_tok)
|
||||||
|
|
||||||
|
# delete the rooms and get joined roomed membership
|
||||||
|
url = f"/_matrix/client/r0/rooms/{room_id}/joined_members"
|
||||||
|
channel = self.make_request("GET", url.encode("ascii"), access_token=user_tok)
|
||||||
|
self.assertEqual(HTTPStatus.FORBIDDEN, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
|
||||||
class JoinAliasRoomTestCase(unittest.HomeserverTestCase):
|
class JoinAliasRoomTestCase(unittest.HomeserverTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue