28
28
parse_integer ,
29
29
)
30
30
from synapse .http .site import SynapseRequest
31
+ from synapse .replication .http .devices import ReplicationUploadKeysForUserRestServlet
31
32
from synapse .rest .client ._base import client_patterns , interactive_auth_handler
32
33
from synapse .rest .client .models import AuthenticationData
33
34
from synapse .rest .models import RequestBodyModel
@@ -301,6 +302,7 @@ async def on_PUT(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
301
302
302
303
device_id = await self .device_handler .store_dehydrated_device (
303
304
requester .user .to_string (),
305
+ None ,
304
306
submission .device_data .dict (),
305
307
submission .initial_device_display_name ,
306
308
)
@@ -390,6 +392,170 @@ async def on_POST(
390
392
return 200 , msgs
391
393
392
394
395
+ class DehydratedDeviceV2Servlet (RestServlet ):
396
+ """Upload, retrieve, or delete a dehydrated device.
397
+
398
+ GET /org.matrix.msc3814.v1/dehydrated_device
399
+
400
+ HTTP/1.1 200 OK
401
+ Content-Type: application/json
402
+
403
+ {
404
+ "device_id": "dehydrated_device_id",
405
+ "device_data": {
406
+ "algorithm": "org.matrix.msc2697.v1.dehydration.v1.olm",
407
+ "account": "dehydrated_device"
408
+ }
409
+ }
410
+
411
+ PUT /org.matrix.msc3814.v1/dehydrated_device
412
+ Content-Type: application/json
413
+
414
+ {
415
+ "device_id": "dehydrated_device_id",
416
+ "device_data": {
417
+ "algorithm": "org.matrix.msc2697.v1.dehydration.v1.olm",
418
+ "account": "dehydrated_device"
419
+ },
420
+ "device_keys": {
421
+ "user_id": "<user_id>",
422
+ "device_id": "<device_id>",
423
+ "valid_until_ts": <millisecond_timestamp>,
424
+ "algorithms": [
425
+ "m.olm.curve25519-aes-sha2",
426
+ ]
427
+ "keys": {
428
+ "<algorithm>:<device_id>": "<key_base64>",
429
+ },
430
+ "signatures:" {
431
+ "<user_id>" {
432
+ "<algorithm>:<device_id>": "<signature_base64>"
433
+ }
434
+ }
435
+ },
436
+ "fallback_keys": {
437
+ "<algorithm>:<device_id>": "<key_base64>",
438
+ "signed_<algorithm>:<device_id>": {
439
+ "fallback": true,
440
+ "key": "<key_base64>",
441
+ "signatures": {
442
+ "<user_id>": {
443
+ "<algorithm>:<device_id>": "<key_base64>"
444
+ }
445
+ }
446
+ }
447
+ }
448
+ "one_time_keys": {
449
+ "<algorithm>:<key_id>": "<key_base64>"
450
+ },
451
+
452
+ }
453
+
454
+ HTTP/1.1 200 OK
455
+ Content-Type: application/json
456
+
457
+ {
458
+ "device_id": "dehydrated_device_id"
459
+ }
460
+
461
+ DELETE /org.matrix.msc3814.v1/dehydrated_device
462
+
463
+ HTTP/1.1 200 OK
464
+ Content-Type: application/json
465
+
466
+ {
467
+ "device_id": "dehydrated_device_id",
468
+ }
469
+ """
470
+
471
+ PATTERNS = [
472
+ * client_patterns ("/org.matrix.msc3814.v1/dehydrated_device$" , releases = ()),
473
+ ]
474
+
475
+ def __init__ (self , hs : "HomeServer" ):
476
+ super ().__init__ ()
477
+ self .hs = hs
478
+ self .auth = hs .get_auth ()
479
+ handler = hs .get_device_handler ()
480
+ assert isinstance (handler , DeviceHandler )
481
+ self .e2e_keys_handler = hs .get_e2e_keys_handler ()
482
+ self .device_handler = handler
483
+
484
+ if hs .config .worker .worker_app is None :
485
+ # if main process
486
+ self .key_uploader = self .e2e_keys_handler .upload_keys_for_user
487
+ else :
488
+ # then a worker
489
+ self .key_uploader = ReplicationUploadKeysForUserRestServlet .make_client (hs )
490
+
491
+ async def on_GET (self , request : SynapseRequest ) -> Tuple [int , JsonDict ]:
492
+ requester = await self .auth .get_user_by_req (request )
493
+
494
+ dehydrated_device = await self .device_handler .get_dehydrated_device (
495
+ requester .user .to_string ()
496
+ )
497
+
498
+ if dehydrated_device is not None :
499
+ (device_id , device_data ) = dehydrated_device
500
+ result = {"device_id" : device_id , "device_data" : device_data }
501
+ return 200 , result
502
+ else :
503
+ raise errors .NotFoundError ("No dehydrated device available" )
504
+
505
+ async def on_DELETE (self , request : SynapseRequest ) -> Tuple [int , JsonDict ]:
506
+ requester = await self .auth .get_user_by_req (request )
507
+
508
+ dehydrated_device = await self .device_handler .get_dehydrated_device (
509
+ requester .user .to_string ()
510
+ )
511
+
512
+ if dehydrated_device is not None :
513
+ (device_id , device_data ) = dehydrated_device
514
+
515
+ result = await self .device_handler .rehydrate_device (
516
+ requester .user .to_string (),
517
+ self .auth .get_access_token_from_request (request ),
518
+ device_id ,
519
+ )
520
+
521
+ result = {"device_id" : device_id }
522
+
523
+ return 200 , result
524
+ else :
525
+ raise errors .NotFoundError ("No dehydrated device available" )
526
+
527
+ class PutBody (RequestBodyModel ):
528
+ device_data : DehydratedDeviceDataModel
529
+ device_id : Optional [StrictStr ]
530
+ initial_device_display_name : Optional [StrictStr ]
531
+
532
+ class Config :
533
+ extra = Extra .allow
534
+
535
+ async def on_PUT (self , request : SynapseRequest ) -> Tuple [int , JsonDict ]:
536
+ submission = parse_and_validate_json_object_from_request (request , self .PutBody )
537
+ requester = await self .auth .get_user_by_req (request )
538
+ user_id = requester .user .to_string ()
539
+
540
+ # TODO: Those two operations, creating a device and storing the
541
+ # device's keys should be atomic.
542
+ device_id = await self .device_handler .store_dehydrated_device (
543
+ requester .user .to_string (),
544
+ submission .device_id ,
545
+ submission .device_data .dict (),
546
+ submission .initial_device_display_name ,
547
+ )
548
+
549
+ # TODO: Do we need to do something with the result here?
550
+ await self .key_uploader (
551
+ user_id = user_id ,
552
+ device_id = submission .device_id ,
553
+ keys = submission .dict ()
554
+ )
555
+
556
+ return 200 , {"device_id" : device_id }
557
+
558
+
393
559
def register_servlets (hs : "HomeServer" , http_server : HttpServer ) -> None :
394
560
if (
395
561
hs .config .worker .worker_app is None
@@ -404,5 +570,5 @@ def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
404
570
DehydratedDeviceServlet (hs , msc2697 = True ).register (http_server )
405
571
ClaimDehydratedDeviceServlet (hs ).register (http_server )
406
572
if hs .config .experimental .msc3814_enabled :
407
- DehydratedDeviceServlet (hs , msc2697 = False ).register (http_server )
573
+ DehydratedDeviceV2Servlet (hs ).register (http_server )
408
574
DehydratedDeviceEventsServlet (hs ).register (http_server )
0 commit comments