From 04d7f56f53d7d5530ce7470bc51fcf0b43facf85 Mon Sep 17 00:00:00 2001
From: Will Hunt
Date: Wed, 19 Oct 2022 11:41:25 +0100
Subject: [PATCH 01/57] Use backend-meta edition of issue triage workflow
(#14230)
---
.github/workflows/triage-incoming.yml | 29 ++++++++-------------------
changelog.d/14230.misc | 1 +
2 files changed, 9 insertions(+), 21 deletions(-)
create mode 100644 changelog.d/14230.misc
diff --git a/.github/workflows/triage-incoming.yml b/.github/workflows/triage-incoming.yml
index f926bcb75959..0f0397cf5bc6 100644
--- a/.github/workflows/triage-incoming.yml
+++ b/.github/workflows/triage-incoming.yml
@@ -5,24 +5,11 @@ on:
types: [ opened ]
jobs:
- add_new_issues:
- name: Add new issues to the triage board
- runs-on: ubuntu-latest
- steps:
- - uses: octokit/graphql-action@v2.x
- id: add_to_project
- with:
- headers: '{"GraphQL-Features": "projects_next_graphql"}'
- query: |
- mutation add_to_project($projectid:ID!,$contentid:ID!) {
- addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
- item {
- id
- }
- }
- }
- projectid: ${{ env.PROJECT_ID }}
- contentid: ${{ github.event.issue.node_id }}
- env:
- PROJECT_ID: "PVT_kwDOAIB0Bs4AFDdZ"
- GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
+ triage:
+ uses: matrix-org/backend-meta/.github/workflows/triage-incoming.yml@v1
+ with:
+ project_id: 'PVT_kwDOAIB0Bs4AFDdZ'
+ content_id: ${{ github.event.issue.node_id }}
+ secrets:
+ github_access_token: ${{ secrets.ELEMENT_BOT_TOKEN }}
+
diff --git a/changelog.d/14230.misc b/changelog.d/14230.misc
new file mode 100644
index 000000000000..c9b4b112cb56
--- /dev/null
+++ b/changelog.d/14230.misc
@@ -0,0 +1 @@
+Switch to using the `matrix-org/backend-meta` version of `triage-incoming` for new issues in CI.
From fe50738e597817735aa910e3cd1e13e4792f7d9f Mon Sep 17 00:00:00 2001
From: Finn
Date: Wed, 19 Oct 2022 11:08:40 -0700
Subject: [PATCH 02/57] let update_synapse_database run on a multi-database
configurations (#13422)
* Allow sharded database in db migrate script
Signed-off-by: Finn Herzfeld
* Update changelog.d/13422.bugfix
Co-authored-by: Patrick Cloke
* Remove check entirely
* remove unused import
Signed-off-by: Finn Herzfeld
Co-authored-by: finn
Co-authored-by: Patrick Cloke
---
changelog.d/13422.bugfix | 1 +
synapse/_scripts/update_synapse_database.py | 8 --------
2 files changed, 1 insertion(+), 8 deletions(-)
create mode 100644 changelog.d/13422.bugfix
mode change 100755 => 100644 synapse/_scripts/update_synapse_database.py
diff --git a/changelog.d/13422.bugfix b/changelog.d/13422.bugfix
new file mode 100644
index 000000000000..3a099acbe6b8
--- /dev/null
+++ b/changelog.d/13422.bugfix
@@ -0,0 +1 @@
+Fix a long-standing bug where the `update_synapse_database` script could not be run with multiple databases. Contributed by @thefinn93 @ Beeper.
\ No newline at end of file
diff --git a/synapse/_scripts/update_synapse_database.py b/synapse/_scripts/update_synapse_database.py
old mode 100755
new mode 100644
index fb1fb83f50d9..0adf94bba68f
--- a/synapse/_scripts/update_synapse_database.py
+++ b/synapse/_scripts/update_synapse_database.py
@@ -15,7 +15,6 @@
import argparse
import logging
-import sys
from typing import cast
import yaml
@@ -100,13 +99,6 @@ def main() -> None:
# Load, process and sanity-check the config.
hs_config = yaml.safe_load(args.database_config)
- if "database" not in hs_config and "databases" not in hs_config:
- sys.stderr.write(
- "The configuration file must have a 'database' or 'databases' section. "
- "See https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#database"
- )
- sys.exit(4)
-
config = HomeServerConfig()
config.parse_config_dict(hs_config, "", "")
From 695a85d1bc05d38592b811f38f724bc61d683b1c Mon Sep 17 00:00:00 2001
From: Matthew Hodgson
Date: Wed, 19 Oct 2022 20:17:37 +0100
Subject: [PATCH 03/57] Document encryption_enabled_by_default_for_room_type
under the right name (#14110)
* document encryption_enabled_by_default_for_room_type under the right name
* add changelog
* Update changelog.d/14110.doc
---
changelog.d/14110.doc | 1 +
docs/usage/configuration/config_documentation.md | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 changelog.d/14110.doc
diff --git a/changelog.d/14110.doc b/changelog.d/14110.doc
new file mode 100644
index 000000000000..0927e31e4fc7
--- /dev/null
+++ b/changelog.d/14110.doc
@@ -0,0 +1 @@
+Correct the name of the config option [`encryption_enabled_by_default_for_room_type`](https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#encryption_enabled_by_default_for_room_type).
diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md
index 7c91a3ac4e28..d81eda52c156 100644
--- a/docs/usage/configuration/config_documentation.md
+++ b/docs/usage/configuration/config_documentation.md
@@ -3385,7 +3385,7 @@ push:
Config options relating to rooms.
---
-### `encryption_enabled_by_default`
+### `encryption_enabled_by_default_for_room_type`
Controls whether locally-created rooms should be end-to-end encrypted by
default.
From 0b7830e457359ce651b293c8748bf636973404a9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 19 Oct 2022 19:38:24 +0000
Subject: [PATCH 04/57] Bump flake8-bugbear from 21.3.2 to 22.9.23 (#14042)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Erik Johnston
Co-authored-by: David Robertson
---
.flake8 | 9 ++++++++-
changelog.d/14042.misc | 1 +
poetry.lock | 8 ++++----
synapse/storage/databases/main/roommember.py | 4 ++--
synapse/util/caches/deferred_cache.py | 4 ++--
synapse/util/caches/descriptors.py | 2 +-
tests/federation/transport/test_client.py | 7 +++----
tests/util/caches/test_descriptors.py | 2 +-
8 files changed, 22 insertions(+), 15 deletions(-)
create mode 100644 changelog.d/14042.misc
diff --git a/.flake8 b/.flake8
index acb118c86e84..4c6a4d5843e2 100644
--- a/.flake8
+++ b/.flake8
@@ -8,4 +8,11 @@
# E203: whitespace before ':' (which is contrary to pep8?)
# E731: do not assign a lambda expression, use a def
# E501: Line too long (black enforces this for us)
-ignore=W503,W504,E203,E731,E501
+#
+# flake8-bugbear runs extra checks. Its error codes are described at
+# https://github.com/PyCQA/flake8-bugbear#list-of-warnings
+# B019: Use of functools.lru_cache or functools.cache on methods can lead to memory leaks
+# B023: Functions defined inside a loop must not use variables redefined in the loop
+# B024: Abstract base class with no abstract method.
+
+ignore=W503,W504,E203,E731,E501,B019,B023,B024
diff --git a/changelog.d/14042.misc b/changelog.d/14042.misc
new file mode 100644
index 000000000000..868d55e76a13
--- /dev/null
+++ b/changelog.d/14042.misc
@@ -0,0 +1 @@
+Bump flake8-bugbear from 21.3.2 to 22.9.23.
diff --git a/poetry.lock b/poetry.lock
index ed0b59fbe518..0a2f9ab69eca 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -260,7 +260,7 @@ pyflakes = ">=2.4.0,<2.5.0"
[[package]]
name = "flake8-bugbear"
-version = "21.3.2"
+version = "22.9.23"
description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
category = "dev"
optional = false
@@ -271,7 +271,7 @@ attrs = ">=19.2.0"
flake8 = ">=3.0.0"
[package.extras]
-dev = ["black", "coverage", "hypothesis", "hypothesmith"]
+dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"]
[[package]]
name = "flake8-comprehensions"
@@ -1826,8 +1826,8 @@ flake8 = [
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
]
flake8-bugbear = [
- {file = "flake8-bugbear-21.3.2.tar.gz", hash = "sha256:cadce434ceef96463b45a7c3000f23527c04ea4b531d16c7ac8886051f516ca0"},
- {file = "flake8_bugbear-21.3.2-py36.py37.py38-none-any.whl", hash = "sha256:5d6ccb0c0676c738a6e066b4d50589c408dcc1c5bf1d73b464b18b73cd6c05c2"},
+ {file = "flake8-bugbear-22.9.23.tar.gz", hash = "sha256:17b9623325e6e0dcdcc80ed9e4aa811287fcc81d7e03313b8736ea5733759937"},
+ {file = "flake8_bugbear-22.9.23-py3-none-any.whl", hash = "sha256:cd2779b2b7ada212d7a322814a1e5651f1868ab0d3f24cc9da66169ab8fda474"},
]
flake8-comprehensions = [
{file = "flake8-comprehensions-3.8.0.tar.gz", hash = "sha256:8e108707637b1d13734f38e03435984f6b7854fa6b5a4e34f93e69534be8e521"},
diff --git a/synapse/storage/databases/main/roommember.py b/synapse/storage/databases/main/roommember.py
index 2ed6ad754fcd..32e1e983a5da 100644
--- a/synapse/storage/databases/main/roommember.py
+++ b/synapse/storage/databases/main/roommember.py
@@ -707,8 +707,8 @@ async def get_rooms_for_users(
# 250 users is pretty arbitrary but the data can be quite large if users
# are in many rooms.
- for user_ids in batch_iter(user_ids, 250):
- all_user_rooms.update(await self._get_rooms_for_users(user_ids))
+ for batch_user_ids in batch_iter(user_ids, 250):
+ all_user_rooms.update(await self._get_rooms_for_users(batch_user_ids))
return all_user_rooms
diff --git a/synapse/util/caches/deferred_cache.py b/synapse/util/caches/deferred_cache.py
index 6425f851eaa4..bcb1cba3620a 100644
--- a/synapse/util/caches/deferred_cache.py
+++ b/synapse/util/caches/deferred_cache.py
@@ -395,8 +395,8 @@ def invalidate(self, key: KT) -> None:
# _pending_deferred_cache.pop should either return a CacheEntry, or, in the
# case of a TreeCache, a dict of keys to cache entries. Either way calling
# iterate_tree_cache_entry on it will do the right thing.
- for entry in iterate_tree_cache_entry(entry):
- for cb in entry.get_invalidation_callbacks(key):
+ for iter_entry in iterate_tree_cache_entry(entry):
+ for cb in iter_entry.get_invalidation_callbacks(key):
cb()
def invalidate_all(self) -> None:
diff --git a/synapse/util/caches/descriptors.py b/synapse/util/caches/descriptors.py
index 0391966462e7..b3c748ef44dd 100644
--- a/synapse/util/caches/descriptors.py
+++ b/synapse/util/caches/descriptors.py
@@ -432,7 +432,7 @@ def __get__(
num_args = cached_method.num_args
if num_args != self.num_args:
- raise Exception(
+ raise TypeError(
"Number of args (%s) does not match underlying cache_method_name=%s (%s)."
% (self.num_args, self.cached_method_name, num_args)
)
diff --git a/tests/federation/transport/test_client.py b/tests/federation/transport/test_client.py
index 0926e0583dca..dd4d1b56de96 100644
--- a/tests/federation/transport/test_client.py
+++ b/tests/federation/transport/test_client.py
@@ -17,6 +17,7 @@
from synapse.api.room_versions import RoomVersions
from synapse.federation.transport.client import SendJoinParser
+from synapse.util import ExceptionBundle
from tests.unittest import TestCase
@@ -121,10 +122,8 @@ def test_errors_closing_coroutines(self) -> None:
# Send half of the data to the parser
parser.write(serialisation[: len(serialisation) // 2])
- # Close the parser. There should be _some_ kind of exception, but it need not
- # be that RuntimeError directly. E.g. we might want to raise a wrapper
- # encompassing multiple errors from multiple coroutines.
- with self.assertRaises(Exception):
+ # Close the parser. There should be _some_ kind of exception.
+ with self.assertRaises(ExceptionBundle):
parser.finish()
# In any case, we should have tried to close both coros.
diff --git a/tests/util/caches/test_descriptors.py b/tests/util/caches/test_descriptors.py
index 90861fe522c2..78fd7b69615c 100644
--- a/tests/util/caches/test_descriptors.py
+++ b/tests/util/caches/test_descriptors.py
@@ -1037,5 +1037,5 @@ def list_fn(self, keys: Iterable[Tuple[str, str]]):
obj = Cls()
# Make sure this raises an error about the arg mismatch
- with self.assertRaises(Exception):
+ with self.assertRaises(TypeError):
obj.list_fn([("foo", "bar")])
From 3841900aaa8666d193bb6506397d331fbf958233 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 19 Oct 2022 20:04:40 +0000
Subject: [PATCH 05/57] Bump types-opentracing from 2.4.7 to 2.4.10 (#14133)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions
Co-authored-by: reivilibre
---
changelog.d/14133.misc | 1 +
poetry.lock | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
create mode 100644 changelog.d/14133.misc
diff --git a/changelog.d/14133.misc b/changelog.d/14133.misc
new file mode 100644
index 000000000000..5180019c6823
--- /dev/null
+++ b/changelog.d/14133.misc
@@ -0,0 +1 @@
+Bump types-opentracing from 2.4.7 to 2.4.10.
diff --git a/poetry.lock b/poetry.lock
index 0a2f9ab69eca..2713cf2d69f6 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1426,7 +1426,7 @@ python-versions = "*"
[[package]]
name = "types-opentracing"
-version = "2.4.7"
+version = "2.4.10"
description = "Typing stubs for opentracing"
category = "dev"
optional = false
@@ -2767,8 +2767,8 @@ types-jsonschema = [
{file = "types_jsonschema-4.4.6-py3-none-any.whl", hash = "sha256:1db9031ca49a8444d01bd2ce8cf2f89318382b04610953b108321e6f8fb03390"},
]
types-opentracing = [
- {file = "types-opentracing-2.4.7.tar.gz", hash = "sha256:be60e9618355aa892571ace002e6b353702538b1c0dc4fbc1c921219d6658830"},
- {file = "types_opentracing-2.4.7-py3-none-any.whl", hash = "sha256:861fb8103b07cf717f501dd400cb274ca9992552314d4d6c7a824b11a215e512"},
+ {file = "types-opentracing-2.4.10.tar.gz", hash = "sha256:6101414f3b6d3b9c10f1c510a261e8439b6c8d67c723d5c2872084697b4580a7"},
+ {file = "types_opentracing-2.4.10-py3-none-any.whl", hash = "sha256:66d9cfbbdc4a6f8ca8189a15ad26f0fe41cee84c07057759c5d194e2505b84c2"},
]
types-pillow = [
{file = "types-Pillow-9.2.2.1.tar.gz", hash = "sha256:85c139e06e1c46ec5f9c634d5c54a156b0958d5d0e8be024ed353db0c804b426"},
From 70b33965065f0e93eaba68e371896149c9405f51 Mon Sep 17 00:00:00 2001
From: Eric Eastwood
Date: Wed, 19 Oct 2022 15:39:43 -0500
Subject: [PATCH 06/57] Explain `SynapseError` and `FederationError` better
(#14191)
Explain `SynapseError` and `FederationError` better
Spawning from https://github.com/matrix-org/synapse/pull/13816#discussion_r993262622
---
changelog.d/14191.doc | 1 +
synapse/api/errors.py | 24 +++++++++++++++++++++---
synapse/federation/federation_server.py | 8 ++++++++
3 files changed, 30 insertions(+), 3 deletions(-)
create mode 100644 changelog.d/14191.doc
diff --git a/changelog.d/14191.doc b/changelog.d/14191.doc
new file mode 100644
index 000000000000..6b0eeb1ae165
--- /dev/null
+++ b/changelog.d/14191.doc
@@ -0,0 +1 @@
+Update docstrings of `SynapseError` and `FederationError` to bettter describe what they are used for and the effects of using them are.
diff --git a/synapse/api/errors.py b/synapse/api/errors.py
index e0873b191309..400dd12aba7e 100644
--- a/synapse/api/errors.py
+++ b/synapse/api/errors.py
@@ -155,7 +155,13 @@ def __init__(self, location: bytes, http_code: int = http.FOUND):
class SynapseError(CodeMessageException):
"""A base exception type for matrix errors which have an errcode and error
- message (as well as an HTTP status code).
+ message (as well as an HTTP status code). These often bubble all the way up to the
+ client API response so the error code and status often reach the client directly as
+ defined here. If the error doesn't make sense to present to a client, then it
+ probably shouldn't be a `SynapseError`. For example, if we contact another
+ homeserver over federation, we shouldn't automatically ferry response errors back to
+ the client on our end (a 500 from a remote server does not make sense to a client
+ when our server did not experience a 500).
Attributes:
errcode: Matrix error code e.g 'M_FORBIDDEN'
@@ -600,8 +606,20 @@ def cs_error(msg: str, code: str = Codes.UNKNOWN, **kwargs: Any) -> "JsonDict":
class FederationError(RuntimeError):
- """This class is used to inform remote homeservers about erroneous
- PDUs they sent us.
+ """
+ Raised when we process an erroneous PDU.
+
+ There are two kinds of scenarios where this exception can be raised:
+
+ 1. We may pull an invalid PDU from a remote homeserver (e.g. during backfill). We
+ raise this exception to signal an error to the rest of the application.
+ 2. We may be pushed an invalid PDU as part of a `/send` transaction from a remote
+ homeserver. We raise so that we can respond to the transaction and include the
+ error string in the "PDU Processing Result". The message which will likely be
+ ignored by the remote homeserver and is not machine parse-able since it's just a
+ string.
+
+ TODO: In the future, we should split these usage scenarios into their own error types.
FATAL: The remote server could not interpret the source event.
(e.g., it was missing a required field)
diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py
index 28097664b4d6..59e351595be3 100644
--- a/synapse/federation/federation_server.py
+++ b/synapse/federation/federation_server.py
@@ -481,6 +481,14 @@ async def process_pdus_for_room(room_id: str) -> None:
pdu_results[pdu.event_id] = await process_pdu(pdu)
async def process_pdu(pdu: EventBase) -> JsonDict:
+ """
+ Processes a pushed PDU sent to us via a `/send` transaction
+
+ Returns:
+ JsonDict representing a "PDU Processing Result" that will be bundled up
+ with the other processed PDU's in the `/send` transaction and sent back
+ to remote homeserver.
+ """
event_id = pdu.event_id
with nested_logging_context(event_id):
try:
From da2c93d4b69200c1ea9fb94ec3c951fd4b424864 Mon Sep 17 00:00:00 2001
From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
Date: Thu, 20 Oct 2022 15:17:45 +0100
Subject: [PATCH 07/57] Stop returning `unsigned.invite_room_state` in `PUT
/_matrix/federation/v2/invite/{roomId}/{eventId}` responses (#14064)
Co-authored-by: David Robertson
---
changelog.d/14064.bugfix | 1 +
synapse/federation/transport/server/federation.py | 5 +++++
2 files changed, 6 insertions(+)
create mode 100644 changelog.d/14064.bugfix
diff --git a/changelog.d/14064.bugfix b/changelog.d/14064.bugfix
new file mode 100644
index 000000000000..cce6ef3b710c
--- /dev/null
+++ b/changelog.d/14064.bugfix
@@ -0,0 +1 @@
+ Fix a long-standing bug where Synapse would accidentally include extra information in the response to [`PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`](https://spec.matrix.org/v1.4/server-server-api/#put_matrixfederationv2inviteroomideventid).
\ No newline at end of file
diff --git a/synapse/federation/transport/server/federation.py b/synapse/federation/transport/server/federation.py
index 6f11138b57dd..205fd16daa98 100644
--- a/synapse/federation/transport/server/federation.py
+++ b/synapse/federation/transport/server/federation.py
@@ -499,6 +499,11 @@ async def on_PUT(
result = await self.handler.on_invite_request(
origin, event, room_version_id=room_version
)
+
+ # We only store invite_room_state for internal use, so remove it before
+ # returning the event to the remote homeserver.
+ result["event"].get("unsigned", {}).pop("invite_room_state", None)
+
return 200, result
From 755bfeee3a1ac7077045ab9e5a994b6ca89afba3 Mon Sep 17 00:00:00 2001
From: Patrick Cloke
Date: Thu, 20 Oct 2022 11:32:47 -0400
Subject: [PATCH 08/57] Use servlets for /key/ endpoints. (#14229)
To fix the response for unknown endpoints under that prefix.
See MSC3743.
---
changelog.d/14229.misc | 1 +
synapse/api/urls.py | 2 +-
synapse/app/generic_worker.py | 20 ++---
synapse/app/homeserver.py | 26 +++----
synapse/rest/key/v2/__init__.py | 19 +++--
synapse/rest/key/v2/local_key_resource.py | 22 +++---
synapse/rest/key/v2/remote_key_resource.py | 73 +++++++++++--------
tests/app/test_openid_listener.py | 2 +-
tests/rest/key/v2/test_remote_key_resource.py | 4 +-
9 files changed, 86 insertions(+), 83 deletions(-)
create mode 100644 changelog.d/14229.misc
diff --git a/changelog.d/14229.misc b/changelog.d/14229.misc
new file mode 100644
index 000000000000..b9cd9a34d59a
--- /dev/null
+++ b/changelog.d/14229.misc
@@ -0,0 +1 @@
+Refactor `/key/` endpoints to use `RestServlet` classes.
diff --git a/synapse/api/urls.py b/synapse/api/urls.py
index bd49fa6a5f03..a918579f5051 100644
--- a/synapse/api/urls.py
+++ b/synapse/api/urls.py
@@ -28,7 +28,7 @@
FEDERATION_V2_PREFIX = FEDERATION_PREFIX + "/v2"
FEDERATION_UNSTABLE_PREFIX = FEDERATION_PREFIX + "/unstable"
STATIC_PREFIX = "/_matrix/static"
-SERVER_KEY_V2_PREFIX = "/_matrix/key/v2"
+SERVER_KEY_PREFIX = "/_matrix/key"
MEDIA_R0_PREFIX = "/_matrix/media/r0"
MEDIA_V3_PREFIX = "/_matrix/media/v3"
LEGACY_MEDIA_PREFIX = "/_matrix/media/v1"
diff --git a/synapse/app/generic_worker.py b/synapse/app/generic_worker.py
index dc49840f73f1..2a9f039367b9 100644
--- a/synapse/app/generic_worker.py
+++ b/synapse/app/generic_worker.py
@@ -28,7 +28,7 @@
LEGACY_MEDIA_PREFIX,
MEDIA_R0_PREFIX,
MEDIA_V3_PREFIX,
- SERVER_KEY_V2_PREFIX,
+ SERVER_KEY_PREFIX,
)
from synapse.app import _base
from synapse.app._base import (
@@ -89,7 +89,7 @@
RegistrationTokenValidityRestServlet,
)
from synapse.rest.health import HealthResource
-from synapse.rest.key.v2 import KeyApiV2Resource
+from synapse.rest.key.v2 import KeyResource
from synapse.rest.synapse.client import build_synapse_client_resource_tree
from synapse.rest.well_known import well_known_resource
from synapse.server import HomeServer
@@ -325,13 +325,13 @@ def _listen_http(self, listener_config: ListenerConfig) -> None:
presence.register_servlets(self, resource)
- resources.update({CLIENT_API_PREFIX: resource})
+ resources[CLIENT_API_PREFIX] = resource
resources.update(build_synapse_client_resource_tree(self))
- resources.update({"/.well-known": well_known_resource(self)})
+ resources["/.well-known"] = well_known_resource(self)
elif name == "federation":
- resources.update({FEDERATION_PREFIX: TransportLayerServer(self)})
+ resources[FEDERATION_PREFIX] = TransportLayerServer(self)
elif name == "media":
if self.config.media.can_load_media_repo:
media_repo = self.get_media_repository_resource()
@@ -359,16 +359,12 @@ def _listen_http(self, listener_config: ListenerConfig) -> None:
# Only load the openid resource separately if federation resource
# is not specified since federation resource includes openid
# resource.
- resources.update(
- {
- FEDERATION_PREFIX: TransportLayerServer(
- self, servlet_groups=["openid"]
- )
- }
+ resources[FEDERATION_PREFIX] = TransportLayerServer(
+ self, servlet_groups=["openid"]
)
if name in ["keys", "federation"]:
- resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)
+ resources[SERVER_KEY_PREFIX] = KeyResource(self)
if name == "replication":
resources[REPLICATION_PREFIX] = ReplicationRestResource(self)
diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index 883f2fd2ecd8..de3f08876f99 100644
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -31,7 +31,7 @@
LEGACY_MEDIA_PREFIX,
MEDIA_R0_PREFIX,
MEDIA_V3_PREFIX,
- SERVER_KEY_V2_PREFIX,
+ SERVER_KEY_PREFIX,
STATIC_PREFIX,
)
from synapse.app import _base
@@ -60,7 +60,7 @@
from synapse.rest import ClientRestResource
from synapse.rest.admin import AdminRestResource
from synapse.rest.health import HealthResource
-from synapse.rest.key.v2 import KeyApiV2Resource
+from synapse.rest.key.v2 import KeyResource
from synapse.rest.synapse.client import build_synapse_client_resource_tree
from synapse.rest.well_known import well_known_resource
from synapse.server import HomeServer
@@ -215,30 +215,22 @@ def _configure_named_resource(
consent_resource: Resource = ConsentResource(self)
if compress:
consent_resource = gz_wrap(consent_resource)
- resources.update({"/_matrix/consent": consent_resource})
+ resources["/_matrix/consent"] = consent_resource
if name == "federation":
federation_resource: Resource = TransportLayerServer(self)
if compress:
federation_resource = gz_wrap(federation_resource)
- resources.update({FEDERATION_PREFIX: federation_resource})
+ resources[FEDERATION_PREFIX] = federation_resource
if name == "openid":
- resources.update(
- {
- FEDERATION_PREFIX: TransportLayerServer(
- self, servlet_groups=["openid"]
- )
- }
+ resources[FEDERATION_PREFIX] = TransportLayerServer(
+ self, servlet_groups=["openid"]
)
if name in ["static", "client"]:
- resources.update(
- {
- STATIC_PREFIX: StaticResource(
- os.path.join(os.path.dirname(synapse.__file__), "static")
- )
- }
+ resources[STATIC_PREFIX] = StaticResource(
+ os.path.join(os.path.dirname(synapse.__file__), "static")
)
if name in ["media", "federation", "client"]:
@@ -257,7 +249,7 @@ def _configure_named_resource(
)
if name in ["keys", "federation"]:
- resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)
+ resources[SERVER_KEY_PREFIX] = KeyResource(self)
if name == "metrics" and self.config.metrics.enable_metrics:
metrics_resource: Resource = MetricsResource(RegistryProxy)
diff --git a/synapse/rest/key/v2/__init__.py b/synapse/rest/key/v2/__init__.py
index 7f8c1de1ff50..26403facb84c 100644
--- a/synapse/rest/key/v2/__init__.py
+++ b/synapse/rest/key/v2/__init__.py
@@ -14,17 +14,20 @@
from typing import TYPE_CHECKING
-from twisted.web.resource import Resource
-
-from .local_key_resource import LocalKey
-from .remote_key_resource import RemoteKey
+from synapse.http.server import HttpServer, JsonResource
+from synapse.rest.key.v2.local_key_resource import LocalKey
+from synapse.rest.key.v2.remote_key_resource import RemoteKey
if TYPE_CHECKING:
from synapse.server import HomeServer
-class KeyApiV2Resource(Resource):
+class KeyResource(JsonResource):
def __init__(self, hs: "HomeServer"):
- Resource.__init__(self)
- self.putChild(b"server", LocalKey(hs))
- self.putChild(b"query", RemoteKey(hs))
+ super().__init__(hs, canonical_json=True)
+ self.register_servlets(self, hs)
+
+ @staticmethod
+ def register_servlets(http_server: HttpServer, hs: "HomeServer") -> None:
+ LocalKey(hs).register(http_server)
+ RemoteKey(hs).register(http_server)
diff --git a/synapse/rest/key/v2/local_key_resource.py b/synapse/rest/key/v2/local_key_resource.py
index 095993415c3e..d03e728d4208 100644
--- a/synapse/rest/key/v2/local_key_resource.py
+++ b/synapse/rest/key/v2/local_key_resource.py
@@ -13,16 +13,15 @@
# limitations under the License.
import logging
-from typing import TYPE_CHECKING, Optional
+import re
+from typing import TYPE_CHECKING, Optional, Tuple
-from canonicaljson import encode_canonical_json
from signedjson.sign import sign_json
from unpaddedbase64 import encode_base64
-from twisted.web.resource import Resource
+from twisted.web.server import Request
-from synapse.http.server import respond_with_json_bytes
-from synapse.http.site import SynapseRequest
+from synapse.http.servlet import RestServlet
from synapse.types import JsonDict
if TYPE_CHECKING:
@@ -31,7 +30,7 @@
logger = logging.getLogger(__name__)
-class LocalKey(Resource):
+class LocalKey(RestServlet):
"""HTTP resource containing encoding the TLS X.509 certificate and NACL
signature verification keys for this server::
@@ -61,18 +60,17 @@ class LocalKey(Resource):
}
"""
- isLeaf = True
+ PATTERNS = (re.compile("^/_matrix/key/v2/server(/(?P[^/]*))?$"),)
def __init__(self, hs: "HomeServer"):
self.config = hs.config
self.clock = hs.get_clock()
self.update_response_body(self.clock.time_msec())
- Resource.__init__(self)
def update_response_body(self, time_now_msec: int) -> None:
refresh_interval = self.config.key.key_refresh_interval
self.valid_until_ts = int(time_now_msec + refresh_interval)
- self.response_body = encode_canonical_json(self.response_json_object())
+ self.response_body = self.response_json_object()
def response_json_object(self) -> JsonDict:
verify_keys = {}
@@ -99,9 +97,11 @@ def response_json_object(self) -> JsonDict:
json_object = sign_json(json_object, self.config.server.server_name, key)
return json_object
- def render_GET(self, request: SynapseRequest) -> Optional[int]:
+ def on_GET(
+ self, request: Request, key_id: Optional[str] = None
+ ) -> Tuple[int, JsonDict]:
time_now = self.clock.time_msec()
# Update the expiry time if less than half the interval remains.
if time_now + self.config.key.key_refresh_interval / 2 > self.valid_until_ts:
self.update_response_body(time_now)
- return respond_with_json_bytes(request, 200, self.response_body)
+ return 200, self.response_body
diff --git a/synapse/rest/key/v2/remote_key_resource.py b/synapse/rest/key/v2/remote_key_resource.py
index 7f8ad29566a4..19820886f536 100644
--- a/synapse/rest/key/v2/remote_key_resource.py
+++ b/synapse/rest/key/v2/remote_key_resource.py
@@ -13,15 +13,20 @@
# limitations under the License.
import logging
-from typing import TYPE_CHECKING, Dict, Set
+import re
+from typing import TYPE_CHECKING, Dict, Optional, Set, Tuple
from signedjson.sign import sign_json
-from synapse.api.errors import Codes, SynapseError
+from twisted.web.server import Request
+
from synapse.crypto.keyring import ServerKeyFetcher
-from synapse.http.server import DirectServeJsonResource, respond_with_json
-from synapse.http.servlet import parse_integer, parse_json_object_from_request
-from synapse.http.site import SynapseRequest
+from synapse.http.server import HttpServer
+from synapse.http.servlet import (
+ RestServlet,
+ parse_integer,
+ parse_json_object_from_request,
+)
from synapse.types import JsonDict
from synapse.util import json_decoder
from synapse.util.async_helpers import yieldable_gather_results
@@ -32,7 +37,7 @@
logger = logging.getLogger(__name__)
-class RemoteKey(DirectServeJsonResource):
+class RemoteKey(RestServlet):
"""HTTP resource for retrieving the TLS certificate and NACL signature
verification keys for a collection of servers. Checks that the reported
X.509 TLS certificate matches the one used in the HTTPS connection. Checks
@@ -88,11 +93,7 @@ class RemoteKey(DirectServeJsonResource):
}
"""
- isLeaf = True
-
def __init__(self, hs: "HomeServer"):
- super().__init__()
-
self.fetcher = ServerKeyFetcher(hs)
self.store = hs.get_datastores().main
self.clock = hs.get_clock()
@@ -101,36 +102,48 @@ def __init__(self, hs: "HomeServer"):
)
self.config = hs.config
- async def _async_render_GET(self, request: SynapseRequest) -> None:
- assert request.postpath is not None
- if len(request.postpath) == 1:
- (server,) = request.postpath
- query: dict = {server.decode("ascii"): {}}
- elif len(request.postpath) == 2:
- server, key_id = request.postpath
+ def register(self, http_server: HttpServer) -> None:
+ http_server.register_paths(
+ "GET",
+ (
+ re.compile(
+ "^/_matrix/key/v2/query/(?P[^/]*)(/(?P[^/]*))?$"
+ ),
+ ),
+ self.on_GET,
+ self.__class__.__name__,
+ )
+ http_server.register_paths(
+ "POST",
+ (re.compile("^/_matrix/key/v2/query$"),),
+ self.on_POST,
+ self.__class__.__name__,
+ )
+
+ async def on_GET(
+ self, request: Request, server: str, key_id: Optional[str] = None
+ ) -> Tuple[int, JsonDict]:
+ if server and key_id:
minimum_valid_until_ts = parse_integer(request, "minimum_valid_until_ts")
arguments = {}
if minimum_valid_until_ts is not None:
arguments["minimum_valid_until_ts"] = minimum_valid_until_ts
- query = {server.decode("ascii"): {key_id.decode("ascii"): arguments}}
+ query = {server: {key_id: arguments}}
else:
- raise SynapseError(404, "Not found %r" % request.postpath, Codes.NOT_FOUND)
+ query = {server: {}}
- await self.query_keys(request, query, query_remote_on_cache_miss=True)
+ return 200, await self.query_keys(query, query_remote_on_cache_miss=True)
- async def _async_render_POST(self, request: SynapseRequest) -> None:
+ async def on_POST(self, request: Request) -> Tuple[int, JsonDict]:
content = parse_json_object_from_request(request)
query = content["server_keys"]
- await self.query_keys(request, query, query_remote_on_cache_miss=True)
+ return 200, await self.query_keys(query, query_remote_on_cache_miss=True)
async def query_keys(
- self,
- request: SynapseRequest,
- query: JsonDict,
- query_remote_on_cache_miss: bool = False,
- ) -> None:
+ self, query: JsonDict, query_remote_on_cache_miss: bool = False
+ ) -> JsonDict:
logger.info("Handling query for keys %r", query)
store_queries = []
@@ -232,7 +245,7 @@ async def query_keys(
for server_name, keys in cache_misses.items()
),
)
- await self.query_keys(request, query, query_remote_on_cache_miss=False)
+ return await self.query_keys(query, query_remote_on_cache_miss=False)
else:
signed_keys = []
for key_json_raw in json_results:
@@ -244,6 +257,4 @@ async def query_keys(
signed_keys.append(key_json)
- response = {"server_keys": signed_keys}
-
- respond_with_json(request, 200, response, canonical_json=True)
+ return {"server_keys": signed_keys}
diff --git a/tests/app/test_openid_listener.py b/tests/app/test_openid_listener.py
index c7dae58eb549..8d03da7f96a6 100644
--- a/tests/app/test_openid_listener.py
+++ b/tests/app/test_openid_listener.py
@@ -79,7 +79,7 @@ def test_openid_listener(self, names, expectation):
self.assertEqual(channel.code, 401)
-@patch("synapse.app.homeserver.KeyApiV2Resource", new=Mock())
+@patch("synapse.app.homeserver.KeyResource", new=Mock())
class SynapseHomeserverOpenIDListenerTests(HomeserverTestCase):
def make_homeserver(self, reactor, clock):
hs = self.setup_test_homeserver(
diff --git a/tests/rest/key/v2/test_remote_key_resource.py b/tests/rest/key/v2/test_remote_key_resource.py
index ac0ac06b7e18..7f1fba10869c 100644
--- a/tests/rest/key/v2/test_remote_key_resource.py
+++ b/tests/rest/key/v2/test_remote_key_resource.py
@@ -26,7 +26,7 @@
from synapse.crypto.keyring import PerspectivesKeyFetcher
from synapse.http.site import SynapseRequest
-from synapse.rest.key.v2 import KeyApiV2Resource
+from synapse.rest.key.v2 import KeyResource
from synapse.server import HomeServer
from synapse.storage.keys import FetchKeyResult
from synapse.types import JsonDict
@@ -46,7 +46,7 @@ def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:
def create_test_resource(self) -> Resource:
return create_resource_tree(
- {"/_matrix/key/v2": KeyApiV2Resource(self.hs)}, root_resource=NoResource()
+ {"/_matrix/key/v2": KeyResource(self.hs)}, root_resource=NoResource()
)
def expect_outgoing_key_request(
From cacda2d1f5cef3fcbb62e3db2a0b0a4a634c86dd Mon Sep 17 00:00:00 2001
From: David Robertson
Date: Thu, 20 Oct 2022 23:01:08 +0100
Subject: [PATCH 09/57] Build wheels on macos 11, not 10.15 (#14249)
---
.github/workflows/release-artifacts.yml | 6 +++---
changelog.d/14249.misc | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
create mode 100644 changelog.d/14249.misc
diff --git a/.github/workflows/release-artifacts.yml b/.github/workflows/release-artifacts.yml
index 60db6ad7f09d..0601a7dbaf15 100644
--- a/.github/workflows/release-artifacts.yml
+++ b/.github/workflows/release-artifacts.yml
@@ -99,7 +99,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [ubuntu-20.04, macos-10.15]
+ os: [ubuntu-20.04, macos-11]
arch: [x86_64, aarch64]
# is_pr is a flag used to exclude certain jobs from the matrix on PRs.
# It is not read by the rest of the workflow.
@@ -109,9 +109,9 @@ jobs:
exclude:
# Don't build macos wheels on PR CI.
- is_pr: true
- os: "macos-10.15"
+ os: "macos-11"
# Don't build aarch64 wheels on mac.
- - os: "macos-10.15"
+ - os: "macos-11"
arch: aarch64
# Don't build aarch64 wheels on PR CI.
- is_pr: true
diff --git a/changelog.d/14249.misc b/changelog.d/14249.misc
new file mode 100644
index 000000000000..3a2ce1e0c2a3
--- /dev/null
+++ b/changelog.d/14249.misc
@@ -0,0 +1 @@
+Build wheels on macos 11, not 10.15.
From fab495a9e1442d99e922367f65f41de5eaa488eb Mon Sep 17 00:00:00 2001
From: "DeepBlueV7.X"
Date: Fri, 21 Oct 2022 08:49:47 +0000
Subject: [PATCH 10/57] Fix event size checks (#13710)
---
changelog.d/13710.bugfix | 1 +
synapse/event_auth.py | 10 +++++-----
2 files changed, 6 insertions(+), 5 deletions(-)
create mode 100644 changelog.d/13710.bugfix
diff --git a/changelog.d/13710.bugfix b/changelog.d/13710.bugfix
new file mode 100644
index 000000000000..4c318d15f5ea
--- /dev/null
+++ b/changelog.d/13710.bugfix
@@ -0,0 +1 @@
+Fix a long-standing bug where Synapse would count codepoints instead of bytes when validating the size of some fields.
diff --git a/synapse/event_auth.py b/synapse/event_auth.py
index bab31e33c5e3..50366040369b 100644
--- a/synapse/event_auth.py
+++ b/synapse/event_auth.py
@@ -342,15 +342,15 @@ def check_state_dependent_auth_rules(
def _check_size_limits(event: "EventBase") -> None:
- if len(event.user_id) > 255:
+ if len(event.user_id.encode("utf-8")) > 255:
raise EventSizeError("'user_id' too large")
- if len(event.room_id) > 255:
+ if len(event.room_id.encode("utf-8")) > 255:
raise EventSizeError("'room_id' too large")
- if event.is_state() and len(event.state_key) > 255:
+ if event.is_state() and len(event.state_key.encode("utf-8")) > 255:
raise EventSizeError("'state_key' too large")
- if len(event.type) > 255:
+ if len(event.type.encode("utf-8")) > 255:
raise EventSizeError("'type' too large")
- if len(event.event_id) > 255:
+ if len(event.event_id.encode("utf-8")) > 255:
raise EventSizeError("'event_id' too large")
if len(encode_canonical_json(event.get_pdu_json())) > MAX_PDU_SIZE:
raise EventSizeError("event too large")
From 1433b5d5b64c3a6624e6e4ff4fef22127c49df86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?=
Date: Fri, 21 Oct 2022 14:52:44 +0200
Subject: [PATCH 11/57] Show erasure status when listing users in the Admin API
(#14205)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Show erasure status when listing users in the Admin API
* Use USING when joining erased_users
* Add changelog entry
* Revert "Use USING when joining erased_users"
This reverts commit 30bd2bf106415caadcfdbdd1b234ef2b106cc394.
* Make the erased check work on postgres
* Add a testcase for showing erased user status
* Appease the style linter
* Explicitly convert `erased` to bool to make SQLite consistent with Postgres
This also adds us an easy way in to fix the other accidentally integered columns.
* Move erasure status test to UsersListTestCase
* Include user erased status when fetching user info via the admin API
* Document the erase status in user_admin_api
* Appease the linter and mypy
* Signpost comments in tests
Co-authored-by: Tadeusz Sośnierz
Co-authored-by: David Robertson
---
changelog.d/14205.feature | 1 +
docs/admin_api/user_admin_api.md | 4 +++
synapse/handlers/admin.py | 1 +
synapse/storage/databases/main/__init__.py | 13 ++++++--
tests/rest/admin/test_user.py | 35 +++++++++++++++++++++-
5 files changed, 51 insertions(+), 3 deletions(-)
create mode 100644 changelog.d/14205.feature
diff --git a/changelog.d/14205.feature b/changelog.d/14205.feature
new file mode 100644
index 000000000000..6692063352ba
--- /dev/null
+++ b/changelog.d/14205.feature
@@ -0,0 +1 @@
+Show erasure status when listing users in the Admin API.
diff --git a/docs/admin_api/user_admin_api.md b/docs/admin_api/user_admin_api.md
index 3625c7b6c5f5..c95d6c9b0536 100644
--- a/docs/admin_api/user_admin_api.md
+++ b/docs/admin_api/user_admin_api.md
@@ -37,6 +37,7 @@ It returns a JSON body like the following:
"is_guest": 0,
"admin": 0,
"deactivated": 0,
+ "erased": false,
"shadow_banned": 0,
"creation_ts": 1560432506,
"appservice_id": null,
@@ -167,6 +168,7 @@ A response body like the following is returned:
"admin": 0,
"user_type": null,
"deactivated": 0,
+ "erased": false,
"shadow_banned": 0,
"displayname": "",
"avatar_url": null,
@@ -177,6 +179,7 @@ A response body like the following is returned:
"admin": 1,
"user_type": null,
"deactivated": 0,
+ "erased": false,
"shadow_banned": 0,
"displayname": "",
"avatar_url": "",
@@ -247,6 +250,7 @@ The following fields are returned in the JSON response body:
- `user_type` - string - Type of the user. Normal users are type `None`.
This allows user type specific behaviour. There are also types `support` and `bot`.
- `deactivated` - bool - Status if that user has been marked as deactivated.
+ - `erased` - bool - Status if that user has been marked as erased.
- `shadow_banned` - bool - Status if that user has been marked as shadow banned.
- `displayname` - string - The user's display name if they have set one.
- `avatar_url` - string - The user's avatar URL if they have set one.
diff --git a/synapse/handlers/admin.py b/synapse/handlers/admin.py
index f2989cc4a214..5bf8e863875b 100644
--- a/synapse/handlers/admin.py
+++ b/synapse/handlers/admin.py
@@ -100,6 +100,7 @@ async def get_user(self, user: UserID) -> Optional[JsonDict]:
user_info_dict["avatar_url"] = profile.avatar_url
user_info_dict["threepids"] = threepids
user_info_dict["external_ids"] = external_ids
+ user_info_dict["erased"] = await self.store.is_user_erased(user.to_string())
return user_info_dict
diff --git a/synapse/storage/databases/main/__init__.py b/synapse/storage/databases/main/__init__.py
index a62b4abd4e24..cfaedf5e0ca9 100644
--- a/synapse/storage/databases/main/__init__.py
+++ b/synapse/storage/databases/main/__init__.py
@@ -201,7 +201,7 @@ async def get_users_paginate(
name: Optional[str] = None,
guests: bool = True,
deactivated: bool = False,
- order_by: str = UserSortOrder.USER_ID.value,
+ order_by: str = UserSortOrder.NAME.value,
direction: str = "f",
approved: bool = True,
) -> Tuple[List[JsonDict], int]:
@@ -261,6 +261,7 @@ def get_users_paginate_txn(
sql_base = f"""
FROM users as u
LEFT JOIN profiles AS p ON u.name = '@' || p.user_id || ':' || ?
+ LEFT JOIN erased_users AS eu ON u.name = eu.user_id
{where_clause}
"""
sql = "SELECT COUNT(*) as total_users " + sql_base
@@ -269,7 +270,8 @@ def get_users_paginate_txn(
sql = f"""
SELECT name, user_type, is_guest, admin, deactivated, shadow_banned,
- displayname, avatar_url, creation_ts * 1000 as creation_ts, approved
+ displayname, avatar_url, creation_ts * 1000 as creation_ts, approved,
+ eu.user_id is not null as erased
{sql_base}
ORDER BY {order_by_column} {order}, u.name ASC
LIMIT ? OFFSET ?
@@ -277,6 +279,13 @@ def get_users_paginate_txn(
args += [limit, start]
txn.execute(sql, args)
users = self.db_pool.cursor_to_dict(txn)
+
+ # some of those boolean values are returned as integers when we're on SQLite
+ columns_to_boolify = ["erased"]
+ for user in users:
+ for column in columns_to_boolify:
+ user[column] = bool(user[column])
+
return users, count
return await self.db_pool.runInteraction(
diff --git a/tests/rest/admin/test_user.py b/tests/rest/admin/test_user.py
index 4c1ce33463a9..63410ffdf14b 100644
--- a/tests/rest/admin/test_user.py
+++ b/tests/rest/admin/test_user.py
@@ -31,7 +31,7 @@
from synapse.rest.client import devices, login, logout, profile, register, room, sync
from synapse.rest.media.v1.filepath import MediaFilePaths
from synapse.server import HomeServer
-from synapse.types import JsonDict, UserID
+from synapse.types import JsonDict, UserID, create_requester
from synapse.util import Clock
from tests import unittest
@@ -924,6 +924,36 @@ def test_filter_out_approved(self) -> None:
self.assertEqual(1, len(non_admin_user_ids), non_admin_user_ids)
self.assertEqual(not_approved_user, non_admin_user_ids[0])
+ def test_erasure_status(self) -> None:
+ # Create a new user.
+ user_id = self.register_user("eraseme", "eraseme")
+
+ # They should appear in the list users API, marked as not erased.
+ channel = self.make_request(
+ "GET",
+ self.url + "?deactivated=true",
+ access_token=self.admin_user_tok,
+ )
+ users = {user["name"]: user for user in channel.json_body["users"]}
+ self.assertIs(users[user_id]["erased"], False)
+
+ # Deactivate that user, requesting erasure.
+ deactivate_account_handler = self.hs.get_deactivate_account_handler()
+ self.get_success(
+ deactivate_account_handler.deactivate_account(
+ user_id, erase_data=True, requester=create_requester(user_id)
+ )
+ )
+
+ # Repeat the list users query. They should now be marked as erased.
+ channel = self.make_request(
+ "GET",
+ self.url + "?deactivated=true",
+ access_token=self.admin_user_tok,
+ )
+ users = {user["name"]: user for user in channel.json_body["users"]}
+ self.assertIs(users[user_id]["erased"], True)
+
def _order_test(
self,
expected_user_list: List[str],
@@ -1195,6 +1225,7 @@ def test_deactivate_user_erase_true(self) -> None:
self.assertEqual("foo@bar.com", channel.json_body["threepids"][0]["address"])
self.assertEqual("mxc://servername/mediaid", channel.json_body["avatar_url"])
self.assertEqual("User1", channel.json_body["displayname"])
+ self.assertFalse(channel.json_body["erased"])
# Deactivate and erase user
channel = self.make_request(
@@ -1219,6 +1250,7 @@ def test_deactivate_user_erase_true(self) -> None:
self.assertEqual(0, len(channel.json_body["threepids"]))
self.assertIsNone(channel.json_body["avatar_url"])
self.assertIsNone(channel.json_body["displayname"])
+ self.assertTrue(channel.json_body["erased"])
self._is_erased("@user:test", True)
@@ -2757,6 +2789,7 @@ def _check_fields(self, content: JsonDict) -> None:
self.assertIn("avatar_url", content)
self.assertIn("admin", content)
self.assertIn("deactivated", content)
+ self.assertIn("erased", content)
self.assertIn("shadow_banned", content)
self.assertIn("creation_ts", content)
self.assertIn("appservice_id", content)
From d24346f53055eae7fb8e9038ef35fa843790742b Mon Sep 17 00:00:00 2001
From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Date: Fri, 21 Oct 2022 16:03:44 +0100
Subject: [PATCH 12/57] Fix logging error on SIGHUP (#14258)
---
changelog.d/14258.bugfix | 2 ++
synapse/app/_base.py | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 changelog.d/14258.bugfix
diff --git a/changelog.d/14258.bugfix b/changelog.d/14258.bugfix
new file mode 100644
index 000000000000..de979458449e
--- /dev/null
+++ b/changelog.d/14258.bugfix
@@ -0,0 +1,2 @@
+Fix a bug introduced in Synapse 1.60.0 which caused an error to be logged when Synapse received a SIGHUP signal, and debug logging was enabled.
+
diff --git a/synapse/app/_base.py b/synapse/app/_base.py
index 000912e86ee9..a683ebf4cbe9 100644
--- a/synapse/app/_base.py
+++ b/synapse/app/_base.py
@@ -558,7 +558,7 @@ def reload_cache_config(config: HomeServerConfig) -> None:
logger.warning(f)
else:
logger.debug(
- "New cache config. Was:\n %s\nNow:\n",
+ "New cache config. Was:\n %s\nNow:\n %s",
previous_cache_config.__dict__,
config.caches.__dict__,
)
From 1d45ad8b2ab1c41dd489ccd581d027077bc917e5 Mon Sep 17 00:00:00 2001
From: Germain
Date: Fri, 21 Oct 2022 18:44:00 +0100
Subject: [PATCH 13/57] Improve aesthetics and reusability of HTML templates.
(#13652)
Use a base template to create a cohesive feel across the HTML
templates provided by Synapse.
Adds basic styling to the base template for a more user-friendly
look and feel.
---
changelog.d/13652.feature | 1 +
synapse/res/templates/_base.html | 29 ++
.../templates/account_previously_renewed.html | 18 +-
synapse/res/templates/account_renewed.html | 18 +-
synapse/res/templates/add_threepid.html | 22 +-
.../res/templates/add_threepid_failure.html | 20 +-
.../res/templates/add_threepid_success.html | 18 +-
synapse/res/templates/auth_success.html | 28 +-
synapse/res/templates/invalid_token.html | 17 +-
synapse/res/templates/notice_expiry.html | 93 +++--
synapse/res/templates/notif_mail.html | 116 +++---
synapse/res/templates/password_reset.html | 19 +-
.../password_reset_confirmation.html | 14 +-
.../res/templates/password_reset_failure.html | 14 +-
.../res/templates/password_reset_success.html | 12 +-
synapse/res/templates/recaptcha.html | 19 +-
synapse/res/templates/registration.html | 21 +-
.../res/templates/registration_failure.html | 12 +-
.../res/templates/registration_success.html | 13 +-
synapse/res/templates/registration_token.html | 16 +-
.../templates/sso_account_deactivated.html | 49 ++-
.../templates/sso_auth_account_details.html | 372 +++++++++---------
synapse/res/templates/sso_auth_bad_user.html | 52 ++-
synapse/res/templates/sso_auth_confirm.html | 56 ++-
synapse/res/templates/sso_auth_success.html | 54 ++-
synapse/res/templates/sso_error.html | 34 +-
.../res/templates/sso_login_idp_picker.html | 114 +++---
.../res/templates/sso_new_user_consent.html | 60 ++-
.../res/templates/sso_redirect_confirm.html | 75 ++--
synapse/res/templates/style.css | 29 ++
synapse/res/templates/terms.html | 16 +-
31 files changed, 691 insertions(+), 740 deletions(-)
create mode 100644 changelog.d/13652.feature
create mode 100644 synapse/res/templates/_base.html
create mode 100644 synapse/res/templates/style.css
diff --git a/changelog.d/13652.feature b/changelog.d/13652.feature
new file mode 100644
index 000000000000..bc7f2926dc1d
--- /dev/null
+++ b/changelog.d/13652.feature
@@ -0,0 +1 @@
+Improve aesthetics of HTML templates. Note that these changes do not retroactively apply to templates which have been [customised](https://matrix-org.github.io/synapse/latest/templates.html#templates) by server admins.
\ No newline at end of file
diff --git a/synapse/res/templates/_base.html b/synapse/res/templates/_base.html
new file mode 100644
index 000000000000..46439fce6aa6
--- /dev/null
+++ b/synapse/res/templates/_base.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+ {% block title %}{% endblock %}
+
+ {% block header %}{% endblock %}
+
+
+
+ {% if app_name == "Riot" %}
+
+ {% elif app_name == "Vector" %}
+
+ {% elif app_name == "Element" %}
+
+ {% else %}
+
+ {% endif %}
+
+
+{% block body %}{% endblock %}
+
+
+
diff --git a/synapse/res/templates/account_previously_renewed.html b/synapse/res/templates/account_previously_renewed.html
index bd4f7cea97a0..91582a8af006 100644
--- a/synapse/res/templates/account_previously_renewed.html
+++ b/synapse/res/templates/account_previously_renewed.html
@@ -1,12 +1,6 @@
-
-
-
-
-
-
- Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
-
-
- Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
-
-
\ No newline at end of file
+{% extends "_base.html" %}
+{% block title %}Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.{% endblock %}
+
+{% block body %}
+
Your account is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
+{% endblock %}
diff --git a/synapse/res/templates/account_renewed.html b/synapse/res/templates/account_renewed.html
index 57b319f37584..18a57833f1f0 100644
--- a/synapse/res/templates/account_renewed.html
+++ b/synapse/res/templates/account_renewed.html
@@ -1,12 +1,6 @@
-
-
-
-
-
-
- Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
-
-
- Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
-
-
\ No newline at end of file
+{% extends "_base.html" %}
+{% block title %}Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.{% endblock %}
+
+{% block body %}
+
Your account has been successfully renewed and is valid until {{ expiration_ts|format_ts("%d-%m-%Y") }}.
+{% endblock %}
diff --git a/synapse/res/templates/add_threepid.html b/synapse/res/templates/add_threepid.html
index 71f2215b7aea..33c883936ac1 100644
--- a/synapse/res/templates/add_threepid.html
+++ b/synapse/res/templates/add_threepid.html
@@ -1,14 +1,8 @@
-
-
-
-
-
-
- Request to add an email address to your Matrix account
-
-
-
A request to add an email address to your Matrix account has been received. If this was you, please click the link below to confirm adding this email:
Validation failed for the following reason: {{ failure_reason }}.
-
-
+{% endblock %}
diff --git a/synapse/res/templates/registration_success.html b/synapse/res/templates/registration_success.html
index d51d5549d85b..e2dd020a9edf 100644
--- a/synapse/res/templates/registration_success.html
+++ b/synapse/res/templates/registration_success.html
@@ -1,10 +1,5 @@
-
-
- Your email has now been validated
-
-
-
-
+{% block title %}Your email has now been validated{% endblock %}
+
+{% block body %}
Your email has now been validated, please return to your client. You may now close this window.
- Your account might have been deactivated by the server administrator.
- You can either try to create a new account or contact the server’s
- administrator.
-
-
- {% include "sso_footer.html" without context %}
-
-
+{% block title %}SSO account deactivated{% endblock %}
+
+{% block header %}
+
+{% endblock %}
+
+{% block body %}
+
+
+
Your account has been deactivated
+
+ No account found
+
+
+ Your account might have been deactivated by the server administrator.
+ You can either try to create a new account or contact the server’s
+ administrator.
+
+
+
+{% include "sso_footer.html" without context %}
+{% endblock %}
diff --git a/synapse/res/templates/sso_auth_account_details.html b/synapse/res/templates/sso_auth_account_details.html
index 2d1db386e1b4..b51633337306 100644
--- a/synapse/res/templates/sso_auth_account_details.html
+++ b/synapse/res/templates/sso_auth_account_details.html
@@ -1,189 +1,185 @@
-
-
-
- Create your account
-
-
-
-
-
-
-
-
-
Create your account
-
This is required. Continue to create your account on {{ server_name }}. You can't change this later.