From 8e1e62c9e010014cf0d46065de21c82a293cf9a1 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 21 Nov 2023 15:29:58 -0500 Subject: Update license headers --- tests/rest/admin/__init__.py | 26 ++++++++++++++++---------- tests/rest/admin/test_admin.py | 26 ++++++++++++++++---------- tests/rest/admin/test_background_updates.py | 26 ++++++++++++++++---------- tests/rest/admin/test_device.py | 26 ++++++++++++++++---------- tests/rest/admin/test_event_reports.py | 26 ++++++++++++++++---------- tests/rest/admin/test_federation.py | 26 ++++++++++++++++---------- tests/rest/admin/test_jwks.py | 26 ++++++++++++++++---------- tests/rest/admin/test_media.py | 27 ++++++++++++++++----------- tests/rest/admin/test_registration_tokens.py | 26 ++++++++++++++++---------- tests/rest/admin/test_room.py | 26 ++++++++++++++++---------- tests/rest/admin/test_server_notice.py | 26 ++++++++++++++++---------- tests/rest/admin/test_statistics.py | 27 ++++++++++++++++----------- tests/rest/admin/test_user.py | 26 ++++++++++++++++---------- tests/rest/admin/test_username_available.py | 26 ++++++++++++++++---------- 14 files changed, 224 insertions(+), 142 deletions(-) (limited to 'tests/rest/admin') diff --git a/tests/rest/admin/__init__.py b/tests/rest/admin/__init__.py index 743fb9904a..3d833a2e44 100644 --- a/tests/rest/admin/__init__.py +++ b/tests/rest/admin/__init__.py @@ -1,13 +1,19 @@ -# Copyright 2019 New Vector Ltd # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/tests/rest/admin/test_admin.py b/tests/rest/admin/test_admin.py index 8646b2f0fd..defccd7d12 100644 --- a/tests/rest/admin/test_admin.py +++ b/tests/rest/admin/test_admin.py @@ -1,16 +1,22 @@ -# Copyright 2018-2021 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. import urllib.parse from typing import Dict diff --git a/tests/rest/admin/test_background_updates.py b/tests/rest/admin/test_background_updates.py index d507a3af8d..caea9d4415 100644 --- a/tests/rest/admin/test_background_updates.py +++ b/tests/rest/admin/test_background_updates.py @@ -1,16 +1,22 @@ -# Copyright 2021 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. from typing import Collection from parameterized import parameterized diff --git a/tests/rest/admin/test_device.py b/tests/rest/admin/test_device.py index aaa488bced..c8f6fa105a 100644 --- a/tests/rest/admin/test_device.py +++ b/tests/rest/admin/test_device.py @@ -1,16 +1,22 @@ -# Copyright 2020 Dirk Klimpel # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. import urllib.parse from parameterized import parameterized diff --git a/tests/rest/admin/test_event_reports.py b/tests/rest/admin/test_event_reports.py index f189b07769..3e695e9700 100644 --- a/tests/rest/admin/test_event_reports.py +++ b/tests/rest/admin/test_event_reports.py @@ -1,16 +1,22 @@ -# Copyright 2020 Dirk Klimpel # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. from typing import List from twisted.test.proto_helpers import MemoryReactor diff --git a/tests/rest/admin/test_federation.py b/tests/rest/admin/test_federation.py index 0e2824d1b5..1cdb1105eb 100644 --- a/tests/rest/admin/test_federation.py +++ b/tests/rest/admin/test_federation.py @@ -1,16 +1,22 @@ -# Copyright 2021 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. from typing import List, Optional from parameterized import parameterized diff --git a/tests/rest/admin/test_jwks.py b/tests/rest/admin/test_jwks.py index a9a6191c73..6c2b355aa8 100644 --- a/tests/rest/admin/test_jwks.py +++ b/tests/rest/admin/test_jwks.py @@ -1,16 +1,22 @@ -# Copyright 2023 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. from typing import Dict diff --git a/tests/rest/admin/test_media.py b/tests/rest/admin/test_media.py index dac79bd745..ea5b4e2c12 100644 --- a/tests/rest/admin/test_media.py +++ b/tests/rest/admin/test_media.py @@ -1,17 +1,22 @@ -# Copyright 2020 Dirk Klimpel -# Copyright 2021 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. import os from typing import Dict diff --git a/tests/rest/admin/test_registration_tokens.py b/tests/rest/admin/test_registration_tokens.py index 8f8abc21c7..773cfa8d6a 100644 --- a/tests/rest/admin/test_registration_tokens.py +++ b/tests/rest/admin/test_registration_tokens.py @@ -1,16 +1,22 @@ -# Copyright 2021 Callum Brown # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. import random import string from typing import Optional diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py index 206ca7f083..a511175b99 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py @@ -1,16 +1,22 @@ -# Copyright 2020 Dirk Klimpel # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. import json import time import urllib.parse diff --git a/tests/rest/admin/test_server_notice.py b/tests/rest/admin/test_server_notice.py index dfd14f5751..ceba09ec46 100644 --- a/tests/rest/admin/test_server_notice.py +++ b/tests/rest/admin/test_server_notice.py @@ -1,16 +1,22 @@ -# Copyright 2021 Dirk Klimpel # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. from typing import List, Sequence from twisted.test.proto_helpers import MemoryReactor diff --git a/tests/rest/admin/test_statistics.py b/tests/rest/admin/test_statistics.py index cd8ee274d8..0b30e8c65f 100644 --- a/tests/rest/admin/test_statistics.py +++ b/tests/rest/admin/test_statistics.py @@ -1,17 +1,22 @@ -# Copyright 2020 Dirk Klimpel -# Copyright 2021 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. from typing import Dict, List, Optional from twisted.test.proto_helpers import MemoryReactor diff --git a/tests/rest/admin/test_user.py b/tests/rest/admin/test_user.py index cf71bbb461..3caca98a35 100644 --- a/tests/rest/admin/test_user.py +++ b/tests/rest/admin/test_user.py @@ -1,16 +1,22 @@ -# Copyright 2018-2022 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. import hashlib import hmac diff --git a/tests/rest/admin/test_username_available.py b/tests/rest/admin/test_username_available.py index 4c69d224b8..d302be33a3 100644 --- a/tests/rest/admin/test_username_available.py +++ b/tests/rest/admin/test_username_available.py @@ -1,16 +1,22 @@ -# Copyright 2021 The Matrix.org Foundation C.I.C. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] # -# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. from typing import Optional from twisted.test.proto_helpers import MemoryReactor -- cgit 1.5.1 From e108c31fc0ba4fa8b8890170ce4433df334ab58b Mon Sep 17 00:00:00 2001 From: Mathieu Velten Date: Tue, 12 Dec 2023 16:22:19 +0100 Subject: Add avatar and topic settings for server notice room (#16679) --- changelog.d/16679.feature | 1 + docs/server_notices.md | 6 +- docs/usage/configuration/config_documentation.md | 8 +- synapse/config/server_notices.py | 12 +++ synapse/server_notices/server_notices_manager.py | 113 ++++++++++++++++++++--- tests/rest/admin/test_server_notice.py | 109 ++++++++++++++++++++++ 6 files changed, 235 insertions(+), 14 deletions(-) create mode 100644 changelog.d/16679.feature (limited to 'tests/rest/admin') diff --git a/changelog.d/16679.feature b/changelog.d/16679.feature new file mode 100644 index 0000000000..85af837ae1 --- /dev/null +++ b/changelog.d/16679.feature @@ -0,0 +1 @@ +Add config options to set the avatar and the topic of the server notices room. diff --git a/docs/server_notices.md b/docs/server_notices.md index aae25d23b8..33b2f4c9ee 100644 --- a/docs/server_notices.md +++ b/docs/server_notices.md @@ -44,14 +44,16 @@ section, which should look like this: server_notices: system_mxid_localpart: server system_mxid_display_name: "Server Notices" - system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ" + system_mxid_avatar_url: "mxc://example.com/oumMVlgDnLYFaPVkExemNVVZ" room_name: "Server Notices" + room_avatar_url: "mxc://example.com/oumMVlgDnLYFaPVkExemNVVZ" + room_topic: "Room used by your server admin to notice you of important information" auto_join: true ``` The only compulsory setting is `system_mxid_localpart`, which defines the user id of the Server Notices user, as above. `room_name` defines the name of the -room which will be created. +room which will be created, `room_avatar_url` its avatar and `room_topic` its topic. `system_mxid_display_name` and `system_mxid_avatar_url` can be used to set the displayname and avatar of the Server Notices user. diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 560cd65977..90ea8d093f 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -3837,16 +3837,22 @@ Sub-options for this setting include: * `system_mxid_display_name`: set the display name of the "notices" user * `system_mxid_avatar_url`: set the avatar for the "notices" user * `room_name`: set the room name of the server notices room +* `room_avatar_url`: optional string. The room avatar to use for server notice rooms. If set to the empty string `""`, notice rooms will not be given an avatar. Defaults to the empty string. _Added in Synapse 1.99.0._ +* `room_topic`: optional string. The topic to use for server notice rooms. If set to the empty string `""`, notice rooms will not be given a topic. Defaults to the empty string. _Added in Synapse 1.99.0._ * `auto_join`: boolean. If true, the user will be automatically joined to the room instead of being invited. Defaults to false. _Added in Synapse 1.98.0._ +Note that the name, topic and avatar of existing server notice rooms will only be updated when a new notice event is sent. + Example configuration: ```yaml server_notices: system_mxid_localpart: notices system_mxid_display_name: "Server Notices" - system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ" + system_mxid_avatar_url: "mxc://example.com/oumMVlgDnLYFaPVkExemNVVZ" room_name: "Server Notices" + room_avatar_url: "mxc://example.com/oumMVlgDnLYFaPVkExemNVVZ" + room_topic: "Room used by your server admin to notice you of important information" auto_join: true ``` --- diff --git a/synapse/config/server_notices.py b/synapse/config/server_notices.py index a8badba0f8..79f365cad5 100644 --- a/synapse/config/server_notices.py +++ b/synapse/config/server_notices.py @@ -38,6 +38,14 @@ class ServerNoticesConfig(Config): server_notices_room_name (str|None): The name to use for the server notices room. None if server notices are not enabled. + + server_notices_room_avatar_url (str|None): + The avatar URL to use for the server notices room. + None if server notices are not enabled. + + server_notices_room_topic (str|None): + The topic to use for the server notices room. + None if server notices are not enabled. """ section = "servernotices" @@ -48,6 +56,8 @@ class ServerNoticesConfig(Config): self.server_notices_mxid_display_name: Optional[str] = None self.server_notices_mxid_avatar_url: Optional[str] = None self.server_notices_room_name: Optional[str] = None + self.server_notices_room_avatar_url: Optional[str] = None + self.server_notices_room_topic: Optional[str] = None self.server_notices_auto_join: bool = False def read_config(self, config: JsonDict, **kwargs: Any) -> None: @@ -63,4 +73,6 @@ class ServerNoticesConfig(Config): self.server_notices_mxid_avatar_url = c.get("system_mxid_avatar_url", None) # todo: i18n self.server_notices_room_name = c.get("room_name", "Server Notices") + self.server_notices_room_avatar_url = c.get("room_avatar_url", None) + self.server_notices_room_topic = c.get("room_topic", None) self.server_notices_auto_join = c.get("auto_join", False) diff --git a/synapse/server_notices/server_notices_manager.py b/synapse/server_notices/server_notices_manager.py index 2353b5d47f..39a54362d8 100644 --- a/synapse/server_notices/server_notices_manager.py +++ b/synapse/server_notices/server_notices_manager.py @@ -16,7 +16,7 @@ from typing import TYPE_CHECKING, Optional from synapse.api.constants import EventTypes, Membership, RoomCreationPreset from synapse.events import EventBase -from synapse.types import Requester, StreamKeyType, UserID, create_requester +from synapse.types import JsonDict, Requester, StreamKeyType, UserID, create_requester from synapse.util.caches.descriptors import cached if TYPE_CHECKING: @@ -36,6 +36,7 @@ class ServerNoticesManager: self._room_member_handler = hs.get_room_member_handler() self._event_creation_handler = hs.get_event_creation_handler() self._message_handler = hs.get_message_handler() + self._storage_controllers = hs.get_storage_controllers() self._is_mine_id = hs.is_mine_id self._server_name = hs.hostname @@ -160,6 +161,27 @@ class ServerNoticesManager: self._config.servernotices.server_notices_mxid_display_name, self._config.servernotices.server_notices_mxid_avatar_url, ) + await self._update_room_info( + requester, + room_id, + EventTypes.Name, + "name", + self._config.servernotices.server_notices_room_name, + ) + await self._update_room_info( + requester, + room_id, + EventTypes.RoomAvatar, + "url", + self._config.servernotices.server_notices_room_avatar_url, + ) + await self._update_room_info( + requester, + room_id, + EventTypes.Topic, + "topic", + self._config.servernotices.server_notices_room_topic, + ) return room_id # apparently no existing notice room: create a new one @@ -178,15 +200,31 @@ class ServerNoticesManager: "avatar_url": self._config.servernotices.server_notices_mxid_avatar_url, } + room_config: JsonDict = { + "preset": RoomCreationPreset.PRIVATE_CHAT, + "power_level_content_override": {"users_default": -10}, + } + + if self._config.servernotices.server_notices_room_name: + room_config["name"] = self._config.servernotices.server_notices_room_name + if self._config.servernotices.server_notices_room_topic: + room_config["topic"] = self._config.servernotices.server_notices_room_topic + if self._config.servernotices.server_notices_room_avatar_url: + room_config["initial_state"] = [ + { + "type": EventTypes.RoomAvatar, + "state_key": "", + "content": { + "url": self._config.servernotices.server_notices_room_avatar_url, + }, + } + ] + # `ignore_forced_encryption` is used to bypass `encryption_enabled_by_default_for_room_type` # setting if it set, since the server notices will not be encrypted anyway. room_id, _, _ = await self._room_creation_handler.create_room( requester, - config={ - "preset": RoomCreationPreset.PRIVATE_CHAT, - "name": self._config.servernotices.server_notices_room_name, - "power_level_content_override": {"users_default": -10}, - }, + config=room_config, ratelimit=False, creator_join_profile=join_profile, ignore_forced_encryption=True, @@ -265,11 +303,12 @@ class ServerNoticesManager: assert self.server_notices_mxid is not None - notice_user_data_in_room = await self._message_handler.get_room_data( - create_requester(self.server_notices_mxid), - room_id, - EventTypes.Member, - self.server_notices_mxid, + notice_user_data_in_room = ( + await self._storage_controllers.state.get_current_state_event( + room_id, + EventTypes.Member, + self.server_notices_mxid, + ) ) assert notice_user_data_in_room is not None @@ -288,3 +327,55 @@ class ServerNoticesManager: ratelimit=False, content={"displayname": display_name, "avatar_url": avatar_url}, ) + + async def _update_room_info( + self, + requester: Requester, + room_id: str, + info_event_type: str, + info_content_key: str, + info_value: Optional[str], + ) -> None: + """ + Updates a specific notice room's info if it's different from what is set. + + Args: + requester: The user who is performing the update. + room_id: The ID of the server notice room + info_event_type: The event type holding the specific info + info_content_key: The key containing the specific info in the event's content + info_value: The expected value for the specific info + """ + room_info_event = await self._storage_controllers.state.get_current_state_event( + room_id, + info_event_type, + "", + ) + + existing_info_value = None + if room_info_event: + existing_info_value = room_info_event.get(info_content_key) + if existing_info_value == info_value: + return + if not existing_info_value and not info_value: + # A missing `info_value` can either be represented by a None + # or an empty string, so we assume that if they're both falsey + # they're equivalent. + return + + if info_value is None: + info_value = "" + + room_info_event_dict = { + "type": info_event_type, + "room_id": room_id, + "sender": requester.user.to_string(), + "state_key": "", + "content": { + info_content_key: info_value, + }, + } + + event, _ = await self._event_creation_handler.create_and_send_nonmember_event( + requester, room_info_event_dict, ratelimit=False + ) diff --git a/tests/rest/admin/test_server_notice.py b/tests/rest/admin/test_server_notice.py index 2398bc503a..e1d4ceb698 100644 --- a/tests/rest/admin/test_server_notice.py +++ b/tests/rest/admin/test_server_notice.py @@ -596,6 +596,115 @@ class ServerNoticeTestCase(unittest.HomeserverTestCase): ) self.assertEqual(notice_user_state["avatar_url"], new_avatar_url) + @override_config( + { + "server_notices": { + "system_mxid_localpart": "notices", + "room_avatar_url": "test/url", + "room_topic": "Test Topic", + } + } + ) + def test_notice_room_avatar_and_topic(self) -> None: + """ + Tests that using `room_avatar_url` and `room_topic` config properly sets + those properties for the created notice rooms. + """ + server_notice_request_content = { + "user_id": self.other_user, + "content": {"msgtype": "m.text", "body": "test msg one"}, + } + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + invited_rooms = self._check_invite_and_join_status(self.other_user, 1, 0) + notice_room_id = invited_rooms[0].room_id + self.helper.join( + room=notice_room_id, user=self.other_user, tok=self.other_user_token + ) + + room_avatar_state = self.helper.get_state( + notice_room_id, + "m.room.avatar", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_avatar_state["url"], "test/url") + + room_topic_state = self.helper.get_state( + notice_room_id, + "m.room.topic", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_topic_state["topic"], "Test Topic") + + @override_config( + { + "server_notices": { + "system_mxid_localpart": "notices", + "room_avatar_url": "test/url", + } + } + ) + def test_update_room_avatar_when_changed(self) -> None: + """ + Tests that existing server notices room avatar is updated when it is + different from the one in homeserver config. + """ + server_notice_request_content = { + "user_id": self.other_user, + "content": {"msgtype": "m.text", "body": "test msg one"}, + } + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + invited_rooms = self._check_invite_and_join_status(self.other_user, 1, 0) + notice_room_id = invited_rooms[0].room_id + self.helper.join( + room=notice_room_id, user=self.other_user, tok=self.other_user_token + ) + + room_avatar_state = self.helper.get_state( + notice_room_id, + "m.room.avatar", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_avatar_state["url"], "test/url") + + # simulate a change in server config after a server restart. + new_avatar_url = "test/new-url" + self.server_notices_manager._config.servernotices.server_notices_room_avatar_url = ( + new_avatar_url + ) + self.server_notices_manager.get_or_create_notice_room_for_user.cache.invalidate_all() + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + room_avatar_state = self.helper.get_state( + notice_room_id, + "m.room.avatar", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_avatar_state["url"], new_avatar_url) + def _check_invite_and_join_status( self, user_id: str, expected_invites: int, expected_memberships: int ) -> Sequence[RoomsForUser]: -- cgit 1.5.1 From 14ed84ac333a7dd7223793bab53fd115ea24a149 Mon Sep 17 00:00:00 2001 From: Dirk Klimpel <5740567+dklimpel@users.noreply.github.com> Date: Tue, 2 Jan 2024 12:52:51 +0100 Subject: Enable user without password (#16770) Closes: - https://github.com/matrix-org/synapse/issues/10397 - #10397 An administrator should know whether he wants to set a password or not. There are many uses cases where a blank password is required. - Use of only some users with SSO. - Use of bots with password, users with SSO --- changelog.d/16770.bugfix | 1 + docs/admin_api/user_admin_api.md | 19 ++++++++++--------- synapse/rest/admin/users.py | 9 --------- tests/rest/admin/test_user.py | 31 +++++++++++++++++++++++-------- 4 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 changelog.d/16770.bugfix (limited to 'tests/rest/admin') diff --git a/changelog.d/16770.bugfix b/changelog.d/16770.bugfix new file mode 100644 index 0000000000..c02bd8510d --- /dev/null +++ b/changelog.d/16770.bugfix @@ -0,0 +1 @@ +Allow reactivate user without password with Admin API in some edge cases. diff --git a/docs/admin_api/user_admin_api.md b/docs/admin_api/user_admin_api.md index e8e492d095..9dc600b875 100644 --- a/docs/admin_api/user_admin_api.md +++ b/docs/admin_api/user_admin_api.md @@ -149,10 +149,11 @@ Body parameters: granting them access to the Admin API, among other things. - `deactivated` - **bool**, optional. If unspecified, deactivation state will be left unchanged. - Note: the `password` field must also be set if both of the following are true: - - `deactivated` is set to `false` and the user was previously deactivated (you are reactivating this user) - - Users are allowed to set their password on this homeserver (both `password_config.enabled` and - `password_config.localdb_enabled` config options are set to `true`). + Note: + - For the password field there is no strict check of the necessity for its presence. + It is possible to have active users without a password, e.g. when authenticating with OIDC is configured. + You must check yourself whether a password is required when reactivating a user or not. + - It is not possible to set a password if the config option `password_config.localdb_enabled` is set `false`. Users' passwords are wiped upon account deactivation, hence the need to set a new one here. Note: a user cannot be erased with this API. For more details on @@ -223,7 +224,7 @@ The following parameters should be set in the URL: **or** displaynames that contain this value. - `guests` - string representing a bool - Is optional and if `false` will **exclude** guest users. Defaults to `true` to include guest users. This parameter is not supported when MSC3861 is enabled. [See #15582](https://github.com/matrix-org/synapse/pull/15582) -- `admins` - Optional flag to filter admins. If `true`, only admins are queried. If `false`, admins are excluded from +- `admins` - Optional flag to filter admins. If `true`, only admins are queried. If `false`, admins are excluded from the query. When the flag is absent (the default), **both** admins and non-admins are included in the search results. - `deactivated` - string representing a bool - Is optional and if `true` will **include** deactivated users. Defaults to `false` to exclude deactivated users. @@ -272,7 +273,7 @@ The following fields are returned in the JSON response body: - `is_guest` - bool - Status if that user is a guest account. - `admin` - bool - Status if that user is a server administrator. - `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`. + 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. @@ -887,7 +888,7 @@ The following fields are returned in the JSON response body: ### Create a device -Creates a new device for a specific `user_id` and `device_id`. Does nothing if the `device_id` +Creates a new device for a specific `user_id` and `device_id`. Does nothing if the `device_id` exists already. The API is: @@ -1254,11 +1255,11 @@ The following parameters should be set in the URL: ## Check username availability -Checks to see if a username is available, and valid, for the server. See [the client-server +Checks to see if a username is available, and valid, for the server. See [the client-server API](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-register-available) for more information. -This endpoint will work even if registration is disabled on the server, unlike +This endpoint will work even if registration is disabled on the server, unlike `/_matrix/client/r0/register/available`. The API is: diff --git a/synapse/rest/admin/users.py b/synapse/rest/admin/users.py index 4059039bab..a31a268ccc 100644 --- a/synapse/rest/admin/users.py +++ b/synapse/rest/admin/users.py @@ -412,15 +412,6 @@ class UserRestServletV2(RestServlet): target_user.to_string(), False, requester, by_admin=True ) elif not deactivate and user["deactivated"]: - if ( - "password" not in body - and self.auth_handler.can_change_password() - ): - raise SynapseError( - HTTPStatus.BAD_REQUEST, - "Must provide a password to re-activate an account.", - ) - await self.deactivate_account_handler.activate_account( target_user.to_string() ) diff --git a/tests/rest/admin/test_user.py b/tests/rest/admin/test_user.py index 3caca98a35..04604bfc04 100644 --- a/tests/rest/admin/test_user.py +++ b/tests/rest/admin/test_user.py @@ -2747,7 +2747,7 @@ class UserRestTestCase(unittest.HomeserverTestCase): profile = self.get_success(self.store._get_user_in_directory(self.other_user)) self.assertIsNone(profile) - def test_reactivate_user(self) -> None: + def test_reactivate_user_with_password(self) -> None: """ Test reactivating another user. """ @@ -2755,21 +2755,36 @@ class UserRestTestCase(unittest.HomeserverTestCase): # Deactivate the user. self._deactivate_user("@user:test") - # Attempt to reactivate the user (without a password). + # Reactivate the user with password. channel = self.make_request( "PUT", self.url_other_user, access_token=self.admin_user_tok, - content={"deactivated": False}, + content={"deactivated": False, "password": "foo"}, ) - self.assertEqual(400, channel.code, msg=channel.json_body) + self.assertEqual(200, channel.code, msg=channel.json_body) + self.assertEqual("@user:test", channel.json_body["name"]) + self.assertFalse(channel.json_body["deactivated"]) + self._is_erased("@user:test", False) + + # This key was removed intentionally. Ensure it is not accidentally re-included. + self.assertNotIn("password_hash", channel.json_body) - # Reactivate the user. + def test_reactivate_user_without_password(self) -> None: + """ + Test reactivating another user without a password. + This can be using some local users and some user with SSO (password = `null`). + """ + + # Deactivate the user. + self._deactivate_user("@user:test") + + # Reactivate the user without a password. channel = self.make_request( "PUT", self.url_other_user, access_token=self.admin_user_tok, - content={"deactivated": False, "password": "foo"}, + content={"deactivated": False}, ) self.assertEqual(200, channel.code, msg=channel.json_body) self.assertEqual("@user:test", channel.json_body["name"]) @@ -2788,7 +2803,7 @@ class UserRestTestCase(unittest.HomeserverTestCase): # Deactivate the user. self._deactivate_user("@user:test") - # Reactivate the user with a password + # Reactivate the user with a password. channel = self.make_request( "PUT", self.url_other_user, @@ -2822,7 +2837,7 @@ class UserRestTestCase(unittest.HomeserverTestCase): # Deactivate the user. self._deactivate_user("@user:test") - # Reactivate the user with a password + # Reactivate the user with a password. channel = self.make_request( "PUT", self.url_other_user, -- cgit 1.5.1 From c7d0d02be7bf61e58388676e9e31b44004cbf257 Mon Sep 17 00:00:00 2001 From: Adam Jędrzejewski <59581316+adamjedrzejewski@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:36:57 +0100 Subject: Search non ASCII display names using Admin API (#16767) Closes #16370 Signed-off-by: Adam Jedrzejewski --- changelog.d/16767.bugfix | 2 ++ synapse/rest/admin/users.py | 2 +- tests/rest/admin/test_user.py | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 changelog.d/16767.bugfix (limited to 'tests/rest/admin') diff --git a/changelog.d/16767.bugfix b/changelog.d/16767.bugfix new file mode 100644 index 0000000000..b1fa1285ef --- /dev/null +++ b/changelog.d/16767.bugfix @@ -0,0 +1,2 @@ +Fixed a bug that prevented users from being queried by display name if it contains non-ASCII characters. + diff --git a/synapse/rest/admin/users.py b/synapse/rest/admin/users.py index a31a268ccc..ee73f0233d 100644 --- a/synapse/rest/admin/users.py +++ b/synapse/rest/admin/users.py @@ -107,7 +107,7 @@ class UsersRestServletV2(RestServlet): ) user_id = parse_string(request, "user_id") - name = parse_string(request, "name") + name = parse_string(request, "name", encoding="utf-8") guests = parse_boolean(request, "guests", default=True) if self._msc3861_enabled and guests: diff --git a/tests/rest/admin/test_user.py b/tests/rest/admin/test_user.py index 04604bfc04..61cbac2332 100644 --- a/tests/rest/admin/test_user.py +++ b/tests/rest/admin/test_user.py @@ -1638,8 +1638,17 @@ class UserRestTestCase(unittest.HomeserverTestCase): ) ) + self.non_ascii_displayname = "ąćęłńóśżźäöüß中国日本" + self.non_ascii_user = self.register_user( + "nonascii", "nonascii", displayname=self.non_ascii_displayname + ) + self.url_prefix = "/_synapse/admin/v2/users/%s" self.url_other_user = self.url_prefix % self.other_user + self.url_non_ascii_user = ( + "/_synapse/admin/v2/users?name=%s" + % urllib.parse.quote(self.non_ascii_displayname) + ) def test_requester_is_no_admin(self) -> None: """ @@ -1790,6 +1799,20 @@ class UserRestTestCase(unittest.HomeserverTestCase): self.assertEqual("User", channel.json_body["displayname"]) self._check_fields(channel.json_body) + def test_get_user_nonascii_displayname(self) -> None: + """ + Test get user by non-ascii display name + """ + channel = self.make_request( + "GET", + self.url_non_ascii_user, + access_token=self.admin_user_tok, + ) + + users = {user["name"]: user for user in channel.json_body["users"]} + self.assertEqual(200, channel.code, msg=channel.json_body) + self.assertIn(self.non_ascii_user, users, channel.json_body["users"]) + def test_create_server_admin(self) -> None: """ Check that a new admin user is created successfully. -- cgit 1.5.1