1
0

Add stable support for MSC4380 invite blocking. (#19431)

MSC4380 has now completed FCP, so we can add stable support for it.

Co-authored-by: Quentin Gliech <quenting@element.io>
This commit is contained in:
Richard van der Hoff
2026-02-27 14:47:07 +00:00
committed by GitHub
parent 9de28df7a2
commit b9ea2285b3
7 changed files with 19 additions and 52 deletions

View File

@@ -0,0 +1 @@
Add stable support for [MSC4380](https://github.com/matrix-org/matrix-spec-proposals/pull/4380) invite blocking.

View File

@@ -325,9 +325,7 @@ class AccountDataTypes:
"org.matrix.msc4155.invite_permission_config"
)
# MSC4380: Invite blocking
MSC4380_INVITE_PERMISSION_CONFIG: Final = (
"org.matrix.msc4380.invite_permission_config"
)
INVITE_PERMISSION_CONFIG: Final = "m.invite_permission_config"
# Synapse-specific behaviour. See "Client-Server API Extensions" documentation
# in Admin API for more information.
SYNAPSE_ADMIN_CLIENT_CONFIG: Final = "io.element.synapse.admin_client_config"

View File

@@ -138,7 +138,7 @@ class Codes(str, Enum):
KEY_TOO_LARGE = "M_KEY_TOO_LARGE"
# Part of MSC4155/MSC4380
INVITE_BLOCKED = "ORG.MATRIX.MSC4155.M_INVITE_BLOCKED"
INVITE_BLOCKED = "M_INVITE_BLOCKED"
# Part of MSC4190
APPSERVICE_LOGIN_UNSUPPORTED = "IO.ELEMENT.MSC4190.M_APPSERVICE_LOGIN_UNSUPPORTED"

View File

@@ -606,6 +606,3 @@ class ExperimentalConfig(Config):
# Note that sticky events persisted before this feature is enabled will not be
# considered sticky by the local homeserver.
self.msc4354_enabled: bool = experimental.get("msc4354_enabled", False)
# MSC4380: Invite blocking
self.msc4380_enabled: bool = experimental.get("msc4380_enabled", False)

View File

@@ -187,7 +187,7 @@ class VersionsRestServlet(RestServlet):
# MSC4354: Sticky events
"org.matrix.msc4354": self.config.experimental.msc4354_enabled,
# MSC4380: Invite blocking
"org.matrix.msc4380": self.config.experimental.msc4380_enabled,
"org.matrix.msc4380.stable": True,
},
},
)

View File

@@ -109,7 +109,6 @@ class AccountDataWorkerStore(PushRulesWorkerStore, CacheInvalidationWorkerStore)
)
self._msc4155_enabled = hs.config.experimental.msc4155_enabled
self._msc4380_enabled = hs.config.experimental.msc4380_enabled
def get_max_account_data_stream_id(self) -> int:
"""Get the current max stream ID for account data stream
@@ -573,14 +572,13 @@ class AccountDataWorkerStore(PushRulesWorkerStore, CacheInvalidationWorkerStore)
Args:
user_id: The user whose invite configuration should be returned.
"""
if self._msc4380_enabled:
data = await self.get_global_account_data_by_type_for_user(
user_id, AccountDataTypes.MSC4380_INVITE_PERMISSION_CONFIG
)
# If the user has an MSC4380-style config setting, prioritise that
# above an MSC4155 one
if data is not None:
return MSC4380InviteRulesConfig.from_account_data(data)
data = await self.get_global_account_data_by_type_for_user(
user_id, AccountDataTypes.INVITE_PERMISSION_CONFIG
)
# If the user has an MSC4380-style config setting, prioritise that
# above an MSC4155 one
if data is not None:
return MSC4380InviteRulesConfig.from_account_data(data)
if self._msc4155_enabled:
data = await self.get_global_account_data_by_type_for_user(

View File

@@ -503,7 +503,7 @@ class TestMSC4155InviteFiltering(FederatingHomeserverTestCase):
SynapseError,
).value
self.assertEqual(f.code, 403)
self.assertEqual(f.errcode, "ORG.MATRIX.MSC4155.M_INVITE_BLOCKED")
self.assertEqual(f.errcode, "M_INVITE_BLOCKED")
@override_config({"experimental_features": {"msc4155_enabled": False}})
def test_msc4155_disabled_allow_invite_local(self) -> None:
@@ -573,7 +573,7 @@ class TestMSC4155InviteFiltering(FederatingHomeserverTestCase):
SynapseError,
).value
self.assertEqual(f.code, 403)
self.assertEqual(f.errcode, "ORG.MATRIX.MSC4155.M_INVITE_BLOCKED")
self.assertEqual(f.errcode, "M_INVITE_BLOCKED")
@override_config({"experimental_features": {"msc4155_enabled": True}})
def test_msc4155_block_invite_remote_server(self) -> None:
@@ -619,7 +619,7 @@ class TestMSC4155InviteFiltering(FederatingHomeserverTestCase):
SynapseError,
).value
self.assertEqual(f.code, 403)
self.assertEqual(f.errcode, "ORG.MATRIX.MSC4155.M_INVITE_BLOCKED")
self.assertEqual(f.errcode, "M_INVITE_BLOCKED")
class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
@@ -642,7 +642,6 @@ class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
self.bob = self.register_user("bob", "pass")
self.bob_token = self.login("bob", "pass")
@override_config({"experimental_features": {"msc4380_enabled": True}})
def test_misc4380_block_invite_local(self) -> None:
"""Test that MSC4380 will block a user from being invited to a room"""
room_id = self.helper.create_room_as(self.alice, tok=self.alice_token)
@@ -650,7 +649,7 @@ class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
self.get_success(
self.store.add_account_data_for_user(
self.bob,
AccountDataTypes.MSC4380_INVITE_PERMISSION_CONFIG,
AccountDataTypes.INVITE_PERMISSION_CONFIG,
{
"default_action": "block",
},
@@ -667,9 +666,8 @@ class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
SynapseError,
).value
self.assertEqual(f.code, 403)
self.assertEqual(f.errcode, "ORG.MATRIX.MSC4155.M_INVITE_BLOCKED")
self.assertEqual(f.errcode, "M_INVITE_BLOCKED")
@override_config({"experimental_features": {"msc4380_enabled": True}})
def test_misc4380_non_string_setting(self) -> None:
"""Test that `default_action` being set to something non-stringy is the same as "accept"."""
room_id = self.helper.create_room_as(self.alice, tok=self.alice_token)
@@ -677,7 +675,7 @@ class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
self.get_success(
self.store.add_account_data_for_user(
self.bob,
AccountDataTypes.MSC4380_INVITE_PERMISSION_CONFIG,
AccountDataTypes.INVITE_PERMISSION_CONFIG,
{
"default_action": 1,
},
@@ -693,31 +691,6 @@ class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
)
)
@override_config({"experimental_features": {"msc4380_enabled": False}})
def test_msc4380_disabled_allow_invite_local(self) -> None:
"""Test that, when MSC4380 is not enabled, invites are accepted as normal"""
room_id = self.helper.create_room_as(self.alice, tok=self.alice_token)
self.get_success(
self.store.add_account_data_for_user(
self.bob,
AccountDataTypes.MSC4380_INVITE_PERMISSION_CONFIG,
{
"default_action": "block",
},
)
)
self.get_success(
self.handler.update_membership(
requester=create_requester(self.alice),
target=UserID.from_string(self.bob),
room_id=room_id,
action=Membership.INVITE,
),
)
@override_config({"experimental_features": {"msc4380_enabled": True}})
def test_msc4380_block_invite_remote(self) -> None:
"""Test that MSC4380 will block a user from being invited to a room by a remote user."""
# A remote user who sends the invite
@@ -727,7 +700,7 @@ class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
self.get_success(
self.store.add_account_data_for_user(
self.bob,
AccountDataTypes.MSC4380_INVITE_PERMISSION_CONFIG,
AccountDataTypes.INVITE_PERMISSION_CONFIG,
{"default_action": "block"},
)
)
@@ -761,4 +734,4 @@ class TestMSC4380InviteBlocking(FederatingHomeserverTestCase):
SynapseError,
).value
self.assertEqual(f.code, 403)
self.assertEqual(f.errcode, "ORG.MATRIX.MSC4155.M_INVITE_BLOCKED")
self.assertEqual(f.errcode, "M_INVITE_BLOCKED")