test_federation.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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. import logging
  16. from unittest import TestCase
  17. from synapse.api.constants import EventTypes
  18. from synapse.api.errors import AuthError, Codes, SynapseError
  19. from synapse.api.room_versions import RoomVersions
  20. from synapse.events import EventBase
  21. from synapse.federation.federation_base import event_from_pdu_json
  22. from synapse.logging.context import LoggingContext, run_in_background
  23. from synapse.rest import admin
  24. from synapse.rest.client.v1 import login, room
  25. from tests import unittest
  26. logger = logging.getLogger(__name__)
  27. class FederationTestCase(unittest.HomeserverTestCase):
  28. servlets = [
  29. admin.register_servlets,
  30. login.register_servlets,
  31. room.register_servlets,
  32. ]
  33. def make_homeserver(self, reactor, clock):
  34. hs = self.setup_test_homeserver(http_client=None)
  35. self.handler = hs.get_handlers().federation_handler
  36. self.store = hs.get_datastore()
  37. return hs
  38. def test_exchange_revoked_invite(self):
  39. user_id = self.register_user("kermit", "test")
  40. tok = self.login("kermit", "test")
  41. room_id = self.helper.create_room_as(room_creator=user_id, tok=tok)
  42. # Send a 3PID invite event with an empty body so it's considered as a revoked one.
  43. invite_token = "sometoken"
  44. self.helper.send_state(
  45. room_id=room_id,
  46. event_type=EventTypes.ThirdPartyInvite,
  47. state_key=invite_token,
  48. body={},
  49. tok=tok,
  50. )
  51. d = self.handler.on_exchange_third_party_invite_request(
  52. room_id=room_id,
  53. event_dict={
  54. "type": EventTypes.Member,
  55. "room_id": room_id,
  56. "sender": user_id,
  57. "state_key": "@someone:example.org",
  58. "content": {
  59. "membership": "invite",
  60. "third_party_invite": {
  61. "display_name": "alice",
  62. "signed": {
  63. "mxid": "@alice:localhost",
  64. "token": invite_token,
  65. "signatures": {
  66. "magic.forest": {
  67. "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
  68. }
  69. },
  70. },
  71. },
  72. },
  73. },
  74. )
  75. failure = self.get_failure(d, AuthError).value
  76. self.assertEqual(failure.code, 403, failure)
  77. self.assertEqual(failure.errcode, Codes.FORBIDDEN, failure)
  78. self.assertEqual(failure.msg, "You are not invited to this room.")
  79. def test_rejected_message_event_state(self):
  80. """
  81. Check that we store the state group correctly for rejected non-state events.
  82. Regression test for #6289.
  83. """
  84. OTHER_SERVER = "otherserver"
  85. OTHER_USER = "@otheruser:" + OTHER_SERVER
  86. # create the room
  87. user_id = self.register_user("kermit", "test")
  88. tok = self.login("kermit", "test")
  89. room_id = self.helper.create_room_as(room_creator=user_id, tok=tok)
  90. room_version = self.get_success(self.store.get_room_version(room_id))
  91. # pretend that another server has joined
  92. join_event = self._build_and_send_join_event(OTHER_SERVER, OTHER_USER, room_id)
  93. # check the state group
  94. sg = self.successResultOf(
  95. self.store._get_state_group_for_event(join_event.event_id)
  96. )
  97. # build and send an event which will be rejected
  98. ev = event_from_pdu_json(
  99. {
  100. "type": EventTypes.Message,
  101. "content": {},
  102. "room_id": room_id,
  103. "sender": "@yetanotheruser:" + OTHER_SERVER,
  104. "depth": join_event["depth"] + 1,
  105. "prev_events": [join_event.event_id],
  106. "auth_events": [],
  107. "origin_server_ts": self.clock.time_msec(),
  108. },
  109. room_version,
  110. )
  111. with LoggingContext(request="send_rejected"):
  112. d = run_in_background(self.handler.on_receive_pdu, OTHER_SERVER, ev)
  113. self.get_success(d)
  114. # that should have been rejected
  115. e = self.get_success(self.store.get_event(ev.event_id, allow_rejected=True))
  116. self.assertIsNotNone(e.rejected_reason)
  117. # ... and the state group should be the same as before
  118. sg2 = self.successResultOf(self.store._get_state_group_for_event(ev.event_id))
  119. self.assertEqual(sg, sg2)
  120. def test_rejected_state_event_state(self):
  121. """
  122. Check that we store the state group correctly for rejected state events.
  123. Regression test for #6289.
  124. """
  125. OTHER_SERVER = "otherserver"
  126. OTHER_USER = "@otheruser:" + OTHER_SERVER
  127. # create the room
  128. user_id = self.register_user("kermit", "test")
  129. tok = self.login("kermit", "test")
  130. room_id = self.helper.create_room_as(room_creator=user_id, tok=tok)
  131. room_version = self.get_success(self.store.get_room_version(room_id))
  132. # pretend that another server has joined
  133. join_event = self._build_and_send_join_event(OTHER_SERVER, OTHER_USER, room_id)
  134. # check the state group
  135. sg = self.successResultOf(
  136. self.store._get_state_group_for_event(join_event.event_id)
  137. )
  138. # build and send an event which will be rejected
  139. ev = event_from_pdu_json(
  140. {
  141. "type": "org.matrix.test",
  142. "state_key": "test_key",
  143. "content": {},
  144. "room_id": room_id,
  145. "sender": "@yetanotheruser:" + OTHER_SERVER,
  146. "depth": join_event["depth"] + 1,
  147. "prev_events": [join_event.event_id],
  148. "auth_events": [],
  149. "origin_server_ts": self.clock.time_msec(),
  150. },
  151. room_version,
  152. )
  153. with LoggingContext(request="send_rejected"):
  154. d = run_in_background(self.handler.on_receive_pdu, OTHER_SERVER, ev)
  155. self.get_success(d)
  156. # that should have been rejected
  157. e = self.get_success(self.store.get_event(ev.event_id, allow_rejected=True))
  158. self.assertIsNotNone(e.rejected_reason)
  159. # ... and the state group should be the same as before
  160. sg2 = self.successResultOf(self.store._get_state_group_for_event(ev.event_id))
  161. self.assertEqual(sg, sg2)
  162. def _build_and_send_join_event(self, other_server, other_user, room_id):
  163. join_event = self.get_success(
  164. self.handler.on_make_join_request(other_server, room_id, other_user)
  165. )
  166. # the auth code requires that a signature exists, but doesn't check that
  167. # signature... go figure.
  168. join_event.signatures[other_server] = {"x": "y"}
  169. with LoggingContext(request="send_join"):
  170. d = run_in_background(
  171. self.handler.on_send_join_request, other_server, join_event
  172. )
  173. self.get_success(d)
  174. # sanity-check: the room should show that the new user is a member
  175. r = self.get_success(self.store.get_current_state_ids(room_id))
  176. self.assertEqual(r[(EventTypes.Member, other_user)], join_event.event_id)
  177. return join_event
  178. class EventFromPduTestCase(TestCase):
  179. def test_valid_json(self):
  180. """Valid JSON should be turned into an event."""
  181. ev = event_from_pdu_json(
  182. {
  183. "type": EventTypes.Message,
  184. "content": {"bool": True, "null": None, "int": 1, "str": "foobar"},
  185. "room_id": "!room:test",
  186. "sender": "@user:test",
  187. "depth": 1,
  188. "prev_events": [],
  189. "auth_events": [],
  190. "origin_server_ts": 1234,
  191. },
  192. RoomVersions.V6,
  193. )
  194. self.assertIsInstance(ev, EventBase)
  195. def test_invalid_numbers(self):
  196. """Invalid values for an integer should be rejected, all floats should be rejected."""
  197. for value in [
  198. -(2 ** 53),
  199. 2 ** 53,
  200. 1.0,
  201. float("inf"),
  202. float("-inf"),
  203. float("nan"),
  204. ]:
  205. with self.assertRaises(SynapseError):
  206. event_from_pdu_json(
  207. {
  208. "type": EventTypes.Message,
  209. "content": {"foo": value},
  210. "room_id": "!room:test",
  211. "sender": "@user:test",
  212. "depth": 1,
  213. "prev_events": [],
  214. "auth_events": [],
  215. "origin_server_ts": 1234,
  216. },
  217. RoomVersions.V6,
  218. )
  219. def test_invalid_nested(self):
  220. """List and dictionaries are recursively searched."""
  221. with self.assertRaises(SynapseError):
  222. event_from_pdu_json(
  223. {
  224. "type": EventTypes.Message,
  225. "content": {"foo": [{"bar": 2 ** 56}]},
  226. "room_id": "!room:test",
  227. "sender": "@user:test",
  228. "depth": 1,
  229. "prev_events": [],
  230. "auth_events": [],
  231. "origin_server_ts": 1234,
  232. },
  233. RoomVersions.V6,
  234. )