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