test_deactivate_account.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. # Copyright 2021 The Matrix.org Foundation C.I.C.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from twisted.test.proto_helpers import MemoryReactor
  15. from synapse.api.constants import AccountDataTypes
  16. from synapse.push.baserules import PushRule
  17. from synapse.push.rulekinds import PRIORITY_CLASS_MAP
  18. from synapse.rest import admin
  19. from synapse.rest.client import account, login
  20. from synapse.server import HomeServer
  21. from synapse.util import Clock
  22. from tests.unittest import HomeserverTestCase
  23. class DeactivateAccountTestCase(HomeserverTestCase):
  24. servlets = [
  25. login.register_servlets,
  26. admin.register_servlets,
  27. account.register_servlets,
  28. ]
  29. def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
  30. self._store = hs.get_datastores().main
  31. self.user = self.register_user("user", "pass")
  32. self.token = self.login("user", "pass")
  33. def _deactivate_my_account(self) -> None:
  34. """
  35. Deactivates the account `self.user` using `self.token` and asserts
  36. that it returns a 200 success code.
  37. """
  38. req = self.make_request(
  39. "POST",
  40. "account/deactivate",
  41. {
  42. "auth": {
  43. "type": "m.login.password",
  44. "user": self.user,
  45. "password": "pass",
  46. },
  47. "erase": True,
  48. },
  49. access_token=self.token,
  50. )
  51. self.assertEqual(req.code, 200, req)
  52. def test_global_account_data_deleted_upon_deactivation(self) -> None:
  53. """
  54. Tests that global account data is removed upon deactivation.
  55. """
  56. # Add some account data
  57. self.get_success(
  58. self._store.add_account_data_for_user(
  59. self.user,
  60. AccountDataTypes.DIRECT,
  61. {"@someone:remote": ["!somewhere:remote"]},
  62. )
  63. )
  64. # Check that we actually added some.
  65. self.assertIsNotNone(
  66. self.get_success(
  67. self._store.get_global_account_data_by_type_for_user(
  68. self.user, AccountDataTypes.DIRECT
  69. )
  70. ),
  71. )
  72. # Request the deactivation of our account
  73. self._deactivate_my_account()
  74. # Check that the account data does not persist.
  75. self.assertIsNone(
  76. self.get_success(
  77. self._store.get_global_account_data_by_type_for_user(
  78. self.user, AccountDataTypes.DIRECT
  79. )
  80. ),
  81. )
  82. def test_room_account_data_deleted_upon_deactivation(self) -> None:
  83. """
  84. Tests that room account data is removed upon deactivation.
  85. """
  86. room_id = "!room:test"
  87. # Add some room account data
  88. self.get_success(
  89. self._store.add_account_data_to_room(
  90. self.user,
  91. room_id,
  92. "m.fully_read",
  93. {"event_id": "$aaaa:test"},
  94. )
  95. )
  96. # Check that we actually added some.
  97. self.assertIsNotNone(
  98. self.get_success(
  99. self._store.get_account_data_for_room_and_type(
  100. self.user, room_id, "m.fully_read"
  101. )
  102. ),
  103. )
  104. # Request the deactivation of our account
  105. self._deactivate_my_account()
  106. # Check that the account data does not persist.
  107. self.assertIsNone(
  108. self.get_success(
  109. self._store.get_account_data_for_room_and_type(
  110. self.user, room_id, "m.fully_read"
  111. )
  112. ),
  113. )
  114. def _is_custom_rule(self, push_rule: PushRule) -> bool:
  115. """
  116. Default rules start with a dot: such as .m.rule and .im.vector.
  117. This function returns true iff a rule is custom (not default).
  118. """
  119. return "/." not in push_rule.rule_id
  120. def test_push_rules_deleted_upon_account_deactivation(self) -> None:
  121. """
  122. Push rules are a special case of account data.
  123. They are stored separately but get sent to the client as account data in /sync.
  124. This tests that deactivating a user deletes push rules along with the rest
  125. of their account data.
  126. """
  127. # Add a push rule
  128. self.get_success(
  129. self._store.add_push_rule(
  130. self.user,
  131. "personal.override.rule1",
  132. PRIORITY_CLASS_MAP["override"],
  133. [],
  134. [],
  135. )
  136. )
  137. # Test the rule exists
  138. filtered_push_rules = self.get_success(
  139. self._store.get_push_rules_for_user(self.user)
  140. )
  141. # Filter out default rules; we don't care
  142. push_rules = [r for r, _ in filtered_push_rules if self._is_custom_rule(r)]
  143. # Check our rule made it
  144. self.assertEqual(
  145. push_rules,
  146. [
  147. PushRule(
  148. rule_id="personal.override.rule1",
  149. priority_class=5,
  150. conditions=[],
  151. actions=[],
  152. )
  153. ],
  154. push_rules,
  155. )
  156. # Request the deactivation of our account
  157. self._deactivate_my_account()
  158. filtered_push_rules = self.get_success(
  159. self._store.get_push_rules_for_user(self.user)
  160. )
  161. # Filter out default rules; we don't care
  162. push_rules = [r for r, _ in filtered_push_rules if self._is_custom_rule(r)]
  163. # Check our rule no longer exists
  164. self.assertEqual(push_rules, [], push_rules)
  165. def test_ignored_users_deleted_upon_deactivation(self) -> None:
  166. """
  167. Ignored users are a special case of account data.
  168. They get denormalised into the `ignored_users` table upon being stored as
  169. account data.
  170. Test that a user's list of ignored users is deleted upon deactivation.
  171. """
  172. # Add an ignored user
  173. self.get_success(
  174. self._store.add_account_data_for_user(
  175. self.user,
  176. AccountDataTypes.IGNORED_USER_LIST,
  177. {"ignored_users": {"@sheltie:test": {}}},
  178. )
  179. )
  180. # Test the user is ignored
  181. self.assertEqual(
  182. self.get_success(self._store.ignored_by("@sheltie:test")), {self.user}
  183. )
  184. # Request the deactivation of our account
  185. self._deactivate_my_account()
  186. # Test the user is no longer ignored by the user that was deactivated
  187. self.assertEqual(
  188. self.get_success(self._store.ignored_by("@sheltie:test")), set()
  189. )
  190. def _rerun_retroactive_account_data_deletion_update(self) -> None:
  191. # Reset the 'all done' flag
  192. self._store.db_pool.updates._all_done = False
  193. self.get_success(
  194. self._store.db_pool.simple_insert(
  195. "background_updates",
  196. {
  197. "update_name": "delete_account_data_for_deactivated_users",
  198. "progress_json": "{}",
  199. },
  200. )
  201. )
  202. self.wait_for_background_updates()
  203. def test_account_data_deleted_retroactively_by_background_update_if_deactivated(
  204. self,
  205. ) -> None:
  206. """
  207. Tests that a user, who deactivated their account before account data was
  208. deleted automatically upon deactivation, has their account data retroactively
  209. scrubbed by the background update.
  210. """
  211. # Request the deactivation of our account
  212. self._deactivate_my_account()
  213. # Add some account data
  214. # (we do this after the deactivation so that the act of deactivating doesn't
  215. # clear it out. This emulates a user that was deactivated before this was cleared
  216. # upon deactivation.)
  217. self.get_success(
  218. self._store.add_account_data_for_user(
  219. self.user,
  220. AccountDataTypes.DIRECT,
  221. {"@someone:remote": ["!somewhere:remote"]},
  222. )
  223. )
  224. # Check that the account data is there.
  225. self.assertIsNotNone(
  226. self.get_success(
  227. self._store.get_global_account_data_by_type_for_user(
  228. self.user,
  229. AccountDataTypes.DIRECT,
  230. )
  231. ),
  232. )
  233. # Re-run the retroactive deletion update
  234. self._rerun_retroactive_account_data_deletion_update()
  235. # Check that the account data was cleared.
  236. self.assertIsNone(
  237. self.get_success(
  238. self._store.get_global_account_data_by_type_for_user(
  239. self.user,
  240. AccountDataTypes.DIRECT,
  241. )
  242. ),
  243. )
  244. def test_account_data_preserved_by_background_update_if_not_deactivated(
  245. self,
  246. ) -> None:
  247. """
  248. Tests that the background update does not scrub account data for users that have
  249. not been deactivated.
  250. """
  251. # Add some account data
  252. # (we do this after the deactivation so that the act of deactivating doesn't
  253. # clear it out. This emulates a user that was deactivated before this was cleared
  254. # upon deactivation.)
  255. self.get_success(
  256. self._store.add_account_data_for_user(
  257. self.user,
  258. AccountDataTypes.DIRECT,
  259. {"@someone:remote": ["!somewhere:remote"]},
  260. )
  261. )
  262. # Check that the account data is there.
  263. self.assertIsNotNone(
  264. self.get_success(
  265. self._store.get_global_account_data_by_type_for_user(
  266. self.user,
  267. AccountDataTypes.DIRECT,
  268. )
  269. ),
  270. )
  271. # Re-run the retroactive deletion update
  272. self._rerun_retroactive_account_data_deletion_update()
  273. # Check that the account data was NOT cleared.
  274. self.assertIsNotNone(
  275. self.get_success(
  276. self._store.get_global_account_data_by_type_for_user(
  277. self.user,
  278. AccountDataTypes.DIRECT,
  279. )
  280. ),
  281. )