test_filtering.py 18 KB

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