@@ -33,6 +33,7 @@ mod v10_to_v11;
3333mod v11_to_v12;
3434mod v12_to_v13;
3535mod v13_to_v14;
36+ mod v14_to_v101;
3637mod v5_to_v7;
3738mod v7;
3839mod v7_to_v8;
@@ -101,7 +102,7 @@ impl Drop for MigrationDb {
101102/// as is version 200, but versions 101-199 are all backwards compatible with
102103/// version 100. In other words, if you divide by 100, you get something
103104/// approaching semver: version 200 is major version 2, minor version 0.
104- const MAX_SUPPORTED_SCHEMA_VERSION : u32 = 99 ;
105+ const MAX_SUPPORTED_SCHEMA_VERSION : u32 = 199 ;
105106
106107/// Open the indexeddb with the given name, upgrading it to the latest version
107108/// of the schema if necessary.
@@ -176,6 +177,15 @@ pub async fn open_and_upgrade_db(
176177 v13_to_v14:: schema_bump ( name) . await ?;
177178 }
178179
180+ if old_version < 100 {
181+ v14_to_v101:: schema_add ( name) . await ?;
182+ }
183+
184+ if old_version < 101 {
185+ v14_to_v101:: data_migrate ( name, serializer) . await ?;
186+ v14_to_v101:: schema_delete ( name) . await ?;
187+ }
188+
179189 // If you add more migrations here, you'll need to update
180190 // `tests::EXPECTED_SCHEMA_VERSION`.
181191
@@ -254,16 +264,18 @@ mod tests {
254264 use indexed_db_futures:: {
255265 database:: VersionChangeEvent , prelude:: * , transaction:: TransactionMode ,
256266 } ;
257- use matrix_sdk_common:: js_tracing:: make_tracing_subscriber;
267+ use matrix_sdk_common:: {
268+ deserialized_responses:: WithheldCode , js_tracing:: make_tracing_subscriber,
269+ } ;
258270 use matrix_sdk_crypto:: {
259271 olm:: { InboundGroupSession , SenderData , SessionKey } ,
260- store:: CryptoStore ,
261- types:: EventEncryptionAlgorithm ,
272+ store:: { types :: RoomKeyWithheldEntry , CryptoStore } ,
273+ types:: { events :: room_key_withheld :: RoomKeyWithheldContent , EventEncryptionAlgorithm } ,
262274 vodozemac:: { Curve25519PublicKey , Curve25519SecretKey , Ed25519PublicKey , Ed25519SecretKey } ,
263275 } ;
264276 use matrix_sdk_store_encryption:: StoreCipher ;
265277 use matrix_sdk_test:: async_test;
266- use ruma:: { room_id, OwnedRoomId , RoomId } ;
278+ use ruma:: { device_id , owned_user_id , room_id, OwnedRoomId , RoomId } ;
267279 use serde:: Serialize ;
268280 use tracing_subscriber:: util:: SubscriberInitExt ;
269281 use wasm_bindgen:: JsValue ;
@@ -278,7 +290,7 @@ mod tests {
278290 wasm_bindgen_test:: wasm_bindgen_test_configure!( run_in_browser) ;
279291
280292 /// The schema version we expect after we open the store.
281- const EXPECTED_SCHEMA_VERSION : u32 = 14 ;
293+ const EXPECTED_SCHEMA_VERSION : u32 = 101 ;
282294
283295 /// Adjust this to test do a more comprehensive perf test
284296 const NUM_RECORDS_FOR_PERF : usize = 2_000 ;
@@ -786,6 +798,89 @@ mod tests {
786798 assert_eq ! ( backup_data. backup_version, Some ( "1" . to_owned( ) ) ) ;
787799 }
788800
801+ /// Test migrating `withheld_sessions` data from store v14 to latest,
802+ /// on a store with encryption disabled.
803+ #[ async_test]
804+ async fn test_v14_v101_migration_unencrypted ( ) {
805+ test_v14_v101_migration_with_cipher ( "test_v101_migration_unencrypted" , None ) . await
806+ }
807+
808+ /// Test migrating `withheld_sessions` data from store v14 to latest,
809+ /// on a store with encryption enabled.
810+ #[ async_test]
811+ async fn test_v14_v101_migration_encrypted ( ) {
812+ let cipher = StoreCipher :: new ( ) . unwrap ( ) ;
813+ test_v14_v101_migration_with_cipher (
814+ "test_v101_migration_encrypted" ,
815+ Some ( Arc :: new ( cipher) ) ,
816+ )
817+ . await ;
818+ }
819+
820+ /// Helper function for `test_v14_v101_migration_{un,}encrypted`: test
821+ /// migrating `withheld_sessions` data from store v14 to store v101.
822+ async fn test_v14_v101_migration_with_cipher (
823+ db_prefix : & str ,
824+ store_cipher : Option < Arc < StoreCipher > > ,
825+ ) {
826+ let serializer = SafeEncodeSerializer :: new ( store_cipher. clone ( ) ) ;
827+
828+ let _ = make_tracing_subscriber ( None ) . try_init ( ) ;
829+ let db_name = format ! ( "{db_prefix:0}::matrix-sdk-crypto" ) ;
830+
831+ // delete the db in case it was used in a previous run
832+ let _ = Database :: delete_by_name ( & db_name) . unwrap ( ) . await . unwrap ( ) ;
833+
834+ let room_id = room_id ! ( "!test:example.com" ) ;
835+ let session_id = "12345" ;
836+
837+ // Given a DB with data in it as it was at v5
838+ {
839+ let db = create_v5_db ( & db_name) . await . unwrap ( ) ;
840+
841+ let txn = db
842+ . transaction ( old_keys:: DIRECT_WITHHELD_INFO )
843+ . with_mode ( TransactionMode :: Readwrite )
844+ . build ( )
845+ . unwrap ( ) ;
846+ let store = txn. object_store ( old_keys:: DIRECT_WITHHELD_INFO ) . unwrap ( ) ;
847+
848+ let sender_key =
849+ Curve25519PublicKey :: from_base64 ( "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA" )
850+ . unwrap ( ) ;
851+
852+ let withheld_entry = RoomKeyWithheldEntry {
853+ sender : owned_user_id ! ( "@alice:example.com" ) ,
854+ content : RoomKeyWithheldContent :: new (
855+ EventEncryptionAlgorithm :: MegolmV1AesSha2 ,
856+ WithheldCode :: Blacklisted ,
857+ room_id. to_owned ( ) ,
858+ session_id. to_owned ( ) ,
859+ sender_key,
860+ device_id ! ( "ABC" ) . to_owned ( ) ,
861+ ) ,
862+ } ;
863+
864+ let key = serializer. encode_key ( old_keys:: DIRECT_WITHHELD_INFO , ( room_id, session_id) ) ;
865+ let value = serializer. serialize_value ( & withheld_entry) . unwrap ( ) ;
866+ store. add ( value) . with_key ( key) . build ( ) . unwrap ( ) ;
867+ txn. commit ( ) . await . unwrap ( ) ;
868+ db. close ( ) ;
869+ }
870+
871+ // When I open a store based on that DB, triggering an upgrade
872+ let store =
873+ IndexeddbCryptoStore :: open_with_store_cipher ( & db_prefix, store_cipher) . await . unwrap ( ) ;
874+
875+ // Then I can read the withheld session settings
876+ let withheld_entry = store
877+ . get_withheld_info ( room_id, session_id)
878+ . await
879+ . unwrap ( )
880+ . expect ( "Should find a withheld entry in migrated data" ) ;
881+ assert_eq ! ( withheld_entry. content. withheld_code( ) , WithheldCode :: Blacklisted )
882+ }
883+
789884 async fn create_v5_db ( name : & str ) -> std:: result:: Result < Database , OpenDbError > {
790885 v0_to_v5:: schema_add ( name) . await ?;
791886 Database :: open ( name) . with_version ( 5u32 ) . build ( ) ?. await
0 commit comments