summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Eastwood <erice@element.io>2022-08-03 17:05:04 -0500
committerEric Eastwood <erice@element.io>2022-08-03 17:05:04 -0500
commitc3f3e59ccad4e1dcaacf0b5963492f66d662b093 (patch)
treeb5495949188f144a3992fdcc0878c90edc382137
parentFix imports after OTEL changes (diff)
parentUpdate docs/tracing.md (diff)
downloadsynapse-c3f3e59ccad4e1dcaacf0b5963492f66d662b093.tar.xz
Merge branch 'madlittlemods/11850-migrate-to-opentelemetry' into madlittlemods/13356-messages-investigation-scratch-v1
-rw-r--r--changelog.d/13230.doc1
-rw-r--r--changelog.d/13368.misc1
-rw-r--r--changelog.d/13372.docker1
-rw-r--r--changelog.d/13374.bugfix1
-rw-r--r--changelog.d/13428.feature1
-rw-r--r--changelog.d/13437.doc1
-rw-r--r--changelog.d/13438.doc1
-rw-r--r--changelog.d/13439.misc1
-rw-r--r--changelog.d/13442.misc1
-rw-r--r--changelog.d/13443.doc1
-rw-r--r--docker/Dockerfile3
-rw-r--r--docs/tracing.md46
-rw-r--r--docs/usage/administration/admin_api/README.md3
-rw-r--r--docs/usage/configuration/config_documentation.md56
-rw-r--r--poetry.lock61
-rw-r--r--pyproject.toml2
-rw-r--r--synapse/api/ratelimiting.py6
-rw-r--r--synapse/config/ratelimiting.py42
-rw-r--r--synapse/handlers/message.py21
-rw-r--r--synapse/handlers/room_member.py57
-rw-r--r--synapse/logging/context.py2
-rw-r--r--synapse/module_api/__init__.py24
-rw-r--r--synapse/rest/client/register.py4
-rw-r--r--synapse/streams/events.py2
-rw-r--r--synapse/util/ratelimitutils.py6
-rw-r--r--tests/logging/test_tracing.py10
-rw-r--r--tests/module_api/test_api.py19
-rw-r--r--tests/rest/admin/test_room.py15
28 files changed, 213 insertions, 176 deletions
diff --git a/changelog.d/13230.doc b/changelog.d/13230.doc
new file mode 100644

index 0000000000..dce7be2425 --- /dev/null +++ b/changelog.d/13230.doc
@@ -0,0 +1 @@ +Add steps describing how to elevate an existing user to administrator by manipulating the database. diff --git a/changelog.d/13368.misc b/changelog.d/13368.misc new file mode 100644
index 0000000000..4b433a5107 --- /dev/null +++ b/changelog.d/13368.misc
@@ -0,0 +1 @@ +Instrument `/messages` for understandable traces in Jaeger. diff --git a/changelog.d/13372.docker b/changelog.d/13372.docker new file mode 100644
index 0000000000..238c78de09 --- /dev/null +++ b/changelog.d/13372.docker
@@ -0,0 +1 @@ +Make docker images build on armv7 by installing cryptography dependencies in the "requirements" stage. Contributed by Jasper Spaans. \ No newline at end of file diff --git a/changelog.d/13374.bugfix b/changelog.d/13374.bugfix new file mode 100644
index 0000000000..1c5bd1b363 --- /dev/null +++ b/changelog.d/13374.bugfix
@@ -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. \ No newline at end of file diff --git a/changelog.d/13428.feature b/changelog.d/13428.feature new file mode 100644
index 0000000000..085b61483f --- /dev/null +++ b/changelog.d/13428.feature
@@ -0,0 +1 @@ +Add a module API method to translate a room alias into a room ID. diff --git a/changelog.d/13437.doc b/changelog.d/13437.doc new file mode 100644
index 0000000000..fb772b24dc --- /dev/null +++ b/changelog.d/13437.doc
@@ -0,0 +1 @@ +Fix wrong headline for `url_preview_accept_language` in documentation. diff --git a/changelog.d/13438.doc b/changelog.d/13438.doc new file mode 100644
index 0000000000..163b63ffc6 --- /dev/null +++ b/changelog.d/13438.doc
@@ -0,0 +1 @@ +Remove redundant 'Contents' section from the Configuration Manual. Contributed by @dklimpel. diff --git a/changelog.d/13439.misc b/changelog.d/13439.misc new file mode 100644
index 0000000000..4aa73d7075 --- /dev/null +++ b/changelog.d/13439.misc
@@ -0,0 +1 @@ +Add some tracing to give more insight into local room joins. diff --git a/changelog.d/13442.misc b/changelog.d/13442.misc new file mode 100644
index 0000000000..f503bc79d3 --- /dev/null +++ b/changelog.d/13442.misc
@@ -0,0 +1 @@ +Rename class `RateLimitConfig` to `RatelimitSettings` and `FederationRateLimitConfig` to `FederationRatelimitSettings`. \ No newline at end of file diff --git a/changelog.d/13443.doc b/changelog.d/13443.doc new file mode 100644
index 0000000000..0db5d1b3b4 --- /dev/null +++ b/changelog.d/13443.doc
@@ -0,0 +1 @@ +Update documentation for config setting `macaroon_secret_key`. \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile
index 97bb03b08f..fa58ae3acb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile
@@ -40,7 +40,8 @@ FROM docker.io/python:${PYTHON_VERSION}-slim as requirements RUN \ --mount=type=cache,target=/var/cache/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/* # We install poetry in its own build stage to avoid its dependencies conflicting with diff --git a/docs/tracing.md b/docs/tracing.md
index abb94b565f..37f07fc28e 100644 --- a/docs/tracing.md +++ b/docs/tracing.md
@@ -1,14 +1,12 @@ -# OpenTracing +# Tracing ## Background -OpenTracing is a semi-standard being adopted by a number of distributed -tracing platforms. It is a common api for facilitating vendor-agnostic -tracing instrumentation. That is, we can use the OpenTracing api and -select one of a number of tracer implementations to do the heavy lifting -in the background. Our current selected implementation is Jaeger. +OpenTelemetry is a semi-standard being adopted by a number of distributed +tracing platforms. It is a common API for facilitating vendor-agnostic +tracing instrumentation. -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 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 @@ -22,7 +20,7 @@ finish. 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 (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 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 through Jaeger's settings. -For OpenTracing concepts see -<https://opentracing.io/docs/overview/what-is-tracing/>. +For OpenTelemetry concepts, see +<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/> -## 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: ```sh @@ -54,15 +55,15 @@ docker run -d --name jaeger \ Latest documentation is probably at 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 -homeserver config by adding the `opentracing` 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). -See below for an example Opentracing configuration: +Tracing is not enabled by default. It must be enabled in the +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 'Tracing'](usage/configuration/config_documentation.md#tracing). +See below for an example tracing configuration: ```yaml -opentracing: +tracing: enabled: true homeserver_whitelist: - "mytrustedhomeserver.org" @@ -86,9 +87,4 @@ to two problems, namely: - Sending servers can attach arbitrary data to spans, known as 'baggage'. For safety this has been disabled in Synapse but that doesn't prevent another server sending you baggage which will be - logged to OpenTracing's logs. - -## Configuring Jaeger - -Sampling strategies can be set as in this document: -<https://www.jaegertracing.io/docs/latest/sampling/>. + logged in the trace. diff --git a/docs/usage/administration/admin_api/README.md b/docs/usage/administration/admin_api/README.md
index c60b6da0de..f11e0b19a6 100644 --- a/docs/usage/administration/admin_api/README.md +++ b/docs/usage/administration/admin_api/README.md
@@ -5,8 +5,9 @@ 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.) -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 UPDATE users SET admin = 1 WHERE name = '@foo:bar.com'; ``` diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md
index 100f95776b..d215af7250 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md
@@ -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 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 @@ -1859,7 +1817,7 @@ Example configuration: max_spider_size: 8M ``` --- -### `url_preview_language` +### `url_preview_accept_language` A list of values for the Accept-Language HTTP header used when downloading webpages during URL preview generation. This allows @@ -2538,9 +2496,13 @@ track_appservice_user_ips: true --- ### `macaroon_secret_key` -A secret which is used to sign access tokens. If none is specified, -the `registration_shared_secret` is used, if one is given; otherwise, -a secret key is derived from the signing key. +A secret which is used to sign +- access token for guest users, +- 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: ```yaml @@ -3578,7 +3540,7 @@ OpenTelemetry. Sub-options include: * `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. - 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. 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 diff --git a/poetry.lock b/poetry.lock
index 5195892a06..a78ceb0ae5 100644 --- a/poetry.lock +++ b/poetry.lock
@@ -1267,22 +1267,17 @@ telegram = ["requests"] [[package]] name = "treq" -version = "22.2.0" -description = "High-level Twisted HTTP Client API" +version = "15.1.0" +description = "A requests-like API built on top of twisted.web's Agent" category = "main" optional = false -python-versions = ">=3.6" +python-versions = "*" [package.dependencies] -attrs = "*" -hyperlink = ">=21.0.0" -incremental = "*" +pyOpenSSL = {version = ">=0.15.1", markers = "python_version > \"3.0\""} requests = ">=2.1.0" -Twisted = {version = ">=18.7.0", extras = ["tls"]} - -[package.extras] -dev = ["pep8", "pyflakes", "httpbin (==0.5.0)"] -docs = ["sphinx (>=1.4.8)"] +service_identity = ">=14.0.0" +Twisted = {version = ">=15.5.0", markers = "python_version > \"3.0\""} [[package]] name = "twine" @@ -1305,41 +1300,46 @@ tqdm = ">=4.14" urllib3 = ">=1.26.0" [[package]] -name = "twisted" -version = "22.4.0" +name = "Twisted" +version = "22.4.0.post0" description = "An asynchronous networking framework written in Python" category = "main" optional = false -python-versions = ">=3.6.7" +python-versions = ">=3.7.1" +develop = false [package.dependencies] attrs = ">=19.2.0" Automat = ">=0.8.0" constantly = ">=15.1" hyperlink = ">=17.1.1" -idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""} 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\""} typing-extensions = ">=3.6.5" "zope.interface" = ">=4.4.2" [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_nacl = ["pyasn1", "cryptography (>=2.6)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "pynacl"] 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_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 = ["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)", "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)"] -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)"] -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)"] -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)"] +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)", "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 (>=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)"] 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)"] -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)"] +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 (>=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]] name = "twisted-iocpsupport" @@ -1615,7 +1615,7 @@ url_preview = ["lxml"] [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "06a9f9259d4aa587a48242adf571bbd1132eda149226c1d2819a8b7a05c7ce5c" +content-hash = "c2cfbb348a49e088c404148c1b682fc5af5abb6278cf4479c6a51fff1656328c" [metadata.files] attrs = [ @@ -2642,17 +2642,14 @@ tqdm = [ {file = "tqdm-4.63.0.tar.gz", hash = "sha256:1d9835ede8e394bb8c9dcbffbca02d717217113adc679236873eeaac5bc0b3cd"}, ] treq = [ - {file = "treq-22.2.0-py3-none-any.whl", hash = "sha256:27d95b07c5c14be3e7b280416139b036087617ad5595be913b1f9b3ce981b9b2"}, - {file = "treq-22.2.0.tar.gz", hash = "sha256:df757e3f141fc782ede076a604521194ffcb40fa2645cf48e5a37060307f52ec"}, + {file = "treq-15.1.0-py2.py3-none-any.whl", hash = "sha256:1ad1ba89ddc62ae877084b290bd327755b13f6e7bc7076dc4d8e2efb701bfd63"}, + {file = "treq-15.1.0.tar.gz", hash = "sha256:425a47d5d52a993d51211028fb6ade252e5fbea094e878bb4b644096a7322de8"}, ] twine = [ {file = "twine-3.8.0-py3-none-any.whl", hash = "sha256:d0550fca9dc19f3d5e8eadfce0c227294df0a2a951251a4385797c8a6198b7c8"}, {file = "twine-3.8.0.tar.gz", hash = "sha256:8efa52658e0ae770686a13b675569328f1fba9837e5de1867bfe5f46a9aefe19"}, ] -twisted = [ - {file = "Twisted-22.4.0-py3-none-any.whl", hash = "sha256:f9f7a91f94932477a9fc3b169d57f54f96c6e74a23d78d9ce54039a7f48928a2"}, - {file = "Twisted-22.4.0.tar.gz", hash = "sha256:a047990f57dfae1e0bd2b7df2526d4f16dcdc843774dc108b78c52f2a5f13680"}, -] +Twisted = [] twisted-iocpsupport = [ {file = "twisted-iocpsupport-1.0.2.tar.gz", hash = "sha256:72068b206ee809c9c596b57b5287259ea41ddb4774d86725b19f35bf56aa32a9"}, {file = "twisted_iocpsupport-1.0.2-cp310-cp310-win32.whl", hash = "sha256:985c06a33f5c0dae92c71a036d1ea63872ee86a21dd9b01e1f287486f15524b4"}, diff --git a/pyproject.toml b/pyproject.toml
index 4fbd544b87..989d1b3a69 100644 --- a/pyproject.toml +++ b/pyproject.toml
@@ -119,7 +119,6 @@ signedjson = "^1.1.0" service-identity = ">=18.1.0" # Twisted 18.9 introduces some logger improvements that the structured # logger utilises -Twisted = {extras = ["tls"], version = ">=18.9.0"} treq = ">=15.1" # Twisted has required pyopenssl 16.0 since about Twisted 16.6. pyOpenSSL = ">=16.0.0" @@ -183,6 +182,7 @@ idna = { version = ">=2.5", optional = true } opentelemetry-api = {version = "^1.11.1", optional = true} opentelemetry-sdk = {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] # NB: Packages that should be part of `pip install matrix-synapse[all]` need to be specified diff --git a/synapse/api/ratelimiting.py b/synapse/api/ratelimiting.py
index f43965c1c8..044c7d4926 100644 --- a/synapse/api/ratelimiting.py +++ b/synapse/api/ratelimiting.py
@@ -17,7 +17,7 @@ from collections import OrderedDict from typing import Hashable, Optional, Tuple 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.types import Requester from synapse.util import Clock @@ -314,8 +314,8 @@ class RequestRatelimiter: self, store: DataStore, clock: Clock, - rc_message: RateLimitConfig, - rc_admin_redaction: Optional[RateLimitConfig], + rc_message: RatelimitSettings, + rc_admin_redaction: Optional[RatelimitSettings], ): self.store = store self.clock = clock diff --git a/synapse/config/ratelimiting.py b/synapse/config/ratelimiting.py
index 5a91917b4a..1ed001e105 100644 --- a/synapse/config/ratelimiting.py +++ b/synapse/config/ratelimiting.py
@@ -21,7 +21,7 @@ from synapse.types import JsonDict from ._base import Config -class RateLimitConfig: +class RatelimitSettings: def __init__( self, config: Dict[str, float], @@ -34,7 +34,7 @@ class RateLimitConfig: @attr.s(auto_attribs=True) -class FederationRateLimitConfig: +class FederationRatelimitSettings: window_size: int = 1000 sleep_limit: int = 10 sleep_delay: int = 500 @@ -50,11 +50,11 @@ class RatelimitConfig(Config): # Load the new-style messages config if it exists. Otherwise fall back # to the old method. 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} ) else: - self.rc_message = RateLimitConfig( + self.rc_message = RatelimitSettings( { "per_second": config.get("rc_messages_per_second", 0.2), "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 # back to the old method. if "rc_federation" in config: - self.rc_federation = FederationRateLimitConfig(**config["rc_federation"]) + self.rc_federation = FederationRatelimitSettings(**config["rc_federation"]) else: - self.rc_federation = FederationRateLimitConfig( + self.rc_federation = FederationRatelimitSettings( **{ k: v 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", {}), defaults={"per_second": 0.1, "burst_count": 5}, ) rc_login_config = config.get("rc_login", {}) - self.rc_login_address = RateLimitConfig(rc_login_config.get("address", {})) - self.rc_login_account = RateLimitConfig(rc_login_config.get("account", {})) - self.rc_login_failed_attempts = RateLimitConfig( + self.rc_login_address = RatelimitSettings(rc_login_config.get("address", {})) + self.rc_login_account = RatelimitSettings(rc_login_config.get("account", {})) + self.rc_login_failed_attempts = RatelimitSettings( rc_login_config.get("failed_attempts", {}) ) @@ -101,20 +101,20 @@ class RatelimitConfig(Config): rc_admin_redaction = config.get("rc_admin_redaction") self.rc_admin_redaction = None 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", {}), defaults={"per_second": 0.1, "burst_count": 10}, ) - self.rc_joins_remote = RateLimitConfig( + self.rc_joins_remote = RatelimitSettings( config.get("rc_joins", {}).get("remote", {}), defaults={"per_second": 0.01, "burst_count": 10}, ) # Track the rate of joins to a given room. If there are too many, temporarily # 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", {}), 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. # # 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", {}), defaults={"per_second": 20, "burst_count": 100}, ) - self.rc_3pid_validation = RateLimitConfig( + self.rc_3pid_validation = RatelimitSettings( config.get("rc_3pid_validation") or {}, 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", {}), 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", {}), 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", {}), 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", {}), defaults={ "per_second": self.rc_message.per_second, diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index e85b540451..8d9754f306 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py
@@ -52,6 +52,7 @@ from synapse.events.builder import EventBuilder from synapse.events.snapshot import EventContext from synapse.events.validator import EventValidator from synapse.handlers.directory import DirectoryHandler +from synapse.logging import tracing from synapse.logging.context import make_deferred_yieldable, run_in_background from synapse.metrics.background_process_metrics import run_as_background_process from synapse.replication.http.send_event import ReplicationSendEventRestServlet @@ -324,8 +325,10 @@ class MessageHandler: room_id, user_id, allow_departed_users=True ) if membership != Membership.JOIN: - raise NotImplementedError( - "Getting joined members after leaving is not implemented" + raise SynapseError( + 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) @@ -1372,9 +1375,10 @@ class EventCreationHandler: # and `state_groups` because they have `prev_events` that aren't persisted yet # (historical messages persisted in reverse-chronological order). if not event.internal_metadata.is_historical(): - await self._bulk_push_rule_evaluator.action_for_event_by_user( - event, context - ) + with tracing.start_active_span("calculate_push_actions"): + await self._bulk_push_rule_evaluator.action_for_event_by_user( + event, context + ) try: # 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( self._storage_controllers.state, StateFilter.all() ) - joined_hosts = await self.store.get_joined_hosts( - event.room_id, state, state_entry - ) + with tracing.start_active_span("get_joined_hosts"): + 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 # _external_cache_joined_hosts_updates. diff --git a/synapse/handlers/room_member.py b/synapse/handlers/room_member.py
index 520c52e013..0f95d4127e 100644 --- a/synapse/handlers/room_member.py +++ b/synapse/handlers/room_member.py
@@ -32,6 +32,7 @@ from synapse.event_auth import get_named_level, get_power_level_event from synapse.events import EventBase from synapse.events.snapshot import EventContext 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.storage.state import StateFilter from synapse.types import ( @@ -428,14 +429,14 @@ class RoomMemberHandler(metaclass=abc.ABCMeta): await self._join_rate_per_room_limiter.ratelimit( requester, key=room_id, update=False ) - - result_event = await self.event_creation_handler.handle_new_client_event( - requester, - event, - context, - extra_users=[target], - ratelimit=ratelimit, - ) + with tracing.start_active_span("handle_new_client_event"): + result_event = await self.event_creation_handler.handle_new_client_event( + requester, + event, + context, + extra_users=[target], + ratelimit=ratelimit, + ) if event.membership == Membership.LEAVE: if prev_member_event_id: @@ -564,25 +565,26 @@ class RoomMemberHandler(metaclass=abc.ABCMeta): # by application services), and then by room ID. async with self.member_as_limiter.queue(as_id): async with self.member_linearizer.queue(key): - result = await self.update_membership_locked( - requester, - target, - room_id, - action, - txn_id=txn_id, - remote_room_hosts=remote_room_hosts, - third_party_signed=third_party_signed, - ratelimit=ratelimit, - content=content, - new_room=new_room, - require_consent=require_consent, - outlier=outlier, - historical=historical, - allow_no_prev_events=allow_no_prev_events, - prev_event_ids=prev_event_ids, - state_event_ids=state_event_ids, - depth=depth, - ) + with tracing.start_active_span("update_membership_locked"): + result = await self.update_membership_locked( + requester, + target, + room_id, + action, + txn_id=txn_id, + remote_room_hosts=remote_room_hosts, + third_party_signed=third_party_signed, + ratelimit=ratelimit, + content=content, + new_room=new_room, + require_consent=require_consent, + outlier=outlier, + historical=historical, + allow_no_prev_events=allow_no_prev_events, + prev_event_ids=prev_event_ids, + state_event_ids=state_event_ids, + depth=depth, + ) return result @@ -649,6 +651,7 @@ class RoomMemberHandler(metaclass=abc.ABCMeta): Returns: A tuple of the new event ID and stream ID. """ + content_specified = bool(content) if content is None: content = {} diff --git a/synapse/logging/context.py b/synapse/logging/context.py
index dde9c151f5..a417b13ffd 100644 --- a/synapse/logging/context.py +++ b/synapse/logging/context.py
@@ -330,8 +330,10 @@ class LoggingContext: @classmethod def current_context(cls) -> LoggingContextOrSentinel: """Get the current logging context from thread local storage + This exists for backwards compatibility. ``current_context()`` should be called directly. + Returns: LoggingContext: the current logging context """ diff --git a/synapse/module_api/__init__.py b/synapse/module_api/__init__.py
index 6d8bf54083..18d6d1058a 100644 --- a/synapse/module_api/__init__.py +++ b/synapse/module_api/__init__.py
@@ -1452,6 +1452,30 @@ class ModuleApi: 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: """Contains methods for adding to, removing from and querying whether a room diff --git a/synapse/rest/client/register.py b/synapse/rest/client/register.py
index b7ab090bbd..956c45e60a 100644 --- a/synapse/rest/client/register.py +++ b/synapse/rest/client/register.py
@@ -33,7 +33,7 @@ from synapse.api.ratelimiting import Ratelimiter from synapse.config import ConfigError from synapse.config.emailconfig import ThreepidBehaviour 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.handlers.auth import AuthHandler from synapse.handlers.ui_auth import UIAuthSessionDataConstants @@ -325,7 +325,7 @@ class UsernameAvailabilityRestServlet(RestServlet): self.registration_handler = hs.get_registration_handler() self.ratelimiter = FederationRateLimiter( hs.get_clock(), - FederationRateLimitConfig( + FederationRatelimitSettings( # Time window of 2s window_size=2000, # Artificially delay requests if rate > sleep_limit/window_size diff --git a/synapse/streams/events.py b/synapse/streams/events.py
index 54e0b1a23b..047203e2f0 100644 --- a/synapse/streams/events.py +++ b/synapse/streams/events.py
@@ -21,6 +21,7 @@ from synapse.handlers.presence import PresenceEventSource from synapse.handlers.receipts import ReceiptEventSource from synapse.handlers.room import RoomEventSource from synapse.handlers.typing import TypingNotificationEventSource +from synapse.logging.tracing import trace from synapse.streams import EventSource from synapse.types import StreamToken @@ -69,6 +70,7 @@ class EventSources: ) return token + @trace 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 events. diff --git a/synapse/util/ratelimitutils.py b/synapse/util/ratelimitutils.py
index dfe628c97e..6394cc39ac 100644 --- a/synapse/util/ratelimitutils.py +++ b/synapse/util/ratelimitutils.py
@@ -21,7 +21,7 @@ from typing import Any, DefaultDict, Iterator, List, Set from twisted.internet import defer from synapse.api.errors import LimitExceededError -from synapse.config.ratelimiting import FederationRateLimitConfig +from synapse.config.ratelimiting import FederationRatelimitSettings from synapse.logging.context import ( PreserveLoggingContext, make_deferred_yieldable, @@ -36,7 +36,7 @@ logger = logging.getLogger(__name__) class FederationRateLimiter: - def __init__(self, clock: Clock, config: FederationRateLimitConfig): + def __init__(self, clock: Clock, config: FederationRatelimitSettings): def new_limiter() -> "_PerHostRatelimiter": return _PerHostRatelimiter(clock=clock, config=config) @@ -63,7 +63,7 @@ class FederationRateLimiter: class _PerHostRatelimiter: - def __init__(self, clock: Clock, config: FederationRateLimitConfig): + def __init__(self, clock: Clock, config: FederationRatelimitSettings): """ Args: clock diff --git a/tests/logging/test_tracing.py b/tests/logging/test_tracing.py
index 25a617ea6d..a2065d75de 100644 --- a/tests/logging/test_tracing.py +++ b/tests/logging/test_tracing.py
@@ -139,10 +139,10 @@ class TracingTestCase(TestCase): with start_active_span( f"task{i}", tracer=self._tracer, - ) as span1: - self.assertEqual(opentelemetry.trace.get_current_span(), span1) + ) as span: + self.assertEqual(opentelemetry.trace.get_current_span(), span) await clock.sleep(4) - self.assertEqual(opentelemetry.trace.get_current_span(), span1) + self.assertEqual(opentelemetry.trace.get_current_span(), span) async def root(): 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) # start the test off - d1 = defer.ensureDeferred(root()) + root_defferred = defer.ensureDeferred(root()) # let the tasks complete reactor.pump((2,) * 8) - self.successResultOf(d1) + self.successResultOf(root_defferred) # Active span is unset now that we're outside of the `with` scopes self.assertEqual( opentelemetry.trace.get_current_span(), opentelemetry.trace.INVALID_SPAN diff --git a/tests/module_api/test_api.py b/tests/module_api/test_api.py
index 169e29b590..8e05590230 100644 --- a/tests/module_api/test_api.py +++ b/tests/module_api/test_api.py
@@ -635,6 +635,25 @@ class ModuleApiTestCase(HomeserverTestCase): [{"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): """For testing ModuleApi functionality in a multi-worker setup""" diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py
index 623883b53c..989cbdb5e2 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py
@@ -1772,6 +1772,21 @@ class RoomTestCase(unittest.HomeserverTestCase): 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):