test_shadow_banned.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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 EduTypes, 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, create_requester
  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. {
  83. "id_server": "test",
  84. "medium": "email",
  85. "address": "test@test.test",
  86. "id_access_token": "anytoken",
  87. },
  88. access_token=self.banned_access_token,
  89. )
  90. self.assertEqual(200, channel.code, channel.result)
  91. # This should have raised an error earlier, but double check this wasn't called.
  92. identity_handler.lookup_3pid.assert_not_called()
  93. def test_create_room(self) -> None:
  94. """Invitations during a room creation should be discarded, but the room still gets created."""
  95. # The room creation is successful.
  96. channel = self.make_request(
  97. "POST",
  98. "/_matrix/client/r0/createRoom",
  99. {"visibility": "public", "invite": [self.other_user_id]},
  100. access_token=self.banned_access_token,
  101. )
  102. self.assertEqual(200, channel.code, channel.result)
  103. room_id = channel.json_body["room_id"]
  104. # But the user wasn't actually invited.
  105. invited_rooms = self.get_success(
  106. self.store.get_invited_rooms_for_local_user(self.other_user_id)
  107. )
  108. self.assertEqual(invited_rooms, [])
  109. # Since a real room was created, the other user should be able to join it.
  110. self.helper.join(room_id, self.other_user_id, tok=self.other_access_token)
  111. # Both users should be in the room.
  112. users = self.get_success(self.store.get_users_in_room(room_id))
  113. self.assertCountEqual(users, ["@banned:test", "@otheruser:test"])
  114. def test_message(self) -> None:
  115. """Messages from shadow-banned users don't actually get sent."""
  116. room_id = self.helper.create_room_as(
  117. self.other_user_id, tok=self.other_access_token
  118. )
  119. # The user should be in the room.
  120. self.helper.join(room_id, self.banned_user_id, tok=self.banned_access_token)
  121. # Sending a message should complete successfully.
  122. result = self.helper.send_event(
  123. room_id=room_id,
  124. type=EventTypes.Message,
  125. content={"msgtype": "m.text", "body": "with right label"},
  126. tok=self.banned_access_token,
  127. )
  128. self.assertIn("event_id", result)
  129. event_id = result["event_id"]
  130. latest_events = self.get_success(
  131. self.store.get_latest_event_ids_in_room(room_id)
  132. )
  133. self.assertNotIn(event_id, latest_events)
  134. def test_upgrade(self) -> None:
  135. """A room upgrade should fail, but look like it succeeded."""
  136. # The create works fine.
  137. room_id = self.helper.create_room_as(
  138. self.banned_user_id, tok=self.banned_access_token
  139. )
  140. channel = self.make_request(
  141. "POST",
  142. "/_matrix/client/r0/rooms/%s/upgrade" % (room_id,),
  143. {"new_version": "6"},
  144. access_token=self.banned_access_token,
  145. )
  146. self.assertEqual(200, channel.code, channel.result)
  147. # A new room_id should be returned.
  148. self.assertIn("replacement_room", channel.json_body)
  149. new_room_id = channel.json_body["replacement_room"]
  150. # It doesn't really matter what API we use here, we just want to assert
  151. # that the room doesn't exist.
  152. summary = self.get_success(self.store.get_room_summary(new_room_id))
  153. # The summary should be empty since the room doesn't exist.
  154. self.assertEqual(summary, {})
  155. def test_typing(self) -> None:
  156. """Typing notifications should not be propagated into the room."""
  157. # The create works fine.
  158. room_id = self.helper.create_room_as(
  159. self.banned_user_id, tok=self.banned_access_token
  160. )
  161. channel = self.make_request(
  162. "PUT",
  163. "/rooms/%s/typing/%s" % (room_id, self.banned_user_id),
  164. {"typing": True, "timeout": 30000},
  165. access_token=self.banned_access_token,
  166. )
  167. self.assertEqual(200, channel.code)
  168. # There should be no typing events.
  169. event_source = self.hs.get_event_sources().sources.typing
  170. self.assertEqual(event_source.get_current_key(), 0)
  171. # The other user can join and send typing events.
  172. self.helper.join(room_id, self.other_user_id, tok=self.other_access_token)
  173. channel = self.make_request(
  174. "PUT",
  175. "/rooms/%s/typing/%s" % (room_id, self.other_user_id),
  176. {"typing": True, "timeout": 30000},
  177. access_token=self.other_access_token,
  178. )
  179. self.assertEqual(200, channel.code)
  180. # These appear in the room.
  181. self.assertEqual(event_source.get_current_key(), 1)
  182. events = self.get_success(
  183. event_source.get_new_events(
  184. user=UserID.from_string(self.other_user_id),
  185. from_key=0,
  186. limit=None,
  187. room_ids=[room_id],
  188. is_guest=False,
  189. )
  190. )
  191. self.assertEqual(
  192. events[0],
  193. [
  194. {
  195. "type": EduTypes.TYPING,
  196. "room_id": room_id,
  197. "content": {"user_ids": [self.other_user_id]},
  198. }
  199. ],
  200. )
  201. # To avoid the tests timing out don't add a delay to "annoy the requester".
  202. @patch("random.randint", new=lambda a, b: 0)
  203. class ProfileTestCase(_ShadowBannedBase):
  204. servlets = [
  205. synapse.rest.admin.register_servlets_for_client_rest_resource,
  206. login.register_servlets,
  207. profile.register_servlets,
  208. room.register_servlets,
  209. ]
  210. def test_displayname(self) -> None:
  211. """Profile changes should succeed, but don't end up in a room."""
  212. original_display_name = "banned"
  213. new_display_name = "new name"
  214. # Join a room.
  215. room_id = self.helper.create_room_as(
  216. self.banned_user_id, tok=self.banned_access_token
  217. )
  218. # The update should succeed.
  219. channel = self.make_request(
  220. "PUT",
  221. "/_matrix/client/r0/profile/%s/displayname" % (self.banned_user_id,),
  222. {"displayname": new_display_name},
  223. access_token=self.banned_access_token,
  224. )
  225. self.assertEqual(200, channel.code, channel.result)
  226. self.assertEqual(channel.json_body, {})
  227. # The user's display name should be updated.
  228. channel = self.make_request(
  229. "GET", "/profile/%s/displayname" % (self.banned_user_id,)
  230. )
  231. self.assertEqual(channel.code, 200, channel.result)
  232. self.assertEqual(channel.json_body["displayname"], new_display_name)
  233. # But the display name in the room should not be.
  234. message_handler = self.hs.get_message_handler()
  235. event = self.get_success(
  236. message_handler.get_room_data(
  237. create_requester(self.banned_user_id),
  238. room_id,
  239. "m.room.member",
  240. self.banned_user_id,
  241. )
  242. )
  243. self.assertEqual(
  244. event.content, {"membership": "join", "displayname": original_display_name}
  245. )
  246. def test_room_displayname(self) -> None:
  247. """Changes to state events for a room should be processed, but not end up in the room."""
  248. original_display_name = "banned"
  249. new_display_name = "new name"
  250. # Join a room.
  251. room_id = self.helper.create_room_as(
  252. self.banned_user_id, tok=self.banned_access_token
  253. )
  254. # The update should succeed.
  255. channel = self.make_request(
  256. "PUT",
  257. "/_matrix/client/r0/rooms/%s/state/m.room.member/%s"
  258. % (room_id, self.banned_user_id),
  259. {"membership": "join", "displayname": new_display_name},
  260. access_token=self.banned_access_token,
  261. )
  262. self.assertEqual(200, channel.code, channel.result)
  263. self.assertIn("event_id", channel.json_body)
  264. # The display name in the room should not be changed.
  265. message_handler = self.hs.get_message_handler()
  266. event = self.get_success(
  267. message_handler.get_room_data(
  268. create_requester(self.banned_user_id),
  269. room_id,
  270. "m.room.member",
  271. self.banned_user_id,
  272. )
  273. )
  274. self.assertEqual(
  275. event.content, {"membership": "join", "displayname": original_display_name}
  276. )