Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 0328b56

Browse files
authored
Support MSC3814: Dehydrated Devices Part 2 (#16010)
1 parent 4581809 commit 0328b56

File tree

8 files changed

+254
-97
lines changed

8 files changed

+254
-97
lines changed

changelog.d/16010.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Update dehydrated devices implementation.

synapse/handlers/device.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ def __init__(self, hs: "HomeServer"):
385385
self.federation_sender = hs.get_federation_sender()
386386
self._account_data_handler = hs.get_account_data_handler()
387387
self._storage_controllers = hs.get_storage_controllers()
388+
self.db_pool = hs.get_datastores().main.db_pool
388389

389390
self.device_list_updater = DeviceListUpdater(hs, self)
390391

@@ -656,15 +657,17 @@ async def store_dehydrated_device(
656657
device_id: Optional[str],
657658
device_data: JsonDict,
658659
initial_device_display_name: Optional[str] = None,
660+
keys_for_device: Optional[JsonDict] = None,
659661
) -> str:
660-
"""Store a dehydrated device for a user. If the user had a previous
661-
dehydrated device, it is removed.
662+
"""Store a dehydrated device for a user, optionally storing the keys associated with
663+
it as well. If the user had a previous dehydrated device, it is removed.
662664
663665
Args:
664666
user_id: the user that we are storing the device for
665667
device_id: device id supplied by client
666668
device_data: the dehydrated device information
667669
initial_device_display_name: The display name to use for the device
670+
keys_for_device: keys for the dehydrated device
668671
Returns:
669672
device id of the dehydrated device
670673
"""
@@ -673,11 +676,16 @@ async def store_dehydrated_device(
673676
device_id,
674677
initial_device_display_name,
675678
)
679+
680+
time_now = self.clock.time_msec()
681+
676682
old_device_id = await self.store.store_dehydrated_device(
677-
user_id, device_id, device_data
683+
user_id, device_id, device_data, time_now, keys_for_device
678684
)
685+
679686
if old_device_id is not None:
680687
await self.delete_devices(user_id, [old_device_id])
688+
681689
return device_id
682690

683691
async def rehydrate_device(

synapse/handlers/devicemessage.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -367,19 +367,6 @@ async def get_events_for_dehydrated_device(
367367
errcode=Codes.INVALID_PARAM,
368368
)
369369

370-
# if we have a since token, delete any to-device messages before that token
371-
# (since we now know that the device has received them)
372-
deleted = await self.store.delete_messages_for_device(
373-
user_id, device_id, since_stream_id
374-
)
375-
logger.debug(
376-
"Deleted %d to-device messages up to %d for user_id %s device_id %s",
377-
deleted,
378-
since_stream_id,
379-
user_id,
380-
device_id,
381-
)
382-
383370
to_token = self.event_sources.get_current_token().to_device_key
384371

385372
messages, stream_id = await self.store.get_messages_for_device(

synapse/rest/client/devices.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
parse_integer,
3030
)
3131
from synapse.http.site import SynapseRequest
32-
from synapse.replication.http.devices import ReplicationUploadKeysForUserRestServlet
3332
from synapse.rest.client._base import client_patterns, interactive_auth_handler
3433
from synapse.rest.client.models import AuthenticationData
3534
from synapse.rest.models import RequestBodyModel
@@ -480,13 +479,6 @@ def __init__(self, hs: "HomeServer"):
480479
self.e2e_keys_handler = hs.get_e2e_keys_handler()
481480
self.device_handler = handler
482481

483-
if hs.config.worker.worker_app is None:
484-
# if main process
485-
self.key_uploader = self.e2e_keys_handler.upload_keys_for_user
486-
else:
487-
# then a worker
488-
self.key_uploader = ReplicationUploadKeysForUserRestServlet.make_client(hs)
489-
490482
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
491483
requester = await self.auth.get_user_by_req(request)
492484

@@ -549,18 +541,12 @@ async def on_PUT(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
549541
"Device key(s) not found, these must be provided.",
550542
)
551543

552-
# TODO: Those two operations, creating a device and storing the
553-
# device's keys should be atomic.
554544
device_id = await self.device_handler.store_dehydrated_device(
555545
requester.user.to_string(),
556546
submission.device_id,
557547
submission.device_data.dict(),
558548
submission.initial_device_display_name,
559-
)
560-
561-
# TODO: Do we need to do something with the result here?
562-
await self.key_uploader(
563-
user_id=user_id, device_id=submission.device_id, keys=submission.dict()
549+
device_info,
564550
)
565551

566552
return 200, {"device_id": device_id}

synapse/storage/databases/main/devices.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
cast,
2929
)
3030

31+
from canonicaljson import encode_canonical_json
3132
from typing_extensions import Literal
3233

3334
from synapse.api.constants import EduTypes
@@ -1188,8 +1189,42 @@ async def get_dehydrated_device(
11881189
)
11891190

11901191
def _store_dehydrated_device_txn(
1191-
self, txn: LoggingTransaction, user_id: str, device_id: str, device_data: str
1192+
self,
1193+
txn: LoggingTransaction,
1194+
user_id: str,
1195+
device_id: str,
1196+
device_data: str,
1197+
time: int,
1198+
keys: Optional[JsonDict] = None,
11921199
) -> Optional[str]:
1200+
# TODO: make keys non-optional once support for msc2697 is dropped
1201+
if keys:
1202+
device_keys = keys.get("device_keys", None)
1203+
if device_keys:
1204+
# Type ignore - this function is defined on EndToEndKeyStore which we do
1205+
# have access to due to hs.get_datastore() "magic"
1206+
self._set_e2e_device_keys_txn( # type: ignore[attr-defined]
1207+
txn, user_id, device_id, time, device_keys
1208+
)
1209+
1210+
one_time_keys = keys.get("one_time_keys", None)
1211+
if one_time_keys:
1212+
key_list = []
1213+
for key_id, key_obj in one_time_keys.items():
1214+
algorithm, key_id = key_id.split(":")
1215+
key_list.append(
1216+
(
1217+
algorithm,
1218+
key_id,
1219+
encode_canonical_json(key_obj).decode("ascii"),
1220+
)
1221+
)
1222+
self._add_e2e_one_time_keys_txn(txn, user_id, device_id, time, key_list)
1223+
1224+
fallback_keys = keys.get("fallback_keys", None)
1225+
if fallback_keys:
1226+
self._set_e2e_fallback_keys_txn(txn, user_id, device_id, fallback_keys)
1227+
11931228
old_device_id = self.db_pool.simple_select_one_onecol_txn(
11941229
txn,
11951230
table="dehydrated_devices",
@@ -1203,26 +1238,38 @@ def _store_dehydrated_device_txn(
12031238
keyvalues={"user_id": user_id},
12041239
values={"device_id": device_id, "device_data": device_data},
12051240
)
1241+
12061242
return old_device_id
12071243

12081244
async def store_dehydrated_device(
1209-
self, user_id: str, device_id: str, device_data: JsonDict
1245+
self,
1246+
user_id: str,
1247+
device_id: str,
1248+
device_data: JsonDict,
1249+
time_now: int,
1250+
keys: Optional[dict] = None,
12101251
) -> Optional[str]:
12111252
"""Store a dehydrated device for a user.
12121253
12131254
Args:
12141255
user_id: the user that we are storing the device for
12151256
device_id: the ID of the dehydrated device
12161257
device_data: the dehydrated device information
1258+
time_now: current time at the request in milliseconds
1259+
keys: keys for the dehydrated device
1260+
12171261
Returns:
12181262
device id of the user's previous dehydrated device, if any
12191263
"""
1264+
12201265
return await self.db_pool.runInteraction(
12211266
"store_dehydrated_device_txn",
12221267
self._store_dehydrated_device_txn,
12231268
user_id,
12241269
device_id,
12251270
json_encoder.encode(device_data),
1271+
time_now,
1272+
keys,
12261273
)
12271274

12281275
async def remove_dehydrated_device(self, user_id: str, device_id: str) -> bool:

0 commit comments

Comments
 (0)