test_redactions.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2019 The Matrix.org Foundation C.I.C.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from synapse.rest import admin
  16. from synapse.rest.client.v1 import login, room
  17. from synapse.rest.client.v2_alpha import sync
  18. from tests.unittest import HomeserverTestCase
  19. class RedactionsTestCase(HomeserverTestCase):
  20. """Tests that various redaction events are handled correctly"""
  21. servlets = [
  22. admin.register_servlets,
  23. room.register_servlets,
  24. login.register_servlets,
  25. sync.register_servlets,
  26. ]
  27. def make_homeserver(self, reactor, clock):
  28. config = self.default_config()
  29. config["rc_message"] = {"per_second": 0.2, "burst_count": 10}
  30. config["rc_admin_redaction"] = {"per_second": 1, "burst_count": 100}
  31. return self.setup_test_homeserver(config=config)
  32. def prepare(self, reactor, clock, hs):
  33. # register a couple of users
  34. self.mod_user_id = self.register_user("user1", "pass")
  35. self.mod_access_token = self.login("user1", "pass")
  36. self.other_user_id = self.register_user("otheruser", "pass")
  37. self.other_access_token = self.login("otheruser", "pass")
  38. # Create a room
  39. self.room_id = self.helper.create_room_as(
  40. self.mod_user_id, tok=self.mod_access_token
  41. )
  42. # Invite the other user
  43. self.helper.invite(
  44. room=self.room_id,
  45. src=self.mod_user_id,
  46. tok=self.mod_access_token,
  47. targ=self.other_user_id,
  48. )
  49. # The other user joins
  50. self.helper.join(
  51. room=self.room_id, user=self.other_user_id, tok=self.other_access_token
  52. )
  53. def _redact_event(self, access_token, room_id, event_id, expect_code=200):
  54. """Helper function to send a redaction event.
  55. Returns the json body.
  56. """
  57. path = "/_matrix/client/r0/rooms/%s/redact/%s" % (room_id, event_id)
  58. channel = self.make_request("POST", path, content={}, access_token=access_token)
  59. self.assertEqual(int(channel.result["code"]), expect_code)
  60. return channel.json_body
  61. def _sync_room_timeline(self, access_token, room_id):
  62. channel = self.make_request("GET", "sync", access_token=self.mod_access_token)
  63. self.assertEqual(channel.result["code"], b"200")
  64. room_sync = channel.json_body["rooms"]["join"][room_id]
  65. return room_sync["timeline"]["events"]
  66. def test_redact_event_as_moderator(self):
  67. # as a regular user, send a message to redact
  68. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  69. msg_id = b["event_id"]
  70. # as the moderator, send a redaction
  71. b = self._redact_event(self.mod_access_token, self.room_id, msg_id)
  72. redaction_id = b["event_id"]
  73. # now sync
  74. timeline = self._sync_room_timeline(self.mod_access_token, self.room_id)
  75. # the last event should be the redaction
  76. self.assertEqual(timeline[-1]["event_id"], redaction_id)
  77. self.assertEqual(timeline[-1]["redacts"], msg_id)
  78. # and the penultimate should be the redacted original
  79. self.assertEqual(timeline[-2]["event_id"], msg_id)
  80. self.assertEqual(timeline[-2]["unsigned"]["redacted_by"], redaction_id)
  81. self.assertEqual(timeline[-2]["content"], {})
  82. def test_redact_event_as_normal(self):
  83. # as a regular user, send a message to redact
  84. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  85. normal_msg_id = b["event_id"]
  86. # also send one as the admin
  87. b = self.helper.send(room_id=self.room_id, tok=self.mod_access_token)
  88. admin_msg_id = b["event_id"]
  89. # as a normal, try to redact the admin's event
  90. self._redact_event(
  91. self.other_access_token, self.room_id, admin_msg_id, expect_code=403
  92. )
  93. # now try to redact our own event
  94. b = self._redact_event(self.other_access_token, self.room_id, normal_msg_id)
  95. redaction_id = b["event_id"]
  96. # now sync
  97. timeline = self._sync_room_timeline(self.other_access_token, self.room_id)
  98. # the last event should be the redaction of the normal event
  99. self.assertEqual(timeline[-1]["event_id"], redaction_id)
  100. self.assertEqual(timeline[-1]["redacts"], normal_msg_id)
  101. # the penultimate should be the unredacted one from the admin
  102. self.assertEqual(timeline[-2]["event_id"], admin_msg_id)
  103. self.assertNotIn("redacted_by", timeline[-2]["unsigned"])
  104. self.assertTrue(timeline[-2]["content"]["body"], {})
  105. # and the antepenultimate should be the redacted normal
  106. self.assertEqual(timeline[-3]["event_id"], normal_msg_id)
  107. self.assertEqual(timeline[-3]["unsigned"]["redacted_by"], redaction_id)
  108. self.assertEqual(timeline[-3]["content"], {})
  109. def test_redact_nonexistent_event(self):
  110. # control case: an existing event
  111. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  112. msg_id = b["event_id"]
  113. b = self._redact_event(self.other_access_token, self.room_id, msg_id)
  114. redaction_id = b["event_id"]
  115. # room moderators can send redactions for non-existent events
  116. self._redact_event(self.mod_access_token, self.room_id, "$zzz")
  117. # ... but normals cannot
  118. self._redact_event(
  119. self.other_access_token, self.room_id, "$zzz", expect_code=404
  120. )
  121. # when we sync, we should see only the valid redaction
  122. timeline = self._sync_room_timeline(self.other_access_token, self.room_id)
  123. self.assertEqual(timeline[-1]["event_id"], redaction_id)
  124. self.assertEqual(timeline[-1]["redacts"], msg_id)
  125. # and the penultimate should be the redacted original
  126. self.assertEqual(timeline[-2]["event_id"], msg_id)
  127. self.assertEqual(timeline[-2]["unsigned"]["redacted_by"], redaction_id)
  128. self.assertEqual(timeline[-2]["content"], {})
  129. def test_redact_create_event(self):
  130. # control case: an existing event
  131. b = self.helper.send(room_id=self.room_id, tok=self.mod_access_token)
  132. msg_id = b["event_id"]
  133. self._redact_event(self.mod_access_token, self.room_id, msg_id)
  134. # sync the room, to get the id of the create event
  135. timeline = self._sync_room_timeline(self.other_access_token, self.room_id)
  136. create_event_id = timeline[0]["event_id"]
  137. # room moderators cannot send redactions for create events
  138. self._redact_event(
  139. self.mod_access_token, self.room_id, create_event_id, expect_code=403
  140. )
  141. # and nor can normals
  142. self._redact_event(
  143. self.other_access_token, self.room_id, create_event_id, expect_code=403
  144. )
  145. def test_redact_event_as_moderator_ratelimit(self):
  146. """Tests that the correct ratelimiting is applied to redactions
  147. """
  148. message_ids = []
  149. # as a regular user, send messages to redact
  150. for _ in range(20):
  151. b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
  152. message_ids.append(b["event_id"])
  153. self.reactor.advance(10) # To get around ratelimits
  154. # as the moderator, send a bunch of redactions
  155. for msg_id in message_ids:
  156. # These should all succeed, even though this would be denied by
  157. # the standard message ratelimiter
  158. self._redact_event(self.mod_access_token, self.room_id, msg_id)