@@ -11,6 +11,7 @@ mod tests {
1111 use crate :: video:: { encrypt_video_file, decrypt_video_file,
1212 encrypt_thumbnail_file, decrypt_thumbnail_file} ;
1313 use crate :: thumbnail_meta_info:: ThumbnailMetaInfo ;
14+ use openmls:: prelude:: QueuedProposal ;
1415 use std:: fs:: { self , File } ;
1516 use std:: io;
1617 use std:: io:: { Read , Write } ;
@@ -587,14 +588,14 @@ mod tests {
587588 assert ! ( msg == msg_dec) ;
588589 }
589590
590- /// This function is a complete, successful pairing process with built-in secrets.
591+ /// This function is a complete, successful pairing process with the first
592+ /// secondary app (app2) with built-in secrets.
591593 /// It is used in other tests.
592- fn pair_with_two_more_apps (
594+ fn pair_with_app2 (
593595 camera : & mut MlsClient ,
594596 app : & mut MlsClient ,
595- ) -> ( MlsClient , MlsClient ) {
597+ ) -> MlsClient {
596598 fs:: create_dir ( "test_data/app2" ) . unwrap ( ) ;
597- fs:: create_dir ( "test_data/app3" ) . unwrap ( ) ;
598599
599600 // Add the second app
600601 let mut app2 = MlsClient :: new (
@@ -616,15 +617,28 @@ mod tests {
616617 let ( welcome_msg_vec, psk_proposal_vec, commit_msg_vec) = camera
617618 . invite_with_secret ( & camera_contact, new_secret. clone ( ) ) . unwrap ( ) ;
618619 camera. save_group_state ( ) . unwrap ( ) ;
620+ let update_proposals = camera. get_update_proposals ( ) . unwrap ( ) ;
619621
620622 app2. process_welcome_with_secret ( app2_contact, welcome_msg_vec, new_secret. clone ( ) , GROUP_NAME ) . unwrap ( ) ;
621623 app2. save_group_state ( ) . unwrap ( ) ;
622624
623625 // App merges the psk_proposal and commit for the add operation
626+ app. store_update_proposals ( update_proposals) . unwrap ( ) ;
624627 app. decrypt ( psk_proposal_vec, false ) . unwrap ( ) ;
625628 app. decrypt_with_secret ( commit_msg_vec, false , new_secret) . unwrap ( ) ;
626629 app. save_group_state ( ) . unwrap ( ) ;
627630
631+ app2
632+ }
633+
634+ /// This function is the first step of adding the second secondary app (app3).
635+ /// It is used in other tests.
636+ fn pair_with_app3_handshake (
637+ camera : & mut MlsClient ,
638+ app : & mut MlsClient ,
639+ ) -> ( MlsClient , Vec < u8 > , Vec < u8 > , Vec < QueuedProposal > ) {
640+ fs:: create_dir ( "test_data/app3" ) . unwrap ( ) ;
641+
628642 // Add the third app
629643 let mut app3 = MlsClient :: new (
630644 "app3" . to_string ( ) ,
@@ -641,21 +655,49 @@ mod tests {
641655
642656 let new_secret = vec ! [ 3u8 ; NUM_SECRET_BYTES ] ;
643657
658+ let update_proposals = camera. get_update_proposals ( ) . unwrap ( ) ;
644659 let ( welcome_msg_vec, psk_proposal_vec, commit_msg_vec) = camera
645660 . invite_with_secret ( & camera_contact, new_secret. clone ( ) ) . unwrap ( ) ;
646661 camera. save_group_state ( ) . unwrap ( ) ;
647662
648663 app3. process_welcome_with_secret ( app3_contact, welcome_msg_vec, new_secret. clone ( ) , GROUP_NAME ) . unwrap ( ) ;
649664 app3. save_group_state ( ) . unwrap ( ) ;
650665
666+ app. store_update_proposals ( update_proposals. clone ( ) ) . unwrap ( ) ;
651667 app. decrypt ( psk_proposal_vec. clone ( ) , false ) . unwrap ( ) ;
652668 app. decrypt_with_secret ( commit_msg_vec. clone ( ) , false , new_secret. clone ( ) ) . unwrap ( ) ;
653669 app. save_group_state ( ) . unwrap ( ) ;
670+
671+ ( app3, psk_proposal_vec, commit_msg_vec, update_proposals)
672+ }
673+
674+ /// This function is the second step of adding the second secondary app (app3).
675+ /// It is used in other tests.
676+ fn pair_with_app3_inform_app2 (
677+ app2 : & mut MlsClient ,
678+ psk_proposal_vec : Vec < u8 > ,
679+ commit_msg_vec : Vec < u8 > ,
680+ update_proposals : Vec < QueuedProposal > ,
681+ ) {
682+ // Must be the same as the one in pair_with_app3_handshake()
683+ let new_secret = vec ! [ 3u8 ; NUM_SECRET_BYTES ] ;
654684
685+ app2. store_update_proposals ( update_proposals) . unwrap ( ) ;
655686 app2. decrypt ( psk_proposal_vec, false ) . unwrap ( ) ;
656687 app2. decrypt_with_secret ( commit_msg_vec, false , new_secret) . unwrap ( ) ;
657688 app2. save_group_state ( ) . unwrap ( ) ;
689+ }
658690
691+ /// This function is a complete, successful pairing process with built-in secrets.
692+ /// It is used in other tests.
693+ fn pair_with_two_more_apps (
694+ camera : & mut MlsClient ,
695+ app : & mut MlsClient ,
696+ ) -> ( MlsClient , MlsClient ) {
697+ let mut app2 = pair_with_app2 ( camera, app) ;
698+ let ( app3, psk_proposal_vec, commit_msg_vec, update_proposals) = pair_with_app3_handshake ( camera, app) ;
699+ pair_with_app3_inform_app2 ( & mut app2, psk_proposal_vec, commit_msg_vec, update_proposals) ;
700+
659701 ( app2, app3)
660702 }
661703
@@ -1456,4 +1498,150 @@ mod tests {
14561498 check_decrypted_dummy_file ( & dec_thumbnail_pathname, file_size) ;
14571499 }
14581500 }
1501+
1502+ /// The input app generates an update proposal and returns it.
1503+ fn app_update (
1504+ app : & mut MlsClient ,
1505+ ) -> Vec < u8 > {
1506+ let update_proposal = app. update_proposal ( ) . unwrap ( ) ;
1507+ app. save_group_state ( ) . unwrap ( ) ;
1508+
1509+ update_proposal
1510+ }
1511+
1512+ /// Camera receives the update proposal.
1513+ fn camera_receive_update_proposal (
1514+ camera : & mut MlsClient ,
1515+ update_proposal : Vec < u8 > ,
1516+ ) {
1517+ camera. decrypt ( update_proposal, false ) . unwrap ( ) ;
1518+ camera. save_group_state ( ) . unwrap ( ) ;
1519+ }
1520+
1521+ /// Camera receives the update proposal.
1522+ fn camera_receive_update_proposal_ignore_old (
1523+ camera : & mut MlsClient ,
1524+ update_proposal : Vec < u8 > ,
1525+ ) {
1526+ let _ = camera. decrypt ( update_proposal, false ) ;
1527+ camera. save_group_state ( ) . unwrap ( ) ;
1528+ }
1529+
1530+ /// Decrypts an encrypted file and check the decrypted file.
1531+ fn decrypt_and_check_file (
1532+ app : & mut MlsClient ,
1533+ name : & str ,
1534+ enc_video_pathname : & str ,
1535+ file_size : usize ,
1536+ ) {
1537+ // App decrypts video file
1538+ let dir = format ! ( "test_data/{}/videos" , name) ;
1539+ fs:: create_dir_all ( & dir) . unwrap ( ) ;
1540+
1541+ let dec_video_filename = decrypt_video_file (
1542+ app,
1543+ enc_video_pathname,
1544+ ) . unwrap ( ) ;
1545+
1546+ let dec_video_pathname = format ! ( "{}/{}" , dir, dec_video_filename) ;
1547+
1548+ // Check decrypted file
1549+ check_decrypted_dummy_file ( & dec_video_pathname, file_size) ;
1550+ }
1551+
1552+ #[ test]
1553+ /// Functionally, this test is supposed to be similar
1554+ /// to camera_to_more_apps_update_video_test.
1555+ /// However, it is one of the tests that shuffle
1556+ /// the operations to test race conditions that we find.
1557+ /// In this specific test, app3 is added after updates by other apps,
1558+ /// but before a video is encrypted.
1559+ fn camera_to_more_apps_update_video_race_test_1 ( ) {
1560+ let ( mut camera, mut app) = pair ( ) ;
1561+ //let (mut app2, mut app3) = pair_with_two_more_apps(&mut camera, &mut app);
1562+ let mut app2 = pair_with_app2 ( & mut camera, & mut app) ;
1563+
1564+ // app1 update
1565+ let update_proposal = app_update ( & mut app) ;
1566+ camera_receive_update_proposal ( & mut camera, update_proposal) ;
1567+
1568+ // app2 update
1569+ let update_proposal = app_update ( & mut app2) ;
1570+ camera_receive_update_proposal ( & mut camera, update_proposal) ;
1571+
1572+ // Create input video file to be encrypted (all 0's)
1573+ let video_pathname = "test_data/video_file" ;
1574+ let file_size: usize = 96 * 1024 + 135 ;
1575+
1576+ generate_dummy_file ( video_pathname, file_size) ;
1577+
1578+ // Add app3
1579+ let ( mut app3, psk_proposal_vec, commit_msg_vec, update_proposals) = pair_with_app3_handshake ( & mut camera, & mut app) ;
1580+ pair_with_app3_inform_app2 ( & mut app2, psk_proposal_vec, commit_msg_vec, update_proposals) ;
1581+
1582+ // Camera encrypts video file
1583+ let enc_video_pathname = "test_data/enc_video_file" ;
1584+
1585+ encrypt_video_file (
1586+ & mut camera,
1587+ video_pathname,
1588+ enc_video_pathname,
1589+ 0 ,
1590+ ) . unwrap ( ) ;
1591+
1592+ decrypt_and_check_file ( & mut app, "app" , enc_video_pathname, file_size) ;
1593+ decrypt_and_check_file ( & mut app2, "app2" , enc_video_pathname, file_size) ;
1594+ decrypt_and_check_file ( & mut app3, "app3" , enc_video_pathname, file_size) ;
1595+ }
1596+
1597+ #[ test]
1598+ /// Functionally, this test is supposed to be similar
1599+ /// to camera_to_more_apps_update_video_test.
1600+ /// However, it is one of the tests that shuffle
1601+ /// the operations to test race conditions that we find.
1602+ /// In this specific test, app2 is informed of the addition of
1603+ /// app3 after app performs an update.
1604+ fn camera_to_more_apps_update_video_race_test_2 ( ) {
1605+ let ( mut camera, mut app) = pair ( ) ;
1606+ //let (mut app2, mut app3) = pair_with_two_more_apps(&mut camera, &mut app);
1607+ let mut app2 = pair_with_app2 ( & mut camera, & mut app) ;
1608+ let ( mut app3, psk_proposal_vec, commit_msg_vec, update_proposals) = pair_with_app3_handshake ( & mut camera, & mut app) ;
1609+
1610+ // app1 update
1611+ let update_proposal = app_update ( & mut app) ;
1612+ camera_receive_update_proposal ( & mut camera, update_proposal) ;
1613+
1614+ // app2 update
1615+ // NOTE: diagnosis: update generated by app2 is on an old epoch.
1616+ // This is currently prevented by fetching config response before generating a new heartbeat.
1617+ // Can there be a race condition there? What if config response hasn't been submitted yet?
1618+ let update_proposal = app_update ( & mut app2) ;
1619+
1620+ pair_with_app3_inform_app2 ( & mut app2, psk_proposal_vec, commit_msg_vec, update_proposals) ;
1621+ camera_receive_update_proposal_ignore_old ( & mut camera, update_proposal) ;
1622+
1623+ // app3 update
1624+ let update_proposal = app_update ( & mut app3) ;
1625+ camera_receive_update_proposal ( & mut camera, update_proposal) ;
1626+
1627+ // Create input video file to be encrypted (all 0's)
1628+ let video_pathname = "test_data/video_file" ;
1629+ let file_size: usize = 96 * 1024 + 135 ;
1630+
1631+ generate_dummy_file ( video_pathname, file_size) ;
1632+
1633+ // Camera encrypts video file
1634+ let enc_video_pathname = "test_data/enc_video_file" ;
1635+
1636+ encrypt_video_file (
1637+ & mut camera,
1638+ video_pathname,
1639+ enc_video_pathname,
1640+ 0 ,
1641+ ) . unwrap ( ) ;
1642+
1643+ decrypt_and_check_file ( & mut app, "app" , enc_video_pathname, file_size) ;
1644+ decrypt_and_check_file ( & mut app2, "app2" , enc_video_pathname, file_size) ;
1645+ decrypt_and_check_file ( & mut app3, "app3" , enc_video_pathname, file_size) ;
1646+ }
14591647}
0 commit comments