test_filtering.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2015, 2016 OpenMarket Ltd
  3. # Copyright 2017 Vector Creations Ltd
  4. # Copyright 2018-2019 New Vector Ltd
  5. # Copyright 2019 The Matrix.org Foundation C.I.C.
  6. #
  7. # Licensed under the Apache License, Version 2.0 (the "License");
  8. # you may not use this file except in compliance with the License.
  9. # You may obtain a copy of the License at
  10. #
  11. # http://www.apache.org/licenses/LICENSE-2.0
  12. #
  13. # Unless required by applicable law or agreed to in writing, software
  14. # distributed under the License is distributed on an "AS IS" BASIS,
  15. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. # See the License for the specific language governing permissions and
  17. # limitations under the License.
  18. import jsonschema
  19. from twisted.internet import defer
  20. from synapse.api.constants import EventContentFields
  21. from synapse.api.errors import SynapseError
  22. from synapse.api.filtering import Filter
  23. from synapse.events import make_event_from_dict
  24. from tests import unittest
  25. from tests.utils import setup_test_homeserver
  26. user_localpart = "test_user"
  27. def MockEvent(**kwargs):
  28. if "event_id" not in kwargs:
  29. kwargs["event_id"] = "fake_event_id"
  30. if "type" not in kwargs:
  31. kwargs["type"] = "fake_type"
  32. return make_event_from_dict(kwargs)
  33. class FilteringTestCase(unittest.TestCase):
  34. def setUp(self):
  35. hs = setup_test_homeserver(self.addCleanup)
  36. self.filtering = hs.get_filtering()
  37. self.datastore = hs.get_datastore()
  38. def test_errors_on_invalid_filters(self):
  39. invalid_filters = [
  40. {"boom": {}},
  41. {"account_data": "Hello World"},
  42. {"event_fields": [r"\\foo"]},
  43. {"room": {"timeline": {"limit": 0}, "state": {"not_bars": ["*"]}}},
  44. {"event_format": "other"},
  45. {"room": {"not_rooms": ["#foo:pik-test"]}},
  46. {"presence": {"senders": ["@bar;pik.test.com"]}},
  47. ]
  48. for filter in invalid_filters:
  49. with self.assertRaises(SynapseError) as check_filter_error:
  50. self.filtering.check_valid_filter(filter)
  51. self.assertIsInstance(check_filter_error.exception, SynapseError)
  52. def test_valid_filters(self):
  53. valid_filters = [
  54. {
  55. "room": {
  56. "timeline": {"limit": 20},
  57. "state": {"not_types": ["m.room.member"]},
  58. "ephemeral": {"limit": 0, "not_types": ["*"]},
  59. "include_leave": False,
  60. "rooms": ["!dee:pik-test"],
  61. "not_rooms": ["!gee:pik-test"],
  62. "account_data": {"limit": 0, "types": ["*"]},
  63. }
  64. },
  65. {
  66. "room": {
  67. "state": {
  68. "types": ["m.room.*"],
  69. "not_rooms": ["!726s6s6q:example.com"],
  70. },
  71. "timeline": {
  72. "limit": 10,
  73. "types": ["m.room.message"],
  74. "not_rooms": ["!726s6s6q:example.com"],
  75. "not_senders": ["@spam:example.com"],
  76. "org.matrix.labels": ["#fun"],
  77. "org.matrix.not_labels": ["#work"],
  78. },
  79. "ephemeral": {
  80. "types": ["m.receipt", "m.typing"],
  81. "not_rooms": ["!726s6s6q:example.com"],
  82. "not_senders": ["@spam:example.com"],
  83. },
  84. },
  85. "presence": {
  86. "types": ["m.presence"],
  87. "not_senders": ["@alice:example.com"],
  88. },
  89. "event_format": "client",
  90. "event_fields": ["type", "content", "sender"],
  91. },
  92. # a single backslash should be permitted (though it is debatable whether
  93. # it should be permitted before anything other than `.`, and what that
  94. # actually means)
  95. #
  96. # (note that event_fields is implemented in
  97. # synapse.events.utils.serialize_event, and so whether this actually works
  98. # is tested elsewhere. We just want to check that it is allowed through the
  99. # filter validation)
  100. {"event_fields": [r"foo\.bar"]},
  101. ]
  102. for filter in valid_filters:
  103. try:
  104. self.filtering.check_valid_filter(filter)
  105. except jsonschema.ValidationError as e:
  106. self.fail(e)
  107. def test_limits_are_applied(self):
  108. # TODO
  109. pass
  110. def test_definition_types_works_with_literals(self):
  111. definition = {"types": ["m.room.message", "org.matrix.foo.bar"]}
  112. event = MockEvent(sender="@foo:bar", type="m.room.message", room_id="!foo:bar")
  113. self.assertTrue(Filter(definition).check(event))
  114. def test_definition_types_works_with_wildcards(self):
  115. definition = {"types": ["m.*", "org.matrix.foo.bar"]}
  116. event = MockEvent(sender="@foo:bar", type="m.room.message", room_id="!foo:bar")
  117. self.assertTrue(Filter(definition).check(event))
  118. def test_definition_types_works_with_unknowns(self):
  119. definition = {"types": ["m.room.message", "org.matrix.foo.bar"]}
  120. event = MockEvent(
  121. sender="@foo:bar",
  122. type="now.for.something.completely.different",
  123. room_id="!foo:bar",
  124. )
  125. self.assertFalse(Filter(definition).check(event))
  126. def test_definition_not_types_works_with_literals(self):
  127. definition = {"not_types": ["m.room.message", "org.matrix.foo.bar"]}
  128. event = MockEvent(sender="@foo:bar", type="m.room.message", room_id="!foo:bar")
  129. self.assertFalse(Filter(definition).check(event))
  130. def test_definition_not_types_works_with_wildcards(self):
  131. definition = {"not_types": ["m.room.message", "org.matrix.*"]}
  132. event = MockEvent(
  133. sender="@foo:bar", type="org.matrix.custom.event", room_id="!foo:bar"
  134. )
  135. self.assertFalse(Filter(definition).check(event))
  136. def test_definition_not_types_works_with_unknowns(self):
  137. definition = {"not_types": ["m.*", "org.*"]}
  138. event = MockEvent(sender="@foo:bar", type="com.nom.nom.nom", room_id="!foo:bar")
  139. self.assertTrue(Filter(definition).check(event))
  140. def test_definition_not_types_takes_priority_over_types(self):
  141. definition = {
  142. "not_types": ["m.*", "org.*"],
  143. "types": ["m.room.message", "m.room.topic"],
  144. }
  145. event = MockEvent(sender="@foo:bar", type="m.room.topic", room_id="!foo:bar")
  146. self.assertFalse(Filter(definition).check(event))
  147. def test_definition_senders_works_with_literals(self):
  148. definition = {"senders": ["@flibble:wibble"]}
  149. event = MockEvent(
  150. sender="@flibble:wibble", type="com.nom.nom.nom", room_id="!foo:bar"
  151. )
  152. self.assertTrue(Filter(definition).check(event))
  153. def test_definition_senders_works_with_unknowns(self):
  154. definition = {"senders": ["@flibble:wibble"]}
  155. event = MockEvent(
  156. sender="@challenger:appears", type="com.nom.nom.nom", room_id="!foo:bar"
  157. )
  158. self.assertFalse(Filter(definition).check(event))
  159. def test_definition_not_senders_works_with_literals(self):
  160. definition = {"not_senders": ["@flibble:wibble"]}
  161. event = MockEvent(
  162. sender="@flibble:wibble", type="com.nom.nom.nom", room_id="!foo:bar"
  163. )
  164. self.assertFalse(Filter(definition).check(event))
  165. def test_definition_not_senders_works_with_unknowns(self):
  166. definition = {"not_senders": ["@flibble:wibble"]}
  167. event = MockEvent(
  168. sender="@challenger:appears", type="com.nom.nom.nom", room_id="!foo:bar"
  169. )
  170. self.assertTrue(Filter(definition).check(event))
  171. def test_definition_not_senders_takes_priority_over_senders(self):
  172. definition = {
  173. "not_senders": ["@misspiggy:muppets"],
  174. "senders": ["@kermit:muppets", "@misspiggy:muppets"],
  175. }
  176. event = MockEvent(
  177. sender="@misspiggy:muppets", type="m.room.topic", room_id="!foo:bar"
  178. )
  179. self.assertFalse(Filter(definition).check(event))
  180. def test_definition_rooms_works_with_literals(self):
  181. definition = {"rooms": ["!secretbase:unknown"]}
  182. event = MockEvent(
  183. sender="@foo:bar", type="m.room.message", room_id="!secretbase:unknown"
  184. )
  185. self.assertTrue(Filter(definition).check(event))
  186. def test_definition_rooms_works_with_unknowns(self):
  187. definition = {"rooms": ["!secretbase:unknown"]}
  188. event = MockEvent(
  189. sender="@foo:bar",
  190. type="m.room.message",
  191. room_id="!anothersecretbase:unknown",
  192. )
  193. self.assertFalse(Filter(definition).check(event))
  194. def test_definition_not_rooms_works_with_literals(self):
  195. definition = {"not_rooms": ["!anothersecretbase:unknown"]}
  196. event = MockEvent(
  197. sender="@foo:bar",
  198. type="m.room.message",
  199. room_id="!anothersecretbase:unknown",
  200. )
  201. self.assertFalse(Filter(definition).check(event))
  202. def test_definition_not_rooms_works_with_unknowns(self):
  203. definition = {"not_rooms": ["!secretbase:unknown"]}
  204. event = MockEvent(
  205. sender="@foo:bar",
  206. type="m.room.message",
  207. room_id="!anothersecretbase:unknown",
  208. )
  209. self.assertTrue(Filter(definition).check(event))
  210. def test_definition_not_rooms_takes_priority_over_rooms(self):
  211. definition = {
  212. "not_rooms": ["!secretbase:unknown"],
  213. "rooms": ["!secretbase:unknown"],
  214. }
  215. event = MockEvent(
  216. sender="@foo:bar", type="m.room.message", room_id="!secretbase:unknown"
  217. )
  218. self.assertFalse(Filter(definition).check(event))
  219. def test_definition_combined_event(self):
  220. definition = {
  221. "not_senders": ["@misspiggy:muppets"],
  222. "senders": ["@kermit:muppets"],
  223. "rooms": ["!stage:unknown"],
  224. "not_rooms": ["!piggyshouse:muppets"],
  225. "types": ["m.room.message", "muppets.kermit.*"],
  226. "not_types": ["muppets.misspiggy.*"],
  227. }
  228. event = MockEvent(
  229. sender="@kermit:muppets", # yup
  230. type="m.room.message", # yup
  231. room_id="!stage:unknown", # yup
  232. )
  233. self.assertTrue(Filter(definition).check(event))
  234. def test_definition_combined_event_bad_sender(self):
  235. definition = {
  236. "not_senders": ["@misspiggy:muppets"],
  237. "senders": ["@kermit:muppets"],
  238. "rooms": ["!stage:unknown"],
  239. "not_rooms": ["!piggyshouse:muppets"],
  240. "types": ["m.room.message", "muppets.kermit.*"],
  241. "not_types": ["muppets.misspiggy.*"],
  242. }
  243. event = MockEvent(
  244. sender="@misspiggy:muppets", # nope
  245. type="m.room.message", # yup
  246. room_id="!stage:unknown", # yup
  247. )
  248. self.assertFalse(Filter(definition).check(event))
  249. def test_definition_combined_event_bad_room(self):
  250. definition = {
  251. "not_senders": ["@misspiggy:muppets"],
  252. "senders": ["@kermit:muppets"],
  253. "rooms": ["!stage:unknown"],
  254. "not_rooms": ["!piggyshouse:muppets"],
  255. "types": ["m.room.message", "muppets.kermit.*"],
  256. "not_types": ["muppets.misspiggy.*"],
  257. }
  258. event = MockEvent(
  259. sender="@kermit:muppets", # yup
  260. type="m.room.message", # yup
  261. room_id="!piggyshouse:muppets", # nope
  262. )
  263. self.assertFalse(Filter(definition).check(event))
  264. def test_definition_combined_event_bad_type(self):
  265. definition = {
  266. "not_senders": ["@misspiggy:muppets"],
  267. "senders": ["@kermit:muppets"],
  268. "rooms": ["!stage:unknown"],
  269. "not_rooms": ["!piggyshouse:muppets"],
  270. "types": ["m.room.message", "muppets.kermit.*"],
  271. "not_types": ["muppets.misspiggy.*"],
  272. }
  273. event = MockEvent(
  274. sender="@kermit:muppets", # yup
  275. type="muppets.misspiggy.kisses", # nope
  276. room_id="!stage:unknown", # yup
  277. )
  278. self.assertFalse(Filter(definition).check(event))
  279. def test_filter_labels(self):
  280. definition = {"org.matrix.labels": ["#fun"]}
  281. event = MockEvent(
  282. sender="@foo:bar",
  283. type="m.room.message",
  284. room_id="!secretbase:unknown",
  285. content={EventContentFields.LABELS: ["#fun"]},
  286. )
  287. self.assertTrue(Filter(definition).check(event))
  288. event = MockEvent(
  289. sender="@foo:bar",
  290. type="m.room.message",
  291. room_id="!secretbase:unknown",
  292. content={EventContentFields.LABELS: ["#notfun"]},
  293. )
  294. self.assertFalse(Filter(definition).check(event))
  295. def test_filter_not_labels(self):
  296. definition = {"org.matrix.not_labels": ["#fun"]}
  297. event = MockEvent(
  298. sender="@foo:bar",
  299. type="m.room.message",
  300. room_id="!secretbase:unknown",
  301. content={EventContentFields.LABELS: ["#fun"]},
  302. )
  303. self.assertFalse(Filter(definition).check(event))
  304. event = MockEvent(
  305. sender="@foo:bar",
  306. type="m.room.message",
  307. room_id="!secretbase:unknown",
  308. content={EventContentFields.LABELS: ["#notfun"]},
  309. )
  310. self.assertTrue(Filter(definition).check(event))
  311. @defer.inlineCallbacks
  312. def test_filter_presence_match(self):
  313. user_filter_json = {"presence": {"types": ["m.*"]}}
  314. filter_id = yield defer.ensureDeferred(
  315. self.datastore.add_user_filter(
  316. user_localpart=user_localpart, user_filter=user_filter_json
  317. )
  318. )
  319. event = MockEvent(sender="@foo:bar", type="m.profile")
  320. events = [event]
  321. user_filter = yield defer.ensureDeferred(
  322. self.filtering.get_user_filter(
  323. user_localpart=user_localpart, filter_id=filter_id
  324. )
  325. )
  326. results = user_filter.filter_presence(events=events)
  327. self.assertEquals(events, results)
  328. @defer.inlineCallbacks
  329. def test_filter_presence_no_match(self):
  330. user_filter_json = {"presence": {"types": ["m.*"]}}
  331. filter_id = yield defer.ensureDeferred(
  332. self.datastore.add_user_filter(
  333. user_localpart=user_localpart + "2", user_filter=user_filter_json
  334. )
  335. )
  336. event = MockEvent(
  337. event_id="$asdasd:localhost",
  338. sender="@foo:bar",
  339. type="custom.avatar.3d.crazy",
  340. )
  341. events = [event]
  342. user_filter = yield defer.ensureDeferred(
  343. self.filtering.get_user_filter(
  344. user_localpart=user_localpart + "2", filter_id=filter_id
  345. )
  346. )
  347. results = user_filter.filter_presence(events=events)
  348. self.assertEquals([], results)
  349. @defer.inlineCallbacks
  350. def test_filter_room_state_match(self):
  351. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  352. filter_id = yield defer.ensureDeferred(
  353. self.datastore.add_user_filter(
  354. user_localpart=user_localpart, user_filter=user_filter_json
  355. )
  356. )
  357. event = MockEvent(sender="@foo:bar", type="m.room.topic", room_id="!foo:bar")
  358. events = [event]
  359. user_filter = yield defer.ensureDeferred(
  360. self.filtering.get_user_filter(
  361. user_localpart=user_localpart, filter_id=filter_id
  362. )
  363. )
  364. results = user_filter.filter_room_state(events=events)
  365. self.assertEquals(events, results)
  366. @defer.inlineCallbacks
  367. def test_filter_room_state_no_match(self):
  368. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  369. filter_id = yield defer.ensureDeferred(
  370. self.datastore.add_user_filter(
  371. user_localpart=user_localpart, user_filter=user_filter_json
  372. )
  373. )
  374. event = MockEvent(
  375. sender="@foo:bar", type="org.matrix.custom.event", room_id="!foo:bar"
  376. )
  377. events = [event]
  378. user_filter = yield defer.ensureDeferred(
  379. self.filtering.get_user_filter(
  380. user_localpart=user_localpart, filter_id=filter_id
  381. )
  382. )
  383. results = user_filter.filter_room_state(events)
  384. self.assertEquals([], results)
  385. def test_filter_rooms(self):
  386. definition = {
  387. "rooms": ["!allowed:example.com", "!excluded:example.com"],
  388. "not_rooms": ["!excluded:example.com"],
  389. }
  390. room_ids = [
  391. "!allowed:example.com", # Allowed because in rooms and not in not_rooms.
  392. "!excluded:example.com", # Disallowed because in not_rooms.
  393. "!not_included:example.com", # Disallowed because not in rooms.
  394. ]
  395. filtered_room_ids = list(Filter(definition).filter_rooms(room_ids))
  396. self.assertEquals(filtered_room_ids, ["!allowed:example.com"])
  397. @defer.inlineCallbacks
  398. def test_add_filter(self):
  399. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  400. filter_id = yield defer.ensureDeferred(
  401. self.filtering.add_user_filter(
  402. user_localpart=user_localpart, user_filter=user_filter_json
  403. )
  404. )
  405. self.assertEquals(filter_id, 0)
  406. self.assertEquals(
  407. user_filter_json,
  408. (
  409. yield defer.ensureDeferred(
  410. self.datastore.get_user_filter(
  411. user_localpart=user_localpart, filter_id=0
  412. )
  413. )
  414. ),
  415. )
  416. @defer.inlineCallbacks
  417. def test_get_filter(self):
  418. user_filter_json = {"room": {"state": {"types": ["m.*"]}}}
  419. filter_id = yield defer.ensureDeferred(
  420. self.datastore.add_user_filter(
  421. user_localpart=user_localpart, user_filter=user_filter_json
  422. )
  423. )
  424. filter = yield defer.ensureDeferred(
  425. self.filtering.get_user_filter(
  426. user_localpart=user_localpart, filter_id=filter_id
  427. )
  428. )
  429. self.assertEquals(filter.get_filter_json(), user_filter_json)
  430. self.assertRegexpMatches(repr(filter), r"<FilterCollection \{.*\}>")