diff --git a/synapse/handlers/sync.py b/synapse/handlers/sync.py index 215986d2fa..881dde15a6 100644 --- a/synapse/handlers/sync.py +++ b/synapse/handlers/sync.py @@ -289,9 +289,9 @@ class SyncResult: class E2eeSyncResult: next_batch: StreamToken to_device: List[JsonDict] - # device_lists: DeviceListUpdates - # device_one_time_keys_count: JsonMapping - # device_unused_fallback_key_types: List[str] + device_lists: DeviceListUpdates + device_one_time_keys_count: JsonMapping + device_unused_fallback_key_types: List[str] class SyncHandler: @@ -1813,19 +1813,46 @@ class SyncHandler: full_state=False, ) - # 1. Calculate `device_lists` - device_lists = await self._generate_sync_entry_for_device_list( - sync_result_builder - ) - - # 2. Calculate `to_device` events + # 1. Calculate `to_device` events await self._generate_sync_entry_for_to_device(sync_result_builder) + # 2. Calculate `device_lists` + # Device list updates are sent if a since token is provided. + device_lists = DeviceListUpdates() + include_device_list_updates = bool(since_token and since_token.device_list_key) + if include_device_list_updates: + device_lists = await self._generate_sync_entry_for_device_list( + sync_result_builder, + # TODO: Do we need to worry about these? All of this info is + # normally calculated when we `_generate_sync_entry_for_rooms()` but we + # probably don't want to do all of that work for this endpoint. + newly_joined_rooms=frozenset(), + newly_joined_or_invited_or_knocked_users=frozenset(), + newly_left_rooms=frozenset(), + newly_left_users=frozenset(), + ) + + # 3. Calculate `device_one_time_keys_count` and `device_unused_fallback_key_types` + device_id = sync_config.device_id + one_time_keys_count: JsonMapping = {} + unused_fallback_key_types: List[str] = [] + if device_id: + # TODO: We should have a way to let clients differentiate between the states of: + # * no change in OTK count since the provided since token + # * the server has zero OTKs left for this device + # Spec issue: https://github.com/matrix-org/matrix-doc/issues/3298 + one_time_keys_count = await self.store.count_e2e_one_time_keys( + user_id, device_id + ) + unused_fallback_key_types = list( + await self.store.get_e2e_unused_fallback_key_types(user_id, device_id) + ) + return E2eeSyncResult( to_device=sync_result_builder.to_device, device_lists=device_lists, - # device_one_time_keys_count: JsonMapping - # device_unused_fallback_key_types: List[str] + device_one_time_keys_count=one_time_keys_count, + device_unused_fallback_key_types=unused_fallback_key_types, next_batch=sync_result_builder.now_token, ) @@ -2007,7 +2034,7 @@ class SyncHandler: users_that_have_changed = set() - joined_rooms = sync_result_builder.joined_room_ids + joined_room_ids = sync_result_builder.joined_room_ids # Step 1a, check for changes in devices of users we share a room # with @@ -2032,14 +2059,14 @@ class SyncHandler: # or if the changed user is the syncing user (as we always # want to include device list updates of their own devices). if user_id == changed_user_id or any( - rid in joined_rooms for rid in entries + rid in joined_room_ids for rid in entries ): users_that_have_changed.add(changed_user_id) else: users_that_have_changed = ( await self._device_handler.get_device_changes_in_shared_rooms( user_id, - sync_result_builder.joined_room_ids, + joined_room_ids, from_token=since_token, ) ) @@ -2066,7 +2093,7 @@ class SyncHandler: # Remove any users that we still share a room with. left_users_rooms = await self.store.get_rooms_for_users(newly_left_users) for user_id, entries in left_users_rooms.items(): - if any(rid in joined_rooms for rid in entries): + if any(rid in joined_room_ids for rid in entries): newly_left_users.discard(user_id) return DeviceListUpdates(changed=users_that_have_changed, left=newly_left_users) diff --git a/synapse/rest/client/sync.py b/synapse/rest/client/sync.py index 01e616cec6..30c5c13f1a 100644 --- a/synapse/rest/client/sync.py +++ b/synapse/rest/client/sync.py @@ -624,9 +624,11 @@ class SlidingSyncE2eeRestServlet(RestServlet): if since is not None: since_token = await StreamToken.from_string(self.store, since) + logger.info(f"sync with since_token: {since_token}") + # Request cache key request_key = ( - SyncVersion.SYNC_V2, + SyncVersion.E2EE_SYNC, user, timeout, since, @@ -636,7 +638,7 @@ class SlidingSyncE2eeRestServlet(RestServlet): sync_result = await self.sync_handler.wait_for_sync_for_user( requester, sync_config, - SyncVersion.SYNC_V2, + SyncVersion.E2EE_SYNC, request_key, since_token=since_token, timeout=timeout, @@ -655,6 +657,24 @@ class SlidingSyncE2eeRestServlet(RestServlet): if sync_result.to_device: response["to_device"] = {"events": sync_result.to_device} + if sync_result.device_lists.changed: + response["device_lists"]["changed"] = list(sync_result.device_lists.changed) + if sync_result.device_lists.left: + response["device_lists"]["left"] = list(sync_result.device_lists.left) + + # We always include this because https://github.com/vector-im/element-android/issues/3725 + # The spec isn't terribly clear on when this can be omitted and how a client would tell + # the difference between "no keys present" and "nothing changed" in terms of whole field + # absent / individual key type entry absent + # Corresponding synapse issue: https://github.com/matrix-org/synapse/issues/10456 + response["device_one_time_keys_count"] = sync_result.device_one_time_keys_count + + # https://github.com/matrix-org/matrix-doc/blob/54255851f642f84a4f1aaf7bc063eebe3d76752b/proposals/2732-olm-fallback-keys.md + # states that this field should always be included, as long as the server supports the feature. + response["device_unused_fallback_key_types"] = ( + sync_result.device_unused_fallback_key_types + ) + return 200, response