test_shadow_banned.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. # Copyright 2020 The Matrix.org Foundation C.I.C.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from unittest.mock import Mock, patch
  15. from twisted.test.proto_helpers import MemoryReactor
  16. import synapse.rest.admin
  17. from synapse.api.constants import EventTypes
  18. from synapse.rest.client import (
  19. directory,
  20. login,
  21. profile,
  22. room,
  23. room_upgrade_rest_servlet,
  24. )
  25. from synapse.server import HomeServer
  26. from synapse.types import UserID
  27. from synapse.util import Clock
  28. from tests import unittest
  29. class _ShadowBannedBase(unittest.HomeserverTestCase):
  30. def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
  31. # Create two users, one of which is shadow-banned.
  32. self.banned_user_id = self.register_user("banned", "test")
  33. self.banned_access_token = self.login("banned", "test")
  34. self.store = self.hs.get_datastores().main
  35. self.get_success(
  36. self.store.set_shadow_banned(UserID.from_string(self.banned_user_id), True)
  37. )
  38. self.other_user_id = self.register_user("otheruser", "pass")
  39. self.other_access_token = self.login("otheruser", "pass")
  40. # To avoid the tests timing out don't add a delay to "annoy the requester".
  41. @patch("random.randint", new=lambda a, b: 0)
  42. class RoomTestCase(_ShadowBannedBase):
  43. servlets = [
  44. synapse.rest.admin.register_servlets_for_client_rest_resource,
  45. directory.register_servlets,
  46. login.register_servlets,
  47. room.register_servlets,
  48. room_upgrade_rest_servlet.register_servlets,
  49. ]
  50. def test_invite(self) -> None:
  51. """Invites from shadow-banned users don't actually get sent."""
  52. # The create works fine.
  53. room_id = self.helper.create_room_as(
  54. self.banned_user_id, tok=self.banned_access_token
  55. )
  56. # Inviting the user completes successfully.
  57. self.helper.invite(
  58. room=room_id,
  59. src=self.banned_user_id,
  60. tok=self.banned_access_token,
  61. targ=self.other_user_id,
  62. )
  63. # But the user wasn't actually invited.
  64. invited_rooms = self.get_success(
  65. self.store.get_invited_rooms_for_local_user(self.other_user_id)
  66. )
  67. self.assertEqual(invited_rooms, [])
  68. def test_invite_3pid(self) -> None:
  69. """Ensure that a 3PID invite does not attempt to contact the identity server."""
  70. identity_handler = self.hs.get_identity_handler()
  71. identity_handler.lookup_3pid = Mock(
  72. side_effect=AssertionError("This should not get called")
  73. )
  74. # The create works fine.
  75. room_id = self.helper.create_room_as(
  76. self.banned_user_id, tok=self.banned_access_token
  77. )
  78. # Inviting the user completes successfully.
  79. channel = self.make_request(
  80. "POST",
  81. "/rooms/%s/invite" % (room_id,),
  82. {"id_server": "test", "medium": "email", "address": "test@test.test"},
  83. access_token=self.banned_access_token,
  84. )
  85. self.assertEqual(200, channel.code, channel.result)
  86. # This should have raised an error earlier, but double check this wasn't called.
  87. identity_handler.lookup_3pid.assert_not_called()
  88. def test_create_room(self) -> None:
  89. """Invitations during a room creation should be discarded, but the room still gets created."""
  90. # The room creation is successful.
  91. channel = self.make_request(
  92. "POST",
  93. "/_matrix/client/r0/createRoom",
  94. {"visibility": "public", "invite": [self.other_user_id]},
  95. access_token=self.banned_access_token,
  96. )
  97. self.assertEqual(200, channel.code, channel.result)
  98. room_id = channel.json_body["room_id"]
  99. # But the user wasn't actually invited.
  100. invited_rooms = self.get_success(
  101. self.store.get_invited_rooms_for_local_user(self.other_user_id)
  102. )
  103. self.assertEqual(invited_rooms, [])
  104. # Since a real room was created, the other user should be able to join it.
  105. self.helper.join(room_id, self.other_user_id, tok=self.other_access_token)
  106. # Both users should be in the room.
  107. users = self.get_success(self.store.get_users_in_room(room_id))
  108. self.assertCountEqual(users, ["@banned:test", "@otheruser:test"])
  109. def test_message(self) -> None:
  110. """Messages from shadow-banned users don't actually get sent."""
  111. room_id = self.helper.create_room_as(
  112. self.other_user_id, tok=self.other_access_token
  113. )
  114. # The user should be in the room.
  115. self.helper.join(room_id, self.banned_user_id, tok=self.banned_access_token)
  116. # Sending a message should complete successfully.
  117. result = self.helper.send_event(
  118. room_id=room_id,
  119. type=EventTypes.Message,
  120. content={"msgtype": "m.text", "body": "with right label"},
  121. tok=self.banned_access_token,
  122. )
  123. self.assertIn("event_id", result)
  124. event_id = result["event_id"]
  125. latest_events = self.get_success(
  126. self.store.get_latest_event_ids_in_room(room_id)
  127. )
  128. self.assertNotIn(event_id, latest_events)
  129. def test_upgrade(self) -> None:
  130. """A room upgrade should fail, but look like it succeeded."""
  131. # The create works fine.
  132. room_id = self.helper.create_room_as(
  133. self.banned_user_id, tok=self.banned_access_token
  134. )
  135. channel = self.make_request(
  136. "POST",
  137. "/_matrix/client/r0/rooms/%s/upgrade" % (room_id,),
  138. {"new_version": "6"},
  139. access_token=self.banned_access_token,
  140. )
  141. self.assertEqual(200, channel.code, channel.result)
  142. # A new room_id should be returned.
  143. self.assertIn("replacement_room", channel.json_body)
  144. new_room_id = channel.json_body["replacement_room"]
  145. # It doesn't really matter what API we use here, we just want to assert
  146. # that the room doesn't exist.
  147. summary = self.get_success(self.store.get_room_summary(new_room_id))
  148. # The summary should be empty since the room doesn't exist.
  149. self.assertEqual(summary, {})
  150. def test_typing(self) -> None:
  151. """Typing notifications should not be propagated into the room."""
  152. # The create works fine.
  153. room_id = self.helper.create_room_as(
  154. self.banned_user_id, tok=self.banned_access_token
  155. )
  156. channel = self.make_request(
  157. "PUT",
  158. "/rooms/%s/typing/%s" % (room_id, self.banned_user_id),
  159. {"typing": True, "timeout": 30000},
  160. access_token=self.banned_access_token,
  161. )
  162. self.assertEqual(200, channel.code)
  163. # There should be no typing events.
  164. event_source = self.hs.get_event_sources().sources.typing
  165. self.assertEqual(event_source.get_current_key(), 0)
  166. # The other user can join and send typing events.
  167. self.helper.join(room_id, self.other_user_id, tok=self.other_access_token)
  168. channel = self.make_request(
  169. "PUT",
  170. "/rooms/%s/typing/%s" % (room_id, self.other_user_id),
  171. {"typing": True, "timeout": 30000},
  172. access_token=self.other_access_token,
  173. )
  174. self.assertEqual(200, channel.code)
  175. # These appear in the room.
  176. self.assertEqual(event_source.get_current_key(), 1)
  177. events = self.get_success(
  178. event_source.get_new_events(
  179. user=UserID.from_string(self.other_user_id),
  180. from_key=0,
  181. limit=None,
  182. room_ids=[room_id],
  183. is_guest=False,
  184. )
  185. )
  186. self.assertEqual(
  187. events[0],
  188. [
  189. {
  190. "type": "m.typing",
  191. "room_id": room_id,
  192. "content": {"user_ids": [self.other_user_id]},
  193. }
  194. ],
  195. )
  196. # To avoid the tests timing out don't add a delay to "annoy the requester".
  197. @patch("random.randint", new=lambda a, b: 0)
  198. class ProfileTestCase(_ShadowBannedBase):
  199. servlets = [
  200. synapse.rest.admin.register_servlets_for_client_rest_resource,
  201. login.register_servlets,
  202. profile.register_servlets,
  203. room.register_servlets,
  204. ]
  205. def test_displayname(self) -> None:
  206. """Profile changes should succeed, but don't end up in a room."""
  207. original_display_name = "banned"
  208. new_display_name = "new name"
  209. # Join a room.
  210. room_id = self.helper.create_room_as(
  211. self.banned_user_id, tok=self.banned_access_token
  212. )
  213. # The update should succeed.
  214. channel = self.make_request(
  215. "PUT",
  216. "/_matrix/client/r0/profile/%s/displayname" % (self.banned_user_id,),
  217. {"displayname": new_display_name},
  218. access_token=self.banned_access_token,
  219. )
  220. self.assertEqual(200, channel.code, channel.result)
  221. self.assertEqual(channel.json_body, {})
  222. # The user's display name should be updated.
  223. channel = self.make_request(
  224. "GET", "/profile/%s/displayname" % (self.banned_user_id,)
  225. )
  226. self.assertEqual(channel.code, 200, channel.result)
  227. self.assertEqual(channel.json_body["displayname"], new_display_name)
  228. # But the display name in the room should not be.
  229. message_handler = self.hs.get_message_handler()
  230. event = self.get_success(
  231. message_handler.get_room_data(
  232. self.banned_user_id,
  233. room_id,
  234. "m.room.member",
  235. self.banned_user_id,
  236. )
  237. )
  238. self.assertEqual(
  239. event.content, {"membership": "join", "displayname": original_display_name}
  240. )
  241. def test_room_displayname(self) -> None:
  242. """Changes to state events for a room should be processed, but not end up in the room."""
  243. original_display_name = "banned"
  244. new_display_name = "new name"
  245. # Join a room.
  246. room_id = self.helper.create_room_as(
  247. self.banned_user_id, tok=self.banned_access_token
  248. )
  249. # The update should succeed.
  250. channel = self.make_request(
  251. "PUT",
  252. "/_matrix/client/r0/rooms/%s/state/m.room.member/%s"
  253. % (room_id, self.banned_user_id),
  254. {"membership": "join", "displayname": new_display_name},
  255. access_token=self.banned_access_token,
  256. )
  257. self.assertEqual(200, channel.code, channel.result)
  258. self.assertIn("event_id", channel.json_body)
  259. # The display name in the room should not be changed.
  260. message_handler = self.hs.get_message_handler()
  261. event = self.get_success(
  262. message_handler.get_room_data(
  263. self.banned_user_id,
  264. room_id,
  265. "m.room.member",
  266. self.banned_user_id,
  267. )
  268. )
  269. self.assertEqual(
  270. event.content, {"membership": "join", "displayname": original_display_name}
  271. )