diff --git a/docs/modules/third_party_rules_callbacks.md b/docs/modules/third_party_rules_callbacks.md index 947a92bd9358..9c1f88057707 100644 --- a/docs/modules/third_party_rules_callbacks.md +++ b/docs/modules/third_party_rules_callbacks.md @@ -161,7 +161,7 @@ async def check_can_shutdown_room( Called when an admin user requests the shutdown of a room. The module must return a boolean indicating whether the shutdown can go through. If the callback returns `False`, -the shutdown will not proceed and the caller will see a `M_FOBIDDEN` error. +the shutdown will not proceed and the caller will see a `M_FORBIDDEN` error. If multiple modules implement this callback, they will be considered in order. If a callback returns `True`, Synapse falls through to the next one. The value of the first @@ -174,8 +174,8 @@ _First introduced in Synapse v1.5X.0_ ```python async def check_can_deactivate_user( - requester: "synapse.types.Requester", user_id: str, + admin_user_id: str|None, ) -> bool: ``` @@ -183,7 +183,7 @@ Called when the deactivation of a user is requested. User deactivation can be performed by an admin or the user themselves, so developers are encouraged to check the requester when implementing this callback. The module must return a boolean indicating whether the deactivation can go through. If the callback returns `False`, -the deactivation will not proceed and the caller will see a `M_FOBIDDEN` error. +the deactivation will not proceed and the caller will see a `M_FORBIDDEN` error. If multiple modules implement this callback, they will be considered in order. If a callback returns `True`, Synapse falls through to the next one. The value of the first diff --git a/synapse/events/third_party_rules.py b/synapse/events/third_party_rules.py index e69d6fb15837..014ea1c38359 100644 --- a/synapse/events/third_party_rules.py +++ b/synapse/events/third_party_rules.py @@ -39,7 +39,7 @@ ] ON_NEW_EVENT_CALLBACK = Callable[[EventBase, StateMap[EventBase]], Awaitable] CHECK_CAN_SHUTDOWN_ROOM_CALLBACK = Callable[[str, str], Awaitable[bool]] -CHECK_CAN_DEACTIVATE_USER_CALLBACK = Callable[[Requester, str], Awaitable[bool]] +CHECK_CAN_DEACTIVATE_USER_CALLBACK = Callable[[str, str | None], Awaitable[bool]] ON_PROFILE_UPDATE_CALLBACK = Callable[[str, ProfileInfo, bool, bool], Awaitable] ON_USER_DEACTIVATION_STATUS_CHANGED_CALLBACK = Callable[[str, bool, bool], Awaitable] @@ -403,7 +403,9 @@ async def check_can_shutdown_room(self, user_id: str, room_id: str) -> bool: return True async def check_can_deactivate_user( - self, requester: Requester, user_id: str + self, + user_id: str, + admin_user_id: str | None, ) -> bool: """Intercept requests to deactivate a user. If `False` is returned, the user should not be deactivated. @@ -414,7 +416,7 @@ async def check_can_deactivate_user( """ for callback in self._check_can_deactivate_user_callbacks: try: - if await callback(requester, user_id) is False: + if await callback(user_id, admin_user_id) is False: return False except Exception as e: logger.exception( diff --git a/synapse/handlers/deactivate_account.py b/synapse/handlers/deactivate_account.py index f997a340a10b..dfc5827f4f93 100644 --- a/synapse/handlers/deactivate_account.py +++ b/synapse/handlers/deactivate_account.py @@ -78,7 +78,7 @@ async def deactivate_account( # Check if this user can be deactivated if not await self._third_party_rules.check_can_deactivate_user( - requester, user_id + user_id, requester.user.to_string() if by_admin else None ): raise SynapseError( 403, "Deactivation of this user is forbidden", Codes.FORBIDDEN diff --git a/tests/rest/client/test_third_party_rules.py b/tests/rest/client/test_third_party_rules.py index 1016581a6b08..fb1a755b6ea0 100644 --- a/tests/rest/client/test_third_party_rules.py +++ b/tests/rest/client/test_third_party_rules.py @@ -816,11 +816,11 @@ def test_check_can_deactivate_user(self) -> None: deactivation_mock.assert_called_once() args = deactivation_mock.call_args[0] - # Check that the mock was called with the right requester - self.assertEqual(args[0].user.to_string(), user_id) - # Check that the mock was called with the right user ID - self.assertEqual(args[1], user_id) + self.assertEqual(args[0], user_id) + + # Check that the admin user ID was not provided + self.assertEqual(args[1], None) def test_check_can_deactivate_user_admin(self) -> None: """Tests that the on_user_deactivation_status_changed module callback is called @@ -855,11 +855,11 @@ def test_check_can_deactivate_user_admin(self) -> None: deactivation_mock.assert_called_once() args = deactivation_mock.call_args[0] - # Check that the mock was called with the right requester - self.assertEqual(args[0].user.to_string(), admin_user_id) - # Check that the mock was called with the right user ID - self.assertEqual(args[1], user_id) + self.assertEqual(args[0], user_id) + + # Check that the mock was called with the right admin user id + self.assertEqual(args[1], admin_user_id) def test_check_can_shutdown_room(self) -> None: """Tests that the check_can_shutdown_room module callback is called