test_redactions.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. # Copyright 2019 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 typing import List
  15. from twisted.test.proto_helpers import MemoryReactor
  16. from synapse.rest import admin
  17. from synapse.rest.client import login, room, sync
  18. from synapse.server import HomeServer
  19. from synapse.types import JsonDict
  20. from synapse.util import Clock
  21. from tests.unittest import HomeserverTestCase
  22. class RedactionsTestCase(HomeserverTestCase):
  23. """Tests that various redaction events are handled correctly"""
  24. servlets = [
  25. admin.register_servlets,
  26. room.register_servlets,
  27. login.register_servlets,
  28. sync.register_servlets,
  29. ]
  30. def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:
  31. config = self.default_config()
  32. config["rc_message"] = {"per_second": 0.2, "burst_count": 10}
  33. config["rc_admin_redaction"] = {"per_second": 1, "burst_count": 100}
  34. return self.setup_test_homeserver(config=config)
  35. def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
  36. # register a couple of users
  37. self.mod_user_id = self.register_user("user1", "pass")
  38. self.mod_access_token = self.login("user1", "pass")
  39. self.other_user_id = self.register_user("otheruser", "pass")
  40. self.other_access_token = self.login("otheruser", "pass")
  41. # Create a room
  42. self.room_id = self.helper.create_room_as(
  43. self.mod_user_id, tok=self.mod_access_token
  44. )
  45. # Invite the other user
  46. self.helper.invite(
  47. room=self.room_id,
  48. src=self.mod_user_id,
  49. tok=self.mod_access_token,
  50. targ=self.other_user_id,
  51. )
  52. # The other user joins
  53. self.helper.join(
  54. room=self.room_id, user=self.other_user_id, tok=self.other_access_token
  55. )
  56. def _redact_event(
  57. self, access_token: str, room_id: str, event_id: str, expect_code: int = 200
  58. ) -> JsonDict:
  59. """Helper function to send a redaction event.
  60. Returns the json body.
  61. """
  62. path = "/_matrix/client/r0/rooms/%s/redact/%s" % (room_id, event_id)
  63. channel = self.make_request("POST", path, content={}, access_token=access_token)
  64. self.assertEqual(channel.code, expect_code)
  65. return channel.json_body
  66. def _sync_room_timeline(self, access_token: str, room_id: str) -> List[JsonDict]:
  67. channel = self.make_request("GET", "sync", access_token=self.mod_access_token)
  68. self.assertEqual(channel.code, 200)
  69. room_sync = channel.json_body["rooms"]["join"][room_id]
  70. return room_sync["timeline"]["events"]
  71. def test_redact_event_as_moderator(self) -> None:
  72. # as a regular user, send a message to redact
  73. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  74. msg_id = b["event_id"]
  75. # as the moderator, send a redaction
  76. b = self._redact_event(self.mod_access_token, self.room_id, msg_id)
  77. redaction_id = b["event_id"]
  78. # now sync
  79. timeline = self._sync_room_timeline(self.mod_access_token, self.room_id)
  80. # the last event should be the redaction
  81. self.assertEqual(timeline[-1]["event_id"], redaction_id)
  82. self.assertEqual(timeline[-1]["redacts"], msg_id)
  83. # and the penultimate should be the redacted original
  84. self.assertEqual(timeline[-2]["event_id"], msg_id)
  85. self.assertEqual(timeline[-2]["unsigned"]["redacted_by"], redaction_id)
  86. self.assertEqual(timeline[-2]["content"], {})
  87. def test_redact_event_as_normal(self) -> None:
  88. # as a regular user, send a message to redact
  89. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  90. normal_msg_id = b["event_id"]
  91. # also send one as the admin
  92. b = self.helper.send(room_id=self.room_id, tok=self.mod_access_token)
  93. admin_msg_id = b["event_id"]
  94. # as a normal, try to redact the admin's event
  95. self._redact_event(
  96. self.other_access_token, self.room_id, admin_msg_id, expect_code=403
  97. )
  98. # now try to redact our own event
  99. b = self._redact_event(self.other_access_token, self.room_id, normal_msg_id)
  100. redaction_id = b["event_id"]
  101. # now sync
  102. timeline = self._sync_room_timeline(self.other_access_token, self.room_id)
  103. # the last event should be the redaction of the normal event
  104. self.assertEqual(timeline[-1]["event_id"], redaction_id)
  105. self.assertEqual(timeline[-1]["redacts"], normal_msg_id)
  106. # the penultimate should be the unredacted one from the admin
  107. self.assertEqual(timeline[-2]["event_id"], admin_msg_id)
  108. self.assertNotIn("redacted_by", timeline[-2]["unsigned"])
  109. self.assertTrue(timeline[-2]["content"]["body"], {})
  110. # and the antepenultimate should be the redacted normal
  111. self.assertEqual(timeline[-3]["event_id"], normal_msg_id)
  112. self.assertEqual(timeline[-3]["unsigned"]["redacted_by"], redaction_id)
  113. self.assertEqual(timeline[-3]["content"], {})
  114. def test_redact_nonexistent_event(self) -> None:
  115. # control case: an existing event
  116. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  117. msg_id = b["event_id"]
  118. b = self._redact_event(self.other_access_token, self.room_id, msg_id)
  119. redaction_id = b["event_id"]
  120. # room moderators can send redactions for non-existent events
  121. self._redact_event(self.mod_access_token, self.room_id, "$zzz")
  122. # ... but normals cannot
  123. self._redact_event(
  124. self.other_access_token, self.room_id, "$zzz", expect_code=404
  125. )
  126. # when we sync, we should see only the valid redaction
  127. timeline = self._sync_room_timeline(self.other_access_token, self.room_id)
  128. self.assertEqual(timeline[-1]["event_id"], redaction_id)
  129. self.assertEqual(timeline[-1]["redacts"], msg_id)
  130. # and the penultimate should be the redacted original
  131. self.assertEqual(timeline[-2]["event_id"], msg_id)
  132. self.assertEqual(timeline[-2]["unsigned"]["redacted_by"], redaction_id)
  133. self.assertEqual(timeline[-2]["content"], {})
  134. def test_redact_create_event(self) -> None:
  135. # control case: an existing event
  136. b = self.helper.send(room_id=self.room_id, tok=self.mod_access_token)
  137. msg_id = b["event_id"]
  138. self._redact_event(self.mod_access_token, self.room_id, msg_id)
  139. # sync the room, to get the id of the create event
  140. timeline = self._sync_room_timeline(self.other_access_token, self.room_id)
  141. create_event_id = timeline[0]["event_id"]
  142. # room moderators cannot send redactions for create events
  143. self._redact_event(
  144. self.mod_access_token, self.room_id, create_event_id, expect_code=403
  145. )
  146. # and nor can normals
  147. self._redact_event(
  148. self.other_access_token, self.room_id, create_event_id, expect_code=403
  149. )
  150. def test_redact_event_as_moderator_ratelimit(self) -> None:
  151. """Tests that the correct ratelimiting is applied to redactions"""
  152. message_ids = []
  153. # as a regular user, send messages to redact
  154. for _ in range(20):
  155. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  156. message_ids.append(b["event_id"])
  157. self.reactor.advance(10) # To get around ratelimits
  158. # as the moderator, send a bunch of redactions
  159. for msg_id in message_ids:
  160. # These should all succeed, even though this would be denied by
  161. # the standard message ratelimiter
  162. self._redact_event(self.mod_access_token, self.room_id, msg_id)