diff --git a/synapse/handlers/device.py b/synapse/handlers/device.py
index 5c06073901..563a17f888 100644
--- a/synapse/handlers/device.py
+++ b/synapse/handlers/device.py
@@ -1086,7 +1086,7 @@ class DeviceListUpdater(DeviceListWorkerUpdater):
@measure_func("_incoming_device_list_update")
async def _handle_device_updates(self, user_id: str) -> None:
- "Actually handle pending updates."
+ """Actually handle pending updates."""
async with self._remote_edu_linearizer.queue(user_id):
pending_updates = self._pending_updates.pop(user_id, [])
diff --git a/synapse/handlers/e2e_keys.py b/synapse/handlers/e2e_keys.py
index 8eca6b1381..12a2c09618 100644
--- a/synapse/handlers/e2e_keys.py
+++ b/synapse/handlers/e2e_keys.py
@@ -118,7 +118,8 @@ class E2eKeysHandler:
Args:
from_user_id: the user making the query. This is used when
adding cross-signing signatures to limit what signatures users
- can see.
+ can see, and to prevent leaking the displayname of devices of
+ one user to another when experimental MSC3480 support is enabled.
from_device_id: the device making the query. This is used to limit
the number of in-flight queries at a time.
"""
@@ -145,7 +146,7 @@ class E2eKeysHandler:
failures: Dict[str, JsonDict] = {}
results = {}
if local_query:
- local_result = await self.query_local_devices(local_query)
+ local_result = await self.query_local_devices(local_query, from_user_id)
for user_id, keys in local_result.items():
if user_id in local_query:
results[user_id] = keys
@@ -453,15 +454,15 @@ class E2eKeysHandler:
async def query_local_devices(
self,
query: Mapping[str, Optional[List[str]]],
- include_displaynames: bool = True,
+ from_local_user_id: Optional[str],
) -> Dict[str, Dict[str, dict]]:
"""Get E2E device keys for local users
Args:
query: map from user_id to a list
of devices to query (None for all devices)
- include_displaynames: Whether to include device displaynames in the returned
- device details.
+ from_local_user_id: If the request originates from a local user, their
+ User ID should be specified here. Otherwise, this should be None.
Returns:
A map from user_id -> device_id -> device details
@@ -494,7 +495,7 @@ class E2eKeysHandler:
result_dict[user_id] = {}
results = await self.store.get_e2e_device_keys_for_cs_api(
- local_query, include_displaynames
+ local_query, from_local_user_id
)
# Build the result structure
@@ -531,9 +532,8 @@ class E2eKeysHandler:
)
res = await self.query_local_devices(
device_keys_query,
- include_displaynames=(
- self.config.federation.allow_device_name_lookup_over_federation
- ),
+ # This is a request originating from a remote user.
+ from_local_user_id=None,
)
ret = {"device_keys": res}
@@ -935,7 +935,9 @@ class E2eKeysHandler:
# fetch our stored devices. This is used to 1. verify
# signatures on the master key, and 2. to compare with what
# was sent if the device was signed
- devices = await self.store.get_e2e_device_keys_for_cs_api([(user_id, None)])
+ devices = await self.store.get_e2e_device_keys_for_cs_api(
+ [(user_id, None)], user_id
+ )
if user_id not in devices:
raise NotFoundError("No device keys found")
diff --git a/synapse/storage/databases/main/end_to_end_keys.py b/synapse/storage/databases/main/end_to_end_keys.py
index c4ac6c33ba..22460819a4 100644
--- a/synapse/storage/databases/main/end_to_end_keys.py
+++ b/synapse/storage/databases/main/end_to_end_keys.py
@@ -141,13 +141,15 @@ class EndToEndKeyWorkerStore(EndToEndKeyBackgroundStore, CacheInvalidationWorker
async def get_e2e_device_keys_for_cs_api(
self,
query_list: Collection[Tuple[str, Optional[str]]],
- include_displaynames: bool = True,
+ from_local_user_id: Optional[str],
) -> Dict[str, Dict[str, JsonDict]]:
"""Fetch a list of device keys, formatted suitably for the C/S API.
+
Args:
query_list: List of pairs of user_ids and device_ids.
- include_displaynames: Whether to include the displayname of returned devices
- (if one exists).
+ from_local_user_id: If the request originates from a local user, their
+ User ID should be specified here. Otherwise, this should be None.
+
Returns:
Dict mapping from user-id to dict mapping from device_id to
key data. The key data will be a dict in the same format as the
@@ -169,6 +171,25 @@ class EndToEndKeyWorkerStore(EndToEndKeyBackgroundStore, CacheInvalidationWorker
if r is None:
continue
+ # Determine whether the displayname of this device should be shared with
+ # the user making the request.
+ include_displaynames = True
+
+ if (
+ from_local_user_id is not None
+ and user_id != from_local_user_id
+ and self.hs.config.experimental.msc3480_enabled is True
+ ):
+ include_displaynames = False
+
+ # If this is a request from a remote user, and we've disallowed sharing
+ # local user device names over federation, strip the device's displayname.
+ elif (
+ from_local_user_id is None
+ and not self._allow_device_name_lookup_over_federation
+ ):
+ include_displaynames = False
+
r["unsigned"] = {}
if include_displaynames:
# Include the device's display name in the "unsigned" dictionary
|