matrix-synapse 1.142.0rc3__cp314-abi3-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of matrix-synapse might be problematic. Click here for more details.

Files changed (1057) hide show
  1. matrix_synapse-1.142.0rc3.dist-info/AUTHORS.rst +51 -0
  2. matrix_synapse-1.142.0rc3.dist-info/LICENSE-AGPL-3.0 +661 -0
  3. matrix_synapse-1.142.0rc3.dist-info/LICENSE-COMMERCIAL +6 -0
  4. matrix_synapse-1.142.0rc3.dist-info/METADATA +375 -0
  5. matrix_synapse-1.142.0rc3.dist-info/RECORD +1057 -0
  6. matrix_synapse-1.142.0rc3.dist-info/WHEEL +4 -0
  7. matrix_synapse-1.142.0rc3.dist-info/entry_points.txt +14 -0
  8. matrix_synapse.libs/libgcc_s-2d945d6c.so.1 +0 -0
  9. synapse/__init__.py +97 -0
  10. synapse/_scripts/__init__.py +0 -0
  11. synapse/_scripts/export_signing_key.py +109 -0
  12. synapse/_scripts/generate_config.py +83 -0
  13. synapse/_scripts/generate_log_config.py +56 -0
  14. synapse/_scripts/generate_signing_key.py +55 -0
  15. synapse/_scripts/generate_workers_map.py +318 -0
  16. synapse/_scripts/hash_password.py +95 -0
  17. synapse/_scripts/move_remote_media_to_new_store.py +128 -0
  18. synapse/_scripts/register_new_matrix_user.py +374 -0
  19. synapse/_scripts/review_recent_signups.py +212 -0
  20. synapse/_scripts/synapse_port_db.py +1603 -0
  21. synapse/_scripts/synctl.py +365 -0
  22. synapse/_scripts/update_synapse_database.py +130 -0
  23. synapse/api/__init__.py +20 -0
  24. synapse/api/auth/__init__.py +207 -0
  25. synapse/api/auth/base.py +406 -0
  26. synapse/api/auth/internal.py +299 -0
  27. synapse/api/auth/mas.py +457 -0
  28. synapse/api/auth/msc3861_delegated.py +617 -0
  29. synapse/api/auth_blocking.py +144 -0
  30. synapse/api/constants.py +362 -0
  31. synapse/api/errors.py +907 -0
  32. synapse/api/filtering.py +539 -0
  33. synapse/api/presence.py +104 -0
  34. synapse/api/ratelimiting.py +482 -0
  35. synapse/api/room_versions.py +535 -0
  36. synapse/api/urls.py +119 -0
  37. synapse/app/__init__.py +60 -0
  38. synapse/app/_base.py +866 -0
  39. synapse/app/admin_cmd.py +388 -0
  40. synapse/app/appservice.py +30 -0
  41. synapse/app/client_reader.py +30 -0
  42. synapse/app/complement_fork_starter.py +206 -0
  43. synapse/app/event_creator.py +29 -0
  44. synapse/app/federation_reader.py +30 -0
  45. synapse/app/federation_sender.py +30 -0
  46. synapse/app/frontend_proxy.py +30 -0
  47. synapse/app/generic_worker.py +475 -0
  48. synapse/app/homeserver.py +504 -0
  49. synapse/app/media_repository.py +30 -0
  50. synapse/app/phone_stats_home.py +296 -0
  51. synapse/app/pusher.py +30 -0
  52. synapse/app/synchrotron.py +30 -0
  53. synapse/app/user_dir.py +31 -0
  54. synapse/appservice/__init__.py +461 -0
  55. synapse/appservice/api.py +569 -0
  56. synapse/appservice/scheduler.py +567 -0
  57. synapse/config/__init__.py +27 -0
  58. synapse/config/__main__.py +62 -0
  59. synapse/config/_base.py +1108 -0
  60. synapse/config/_base.pyi +217 -0
  61. synapse/config/_util.py +99 -0
  62. synapse/config/account_validity.py +116 -0
  63. synapse/config/api.py +141 -0
  64. synapse/config/appservice.py +210 -0
  65. synapse/config/auth.py +80 -0
  66. synapse/config/auto_accept_invites.py +43 -0
  67. synapse/config/background_updates.py +44 -0
  68. synapse/config/cache.py +231 -0
  69. synapse/config/captcha.py +90 -0
  70. synapse/config/cas.py +116 -0
  71. synapse/config/consent.py +73 -0
  72. synapse/config/database.py +184 -0
  73. synapse/config/emailconfig.py +367 -0
  74. synapse/config/experimental.py +595 -0
  75. synapse/config/federation.py +114 -0
  76. synapse/config/homeserver.py +141 -0
  77. synapse/config/jwt.py +55 -0
  78. synapse/config/key.py +447 -0
  79. synapse/config/logger.py +390 -0
  80. synapse/config/mas.py +191 -0
  81. synapse/config/matrixrtc.py +66 -0
  82. synapse/config/metrics.py +84 -0
  83. synapse/config/modules.py +40 -0
  84. synapse/config/oembed.py +185 -0
  85. synapse/config/oidc.py +509 -0
  86. synapse/config/password_auth_providers.py +82 -0
  87. synapse/config/push.py +64 -0
  88. synapse/config/ratelimiting.py +254 -0
  89. synapse/config/redis.py +74 -0
  90. synapse/config/registration.py +296 -0
  91. synapse/config/repository.py +311 -0
  92. synapse/config/retention.py +162 -0
  93. synapse/config/room.py +88 -0
  94. synapse/config/room_directory.py +165 -0
  95. synapse/config/saml2.py +251 -0
  96. synapse/config/server.py +1170 -0
  97. synapse/config/server_notices.py +84 -0
  98. synapse/config/spam_checker.py +66 -0
  99. synapse/config/sso.py +121 -0
  100. synapse/config/stats.py +54 -0
  101. synapse/config/third_party_event_rules.py +40 -0
  102. synapse/config/tls.py +192 -0
  103. synapse/config/tracer.py +71 -0
  104. synapse/config/user_directory.py +47 -0
  105. synapse/config/user_types.py +44 -0
  106. synapse/config/voip.py +59 -0
  107. synapse/config/workers.py +642 -0
  108. synapse/crypto/__init__.py +20 -0
  109. synapse/crypto/context_factory.py +278 -0
  110. synapse/crypto/event_signing.py +194 -0
  111. synapse/crypto/keyring.py +931 -0
  112. synapse/event_auth.py +1266 -0
  113. synapse/events/__init__.py +668 -0
  114. synapse/events/auto_accept_invites.py +216 -0
  115. synapse/events/builder.py +387 -0
  116. synapse/events/presence_router.py +245 -0
  117. synapse/events/snapshot.py +559 -0
  118. synapse/events/utils.py +928 -0
  119. synapse/events/validator.py +305 -0
  120. synapse/federation/__init__.py +22 -0
  121. synapse/federation/federation_base.py +383 -0
  122. synapse/federation/federation_client.py +2134 -0
  123. synapse/federation/federation_server.py +1544 -0
  124. synapse/federation/persistence.py +71 -0
  125. synapse/federation/send_queue.py +532 -0
  126. synapse/federation/sender/__init__.py +1165 -0
  127. synapse/federation/sender/per_destination_queue.py +884 -0
  128. synapse/federation/sender/transaction_manager.py +210 -0
  129. synapse/federation/transport/__init__.py +28 -0
  130. synapse/federation/transport/client.py +1201 -0
  131. synapse/federation/transport/server/__init__.py +334 -0
  132. synapse/federation/transport/server/_base.py +429 -0
  133. synapse/federation/transport/server/federation.py +912 -0
  134. synapse/federation/units.py +133 -0
  135. synapse/handlers/__init__.py +20 -0
  136. synapse/handlers/account.py +162 -0
  137. synapse/handlers/account_data.py +362 -0
  138. synapse/handlers/account_validity.py +361 -0
  139. synapse/handlers/admin.py +618 -0
  140. synapse/handlers/appservice.py +991 -0
  141. synapse/handlers/auth.py +2494 -0
  142. synapse/handlers/cas.py +413 -0
  143. synapse/handlers/deactivate_account.py +363 -0
  144. synapse/handlers/delayed_events.py +635 -0
  145. synapse/handlers/device.py +1873 -0
  146. synapse/handlers/devicemessage.py +399 -0
  147. synapse/handlers/directory.py +554 -0
  148. synapse/handlers/e2e_keys.py +1834 -0
  149. synapse/handlers/e2e_room_keys.py +455 -0
  150. synapse/handlers/event_auth.py +390 -0
  151. synapse/handlers/events.py +201 -0
  152. synapse/handlers/federation.py +2043 -0
  153. synapse/handlers/federation_event.py +2420 -0
  154. synapse/handlers/identity.py +812 -0
  155. synapse/handlers/initial_sync.py +528 -0
  156. synapse/handlers/jwt.py +120 -0
  157. synapse/handlers/message.py +2347 -0
  158. synapse/handlers/oidc.py +1803 -0
  159. synapse/handlers/pagination.py +768 -0
  160. synapse/handlers/password_policy.py +102 -0
  161. synapse/handlers/presence.py +2638 -0
  162. synapse/handlers/profile.py +655 -0
  163. synapse/handlers/push_rules.py +164 -0
  164. synapse/handlers/read_marker.py +79 -0
  165. synapse/handlers/receipts.py +351 -0
  166. synapse/handlers/register.py +1060 -0
  167. synapse/handlers/relations.py +624 -0
  168. synapse/handlers/reports.py +98 -0
  169. synapse/handlers/room.py +2447 -0
  170. synapse/handlers/room_list.py +632 -0
  171. synapse/handlers/room_member.py +2365 -0
  172. synapse/handlers/room_member_worker.py +146 -0
  173. synapse/handlers/room_policy.py +186 -0
  174. synapse/handlers/room_summary.py +1057 -0
  175. synapse/handlers/saml.py +524 -0
  176. synapse/handlers/search.py +723 -0
  177. synapse/handlers/send_email.py +209 -0
  178. synapse/handlers/set_password.py +71 -0
  179. synapse/handlers/sliding_sync/__init__.py +1701 -0
  180. synapse/handlers/sliding_sync/extensions.py +970 -0
  181. synapse/handlers/sliding_sync/room_lists.py +2266 -0
  182. synapse/handlers/sliding_sync/store.py +128 -0
  183. synapse/handlers/sso.py +1292 -0
  184. synapse/handlers/state_deltas.py +82 -0
  185. synapse/handlers/stats.py +322 -0
  186. synapse/handlers/sync.py +3109 -0
  187. synapse/handlers/thread_subscriptions.py +190 -0
  188. synapse/handlers/typing.py +606 -0
  189. synapse/handlers/ui_auth/__init__.py +48 -0
  190. synapse/handlers/ui_auth/checkers.py +332 -0
  191. synapse/handlers/user_directory.py +783 -0
  192. synapse/handlers/worker_lock.py +365 -0
  193. synapse/http/__init__.py +106 -0
  194. synapse/http/additional_resource.py +62 -0
  195. synapse/http/client.py +1360 -0
  196. synapse/http/connectproxyclient.py +309 -0
  197. synapse/http/federation/__init__.py +19 -0
  198. synapse/http/federation/matrix_federation_agent.py +490 -0
  199. synapse/http/federation/srv_resolver.py +196 -0
  200. synapse/http/federation/well_known_resolver.py +367 -0
  201. synapse/http/matrixfederationclient.py +1875 -0
  202. synapse/http/proxy.py +290 -0
  203. synapse/http/proxyagent.py +497 -0
  204. synapse/http/replicationagent.py +203 -0
  205. synapse/http/request_metrics.py +309 -0
  206. synapse/http/server.py +1114 -0
  207. synapse/http/servlet.py +1019 -0
  208. synapse/http/site.py +825 -0
  209. synapse/http/types.py +27 -0
  210. synapse/logging/__init__.py +31 -0
  211. synapse/logging/_remote.py +261 -0
  212. synapse/logging/_terse_json.py +95 -0
  213. synapse/logging/context.py +1211 -0
  214. synapse/logging/formatter.py +63 -0
  215. synapse/logging/handlers.py +99 -0
  216. synapse/logging/loggers.py +25 -0
  217. synapse/logging/opentracing.py +1132 -0
  218. synapse/logging/scopecontextmanager.py +161 -0
  219. synapse/media/_base.py +827 -0
  220. synapse/media/filepath.py +417 -0
  221. synapse/media/media_repository.py +1580 -0
  222. synapse/media/media_storage.py +704 -0
  223. synapse/media/oembed.py +277 -0
  224. synapse/media/preview_html.py +559 -0
  225. synapse/media/storage_provider.py +195 -0
  226. synapse/media/thumbnailer.py +833 -0
  227. synapse/media/url_previewer.py +875 -0
  228. synapse/metrics/__init__.py +754 -0
  229. synapse/metrics/_gc.py +219 -0
  230. synapse/metrics/_reactor_metrics.py +171 -0
  231. synapse/metrics/_types.py +38 -0
  232. synapse/metrics/background_process_metrics.py +556 -0
  233. synapse/metrics/common_usage_metrics.py +94 -0
  234. synapse/metrics/jemalloc.py +248 -0
  235. synapse/module_api/__init__.py +2154 -0
  236. synapse/module_api/callbacks/__init__.py +50 -0
  237. synapse/module_api/callbacks/account_validity_callbacks.py +106 -0
  238. synapse/module_api/callbacks/media_repository_callbacks.py +160 -0
  239. synapse/module_api/callbacks/ratelimit_callbacks.py +79 -0
  240. synapse/module_api/callbacks/spamchecker_callbacks.py +1113 -0
  241. synapse/module_api/callbacks/third_party_event_rules_callbacks.py +599 -0
  242. synapse/module_api/errors.py +42 -0
  243. synapse/notifier.py +972 -0
  244. synapse/push/__init__.py +212 -0
  245. synapse/push/bulk_push_rule_evaluator.py +637 -0
  246. synapse/push/clientformat.py +126 -0
  247. synapse/push/emailpusher.py +333 -0
  248. synapse/push/httppusher.py +564 -0
  249. synapse/push/mailer.py +1012 -0
  250. synapse/push/presentable_names.py +216 -0
  251. synapse/push/push_tools.py +114 -0
  252. synapse/push/push_types.py +141 -0
  253. synapse/push/pusher.py +87 -0
  254. synapse/push/pusherpool.py +501 -0
  255. synapse/push/rulekinds.py +33 -0
  256. synapse/py.typed +0 -0
  257. synapse/replication/__init__.py +20 -0
  258. synapse/replication/http/__init__.py +68 -0
  259. synapse/replication/http/_base.py +468 -0
  260. synapse/replication/http/account_data.py +297 -0
  261. synapse/replication/http/deactivate_account.py +81 -0
  262. synapse/replication/http/delayed_events.py +62 -0
  263. synapse/replication/http/devices.py +254 -0
  264. synapse/replication/http/federation.py +334 -0
  265. synapse/replication/http/login.py +106 -0
  266. synapse/replication/http/membership.py +364 -0
  267. synapse/replication/http/presence.py +133 -0
  268. synapse/replication/http/push.py +156 -0
  269. synapse/replication/http/register.py +172 -0
  270. synapse/replication/http/send_events.py +182 -0
  271. synapse/replication/http/state.py +82 -0
  272. synapse/replication/http/streams.py +101 -0
  273. synapse/replication/tcp/__init__.py +56 -0
  274. synapse/replication/tcp/client.py +552 -0
  275. synapse/replication/tcp/commands.py +569 -0
  276. synapse/replication/tcp/context.py +41 -0
  277. synapse/replication/tcp/external_cache.py +156 -0
  278. synapse/replication/tcp/handler.py +942 -0
  279. synapse/replication/tcp/protocol.py +608 -0
  280. synapse/replication/tcp/redis.py +509 -0
  281. synapse/replication/tcp/resource.py +348 -0
  282. synapse/replication/tcp/streams/__init__.py +96 -0
  283. synapse/replication/tcp/streams/_base.py +766 -0
  284. synapse/replication/tcp/streams/events.py +287 -0
  285. synapse/replication/tcp/streams/federation.py +92 -0
  286. synapse/replication/tcp/streams/partial_state.py +80 -0
  287. synapse/res/providers.json +29 -0
  288. synapse/res/templates/_base.html +29 -0
  289. synapse/res/templates/account_previously_renewed.html +6 -0
  290. synapse/res/templates/account_renewed.html +6 -0
  291. synapse/res/templates/add_threepid.html +8 -0
  292. synapse/res/templates/add_threepid.txt +6 -0
  293. synapse/res/templates/add_threepid_failure.html +7 -0
  294. synapse/res/templates/add_threepid_success.html +6 -0
  295. synapse/res/templates/already_in_use.html +12 -0
  296. synapse/res/templates/already_in_use.txt +10 -0
  297. synapse/res/templates/auth_success.html +21 -0
  298. synapse/res/templates/invalid_token.html +6 -0
  299. synapse/res/templates/mail-Element.css +7 -0
  300. synapse/res/templates/mail-Vector.css +7 -0
  301. synapse/res/templates/mail-expiry.css +4 -0
  302. synapse/res/templates/mail.css +156 -0
  303. synapse/res/templates/notice_expiry.html +46 -0
  304. synapse/res/templates/notice_expiry.txt +7 -0
  305. synapse/res/templates/notif.html +51 -0
  306. synapse/res/templates/notif.txt +22 -0
  307. synapse/res/templates/notif_mail.html +59 -0
  308. synapse/res/templates/notif_mail.txt +10 -0
  309. synapse/res/templates/password_reset.html +10 -0
  310. synapse/res/templates/password_reset.txt +7 -0
  311. synapse/res/templates/password_reset_confirmation.html +15 -0
  312. synapse/res/templates/password_reset_failure.html +7 -0
  313. synapse/res/templates/password_reset_success.html +6 -0
  314. synapse/res/templates/recaptcha.html +42 -0
  315. synapse/res/templates/registration.html +12 -0
  316. synapse/res/templates/registration.txt +10 -0
  317. synapse/res/templates/registration_failure.html +6 -0
  318. synapse/res/templates/registration_success.html +6 -0
  319. synapse/res/templates/registration_token.html +18 -0
  320. synapse/res/templates/room.html +33 -0
  321. synapse/res/templates/room.txt +9 -0
  322. synapse/res/templates/sso.css +129 -0
  323. synapse/res/templates/sso_account_deactivated.html +25 -0
  324. synapse/res/templates/sso_auth_account_details.html +186 -0
  325. synapse/res/templates/sso_auth_account_details.js +116 -0
  326. synapse/res/templates/sso_auth_bad_user.html +26 -0
  327. synapse/res/templates/sso_auth_confirm.html +27 -0
  328. synapse/res/templates/sso_auth_success.html +26 -0
  329. synapse/res/templates/sso_error.html +71 -0
  330. synapse/res/templates/sso_footer.html +19 -0
  331. synapse/res/templates/sso_login_idp_picker.html +60 -0
  332. synapse/res/templates/sso_new_user_consent.html +30 -0
  333. synapse/res/templates/sso_partial_profile.html +19 -0
  334. synapse/res/templates/sso_redirect_confirm.html +39 -0
  335. synapse/res/templates/style.css +33 -0
  336. synapse/res/templates/terms.html +27 -0
  337. synapse/rest/__init__.py +197 -0
  338. synapse/rest/admin/__init__.py +390 -0
  339. synapse/rest/admin/_base.py +72 -0
  340. synapse/rest/admin/background_updates.py +171 -0
  341. synapse/rest/admin/devices.py +221 -0
  342. synapse/rest/admin/event_reports.py +173 -0
  343. synapse/rest/admin/events.py +69 -0
  344. synapse/rest/admin/experimental_features.py +137 -0
  345. synapse/rest/admin/federation.py +243 -0
  346. synapse/rest/admin/media.py +540 -0
  347. synapse/rest/admin/registration_tokens.py +358 -0
  348. synapse/rest/admin/rooms.py +1061 -0
  349. synapse/rest/admin/scheduled_tasks.py +70 -0
  350. synapse/rest/admin/server_notice_servlet.py +132 -0
  351. synapse/rest/admin/statistics.py +132 -0
  352. synapse/rest/admin/username_available.py +58 -0
  353. synapse/rest/admin/users.py +1608 -0
  354. synapse/rest/client/__init__.py +20 -0
  355. synapse/rest/client/_base.py +113 -0
  356. synapse/rest/client/account.py +930 -0
  357. synapse/rest/client/account_data.py +319 -0
  358. synapse/rest/client/account_validity.py +103 -0
  359. synapse/rest/client/appservice_ping.py +125 -0
  360. synapse/rest/client/auth.py +218 -0
  361. synapse/rest/client/auth_metadata.py +122 -0
  362. synapse/rest/client/capabilities.py +121 -0
  363. synapse/rest/client/delayed_events.py +111 -0
  364. synapse/rest/client/devices.py +587 -0
  365. synapse/rest/client/directory.py +211 -0
  366. synapse/rest/client/events.py +116 -0
  367. synapse/rest/client/filter.py +112 -0
  368. synapse/rest/client/initial_sync.py +65 -0
  369. synapse/rest/client/keys.py +678 -0
  370. synapse/rest/client/knock.py +104 -0
  371. synapse/rest/client/login.py +754 -0
  372. synapse/rest/client/login_token_request.py +127 -0
  373. synapse/rest/client/logout.py +93 -0
  374. synapse/rest/client/matrixrtc.py +52 -0
  375. synapse/rest/client/media.py +286 -0
  376. synapse/rest/client/mutual_rooms.py +93 -0
  377. synapse/rest/client/notifications.py +137 -0
  378. synapse/rest/client/openid.py +109 -0
  379. synapse/rest/client/password_policy.py +69 -0
  380. synapse/rest/client/presence.py +131 -0
  381. synapse/rest/client/profile.py +291 -0
  382. synapse/rest/client/push_rule.py +331 -0
  383. synapse/rest/client/pusher.py +181 -0
  384. synapse/rest/client/read_marker.py +104 -0
  385. synapse/rest/client/receipts.py +165 -0
  386. synapse/rest/client/register.py +1067 -0
  387. synapse/rest/client/relations.py +138 -0
  388. synapse/rest/client/rendezvous.py +76 -0
  389. synapse/rest/client/reporting.py +207 -0
  390. synapse/rest/client/room.py +1669 -0
  391. synapse/rest/client/room_keys.py +426 -0
  392. synapse/rest/client/room_upgrade_rest_servlet.py +112 -0
  393. synapse/rest/client/sendtodevice.py +85 -0
  394. synapse/rest/client/sync.py +1131 -0
  395. synapse/rest/client/tags.py +129 -0
  396. synapse/rest/client/thirdparty.py +130 -0
  397. synapse/rest/client/thread_subscriptions.py +247 -0
  398. synapse/rest/client/tokenrefresh.py +52 -0
  399. synapse/rest/client/transactions.py +149 -0
  400. synapse/rest/client/user_directory.py +90 -0
  401. synapse/rest/client/versions.py +191 -0
  402. synapse/rest/client/voip.py +88 -0
  403. synapse/rest/consent/__init__.py +0 -0
  404. synapse/rest/consent/consent_resource.py +210 -0
  405. synapse/rest/health.py +38 -0
  406. synapse/rest/key/__init__.py +20 -0
  407. synapse/rest/key/v2/__init__.py +40 -0
  408. synapse/rest/key/v2/local_key_resource.py +125 -0
  409. synapse/rest/key/v2/remote_key_resource.py +302 -0
  410. synapse/rest/media/__init__.py +0 -0
  411. synapse/rest/media/config_resource.py +53 -0
  412. synapse/rest/media/create_resource.py +90 -0
  413. synapse/rest/media/download_resource.py +110 -0
  414. synapse/rest/media/media_repository_resource.py +113 -0
  415. synapse/rest/media/preview_url_resource.py +77 -0
  416. synapse/rest/media/thumbnail_resource.py +142 -0
  417. synapse/rest/media/upload_resource.py +187 -0
  418. synapse/rest/media/v1/__init__.py +39 -0
  419. synapse/rest/media/v1/_base.py +23 -0
  420. synapse/rest/media/v1/media_storage.py +23 -0
  421. synapse/rest/media/v1/storage_provider.py +23 -0
  422. synapse/rest/synapse/__init__.py +20 -0
  423. synapse/rest/synapse/client/__init__.py +93 -0
  424. synapse/rest/synapse/client/federation_whitelist.py +66 -0
  425. synapse/rest/synapse/client/jwks.py +77 -0
  426. synapse/rest/synapse/client/new_user_consent.py +115 -0
  427. synapse/rest/synapse/client/oidc/__init__.py +45 -0
  428. synapse/rest/synapse/client/oidc/backchannel_logout_resource.py +42 -0
  429. synapse/rest/synapse/client/oidc/callback_resource.py +48 -0
  430. synapse/rest/synapse/client/password_reset.py +129 -0
  431. synapse/rest/synapse/client/pick_idp.py +107 -0
  432. synapse/rest/synapse/client/pick_username.py +153 -0
  433. synapse/rest/synapse/client/rendezvous.py +58 -0
  434. synapse/rest/synapse/client/saml2/__init__.py +42 -0
  435. synapse/rest/synapse/client/saml2/metadata_resource.py +46 -0
  436. synapse/rest/synapse/client/saml2/response_resource.py +52 -0
  437. synapse/rest/synapse/client/sso_register.py +56 -0
  438. synapse/rest/synapse/client/unsubscribe.py +88 -0
  439. synapse/rest/synapse/mas/__init__.py +71 -0
  440. synapse/rest/synapse/mas/_base.py +55 -0
  441. synapse/rest/synapse/mas/devices.py +239 -0
  442. synapse/rest/synapse/mas/users.py +469 -0
  443. synapse/rest/well_known.py +148 -0
  444. synapse/server.py +1258 -0
  445. synapse/server_notices/__init__.py +0 -0
  446. synapse/server_notices/consent_server_notices.py +136 -0
  447. synapse/server_notices/resource_limits_server_notices.py +215 -0
  448. synapse/server_notices/server_notices_manager.py +388 -0
  449. synapse/server_notices/server_notices_sender.py +67 -0
  450. synapse/server_notices/worker_server_notices_sender.py +46 -0
  451. synapse/spam_checker_api/__init__.py +31 -0
  452. synapse/state/__init__.py +1022 -0
  453. synapse/state/v1.py +370 -0
  454. synapse/state/v2.py +985 -0
  455. synapse/static/client/login/index.html +47 -0
  456. synapse/static/client/login/js/jquery-3.4.1.min.js +2 -0
  457. synapse/static/client/login/js/login.js +291 -0
  458. synapse/static/client/login/spinner.gif +0 -0
  459. synapse/static/client/login/style.css +79 -0
  460. synapse/static/index.html +63 -0
  461. synapse/storage/__init__.py +43 -0
  462. synapse/storage/_base.py +245 -0
  463. synapse/storage/admin_client_config.py +26 -0
  464. synapse/storage/background_updates.py +1189 -0
  465. synapse/storage/controllers/__init__.py +57 -0
  466. synapse/storage/controllers/persist_events.py +1239 -0
  467. synapse/storage/controllers/purge_events.py +456 -0
  468. synapse/storage/controllers/state.py +954 -0
  469. synapse/storage/controllers/stats.py +119 -0
  470. synapse/storage/database.py +2720 -0
  471. synapse/storage/databases/__init__.py +175 -0
  472. synapse/storage/databases/main/__init__.py +424 -0
  473. synapse/storage/databases/main/account_data.py +1060 -0
  474. synapse/storage/databases/main/appservice.py +473 -0
  475. synapse/storage/databases/main/cache.py +911 -0
  476. synapse/storage/databases/main/censor_events.py +225 -0
  477. synapse/storage/databases/main/client_ips.py +817 -0
  478. synapse/storage/databases/main/delayed_events.py +560 -0
  479. synapse/storage/databases/main/deviceinbox.py +1272 -0
  480. synapse/storage/databases/main/devices.py +2581 -0
  481. synapse/storage/databases/main/directory.py +212 -0
  482. synapse/storage/databases/main/e2e_room_keys.py +690 -0
  483. synapse/storage/databases/main/end_to_end_keys.py +1896 -0
  484. synapse/storage/databases/main/event_federation.py +2509 -0
  485. synapse/storage/databases/main/event_push_actions.py +1937 -0
  486. synapse/storage/databases/main/events.py +3746 -0
  487. synapse/storage/databases/main/events_bg_updates.py +2910 -0
  488. synapse/storage/databases/main/events_forward_extremities.py +126 -0
  489. synapse/storage/databases/main/events_worker.py +2784 -0
  490. synapse/storage/databases/main/experimental_features.py +130 -0
  491. synapse/storage/databases/main/filtering.py +231 -0
  492. synapse/storage/databases/main/keys.py +291 -0
  493. synapse/storage/databases/main/lock.py +553 -0
  494. synapse/storage/databases/main/media_repository.py +1070 -0
  495. synapse/storage/databases/main/metrics.py +460 -0
  496. synapse/storage/databases/main/monthly_active_users.py +443 -0
  497. synapse/storage/databases/main/openid.py +61 -0
  498. synapse/storage/databases/main/presence.py +511 -0
  499. synapse/storage/databases/main/profile.py +541 -0
  500. synapse/storage/databases/main/purge_events.py +511 -0
  501. synapse/storage/databases/main/push_rule.py +972 -0
  502. synapse/storage/databases/main/pusher.py +794 -0
  503. synapse/storage/databases/main/receipts.py +1342 -0
  504. synapse/storage/databases/main/registration.py +3076 -0
  505. synapse/storage/databases/main/rejections.py +38 -0
  506. synapse/storage/databases/main/relations.py +1118 -0
  507. synapse/storage/databases/main/room.py +2781 -0
  508. synapse/storage/databases/main/roommember.py +2112 -0
  509. synapse/storage/databases/main/search.py +941 -0
  510. synapse/storage/databases/main/session.py +151 -0
  511. synapse/storage/databases/main/signatures.py +94 -0
  512. synapse/storage/databases/main/sliding_sync.py +603 -0
  513. synapse/storage/databases/main/state.py +1006 -0
  514. synapse/storage/databases/main/state_deltas.py +329 -0
  515. synapse/storage/databases/main/stats.py +791 -0
  516. synapse/storage/databases/main/stream.py +2580 -0
  517. synapse/storage/databases/main/tags.py +360 -0
  518. synapse/storage/databases/main/task_scheduler.py +225 -0
  519. synapse/storage/databases/main/thread_subscriptions.py +591 -0
  520. synapse/storage/databases/main/transactions.py +681 -0
  521. synapse/storage/databases/main/ui_auth.py +420 -0
  522. synapse/storage/databases/main/user_directory.py +1331 -0
  523. synapse/storage/databases/main/user_erasure_store.py +117 -0
  524. synapse/storage/databases/state/__init__.py +22 -0
  525. synapse/storage/databases/state/bg_updates.py +499 -0
  526. synapse/storage/databases/state/deletion.py +558 -0
  527. synapse/storage/databases/state/store.py +949 -0
  528. synapse/storage/engines/__init__.py +70 -0
  529. synapse/storage/engines/_base.py +154 -0
  530. synapse/storage/engines/postgres.py +261 -0
  531. synapse/storage/engines/sqlite.py +199 -0
  532. synapse/storage/invite_rule.py +112 -0
  533. synapse/storage/keys.py +40 -0
  534. synapse/storage/prepare_database.py +731 -0
  535. synapse/storage/push_rule.py +28 -0
  536. synapse/storage/roommember.py +89 -0
  537. synapse/storage/schema/README.md +4 -0
  538. synapse/storage/schema/__init__.py +182 -0
  539. synapse/storage/schema/common/delta/25/00background_updates.sql +40 -0
  540. synapse/storage/schema/common/delta/35/00background_updates_add_col.sql +36 -0
  541. synapse/storage/schema/common/delta/58/00background_update_ordering.sql +38 -0
  542. synapse/storage/schema/common/full_schemas/72/full.sql.postgres +8 -0
  543. synapse/storage/schema/common/full_schemas/72/full.sql.sqlite +6 -0
  544. synapse/storage/schema/common/schema_version.sql +60 -0
  545. synapse/storage/schema/main/delta/12/v12.sql +82 -0
  546. synapse/storage/schema/main/delta/13/v13.sql +38 -0
  547. synapse/storage/schema/main/delta/14/v14.sql +42 -0
  548. synapse/storage/schema/main/delta/15/appservice_txns.sql +50 -0
  549. synapse/storage/schema/main/delta/15/presence_indices.sql +2 -0
  550. synapse/storage/schema/main/delta/15/v15.sql +24 -0
  551. synapse/storage/schema/main/delta/16/events_order_index.sql +4 -0
  552. synapse/storage/schema/main/delta/16/remote_media_cache_index.sql +2 -0
  553. synapse/storage/schema/main/delta/16/remove_duplicates.sql +9 -0
  554. synapse/storage/schema/main/delta/16/room_alias_index.sql +3 -0
  555. synapse/storage/schema/main/delta/16/unique_constraints.sql +72 -0
  556. synapse/storage/schema/main/delta/16/users.sql +56 -0
  557. synapse/storage/schema/main/delta/17/drop_indexes.sql +37 -0
  558. synapse/storage/schema/main/delta/17/server_keys.sql +43 -0
  559. synapse/storage/schema/main/delta/17/user_threepids.sql +9 -0
  560. synapse/storage/schema/main/delta/18/server_keys_bigger_ints.sql +51 -0
  561. synapse/storage/schema/main/delta/19/event_index.sql +38 -0
  562. synapse/storage/schema/main/delta/20/dummy.sql +1 -0
  563. synapse/storage/schema/main/delta/20/pushers.py +93 -0
  564. synapse/storage/schema/main/delta/21/end_to_end_keys.sql +53 -0
  565. synapse/storage/schema/main/delta/21/receipts.sql +57 -0
  566. synapse/storage/schema/main/delta/22/receipts_index.sql +41 -0
  567. synapse/storage/schema/main/delta/22/user_threepids_unique.sql +19 -0
  568. synapse/storage/schema/main/delta/24/stats_reporting.sql +37 -0
  569. synapse/storage/schema/main/delta/25/fts.py +81 -0
  570. synapse/storage/schema/main/delta/25/guest_access.sql +44 -0
  571. synapse/storage/schema/main/delta/25/history_visibility.sql +44 -0
  572. synapse/storage/schema/main/delta/25/tags.sql +57 -0
  573. synapse/storage/schema/main/delta/26/account_data.sql +36 -0
  574. synapse/storage/schema/main/delta/27/account_data.sql +55 -0
  575. synapse/storage/schema/main/delta/27/forgotten_memberships.sql +45 -0
  576. synapse/storage/schema/main/delta/27/ts.py +61 -0
  577. synapse/storage/schema/main/delta/28/event_push_actions.sql +46 -0
  578. synapse/storage/schema/main/delta/28/events_room_stream.sql +39 -0
  579. synapse/storage/schema/main/delta/28/public_roms_index.sql +39 -0
  580. synapse/storage/schema/main/delta/28/receipts_user_id_index.sql +41 -0
  581. synapse/storage/schema/main/delta/28/upgrade_times.sql +40 -0
  582. synapse/storage/schema/main/delta/28/users_is_guest.sql +41 -0
  583. synapse/storage/schema/main/delta/29/push_actions.sql +54 -0
  584. synapse/storage/schema/main/delta/30/alias_creator.sql +35 -0
  585. synapse/storage/schema/main/delta/30/as_users.py +82 -0
  586. synapse/storage/schema/main/delta/30/deleted_pushers.sql +44 -0
  587. synapse/storage/schema/main/delta/30/presence_stream.sql +49 -0
  588. synapse/storage/schema/main/delta/30/public_rooms.sql +42 -0
  589. synapse/storage/schema/main/delta/30/push_rule_stream.sql +57 -0
  590. synapse/storage/schema/main/delta/30/threepid_guest_access_tokens.sql +43 -0
  591. synapse/storage/schema/main/delta/31/invites.sql +61 -0
  592. synapse/storage/schema/main/delta/31/local_media_repository_url_cache.sql +46 -0
  593. synapse/storage/schema/main/delta/31/pushers_0.py +92 -0
  594. synapse/storage/schema/main/delta/31/pushers_index.sql +41 -0
  595. synapse/storage/schema/main/delta/31/search_update.py +65 -0
  596. synapse/storage/schema/main/delta/32/events.sql +35 -0
  597. synapse/storage/schema/main/delta/32/openid.sql +9 -0
  598. synapse/storage/schema/main/delta/32/pusher_throttle.sql +42 -0
  599. synapse/storage/schema/main/delta/32/remove_indices.sql +52 -0
  600. synapse/storage/schema/main/delta/32/reports.sql +44 -0
  601. synapse/storage/schema/main/delta/33/access_tokens_device_index.sql +36 -0
  602. synapse/storage/schema/main/delta/33/devices.sql +40 -0
  603. synapse/storage/schema/main/delta/33/devices_for_e2e_keys.sql +38 -0
  604. synapse/storage/schema/main/delta/33/devices_for_e2e_keys_clear_unknown_device.sql +39 -0
  605. synapse/storage/schema/main/delta/33/event_fields.py +61 -0
  606. synapse/storage/schema/main/delta/33/remote_media_ts.py +43 -0
  607. synapse/storage/schema/main/delta/33/user_ips_index.sql +36 -0
  608. synapse/storage/schema/main/delta/34/appservice_stream.sql +42 -0
  609. synapse/storage/schema/main/delta/34/cache_stream.py +50 -0
  610. synapse/storage/schema/main/delta/34/device_inbox.sql +43 -0
  611. synapse/storage/schema/main/delta/34/push_display_name_rename.sql +39 -0
  612. synapse/storage/schema/main/delta/34/received_txn_purge.py +36 -0
  613. synapse/storage/schema/main/delta/35/contains_url.sql +36 -0
  614. synapse/storage/schema/main/delta/35/device_outbox.sql +58 -0
  615. synapse/storage/schema/main/delta/35/device_stream_id.sql +40 -0
  616. synapse/storage/schema/main/delta/35/event_push_actions_index.sql +36 -0
  617. synapse/storage/schema/main/delta/35/public_room_list_change_stream.sql +52 -0
  618. synapse/storage/schema/main/delta/35/stream_order_to_extrem.sql +56 -0
  619. synapse/storage/schema/main/delta/36/readd_public_rooms.sql +45 -0
  620. synapse/storage/schema/main/delta/37/remove_auth_idx.py +89 -0
  621. synapse/storage/schema/main/delta/37/user_threepids.sql +71 -0
  622. synapse/storage/schema/main/delta/38/postgres_fts_gist.sql +38 -0
  623. synapse/storage/schema/main/delta/39/appservice_room_list.sql +48 -0
  624. synapse/storage/schema/main/delta/39/device_federation_stream_idx.sql +35 -0
  625. synapse/storage/schema/main/delta/39/event_push_index.sql +36 -0
  626. synapse/storage/schema/main/delta/39/federation_out_position.sql +41 -0
  627. synapse/storage/schema/main/delta/39/membership_profile.sql +39 -0
  628. synapse/storage/schema/main/delta/40/current_state_idx.sql +36 -0
  629. synapse/storage/schema/main/delta/40/device_inbox.sql +40 -0
  630. synapse/storage/schema/main/delta/40/device_list_streams.sql +79 -0
  631. synapse/storage/schema/main/delta/40/event_push_summary.sql +57 -0
  632. synapse/storage/schema/main/delta/40/pushers.sql +58 -0
  633. synapse/storage/schema/main/delta/41/device_list_stream_idx.sql +36 -0
  634. synapse/storage/schema/main/delta/41/device_outbound_index.sql +35 -0
  635. synapse/storage/schema/main/delta/41/event_search_event_id_idx.sql +36 -0
  636. synapse/storage/schema/main/delta/41/ratelimit.sql +41 -0
  637. synapse/storage/schema/main/delta/42/current_state_delta.sql +48 -0
  638. synapse/storage/schema/main/delta/42/device_list_last_id.sql +52 -0
  639. synapse/storage/schema/main/delta/42/event_auth_state_only.sql +36 -0
  640. synapse/storage/schema/main/delta/42/user_dir.py +88 -0
  641. synapse/storage/schema/main/delta/43/blocked_rooms.sql +40 -0
  642. synapse/storage/schema/main/delta/43/quarantine_media.sql +36 -0
  643. synapse/storage/schema/main/delta/43/url_cache.sql +35 -0
  644. synapse/storage/schema/main/delta/43/user_share.sql +52 -0
  645. synapse/storage/schema/main/delta/44/expire_url_cache.sql +60 -0
  646. synapse/storage/schema/main/delta/45/group_server.sql +186 -0
  647. synapse/storage/schema/main/delta/45/profile_cache.sql +47 -0
  648. synapse/storage/schema/main/delta/46/drop_refresh_tokens.sql +36 -0
  649. synapse/storage/schema/main/delta/46/drop_unique_deleted_pushers.sql +54 -0
  650. synapse/storage/schema/main/delta/46/group_server.sql +51 -0
  651. synapse/storage/schema/main/delta/46/local_media_repository_url_idx.sql +43 -0
  652. synapse/storage/schema/main/delta/46/user_dir_null_room_ids.sql +54 -0
  653. synapse/storage/schema/main/delta/46/user_dir_typos.sql +43 -0
  654. synapse/storage/schema/main/delta/47/last_access_media.sql +35 -0
  655. synapse/storage/schema/main/delta/47/postgres_fts_gin.sql +36 -0
  656. synapse/storage/schema/main/delta/47/push_actions_staging.sql +47 -0
  657. synapse/storage/schema/main/delta/48/add_user_consent.sql +37 -0
  658. synapse/storage/schema/main/delta/48/add_user_ips_last_seen_index.sql +36 -0
  659. synapse/storage/schema/main/delta/48/deactivated_users.sql +44 -0
  660. synapse/storage/schema/main/delta/48/group_unique_indexes.py +67 -0
  661. synapse/storage/schema/main/delta/48/groups_joinable.sql +41 -0
  662. synapse/storage/schema/main/delta/49/add_user_consent_server_notice_sent.sql +39 -0
  663. synapse/storage/schema/main/delta/49/add_user_daily_visits.sql +40 -0
  664. synapse/storage/schema/main/delta/49/add_user_ips_last_seen_only_index.sql +36 -0
  665. synapse/storage/schema/main/delta/50/add_creation_ts_users_index.sql +38 -0
  666. synapse/storage/schema/main/delta/50/erasure_store.sql +40 -0
  667. synapse/storage/schema/main/delta/50/make_event_content_nullable.py +102 -0
  668. synapse/storage/schema/main/delta/51/e2e_room_keys.sql +58 -0
  669. synapse/storage/schema/main/delta/51/monthly_active_users.sql +46 -0
  670. synapse/storage/schema/main/delta/52/add_event_to_state_group_index.sql +38 -0
  671. synapse/storage/schema/main/delta/52/device_list_streams_unique_idx.sql +55 -0
  672. synapse/storage/schema/main/delta/52/e2e_room_keys.sql +72 -0
  673. synapse/storage/schema/main/delta/53/add_user_type_to_users.sql +38 -0
  674. synapse/storage/schema/main/delta/53/drop_sent_transactions.sql +35 -0
  675. synapse/storage/schema/main/delta/53/event_format_version.sql +35 -0
  676. synapse/storage/schema/main/delta/53/user_dir_populate.sql +49 -0
  677. synapse/storage/schema/main/delta/53/user_ips_index.sql +49 -0
  678. synapse/storage/schema/main/delta/53/user_share.sql +63 -0
  679. synapse/storage/schema/main/delta/53/user_threepid_id.sql +48 -0
  680. synapse/storage/schema/main/delta/53/users_in_public_rooms.sql +47 -0
  681. synapse/storage/schema/main/delta/54/account_validity_with_renewal.sql +49 -0
  682. synapse/storage/schema/main/delta/54/add_validity_to_server_keys.sql +42 -0
  683. synapse/storage/schema/main/delta/54/delete_forward_extremities.sql +42 -0
  684. synapse/storage/schema/main/delta/54/drop_legacy_tables.sql +49 -0
  685. synapse/storage/schema/main/delta/54/drop_presence_list.sql +35 -0
  686. synapse/storage/schema/main/delta/54/relations.sql +46 -0
  687. synapse/storage/schema/main/delta/54/stats.sql +99 -0
  688. synapse/storage/schema/main/delta/54/stats2.sql +47 -0
  689. synapse/storage/schema/main/delta/55/access_token_expiry.sql +37 -0
  690. synapse/storage/schema/main/delta/55/track_threepid_validations.sql +50 -0
  691. synapse/storage/schema/main/delta/55/users_alter_deactivated.sql +38 -0
  692. synapse/storage/schema/main/delta/56/add_spans_to_device_lists.sql +39 -0
  693. synapse/storage/schema/main/delta/56/current_state_events_membership.sql +41 -0
  694. synapse/storage/schema/main/delta/56/current_state_events_membership_mk2.sql +43 -0
  695. synapse/storage/schema/main/delta/56/delete_keys_from_deleted_backups.sql +44 -0
  696. synapse/storage/schema/main/delta/56/destinations_failure_ts.sql +44 -0
  697. synapse/storage/schema/main/delta/56/destinations_retry_interval_type.sql.postgres +18 -0
  698. synapse/storage/schema/main/delta/56/device_stream_id_insert.sql +39 -0
  699. synapse/storage/schema/main/delta/56/devices_last_seen.sql +43 -0
  700. synapse/storage/schema/main/delta/56/drop_unused_event_tables.sql +39 -0
  701. synapse/storage/schema/main/delta/56/event_expiry.sql +40 -0
  702. synapse/storage/schema/main/delta/56/event_labels.sql +49 -0
  703. synapse/storage/schema/main/delta/56/event_labels_background_update.sql +36 -0
  704. synapse/storage/schema/main/delta/56/fix_room_keys_index.sql +37 -0
  705. synapse/storage/schema/main/delta/56/hidden_devices.sql +37 -0
  706. synapse/storage/schema/main/delta/56/hidden_devices_fix.sql.sqlite +42 -0
  707. synapse/storage/schema/main/delta/56/nuke_empty_communities_from_db.sql +48 -0
  708. synapse/storage/schema/main/delta/56/public_room_list_idx.sql +35 -0
  709. synapse/storage/schema/main/delta/56/redaction_censor.sql +35 -0
  710. synapse/storage/schema/main/delta/56/redaction_censor2.sql +41 -0
  711. synapse/storage/schema/main/delta/56/redaction_censor3_fix_update.sql.postgres +25 -0
  712. synapse/storage/schema/main/delta/56/redaction_censor4.sql +35 -0
  713. synapse/storage/schema/main/delta/56/remove_tombstoned_rooms_from_directory.sql +38 -0
  714. synapse/storage/schema/main/delta/56/room_key_etag.sql +36 -0
  715. synapse/storage/schema/main/delta/56/room_membership_idx.sql +37 -0
  716. synapse/storage/schema/main/delta/56/room_retention.sql +52 -0
  717. synapse/storage/schema/main/delta/56/signing_keys.sql +75 -0
  718. synapse/storage/schema/main/delta/56/signing_keys_nonunique_signatures.sql +41 -0
  719. synapse/storage/schema/main/delta/56/stats_separated.sql +175 -0
  720. synapse/storage/schema/main/delta/56/unique_user_filter_index.py +46 -0
  721. synapse/storage/schema/main/delta/56/user_external_ids.sql +43 -0
  722. synapse/storage/schema/main/delta/56/users_in_public_rooms_idx.sql +36 -0
  723. synapse/storage/schema/main/delta/57/delete_old_current_state_events.sql +41 -0
  724. synapse/storage/schema/main/delta/57/device_list_remote_cache_stale.sql +44 -0
  725. synapse/storage/schema/main/delta/57/local_current_membership.py +111 -0
  726. synapse/storage/schema/main/delta/57/remove_sent_outbound_pokes.sql +40 -0
  727. synapse/storage/schema/main/delta/57/rooms_version_column.sql +43 -0
  728. synapse/storage/schema/main/delta/57/rooms_version_column_2.sql.postgres +35 -0
  729. synapse/storage/schema/main/delta/57/rooms_version_column_2.sql.sqlite +22 -0
  730. synapse/storage/schema/main/delta/57/rooms_version_column_3.sql.postgres +39 -0
  731. synapse/storage/schema/main/delta/57/rooms_version_column_3.sql.sqlite +23 -0
  732. synapse/storage/schema/main/delta/58/02remove_dup_outbound_pokes.sql +41 -0
  733. synapse/storage/schema/main/delta/58/03persist_ui_auth.sql +55 -0
  734. synapse/storage/schema/main/delta/58/05cache_instance.sql.postgres +30 -0
  735. synapse/storage/schema/main/delta/58/06dlols_unique_idx.py +83 -0
  736. synapse/storage/schema/main/delta/58/07add_method_to_thumbnail_constraint.sql.postgres +33 -0
  737. synapse/storage/schema/main/delta/58/07add_method_to_thumbnail_constraint.sql.sqlite +44 -0
  738. synapse/storage/schema/main/delta/58/07persist_ui_auth_ips.sql +44 -0
  739. synapse/storage/schema/main/delta/58/08_media_safe_from_quarantine.sql.postgres +18 -0
  740. synapse/storage/schema/main/delta/58/08_media_safe_from_quarantine.sql.sqlite +18 -0
  741. synapse/storage/schema/main/delta/58/09shadow_ban.sql +37 -0
  742. synapse/storage/schema/main/delta/58/10_pushrules_enabled_delete_obsolete.sql +47 -0
  743. synapse/storage/schema/main/delta/58/10drop_local_rejections_stream.sql +41 -0
  744. synapse/storage/schema/main/delta/58/10federation_pos_instance_name.sql +41 -0
  745. synapse/storage/schema/main/delta/58/11dehydration.sql +39 -0
  746. synapse/storage/schema/main/delta/58/11fallback.sql +43 -0
  747. synapse/storage/schema/main/delta/58/11user_id_seq.py +38 -0
  748. synapse/storage/schema/main/delta/58/12room_stats.sql +51 -0
  749. synapse/storage/schema/main/delta/58/13remove_presence_allow_inbound.sql +36 -0
  750. synapse/storage/schema/main/delta/58/14events_instance_name.sql +35 -0
  751. synapse/storage/schema/main/delta/58/14events_instance_name.sql.postgres +28 -0
  752. synapse/storage/schema/main/delta/58/15_catchup_destination_rooms.sql +61 -0
  753. synapse/storage/schema/main/delta/58/15unread_count.sql +45 -0
  754. synapse/storage/schema/main/delta/58/16populate_stats_process_rooms_fix.sql +41 -0
  755. synapse/storage/schema/main/delta/58/17_catchup_last_successful.sql +40 -0
  756. synapse/storage/schema/main/delta/58/18stream_positions.sql +41 -0
  757. synapse/storage/schema/main/delta/58/19instance_map.sql.postgres +25 -0
  758. synapse/storage/schema/main/delta/58/19txn_id.sql +59 -0
  759. synapse/storage/schema/main/delta/58/20instance_name_event_tables.sql +36 -0
  760. synapse/storage/schema/main/delta/58/20user_daily_visits.sql +37 -0
  761. synapse/storage/schema/main/delta/58/21as_device_stream.sql +36 -0
  762. synapse/storage/schema/main/delta/58/21drop_device_max_stream_id.sql +1 -0
  763. synapse/storage/schema/main/delta/58/22puppet_token.sql +36 -0
  764. synapse/storage/schema/main/delta/58/22users_have_local_media.sql +2 -0
  765. synapse/storage/schema/main/delta/58/23e2e_cross_signing_keys_idx.sql +36 -0
  766. synapse/storage/schema/main/delta/58/24drop_event_json_index.sql +38 -0
  767. synapse/storage/schema/main/delta/58/25user_external_ids_user_id_idx.sql +36 -0
  768. synapse/storage/schema/main/delta/58/26access_token_last_validated.sql +37 -0
  769. synapse/storage/schema/main/delta/58/27local_invites.sql +37 -0
  770. synapse/storage/schema/main/delta/58/28drop_last_used_column.sql.postgres +16 -0
  771. synapse/storage/schema/main/delta/58/28drop_last_used_column.sql.sqlite +62 -0
  772. synapse/storage/schema/main/delta/59/01ignored_user.py +85 -0
  773. synapse/storage/schema/main/delta/59/02shard_send_to_device.sql +37 -0
  774. synapse/storage/schema/main/delta/59/03shard_send_to_device_sequence.sql.postgres +25 -0
  775. synapse/storage/schema/main/delta/59/04_event_auth_chains.sql +71 -0
  776. synapse/storage/schema/main/delta/59/04_event_auth_chains.sql.postgres +16 -0
  777. synapse/storage/schema/main/delta/59/04drop_account_data.sql +36 -0
  778. synapse/storage/schema/main/delta/59/05cache_invalidation.sql +36 -0
  779. synapse/storage/schema/main/delta/59/06chain_cover_index.sql +36 -0
  780. synapse/storage/schema/main/delta/59/06shard_account_data.sql +39 -0
  781. synapse/storage/schema/main/delta/59/06shard_account_data.sql.postgres +32 -0
  782. synapse/storage/schema/main/delta/59/07shard_account_data_fix.sql +37 -0
  783. synapse/storage/schema/main/delta/59/08delete_pushers_for_deactivated_accounts.sql +39 -0
  784. synapse/storage/schema/main/delta/59/08delete_stale_pushers.sql +39 -0
  785. synapse/storage/schema/main/delta/59/09rejected_events_metadata.sql +45 -0
  786. synapse/storage/schema/main/delta/59/10delete_purged_chain_cover.sql +36 -0
  787. synapse/storage/schema/main/delta/59/11add_knock_members_to_stats.sql +39 -0
  788. synapse/storage/schema/main/delta/59/11drop_thumbnail_constraint.sql.postgres +22 -0
  789. synapse/storage/schema/main/delta/59/12account_validity_token_used_ts_ms.sql +37 -0
  790. synapse/storage/schema/main/delta/59/12presence_stream_instance.sql +37 -0
  791. synapse/storage/schema/main/delta/59/12presence_stream_instance_seq.sql.postgres +20 -0
  792. synapse/storage/schema/main/delta/59/13users_to_send_full_presence_to.sql +53 -0
  793. synapse/storage/schema/main/delta/59/14refresh_tokens.sql +53 -0
  794. synapse/storage/schema/main/delta/59/15locks.sql +56 -0
  795. synapse/storage/schema/main/delta/59/16federation_inbound_staging.sql +51 -0
  796. synapse/storage/schema/main/delta/60/01recreate_stream_ordering.sql.postgres +45 -0
  797. synapse/storage/schema/main/delta/60/02change_stream_ordering_columns.sql.postgres +30 -0
  798. synapse/storage/schema/main/delta/61/01change_appservices_txns.sql.postgres +23 -0
  799. synapse/storage/schema/main/delta/61/01insertion_event_lookups.sql +68 -0
  800. synapse/storage/schema/main/delta/61/02drop_redundant_room_depth_index.sql +37 -0
  801. synapse/storage/schema/main/delta/61/03recreate_min_depth.py +74 -0
  802. synapse/storage/schema/main/delta/62/01insertion_event_extremities.sql +43 -0
  803. synapse/storage/schema/main/delta/63/01create_registration_tokens.sql +42 -0
  804. synapse/storage/schema/main/delta/63/02delete_unlinked_email_pushers.sql +39 -0
  805. synapse/storage/schema/main/delta/63/02populate-rooms-creator.sql +36 -0
  806. synapse/storage/schema/main/delta/63/03session_store.sql +42 -0
  807. synapse/storage/schema/main/delta/63/04add_presence_stream_not_offline_index.sql +37 -0
  808. synapse/storage/schema/main/delta/64/01msc2716_chunk_to_batch_rename.sql.postgres +23 -0
  809. synapse/storage/schema/main/delta/64/01msc2716_chunk_to_batch_rename.sql.sqlite +37 -0
  810. synapse/storage/schema/main/delta/65/01msc2716_insertion_event_edges.sql +38 -0
  811. synapse/storage/schema/main/delta/65/03remove_hidden_devices_from_device_inbox.sql +41 -0
  812. synapse/storage/schema/main/delta/65/04_local_group_updates.sql +37 -0
  813. synapse/storage/schema/main/delta/65/05_remove_room_stats_historical_and_user_stats_historical.sql +38 -0
  814. synapse/storage/schema/main/delta/65/06remove_deleted_devices_from_device_inbox.sql +53 -0
  815. synapse/storage/schema/main/delta/65/07_arbitrary_relations.sql +37 -0
  816. synapse/storage/schema/main/delta/65/08_device_inbox_background_updates.sql +37 -0
  817. synapse/storage/schema/main/delta/65/10_expirable_refresh_tokens.sql +47 -0
  818. synapse/storage/schema/main/delta/65/11_devices_auth_provider_session.sql +46 -0
  819. synapse/storage/schema/main/delta/67/01drop_public_room_list_stream.sql +37 -0
  820. synapse/storage/schema/main/delta/68/01event_columns.sql +45 -0
  821. synapse/storage/schema/main/delta/68/02_msc2409_add_device_id_appservice_stream_type.sql +40 -0
  822. synapse/storage/schema/main/delta/68/03_delete_account_data_for_deactivated_accounts.sql +39 -0
  823. synapse/storage/schema/main/delta/68/04_refresh_tokens_index_next_token_id.sql +47 -0
  824. synapse/storage/schema/main/delta/68/04partial_state_rooms.sql +60 -0
  825. synapse/storage/schema/main/delta/68/05_delete_non_strings_from_event_search.sql.sqlite +22 -0
  826. synapse/storage/schema/main/delta/68/05partial_state_rooms_triggers.py +80 -0
  827. synapse/storage/schema/main/delta/68/06_msc3202_add_device_list_appservice_stream_type.sql +42 -0
  828. synapse/storage/schema/main/delta/69/01as_txn_seq.py +54 -0
  829. synapse/storage/schema/main/delta/69/01device_list_oubound_by_room.sql +57 -0
  830. synapse/storage/schema/main/delta/69/02cache_invalidation_index.sql +37 -0
  831. synapse/storage/schema/main/delta/70/01clean_table_purged_rooms.sql +39 -0
  832. synapse/storage/schema/main/delta/71/01rebuild_event_edges.sql.postgres +43 -0
  833. synapse/storage/schema/main/delta/71/01rebuild_event_edges.sql.sqlite +47 -0
  834. synapse/storage/schema/main/delta/71/01remove_noop_background_updates.sql +80 -0
  835. synapse/storage/schema/main/delta/71/02event_push_summary_unique.sql +37 -0
  836. synapse/storage/schema/main/delta/72/01add_room_type_to_state_stats.sql +38 -0
  837. synapse/storage/schema/main/delta/72/01event_push_summary_receipt.sql +54 -0
  838. synapse/storage/schema/main/delta/72/02event_push_actions_index.sql +38 -0
  839. synapse/storage/schema/main/delta/72/03bg_populate_events_columns.py +57 -0
  840. synapse/storage/schema/main/delta/72/03drop_event_reference_hashes.sql +36 -0
  841. synapse/storage/schema/main/delta/72/03remove_groups.sql +50 -0
  842. synapse/storage/schema/main/delta/72/04drop_column_application_services_state_last_txn.sql.postgres +17 -0
  843. synapse/storage/schema/main/delta/72/04drop_column_application_services_state_last_txn.sql.sqlite +40 -0
  844. synapse/storage/schema/main/delta/72/05receipts_event_stream_ordering.sql +38 -0
  845. synapse/storage/schema/main/delta/72/05remove_unstable_private_read_receipts.sql +38 -0
  846. synapse/storage/schema/main/delta/72/06add_consent_ts_to_users.sql +35 -0
  847. synapse/storage/schema/main/delta/72/06thread_notifications.sql +49 -0
  848. synapse/storage/schema/main/delta/72/07force_update_current_state_events_membership.py +67 -0
  849. synapse/storage/schema/main/delta/72/07thread_receipts.sql.postgres +30 -0
  850. synapse/storage/schema/main/delta/72/07thread_receipts.sql.sqlite +70 -0
  851. synapse/storage/schema/main/delta/72/08begin_cache_invalidation_seq_at_2.sql.postgres +23 -0
  852. synapse/storage/schema/main/delta/72/08thread_receipts.sql +39 -0
  853. synapse/storage/schema/main/delta/72/09partial_indices.sql.sqlite +56 -0
  854. synapse/storage/schema/main/delta/73/01event_failed_pull_attempts.sql +48 -0
  855. synapse/storage/schema/main/delta/73/02add_pusher_enabled.sql +35 -0
  856. synapse/storage/schema/main/delta/73/02room_id_indexes_for_purging.sql +41 -0
  857. synapse/storage/schema/main/delta/73/03pusher_device_id.sql +39 -0
  858. synapse/storage/schema/main/delta/73/03users_approved_column.sql +39 -0
  859. synapse/storage/schema/main/delta/73/04partial_join_details.sql +42 -0
  860. synapse/storage/schema/main/delta/73/04pending_device_list_updates.sql +47 -0
  861. synapse/storage/schema/main/delta/73/05old_push_actions.sql.postgres +22 -0
  862. synapse/storage/schema/main/delta/73/05old_push_actions.sql.sqlite +24 -0
  863. synapse/storage/schema/main/delta/73/06thread_notifications_thread_id_idx.sql +42 -0
  864. synapse/storage/schema/main/delta/73/08thread_receipts_non_null.sql.postgres +23 -0
  865. synapse/storage/schema/main/delta/73/08thread_receipts_non_null.sql.sqlite +76 -0
  866. synapse/storage/schema/main/delta/73/09partial_joined_via_destination.sql +37 -0
  867. synapse/storage/schema/main/delta/73/09threads_table.sql +49 -0
  868. synapse/storage/schema/main/delta/73/10_update_sqlite_fts4_tokenizer.py +71 -0
  869. synapse/storage/schema/main/delta/73/10login_tokens.sql +54 -0
  870. synapse/storage/schema/main/delta/73/11event_search_room_id_n_distinct.sql.postgres +33 -0
  871. synapse/storage/schema/main/delta/73/12refactor_device_list_outbound_pokes.sql +72 -0
  872. synapse/storage/schema/main/delta/73/13add_device_lists_index.sql +39 -0
  873. synapse/storage/schema/main/delta/73/20_un_partial_stated_room_stream.sql +51 -0
  874. synapse/storage/schema/main/delta/73/21_un_partial_stated_room_stream_seq.sql.postgres +20 -0
  875. synapse/storage/schema/main/delta/73/22_rebuild_user_dir_stats.sql +48 -0
  876. synapse/storage/schema/main/delta/73/22_un_partial_stated_event_stream.sql +53 -0
  877. synapse/storage/schema/main/delta/73/23_fix_thread_index.sql +52 -0
  878. synapse/storage/schema/main/delta/73/23_un_partial_stated_room_stream_seq.sql.postgres +20 -0
  879. synapse/storage/schema/main/delta/73/24_events_jump_to_date_index.sql +36 -0
  880. synapse/storage/schema/main/delta/73/25drop_presence.sql +36 -0
  881. synapse/storage/schema/main/delta/74/01_user_directory_stale_remote_users.sql +58 -0
  882. synapse/storage/schema/main/delta/74/02_set_device_id_for_pushers_bg_update.sql +38 -0
  883. synapse/storage/schema/main/delta/74/03_membership_tables_event_stream_ordering.sql.postgres +29 -0
  884. synapse/storage/schema/main/delta/74/03_membership_tables_event_stream_ordering.sql.sqlite +23 -0
  885. synapse/storage/schema/main/delta/74/03_room_membership_index.sql +38 -0
  886. synapse/storage/schema/main/delta/74/04_delete_e2e_backup_keys_for_deactivated_users.sql +36 -0
  887. synapse/storage/schema/main/delta/74/04_membership_tables_event_stream_ordering_triggers.py +87 -0
  888. synapse/storage/schema/main/delta/74/05_events_txn_id_device_id.sql +72 -0
  889. synapse/storage/schema/main/delta/74/90COMMENTS_destinations.sql.postgres +52 -0
  890. synapse/storage/schema/main/delta/76/01_add_profiles_full_user_id_column.sql +39 -0
  891. synapse/storage/schema/main/delta/76/02_add_user_filters_full_user_id_column.sql +39 -0
  892. synapse/storage/schema/main/delta/76/03_per_user_experimental_features.sql +46 -0
  893. synapse/storage/schema/main/delta/76/04_add_room_forgetter.sql +43 -0
  894. synapse/storage/schema/main/delta/77/01_add_profiles_not_valid_check.sql.postgres +16 -0
  895. synapse/storage/schema/main/delta/77/02_add_user_filters_not_valid_check.sql.postgres +16 -0
  896. synapse/storage/schema/main/delta/77/03bg_populate_full_user_id_profiles.sql +35 -0
  897. synapse/storage/schema/main/delta/77/04bg_populate_full_user_id_user_filters.sql +35 -0
  898. synapse/storage/schema/main/delta/77/05thread_notifications_backfill.sql +67 -0
  899. synapse/storage/schema/main/delta/77/06thread_notifications_not_null.sql.sqlite +102 -0
  900. synapse/storage/schema/main/delta/77/06thread_notifications_not_null_event_push_actions.sql.postgres +27 -0
  901. synapse/storage/schema/main/delta/77/06thread_notifications_not_null_event_push_actions_staging.sql.postgres +27 -0
  902. synapse/storage/schema/main/delta/77/06thread_notifications_not_null_event_push_summary.sql.postgres +29 -0
  903. synapse/storage/schema/main/delta/77/14bg_indices_event_stream_ordering.sql +39 -0
  904. synapse/storage/schema/main/delta/78/01_validate_and_update_profiles.py +99 -0
  905. synapse/storage/schema/main/delta/78/02_validate_and_update_user_filters.py +100 -0
  906. synapse/storage/schema/main/delta/78/03_remove_unused_indexes_user_filters.py +72 -0
  907. synapse/storage/schema/main/delta/78/03event_extremities_constraints.py +65 -0
  908. synapse/storage/schema/main/delta/78/04_add_full_user_id_index_user_filters.py +32 -0
  909. synapse/storage/schema/main/delta/79/03_read_write_locks_triggers.sql.postgres +102 -0
  910. synapse/storage/schema/main/delta/79/03_read_write_locks_triggers.sql.sqlite +72 -0
  911. synapse/storage/schema/main/delta/79/04_mitigate_stream_ordering_update_race.py +70 -0
  912. synapse/storage/schema/main/delta/79/05_read_write_locks_triggers.sql.postgres +69 -0
  913. synapse/storage/schema/main/delta/79/05_read_write_locks_triggers.sql.sqlite +65 -0
  914. synapse/storage/schema/main/delta/80/01_users_alter_locked.sql +35 -0
  915. synapse/storage/schema/main/delta/80/02_read_write_locks_unlogged.sql.postgres +30 -0
  916. synapse/storage/schema/main/delta/80/02_scheduled_tasks.sql +47 -0
  917. synapse/storage/schema/main/delta/80/03_read_write_locks_triggers.sql.postgres +37 -0
  918. synapse/storage/schema/main/delta/80/04_read_write_locks_deadlock.sql.postgres +71 -0
  919. synapse/storage/schema/main/delta/82/02_scheduled_tasks_index.sql +35 -0
  920. synapse/storage/schema/main/delta/82/04_add_indices_for_purging_rooms.sql +39 -0
  921. synapse/storage/schema/main/delta/82/05gaps.sql +44 -0
  922. synapse/storage/schema/main/delta/83/01_drop_old_tables.sql +43 -0
  923. synapse/storage/schema/main/delta/83/03_instance_name_receipts.sql.sqlite +17 -0
  924. synapse/storage/schema/main/delta/83/05_cross_signing_key_update_grant.sql +34 -0
  925. synapse/storage/schema/main/delta/83/06_event_push_summary_room.sql +36 -0
  926. synapse/storage/schema/main/delta/84/01_auth_links_stats.sql.postgres +20 -0
  927. synapse/storage/schema/main/delta/84/02_auth_links_index.sql +16 -0
  928. synapse/storage/schema/main/delta/84/03_auth_links_analyze.sql.postgres +16 -0
  929. synapse/storage/schema/main/delta/84/04_access_token_index.sql +15 -0
  930. synapse/storage/schema/main/delta/85/01_add_suspended.sql +14 -0
  931. synapse/storage/schema/main/delta/85/02_add_instance_names.sql +27 -0
  932. synapse/storage/schema/main/delta/85/03_new_sequences.sql.postgres +54 -0
  933. synapse/storage/schema/main/delta/85/04_cleanup_device_federation_outbox.sql +15 -0
  934. synapse/storage/schema/main/delta/85/05_add_instance_names_converted_pos.sql +16 -0
  935. synapse/storage/schema/main/delta/85/06_add_room_reports.sql +20 -0
  936. synapse/storage/schema/main/delta/86/01_authenticate_media.sql +15 -0
  937. synapse/storage/schema/main/delta/86/02_receipts_event_id_index.sql +15 -0
  938. synapse/storage/schema/main/delta/87/01_sliding_sync_memberships.sql +169 -0
  939. synapse/storage/schema/main/delta/87/02_per_connection_state.sql +81 -0
  940. synapse/storage/schema/main/delta/87/03_current_state_index.sql +19 -0
  941. synapse/storage/schema/main/delta/88/01_add_delayed_events.sql +43 -0
  942. synapse/storage/schema/main/delta/88/01_custom_profile_fields.sql +15 -0
  943. synapse/storage/schema/main/delta/88/02_fix_sliding_sync_membership_snapshots_forgotten_column.sql +21 -0
  944. synapse/storage/schema/main/delta/88/03_add_otk_ts_added_index.sql +18 -0
  945. synapse/storage/schema/main/delta/88/04_current_state_delta_index.sql +18 -0
  946. synapse/storage/schema/main/delta/88/05_drop_old_otks.sql.postgres +19 -0
  947. synapse/storage/schema/main/delta/88/05_drop_old_otks.sql.sqlite +19 -0
  948. synapse/storage/schema/main/delta/88/05_sliding_sync_room_config_index.sql +20 -0
  949. synapse/storage/schema/main/delta/88/06_events_received_ts_index.sql +17 -0
  950. synapse/storage/schema/main/delta/89/01_sliding_sync_membership_snapshot_index.sql +15 -0
  951. synapse/storage/schema/main/delta/90/01_add_column_participant_room_memberships_table.sql +16 -0
  952. synapse/storage/schema/main/delta/91/01_media_hash.sql +28 -0
  953. synapse/storage/schema/main/delta/92/01_remove_trigger.sql.postgres +16 -0
  954. synapse/storage/schema/main/delta/92/01_remove_trigger.sql.sqlite +16 -0
  955. synapse/storage/schema/main/delta/92/02_remove_populate_participant_bg_update.sql +17 -0
  956. synapse/storage/schema/main/delta/92/04_ss_membership_snapshot_idx.sql +16 -0
  957. synapse/storage/schema/main/delta/92/04_thread_subscriptions.sql +59 -0
  958. synapse/storage/schema/main/delta/92/04_thread_subscriptions_seq.sql.postgres +19 -0
  959. synapse/storage/schema/main/delta/92/05_fixup_max_depth_cap.sql +17 -0
  960. synapse/storage/schema/main/delta/92/05_thread_subscriptions_comments.sql.postgres +18 -0
  961. synapse/storage/schema/main/delta/92/06_device_federation_inbox_index.sql +16 -0
  962. synapse/storage/schema/main/delta/92/06_threads_last_sent_stream_ordering_comments.sql.postgres +24 -0
  963. synapse/storage/schema/main/delta/92/07_add_user_reports.sql +22 -0
  964. synapse/storage/schema/main/delta/92/07_event_txn_id_device_id_txn_id2.sql +15 -0
  965. synapse/storage/schema/main/delta/92/08_room_ban_redactions.sql +21 -0
  966. synapse/storage/schema/main/delta/92/08_thread_subscriptions_seq_fixup.sql.postgres +19 -0
  967. synapse/storage/schema/main/delta/92/09_thread_subscriptions_update.sql +20 -0
  968. synapse/storage/schema/main/delta/92/09_thread_subscriptions_update.sql.postgres +18 -0
  969. synapse/storage/schema/main/full_schemas/72/full.sql.postgres +1344 -0
  970. synapse/storage/schema/main/full_schemas/72/full.sql.sqlite +646 -0
  971. synapse/storage/schema/state/delta/23/drop_state_index.sql +35 -0
  972. synapse/storage/schema/state/delta/32/remove_state_indices.sql +38 -0
  973. synapse/storage/schema/state/delta/35/add_state_index.sql +36 -0
  974. synapse/storage/schema/state/delta/35/state.sql +41 -0
  975. synapse/storage/schema/state/delta/35/state_dedupe.sql +36 -0
  976. synapse/storage/schema/state/delta/47/state_group_seq.py +38 -0
  977. synapse/storage/schema/state/delta/56/state_group_room_idx.sql +36 -0
  978. synapse/storage/schema/state/delta/61/02state_groups_state_n_distinct.sql.postgres +34 -0
  979. synapse/storage/schema/state/delta/70/08_state_group_edges_unique.sql +36 -0
  980. synapse/storage/schema/state/delta/89/01_state_groups_deletion.sql +39 -0
  981. synapse/storage/schema/state/delta/90/02_delete_unreferenced_state_groups.sql +16 -0
  982. synapse/storage/schema/state/delta/90/03_remove_old_deletion_bg_update.sql +15 -0
  983. synapse/storage/schema/state/full_schemas/72/full.sql.postgres +30 -0
  984. synapse/storage/schema/state/full_schemas/72/full.sql.sqlite +20 -0
  985. synapse/storage/types.py +185 -0
  986. synapse/storage/util/__init__.py +20 -0
  987. synapse/storage/util/id_generators.py +909 -0
  988. synapse/storage/util/partial_state_events_tracker.py +194 -0
  989. synapse/storage/util/sequence.py +315 -0
  990. synapse/streams/__init__.py +43 -0
  991. synapse/streams/config.py +92 -0
  992. synapse/streams/events.py +203 -0
  993. synapse/synapse_rust/__init__.pyi +3 -0
  994. synapse/synapse_rust/acl.pyi +20 -0
  995. synapse/synapse_rust/events.pyi +136 -0
  996. synapse/synapse_rust/http_client.pyi +32 -0
  997. synapse/synapse_rust/push.pyi +86 -0
  998. synapse/synapse_rust/rendezvous.pyi +30 -0
  999. synapse/synapse_rust/segmenter.pyi +1 -0
  1000. synapse/synapse_rust.abi3.so +0 -0
  1001. synapse/types/__init__.py +1600 -0
  1002. synapse/types/handlers/__init__.py +93 -0
  1003. synapse/types/handlers/policy_server.py +16 -0
  1004. synapse/types/handlers/sliding_sync.py +909 -0
  1005. synapse/types/rest/__init__.py +25 -0
  1006. synapse/types/rest/client/__init__.py +415 -0
  1007. synapse/types/state.py +635 -0
  1008. synapse/types/storage/__init__.py +66 -0
  1009. synapse/util/__init__.py +170 -0
  1010. synapse/util/async_helpers.py +1067 -0
  1011. synapse/util/batching_queue.py +202 -0
  1012. synapse/util/caches/__init__.py +300 -0
  1013. synapse/util/caches/cached_call.py +143 -0
  1014. synapse/util/caches/deferred_cache.py +530 -0
  1015. synapse/util/caches/descriptors.py +694 -0
  1016. synapse/util/caches/dictionary_cache.py +350 -0
  1017. synapse/util/caches/expiringcache.py +251 -0
  1018. synapse/util/caches/lrucache.py +977 -0
  1019. synapse/util/caches/response_cache.py +323 -0
  1020. synapse/util/caches/stream_change_cache.py +370 -0
  1021. synapse/util/caches/treecache.py +189 -0
  1022. synapse/util/caches/ttlcache.py +197 -0
  1023. synapse/util/cancellation.py +63 -0
  1024. synapse/util/check_dependencies.py +335 -0
  1025. synapse/util/clock.py +500 -0
  1026. synapse/util/constants.py +22 -0
  1027. synapse/util/daemonize.py +165 -0
  1028. synapse/util/distributor.py +159 -0
  1029. synapse/util/events.py +134 -0
  1030. synapse/util/file_consumer.py +164 -0
  1031. synapse/util/frozenutils.py +57 -0
  1032. synapse/util/gai_resolver.py +180 -0
  1033. synapse/util/hash.py +38 -0
  1034. synapse/util/httpresourcetree.py +108 -0
  1035. synapse/util/iterutils.py +189 -0
  1036. synapse/util/json.py +56 -0
  1037. synapse/util/linked_list.py +156 -0
  1038. synapse/util/logcontext.py +46 -0
  1039. synapse/util/logformatter.py +28 -0
  1040. synapse/util/macaroons.py +325 -0
  1041. synapse/util/manhole.py +191 -0
  1042. synapse/util/metrics.py +340 -0
  1043. synapse/util/module_loader.py +116 -0
  1044. synapse/util/msisdn.py +51 -0
  1045. synapse/util/patch_inline_callbacks.py +250 -0
  1046. synapse/util/pydantic_models.py +56 -0
  1047. synapse/util/ratelimitutils.py +420 -0
  1048. synapse/util/retryutils.py +339 -0
  1049. synapse/util/rlimit.py +42 -0
  1050. synapse/util/rust.py +134 -0
  1051. synapse/util/sentinel.py +21 -0
  1052. synapse/util/stringutils.py +293 -0
  1053. synapse/util/task_scheduler.py +493 -0
  1054. synapse/util/templates.py +126 -0
  1055. synapse/util/threepids.py +123 -0
  1056. synapse/util/wheel_timer.py +112 -0
  1057. synapse/visibility.py +836 -0
@@ -0,0 +1,2266 @@
1
+ #
2
+ # This file is licensed under the Affero General Public License (AGPL) version 3.
3
+ #
4
+ # Copyright (C) 2023 New Vector, Ltd
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as
8
+ # published by the Free Software Foundation, either version 3 of the
9
+ # License, or (at your option) any later version.
10
+ #
11
+ # See the GNU Affero General Public License for more details:
12
+ # <https://www.gnu.org/licenses/agpl-3.0.html>.
13
+ #
14
+
15
+
16
+ import logging
17
+ from itertools import chain
18
+ from typing import (
19
+ TYPE_CHECKING,
20
+ AbstractSet,
21
+ Literal,
22
+ Mapping,
23
+ MutableMapping,
24
+ Optional,
25
+ Union,
26
+ cast,
27
+ )
28
+
29
+ import attr
30
+ from immutabledict import immutabledict
31
+ from typing_extensions import assert_never
32
+
33
+ from synapse.api.constants import (
34
+ AccountDataTypes,
35
+ EventContentFields,
36
+ EventTypes,
37
+ Membership,
38
+ )
39
+ from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
40
+ from synapse.events import StrippedStateEvent
41
+ from synapse.events.utils import parse_stripped_state_event
42
+ from synapse.logging.opentracing import start_active_span, trace
43
+ from synapse.storage.databases.main.state import (
44
+ ROOM_UNKNOWN_SENTINEL,
45
+ Sentinel as StateSentinel,
46
+ )
47
+ from synapse.storage.databases.main.stream import CurrentStateDeltaMembership
48
+ from synapse.storage.invite_rule import InviteRule
49
+ from synapse.storage.roommember import (
50
+ RoomsForUser,
51
+ RoomsForUserSlidingSync,
52
+ RoomsForUserStateReset,
53
+ )
54
+ from synapse.types import (
55
+ MutableStateMap,
56
+ RoomStreamToken,
57
+ StateMap,
58
+ StrCollection,
59
+ StreamKeyType,
60
+ StreamToken,
61
+ UserID,
62
+ )
63
+ from synapse.types.handlers.sliding_sync import (
64
+ HaveSentRoomFlag,
65
+ OperationType,
66
+ PerConnectionState,
67
+ RoomSyncConfig,
68
+ SlidingSyncConfig,
69
+ SlidingSyncResult,
70
+ )
71
+ from synapse.types.state import StateFilter
72
+ from synapse.util import MutableOverlayMapping
73
+ from synapse.util.sentinel import Sentinel
74
+
75
+ if TYPE_CHECKING:
76
+ from synapse.server import HomeServer
77
+
78
+
79
+ logger = logging.getLogger(__name__)
80
+
81
+
82
+ # Helper definition for the types that we might return. We do this to avoid
83
+ # copying data between types (which can be expensive for many rooms).
84
+ RoomsForUserType = Union[RoomsForUserStateReset, RoomsForUser, RoomsForUserSlidingSync]
85
+
86
+
87
+ @attr.s(auto_attribs=True, slots=True, frozen=True)
88
+ class SlidingSyncInterestedRooms:
89
+ """The set of rooms and metadata a client is interested in based on their
90
+ sliding sync request.
91
+
92
+ Returned by `compute_interested_rooms`.
93
+
94
+ Attributes:
95
+ lists: A mapping from list name to the list result for the response
96
+ relevant_room_map: A map from rooms that match the sync request to
97
+ their room sync config.
98
+ relevant_rooms_to_send_map: Subset of `relevant_room_map` that
99
+ includes the rooms that *may* have relevant updates. Rooms not
100
+ in this map will definitely not have room updates (though
101
+ extensions may have updates in these rooms).
102
+ newly_joined_rooms: The set of rooms that were joined in the token range
103
+ and the user is still joined to at the end of this range.
104
+ newly_left_rooms: The set of rooms that we left in the token range
105
+ and are still "leave" at the end of this range.
106
+ dm_room_ids: The set of rooms the user consider as direct-message (DM) rooms
107
+ """
108
+
109
+ lists: Mapping[str, SlidingSyncResult.SlidingWindowList]
110
+ relevant_room_map: Mapping[str, RoomSyncConfig]
111
+ relevant_rooms_to_send_map: Mapping[str, RoomSyncConfig]
112
+ all_rooms: set[str]
113
+ room_membership_for_user_map: Mapping[str, RoomsForUserType]
114
+
115
+ newly_joined_rooms: AbstractSet[str]
116
+ newly_left_rooms: AbstractSet[str]
117
+ dm_room_ids: AbstractSet[str]
118
+
119
+ @staticmethod
120
+ def empty() -> "SlidingSyncInterestedRooms":
121
+ return SlidingSyncInterestedRooms(
122
+ lists={},
123
+ relevant_room_map={},
124
+ relevant_rooms_to_send_map={},
125
+ all_rooms=set(),
126
+ room_membership_for_user_map={},
127
+ newly_joined_rooms=set(),
128
+ newly_left_rooms=set(),
129
+ dm_room_ids=set(),
130
+ )
131
+
132
+
133
+ def filter_membership_for_sync(
134
+ *,
135
+ user_id: str,
136
+ room_membership_for_user: RoomsForUserType,
137
+ newly_left: bool,
138
+ ) -> bool:
139
+ """
140
+ Returns True if the membership event should be included in the sync response,
141
+ otherwise False.
142
+
143
+ Attributes:
144
+ user_id: The user ID that the membership applies to
145
+ room_membership_for_user: Membership information for the user in the room
146
+ """
147
+
148
+ membership = room_membership_for_user.membership
149
+ sender = room_membership_for_user.sender
150
+
151
+ # We want to allow everything except rooms the user has left unless `newly_left`
152
+ # because we want everything that's *still* relevant to the user. We include
153
+ # `newly_left` rooms because the last event that the user should see is their own
154
+ # leave event.
155
+ #
156
+ # A leave != kick. This logic includes kicks (leave events where the sender is not
157
+ # the same user).
158
+ #
159
+ # When `sender=None`, it means that a state reset happened that removed the user
160
+ # from the room without a corresponding leave event. We can just remove the rooms
161
+ # since they are no longer relevant to the user but will still appear if they are
162
+ # `newly_left`.
163
+ return (
164
+ # Anything except leave events
165
+ membership != Membership.LEAVE
166
+ # Unless...
167
+ or newly_left
168
+ # Allow kicks
169
+ or (membership == Membership.LEAVE and sender not in (user_id, None))
170
+ )
171
+
172
+
173
+ class SlidingSyncRoomLists:
174
+ """Handles calculating the room lists from sliding sync requests"""
175
+
176
+ def __init__(self, hs: "HomeServer"):
177
+ self.store = hs.get_datastores().main
178
+ self.storage_controllers = hs.get_storage_controllers()
179
+ self.rooms_to_exclude_globally = hs.config.server.rooms_to_exclude_from_sync
180
+ self.is_mine_id = hs.is_mine_id
181
+
182
+ async def compute_interested_rooms(
183
+ self,
184
+ sync_config: SlidingSyncConfig,
185
+ previous_connection_state: "PerConnectionState",
186
+ to_token: StreamToken,
187
+ from_token: Optional[StreamToken],
188
+ ) -> SlidingSyncInterestedRooms:
189
+ """Fetch the set of rooms that match the request"""
190
+ has_lists = sync_config.lists is not None and len(sync_config.lists) > 0
191
+ has_room_subscriptions = (
192
+ sync_config.room_subscriptions is not None
193
+ and len(sync_config.room_subscriptions) > 0
194
+ )
195
+
196
+ if not has_lists and not has_room_subscriptions:
197
+ return SlidingSyncInterestedRooms.empty()
198
+
199
+ if await self.store.have_finished_sliding_sync_background_jobs():
200
+ return await self._compute_interested_rooms_new_tables(
201
+ sync_config=sync_config,
202
+ previous_connection_state=previous_connection_state,
203
+ to_token=to_token,
204
+ from_token=from_token,
205
+ )
206
+ else:
207
+ # FIXME: This can be removed once we bump `SCHEMA_COMPAT_VERSION` and run the
208
+ # foreground update for
209
+ # `sliding_sync_joined_rooms`/`sliding_sync_membership_snapshots` (tracked by
210
+ # https://github.com/element-hq/synapse/issues/17623)
211
+ return await self._compute_interested_rooms_fallback(
212
+ sync_config=sync_config,
213
+ previous_connection_state=previous_connection_state,
214
+ to_token=to_token,
215
+ from_token=from_token,
216
+ )
217
+
218
+ @trace
219
+ async def _compute_interested_rooms_new_tables(
220
+ self,
221
+ sync_config: SlidingSyncConfig,
222
+ previous_connection_state: "PerConnectionState",
223
+ to_token: StreamToken,
224
+ from_token: Optional[StreamToken],
225
+ ) -> SlidingSyncInterestedRooms:
226
+ """Implementation of `compute_interested_rooms` using new sliding sync db tables."""
227
+ user_id = sync_config.user.to_string()
228
+
229
+ # Assemble sliding window lists
230
+ lists: dict[str, SlidingSyncResult.SlidingWindowList] = {}
231
+ # Keep track of the rooms that we can display and need to fetch more info about
232
+ relevant_room_map: dict[str, RoomSyncConfig] = {}
233
+ # The set of room IDs of all rooms that could appear in any list. These
234
+ # include rooms that are outside the list ranges.
235
+ all_rooms: set[str] = set()
236
+
237
+ # Note: this won't include rooms the user has left themselves. We add back
238
+ # `newly_left` rooms below. This is more efficient than fetching all rooms and
239
+ # then filtering out the old left rooms.
240
+ room_membership_for_user_map: MutableMapping[str, RoomsForUserSlidingSync] = (
241
+ MutableOverlayMapping(
242
+ await self.store.get_sliding_sync_rooms_for_user_from_membership_snapshots(
243
+ user_id
244
+ )
245
+ )
246
+ )
247
+ # To play nice with the rewind logic below, we need to go fetch the rooms the
248
+ # user has left themselves but only if it changed after the `to_token`.
249
+ #
250
+ # If a leave happens *after* the token range, we may have still been joined (or
251
+ # any non-self-leave which is relevant to sync) to the room before so we need to
252
+ # include it in the list of potentially relevant rooms and apply our rewind
253
+ # logic (outside of this function) to see if it's actually relevant.
254
+ #
255
+ # We do this separately from
256
+ # `get_sliding_sync_rooms_for_user_from_membership_snapshots` as those results
257
+ # are cached and the `to_token` isn't very cache friendly (people are constantly
258
+ # requesting with new tokens) so we separate it out here.
259
+ self_leave_room_membership_for_user_map = (
260
+ await self.store.get_sliding_sync_self_leave_rooms_after_to_token(
261
+ user_id, to_token
262
+ )
263
+ )
264
+ if self_leave_room_membership_for_user_map:
265
+ room_membership_for_user_map.update(self_leave_room_membership_for_user_map)
266
+
267
+ # Remove invites from ignored users
268
+ ignored_users = await self.store.ignored_users(user_id)
269
+ invite_config = await self.store.get_invite_config_for_user(user_id)
270
+ if ignored_users:
271
+ # Make a copy so we don't run into an error: `dictionary changed size during
272
+ # iteration`, when we remove items
273
+ for room_id in list(room_membership_for_user_map.keys()):
274
+ room_for_user_sliding_sync = room_membership_for_user_map[room_id]
275
+ if (
276
+ room_for_user_sliding_sync.membership == Membership.INVITE
277
+ and room_for_user_sliding_sync.sender
278
+ and (
279
+ room_for_user_sliding_sync.sender in ignored_users
280
+ or invite_config.get_invite_rule(
281
+ room_for_user_sliding_sync.sender
282
+ )
283
+ == InviteRule.IGNORE
284
+ )
285
+ ):
286
+ room_membership_for_user_map.pop(room_id, None)
287
+
288
+ (
289
+ newly_joined_room_ids,
290
+ newly_left_room_map,
291
+ ) = await self._get_newly_joined_and_left_rooms(
292
+ user_id, from_token=from_token, to_token=to_token
293
+ )
294
+
295
+ changes = await self._get_rewind_changes_to_current_membership_to_token(
296
+ sync_config.user, room_membership_for_user_map, to_token=to_token
297
+ )
298
+ if changes:
299
+ for room_id, change in changes.items():
300
+ if change is None:
301
+ # Remove rooms that the user joined after the `to_token`
302
+ room_membership_for_user_map.pop(room_id, None)
303
+ continue
304
+
305
+ existing_room = room_membership_for_user_map.get(room_id)
306
+ if existing_room is not None:
307
+ # Update room membership events to the point in time of the `to_token`
308
+ room_for_user = RoomsForUserSlidingSync(
309
+ room_id=room_id,
310
+ sender=change.sender,
311
+ membership=change.membership,
312
+ event_id=change.event_id,
313
+ event_pos=change.event_pos,
314
+ room_version_id=change.room_version_id,
315
+ # We keep the state of the room though
316
+ has_known_state=existing_room.has_known_state,
317
+ room_type=existing_room.room_type,
318
+ is_encrypted=existing_room.is_encrypted,
319
+ )
320
+ if filter_membership_for_sync(
321
+ user_id=user_id,
322
+ room_membership_for_user=room_for_user,
323
+ newly_left=room_id in newly_left_room_map,
324
+ ):
325
+ room_membership_for_user_map[room_id] = room_for_user
326
+ else:
327
+ room_membership_for_user_map.pop(room_id, None)
328
+
329
+ # Add back `newly_left` rooms (rooms left in the from -> to token range).
330
+ #
331
+ # We do this because `get_sliding_sync_rooms_for_user_from_membership_snapshots(...)` doesn't include
332
+ # rooms that the user left themselves as it's more efficient to add them back
333
+ # here than to fetch all rooms and then filter out the old left rooms. The user
334
+ # only leaves a room once in a blue moon so this barely needs to run.
335
+ #
336
+ missing_newly_left_rooms = (
337
+ newly_left_room_map.keys() - room_membership_for_user_map.keys()
338
+ )
339
+ if missing_newly_left_rooms:
340
+ for room_id in missing_newly_left_rooms:
341
+ newly_left_room_for_user = newly_left_room_map[room_id]
342
+ # This should be a given
343
+ assert newly_left_room_for_user.membership == Membership.LEAVE
344
+
345
+ # Add back `newly_left` rooms
346
+ #
347
+ # Check for membership and state in the Sliding Sync tables as it's just
348
+ # another membership
349
+ newly_left_room_for_user_sliding_sync = (
350
+ await self.store.get_sliding_sync_room_for_user(user_id, room_id)
351
+ )
352
+ # If the membership exists, it's just a normal user left the room on
353
+ # their own
354
+ if newly_left_room_for_user_sliding_sync is not None:
355
+ if filter_membership_for_sync(
356
+ user_id=user_id,
357
+ room_membership_for_user=newly_left_room_for_user_sliding_sync,
358
+ newly_left=room_id in newly_left_room_map,
359
+ ):
360
+ room_membership_for_user_map[room_id] = (
361
+ newly_left_room_for_user_sliding_sync
362
+ )
363
+ else:
364
+ room_membership_for_user_map.pop(room_id, None)
365
+
366
+ change = changes.get(room_id)
367
+ if change is not None:
368
+ # Update room membership events to the point in time of the `to_token`
369
+ room_for_user = RoomsForUserSlidingSync(
370
+ room_id=room_id,
371
+ sender=change.sender,
372
+ membership=change.membership,
373
+ event_id=change.event_id,
374
+ event_pos=change.event_pos,
375
+ room_version_id=change.room_version_id,
376
+ # We keep the state of the room though
377
+ has_known_state=newly_left_room_for_user_sliding_sync.has_known_state,
378
+ room_type=newly_left_room_for_user_sliding_sync.room_type,
379
+ is_encrypted=newly_left_room_for_user_sliding_sync.is_encrypted,
380
+ )
381
+ if filter_membership_for_sync(
382
+ user_id=user_id,
383
+ room_membership_for_user=room_for_user,
384
+ newly_left=room_id in newly_left_room_map,
385
+ ):
386
+ room_membership_for_user_map[room_id] = room_for_user
387
+ else:
388
+ room_membership_for_user_map.pop(room_id, None)
389
+
390
+ # If we are `newly_left` from the room but can't find any membership,
391
+ # then we have been "state reset" out of the room
392
+ else:
393
+ # Get the state at the time. We can't read from the Sliding Sync
394
+ # tables because the user has no membership in the room according to
395
+ # the state (thanks to the state reset).
396
+ #
397
+ # Note: `room_type` never changes, so we can just get current room
398
+ # type
399
+ room_type = await self.store.get_room_type(room_id)
400
+ has_known_state = room_type is not ROOM_UNKNOWN_SENTINEL
401
+ if isinstance(room_type, StateSentinel):
402
+ room_type = None
403
+
404
+ # Get the encryption status at the time of the token
405
+ is_encrypted = await self.get_is_encrypted_for_room_at_token(
406
+ room_id,
407
+ newly_left_room_for_user.event_pos.to_room_stream_token(),
408
+ )
409
+
410
+ room_for_user = RoomsForUserSlidingSync(
411
+ room_id=room_id,
412
+ sender=newly_left_room_for_user.sender,
413
+ membership=newly_left_room_for_user.membership,
414
+ event_id=newly_left_room_for_user.event_id,
415
+ event_pos=newly_left_room_for_user.event_pos,
416
+ room_version_id=newly_left_room_for_user.room_version_id,
417
+ has_known_state=has_known_state,
418
+ room_type=room_type,
419
+ is_encrypted=is_encrypted,
420
+ )
421
+ if filter_membership_for_sync(
422
+ user_id=user_id,
423
+ room_membership_for_user=room_for_user,
424
+ newly_left=room_id in newly_left_room_map,
425
+ ):
426
+ room_membership_for_user_map[room_id] = room_for_user
427
+ else:
428
+ room_membership_for_user_map.pop(room_id, None)
429
+
430
+ # Remove any rooms that we globally exclude from sync.
431
+ for room_id in self.rooms_to_exclude_globally:
432
+ room_membership_for_user_map.pop(room_id, None)
433
+
434
+ dm_room_ids = await self._get_dm_rooms_for_user(user_id)
435
+
436
+ if sync_config.lists:
437
+ sync_room_map = room_membership_for_user_map
438
+ with start_active_span("assemble_sliding_window_lists"):
439
+ for list_key, list_config in sync_config.lists.items():
440
+ # Apply filters
441
+ filtered_sync_room_map = sync_room_map
442
+ if list_config.filters is not None:
443
+ filtered_sync_room_map = await self.filter_rooms_using_tables(
444
+ user_id,
445
+ sync_room_map,
446
+ previous_connection_state,
447
+ list_config.filters,
448
+ to_token,
449
+ dm_room_ids,
450
+ )
451
+
452
+ # Find which rooms are partially stated and may need to be filtered out
453
+ # depending on the `required_state` requested (see below).
454
+ partial_state_rooms = await self.store.get_partial_rooms()
455
+
456
+ # Since creating the `RoomSyncConfig` takes some work, let's just do it
457
+ # once.
458
+ room_sync_config = RoomSyncConfig.from_room_config(list_config)
459
+
460
+ # Exclude partially-stated rooms if we must wait for the room to be
461
+ # fully-stated
462
+ if room_sync_config.must_await_full_state(self.is_mine_id):
463
+ filtered_sync_room_map = {
464
+ room_id: room
465
+ for room_id, room in filtered_sync_room_map.items()
466
+ if room_id not in partial_state_rooms
467
+ }
468
+
469
+ all_rooms.update(filtered_sync_room_map)
470
+
471
+ ops: list[SlidingSyncResult.SlidingWindowList.Operation] = []
472
+
473
+ if list_config.ranges:
474
+ # Optimization: If we are asking for the full range, we don't
475
+ # need to sort the list.
476
+ if (
477
+ # We're looking for a single range that covers the entire list
478
+ len(list_config.ranges) == 1
479
+ # Range starts at 0
480
+ and list_config.ranges[0][0] == 0
481
+ # And the range extends to the end of the list or more. Each
482
+ # side is inclusive.
483
+ and list_config.ranges[0][1]
484
+ >= len(filtered_sync_room_map) - 1
485
+ ):
486
+ sorted_room_info: list[RoomsForUserType] = list(
487
+ filtered_sync_room_map.values()
488
+ )
489
+ else:
490
+ # Sort the list
491
+ sorted_room_info = await self.sort_rooms(
492
+ # Cast is safe because RoomsForUserSlidingSync is part
493
+ # of the `RoomsForUserType` union. Why can't it detect this?
494
+ cast(
495
+ dict[str, RoomsForUserType], filtered_sync_room_map
496
+ ),
497
+ to_token,
498
+ # We only need to sort the rooms up to the end
499
+ # of the largest range. Both sides of range are
500
+ # inclusive so we `+ 1`.
501
+ limit=max(range[1] + 1 for range in list_config.ranges),
502
+ )
503
+
504
+ for range in list_config.ranges:
505
+ room_ids_in_list: list[str] = []
506
+
507
+ # We're going to loop through the sorted list of rooms starting
508
+ # at the range start index and keep adding rooms until we fill
509
+ # up the range or run out of rooms.
510
+ #
511
+ # Both sides of range are inclusive so we `+ 1`
512
+ max_num_rooms = range[1] - range[0] + 1
513
+ for room_membership in sorted_room_info[range[0] :]:
514
+ room_id = room_membership.room_id
515
+
516
+ if len(room_ids_in_list) >= max_num_rooms:
517
+ break
518
+
519
+ # Take the superset of the `RoomSyncConfig` for each room.
520
+ #
521
+ # Update our `relevant_room_map` with the room we're going
522
+ # to display and need to fetch more info about.
523
+ existing_room_sync_config = relevant_room_map.get(
524
+ room_id
525
+ )
526
+ if existing_room_sync_config is not None:
527
+ room_sync_config = existing_room_sync_config.combine_room_sync_config(
528
+ room_sync_config
529
+ )
530
+
531
+ relevant_room_map[room_id] = room_sync_config
532
+
533
+ room_ids_in_list.append(room_id)
534
+
535
+ ops.append(
536
+ SlidingSyncResult.SlidingWindowList.Operation(
537
+ op=OperationType.SYNC,
538
+ range=range,
539
+ room_ids=room_ids_in_list,
540
+ )
541
+ )
542
+
543
+ lists[list_key] = SlidingSyncResult.SlidingWindowList(
544
+ count=len(filtered_sync_room_map),
545
+ ops=ops,
546
+ )
547
+
548
+ if sync_config.room_subscriptions:
549
+ with start_active_span("assemble_room_subscriptions"):
550
+ # Find which rooms are partially stated and may need to be filtered out
551
+ # depending on the `required_state` requested (see below).
552
+ partial_state_rooms = await self.store.get_partial_rooms()
553
+
554
+ # Fetch any rooms that we have not already fetched from the database.
555
+ subscription_sliding_sync_rooms = (
556
+ await self.store.get_sliding_sync_room_for_user_batch(
557
+ user_id,
558
+ sync_config.room_subscriptions.keys()
559
+ - room_membership_for_user_map.keys(),
560
+ )
561
+ )
562
+ room_membership_for_user_map.update(subscription_sliding_sync_rooms)
563
+
564
+ for (
565
+ room_id,
566
+ room_subscription,
567
+ ) in sync_config.room_subscriptions.items():
568
+ # Check if we have a membership for the room, but didn't pull it out
569
+ # above. This could be e.g. a leave that we don't pull out by
570
+ # default.
571
+ current_room_entry = room_membership_for_user_map.get(room_id)
572
+ if not current_room_entry:
573
+ # TODO: Handle rooms the user isn't in.
574
+ continue
575
+
576
+ all_rooms.add(room_id)
577
+
578
+ # Take the superset of the `RoomSyncConfig` for each room.
579
+ room_sync_config = RoomSyncConfig.from_room_config(
580
+ room_subscription
581
+ )
582
+
583
+ # Exclude partially-stated rooms if we must wait for the room to be
584
+ # fully-stated
585
+ if room_sync_config.must_await_full_state(self.is_mine_id):
586
+ if room_id in partial_state_rooms:
587
+ continue
588
+
589
+ # Update our `relevant_room_map` with the room we're going to display
590
+ # and need to fetch more info about.
591
+ existing_room_sync_config = relevant_room_map.get(room_id)
592
+ if existing_room_sync_config is not None:
593
+ room_sync_config = (
594
+ existing_room_sync_config.combine_room_sync_config(
595
+ room_sync_config
596
+ )
597
+ )
598
+
599
+ relevant_room_map[room_id] = room_sync_config
600
+
601
+ # Filtered subset of `relevant_room_map` for rooms that may have updates
602
+ # (in the event stream)
603
+ relevant_rooms_to_send_map = await self._filter_relevant_rooms_to_send(
604
+ previous_connection_state, from_token, relevant_room_map
605
+ )
606
+
607
+ return SlidingSyncInterestedRooms(
608
+ lists=lists,
609
+ relevant_room_map=relevant_room_map,
610
+ relevant_rooms_to_send_map=relevant_rooms_to_send_map,
611
+ all_rooms=all_rooms,
612
+ room_membership_for_user_map=room_membership_for_user_map,
613
+ newly_joined_rooms=newly_joined_room_ids,
614
+ newly_left_rooms=set(newly_left_room_map),
615
+ dm_room_ids=dm_room_ids,
616
+ )
617
+
618
+ async def _compute_interested_rooms_fallback(
619
+ self,
620
+ sync_config: SlidingSyncConfig,
621
+ previous_connection_state: "PerConnectionState",
622
+ to_token: StreamToken,
623
+ from_token: Optional[StreamToken],
624
+ ) -> SlidingSyncInterestedRooms:
625
+ """Fallback code when the database background updates haven't completed yet."""
626
+
627
+ (
628
+ room_membership_for_user_map,
629
+ newly_joined_room_ids,
630
+ newly_left_room_ids,
631
+ ) = await self.get_room_membership_for_user_at_to_token(
632
+ sync_config.user, to_token, from_token
633
+ )
634
+
635
+ dm_room_ids = await self._get_dm_rooms_for_user(sync_config.user.to_string())
636
+
637
+ # Assemble sliding window lists
638
+ lists: dict[str, SlidingSyncResult.SlidingWindowList] = {}
639
+ # Keep track of the rooms that we can display and need to fetch more info about
640
+ relevant_room_map: dict[str, RoomSyncConfig] = {}
641
+ # The set of room IDs of all rooms that could appear in any list. These
642
+ # include rooms that are outside the list ranges.
643
+ all_rooms: set[str] = set()
644
+
645
+ if sync_config.lists:
646
+ with start_active_span("assemble_sliding_window_lists"):
647
+ sync_room_map = await self.filter_rooms_relevant_for_sync(
648
+ user=sync_config.user,
649
+ room_membership_for_user_map=room_membership_for_user_map,
650
+ newly_left_room_ids=newly_left_room_ids,
651
+ )
652
+
653
+ for list_key, list_config in sync_config.lists.items():
654
+ # Apply filters
655
+ filtered_sync_room_map = sync_room_map
656
+ if list_config.filters is not None:
657
+ filtered_sync_room_map = await self.filter_rooms(
658
+ sync_config.user,
659
+ sync_room_map,
660
+ previous_connection_state,
661
+ list_config.filters,
662
+ to_token,
663
+ dm_room_ids,
664
+ )
665
+
666
+ # Find which rooms are partially stated and may need to be filtered out
667
+ # depending on the `required_state` requested (see below).
668
+ partial_state_rooms = await self.store.get_partial_rooms()
669
+
670
+ # Since creating the `RoomSyncConfig` takes some work, let's just do it
671
+ # once.
672
+ room_sync_config = RoomSyncConfig.from_room_config(list_config)
673
+
674
+ # Exclude partially-stated rooms if we must wait for the room to be
675
+ # fully-stated
676
+ if room_sync_config.must_await_full_state(self.is_mine_id):
677
+ filtered_sync_room_map = {
678
+ room_id: room
679
+ for room_id, room in filtered_sync_room_map.items()
680
+ if room_id not in partial_state_rooms
681
+ }
682
+
683
+ all_rooms.update(filtered_sync_room_map)
684
+
685
+ # Sort the list
686
+ sorted_room_info = await self.sort_rooms(
687
+ filtered_sync_room_map, to_token
688
+ )
689
+
690
+ ops: list[SlidingSyncResult.SlidingWindowList.Operation] = []
691
+ if list_config.ranges:
692
+ for range in list_config.ranges:
693
+ room_ids_in_list: list[str] = []
694
+
695
+ # We're going to loop through the sorted list of rooms starting
696
+ # at the range start index and keep adding rooms until we fill
697
+ # up the range or run out of rooms.
698
+ #
699
+ # Both sides of range are inclusive so we `+ 1`
700
+ max_num_rooms = range[1] - range[0] + 1
701
+ for room_membership in sorted_room_info[range[0] :]:
702
+ room_id = room_membership.room_id
703
+
704
+ if len(room_ids_in_list) >= max_num_rooms:
705
+ break
706
+
707
+ # Take the superset of the `RoomSyncConfig` for each room.
708
+ #
709
+ # Update our `relevant_room_map` with the room we're going
710
+ # to display and need to fetch more info about.
711
+ existing_room_sync_config = relevant_room_map.get(
712
+ room_id
713
+ )
714
+ if existing_room_sync_config is not None:
715
+ room_sync_config = existing_room_sync_config.combine_room_sync_config(
716
+ room_sync_config
717
+ )
718
+
719
+ relevant_room_map[room_id] = room_sync_config
720
+
721
+ room_ids_in_list.append(room_id)
722
+
723
+ ops.append(
724
+ SlidingSyncResult.SlidingWindowList.Operation(
725
+ op=OperationType.SYNC,
726
+ range=range,
727
+ room_ids=room_ids_in_list,
728
+ )
729
+ )
730
+
731
+ lists[list_key] = SlidingSyncResult.SlidingWindowList(
732
+ count=len(sorted_room_info),
733
+ ops=ops,
734
+ )
735
+
736
+ if sync_config.room_subscriptions:
737
+ with start_active_span("assemble_room_subscriptions"):
738
+ # Find which rooms are partially stated and may need to be filtered out
739
+ # depending on the `required_state` requested (see below).
740
+ partial_state_rooms = await self.store.get_partial_rooms()
741
+
742
+ for (
743
+ room_id,
744
+ room_subscription,
745
+ ) in sync_config.room_subscriptions.items():
746
+ room_membership_for_user_at_to_token = (
747
+ await self.check_room_subscription_allowed_for_user(
748
+ room_id=room_id,
749
+ room_membership_for_user_map=room_membership_for_user_map,
750
+ to_token=to_token,
751
+ )
752
+ )
753
+
754
+ # Skip this room if the user isn't allowed to see it
755
+ if not room_membership_for_user_at_to_token:
756
+ continue
757
+
758
+ all_rooms.add(room_id)
759
+
760
+ room_membership_for_user_map[room_id] = (
761
+ room_membership_for_user_at_to_token
762
+ )
763
+
764
+ # Take the superset of the `RoomSyncConfig` for each room.
765
+ room_sync_config = RoomSyncConfig.from_room_config(
766
+ room_subscription
767
+ )
768
+
769
+ # Exclude partially-stated rooms if we must wait for the room to be
770
+ # fully-stated
771
+ if room_sync_config.must_await_full_state(self.is_mine_id):
772
+ if room_id in partial_state_rooms:
773
+ continue
774
+
775
+ all_rooms.add(room_id)
776
+
777
+ # Update our `relevant_room_map` with the room we're going to display
778
+ # and need to fetch more info about.
779
+ existing_room_sync_config = relevant_room_map.get(room_id)
780
+ if existing_room_sync_config is not None:
781
+ room_sync_config = (
782
+ existing_room_sync_config.combine_room_sync_config(
783
+ room_sync_config
784
+ )
785
+ )
786
+
787
+ relevant_room_map[room_id] = room_sync_config
788
+
789
+ # Filtered subset of `relevant_room_map` for rooms that may have updates
790
+ # (in the event stream)
791
+ relevant_rooms_to_send_map = await self._filter_relevant_rooms_to_send(
792
+ previous_connection_state, from_token, relevant_room_map
793
+ )
794
+
795
+ return SlidingSyncInterestedRooms(
796
+ lists=lists,
797
+ relevant_room_map=relevant_room_map,
798
+ relevant_rooms_to_send_map=relevant_rooms_to_send_map,
799
+ all_rooms=all_rooms,
800
+ room_membership_for_user_map=room_membership_for_user_map,
801
+ newly_joined_rooms=newly_joined_room_ids,
802
+ newly_left_rooms=newly_left_room_ids,
803
+ dm_room_ids=dm_room_ids,
804
+ )
805
+
806
+ async def _filter_relevant_rooms_to_send(
807
+ self,
808
+ previous_connection_state: PerConnectionState,
809
+ from_token: Optional[StreamToken],
810
+ relevant_room_map: dict[str, RoomSyncConfig],
811
+ ) -> dict[str, RoomSyncConfig]:
812
+ """Filters the `relevant_room_map` down to those rooms that may have
813
+ updates we need to fetch and return."""
814
+
815
+ # Filtered subset of `relevant_room_map` for rooms that may have updates
816
+ # (in the event stream)
817
+ relevant_rooms_to_send_map: dict[str, RoomSyncConfig] = relevant_room_map
818
+ if relevant_room_map:
819
+ with start_active_span("filter_relevant_rooms_to_send"):
820
+ if from_token:
821
+ rooms_should_send = set()
822
+
823
+ # First we check if there are rooms that match a list/room
824
+ # subscription and have updates we need to send (i.e. either because
825
+ # we haven't sent the room down, or we have but there are missing
826
+ # updates).
827
+ for room_id, room_config in relevant_room_map.items():
828
+ prev_room_sync_config = (
829
+ previous_connection_state.room_configs.get(room_id)
830
+ )
831
+ if prev_room_sync_config is not None:
832
+ # Always include rooms whose timeline limit has increased.
833
+ # (see the "XXX: Odd behavior" described below)
834
+ if (
835
+ prev_room_sync_config.timeline_limit
836
+ < room_config.timeline_limit
837
+ ):
838
+ rooms_should_send.add(room_id)
839
+ continue
840
+
841
+ status = previous_connection_state.rooms.have_sent_room(room_id)
842
+ if (
843
+ # The room was never sent down before so the client needs to know
844
+ # about it regardless of any updates.
845
+ status.status == HaveSentRoomFlag.NEVER
846
+ # `PREVIOUSLY` literally means the "room was sent down before *AND*
847
+ # there are updates we haven't sent down" so we already know this
848
+ # room has updates.
849
+ or status.status == HaveSentRoomFlag.PREVIOUSLY
850
+ ):
851
+ rooms_should_send.add(room_id)
852
+ elif status.status == HaveSentRoomFlag.LIVE:
853
+ # We know that we've sent all updates up until `from_token`,
854
+ # so we just need to check if there have been updates since
855
+ # then.
856
+ pass
857
+ else:
858
+ assert_never(status.status)
859
+
860
+ # We only need to check for new events since any state changes
861
+ # will also come down as new events.
862
+ rooms_that_have_updates = (
863
+ self.store.get_rooms_that_might_have_updates(
864
+ relevant_room_map.keys(), from_token.room_key
865
+ )
866
+ )
867
+ rooms_should_send.update(rooms_that_have_updates)
868
+ relevant_rooms_to_send_map = {
869
+ room_id: room_sync_config
870
+ for room_id, room_sync_config in relevant_room_map.items()
871
+ if room_id in rooms_should_send
872
+ }
873
+
874
+ return relevant_rooms_to_send_map
875
+
876
+ @trace
877
+ async def _get_rewind_changes_to_current_membership_to_token(
878
+ self,
879
+ user: UserID,
880
+ rooms_for_user: Mapping[str, RoomsForUserType],
881
+ to_token: StreamToken,
882
+ ) -> Mapping[str, Optional[RoomsForUser]]:
883
+ """
884
+ Takes the current set of rooms for a user (retrieved after the given
885
+ token), and returns the changes needed to "rewind" it to match the set of
886
+ memberships *at that token* (<= `to_token`).
887
+
888
+ Args:
889
+ user: User to fetch rooms for
890
+ rooms_for_user: The set of rooms for the user after the `to_token`.
891
+ to_token: The token to rewind to
892
+
893
+ Returns:
894
+ The changes to apply to rewind the the current memberships.
895
+ """
896
+ # If the user has never joined any rooms before, we can just return an empty list
897
+ if not rooms_for_user:
898
+ return {}
899
+
900
+ user_id = user.to_string()
901
+
902
+ # Get the `RoomStreamToken` that represents the spot we queried up to when we got
903
+ # our membership snapshot from `get_rooms_for_local_user_where_membership_is()`.
904
+ #
905
+ # First, we need to get the max stream_ordering of each event persister instance
906
+ # that we queried events from.
907
+ instance_to_max_stream_ordering_map: dict[str, int] = {}
908
+ for room_for_user in rooms_for_user.values():
909
+ instance_name = room_for_user.event_pos.instance_name
910
+ stream_ordering = room_for_user.event_pos.stream
911
+
912
+ current_instance_max_stream_ordering = (
913
+ instance_to_max_stream_ordering_map.get(instance_name)
914
+ )
915
+ if (
916
+ current_instance_max_stream_ordering is None
917
+ or stream_ordering > current_instance_max_stream_ordering
918
+ ):
919
+ instance_to_max_stream_ordering_map[instance_name] = stream_ordering
920
+
921
+ # Then assemble the `RoomStreamToken`
922
+ min_stream_pos = min(instance_to_max_stream_ordering_map.values())
923
+ membership_snapshot_token = RoomStreamToken(
924
+ # Minimum position in the `instance_map`
925
+ stream=min_stream_pos,
926
+ instance_map=immutabledict(
927
+ {
928
+ instance_name: stream_pos
929
+ for instance_name, stream_pos in instance_to_max_stream_ordering_map.items()
930
+ if stream_pos > min_stream_pos
931
+ }
932
+ ),
933
+ )
934
+
935
+ # Since we fetched the users room list at some point in time after the
936
+ # tokens, we need to revert/rewind some membership changes to match the point in
937
+ # time of the `to_token`. In particular, we need to make these fixups:
938
+ #
939
+ # - a) Remove rooms that the user joined after the `to_token`
940
+ # - b) Update room membership events to the point in time of the `to_token`
941
+
942
+ # Fetch membership changes that fall in the range from `to_token` up to
943
+ # `membership_snapshot_token`
944
+ #
945
+ # If our `to_token` is already the same or ahead of the latest room membership
946
+ # for the user, we don't need to do any "2)" fix-ups and can just straight-up
947
+ # use the room list from the snapshot as a base (nothing has changed)
948
+ current_state_delta_membership_changes_after_to_token = []
949
+ if not membership_snapshot_token.is_before_or_eq(to_token.room_key):
950
+ current_state_delta_membership_changes_after_to_token = (
951
+ await self.store.get_current_state_delta_membership_changes_for_user(
952
+ user_id,
953
+ from_key=to_token.room_key,
954
+ to_key=membership_snapshot_token,
955
+ excluded_room_ids=self.rooms_to_exclude_globally,
956
+ )
957
+ )
958
+
959
+ if not current_state_delta_membership_changes_after_to_token:
960
+ # There have been no membership changes, so we can early return.
961
+ return {}
962
+
963
+ # Otherwise we're about to make changes to `rooms_for_user`, so we turn
964
+ # it into a mutable dict.
965
+ changes: dict[str, Optional[RoomsForUser]] = {}
966
+
967
+ # Assemble a list of the first membership event after the `to_token` so we can
968
+ # step backward to the previous membership that would apply to the from/to
969
+ # range.
970
+ first_membership_change_by_room_id_after_to_token: dict[
971
+ str, CurrentStateDeltaMembership
972
+ ] = {}
973
+ for membership_change in current_state_delta_membership_changes_after_to_token:
974
+ # Only set if we haven't already set it
975
+ first_membership_change_by_room_id_after_to_token.setdefault(
976
+ membership_change.room_id, membership_change
977
+ )
978
+
979
+ # Since we fetched a snapshot of the users room list at some point in time after
980
+ # the from/to tokens, we need to revert/rewind some membership changes to match
981
+ # the point in time of the `to_token`.
982
+ for (
983
+ room_id,
984
+ first_membership_change_after_to_token,
985
+ ) in first_membership_change_by_room_id_after_to_token.items():
986
+ # 1a) Remove rooms that the user joined after the `to_token`
987
+ if first_membership_change_after_to_token.prev_event_id is None:
988
+ changes[room_id] = None
989
+ # 1b) 1c) From the first membership event after the `to_token`, step backward to the
990
+ # previous membership that would apply to the from/to range.
991
+ else:
992
+ # We don't expect these fields to be `None` if we have a `prev_event_id`
993
+ # but we're being defensive since it's possible that the prev event was
994
+ # culled from the database.
995
+ if (
996
+ first_membership_change_after_to_token.prev_event_pos is not None
997
+ and first_membership_change_after_to_token.prev_membership
998
+ is not None
999
+ and first_membership_change_after_to_token.prev_sender is not None
1000
+ ):
1001
+ # We need to know the room version ID, which we normally we
1002
+ # can get from the current membership, but if we don't have
1003
+ # that then we need to query the DB.
1004
+ current_membership = rooms_for_user.get(room_id)
1005
+ if current_membership is not None:
1006
+ room_version_id = current_membership.room_version_id
1007
+ else:
1008
+ room_version_id = await self.store.get_room_version_id(room_id)
1009
+
1010
+ changes[room_id] = RoomsForUser(
1011
+ room_id=room_id,
1012
+ event_id=first_membership_change_after_to_token.prev_event_id,
1013
+ event_pos=first_membership_change_after_to_token.prev_event_pos,
1014
+ membership=first_membership_change_after_to_token.prev_membership,
1015
+ sender=first_membership_change_after_to_token.prev_sender,
1016
+ room_version_id=room_version_id,
1017
+ )
1018
+ else:
1019
+ # If we can't find the previous membership event, we shouldn't
1020
+ # include the room in the sync response since we can't determine the
1021
+ # exact membership state and shouldn't rely on the current snapshot.
1022
+ changes[room_id] = None
1023
+
1024
+ return changes
1025
+
1026
+ @trace
1027
+ async def get_room_membership_for_user_at_to_token(
1028
+ self,
1029
+ user: UserID,
1030
+ to_token: StreamToken,
1031
+ from_token: Optional[StreamToken],
1032
+ ) -> tuple[dict[str, RoomsForUserType], AbstractSet[str], AbstractSet[str]]:
1033
+ """
1034
+ Fetch room IDs that the user has had membership in (the full room list including
1035
+ long-lost left rooms that will be filtered, sorted, and sliced).
1036
+
1037
+ We're looking for rooms where the user has had any sort of membership in the
1038
+ token range (> `from_token` and <= `to_token`)
1039
+
1040
+ In order for bans/kicks to not show up, you need to `/forget` those rooms. This
1041
+ doesn't modify the event itself though and only adds the `forgotten` flag to the
1042
+ `room_memberships` table in Synapse. There isn't a way to tell when a room was
1043
+ forgotten at the moment so we can't factor it into the token range.
1044
+
1045
+ Args:
1046
+ user: User to fetch rooms for
1047
+ to_token: The token to fetch rooms up to.
1048
+ from_token: The point in the stream to sync from.
1049
+
1050
+ Returns:
1051
+ A 3-tuple of:
1052
+ - A dictionary of room IDs that the user has had membership in along with
1053
+ membership information in that room at the time of `to_token`.
1054
+ - Set of newly joined rooms
1055
+ - Set of newly left rooms
1056
+ """
1057
+ user_id = user.to_string()
1058
+
1059
+ # First grab a current snapshot rooms for the user
1060
+ # (also handles forgotten rooms)
1061
+ room_for_user_list = await self.store.get_rooms_for_local_user_where_membership_is(
1062
+ user_id=user_id,
1063
+ # We want to fetch any kind of membership (joined and left rooms) in order
1064
+ # to get the `event_pos` of the latest room membership event for the
1065
+ # user.
1066
+ membership_list=Membership.LIST,
1067
+ excluded_rooms=self.rooms_to_exclude_globally,
1068
+ )
1069
+
1070
+ # We filter out unknown room versions before we try and load any
1071
+ # metadata about the room. They shouldn't go down sync anyway, and their
1072
+ # metadata may be in a broken state.
1073
+ room_for_user_list = [
1074
+ room_for_user
1075
+ for room_for_user in room_for_user_list
1076
+ if room_for_user.room_version_id in KNOWN_ROOM_VERSIONS
1077
+ ]
1078
+
1079
+ # Remove invites from ignored users
1080
+ ignored_users = await self.store.ignored_users(user_id)
1081
+ if ignored_users:
1082
+ room_for_user_list = [
1083
+ room_for_user
1084
+ for room_for_user in room_for_user_list
1085
+ if not (
1086
+ room_for_user.membership == Membership.INVITE
1087
+ and room_for_user.sender in ignored_users
1088
+ )
1089
+ ]
1090
+
1091
+ (
1092
+ newly_joined_room_ids,
1093
+ newly_left_room_map,
1094
+ ) = await self._get_newly_joined_and_left_rooms_fallback(
1095
+ user_id, to_token=to_token, from_token=from_token
1096
+ )
1097
+
1098
+ # If the user has never joined any rooms before, we can just return an empty
1099
+ # list. We also have to check the `newly_left_room_map` in case someone was
1100
+ # state reset out of all of the rooms they were in.
1101
+ if not room_for_user_list and not newly_left_room_map:
1102
+ return {}, set(), set()
1103
+
1104
+ # Since we fetched the users room list at some point in time after the
1105
+ # tokens, we need to revert/rewind some membership changes to match the point in
1106
+ # time of the `to_token`.
1107
+ rooms_for_user: dict[str, RoomsForUserType] = {
1108
+ room.room_id: room for room in room_for_user_list
1109
+ }
1110
+ changes = await self._get_rewind_changes_to_current_membership_to_token(
1111
+ user, rooms_for_user, to_token
1112
+ )
1113
+ for room_id, change_room_for_user in changes.items():
1114
+ if change_room_for_user is None:
1115
+ rooms_for_user.pop(room_id, None)
1116
+ else:
1117
+ rooms_for_user[room_id] = change_room_for_user
1118
+
1119
+ # Ensure we have entries for rooms that the user has been "state reset"
1120
+ # out of. These are rooms appear in the `newly_left_rooms` map but
1121
+ # aren't in the `rooms_for_user` map.
1122
+ for room_id, newly_left_room_for_user in newly_left_room_map.items():
1123
+ # If we already know about the room, it's not a state reset
1124
+ if room_id in rooms_for_user:
1125
+ continue
1126
+
1127
+ # This should be true if it's a state reset
1128
+ assert newly_left_room_for_user.membership is Membership.LEAVE
1129
+ assert newly_left_room_for_user.event_id is None
1130
+ assert newly_left_room_for_user.sender is None
1131
+
1132
+ rooms_for_user[room_id] = newly_left_room_for_user
1133
+
1134
+ return rooms_for_user, newly_joined_room_ids, set(newly_left_room_map)
1135
+
1136
+ @trace
1137
+ async def _get_newly_joined_and_left_rooms(
1138
+ self,
1139
+ user_id: str,
1140
+ to_token: StreamToken,
1141
+ from_token: Optional[StreamToken],
1142
+ ) -> tuple[AbstractSet[str], Mapping[str, RoomsForUserStateReset]]:
1143
+ """Fetch the sets of rooms that the user newly joined or left in the
1144
+ given token range.
1145
+
1146
+ Note: there may be rooms in the newly left rooms where the user was
1147
+ "state reset" out of the room, and so that room would not be part of the
1148
+ "current memberships" of the user.
1149
+
1150
+ Returns:
1151
+ A 2-tuple of newly joined room IDs and a map of newly_left room
1152
+ IDs to the `RoomsForUserStateReset` entry.
1153
+
1154
+ We're using `RoomsForUserStateReset` but that doesn't necessarily mean the
1155
+ user was state reset of the rooms. It's just that the `event_id`/`sender`
1156
+ are optional and we can't tell the difference between the server leaving the
1157
+ room when the user was the last person participating in the room and left or
1158
+ was state reset out of the room. To actually check for a state reset, you
1159
+ need to check if a membership still exists in the room.
1160
+ """
1161
+
1162
+ newly_joined_room_ids: set[str] = set()
1163
+ newly_left_room_map: dict[str, RoomsForUserStateReset] = {}
1164
+
1165
+ if not from_token:
1166
+ return newly_joined_room_ids, newly_left_room_map
1167
+
1168
+ changes = await self.store.get_sliding_sync_membership_changes(
1169
+ user_id,
1170
+ from_key=from_token.room_key,
1171
+ to_key=to_token.room_key,
1172
+ excluded_room_ids=set(self.rooms_to_exclude_globally),
1173
+ )
1174
+
1175
+ for room_id, entry in changes.items():
1176
+ if entry.membership == Membership.JOIN:
1177
+ newly_joined_room_ids.add(room_id)
1178
+ elif entry.membership == Membership.LEAVE:
1179
+ newly_left_room_map[room_id] = entry
1180
+
1181
+ return newly_joined_room_ids, newly_left_room_map
1182
+
1183
+ @trace
1184
+ async def _get_newly_joined_and_left_rooms_fallback(
1185
+ self,
1186
+ user_id: str,
1187
+ to_token: StreamToken,
1188
+ from_token: Optional[StreamToken],
1189
+ ) -> tuple[AbstractSet[str], Mapping[str, RoomsForUserStateReset]]:
1190
+ """Fetch the sets of rooms that the user newly joined or left in the
1191
+ given token range.
1192
+
1193
+ Note: there may be rooms in the newly left rooms where the user was
1194
+ "state reset" out of the room, and so that room would not be part of the
1195
+ "current memberships" of the user.
1196
+
1197
+ Returns:
1198
+ A 2-tuple of newly joined room IDs and a map of newly_left room
1199
+ IDs to the `RoomsForUserStateReset` entry.
1200
+
1201
+ We're using `RoomsForUserStateReset` but that doesn't necessarily mean the
1202
+ user was state reset of the rooms. It's just that the `event_id`/`sender`
1203
+ are optional and we can't tell the difference between the server leaving the
1204
+ room when the user was the last person participating in the room and left or
1205
+ was state reset out of the room. To actually check for a state reset, you
1206
+ need to check if a membership still exists in the room.
1207
+ """
1208
+ newly_joined_room_ids: set[str] = set()
1209
+ newly_left_room_map: dict[str, RoomsForUserStateReset] = {}
1210
+
1211
+ # We need to figure out the
1212
+ #
1213
+ # - 1) Figure out which rooms are `newly_left` rooms (> `from_token` and <= `to_token`)
1214
+ # - 2) Figure out which rooms are `newly_joined` (> `from_token` and <= `to_token`)
1215
+
1216
+ # 1) Fetch membership changes that fall in the range from `from_token` up to `to_token`
1217
+ current_state_delta_membership_changes_in_from_to_range = []
1218
+ if from_token:
1219
+ current_state_delta_membership_changes_in_from_to_range = (
1220
+ await self.store.get_current_state_delta_membership_changes_for_user(
1221
+ user_id,
1222
+ from_key=from_token.room_key,
1223
+ to_key=to_token.room_key,
1224
+ excluded_room_ids=self.rooms_to_exclude_globally,
1225
+ )
1226
+ )
1227
+
1228
+ # 1) Assemble a list of the last membership events in some given ranges. Someone
1229
+ # could have left and joined multiple times during the given range but we only
1230
+ # care about end-result so we grab the last one.
1231
+ last_membership_change_by_room_id_in_from_to_range: dict[
1232
+ str, CurrentStateDeltaMembership
1233
+ ] = {}
1234
+ # We also want to assemble a list of the first membership events during the token
1235
+ # range so we can step backward to the previous membership that would apply to
1236
+ # before the token range to see if we have `newly_joined` the room.
1237
+ first_membership_change_by_room_id_in_from_to_range: dict[
1238
+ str, CurrentStateDeltaMembership
1239
+ ] = {}
1240
+ # Keep track if the room has a non-join event in the token range so we can later
1241
+ # tell if it was a `newly_joined` room. If the last membership event in the
1242
+ # token range is a join and there is also some non-join in the range, we know
1243
+ # they `newly_joined`.
1244
+ has_non_join_event_by_room_id_in_from_to_range: dict[str, bool] = {}
1245
+ for (
1246
+ membership_change
1247
+ ) in current_state_delta_membership_changes_in_from_to_range:
1248
+ room_id = membership_change.room_id
1249
+
1250
+ last_membership_change_by_room_id_in_from_to_range[room_id] = (
1251
+ membership_change
1252
+ )
1253
+ # Only set if we haven't already set it
1254
+ first_membership_change_by_room_id_in_from_to_range.setdefault(
1255
+ room_id, membership_change
1256
+ )
1257
+
1258
+ if membership_change.membership != Membership.JOIN:
1259
+ has_non_join_event_by_room_id_in_from_to_range[room_id] = True
1260
+
1261
+ # 1) Fixup
1262
+ #
1263
+ # 2) We also want to assemble a list of possibly newly joined rooms. Someone
1264
+ # could have left and joined multiple times during the given range but we only
1265
+ # care about whether they are joined at the end of the token range so we are
1266
+ # working with the last membership even in the token range.
1267
+ possibly_newly_joined_room_ids = set()
1268
+ for (
1269
+ last_membership_change_in_from_to_range
1270
+ ) in last_membership_change_by_room_id_in_from_to_range.values():
1271
+ room_id = last_membership_change_in_from_to_range.room_id
1272
+
1273
+ # 2)
1274
+ if last_membership_change_in_from_to_range.membership == Membership.JOIN:
1275
+ possibly_newly_joined_room_ids.add(room_id)
1276
+
1277
+ # 1) Figure out newly_left rooms (> `from_token` and <= `to_token`).
1278
+ if last_membership_change_in_from_to_range.membership == Membership.LEAVE:
1279
+ # 1) Mark this room as `newly_left`
1280
+ newly_left_room_map[room_id] = RoomsForUserStateReset(
1281
+ room_id=room_id,
1282
+ sender=last_membership_change_in_from_to_range.sender,
1283
+ membership=Membership.LEAVE,
1284
+ event_id=last_membership_change_in_from_to_range.event_id,
1285
+ event_pos=last_membership_change_in_from_to_range.event_pos,
1286
+ room_version_id=await self.store.get_room_version_id(room_id),
1287
+ )
1288
+
1289
+ # 2) Figure out `newly_joined`
1290
+ for room_id in possibly_newly_joined_room_ids:
1291
+ has_non_join_in_from_to_range = (
1292
+ has_non_join_event_by_room_id_in_from_to_range.get(room_id, False)
1293
+ )
1294
+ # If the last membership event in the token range is a join and there is
1295
+ # also some non-join in the range, we know they `newly_joined`.
1296
+ if has_non_join_in_from_to_range:
1297
+ # We found a `newly_joined` room (we left and joined within the token range)
1298
+ newly_joined_room_ids.add(room_id)
1299
+ else:
1300
+ prev_event_id = first_membership_change_by_room_id_in_from_to_range[
1301
+ room_id
1302
+ ].prev_event_id
1303
+ prev_membership = first_membership_change_by_room_id_in_from_to_range[
1304
+ room_id
1305
+ ].prev_membership
1306
+
1307
+ if prev_event_id is None:
1308
+ # We found a `newly_joined` room (we are joining the room for the
1309
+ # first time within the token range)
1310
+ newly_joined_room_ids.add(room_id)
1311
+ # Last resort, we need to step back to the previous membership event
1312
+ # just before the token range to see if we're joined then or not.
1313
+ elif prev_membership != Membership.JOIN:
1314
+ # We found a `newly_joined` room (we left before the token range
1315
+ # and joined within the token range)
1316
+ newly_joined_room_ids.add(room_id)
1317
+
1318
+ return newly_joined_room_ids, newly_left_room_map
1319
+
1320
+ @trace
1321
+ async def _get_dm_rooms_for_user(
1322
+ self,
1323
+ user_id: str,
1324
+ ) -> AbstractSet[str]:
1325
+ """Get the set of DM rooms for the user."""
1326
+
1327
+ # We're using global account data (`m.direct`) instead of checking for
1328
+ # `is_direct` on membership events because that property only appears for
1329
+ # the invitee membership event (doesn't show up for the inviter).
1330
+ #
1331
+ # We're unable to take `to_token` into account for global account data since
1332
+ # we only keep track of the latest account data for the user.
1333
+ dm_map = await self.store.get_global_account_data_by_type_for_user(
1334
+ user_id, AccountDataTypes.DIRECT
1335
+ )
1336
+
1337
+ # Flatten out the map. Account data is set by the client so it needs to be
1338
+ # scrutinized.
1339
+ dm_room_id_set = set()
1340
+ if isinstance(dm_map, dict):
1341
+ for room_ids in dm_map.values():
1342
+ # Account data should be a list of room IDs. Ignore anything else
1343
+ if isinstance(room_ids, list):
1344
+ for room_id in room_ids:
1345
+ if isinstance(room_id, str):
1346
+ dm_room_id_set.add(room_id)
1347
+
1348
+ return dm_room_id_set
1349
+
1350
+ @trace
1351
+ async def filter_rooms_relevant_for_sync(
1352
+ self,
1353
+ user: UserID,
1354
+ room_membership_for_user_map: dict[str, RoomsForUserType],
1355
+ newly_left_room_ids: AbstractSet[str],
1356
+ ) -> dict[str, RoomsForUserType]:
1357
+ """
1358
+ Filter room IDs that should/can be listed for this user in the sync response (the
1359
+ full room list that will be further filtered, sorted, and sliced).
1360
+
1361
+ We're looking for rooms where the user has the following state in the token
1362
+ range (> `from_token` and <= `to_token`):
1363
+
1364
+ - `invite`, `join`, `knock`, `ban` membership events
1365
+ - Kicks (`leave` membership events where `sender` is different from the
1366
+ `user_id`/`state_key`)
1367
+ - `newly_left` (rooms that were left during the given token range)
1368
+ - In order for bans/kicks to not show up in sync, you need to `/forget` those
1369
+ rooms. This doesn't modify the event itself though and only adds the
1370
+ `forgotten` flag to the `room_memberships` table in Synapse. There isn't a way
1371
+ to tell when a room was forgotten at the moment so we can't factor it into the
1372
+ from/to range.
1373
+
1374
+ Args:
1375
+ user: User that is syncing
1376
+ room_membership_for_user_map: Room membership for the user
1377
+ newly_left_room_ids: The set of room IDs we have newly left
1378
+
1379
+ Returns:
1380
+ A dictionary of room IDs that should be listed in the sync response along
1381
+ with membership information in that room at the time of `to_token`.
1382
+ """
1383
+ user_id = user.to_string()
1384
+
1385
+ # Filter rooms to only what we're interested to sync with
1386
+ filtered_sync_room_map = {
1387
+ room_id: room_membership_for_user
1388
+ for room_id, room_membership_for_user in room_membership_for_user_map.items()
1389
+ if filter_membership_for_sync(
1390
+ user_id=user_id,
1391
+ room_membership_for_user=room_membership_for_user,
1392
+ newly_left=room_id in newly_left_room_ids,
1393
+ )
1394
+ }
1395
+
1396
+ return filtered_sync_room_map
1397
+
1398
+ async def check_room_subscription_allowed_for_user(
1399
+ self,
1400
+ room_id: str,
1401
+ room_membership_for_user_map: dict[str, RoomsForUserType],
1402
+ to_token: StreamToken,
1403
+ ) -> Optional[RoomsForUserType]:
1404
+ """
1405
+ Check whether the user is allowed to see the room based on whether they have
1406
+ ever had membership in the room or if the room is `world_readable`.
1407
+
1408
+ Similar to `check_user_in_room_or_world_readable(...)`
1409
+
1410
+ Args:
1411
+ room_id: Room to check
1412
+ room_membership_for_user_map: Room membership for the user at the time of
1413
+ the `to_token` (<= `to_token`).
1414
+ to_token: The token to fetch rooms up to.
1415
+
1416
+ Returns:
1417
+ The room membership for the user if they are allowed to subscribe to the
1418
+ room else `None`.
1419
+ """
1420
+
1421
+ # We can first check if they are already allowed to see the room based
1422
+ # on our previous work to assemble the `room_membership_for_user_map`.
1423
+ #
1424
+ # If they have had any membership in the room over time (up to the `to_token`),
1425
+ # let them subscribe and see what they can.
1426
+ existing_membership_for_user = room_membership_for_user_map.get(room_id)
1427
+ if existing_membership_for_user is not None:
1428
+ return existing_membership_for_user
1429
+
1430
+ # TODO: Handle `world_readable` rooms
1431
+ return None
1432
+
1433
+ # If the room is `world_readable`, it doesn't matter whether they can join,
1434
+ # everyone can see the room.
1435
+ # not_in_room_membership_for_user = _RoomMembershipForUser(
1436
+ # room_id=room_id,
1437
+ # event_id=None,
1438
+ # event_pos=None,
1439
+ # membership=None,
1440
+ # sender=None,
1441
+ # newly_joined=False,
1442
+ # newly_left=False,
1443
+ # is_dm=False,
1444
+ # )
1445
+ # room_state = await self.get_current_state_at(
1446
+ # room_id=room_id,
1447
+ # room_membership_for_user_at_to_token=not_in_room_membership_for_user,
1448
+ # state_filter=StateFilter.from_types(
1449
+ # [(EventTypes.RoomHistoryVisibility, "")]
1450
+ # ),
1451
+ # to_token=to_token,
1452
+ # )
1453
+
1454
+ # visibility_event = room_state.get((EventTypes.RoomHistoryVisibility, ""))
1455
+ # if (
1456
+ # visibility_event is not None
1457
+ # and visibility_event.content.get("history_visibility")
1458
+ # == HistoryVisibility.WORLD_READABLE
1459
+ # ):
1460
+ # return not_in_room_membership_for_user
1461
+
1462
+ # return None
1463
+
1464
+ @trace
1465
+ async def _bulk_get_stripped_state_for_rooms_from_sync_room_map(
1466
+ self,
1467
+ room_ids: StrCollection,
1468
+ sync_room_map: dict[str, RoomsForUserType],
1469
+ ) -> dict[str, Optional[StateMap[StrippedStateEvent]]]:
1470
+ """
1471
+ Fetch stripped state for a list of room IDs. Stripped state is only
1472
+ applicable to invite/knock rooms. Other rooms will have `None` as their
1473
+ stripped state.
1474
+
1475
+ For invite rooms, we pull from `unsigned.invite_room_state`.
1476
+ For knock rooms, we pull from `unsigned.knock_room_state`.
1477
+
1478
+ Args:
1479
+ room_ids: Room IDs to fetch stripped state for
1480
+ sync_room_map: Dictionary of room IDs to sort along with membership
1481
+ information in the room at the time of `to_token`.
1482
+
1483
+ Returns:
1484
+ Mapping from room_id to mapping of (type, state_key) to stripped state
1485
+ event.
1486
+ """
1487
+ room_id_to_stripped_state_map: dict[
1488
+ str, Optional[StateMap[StrippedStateEvent]]
1489
+ ] = {}
1490
+
1491
+ # Fetch what we haven't before
1492
+ room_ids_to_fetch = [
1493
+ room_id
1494
+ for room_id in room_ids
1495
+ if room_id not in room_id_to_stripped_state_map
1496
+ ]
1497
+
1498
+ # Gather a list of event IDs we can grab stripped state from
1499
+ invite_or_knock_event_ids: list[str] = []
1500
+ for room_id in room_ids_to_fetch:
1501
+ if sync_room_map[room_id].membership in (
1502
+ Membership.INVITE,
1503
+ Membership.KNOCK,
1504
+ ):
1505
+ event_id = sync_room_map[room_id].event_id
1506
+ # If this is an invite/knock then there should be an event_id
1507
+ assert event_id is not None
1508
+ invite_or_knock_event_ids.append(event_id)
1509
+ else:
1510
+ room_id_to_stripped_state_map[room_id] = None
1511
+
1512
+ invite_or_knock_events = await self.store.get_events(invite_or_knock_event_ids)
1513
+ for invite_or_knock_event in invite_or_knock_events.values():
1514
+ room_id = invite_or_knock_event.room_id
1515
+ membership = invite_or_knock_event.membership
1516
+
1517
+ raw_stripped_state_events = None
1518
+ if membership == Membership.INVITE:
1519
+ invite_room_state = invite_or_knock_event.unsigned.get(
1520
+ "invite_room_state"
1521
+ )
1522
+ raw_stripped_state_events = invite_room_state
1523
+ elif membership == Membership.KNOCK:
1524
+ knock_room_state = invite_or_knock_event.unsigned.get(
1525
+ "knock_room_state"
1526
+ )
1527
+ raw_stripped_state_events = knock_room_state
1528
+ else:
1529
+ raise AssertionError(
1530
+ f"Unexpected membership {membership} (this is a problem with Synapse itself)"
1531
+ )
1532
+
1533
+ stripped_state_map: Optional[MutableStateMap[StrippedStateEvent]] = None
1534
+ # Scrutinize unsigned things. `raw_stripped_state_events` should be a list
1535
+ # of stripped events
1536
+ if raw_stripped_state_events is not None:
1537
+ stripped_state_map = {}
1538
+ if isinstance(raw_stripped_state_events, list):
1539
+ for raw_stripped_event in raw_stripped_state_events:
1540
+ stripped_state_event = parse_stripped_state_event(
1541
+ raw_stripped_event
1542
+ )
1543
+ if stripped_state_event is not None:
1544
+ stripped_state_map[
1545
+ (
1546
+ stripped_state_event.type,
1547
+ stripped_state_event.state_key,
1548
+ )
1549
+ ] = stripped_state_event
1550
+
1551
+ room_id_to_stripped_state_map[room_id] = stripped_state_map
1552
+
1553
+ return room_id_to_stripped_state_map
1554
+
1555
+ @trace
1556
+ async def _bulk_get_partial_current_state_content_for_rooms(
1557
+ self,
1558
+ content_type: Literal[
1559
+ # `content.type` from `EventTypes.Create``
1560
+ "room_type",
1561
+ # `content.algorithm` from `EventTypes.RoomEncryption`
1562
+ "room_encryption",
1563
+ ],
1564
+ room_ids: set[str],
1565
+ sync_room_map: dict[str, RoomsForUserType],
1566
+ to_token: StreamToken,
1567
+ room_id_to_stripped_state_map: dict[
1568
+ str, Optional[StateMap[StrippedStateEvent]]
1569
+ ],
1570
+ ) -> Mapping[str, Union[Optional[str], StateSentinel]]:
1571
+ """
1572
+ Get the given state event content for a list of rooms. First we check the
1573
+ current state of the room, then fallback to stripped state if available, then
1574
+ historical state.
1575
+
1576
+ Args:
1577
+ content_type: Which content to grab
1578
+ room_ids: Room IDs to fetch the given content field for.
1579
+ sync_room_map: Dictionary of room IDs to sort along with membership
1580
+ information in the room at the time of `to_token`.
1581
+ to_token: We filter based on the state of the room at this token
1582
+ room_id_to_stripped_state_map: This does not need to be filled in before
1583
+ calling this function. Mapping from room_id to mapping of (type, state_key)
1584
+ to stripped state event. Modified in place when we fetch new rooms so we can
1585
+ save work next time this function is called.
1586
+
1587
+ Returns:
1588
+ A mapping from room ID to the state event content if the room has
1589
+ the given state event (event_type, ""), otherwise `None`. Rooms unknown to
1590
+ this server will return `ROOM_UNKNOWN_SENTINEL`.
1591
+ """
1592
+ room_id_to_content: dict[str, Union[Optional[str], StateSentinel]] = {}
1593
+
1594
+ # As a bulk shortcut, use the current state if the server is particpating in the
1595
+ # room (meaning we have current state). Ideally, for leave/ban rooms, we would
1596
+ # want the state at the time of the membership instead of current state to not
1597
+ # leak anything but we consider the create/encryption stripped state events to
1598
+ # not be a secret given they are often set at the start of the room and they are
1599
+ # normally handed out on invite/knock.
1600
+ #
1601
+ # Be mindful to only use this for non-sensitive details. For example, even
1602
+ # though the room name/avatar/topic are also stripped state, they seem a lot
1603
+ # more senstive to leak the current state value of.
1604
+ #
1605
+ # Since this function is cached, we need to make a mutable copy via
1606
+ # `dict(...)`.
1607
+ event_type = ""
1608
+ event_content_field = ""
1609
+ if content_type == "room_type":
1610
+ event_type = EventTypes.Create
1611
+ event_content_field = EventContentFields.ROOM_TYPE
1612
+ room_id_to_content = dict(await self.store.bulk_get_room_type(room_ids))
1613
+ elif content_type == "room_encryption":
1614
+ event_type = EventTypes.RoomEncryption
1615
+ event_content_field = EventContentFields.ENCRYPTION_ALGORITHM
1616
+ room_id_to_content = dict(
1617
+ await self.store.bulk_get_room_encryption(room_ids)
1618
+ )
1619
+ else:
1620
+ assert_never(content_type)
1621
+
1622
+ room_ids_with_results = [
1623
+ room_id
1624
+ for room_id, content_field in room_id_to_content.items()
1625
+ if content_field is not ROOM_UNKNOWN_SENTINEL
1626
+ ]
1627
+
1628
+ # We might not have current room state for remote invite/knocks if we are
1629
+ # the first person on our server to see the room. The best we can do is look
1630
+ # in the optional stripped state from the invite/knock event.
1631
+ room_ids_without_results = room_ids.difference(
1632
+ chain(
1633
+ room_ids_with_results,
1634
+ [
1635
+ room_id
1636
+ for room_id, stripped_state_map in room_id_to_stripped_state_map.items()
1637
+ if stripped_state_map is not None
1638
+ ],
1639
+ )
1640
+ )
1641
+ room_id_to_stripped_state_map.update(
1642
+ await self._bulk_get_stripped_state_for_rooms_from_sync_room_map(
1643
+ room_ids_without_results, sync_room_map
1644
+ )
1645
+ )
1646
+
1647
+ # Update our `room_id_to_content` map based on the stripped state
1648
+ # (applies to invite/knock rooms)
1649
+ rooms_ids_without_stripped_state: set[str] = set()
1650
+ for room_id in room_ids_without_results:
1651
+ stripped_state_map = room_id_to_stripped_state_map.get(
1652
+ room_id, Sentinel.UNSET_SENTINEL
1653
+ )
1654
+ assert stripped_state_map is not Sentinel.UNSET_SENTINEL, (
1655
+ f"Stripped state left unset for room {room_id}. "
1656
+ + "Make sure you're calling `_bulk_get_stripped_state_for_rooms_from_sync_room_map(...)` "
1657
+ + "with that room_id. (this is a problem with Synapse itself)"
1658
+ )
1659
+
1660
+ # If there is some stripped state, we assume the remote server passed *all*
1661
+ # of the potential stripped state events for the room.
1662
+ if stripped_state_map is not None:
1663
+ create_stripped_event = stripped_state_map.get((EventTypes.Create, ""))
1664
+ stripped_event = stripped_state_map.get((event_type, ""))
1665
+ # Sanity check that we at-least have the create event
1666
+ if create_stripped_event is not None:
1667
+ if stripped_event is not None:
1668
+ room_id_to_content[room_id] = stripped_event.content.get(
1669
+ event_content_field
1670
+ )
1671
+ else:
1672
+ # Didn't see the state event we're looking for in the stripped
1673
+ # state so we can assume relevant content field is `None`.
1674
+ room_id_to_content[room_id] = None
1675
+ else:
1676
+ rooms_ids_without_stripped_state.add(room_id)
1677
+
1678
+ # Last resort, we might not have current room state for rooms that the
1679
+ # server has left (no one local is in the room) but we can look at the
1680
+ # historical state.
1681
+ #
1682
+ # Update our `room_id_to_content` map based on the state at the time of
1683
+ # the membership event.
1684
+ for room_id in rooms_ids_without_stripped_state:
1685
+ # TODO: It would be nice to look this up in a bulk way (N+1 queries)
1686
+ #
1687
+ # TODO: `get_state_at(...)` doesn't take into account the "current state".
1688
+ room_state = await self.storage_controllers.state.get_state_at(
1689
+ room_id=room_id,
1690
+ stream_position=to_token.copy_and_replace(
1691
+ StreamKeyType.ROOM,
1692
+ sync_room_map[room_id].event_pos.to_room_stream_token(),
1693
+ ),
1694
+ state_filter=StateFilter.from_types(
1695
+ [
1696
+ (EventTypes.Create, ""),
1697
+ (event_type, ""),
1698
+ ]
1699
+ ),
1700
+ # Partially-stated rooms should have all state events except for
1701
+ # remote membership events so we don't need to wait at all because
1702
+ # we only want the create event and some non-member event.
1703
+ await_full_state=False,
1704
+ )
1705
+ # We can use the create event as a canary to tell whether the server has
1706
+ # seen the room before
1707
+ create_event = room_state.get((EventTypes.Create, ""))
1708
+ state_event = room_state.get((event_type, ""))
1709
+
1710
+ if create_event is None:
1711
+ # Skip for unknown rooms
1712
+ continue
1713
+
1714
+ if state_event is not None:
1715
+ room_id_to_content[room_id] = state_event.content.get(
1716
+ event_content_field
1717
+ )
1718
+ else:
1719
+ # Didn't see the state event we're looking for in the stripped
1720
+ # state so we can assume relevant content field is `None`.
1721
+ room_id_to_content[room_id] = None
1722
+
1723
+ return room_id_to_content
1724
+
1725
+ @trace
1726
+ async def filter_rooms(
1727
+ self,
1728
+ user: UserID,
1729
+ sync_room_map: dict[str, RoomsForUserType],
1730
+ previous_connection_state: PerConnectionState,
1731
+ filters: SlidingSyncConfig.SlidingSyncList.Filters,
1732
+ to_token: StreamToken,
1733
+ dm_room_ids: AbstractSet[str],
1734
+ ) -> dict[str, RoomsForUserType]:
1735
+ """
1736
+ Filter rooms based on the sync request.
1737
+
1738
+ Args:
1739
+ user: User to filter rooms for
1740
+ sync_room_map: Dictionary of room IDs to sort along with membership
1741
+ information in the room at the time of `to_token`.
1742
+ filters: Filters to apply
1743
+ to_token: We filter based on the state of the room at this token
1744
+ dm_room_ids: Set of room IDs that are DMs for the user
1745
+
1746
+ Returns:
1747
+ A filtered dictionary of room IDs along with membership information in the
1748
+ room at the time of `to_token`.
1749
+ """
1750
+ user_id = user.to_string()
1751
+
1752
+ room_id_to_stripped_state_map: dict[
1753
+ str, Optional[StateMap[StrippedStateEvent]]
1754
+ ] = {}
1755
+
1756
+ filtered_room_id_set = set(sync_room_map.keys())
1757
+
1758
+ # Filter for Direct-Message (DM) rooms
1759
+ if filters.is_dm is not None:
1760
+ with start_active_span("filters.is_dm"):
1761
+ if filters.is_dm:
1762
+ # Only DM rooms please
1763
+ filtered_room_id_set = {
1764
+ room_id
1765
+ for room_id in filtered_room_id_set
1766
+ if room_id in dm_room_ids
1767
+ }
1768
+ else:
1769
+ # Only non-DM rooms please
1770
+ filtered_room_id_set = {
1771
+ room_id
1772
+ for room_id in filtered_room_id_set
1773
+ if room_id not in dm_room_ids
1774
+ }
1775
+
1776
+ if filters.spaces is not None:
1777
+ with start_active_span("filters.spaces"):
1778
+ raise NotImplementedError()
1779
+
1780
+ # Filter for encrypted rooms
1781
+ if filters.is_encrypted is not None:
1782
+ with start_active_span("filters.is_encrypted"):
1783
+ room_id_to_encryption = (
1784
+ await self._bulk_get_partial_current_state_content_for_rooms(
1785
+ content_type="room_encryption",
1786
+ room_ids=filtered_room_id_set,
1787
+ to_token=to_token,
1788
+ sync_room_map=sync_room_map,
1789
+ room_id_to_stripped_state_map=room_id_to_stripped_state_map,
1790
+ )
1791
+ )
1792
+
1793
+ # Make a copy so we don't run into an error: `Set changed size during
1794
+ # iteration`, when we filter out and remove items
1795
+ for room_id in filtered_room_id_set.copy():
1796
+ encryption = room_id_to_encryption.get(
1797
+ room_id, ROOM_UNKNOWN_SENTINEL
1798
+ )
1799
+
1800
+ # Just remove rooms if we can't determine their encryption status
1801
+ if encryption is ROOM_UNKNOWN_SENTINEL:
1802
+ filtered_room_id_set.remove(room_id)
1803
+ continue
1804
+
1805
+ # If we're looking for encrypted rooms, filter out rooms that are not
1806
+ # encrypted and vice versa
1807
+ is_encrypted = encryption is not None
1808
+ if (filters.is_encrypted and not is_encrypted) or (
1809
+ not filters.is_encrypted and is_encrypted
1810
+ ):
1811
+ filtered_room_id_set.remove(room_id)
1812
+
1813
+ # Filter for rooms that the user has been invited to
1814
+ if filters.is_invite is not None:
1815
+ with start_active_span("filters.is_invite"):
1816
+ # Make a copy so we don't run into an error: `Set changed size during
1817
+ # iteration`, when we filter out and remove items
1818
+ for room_id in filtered_room_id_set.copy():
1819
+ room_for_user = sync_room_map[room_id]
1820
+ # If we're looking for invite rooms, filter out rooms that the user is
1821
+ # not invited to and vice versa
1822
+ if (
1823
+ filters.is_invite
1824
+ and room_for_user.membership != Membership.INVITE
1825
+ ) or (
1826
+ not filters.is_invite
1827
+ and room_for_user.membership == Membership.INVITE
1828
+ ):
1829
+ filtered_room_id_set.remove(room_id)
1830
+
1831
+ # Filter by room type (space vs room, etc). A room must match one of the types
1832
+ # provided in the list. `None` is a valid type for rooms which do not have a
1833
+ # room type.
1834
+ if filters.room_types is not None or filters.not_room_types is not None:
1835
+ with start_active_span("filters.room_types"):
1836
+ room_id_to_type = (
1837
+ await self._bulk_get_partial_current_state_content_for_rooms(
1838
+ content_type="room_type",
1839
+ room_ids=filtered_room_id_set,
1840
+ to_token=to_token,
1841
+ sync_room_map=sync_room_map,
1842
+ room_id_to_stripped_state_map=room_id_to_stripped_state_map,
1843
+ )
1844
+ )
1845
+
1846
+ # Make a copy so we don't run into an error: `Set changed size during
1847
+ # iteration`, when we filter out and remove items
1848
+ for room_id in filtered_room_id_set.copy():
1849
+ room_type = room_id_to_type.get(room_id, ROOM_UNKNOWN_SENTINEL)
1850
+
1851
+ # Just remove rooms if we can't determine their type
1852
+ if room_type is ROOM_UNKNOWN_SENTINEL:
1853
+ filtered_room_id_set.remove(room_id)
1854
+ continue
1855
+
1856
+ if (
1857
+ filters.room_types is not None
1858
+ and room_type not in filters.room_types
1859
+ ):
1860
+ filtered_room_id_set.remove(room_id)
1861
+ continue
1862
+
1863
+ if (
1864
+ filters.not_room_types is not None
1865
+ and room_type in filters.not_room_types
1866
+ ):
1867
+ filtered_room_id_set.remove(room_id)
1868
+ continue
1869
+
1870
+ if filters.room_name_like is not None:
1871
+ with start_active_span("filters.room_name_like"):
1872
+ # TODO: The room name is a bit more sensitive to leak than the
1873
+ # create/encryption event. Maybe we should consider a better way to fetch
1874
+ # historical state before implementing this.
1875
+ #
1876
+ # room_id_to_create_content = await self._bulk_get_partial_current_state_content_for_rooms(
1877
+ # content_type="room_name",
1878
+ # room_ids=filtered_room_id_set,
1879
+ # to_token=to_token,
1880
+ # sync_room_map=sync_room_map,
1881
+ # room_id_to_stripped_state_map=room_id_to_stripped_state_map,
1882
+ # )
1883
+ raise NotImplementedError()
1884
+
1885
+ # Filter by room tags according to the users account data
1886
+ if filters.tags is not None or filters.not_tags is not None:
1887
+ with start_active_span("filters.tags"):
1888
+ # Fetch the user tags for their rooms
1889
+ room_tags = await self.store.get_tags_for_user(user_id)
1890
+ room_id_to_tag_name_set: dict[str, set[str]] = {
1891
+ room_id: set(tags.keys()) for room_id, tags in room_tags.items()
1892
+ }
1893
+
1894
+ if filters.tags is not None:
1895
+ tags_set = set(filters.tags)
1896
+ filtered_room_id_set = {
1897
+ room_id
1898
+ for room_id in filtered_room_id_set
1899
+ # Remove rooms that don't have one of the tags in the filter
1900
+ if room_id_to_tag_name_set.get(room_id, set()).intersection(
1901
+ tags_set
1902
+ )
1903
+ }
1904
+
1905
+ if filters.not_tags is not None:
1906
+ not_tags_set = set(filters.not_tags)
1907
+ filtered_room_id_set = {
1908
+ room_id
1909
+ for room_id in filtered_room_id_set
1910
+ # Remove rooms if they have any of the tags in the filter
1911
+ if not room_id_to_tag_name_set.get(room_id, set()).intersection(
1912
+ not_tags_set
1913
+ )
1914
+ }
1915
+
1916
+ # Keep rooms if the user has been state reset out of it but we previously sent
1917
+ # down the connection before. We want to make sure that we send these down to
1918
+ # the client regardless of filters so they find out about the state reset.
1919
+ #
1920
+ # We don't always have access to the state in a room after being state reset if
1921
+ # no one else locally on the server is participating in the room so we patch
1922
+ # these back in manually.
1923
+ state_reset_out_of_room_id_set = {
1924
+ room_id
1925
+ for room_id in sync_room_map.keys()
1926
+ if sync_room_map[room_id].event_id is None
1927
+ and previous_connection_state.rooms.have_sent_room(room_id).status
1928
+ != HaveSentRoomFlag.NEVER
1929
+ }
1930
+
1931
+ # Assemble a new sync room map but only with the `filtered_room_id_set`
1932
+ return {
1933
+ room_id: sync_room_map[room_id]
1934
+ for room_id in filtered_room_id_set | state_reset_out_of_room_id_set
1935
+ }
1936
+
1937
+ @trace
1938
+ async def filter_rooms_using_tables(
1939
+ self,
1940
+ user_id: str,
1941
+ sync_room_map: Mapping[str, RoomsForUserSlidingSync],
1942
+ previous_connection_state: PerConnectionState,
1943
+ filters: SlidingSyncConfig.SlidingSyncList.Filters,
1944
+ to_token: StreamToken,
1945
+ dm_room_ids: AbstractSet[str],
1946
+ ) -> dict[str, RoomsForUserSlidingSync]:
1947
+ """
1948
+ Filter rooms based on the sync request.
1949
+
1950
+ Args:
1951
+ user: User to filter rooms for
1952
+ sync_room_map: Dictionary of room IDs to sort along with membership
1953
+ information in the room at the time of `to_token`.
1954
+ filters: Filters to apply
1955
+ to_token: We filter based on the state of the room at this token
1956
+ dm_room_ids: Set of room IDs which are DMs
1957
+ room_tags: Mapping of room ID to tags
1958
+
1959
+ Returns:
1960
+ A filtered dictionary of room IDs along with membership information in the
1961
+ room at the time of `to_token`.
1962
+ """
1963
+
1964
+ filtered_room_id_set = set(sync_room_map.keys())
1965
+
1966
+ # Filter for Direct-Message (DM) rooms
1967
+ if filters.is_dm is not None:
1968
+ with start_active_span("filters.is_dm"):
1969
+ if filters.is_dm:
1970
+ # Intersect with the DM room set
1971
+ filtered_room_id_set &= dm_room_ids
1972
+ else:
1973
+ # Remove DMs
1974
+ filtered_room_id_set -= dm_room_ids
1975
+
1976
+ if filters.spaces is not None:
1977
+ with start_active_span("filters.spaces"):
1978
+ raise NotImplementedError()
1979
+
1980
+ # Filter for encrypted rooms
1981
+ if filters.is_encrypted is not None:
1982
+ filtered_room_id_set = {
1983
+ room_id
1984
+ for room_id in filtered_room_id_set
1985
+ # Remove rooms if we can't figure out what the encryption status is
1986
+ if sync_room_map[room_id].has_known_state
1987
+ # Or remove if it doesn't match the filter
1988
+ and sync_room_map[room_id].is_encrypted == filters.is_encrypted
1989
+ }
1990
+
1991
+ # Filter for rooms that the user has been invited to
1992
+ if filters.is_invite is not None:
1993
+ with start_active_span("filters.is_invite"):
1994
+ # Make a copy so we don't run into an error: `Set changed size during
1995
+ # iteration`, when we filter out and remove items
1996
+ for room_id in filtered_room_id_set.copy():
1997
+ room_for_user = sync_room_map[room_id]
1998
+ # If we're looking for invite rooms, filter out rooms that the user is
1999
+ # not invited to and vice versa
2000
+ if (
2001
+ filters.is_invite
2002
+ and room_for_user.membership != Membership.INVITE
2003
+ ) or (
2004
+ not filters.is_invite
2005
+ and room_for_user.membership == Membership.INVITE
2006
+ ):
2007
+ filtered_room_id_set.remove(room_id)
2008
+
2009
+ # Filter by room type (space vs room, etc). A room must match one of the types
2010
+ # provided in the list. `None` is a valid type for rooms which do not have a
2011
+ # room type.
2012
+ if filters.room_types is not None or filters.not_room_types is not None:
2013
+ with start_active_span("filters.room_types"):
2014
+ # Make a copy so we don't run into an error: `Set changed size during
2015
+ # iteration`, when we filter out and remove items
2016
+ for room_id in filtered_room_id_set.copy():
2017
+ # Remove rooms if we can't figure out what room type it is
2018
+ if not sync_room_map[room_id].has_known_state:
2019
+ filtered_room_id_set.remove(room_id)
2020
+ continue
2021
+
2022
+ room_type = sync_room_map[room_id].room_type
2023
+
2024
+ if (
2025
+ filters.room_types is not None
2026
+ and room_type not in filters.room_types
2027
+ ):
2028
+ filtered_room_id_set.remove(room_id)
2029
+ continue
2030
+
2031
+ if (
2032
+ filters.not_room_types is not None
2033
+ and room_type in filters.not_room_types
2034
+ ):
2035
+ filtered_room_id_set.remove(room_id)
2036
+ continue
2037
+
2038
+ if filters.room_name_like is not None:
2039
+ with start_active_span("filters.room_name_like"):
2040
+ # TODO: The room name is a bit more sensitive to leak than the
2041
+ # create/encryption event. Maybe we should consider a better way to fetch
2042
+ # historical state before implementing this.
2043
+ #
2044
+ # room_id_to_create_content = await self._bulk_get_partial_current_state_content_for_rooms(
2045
+ # content_type="room_name",
2046
+ # room_ids=filtered_room_id_set,
2047
+ # to_token=to_token,
2048
+ # sync_room_map=sync_room_map,
2049
+ # room_id_to_stripped_state_map=room_id_to_stripped_state_map,
2050
+ # )
2051
+ raise NotImplementedError()
2052
+
2053
+ # Filter by room tags according to the users account data
2054
+ if filters.tags is not None or filters.not_tags is not None:
2055
+ with start_active_span("filters.tags"):
2056
+ # Fetch the user tags for their rooms
2057
+ room_tags = await self.store.get_tags_for_user(user_id)
2058
+ room_id_to_tag_name_set: dict[str, set[str]] = {
2059
+ room_id: set(tags.keys()) for room_id, tags in room_tags.items()
2060
+ }
2061
+
2062
+ if filters.tags is not None:
2063
+ tags_set = set(filters.tags)
2064
+ filtered_room_id_set = {
2065
+ room_id
2066
+ for room_id in filtered_room_id_set
2067
+ # Remove rooms that don't have one of the tags in the filter
2068
+ if room_id_to_tag_name_set.get(room_id, set()).intersection(
2069
+ tags_set
2070
+ )
2071
+ }
2072
+
2073
+ if filters.not_tags is not None:
2074
+ not_tags_set = set(filters.not_tags)
2075
+ filtered_room_id_set = {
2076
+ room_id
2077
+ for room_id in filtered_room_id_set
2078
+ # Remove rooms if they have any of the tags in the filter
2079
+ if not room_id_to_tag_name_set.get(room_id, set()).intersection(
2080
+ not_tags_set
2081
+ )
2082
+ }
2083
+
2084
+ # Keep rooms if the user has been state reset out of it but we previously sent
2085
+ # down the connection before. We want to make sure that we send these down to
2086
+ # the client regardless of filters so they find out about the state reset.
2087
+ #
2088
+ # We don't always have access to the state in a room after being state reset if
2089
+ # no one else locally on the server is participating in the room so we patch
2090
+ # these back in manually.
2091
+ state_reset_out_of_room_id_set = {
2092
+ room_id
2093
+ for room_id in sync_room_map.keys()
2094
+ if sync_room_map[room_id].event_id is None
2095
+ and previous_connection_state.rooms.have_sent_room(room_id).status
2096
+ != HaveSentRoomFlag.NEVER
2097
+ }
2098
+
2099
+ # Assemble a new sync room map but only with the `filtered_room_id_set`
2100
+ return {
2101
+ room_id: sync_room_map[room_id]
2102
+ for room_id in filtered_room_id_set | state_reset_out_of_room_id_set
2103
+ }
2104
+
2105
+ @trace
2106
+ async def sort_rooms(
2107
+ self,
2108
+ sync_room_map: dict[str, RoomsForUserType],
2109
+ to_token: StreamToken,
2110
+ limit: Optional[int] = None,
2111
+ ) -> list[RoomsForUserType]:
2112
+ """
2113
+ Sort by `stream_ordering` of the last event that the user should see in the
2114
+ room. `stream_ordering` is unique so we get a stable sort.
2115
+
2116
+ If `limit` is specified then sort may return fewer entries, but will
2117
+ always return at least the top N rooms. This is useful as we don't always
2118
+ need to sort the full list, but are just interested in the top N.
2119
+
2120
+ Args:
2121
+ sync_room_map: Dictionary of room IDs to sort along with membership
2122
+ information in the room at the time of `to_token`.
2123
+ to_token: We sort based on the events in the room at this token (<= `to_token`)
2124
+ limit: The number of rooms that we need to return from the top of the list.
2125
+
2126
+ Returns:
2127
+ A sorted list of room IDs by `stream_ordering` along with membership information.
2128
+ """
2129
+
2130
+ # Assemble a map of room ID to the `stream_ordering` of the last activity that the
2131
+ # user should see in the room (<= `to_token`)
2132
+ last_activity_in_room_map: dict[str, int] = {}
2133
+
2134
+ # Same as above, except for positions that we know are in the event
2135
+ # stream cache.
2136
+ cached_positions: dict[str, int] = {}
2137
+
2138
+ earliest_cache_position = (
2139
+ self.store._events_stream_cache.get_earliest_known_position()
2140
+ )
2141
+
2142
+ for room_id, room_for_user in sync_room_map.items():
2143
+ if room_for_user.membership == Membership.JOIN:
2144
+ # For joined rooms check the stream change cache.
2145
+ cached_position = (
2146
+ self.store._events_stream_cache.get_max_pos_of_last_change(room_id)
2147
+ )
2148
+ if cached_position is not None:
2149
+ cached_positions[room_id] = cached_position
2150
+ else:
2151
+ # If the user has left/been invited/knocked/been banned from a
2152
+ # room, they shouldn't see anything past that point.
2153
+ #
2154
+ # FIXME: It's possible that people should see beyond this point
2155
+ # in invited/knocked cases if for example the room has
2156
+ # `invite`/`world_readable` history visibility, see
2157
+ # https://github.com/matrix-org/matrix-spec-proposals/pull/3575#discussion_r1653045932
2158
+ last_activity_in_room_map[room_id] = room_for_user.event_pos.stream
2159
+
2160
+ # If the stream position is in range of the stream change cache
2161
+ # we can include it.
2162
+ if room_for_user.event_pos.stream > earliest_cache_position:
2163
+ cached_positions[room_id] = room_for_user.event_pos.stream
2164
+
2165
+ # If we are only asked for the top N rooms, and we have enough from
2166
+ # looking in the stream change cache, then we can return early. This
2167
+ # is because the cache must include all entries above
2168
+ # `.get_earliest_known_position()`.
2169
+ if limit is not None and len(cached_positions) >= limit:
2170
+ # ... but first we need to handle the case where the cached max
2171
+ # position is greater than the to_token, in which case we do
2172
+ # actually query the DB. This should happen rarely, so can do it in
2173
+ # a loop.
2174
+ for room_id, position in list(cached_positions.items()):
2175
+ if position > to_token.room_key.stream:
2176
+ result = await self.store.get_last_event_pos_in_room_before_stream_ordering(
2177
+ room_id, to_token.room_key
2178
+ )
2179
+ if (
2180
+ result is not None
2181
+ and result[1].stream > earliest_cache_position
2182
+ ):
2183
+ # We have a stream position in the cached range.
2184
+ cached_positions[room_id] = result[1].stream
2185
+ else:
2186
+ # No position in the range, so we remove the entry.
2187
+ cached_positions.pop(room_id)
2188
+
2189
+ if limit is not None and len(cached_positions) >= limit:
2190
+ return sorted(
2191
+ (
2192
+ room
2193
+ for room in sync_room_map.values()
2194
+ if room.room_id in cached_positions
2195
+ ),
2196
+ # Sort by the last activity (stream_ordering) in the room
2197
+ key=lambda room_info: cached_positions[room_info.room_id],
2198
+ # We want descending order
2199
+ reverse=True,
2200
+ )
2201
+
2202
+ # For fully-joined rooms, we find the latest activity at/before the
2203
+ # `to_token`.
2204
+ joined_room_positions = (
2205
+ await self.store.bulk_get_last_event_pos_in_room_before_stream_ordering(
2206
+ [
2207
+ room_id
2208
+ for room_id, room_for_user in sync_room_map.items()
2209
+ if room_for_user.membership == Membership.JOIN
2210
+ ],
2211
+ to_token.room_key,
2212
+ )
2213
+ )
2214
+
2215
+ last_activity_in_room_map.update(joined_room_positions)
2216
+
2217
+ return sorted(
2218
+ sync_room_map.values(),
2219
+ # Sort by the last activity (stream_ordering) in the room
2220
+ key=lambda room_info: last_activity_in_room_map[room_info.room_id],
2221
+ # We want descending order
2222
+ reverse=True,
2223
+ )
2224
+
2225
+ async def get_is_encrypted_for_room_at_token(
2226
+ self, room_id: str, to_token: RoomStreamToken
2227
+ ) -> bool:
2228
+ """Get if the room is encrypted at the time."""
2229
+
2230
+ # Fetch the current encryption state
2231
+ state_ids = await self.store.get_partial_filtered_current_state_ids(
2232
+ room_id, StateFilter.from_types([(EventTypes.RoomEncryption, "")])
2233
+ )
2234
+ encryption_event_id = state_ids.get((EventTypes.RoomEncryption, ""))
2235
+
2236
+ # Now roll back the state by looking at the state deltas between
2237
+ # to_token and now.
2238
+ deltas = await self.store.get_current_state_deltas_for_room(
2239
+ room_id,
2240
+ from_token=to_token,
2241
+ to_token=self.store.get_room_max_token(),
2242
+ )
2243
+
2244
+ for delta in deltas:
2245
+ if delta.event_type != EventTypes.RoomEncryption:
2246
+ continue
2247
+
2248
+ # Found the first change, we look at the previous event ID to get
2249
+ # the state at the to token.
2250
+
2251
+ if delta.prev_event_id is None:
2252
+ # There is no prev event, so no encryption state event, so room is not encrypted
2253
+ return False
2254
+
2255
+ encryption_event_id = delta.prev_event_id
2256
+ break
2257
+
2258
+ # We didn't find an encryption state, room isn't encrypted
2259
+ if encryption_event_id is None:
2260
+ return False
2261
+
2262
+ # We found encryption state, check if content has a non-null algorithm
2263
+ encrypted_event = await self.store.get_event(encryption_event_id)
2264
+ algorithm = encrypted_event.content.get(EventContentFields.ENCRYPTION_ALGORITHM)
2265
+
2266
+ return algorithm is not None