@@ -21,21 +21,23 @@ use matrix_sdk::{
2121 config:: RequestConfig ,
2222 encryption:: {
2323 backups:: { futures:: SteadyStateError , BackupState , UploadState } ,
24+ secret_storage:: SecretStore ,
2425 BackupDownloadStrategy , EncryptionSettings ,
2526 } ,
2627 matrix_auth:: { MatrixSession , MatrixSessionTokens } ,
2728 test_utils:: { no_retry_test_client_with_server, test_client_builder_with_server} ,
2829 Client ,
2930} ;
3031use matrix_sdk_base:: SessionMeta ;
32+ use matrix_sdk_common:: timeout:: timeout;
3133use matrix_sdk_test:: { async_test, JoinedRoomBuilder , SyncResponseBuilder } ;
3234use ruma:: {
3335 api:: client:: room:: create_room:: v3:: Request as CreateRoomRequest ,
3436 assign, device_id, event_id,
3537 events:: room:: message:: { RoomMessageEvent , RoomMessageEventContent } ,
36- room_id, user_id, TransactionId ,
38+ room_id, user_id, EventId , RoomId , TransactionId ,
3739} ;
38- use serde_json:: json;
40+ use serde_json:: { json, Value } ;
3941use tempfile:: tempdir;
4042use tokio:: spawn;
4143use wiremock:: {
@@ -896,32 +898,18 @@ async fn enable_from_secret_storage() {
896898
897899 client. sync_once ( Default :: default ( ) ) . await . expect ( "We should be able to sync with the server" ) ;
898900
899- Mock :: given ( method ( "GET" ) )
900- . and ( path ( "_matrix/client/r0/rooms/!DovneieKSTkdHKpIXy:morpheus.localhost/event/$JbFHtZpEJiH8uaajZjPLz0QUZc1xtBR9rPGBOjF6WFM" ) )
901- . and ( header ( "authorization" , "Bearer 1234" ) )
902- . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
903- "content" : {
904- "algorithm" : "m.megolm.v1.aes-sha2" ,
905- "ciphertext" : "AwgAEpABhetEzzZzyYrxtEVUtlJnZtJcURBlQUQJ9irVeklCTs06LwgTMQj61PMUS4Vy\
906- YOX+PD67+hhU40/8olOww+Ud0m2afjMjC3wFX+4fFfSkoWPVHEmRVucfcdSF1RSB4EmK\
907- PIP4eo1X6x8kCIMewBvxl2sI9j4VNvDvAN7M3zkLJfFLOFHbBviI4FN7hSFHFeM739Zg\
908- iwxEs3hIkUXEiAfrobzaMEM/zY7SDrTdyffZndgJo7CZOVhoV6vuaOhmAy4X2t4UnbuV\
909- JGJjKfV57NAhp8W+9oT7ugwO",
910- "device_id" : "KIUVQQSDTM" ,
911- "sender_key" : "LvryVyoCjdONdBCi2vvoSbI34yTOx7YrCFACUEKoXnc" ,
912- "session_id" : "64H7XKokIx0ASkYDHZKlT5zd/Zccz/cQspPNdvnNULA"
913- } ,
914- "event_id" : "$JbFHtZpEJiH8uaajZjPLz0QUZc1xtBR9rPGBOjF6WFM" ,
915- "origin_server_ts" : 1698579035927u64 ,
916- "sender" : "@example2:morpheus.localhost" ,
917- "type" : "m.room.encrypted" ,
918- "unsigned" : {
919- "age" : 14393491
920- }
921- } ) ) )
922- . expect ( 2 )
923- . mount ( & server)
924- . await ;
901+ let event_content = json ! ( {
902+ "algorithm" : "m.megolm.v1.aes-sha2" ,
903+ "ciphertext" : "AwgAEpABhetEzzZzyYrxtEVUtlJnZtJcURBlQUQJ9irVeklCTs06LwgTMQj61PMUS4Vy\
904+ YOX+PD67+hhU40/8olOww+Ud0m2afjMjC3wFX+4fFfSkoWPVHEmRVucfcdSF1RSB4EmK\
905+ PIP4eo1X6x8kCIMewBvxl2sI9j4VNvDvAN7M3zkLJfFLOFHbBviI4FN7hSFHFeM739Zg\
906+ iwxEs3hIkUXEiAfrobzaMEM/zY7SDrTdyffZndgJo7CZOVhoV6vuaOhmAy4X2t4UnbuV\
907+ JGJjKfV57NAhp8W+9oT7ugwO",
908+ "device_id" : "KIUVQQSDTM" ,
909+ "sender_key" : "LvryVyoCjdONdBCi2vvoSbI34yTOx7YrCFACUEKoXnc" ,
910+ "session_id" : "64H7XKokIx0ASkYDHZKlT5zd/Zccz/cQspPNdvnNULA"
911+ } ) ;
912+ mock_get_event ( room_id, event_id, event_content, & server) . await ;
925913
926914 let room = client. get_room ( room_id) . expect ( "We should have access to the room after the sync" ) ;
927915 let event = room. event ( event_id) . await . expect ( "We should be able to fetch our encrypted event" ) ;
@@ -940,22 +928,7 @@ async fn enable_from_secret_storage() {
940928 . await
941929 . expect ( "We should be able to open our secret store" ) ;
942930
943- Mock :: given ( method ( "GET" ) )
944- . and ( path ( "_matrix/client/r0/room_keys/version" ) )
945- . and ( header ( "authorization" , "Bearer 1234" ) )
946- . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
947- "algorithm" : "m.megolm_backup.v1.curve25519-aes-sha2" ,
948- "auth_data" : {
949- "public_key" : "hdx5rSn94rBuvJI5cwnhKAVmFyZgfJjk7vwEBD6mIHc" ,
950- "signatures" : { }
951- } ,
952- "count" : 1 ,
953- "etag" : "1" ,
954- "version" : "6"
955- } ) ) )
956- . expect ( 2 )
957- . mount ( & server)
958- . await ;
931+ mock_query_key_backup ( & server) . await ;
959932
960933 Mock :: given ( method ( "GET" ) )
961934 . and ( path ( "_matrix/client/r0/room_keys/keys" ) )
@@ -1032,8 +1005,6 @@ async fn enable_from_secret_storage() {
10321005
10331006#[ async_test]
10341007async fn enable_from_secret_storage_no_existing_backup ( ) {
1035- const SECRET_STORE_KEY : & str = "mypassphrase" ;
1036- const KEY_ID : & str = "yJWwBm2Ts8jHygTBslKpABFyykavhhfA" ;
10371008 let user_id = user_id ! ( "@example2:morpheus.localhost" ) ;
10381009
10391010 let session = MatrixSession {
@@ -1054,15 +1025,7 @@ async fn enable_from_secret_storage_no_existing_backup() {
10541025
10551026 client. restore_session ( session) . await . unwrap ( ) ;
10561027
1057- mock_secret_store_with_backup_key ( user_id, KEY_ID , & server) . await ;
1058-
1059- let secret_storage = client. encryption ( ) . secret_storage ( ) ;
1060-
1061- let store = secret_storage
1062- . open_secret_store ( SECRET_STORE_KEY )
1063- . await
1064- . expect ( "We should be able to open our secret store" ) ;
1065-
1028+ let store = init_secret_store ( & client, & server) . await ;
10661029 store. import_secrets ( ) . await . expect_err (
10671030 "We should return an error if we couldn't fetch the backup version from the server" ,
10681031 ) ;
@@ -1085,8 +1048,6 @@ async fn enable_from_secret_storage_no_existing_backup() {
10851048
10861049#[ async_test]
10871050async fn enable_from_secret_storage_mismatched_key ( ) {
1088- const SECRET_STORE_KEY : & str = "mypassphrase" ;
1089- const KEY_ID : & str = "yJWwBm2Ts8jHygTBslKpABFyykavhhfA" ;
10901051 let user_id = user_id ! ( "@example2:morpheus.localhost" ) ;
10911052
10921053 let session = MatrixSession {
@@ -1107,14 +1068,7 @@ async fn enable_from_secret_storage_mismatched_key() {
11071068
11081069 client. restore_session ( session) . await . unwrap ( ) ;
11091070
1110- mock_secret_store_with_backup_key ( user_id, KEY_ID , & server) . await ;
1111-
1112- let secret_storage = client. encryption ( ) . secret_storage ( ) ;
1113-
1114- let store = secret_storage
1115- . open_secret_store ( SECRET_STORE_KEY )
1116- . await
1117- . expect ( "We should be able to open our secret store" ) ;
1071+ let store = init_secret_store ( & client, & server) . await ;
11181072
11191073 Mock :: given ( method ( "GET" ) )
11201074 . and ( path ( "_matrix/client/r0/room_keys/version" ) )
@@ -1146,8 +1100,6 @@ async fn enable_from_secret_storage_mismatched_key() {
11461100
11471101#[ async_test]
11481102async fn enable_from_secret_storage_manual_download ( ) {
1149- const SECRET_STORE_KEY : & str = "mypassphrase" ;
1150- const KEY_ID : & str = "yJWwBm2Ts8jHygTBslKpABFyykavhhfA" ;
11511103 let user_id = user_id ! ( "@example2:morpheus.localhost" ) ;
11521104
11531105 let session = MatrixSession {
@@ -1160,14 +1112,7 @@ async fn enable_from_secret_storage_manual_download() {
11601112
11611113 client. restore_session ( session) . await . unwrap ( ) ;
11621114
1163- mock_secret_store_with_backup_key ( user_id, KEY_ID , & server) . await ;
1164-
1165- let secret_storage = client. encryption ( ) . secret_storage ( ) ;
1166-
1167- let store = secret_storage
1168- . open_secret_store ( SECRET_STORE_KEY )
1169- . await
1170- . expect ( "We should be able to open our secret store" ) ;
1115+ let store = init_secret_store ( & client, & server) . await ;
11711116
11721117 Mock :: given ( method ( "GET" ) )
11731118 . and ( path ( "_matrix/client/r0/room_keys/version" ) )
@@ -1186,9 +1131,6 @@ async fn enable_from_secret_storage_manual_download() {
11861131
11871132#[ async_test]
11881133async fn enable_from_secret_storage_and_manual_download ( ) {
1189- const SECRET_STORE_KEY : & str = "mypassphrase" ;
1190- const KEY_ID : & str = "yJWwBm2Ts8jHygTBslKpABFyykavhhfA" ;
1191-
11921134 let user_id = user_id ! ( "@example2:morpheus.localhost" ) ;
11931135 let room_id = room_id ! ( "!DovneieKSTkdHKpIXy:morpheus.localhost" ) ;
11941136
@@ -1210,33 +1152,7 @@ async fn enable_from_secret_storage_and_manual_download() {
12101152
12111153 client. restore_session ( session) . await . unwrap ( ) ;
12121154
1213- mock_secret_store_with_backup_key ( user_id, KEY_ID , & server) . await ;
1214-
1215- let secret_storage = client. encryption ( ) . secret_storage ( ) ;
1216-
1217- let store = secret_storage
1218- . open_secret_store ( SECRET_STORE_KEY )
1219- . await
1220- . expect ( "We should be able to open our secret store" ) ;
1221-
1222- Mock :: given ( method ( "GET" ) )
1223- . and ( path ( "_matrix/client/r0/room_keys/version" ) )
1224- . and ( header ( "authorization" , "Bearer 1234" ) )
1225- . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
1226- "algorithm" : "m.megolm_backup.v1.curve25519-aes-sha2" ,
1227- "auth_data" : {
1228- "public_key" : "hdx5rSn94rBuvJI5cwnhKAVmFyZgfJjk7vwEBD6mIHc" ,
1229- "signatures" : { }
1230- } ,
1231- "count" : 1 ,
1232- "etag" : "1" ,
1233- "version" : "6"
1234- } ) ) )
1235- . expect ( 1 )
1236- . mount ( & server)
1237- . await ;
1238-
1239- store. import_secrets ( ) . await . unwrap ( ) ;
1155+ init_client_secret_storage_and_backup ( & client, & server) . await ;
12401156
12411157 Mock :: given ( method ( "GET" ) )
12421158 . and ( path ( "/_matrix/client/r0/room_keys/keys/!DovneieKSTkdHKpIXy:morpheus.localhost" ) )
@@ -1336,9 +1252,6 @@ async fn enable_from_secret_storage_and_manual_download() {
13361252
13371253#[ async_test]
13381254async fn enable_from_secret_storage_and_download_after_utd ( ) {
1339- const SECRET_STORE_KEY : & str = "mypassphrase" ;
1340- const KEY_ID : & str = "yJWwBm2Ts8jHygTBslKpABFyykavhhfA" ;
1341-
13421255 let user_id = user_id ! ( "@example2:morpheus.localhost" ) ;
13431256 let room_id = room_id ! ( "!DovneieKSTkdHKpIXy:morpheus.localhost" ) ;
13441257 let event_id = event_id ! ( "$JbFHtZpEJiH8uaajZjPLz0QUZc1xtBR9rPGBOjF6WFM" ) ;
@@ -1368,60 +1281,21 @@ async fn enable_from_secret_storage_and_download_after_utd() {
13681281
13691282 client. sync_once ( Default :: default ( ) ) . await . expect ( "We should be able to sync with the server" ) ;
13701283
1371- mock_secret_store_with_backup_key ( user_id, KEY_ID , & server) . await ;
1372-
1373- let secret_storage = client. encryption ( ) . secret_storage ( ) ;
1374-
1375- let store = secret_storage
1376- . open_secret_store ( SECRET_STORE_KEY )
1377- . await
1378- . expect ( "We should be able to open our secret store" ) ;
1379-
1380- Mock :: given ( method ( "GET" ) )
1381- . and ( path ( "_matrix/client/r0/room_keys/version" ) )
1382- . and ( header ( "authorization" , "Bearer 1234" ) )
1383- . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
1384- "algorithm" : "m.megolm_backup.v1.curve25519-aes-sha2" ,
1385- "auth_data" : {
1386- "public_key" : "hdx5rSn94rBuvJI5cwnhKAVmFyZgfJjk7vwEBD6mIHc" ,
1387- "signatures" : { }
1388- } ,
1389- "count" : 1 ,
1390- "etag" : "1" ,
1391- "version" : "6"
1392- } ) ) )
1393- . expect ( 1 )
1394- . mount ( & server)
1395- . await ;
1284+ init_client_secret_storage_and_backup ( & client, & server) . await ;
1285+
1286+ let event_content = json ! ( {
1287+ "algorithm" : "m.megolm.v1.aes-sha2" ,
1288+ "ciphertext" : "AwgAEpABhetEzzZzyYrxtEVUtlJnZtJcURBlQUQJ9irVeklCTs06LwgTMQj61PMUS4Vy\
1289+ YOX+PD67+hhU40/8olOww+Ud0m2afjMjC3wFX+4fFfSkoWPVHEmRVucfcdSF1RSB4EmK\
1290+ PIP4eo1X6x8kCIMewBvxl2sI9j4VNvDvAN7M3zkLJfFLOFHbBviI4FN7hSFHFeM739Zg\
1291+ iwxEs3hIkUXEiAfrobzaMEM/zY7SDrTdyffZndgJo7CZOVhoV6vuaOhmAy4X2t4UnbuV\
1292+ JGJjKfV57NAhp8W+9oT7ugwO",
1293+ "device_id" : "KIUVQQSDTM" ,
1294+ "sender_key" : "LvryVyoCjdONdBCi2vvoSbI34yTOx7YrCFACUEKoXnc" ,
1295+ "session_id" : "64H7XKokIx0ASkYDHZKlT5zd/Zccz/cQspPNdvnNULA"
1296+ } ) ;
13961297
1397- store. import_secrets ( ) . await . unwrap ( ) ;
1398-
1399- Mock :: given ( method ( "GET" ) )
1400- . and ( path ( "_matrix/client/r0/rooms/!DovneieKSTkdHKpIXy:morpheus.localhost/event/$JbFHtZpEJiH8uaajZjPLz0QUZc1xtBR9rPGBOjF6WFM" ) )
1401- . and ( header ( "authorization" , "Bearer 1234" ) )
1402- . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
1403- "content" : {
1404- "algorithm" : "m.megolm.v1.aes-sha2" ,
1405- "ciphertext" : "AwgAEpABhetEzzZzyYrxtEVUtlJnZtJcURBlQUQJ9irVeklCTs06LwgTMQj61PMUS4Vy\
1406- YOX+PD67+hhU40/8olOww+Ud0m2afjMjC3wFX+4fFfSkoWPVHEmRVucfcdSF1RSB4EmK\
1407- PIP4eo1X6x8kCIMewBvxl2sI9j4VNvDvAN7M3zkLJfFLOFHbBviI4FN7hSFHFeM739Zg\
1408- iwxEs3hIkUXEiAfrobzaMEM/zY7SDrTdyffZndgJo7CZOVhoV6vuaOhmAy4X2t4UnbuV\
1409- JGJjKfV57NAhp8W+9oT7ugwO",
1410- "device_id" : "KIUVQQSDTM" ,
1411- "sender_key" : "LvryVyoCjdONdBCi2vvoSbI34yTOx7YrCFACUEKoXnc" ,
1412- "session_id" : "64H7XKokIx0ASkYDHZKlT5zd/Zccz/cQspPNdvnNULA"
1413- } ,
1414- "event_id" : "$JbFHtZpEJiH8uaajZjPLz0QUZc1xtBR9rPGBOjF6WFM" ,
1415- "origin_server_ts" : 1698579035927u64 ,
1416- "sender" : "@example2:morpheus.localhost" ,
1417- "type" : "m.room.encrypted" ,
1418- "unsigned" : {
1419- "age" : 14393491
1420- }
1421- } ) ) )
1422- . expect ( 2 )
1423- . mount ( & server)
1424- . await ;
1298+ mock_get_event ( room_id, event_id, event_content, & server) . await ;
14251299
14261300 Mock :: given ( method ( "GET" ) )
14271301 . and ( path ( "/_matrix/client/r0/room_keys/keys/!DovneieKSTkdHKpIXy:morpheus.localhost/64H7XKokIx0ASkYDHZKlT5zd%2FZccz%2FcQspPNdvnNULA" ) )
@@ -1464,11 +1338,16 @@ async fn enable_from_secret_storage_and_download_after_utd() {
14641338 "We should not be able to decrypt the event right away"
14651339 ) ;
14661340
1467- if let Some ( Ok ( room_keys) ) = room_key_stream. next ( ) . await {
1341+ // Wait for the key to be downloaded from backup.
1342+ {
1343+ let room_keys = timeout ( room_key_stream. next ( ) , std:: time:: Duration :: from_secs ( 5 ) )
1344+ . await
1345+ . expect ( "did not get a room key stream update within 5 seconds" )
1346+ . expect ( "room_key_stream.next() returned None" )
1347+ . expect ( "room_key_stream.next() returned an error" ) ;
1348+
14681349 let ( _, room_key_set) = room_keys. first_key_value ( ) . unwrap ( ) ;
14691350 assert ! ( room_key_set. contains( "64H7XKokIx0ASkYDHZKlT5zd/Zccz/cQspPNdvnNULA" ) ) ;
1470- } else {
1471- panic ! ( "Failed to get an update about room keys being imported from the backup" )
14721351 }
14731352
14741353 let event = room. event ( event_id) . await . expect ( "We should be able to fetch our encrypted event" ) ;
@@ -1481,3 +1360,72 @@ async fn enable_from_secret_storage_and_download_after_utd() {
14811360
14821361 server. verify ( ) . await ;
14831362}
1363+
1364+ /// Set up secret storage, and allow the client to import the backup
1365+ /// decryption key from 4S.
1366+ async fn init_client_secret_storage_and_backup ( client : & Client , server : & wiremock:: MockServer ) {
1367+ let store = init_secret_store ( client, server) . await ;
1368+ mock_query_key_backup ( server) . await ;
1369+ store. import_secrets ( ) . await . unwrap ( ) ;
1370+ }
1371+
1372+ /// Mock the data for secret storage, and use it to set up a `SecretStore`.
1373+ async fn init_secret_store ( client : & Client , server : & wiremock:: MockServer ) -> SecretStore {
1374+ const SECRET_STORE_KEY : & str = "mypassphrase" ;
1375+ const KEY_ID : & str = "yJWwBm2Ts8jHygTBslKpABFyykavhhfA" ;
1376+
1377+ mock_secret_store_with_backup_key ( client. user_id ( ) . unwrap ( ) , KEY_ID , server) . await ;
1378+ client
1379+ . encryption ( )
1380+ . secret_storage ( )
1381+ . open_secret_store ( SECRET_STORE_KEY )
1382+ . await
1383+ . expect ( "We should be able to open our secret store" )
1384+ }
1385+
1386+ /// Add a mock for a `GET /_matrix/client/r0/rooms/{}/event/{}` for the given
1387+ /// room/event ID.
1388+ async fn mock_get_event (
1389+ room_id : & RoomId ,
1390+ event_id : & EventId ,
1391+ event_content_json : Value ,
1392+ server : & wiremock:: MockServer ,
1393+ ) {
1394+ let event_json = json ! ( {
1395+ "content" : event_content_json,
1396+ "event_id" : event_id,
1397+ "origin_server_ts" : 1698579035927u64 ,
1398+ "sender" : "@example2:morpheus.localhost" ,
1399+ "type" : "m.room.encrypted" ,
1400+ "unsigned" : {
1401+ "age" : 14393491
1402+ }
1403+ } ) ;
1404+ Mock :: given ( method ( "GET" ) )
1405+ . and ( path ( format ! ( "_matrix/client/r0/rooms/{}/event/{}" , room_id, event_id) ) )
1406+ . and ( header ( "authorization" , "Bearer 1234" ) )
1407+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( event_json) )
1408+ . expect ( 2 )
1409+ . mount ( server)
1410+ . await ;
1411+ }
1412+
1413+ /// Add a mock for a `GET /_matrix/client/r0/room_keys/version` request; return
1414+ /// some suitable backup data.
1415+ async fn mock_query_key_backup ( server : & wiremock:: MockServer ) {
1416+ Mock :: given ( method ( "GET" ) )
1417+ . and ( path ( "_matrix/client/r0/room_keys/version" ) )
1418+ . and ( header ( "authorization" , "Bearer 1234" ) )
1419+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
1420+ "algorithm" : "m.megolm_backup.v1.curve25519-aes-sha2" ,
1421+ "auth_data" : {
1422+ "public_key" : "hdx5rSn94rBuvJI5cwnhKAVmFyZgfJjk7vwEBD6mIHc" ,
1423+ "signatures" : { }
1424+ } ,
1425+ "count" : 1 ,
1426+ "etag" : "1" ,
1427+ "version" : "6"
1428+ } ) ) )
1429+ . mount ( server)
1430+ . await ;
1431+ }
0 commit comments