You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

434 lines
16 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2015, 2016 OpenMarket Ltd
  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 mock import Mock
  16. import jsonschema
  17. from twisted.internet import defer
  18. from synapse.api.errors import SynapseError
  19. from synapse.api.filtering import Filter
  20. from synapse.events import FrozenEvent
  21. from tests import unittest
  22. from tests.utils import DeferredMockCallable, MockHttpResource, setup_test_homeserver
  23. user_localpart = "test_user"
  24. def MockEvent(**kwargs):
  25. if "event_id" not in kwargs:
  26. kwargs["event_id"] = "fake_event_id"
  27. if "type" not in kwargs:
  28. kwargs["type"] = "fake_type"
  29. return FrozenEvent(kwargs)
  30. class FilteringTestCase(unittest.TestCase):
  31. @defer.inlineCallbacks
  32. def setUp(self):
  33. self.mock_federation_resource = MockHttpResource()
  34. self.mock_http_client = Mock(spec=[])
  35. self.mock_http_client.put_json = DeferredMockCallable()
  36. hs = yield setup_test_homeserver(
  37. self.addCleanup,
  38. handlers=None,
  39. http_client=self.mock_http_client,
  40. keyring=Mock(),
  41. )
  42. self.filtering = hs.get_filtering()
  43. self.datastore = hs.get_datastore()
  44. def test_errors_on_invalid_filters(self):
  45. invalid_filters = [
  46. {"boom": {}},
  47. {"account_data": "Hello World"},
  48. {"event_fields": ["\\foo"]},
  49. {"room": {"timeline": {"limit": 0}, "state": {"not_bars": ["*"]}}},
  50. {"event_format": "other"},
  51. {"room": {"not_rooms": ["#foo:pik-test"]}},
  52. {"presence": {"senders": ["@bar;pik.test.com"]}},
  53. ]
  54. for filter in invalid_filters:
  55. with self.assertRaises(SynapseError) as check_filter_error:
  56. self.filtering.check_valid_filter(filter)
  57. self.assertIsInstance(check_filter_error.exception, SynapseError)
  58. def test_valid_filters(self):
  59. valid_filters = [
  60. {
  61. "room": {
  62. "timeline": {"limit": 20},
  63. "state": {"not_types": ["m.room.member"]},
  64. "ephemeral": {"limit": 0, "not_types": ["*"]},
  65. "include_leave": False,
  66. "rooms": ["!dee:pik-test"],
  67. "not_rooms": ["!gee:pik-test"],
  68. "account_data": {"limit": 0, "types": ["*"]},
  69. }
  70. },
  71. {
  72. "room": {
  73. "state": {
  74. "types": ["m.room.*"],
  75. "not_rooms": ["!726s6s6q:example.com"],
  76. },
  77. "timeline": {
  78. "limit": 10,
  79. "types": ["m.room.message"],
  80. "not_rooms": ["!726s6s6q:example.com"],
  81. "not_senders": ["@spam:example.com"],
  82. },
  83. "ephemeral": {
  84. "types": ["m.receipt", "m.typing"],
  85. "not_rooms": ["!726s6s6q:example.com"],
  86. "not_senders": ["@spam:example.com"],
  87. },
  88. },
  89. "presence": {
  90. "types": ["m.presence"],
  91. "not_senders": ["@alice:example.com"],
  92. },
  93. "event_format": "client",
  94. "event_fields": ["type", "content", "sender"],
  95. },
  96. ]
  97. for filter in valid_filters:
  98. try:
  99. self.filtering.check_valid_filter(filter)
  100. except jsonschema.ValidationError as e:
  101. self.fail(e)
  102. def test_limits_are_applied(self):
  103. # TODO
  104. pass
  105. def test_definition_types_works_with_literals(self):
  106. definition = {"types": ["m.room.message", "org.matrix.foo.bar"]}
  107. event = MockEvent(sender="@foo:bar", type="m.room.message", room_id="!foo:bar")
  108. self.assertTrue(Filter(definition).check(event))
  109. def test_definition_types_works_with_wildcards(self):
  110. definition = {"types": ["m.*", "org.matrix.foo.bar"]}
  111. event = MockEvent(sender="@foo:bar", type="m.room.message", room_id="!foo:bar")
  112. self.assertTrue(Filter(definition).check(event))
  113. def test_definition_types_works_with_unknowns(self):
  114. definition = {"types": ["m.room.message", "org.matrix.foo.bar"]}
  115. event = MockEvent(
  116. sender="@foo:bar",
  117. type="now.for.something.completely.different",
  118. room_id="!foo:bar",
  119. )
  120. self.assertFalse(Filter(definition).check(event))
  121. def test_definition_not_types_works_with_literals(self):
  122. definition = {"not_types": ["m.room.message", "org.matrix.foo.bar"]}
  123. event = MockEvent(sender="@foo:bar", type="m.room.message", room_id="!foo:bar")
  124. self.assertFalse(Filter(definition).check(event))
  125. def test_definition_not_types_works_with_wildcards(self):
  126. definition = {"not_types": ["m.room.message", "org.matrix.*"]}
  127. event = MockEvent(
  128. sender="@foo:bar", type="org.matrix.custom.event", room_id="!foo:bar"
  129. )
  130. self.assertFalse(Filter(definition).check(event))
  131. def test_definition_not_types_works_with_unknowns(self):
  132. definition = {"not_types": ["m.*", "org.*"]}
  133. event = MockEvent(sender="@foo:bar", type="com.nom.nom.nom", room_id="!foo:bar")
  134. self.assertTrue(Filter(definition).check(event))
  135. def test_definition_not_types_takes_priority_over_types(self):
  136. definition = {
  137. "not_types": ["m.*", "org.*"],
  138. "types": ["m.room.message", "m.room.topic"],
  139. }
  140. event = MockEvent(sender="@foo:bar", type="m.room.topic", room_id="!foo:bar")
  141. self.assertFalse(Filter(definition).check(event))
  142. def test_definition_senders_works_with_literals(self):
  143. definition = {"senders": ["@flibble:wibble"]}
  144. event = MockEvent(
  145. sender="@flibble:wibble", type="com.nom.nom.nom", room_id="!foo:bar"
  146. )
  147. self.assertTrue(Filter(definition).check(event))
  148. def test_definition_senders_works_with_unknowns(self):
  149. definition = {"senders": ["@flibble:wibble"]}
  150. event = MockEvent(
  151. sender="@challenger:appears", type="com.nom.nom.nom", room_id="!foo:bar"
  152. )
  153. self.assertFalse(Filter(definition).check(event))
  154. def test_definition_not_senders_works_with_literals(self):
  155. definition = {"not_senders": ["@flibble:wibble"]}
  156. event = MockEvent(
  157. sender="@flibble:wibble", type="com.nom.nom.nom", room_id="!foo:bar"
  158. )
  159. self.assertFalse(Filter(definition).check(event))
  160. def test_definition_not_senders_works_with_unknowns(self):
  161. definition = {"not_senders": ["@flibble:wibble"]}
  162. event = MockEvent(
  163. sender="@challenger:appears", type="com.nom.nom.nom", room_id="!foo:bar"
  164. )
  165. self.assertTrue(Filter(definition).check(event))
  166. def test_definition_not_senders_takes_priority_over_senders(self):
  167. definition = {
  168. "not_senders": ["@misspiggy:muppets"],
  169. "senders": ["@kermit:muppets", "@misspiggy:muppets"],
  170. }
  171. event = MockEvent(
  172. sender="@misspiggy:muppets", type="m.room.topic", room_id="!foo:bar"
  173. )
  174. self.assertFalse(Filter(definition).check(event))
  175. def test_definition_rooms_works_with_literals(self):
  176. definition = {"rooms": ["!secretbase:unknown"]}
  177. event = MockEvent(
  178. sender="@foo:bar", type="m.room.message", room_id="!secretbase:unknown"
  179. )
  180. self.assertTrue(Filter(definition).check(event))
  181. def test_definition_rooms_works_with_unknowns(self):
  182. definition = {"rooms": ["!secretbase:unknown"]}
  183. event = MockEvent(
  184. sender="@foo:bar",
  185. type="m.room.message",
  186. room_id="!anothersecretbase:unknown",
  187. )
  188. self.assertFalse(Filter(definition).check(event))
  189. def test_definition_not_rooms_works_with_literals(self):
  190. definition = {"not_rooms": ["!anothersecretbase:unknown"]}
  191. event = MockEvent(
  192. sender="@foo:bar",
  193. type="m.room.message",
  194. room_id="!anothersecretbase:unknown",
  195. )
  196. self.assertFalse(Filter(definition).check(event))
  197. def test_definition_not_rooms_works_with_unknowns(self):
  198. definition = {"not_rooms": ["!secretbase:unknown"]}
  199. event = MockEvent(
  200. sender="@foo:bar",
  201. type="m.room.message",
  202. room_id="!anothersecretbase:unknown",
  203. )
  204. self.assertTrue(Filter(definition).check(event))
  205. def test_definition_not_rooms_takes_priority_over_rooms(self):
  206. definition = {
  207. "not_rooms": ["!secretbase:unknown"],
  208. "rooms": ["!secretbase:unknown"],
  209. }
  210. event = MockEvent(
  211. sender="@foo:bar", type="m.room.message", room_id="!secretbase:unknown"
  212. )
  213. self.assertFalse(Filter(definition).check(event))
  214. def test_definition_combined_event(self):
  215. definition = {
  216. "not_senders": ["@misspiggy:muppets"],
  217. "senders": ["@kermit:muppets"],
  218. "rooms": ["!stage:unknown"],
  219. "not_rooms": ["!piggyshouse:muppets"],
  220. "types": ["m.room.message", "muppets.kermit.*"],
  221. "not_types": ["muppets.misspiggy.*"],
  222. }
  223. event = MockEvent(
  224. sender="@kermit:muppets", # yup
  225. type="m.room.message", # yup
  226. room_id="!stage:unknown", # yup
  227. )
  228. self.assertTrue(Filter(definition).check(event))
  229. def test_definition_combined_event_bad_sender(self):
  230. definition = {
  231. "not_senders": ["@misspiggy:muppets"],
  232. "senders": ["@kermit:muppets"],
  233. "rooms": ["!stage:unknown"],
  234. "not_rooms": ["!piggyshouse:muppets"],
  235. "types": ["m.room.message", "muppets.kermit.*"],
  236. "not_types": ["muppets.misspiggy.*"],
  237. }
  238. event = MockEvent(
  239. sender="@misspiggy:muppets", # nope
  240. type="m.room.message", # yup
  241. room_id="!stage:unknown", # yup
  242. )
  243. self.assertFalse(Filter(definition).check(event))
  244. def test_definition_combined_event_bad_room(self):
  245. definition = {
  246. "not_senders": ["@misspiggy:muppets"],
  247. "senders": ["@kermit:muppets"],
  248. "rooms": ["!stage:unknown"],
  249. "not_rooms": ["!piggyshouse:muppets"],
  250. "types": ["m.room.message", "muppets.kermit.*"],
  251. "not_types": ["muppets.misspiggy.*"],
  252. }
  253. event = MockEvent(
  254. sender="@kermit:muppets", # yup
  255. type="m.room.message", # yup
  256. room_id="!piggyshouse:muppets", # nope
  257. )
  258. self.assertFalse(Filter(definition).check(event))
  259. def test_definition_combined_event_bad_type(self):
  260. definition = {
  261. "not_senders": ["@misspiggy:muppets"],
  262. "senders": ["@kermit:muppets"],
  263. "rooms": ["!stage:unknown"],
  264. "not_rooms": ["!piggyshouse:muppets"],
  265. "types": ["m.room.message", "muppets.kermit.*"],
  266. "not_types": ["muppets.misspiggy.*"],
  267. }
  268. event = MockEvent(
  269. sender="@kermit:muppets", # yup
  270. type="muppets.misspiggy.kisses", # nope
  271. room_id="!stage:unknown", # yup
  272. )
  273. self.assertFalse(Filter(definition).check(event))
  274. @defer.inlineCallbacks
  275. def test_filter_presence_match(self):
  276. user_filter_json = {"presence": {"types": ["m.*"]}}
  277. filter_id = yield self.datastore.add_user_filter(
  278. user_localpart=user_localpart, user_filter=user_filter_json
  279. )
  280. event = MockEvent(sender="@foo:bar", type="m.profile")
  281. events = [event]
  282. user_filter = yield self.filtering.get_user_filter(
  283. user_localpart=user_localpart, filter_id=filter_id
  284. )
  285. results = user_filter.filter_presence(events=events)
  286. self.assertEquals(events, results)
  287. @defer.inlineCallbacks
  288. def test_filter_presence_no_match(self):
  289. user_filter_json = {"presence": {"types": ["m.*"]}}
  290. filter_id = yield self.datastore.add_user_filter(
  291. user_localpart=user_localpart + "2", user_filter=user_filter_json
  292. )
  293. event = MockEvent(
  294. event_id="$asdasd:localhost",
  295. sender="@foo:bar",
  296. type="custom.avatar.3d.crazy",
  297. )
  298. events = [event]
  299. user_filter = yield self.filtering.get_user_filter(
  300. user_localpart=user_localpart + "2", filter_id=filter_id
  301. )
  302. results = user_filter.filter_presence(events=events)
  303. self.assertEquals([], results)
  304. @defer.inlineCallbacks
  305. def test_filter_room_state_match(self):
  306. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  307. filter_id = yield self.datastore.add_user_filter(
  308. user_localpart=user_localpart, user_filter=user_filter_json
  309. )
  310. event = MockEvent(sender="@foo:bar", type="m.room.topic", room_id="!foo:bar")
  311. events = [event]
  312. user_filter = yield self.filtering.get_user_filter(
  313. user_localpart=user_localpart, filter_id=filter_id
  314. )
  315. results = user_filter.filter_room_state(events=events)
  316. self.assertEquals(events, results)
  317. @defer.inlineCallbacks
  318. def test_filter_room_state_no_match(self):
  319. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  320. filter_id = yield self.datastore.add_user_filter(
  321. user_localpart=user_localpart, user_filter=user_filter_json
  322. )
  323. event = MockEvent(
  324. sender="@foo:bar", type="org.matrix.custom.event", room_id="!foo:bar"
  325. )
  326. events = [event]
  327. user_filter = yield self.filtering.get_user_filter(
  328. user_localpart=user_localpart, filter_id=filter_id
  329. )
  330. results = user_filter.filter_room_state(events)
  331. self.assertEquals([], results)
  332. def test_filter_rooms(self):
  333. definition = {
  334. "rooms": ["!allowed:example.com", "!excluded:example.com"],
  335. "not_rooms": ["!excluded:example.com"],
  336. }
  337. room_ids = [
  338. "!allowed:example.com", # Allowed because in rooms and not in not_rooms.
  339. "!excluded:example.com", # Disallowed because in not_rooms.
  340. "!not_included:example.com", # Disallowed because not in rooms.
  341. ]
  342. filtered_room_ids = list(Filter(definition).filter_rooms(room_ids))
  343. self.assertEquals(filtered_room_ids, ["!allowed:example.com"])
  344. @defer.inlineCallbacks
  345. def test_add_filter(self):
  346. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  347. filter_id = yield self.filtering.add_user_filter(
  348. user_localpart=user_localpart, user_filter=user_filter_json
  349. )
  350. self.assertEquals(filter_id, 0)
  351. self.assertEquals(
  352. user_filter_json,
  353. (
  354. yield self.datastore.get_user_filter(
  355. user_localpart=user_localpart, filter_id=0
  356. )
  357. ),
  358. )
  359. @defer.inlineCallbacks
  360. def test_get_filter(self):
  361. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  362. filter_id = yield self.datastore.add_user_filter(
  363. user_localpart=user_localpart, user_filter=user_filter_json
  364. )
  365. filter = yield self.filtering.get_user_filter(
  366. user_localpart=user_localpart, filter_id=filter_id
  367. )
  368. self.assertEquals(filter.get_filter_json(), user_filter_json)
  369. self.assertRegexpMatches(repr(filter), r"<FilterCollection \{.*\}>")