mirror of
https://github.com/element-hq/synapse
synced 2024-08-20 06:10:21 +00:00
Hide device displaynames from other users
Some argument finagling was needed as query_local_devices can be called from requests of both local and remote users, and in the case of remote users, without a user ID. In the end, we have an option 'from_local_user_id' which tells `query_local_devices` both a) whether the request is from a local or remote user and b) if a local user, which one.
This commit is contained in:
parent
813bab78ce
commit
bd5189c9f7
3 changed files with 37 additions and 14 deletions
|
@ -1086,7 +1086,7 @@ class DeviceListUpdater(DeviceListWorkerUpdater):
|
||||||
|
|
||||||
@measure_func("_incoming_device_list_update")
|
@measure_func("_incoming_device_list_update")
|
||||||
async def _handle_device_updates(self, user_id: str) -> None:
|
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):
|
async with self._remote_edu_linearizer.queue(user_id):
|
||||||
pending_updates = self._pending_updates.pop(user_id, [])
|
pending_updates = self._pending_updates.pop(user_id, [])
|
||||||
|
|
|
@ -118,7 +118,8 @@ class E2eKeysHandler:
|
||||||
Args:
|
Args:
|
||||||
from_user_id: the user making the query. This is used when
|
from_user_id: the user making the query. This is used when
|
||||||
adding cross-signing signatures to limit what signatures users
|
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
|
from_device_id: the device making the query. This is used to limit
|
||||||
the number of in-flight queries at a time.
|
the number of in-flight queries at a time.
|
||||||
"""
|
"""
|
||||||
|
@ -145,7 +146,7 @@ class E2eKeysHandler:
|
||||||
failures: Dict[str, JsonDict] = {}
|
failures: Dict[str, JsonDict] = {}
|
||||||
results = {}
|
results = {}
|
||||||
if local_query:
|
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():
|
for user_id, keys in local_result.items():
|
||||||
if user_id in local_query:
|
if user_id in local_query:
|
||||||
results[user_id] = keys
|
results[user_id] = keys
|
||||||
|
@ -453,15 +454,15 @@ class E2eKeysHandler:
|
||||||
async def query_local_devices(
|
async def query_local_devices(
|
||||||
self,
|
self,
|
||||||
query: Mapping[str, Optional[List[str]]],
|
query: Mapping[str, Optional[List[str]]],
|
||||||
include_displaynames: bool = True,
|
from_local_user_id: Optional[str],
|
||||||
) -> Dict[str, Dict[str, dict]]:
|
) -> Dict[str, Dict[str, dict]]:
|
||||||
"""Get E2E device keys for local users
|
"""Get E2E device keys for local users
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
query: map from user_id to a list
|
query: map from user_id to a list
|
||||||
of devices to query (None for all devices)
|
of devices to query (None for all devices)
|
||||||
include_displaynames: Whether to include device displaynames in the returned
|
from_local_user_id: If the request originates from a local user, their
|
||||||
device details.
|
User ID should be specified here. Otherwise, this should be None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A map from user_id -> device_id -> device details
|
A map from user_id -> device_id -> device details
|
||||||
|
@ -494,7 +495,7 @@ class E2eKeysHandler:
|
||||||
result_dict[user_id] = {}
|
result_dict[user_id] = {}
|
||||||
|
|
||||||
results = await self.store.get_e2e_device_keys_for_cs_api(
|
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
|
# Build the result structure
|
||||||
|
@ -531,9 +532,8 @@ class E2eKeysHandler:
|
||||||
)
|
)
|
||||||
res = await self.query_local_devices(
|
res = await self.query_local_devices(
|
||||||
device_keys_query,
|
device_keys_query,
|
||||||
include_displaynames=(
|
# This is a request originating from a remote user.
|
||||||
self.config.federation.allow_device_name_lookup_over_federation
|
from_local_user_id=None,
|
||||||
),
|
|
||||||
)
|
)
|
||||||
ret = {"device_keys": res}
|
ret = {"device_keys": res}
|
||||||
|
|
||||||
|
@ -935,7 +935,9 @@ class E2eKeysHandler:
|
||||||
# fetch our stored devices. This is used to 1. verify
|
# fetch our stored devices. This is used to 1. verify
|
||||||
# signatures on the master key, and 2. to compare with what
|
# signatures on the master key, and 2. to compare with what
|
||||||
# was sent if the device was signed
|
# 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:
|
if user_id not in devices:
|
||||||
raise NotFoundError("No device keys found")
|
raise NotFoundError("No device keys found")
|
||||||
|
|
|
@ -141,13 +141,15 @@ class EndToEndKeyWorkerStore(EndToEndKeyBackgroundStore, CacheInvalidationWorker
|
||||||
async def get_e2e_device_keys_for_cs_api(
|
async def get_e2e_device_keys_for_cs_api(
|
||||||
self,
|
self,
|
||||||
query_list: Collection[Tuple[str, Optional[str]]],
|
query_list: Collection[Tuple[str, Optional[str]]],
|
||||||
include_displaynames: bool = True,
|
from_local_user_id: Optional[str],
|
||||||
) -> Dict[str, Dict[str, JsonDict]]:
|
) -> Dict[str, Dict[str, JsonDict]]:
|
||||||
"""Fetch a list of device keys, formatted suitably for the C/S API.
|
"""Fetch a list of device keys, formatted suitably for the C/S API.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
query_list: List of pairs of user_ids and device_ids.
|
query_list: List of pairs of user_ids and device_ids.
|
||||||
include_displaynames: Whether to include the displayname of returned devices
|
from_local_user_id: If the request originates from a local user, their
|
||||||
(if one exists).
|
User ID should be specified here. Otherwise, this should be None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict mapping from user-id to dict mapping from device_id to
|
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
|
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:
|
if r is None:
|
||||||
continue
|
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"] = {}
|
r["unsigned"] = {}
|
||||||
if include_displaynames:
|
if include_displaynames:
|
||||||
# Include the device's display name in the "unsigned" dictionary
|
# Include the device's display name in the "unsigned" dictionary
|
||||||
|
|
Loading…
Reference in a new issue