Update the SDK.

Handles changes that removed support for the sliding sync proxy.
This commit is contained in:
Doug 2025-02-18 10:34:32 +00:00 committed by Doug
parent f77faee981
commit 8c07ee35c4
33 changed files with 229 additions and 309 deletions

View File

@ -67,7 +67,6 @@
09713669577CDA8D012EE380 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 6647C55D93508C7CE9D954A5 /* MatrixRustSDK */; }; 09713669577CDA8D012EE380 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 6647C55D93508C7CE9D954A5 /* MatrixRustSDK */; };
09AAF04B27732046C755D914 /* SoftLogoutViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */; }; 09AAF04B27732046C755D914 /* SoftLogoutViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */; };
09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */; }; 09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */; };
0A0625A271EE5B06D2AAA069 /* HomeScreenSlidingSyncMigrationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4691B8DE1D51DE152680098A /* HomeScreenSlidingSyncMigrationBanner.swift */; };
0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4999B5FD50AED7CB0F590FF8 /* AdvancedSettingsScreenModels.swift */; }; 0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4999B5FD50AED7CB0F590FF8 /* AdvancedSettingsScreenModels.swift */; };
0ACAA31FD0399CEEBA3ECC21 /* UserDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */; }; 0ACAA31FD0399CEEBA3ECC21 /* UserDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */; };
0AD8EF040A60D62F488C18B5 /* KnockRequestProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F957320D0EB7D7B4E30C79D /* KnockRequestProxyMock.swift */; }; 0AD8EF040A60D62F488C18B5 /* KnockRequestProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F957320D0EB7D7B4E30C79D /* KnockRequestProxyMock.swift */; };
@ -1399,6 +1398,7 @@
0B0E0B55E2EE75AF67029924 /* SwipeToReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeToReplyView.swift; sourceTree = "<group>"; }; 0B0E0B55E2EE75AF67029924 /* SwipeToReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeToReplyView.swift; sourceTree = "<group>"; };
0B32BBA8887BD7A5C4ECF16F /* RoomModerationRole.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomModerationRole.swift; sourceTree = "<group>"; }; 0B32BBA8887BD7A5C4ECF16F /* RoomModerationRole.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomModerationRole.swift; sourceTree = "<group>"; };
0B987FC3FDBAA0E1C5AA235C /* PaginationIndicatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationIndicatorRoomTimelineItem.swift; sourceTree = "<group>"; }; 0B987FC3FDBAA0E1C5AA235C /* PaginationIndicatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationIndicatorRoomTimelineItem.swift; sourceTree = "<group>"; };
0BA7D6C94A50428463D09AF0 /* ka */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ka; path = ka.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenViewModel.swift; sourceTree = "<group>"; }; 0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenViewModel.swift; sourceTree = "<group>"; };
0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModel.swift; sourceTree = "<group>"; }; 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModel.swift; sourceTree = "<group>"; };
0BD116096CAA9139B95EEA9C /* UserProfileScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenViewModel.swift; sourceTree = "<group>"; }; 0BD116096CAA9139B95EEA9C /* UserProfileScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenViewModel.swift; sourceTree = "<group>"; };
@ -1694,7 +1694,6 @@
4629710C0337ADD9C8909542 /* ka */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ka; path = ka.lproj/Localizable.strings; sourceTree = "<group>"; }; 4629710C0337ADD9C8909542 /* ka */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ka; path = ka.lproj/Localizable.strings; sourceTree = "<group>"; };
466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenModels.swift; sourceTree = "<group>"; }; 466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenModels.swift; sourceTree = "<group>"; };
467498BEA681758BE2F80826 /* TimelineMediaPreviewDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDetailsView.swift; sourceTree = "<group>"; }; 467498BEA681758BE2F80826 /* TimelineMediaPreviewDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDetailsView.swift; sourceTree = "<group>"; };
4691B8DE1D51DE152680098A /* HomeScreenSlidingSyncMigrationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenSlidingSyncMigrationBanner.swift; sourceTree = "<group>"; };
46A2AD86F7E618F468F6FAF5 /* VoiceMessageRecordingButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecordingButton.swift; sourceTree = "<group>"; }; 46A2AD86F7E618F468F6FAF5 /* VoiceMessageRecordingButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecordingButton.swift; sourceTree = "<group>"; };
46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; }; 46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; };
46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreen.swift; sourceTree = "<group>"; }; 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreen.swift; sourceTree = "<group>"; };
@ -1752,6 +1751,7 @@
52135BD9E0E7A091688F627A /* MessageForwardingScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenModels.swift; sourceTree = "<group>"; }; 52135BD9E0E7A091688F627A /* MessageForwardingScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenModels.swift; sourceTree = "<group>"; };
5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreen.swift; sourceTree = "<group>"; }; 5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreen.swift; sourceTree = "<group>"; };
5281C5CDC4A712265A0B5FBF /* PollRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollRoomTimelineItem.swift; sourceTree = "<group>"; }; 5281C5CDC4A712265A0B5FBF /* PollRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollRoomTimelineItem.swift; sourceTree = "<group>"; };
529513218340CC8419273165 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
52BD6ED18E2EB61E28C340AD /* AttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedString.swift; sourceTree = "<group>"; }; 52BD6ED18E2EB61E28C340AD /* AttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedString.swift; sourceTree = "<group>"; };
52F5EE5DE3B55D59299DB5BC /* AppLockSetupBiometricsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModelTests.swift; sourceTree = "<group>"; }; 52F5EE5DE3B55D59299DB5BC /* AppLockSetupBiometricsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModelTests.swift; sourceTree = "<group>"; };
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewAdapter.swift; sourceTree = "<group>"; }; 53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewAdapter.swift; sourceTree = "<group>"; };
@ -2315,6 +2315,7 @@
C9F893F4A111CB7BA5C96949 /* AppLockSetupBiometricsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModel.swift; sourceTree = "<group>"; }; C9F893F4A111CB7BA5C96949 /* AppLockSetupBiometricsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModel.swift; sourceTree = "<group>"; };
CA28F29C9F93E93CC3C2C715 /* NavigationRootCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRootCoordinator.swift; sourceTree = "<group>"; }; CA28F29C9F93E93CC3C2C715 /* NavigationRootCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRootCoordinator.swift; sourceTree = "<group>"; };
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModelTests.swift; sourceTree = "<group>"; }; CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModelTests.swift; sourceTree = "<group>"; };
CA46BDF38F87118939BDF659 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
CA4F6D7000EDCD187E0989E7 /* PinnedEventsTimelineScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineScreen.swift; sourceTree = "<group>"; }; CA4F6D7000EDCD187E0989E7 /* PinnedEventsTimelineScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineScreen.swift; sourceTree = "<group>"; };
CA89A2DD51B6BBE1DA55E263 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; }; CA89A2DD51B6BBE1DA55E263 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
CA90BD288E5AE6BC643AFDDF /* TemplateScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenCoordinator.swift; sourceTree = "<group>"; }; CA90BD288E5AE6BC643AFDDF /* TemplateScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenCoordinator.swift; sourceTree = "<group>"; };
@ -2409,6 +2410,7 @@
E0FCA0957FAA0E15A9F5579D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Untranslated.stringsdict; sourceTree = "<group>"; }; E0FCA0957FAA0E15A9F5579D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Untranslated.stringsdict; sourceTree = "<group>"; };
E0FF9CB3EFA753277291F609 /* EncryptionResetScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetScreenCoordinator.swift; sourceTree = "<group>"; }; E0FF9CB3EFA753277291F609 /* EncryptionResetScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetScreenCoordinator.swift; sourceTree = "<group>"; };
E10DA51DBC8C7E1460DBCCBD /* UserProfileListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileListRow.swift; sourceTree = "<group>"; }; E10DA51DBC8C7E1460DBCCBD /* UserProfileListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileListRow.swift; sourceTree = "<group>"; };
E157152B11E347F735C3FD6E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = tr; path = tr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
E1573D28C8A9FB6399D0EEFB /* SecureBackupLogoutConfirmationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenCoordinator.swift; sourceTree = "<group>"; }; E1573D28C8A9FB6399D0EEFB /* SecureBackupLogoutConfirmationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenCoordinator.swift; sourceTree = "<group>"; };
E1A5FEF17ED7E6176D922D4F /* RoomDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreen.swift; sourceTree = "<group>"; }; E1A5FEF17ED7E6176D922D4F /* RoomDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreen.swift; sourceTree = "<group>"; };
E1E0B4A34E69BD2132BEC521 /* MessageText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageText.swift; sourceTree = "<group>"; }; E1E0B4A34E69BD2132BEC521 /* MessageText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageText.swift; sourceTree = "<group>"; };
@ -3764,7 +3766,6 @@
05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */, 05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */,
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */, ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */,
C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */, C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */,
4691B8DE1D51DE152680098A /* HomeScreenSlidingSyncMigrationBanner.swift */,
84AF32E4136FD6F159D86C2C /* RoomDirectorySearchView.swift */, 84AF32E4136FD6F159D86C2C /* RoomDirectorySearchView.swift */,
037A5661B26EC6BE068188D7 /* Filters */, 037A5661B26EC6BE068188D7 /* Filters */,
); );
@ -6296,6 +6297,7 @@
ru, ru,
sk, sk,
sv, sv,
tr,
uk, uk,
uz, uz,
"zh-Hans", "zh-Hans",
@ -7077,7 +7079,6 @@
B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */, B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */,
0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */, 0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */,
A10D6CCDE2010C09EEA1A593 /* HomeScreenRoomList.swift in Sources */, A10D6CCDE2010C09EEA1A593 /* HomeScreenRoomList.swift in Sources */,
0A0625A271EE5B06D2AAA069 /* HomeScreenSlidingSyncMigrationBanner.swift in Sources */,
DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */, DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */,
56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */, 56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */,
2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */, 2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */,
@ -7832,6 +7833,7 @@
E5F2B6443D1ED8602F328539 /* ru */, E5F2B6443D1ED8602F328539 /* ru */,
667DD3A9D932D7D9EB380CAA /* sk */, 667DD3A9D932D7D9EB380CAA /* sk */,
0EE9EAF0309A2A1D67D8FAF5 /* sv */, 0EE9EAF0309A2A1D67D8FAF5 /* sv */,
E157152B11E347F735C3FD6E /* tr */,
5F12E996BFBEB43815189ABF /* uk */, 5F12E996BFBEB43815189ABF /* uk */,
DFFB0E7C6D8E190AFA0176DC /* uz */, DFFB0E7C6D8E190AFA0176DC /* uz */,
AB26D5444A4A7E095222DE8B /* zh-Hans */, AB26D5444A4A7E095222DE8B /* zh-Hans */,
@ -7868,6 +7870,7 @@
E8294DB9E95C0C0630418466 /* ru */, E8294DB9E95C0C0630418466 /* ru */,
AD378D580A41E42560C60E9C /* sk */, AD378D580A41E42560C60E9C /* sk */,
ACA11F7F50A4A3887A18CA5A /* sv */, ACA11F7F50A4A3887A18CA5A /* sv */,
529513218340CC8419273165 /* tr */,
ADCB8A232D3A8FB3E16A7303 /* uk */, ADCB8A232D3A8FB3E16A7303 /* uk */,
475EB595D7527E9A8A14043E /* uz */, 475EB595D7527E9A8A14043E /* uz */,
284FEEB0789B8894E52A7F34 /* zh-Hans */, 284FEEB0789B8894E52A7F34 /* zh-Hans */,
@ -7892,6 +7895,7 @@
1D652E78832289CD9EB64488 /* hu */, 1D652E78832289CD9EB64488 /* hu */,
7199693797B66245EF97BCF5 /* id */, 7199693797B66245EF97BCF5 /* id */,
44C314C00533E2C297796B60 /* it */, 44C314C00533E2C297796B60 /* it */,
0BA7D6C94A50428463D09AF0 /* ka */,
E60757AFE04391B43EA568B8 /* nl */, E60757AFE04391B43EA568B8 /* nl */,
997BF045585AF6DB2EBC5755 /* pl */, 997BF045585AF6DB2EBC5755 /* pl */,
A8DF55467ED4CE76B7AE9A33 /* pt */, A8DF55467ED4CE76B7AE9A33 /* pt */,
@ -7900,6 +7904,7 @@
9B7D8D3638864B7482E148CC /* ru */, 9B7D8D3638864B7482E148CC /* ru */,
7D39AF1F659923D77778511E /* sk */, 7D39AF1F659923D77778511E /* sk */,
969694F67E844FCA51F7E051 /* sv */, 969694F67E844FCA51F7E051 /* sv */,
CA46BDF38F87118939BDF659 /* tr */,
D66B5D86A9AB95E0E01BED82 /* uk */, D66B5D86A9AB95E0E01BED82 /* uk */,
FF720BA68256297680980481 /* zh-Hans */, FF720BA68256297680980481 /* zh-Hans */,
0545AC444BEEA89FF8C509FD /* zh-Hant-TW */, 0545AC444BEEA89FF8C509FD /* zh-Hant-TW */,
@ -8521,7 +8526,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = { requirement = {
kind = exactVersion; kind = exactVersion;
version = 25.02.11; version = 25.02.17;
}; };
}; };
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {

View File

@ -149,8 +149,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift", "location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : { "state" : {
"revision" : "cc010fc6971370d1df2c0eb67cc5cfd577465b62", "revision" : "422d7bef3ffd3edcb3e30afb410ee523f5659adc",
"version" : "25.2.11" "version" : "25.2.17"
} }
}, },
{ {

View File

@ -120,6 +120,7 @@
"action_yes" = "Yes"; "action_yes" = "Yes";
"action_yes_try_again" = "Yes, try again"; "action_yes_try_again" = "Yes, try again";
"banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade"; "banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade";
"banner_migrate_to_native_sliding_sync_app_force_logout_title" = "Element X no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later."; "banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.";
"banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app."; "banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_title" = "Upgrade available"; "banner_migrate_to_native_sliding_sync_title" = "Upgrade available";

View File

@ -120,6 +120,7 @@
"action_yes" = "Yes"; "action_yes" = "Yes";
"action_yes_try_again" = "Yes, try again"; "action_yes_try_again" = "Yes, try again";
"banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade"; "banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade";
"banner_migrate_to_native_sliding_sync_app_force_logout_title" = "Element X no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later."; "banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.";
"banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app."; "banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_title" = "Upgrade available"; "banner_migrate_to_native_sliding_sync_title" = "Upgrade available";

View File

@ -44,7 +44,6 @@ final class AppSettings {
case elementCallBaseURLOverride case elementCallBaseURLOverride
// Feature flags // Feature flags
case slidingSyncDiscovery
case publicSearchEnabled case publicSearchEnabled
case fuzzyRoomListSearchEnabled case fuzzyRoomListSearchEnabled
case enableOnlySignedDeviceIsolationMode case enableOnlySignedDeviceIsolationMode
@ -283,10 +282,6 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.fuzzyRoomListSearchEnabled, defaultValue: false, storageType: .userDefaults(store)) @UserPreference(key: UserDefaultsKeys.fuzzyRoomListSearchEnabled, defaultValue: false, storageType: .userDefaults(store))
var fuzzyRoomListSearchEnabled var fuzzyRoomListSearchEnabled
enum SlidingSyncDiscovery: Codable { case proxy, native, forceNative }
@UserPreference(key: UserDefaultsKeys.slidingSyncDiscovery, defaultValue: .native, storageType: .userDefaults(store))
var slidingSyncDiscovery: SlidingSyncDiscovery
@UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store)) @UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
var knockingEnabled var knockingEnabled

View File

@ -230,7 +230,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
} }
private func presentDeveloperOptions() { private func presentDeveloperOptions() {
let coordinator = DeveloperOptionsScreenCoordinator(isUsingNativeSlidingSync: parameters.userSession.clientProxy.slidingSyncVersion == .native) let coordinator = DeveloperOptionsScreenCoordinator()
coordinator.actions coordinator.actions
.sink { [weak self] action in .sink { [weak self] action in

View File

@ -274,6 +274,8 @@ internal enum L10n {
internal static var actionYesTryAgain: String { return L10n.tr("Localizable", "action_yes_try_again") } internal static var actionYesTryAgain: String { return L10n.tr("Localizable", "action_yes_try_again") }
/// Log Out & Upgrade /// Log Out & Upgrade
internal static var bannerMigrateToNativeSlidingSyncAction: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_action") } internal static var bannerMigrateToNativeSlidingSyncAction: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_action") }
/// Element X no longer supports the old protocol. Please log out and log back in to continue using the app.
internal static var bannerMigrateToNativeSlidingSyncAppForceLogoutTitle: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_app_force_logout_title") }
/// Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later. /// Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.
internal static var bannerMigrateToNativeSlidingSyncDescription: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_description") } internal static var bannerMigrateToNativeSlidingSyncDescription: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_description") }
/// Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app. /// Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.

View File

@ -69,10 +69,8 @@ extension ClientProxyMock {
ignoreUserReturnValue = .success(()) ignoreUserReturnValue = .success(())
unignoreUserReturnValue = .success(()) unignoreUserReturnValue = .success(())
needsSlidingSyncMigration = false
slidingSyncVersion = .native slidingSyncVersion = .native
availableSlidingSyncVersionsClosure = {
[]
}
trackRecentlyVisitedRoomReturnValue = .success(()) trackRecentlyVisitedRoomReturnValue = .success(())
recentlyVisitedRoomsReturnValue = .success([]) recentlyVisitedRoomsReturnValue = .success([])

View File

@ -2235,28 +2235,16 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
set(value) { underlyingHomeserver = value } set(value) { underlyingHomeserver = value }
} }
var underlyingHomeserver: String! var underlyingHomeserver: String!
var needsSlidingSyncMigration: Bool {
get { return underlyingNeedsSlidingSyncMigration }
set(value) { underlyingNeedsSlidingSyncMigration = value }
}
var underlyingNeedsSlidingSyncMigration: Bool!
var slidingSyncVersion: SlidingSyncVersion { var slidingSyncVersion: SlidingSyncVersion {
get { return underlyingSlidingSyncVersion } get { return underlyingSlidingSyncVersion }
set(value) { underlyingSlidingSyncVersion = value } set(value) { underlyingSlidingSyncVersion = value }
} }
var underlyingSlidingSyncVersion: SlidingSyncVersion! var underlyingSlidingSyncVersion: SlidingSyncVersion!
var availableSlidingSyncVersionsCallsCount = 0
var availableSlidingSyncVersionsCalled: Bool {
return availableSlidingSyncVersionsCallsCount > 0
}
var availableSlidingSyncVersions: [SlidingSyncVersion] {
get async {
availableSlidingSyncVersionsCallsCount += 1
if let availableSlidingSyncVersionsClosure = availableSlidingSyncVersionsClosure {
return await availableSlidingSyncVersionsClosure()
} else {
return underlyingAvailableSlidingSyncVersions
}
}
}
var underlyingAvailableSlidingSyncVersions: [SlidingSyncVersion]!
var availableSlidingSyncVersionsClosure: (() async -> [SlidingSyncVersion])?
var canDeactivateAccount: Bool { var canDeactivateAccount: Bool {
get { return underlyingCanDeactivateAccount } get { return underlyingCanDeactivateAccount }
set(value) { underlyingCanDeactivateAccount = value } set(value) { underlyingCanDeactivateAccount = value }

View File

@ -27,9 +27,7 @@ extension ClientBuilder {
builder = switch slidingSync { builder = switch slidingSync {
case .restored: builder case .restored: builder
case .discoverProxy: builder.slidingSyncVersionBuilder(versionBuilder: .discoverProxy) case .discover: builder.slidingSyncVersionBuilder(versionBuilder: .discoverNative)
case .discoverNative: builder.slidingSyncVersionBuilder(versionBuilder: .discoverNative)
case .forceNative: builder.slidingSyncVersionBuilder(versionBuilder: .native)
} }
if setupEncryption { if setupEncryption {
@ -58,12 +56,8 @@ extension ClientBuilder {
} }
enum ClientBuilderSlidingSync { enum ClientBuilderSlidingSync {
/// The proxy will be supplied when restoring the Session. /// Sliding sync will be configured when restoring the Session.
case restored case restored
/// A proxy must be discovered whilst building the session. /// Sliding sync must be discovered whilst building the session.
case discoverProxy case discover
/// Native sliding sync must be discovered whilst building the session.
case discoverNative
/// Forces native sliding sync without discovering it.
case forceNative
} }

View File

@ -36,8 +36,6 @@ enum HomeScreenViewAction {
case confirmRecoveryKey case confirmRecoveryKey
case resetEncryption case resetEncryption
case skipRecoveryKeyConfirmation case skipRecoveryKeyConfirmation
case confirmSlidingSyncUpgrade
case skipSlidingSyncUpgrade
case updateVisibleItemRange(Range<Int>) case updateVisibleItemRange(Range<Int>)
case globalSearch case globalSearch
case markRoomAsUnread(roomIdentifier: String) case markRoomAsUnread(roomIdentifier: String)
@ -86,17 +84,12 @@ enum HomeScreenSecurityBannerMode: Equatable {
} }
} }
enum HomeScreenMigrationBannerMode {
case none, show, dismissed
}
struct HomeScreenViewState: BindableState { struct HomeScreenViewState: BindableState {
let userID: String let userID: String
var userDisplayName: String? var userDisplayName: String?
var userAvatarURL: URL? var userAvatarURL: URL?
var securityBannerMode = HomeScreenSecurityBannerMode.none var securityBannerMode = HomeScreenSecurityBannerMode.none
var slidingSyncMigrationBannerMode = HomeScreenMigrationBannerMode.none
var requiresExtraAccountSetup = false var requiresExtraAccountSetup = false

View File

@ -145,11 +145,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
actionsSubject.send(.presentEncryptionResetScreen) actionsSubject.send(.presentEncryptionResetScreen)
case .skipRecoveryKeyConfirmation: case .skipRecoveryKeyConfirmation:
state.securityBannerMode = .dismissed state.securityBannerMode = .dismissed
case .confirmSlidingSyncUpgrade:
appSettings.slidingSyncDiscovery = .native
actionsSubject.send(.logout)
case .skipSlidingSyncUpgrade:
state.slidingSyncMigrationBannerMode = .dismissed
case .updateVisibleItemRange(let range): case .updateVisibleItemRange(let range):
roomSummaryProvider?.updateVisibleRange(range) roomSummaryProvider?.updateVisibleRange(range)
case .startChat: case .startChat:
@ -307,30 +302,18 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
/// Check whether we can inform the user about potential migrations /// Check whether we can inform the user about potential migrations
/// or have him logout as his proxy is no longer available /// or have him logout as his proxy is no longer available
private func checkSlidingSyncMigration() async { private func checkSlidingSyncMigration() async {
// Not logged in with a proxy, don't need to do anything guard userSession.clientProxy.needsSlidingSyncMigration else {
guard userSession.clientProxy.slidingSyncVersion.isProxy else {
return return
} }
let versions = await userSession.clientProxy.availableSlidingSyncVersions // The proxy is no longer supported so a logout is needed.
// Delay setting the alert otherwise it automatically gets dismissed. Same as the crashed last run one
// Native not available, nothing we can do DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
guard versions.contains(.native) else { self.state.bindings.alertInfo = AlertInfo(id: UUID(),
return title: L10n.bannerMigrateToNativeSlidingSyncAppForceLogoutTitle,
} primaryButton: .init(title: L10n.bannerMigrateToNativeSlidingSyncAction) { [weak self] in
self?.actionsSubject.send(.logoutWithoutConfirmation)
if versions.contains(where: \.isProxy) { // Both available, prompt for migration })
state.slidingSyncMigrationBannerMode = .show
} else { // The proxy has been removed and logout is needed
// Delay setting the alert otherwise it automatically gets dismissed. Same as the crashed last run one
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.state.bindings.alertInfo = AlertInfo(id: UUID(),
title: L10n.bannerMigrateToNativeSlidingSyncForceLogoutTitle,
primaryButton: .init(title: L10n.bannerMigrateToNativeSlidingSyncAction) { [weak self] in
self?.appSettings.slidingSyncDiscovery = .native
self?.actionsSubject.send(.logoutWithoutConfirmation)
})
}
} }
} }
@ -460,14 +443,3 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
message: L10n.errorUnknown) message: L10n.errorUnknown)
} }
} }
extension SlidingSyncVersion {
var isProxy: Bool {
switch self {
case .proxy:
return true
default:
return false
}
}
}

View File

@ -119,17 +119,13 @@ struct HomeScreenContent: View {
@ViewBuilder @ViewBuilder
private var topSection: some View { private var topSection: some View {
// An empty VStack causes glitches within the room list // An empty VStack causes glitches within the room list
if context.viewState.shouldShowFilters || if context.viewState.shouldShowFilters || context.viewState.securityBannerMode.isShown {
context.viewState.securityBannerMode.isShown ||
context.viewState.slidingSyncMigrationBannerMode == .show {
VStack(spacing: 0) { VStack(spacing: 0) {
if context.viewState.shouldShowFilters { if context.viewState.shouldShowFilters {
RoomListFiltersView(state: $context.filtersState) RoomListFiltersView(state: $context.filtersState)
} }
if context.viewState.slidingSyncMigrationBannerMode == .show { if case let .show(state) = context.viewState.securityBannerMode {
HomeScreenSlidingSyncMigrationBanner(context: context)
} else if case let .show(state) = context.viewState.securityBannerMode {
HomeScreenRecoveryKeyConfirmationBanner(state: state, context: context) HomeScreenRecoveryKeyConfirmationBanner(state: state, context: context)
} }
} }

View File

@ -1,68 +0,0 @@
//
// Copyright 2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
import SwiftUI
struct HomeScreenSlidingSyncMigrationBanner: View {
var context: HomeScreenViewModel.Context
var body: some View {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .leading, spacing: 4) {
HStack(spacing: 16) {
Text(L10n.bannerMigrateToNativeSlidingSyncTitle)
.font(.compound.bodyLGSemibold)
.foregroundColor(.compound.textPrimary)
Spacer()
Button {
context.send(viewAction: .skipSlidingSyncUpgrade)
} label: {
Image(systemName: "xmark")
.foregroundColor(.compound.iconSecondary)
.frame(width: 12, height: 12)
}
}
Text(L10n.bannerMigrateToNativeSlidingSyncDescription)
.font(.compound.bodyMD)
.foregroundColor(.compound.textSecondary)
}
Button(L10n.bannerMigrateToNativeSlidingSyncAction) {
context.send(viewAction: .confirmSlidingSyncUpgrade)
}
.frame(maxWidth: .infinity)
.buttonStyle(.compound(.primary, size: .medium))
}
.padding(16)
.background(Color.compound.bgSubtleSecondary)
.cornerRadius(14)
.padding(.horizontal, 16)
}
}
struct HomeScreenSlidingSyncMigrationBanner_Previews: PreviewProvider, TestablePreview {
static let viewModel = buildViewModel()
static var previews: some View {
HomeScreenSlidingSyncMigrationBanner(context: viewModel.context)
}
static func buildViewModel() -> HomeScreenViewModel {
let clientProxy = ClientProxyMock(.init())
let userSession = UserSessionMock(.init(clientProxy: clientProxy))
return HomeScreenViewModel(userSession: userSession,
analyticsService: ServiceLocator.shared.analytics,
appSettings: ServiceLocator.shared.settings,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}
}

View File

@ -22,10 +22,9 @@ final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init(isUsingNativeSlidingSync: Bool) { init() {
viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings, viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings,
elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL, elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL)
isUsingNativeSlidingSync: isUsingNativeSlidingSync)
viewModel.actions viewModel.actions
.sink { [weak self] action in .sink { [weak self] action in

View File

@ -13,12 +13,7 @@ enum DeveloperOptionsScreenViewModelAction {
struct DeveloperOptionsScreenViewState: BindableState { struct DeveloperOptionsScreenViewState: BindableState {
let elementCallBaseURL: URL let elementCallBaseURL: URL
let isUsingNativeSlidingSync: Bool
var bindings: DeveloperOptionsScreenViewStateBindings var bindings: DeveloperOptionsScreenViewStateBindings
var slidingSyncFooter: String {
"The method used to configure sliding sync when signing in. Changing this setting has no effect until you sign out.\n\nYour current session is using \(isUsingNativeSlidingSync ? "native sliding sync." : "a sliding sync proxy.")"
}
} }
// periphery: ignore - subscripts are seen as false positive // periphery: ignore - subscripts are seen as false positive
@ -42,7 +37,6 @@ enum DeveloperOptionsScreenViewAction {
protocol DeveloperOptionsProtocol: AnyObject { protocol DeveloperOptionsProtocol: AnyObject {
var logLevel: LogLevel { get set } var logLevel: LogLevel { get set }
var slidingSyncDiscovery: AppSettings.SlidingSyncDiscovery { get set }
var publicSearchEnabled: Bool { get set } var publicSearchEnabled: Bool { get set }
var hideUnreadMessagesBadge: Bool { get set } var hideUnreadMessagesBadge: Bool { get set }
var fuzzyRoomListSearchEnabled: Bool { get set } var fuzzyRoomListSearchEnabled: Bool { get set }

View File

@ -17,9 +17,9 @@ class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, Deve
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL, isUsingNativeSlidingSync: Bool) { init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL) {
let bindings = DeveloperOptionsScreenViewStateBindings(developerOptions: developerOptions) let bindings = DeveloperOptionsScreenViewStateBindings(developerOptions: developerOptions)
let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, isUsingNativeSlidingSync: isUsingNativeSlidingSync, bindings: bindings) let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, bindings: bindings)
super.init(initialViewState: state) super.init(initialViewState: state)
} }

View File

@ -32,18 +32,6 @@ struct DeveloperOptionsScreen: View {
} }
} }
Section {
Picker("Discovery", selection: $context.slidingSyncDiscovery) {
Text("Proxy only").tag(AppSettings.SlidingSyncDiscovery.proxy)
Text("Automatic").tag(AppSettings.SlidingSyncDiscovery.native)
Text("Force Native ⚠️").tag(AppSettings.SlidingSyncDiscovery.forceNative)
}
} header: {
Text("Sliding Sync")
} footer: {
Text(context.viewState.slidingSyncFooter)
}
Section("Room List") { Section("Room List") {
Toggle(isOn: $context.publicSearchEnabled) { Toggle(isOn: $context.publicSearchEnabled) {
Text("Public search") Text("Public search")
@ -175,8 +163,7 @@ private struct LogLevelConfigurationView: View {
struct DeveloperOptionsScreen_Previews: PreviewProvider { struct DeveloperOptionsScreen_Previews: PreviewProvider {
static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings, static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings,
elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL, elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL)
isUsingNativeSlidingSync: true)
static var previews: some View { static var previews: some View {
NavigationStack { NavigationStack {
DeveloperOptionsScreen(context: viewModel.context) DeveloperOptionsScreen(context: viewModel.context)

View File

@ -27,55 +27,25 @@ struct AuthenticationClientBuilder: AuthenticationClientBuilderProtocol {
/// Builds a Client for login using OIDC or password authentication. /// Builds a Client for login using OIDC or password authentication.
func build(homeserverAddress: String) async throws -> ClientProtocol { func build(homeserverAddress: String) async throws -> ClientProtocol {
if appSettings.slidingSyncDiscovery == .forceNative { try await makeClientBuilder().serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
return try await makeClientBuilder(slidingSync: .forceNative).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
}
if appSettings.slidingSyncDiscovery == .native {
do {
return try await makeClientBuilder(slidingSync: .discoverNative).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
} catch {
MXLog.warning("Native sliding sync not available: \(error)")
MXLog.info("Falling back to a sliding sync proxy.")
}
}
return try await makeClientBuilder(slidingSync: .discoverProxy).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
} }
/// Builds a Client, authenticating with the given QR code data. /// Builds a Client, authenticating with the given QR code data.
func buildWithQRCode(qrCodeData: QrCodeData, func buildWithQRCode(qrCodeData: QrCodeData,
oidcConfiguration: OIDCConfigurationProxy, oidcConfiguration: OIDCConfigurationProxy,
progressListener: QrLoginProgressListenerProxy) async throws -> ClientProtocol { progressListener: QrLoginProgressListenerProxy) async throws -> ClientProtocol {
if appSettings.slidingSyncDiscovery == .forceNative { try await makeClientBuilder().buildWithQrCode(qrCodeData: qrCodeData,
return try await makeClientBuilder(slidingSync: .forceNative).buildWithQrCode(qrCodeData: qrCodeData, oidcConfiguration: oidcConfiguration.rustValue,
oidcConfiguration: oidcConfiguration.rustValue, progressListener: progressListener)
progressListener: progressListener)
}
if appSettings.slidingSyncDiscovery == .native {
do {
return try await makeClientBuilder(slidingSync: .discoverNative).buildWithQrCode(qrCodeData: qrCodeData,
oidcConfiguration: oidcConfiguration.rustValue,
progressListener: progressListener)
} catch HumanQrLoginError.SlidingSyncNotAvailable {
MXLog.warning("Native sliding sync not available")
MXLog.info("Falling back to a sliding sync proxy.")
}
}
return try await makeClientBuilder(slidingSync: .discoverProxy).buildWithQrCode(qrCodeData: qrCodeData,
oidcConfiguration: oidcConfiguration.rustValue,
progressListener: progressListener)
} }
// MARK: - Private // MARK: - Private
/// The base builder configuration used for authentication within the app. /// The base builder configuration used for authentication within the app.
private func makeClientBuilder(slidingSync: ClientBuilderSlidingSync) -> ClientBuilder { private func makeClientBuilder() -> ClientBuilder {
ClientBuilder ClientBuilder
.baseBuilder(httpProxy: appSettings.websiteURL.globalProxy, .baseBuilder(httpProxy: appSettings.websiteURL.globalProxy,
slidingSync: slidingSync, slidingSync: .discover,
sessionDelegate: clientSessionDelegate, sessionDelegate: clientSessionDelegate,
appHooks: appHooks, appHooks: appHooks,
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode, enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,

View File

@ -19,7 +19,7 @@ class ClientProxy: ClientProxyProtocol {
private let mediaLoader: MediaLoaderProtocol private let mediaLoader: MediaLoaderProtocol
private let clientQueue: DispatchQueue private let clientQueue: DispatchQueue
private var roomListService: RoomListService? private var roomListService: RoomListService?
// periphery: ignore - only for retain // periphery: ignore - only for retain
private var roomListStateUpdateTaskHandle: TaskHandle? private var roomListStateUpdateTaskHandle: TaskHandle?
@ -135,6 +135,7 @@ class ClientProxy: ClientProxyProtocol {
private let sendQueueStatusSubject = CurrentValueSubject<Bool, Never>(false) private let sendQueueStatusSubject = CurrentValueSubject<Bool, Never>(false)
init(client: ClientProtocol, init(client: ClientProtocol,
needsSlidingSyncMigration: Bool,
networkMonitor: NetworkMonitorProtocol, networkMonitor: NetworkMonitorProtocol,
appSettings: AppSettings) async { appSettings: AppSettings) async {
self.client = client self.client = client
@ -148,6 +149,8 @@ class ClientProxy: ClientProxyProtocol {
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings()) notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings())
secureBackupController = SecureBackupController(encryption: client.encryption()) secureBackupController = SecureBackupController(encryption: client.encryption())
self.needsSlidingSyncMigration = needsSlidingSyncMigration
delegateHandle = client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in delegateHandle = client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in
self?.hasEncounteredAuthError = true self?.hasEncounteredAuthError = true
@ -221,16 +224,11 @@ class ClientProxy: ClientProxyProtocol {
client.homeserver() client.homeserver()
} }
let needsSlidingSyncMigration: Bool
var slidingSyncVersion: SlidingSyncVersion { var slidingSyncVersion: SlidingSyncVersion {
client.slidingSyncVersion() client.slidingSyncVersion()
} }
var availableSlidingSyncVersions: [SlidingSyncVersion] {
get async {
await client.availableSlidingSyncVersions()
}
}
var canDeactivateAccount: Bool { var canDeactivateAccount: Bool {
client.canDeactivateAccount() client.canDeactivateAccount()
} }
@ -263,6 +261,11 @@ class ClientProxy: ClientProxyProtocol {
} }
func startSync() { func startSync() {
guard !needsSlidingSyncMigration else {
MXLog.warning("Ignoring request, this client needs to be migrated to native sliding sync.")
return
}
guard !hasEncounteredAuthError else { guard !hasEncounteredAuthError else {
MXLog.warning("Ignoring request, this client has an unknown token.") MXLog.warning("Ignoring request, this client has an unknown token.")
return return

View File

@ -75,9 +75,11 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
var deviceID: String? { get } var deviceID: String? { get }
var homeserver: String { get } var homeserver: String { get }
// TODO: This is a temporary value, in the future we should throw a migration error
// when decoding a session that contains a sliding sync proxy URL instead of restoring it.
var needsSlidingSyncMigration: Bool { get }
var slidingSyncVersion: SlidingSyncVersion { get } var slidingSyncVersion: SlidingSyncVersion { get }
var availableSlidingSyncVersions: [SlidingSyncVersion] { get async }
var canDeactivateAccount: Bool { get } var canDeactivateAccount: Bool { get }

View File

@ -112,7 +112,8 @@ class KeychainController: KeychainControllerProtocol {
let restorationToken = RestorationToken(session: session, let restorationToken = RestorationToken(session: session,
sessionDirectories: oldToken.sessionDirectories, sessionDirectories: oldToken.sessionDirectories,
passphrase: oldToken.passphrase, passphrase: oldToken.passphrase,
pusherNotificationClientIdentifier: oldToken.pusherNotificationClientIdentifier) pusherNotificationClientIdentifier: oldToken.pusherNotificationClientIdentifier,
slidingSyncProxyURLString: oldToken.slidingSyncProxyURLString)
setRestorationToken(restorationToken, forUsername: session.userId) setRestorationToken(restorationToken, forUsername: session.userId)
} }

View File

@ -14,6 +14,13 @@ struct RestorationToken: Equatable {
let passphrase: String? let passphrase: String?
let pusherNotificationClientIdentifier: String? let pusherNotificationClientIdentifier: String?
/// The sliding sync proxy URL that was previously encoded in the Session.
/// This is temporary to help make a nicer user migration flow. In the future
/// we will throw when decoding sessions with a sliding sync proxy URL.
let slidingSyncProxyURLString: String?
/// Whether the token is for a session that is using the now unsupported sliding sync proxy.
var needsSlidingSyncMigration: Bool { slidingSyncProxyURLString != nil }
enum CodingKeys: CodingKey { enum CodingKeys: CodingKey {
case session case session
case sessionDirectory case sessionDirectory
@ -27,7 +34,7 @@ extension RestorationToken: Codable {
init(from decoder: Decoder) throws { init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
let session = try container.decode(MatrixRustSDK.Session.self, forKey: .session) let sessionWrapper = try container.decode(SessionWrapper.self, forKey: .session)
let dataDirectory = try container.decodeIfPresent(URL.self, forKey: .sessionDirectory) let dataDirectory = try container.decodeIfPresent(URL.self, forKey: .sessionDirectory)
let cacheDirectory = try container.decodeIfPresent(URL.self, forKey: .cacheDirectory) let cacheDirectory = try container.decodeIfPresent(URL.self, forKey: .cacheDirectory)
@ -38,18 +45,19 @@ extension RestorationToken: Codable {
SessionDirectories(dataDirectory: dataDirectory) SessionDirectories(dataDirectory: dataDirectory)
} }
} else { } else {
SessionDirectories(userID: session.userId) SessionDirectories(userID: sessionWrapper.session.userId)
} }
self = try .init(session: session, self = try .init(session: sessionWrapper.session,
sessionDirectories: sessionDirectories, sessionDirectories: sessionDirectories,
passphrase: container.decodeIfPresent(String.self, forKey: .passphrase), passphrase: container.decodeIfPresent(String.self, forKey: .passphrase),
pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier)) pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier),
slidingSyncProxyURLString: sessionWrapper.slidingSyncProxyURLString)
} }
func encode(to encoder: any Encoder) throws { func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(session, forKey: .session) try container.encode(SessionWrapper(session: session, slidingSyncProxyURLString: slidingSyncProxyURLString), forKey: .session)
try container.encode(sessionDirectories.dataDirectory, forKey: .sessionDirectory) try container.encode(sessionDirectories.dataDirectory, forKey: .sessionDirectory)
try container.encode(sessionDirectories.cacheDirectory, forKey: .cacheDirectory) try container.encode(sessionDirectories.cacheDirectory, forKey: .cacheDirectory)
try container.encode(passphrase, forKey: .passphrase) try container.encode(passphrase, forKey: .passphrase)
@ -57,17 +65,40 @@ extension RestorationToken: Codable {
} }
} }
/// Temporary struct to smooth the forced migration by keeping a user session.
/// In the future we can remove this and throw a migration error when the URL
/// is decoded to a non-nil value.
private struct SessionWrapper {
let session: MatrixRustSDK.Session
let slidingSyncProxyURLString: String?
}
extension SessionWrapper: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: MatrixRustSDK.Session.CodingKeys.self)
session = try Session(from: decoder)
// TODO: In the future we should decode this in the Session and throw a migration error if it contains a value.
slidingSyncProxyURLString = try container.decodeIfPresent(String.self, forKey: .slidingSyncProxy)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: MatrixRustSDK.Session.CodingKeys.self)
try session.encode(to: encoder)
try container.encode(slidingSyncProxyURLString, forKey: .slidingSyncProxy)
}
}
extension MatrixRustSDK.Session: Codable { extension MatrixRustSDK.Session: Codable {
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
let slidingSyncProxy = try container.decodeIfPresent(String.self, forKey: .slidingSyncProxy)
self = try .init(accessToken: container.decode(String.self, forKey: .accessToken), self = try .init(accessToken: container.decode(String.self, forKey: .accessToken),
refreshToken: container.decodeIfPresent(String.self, forKey: .refreshToken), refreshToken: container.decodeIfPresent(String.self, forKey: .refreshToken),
userId: container.decode(String.self, forKey: .userId), userId: container.decode(String.self, forKey: .userId),
deviceId: container.decode(String.self, forKey: .deviceId), deviceId: container.decode(String.self, forKey: .deviceId),
homeserverUrl: container.decode(String.self, forKey: .homeserverUrl), homeserverUrl: container.decode(String.self, forKey: .homeserverUrl),
oidcData: container.decodeIfPresent(String.self, forKey: .oidcData), oidcData: container.decodeIfPresent(String.self, forKey: .oidcData),
slidingSyncVersion: slidingSyncProxy.map { .proxy(url: $0) } ?? .native) slidingSyncVersion: .native)
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
@ -78,17 +109,9 @@ extension MatrixRustSDK.Session: Codable {
try container.encode(deviceId, forKey: .deviceId) try container.encode(deviceId, forKey: .deviceId)
try container.encode(homeserverUrl, forKey: .homeserverUrl) try container.encode(homeserverUrl, forKey: .homeserverUrl)
try container.encode(oidcData, forKey: .oidcData) try container.encode(oidcData, forKey: .oidcData)
try container.encode(slidingSyncVersion.proxyURL, forKey: .slidingSyncProxy)
} }
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case accessToken, refreshToken, userId, deviceId, homeserverUrl, oidcData, slidingSyncProxy case accessToken, refreshToken, userId, deviceId, homeserverUrl, oidcData, slidingSyncProxy
} }
} }
private extension SlidingSyncVersion {
var proxyURL: String? {
guard case let .proxy(url) = self else { return nil }
return url
}
}

View File

@ -64,12 +64,13 @@ class UserSessionStore: UserSessionStoreProtocol {
do { do {
let session = try client.session() let session = try client.session()
let userID = try client.userId() let userID = try client.userId()
let clientProxy = await setupProxyForClient(client) let clientProxy = await setupProxyForClient(client, needsSlidingSyncMigration: false)
keychainController.setRestorationToken(RestorationToken(session: session, keychainController.setRestorationToken(RestorationToken(session: session,
sessionDirectories: sessionDirectories, sessionDirectories: sessionDirectories,
passphrase: passphrase, passphrase: passphrase,
pusherNotificationClientIdentifier: clientProxy.pusherNotificationClientIdentifier), pusherNotificationClientIdentifier: clientProxy.pusherNotificationClientIdentifier,
slidingSyncProxyURLString: nil),
forUsername: userID) forUsername: userID)
MXLog.info("Set up session for user \(userID) at: \(sessionDirectories)") MXLog.info("Set up session for user \(userID) at: \(sessionDirectories)")
@ -145,15 +146,16 @@ class UserSessionStore: UserSessionStoreProtocol {
MXLog.info("Set up session for user \(credentials.userID) at: \(credentials.restorationToken.sessionDirectories)") MXLog.info("Set up session for user \(credentials.userID) at: \(credentials.restorationToken.sessionDirectories)")
return await .success(setupProxyForClient(client)) return await .success(setupProxyForClient(client, needsSlidingSyncMigration: credentials.restorationToken.needsSlidingSyncMigration))
} catch { } catch {
MXLog.error("Failed restoring login with error: \(error)") MXLog.error("Failed restoring login with error: \(error)")
return .failure(.failedRestoringLogin) return .failure(.failedRestoringLogin)
} }
} }
private func setupProxyForClient(_ client: ClientProtocol) async -> ClientProxyProtocol { private func setupProxyForClient(_ client: ClientProtocol, needsSlidingSyncMigration: Bool) async -> ClientProxyProtocol {
await ClientProxy(client: client, await ClientProxy(client: client,
needsSlidingSyncMigration: needsSlidingSyncMigration,
networkMonitor: networkMonitor, networkMonitor: networkMonitor,
appSettings: appSettings) appSettings: appSettings)
} }

View File

@ -22,8 +22,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams", "location" : "https://github.com/jpsim/Yams",
"state" : { "state" : {
"revision" : "db9ff235cf800bc657c3ed0961078fc231d0f28b", "revision" : "2688707e563b44d7d87c29ba6c5ca04ce86ae58b",
"version" : "5.2.0" "version" : "5.3.0"
} }
} }
], ],

View File

@ -275,12 +275,6 @@ extension PreviewTests {
} }
} }
func test_homeScreenSlidingSyncMigrationBanner() async throws {
for preview in HomeScreenSlidingSyncMigrationBanner_Previews._allPreviews {
try await assertSnapshots(matching: preview)
}
}
func test_homeScreen() async throws { func test_homeScreen() async throws {
for preview in HomeScreen_Previews._allPreviews { for preview in HomeScreen_Previews._allPreviews {
try await assertSnapshots(matching: preview) try await assertSnapshots(matching: preview)

View File

@ -30,10 +30,11 @@ class KeychainControllerTests: XCTestCase {
deviceId: "deviceId", deviceId: "deviceId",
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID",
slidingSyncProxyURLString: "https://my.sync.proxy")
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
// Then the restoration token should be stored in the keychain. // Then the restoration token should be stored in the keychain.
@ -49,10 +50,11 @@ class KeychainControllerTests: XCTestCase {
deviceId: "deviceId", deviceId: "deviceId",
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID",
slidingSyncProxyURLString: "https://my.sync.proxy")
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
XCTAssertEqual(keychain.restorationTokens().count, 1, "The keychain should have 1 restoration token.") XCTAssertEqual(keychain.restorationTokens().count, 1, "The keychain should have 1 restoration token.")
XCTAssertEqual(keychain.restorationTokenForUsername(username), restorationToken, "The initial restoration token should match the value that was stored.") XCTAssertEqual(keychain.restorationTokenForUsername(username), restorationToken, "The initial restoration token should match the value that was stored.")
@ -74,10 +76,11 @@ class KeychainControllerTests: XCTestCase {
deviceId: "deviceId", deviceId: "deviceId",
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID",
slidingSyncProxyURLString: "https://my.sync.proxy")
keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com")
} }
XCTAssertEqual(keychain.restorationTokens().count, 5, "The keychain should have 5 restoration tokens.") XCTAssertEqual(keychain.restorationTokens().count, 5, "The keychain should have 5 restoration tokens.")
@ -98,10 +101,11 @@ class KeychainControllerTests: XCTestCase {
deviceId: "deviceId", deviceId: "deviceId",
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID",
slidingSyncProxyURLString: "https://my.sync.proxy")
keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com")
} }
XCTAssertEqual(keychain.restorationTokens().count, 5, "The keychain should have 5 restoration tokens.") XCTAssertEqual(keychain.restorationTokens().count, 5, "The keychain should have 5 restoration tokens.")
@ -133,7 +137,8 @@ class KeychainControllerTests: XCTestCase {
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID",
slidingSyncProxyURLString: nil)
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
// Then decoding the restoration token from the keychain should still work. // Then decoding the restoration token from the keychain should still work.

View File

@ -13,38 +13,42 @@ import MatrixRustSDK
class RestorationTokenTests: XCTestCase { class RestorationTokenTests: XCTestCase {
func testDecodeFromTokenV1() throws { func testDecodeFromTokenV1() throws {
// Given an encoded restoration token in the original format that only contains a Session from the SDK. // Given an encoded restoration token in the original format that only contains a Session from the SDK.
let originalToken = RestorationTokenV1(session: Session(accessToken: "1234", let originalToken = RestorationTokenV1(session: SessionV1(accessToken: "1234",
refreshToken: nil, refreshToken: nil,
userId: "@user:example.com", userId: "@user:example.com",
deviceId: "D3V1C3", deviceId: "D3V1C3",
homeserverUrl: "https://matrix.example.com", homeserverUrl: "https://matrix.example.com",
oidcData: nil, oidcData: nil,
slidingSyncVersion: .proxy(url: "https://sync.example.com"))) slidingSyncVersion: .proxy(url: "https://sync.example.com")))
let data = try JSONEncoder().encode(originalToken) let data = try JSONEncoder().encode(originalToken)
// When decoding the data to the current restoration token format. // When decoding the data to the current restoration token format.
let decodedToken = try JSONDecoder().decode(RestorationToken.self, from: data) let decodedToken = try JSONDecoder().decode(RestorationToken.self, from: data)
// Then the output should be a valid token with the expected store directories. // Then the output should be a valid token with the expected store directories.
XCTAssertEqual(decodedToken.session, originalToken.session, "The session should not be changed.") assertEqual(session: decodedToken.session, originalSession: originalToken.session)
XCTAssertNil(decodedToken.passphrase, "There should not be a passphrase.") XCTAssertNil(decodedToken.passphrase, "There should not be a passphrase.")
XCTAssertNil(decodedToken.pusherNotificationClientIdentifier, "There should not be a push notification client ID.") XCTAssertNil(decodedToken.pusherNotificationClientIdentifier, "There should not be a push notification client ID.")
XCTAssertEqual(decodedToken.sessionDirectories.dataDirectory, .sessionsBaseDirectory.appending(component: "@user_example.com"), XCTAssertEqual(decodedToken.sessionDirectories.dataDirectory, .sessionsBaseDirectory.appending(component: "@user_example.com"),
"The session directory should match the original location set by the Rust SDK from our base directory.") "The session directory should match the original location set by the Rust SDK from our base directory.")
XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, .sessionCachesBaseDirectory.appending(component: "@user_example.com"), XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, .sessionCachesBaseDirectory.appending(component: "@user_example.com"),
"The cache directory should be derived from the session directory but in the caches directory.") "The cache directory should be derived from the session directory but in the caches directory.")
XCTAssertEqual(decodedToken.slidingSyncProxyURLString, "https://sync.example.com",
"The original sliding sync URL should be preserved in order to trigger the migration prompt.")
XCTAssertTrue(decodedToken.needsSlidingSyncMigration, "The migration flag should be set to true.")
} }
func testDecodeFromTokenV4() throws { func testDecodeFromTokenV4() throws {
// Given an encoded restoration token in the 4th format that contains a stored session directory. // Given an encoded restoration token in the 4th format that contains a stored session directory.
let sessionDirectoryName = UUID().uuidString let sessionDirectoryName = UUID().uuidString
let originalToken = RestorationTokenV4(session: Session(accessToken: "1234", let originalToken = RestorationTokenV4(session: SessionV1(accessToken: "1234",
refreshToken: "5678", refreshToken: "5678",
userId: "@user:example.com", userId: "@user:example.com",
deviceId: "D3V1C3", deviceId: "D3V1C3",
homeserverUrl: "https://matrix.example.com", homeserverUrl: "https://matrix.example.com",
oidcData: "data-from-mas", oidcData: "data-from-mas",
slidingSyncVersion: .proxy(url: "https://sync.example.com")), slidingSyncVersion: .proxy(url: "https://sync.example.com")),
sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName), sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusher-identifier") pusherNotificationClientIdentifier: "pusher-identifier")
@ -54,7 +58,7 @@ class RestorationTokenTests: XCTestCase {
let decodedToken = try JSONDecoder().decode(RestorationToken.self, from: data) let decodedToken = try JSONDecoder().decode(RestorationToken.self, from: data)
// Then the output should be a valid token with the expected store directories. // Then the output should be a valid token with the expected store directories.
XCTAssertEqual(decodedToken.session, originalToken.session, "The session should not be changed.") assertEqual(session: decodedToken.session, originalSession: originalToken.session)
XCTAssertEqual(decodedToken.passphrase, originalToken.passphrase, "The passphrase should not be changed.") XCTAssertEqual(decodedToken.passphrase, originalToken.passphrase, "The passphrase should not be changed.")
XCTAssertEqual(decodedToken.pusherNotificationClientIdentifier, originalToken.pusherNotificationClientIdentifier, XCTAssertEqual(decodedToken.pusherNotificationClientIdentifier, originalToken.pusherNotificationClientIdentifier,
"The push notification client identifier should not be changed.") "The push notification client identifier should not be changed.")
@ -62,18 +66,22 @@ class RestorationTokenTests: XCTestCase {
"The session directory should not be changed.") "The session directory should not be changed.")
XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, .sessionCachesBaseDirectory.appending(component: sessionDirectoryName), XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, .sessionCachesBaseDirectory.appending(component: sessionDirectoryName),
"The cache directory should be derived from the session directory but in the caches directory.") "The cache directory should be derived from the session directory but in the caches directory.")
XCTAssertEqual(decodedToken.slidingSyncProxyURLString, "https://sync.example.com",
"The original sliding sync URL should be preserved in order to trigger the migration prompt.")
XCTAssertTrue(decodedToken.needsSlidingSyncMigration, "The migration flag should be set to true.")
} }
func testDecodeFromTokenV5() throws { func testDecodeFromTokenV5() throws {
// Given an encoded restoration token in the 5th format that contains separate directories for session data and caches. // Given an encoded restoration token in the 5th format that contains separate directories for session data and caches.
let sessionDirectoryName = UUID().uuidString let sessionDirectoryName = UUID().uuidString
let originalToken = RestorationTokenV5(session: Session(accessToken: "1234", let originalToken = RestorationTokenV5(session: SessionV1(accessToken: "1234",
refreshToken: "5678", refreshToken: "5678",
userId: "@user:example.com", userId: "@user:example.com",
deviceId: "D3V1C3", deviceId: "D3V1C3",
homeserverUrl: "https://matrix.example.com", homeserverUrl: "https://matrix.example.com",
oidcData: "data-from-mas", oidcData: "data-from-mas",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName), sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName),
cacheDirectory: .sessionCachesBaseDirectory.appending(component: sessionDirectoryName), cacheDirectory: .sessionCachesBaseDirectory.appending(component: sessionDirectoryName),
passphrase: "passphrase", passphrase: "passphrase",
@ -84,7 +92,7 @@ class RestorationTokenTests: XCTestCase {
let decodedToken = try JSONDecoder().decode(RestorationToken.self, from: data) let decodedToken = try JSONDecoder().decode(RestorationToken.self, from: data)
// Then the output should be a valid token. // Then the output should be a valid token.
XCTAssertEqual(decodedToken.session, originalToken.session, "The session should not be changed.") assertEqual(session: decodedToken.session, originalSession: originalToken.session)
XCTAssertEqual(decodedToken.passphrase, originalToken.passphrase, "The passphrase should not be changed.") XCTAssertEqual(decodedToken.passphrase, originalToken.passphrase, "The passphrase should not be changed.")
XCTAssertEqual(decodedToken.pusherNotificationClientIdentifier, originalToken.pusherNotificationClientIdentifier, XCTAssertEqual(decodedToken.pusherNotificationClientIdentifier, originalToken.pusherNotificationClientIdentifier,
"The push notification client identifier should not be changed.") "The push notification client identifier should not be changed.")
@ -92,6 +100,9 @@ class RestorationTokenTests: XCTestCase {
"The session directory should not be changed.") "The session directory should not be changed.")
XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, originalToken.cacheDirectory, XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, originalToken.cacheDirectory,
"The cache directory should not be changed.") "The cache directory should not be changed.")
XCTAssertNil(decodedToken.slidingSyncProxyURLString, "No sliding sync proxy URL should be decoded for native sliding sync.")
XCTAssertFalse(decodedToken.needsSlidingSyncMigration, "The migration flag should not be set.")
} }
func testDecodeFromCurrentToken() throws { func testDecodeFromCurrentToken() throws {
@ -105,7 +116,8 @@ class RestorationTokenTests: XCTestCase {
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectories: .init(), sessionDirectories: .init(),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusher-identifier") pusherNotificationClientIdentifier: "pusher-identifier",
slidingSyncProxyURLString: nil)
let data = try JSONEncoder().encode(originalToken) let data = try JSONEncoder().encode(originalToken)
// When decoding the data. // When decoding the data.
@ -114,23 +126,86 @@ class RestorationTokenTests: XCTestCase {
// Then the output should be a valid token. // Then the output should be a valid token.
XCTAssertEqual(decodedToken, originalToken, "The token should remain identical.") XCTAssertEqual(decodedToken, originalToken, "The token should remain identical.")
} }
func assertEqual(session: Session, originalSession: SessionV1) {
XCTAssertEqual(session.accessToken, originalSession.accessToken, "The access token should not be changed.")
XCTAssertEqual(session.refreshToken, originalSession.refreshToken, "The refresh token should not be changed.")
XCTAssertEqual(session.userId, originalSession.userId, "The user ID should not be changed.")
XCTAssertEqual(session.deviceId, originalSession.deviceId, "The device ID should not be changed.")
XCTAssertEqual(session.homeserverUrl, originalSession.homeserverUrl, "The homeserver URL should not be changed.")
XCTAssertEqual(session.oidcData, originalSession.oidcData, "The OIDC data should not be changed.")
}
} }
// MARK: - Token formats
struct RestorationTokenV1: Equatable, Codable { struct RestorationTokenV1: Equatable, Codable {
let session: MatrixRustSDK.Session let session: SessionV1
} }
struct RestorationTokenV4: Equatable, Codable { struct RestorationTokenV4: Equatable, Codable {
let session: MatrixRustSDK.Session let session: SessionV1
let sessionDirectory: URL let sessionDirectory: URL
let passphrase: String? let passphrase: String?
let pusherNotificationClientIdentifier: String? let pusherNotificationClientIdentifier: String?
} }
struct RestorationTokenV5: Equatable, Codable { struct RestorationTokenV5: Equatable, Codable {
let session: MatrixRustSDK.Session let session: SessionV1
let sessionDirectory: URL let sessionDirectory: URL
let cacheDirectory: URL let cacheDirectory: URL
let passphrase: String? let passphrase: String?
let pusherNotificationClientIdentifier: String? let pusherNotificationClientIdentifier: String?
} }
// MARK: - Session formats
struct SessionV1: Equatable {
var accessToken: String
var refreshToken: String?
var userId: String
var deviceId: String
var homeserverUrl: String
var oidcData: String?
var slidingSyncVersion: SlidingSyncVersionV1
}
enum SlidingSyncVersionV1: Equatable {
case none
case proxy(url: String)
case native
var proxyURL: String? {
guard case let .proxy(url) = self else { return nil }
return url
}
}
extension SessionV1: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let slidingSyncProxy = try container.decodeIfPresent(String.self, forKey: .slidingSyncProxy)
self = try .init(accessToken: container.decode(String.self, forKey: .accessToken),
refreshToken: container.decodeIfPresent(String.self, forKey: .refreshToken),
userId: container.decode(String.self, forKey: .userId),
deviceId: container.decode(String.self, forKey: .deviceId),
homeserverUrl: container.decode(String.self, forKey: .homeserverUrl),
oidcData: container.decodeIfPresent(String.self, forKey: .oidcData),
slidingSyncVersion: slidingSyncProxy.map { .proxy(url: $0) } ?? .native)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(accessToken, forKey: .accessToken)
try container.encode(refreshToken, forKey: .refreshToken)
try container.encode(userId, forKey: .userId)
try container.encode(deviceId, forKey: .deviceId)
try container.encode(homeserverUrl, forKey: .homeserverUrl)
try container.encode(oidcData, forKey: .oidcData)
try container.encode(slidingSyncVersion.proxyURL, forKey: .slidingSyncProxy)
}
enum CodingKeys: String, CodingKey {
case accessToken, refreshToken, userId, deviceId, homeserverUrl, oidcData, slidingSyncProxy
}
}

View File

@ -61,7 +61,7 @@ packages:
# Element/Matrix dependencies # Element/Matrix dependencies
MatrixRustSDK: MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 25.02.11 exactVersion: 25.02.17
# path: ../matrix-rust-sdk # path: ../matrix-rust-sdk
Compound: Compound:
url: https://github.com/element-hq/compound-ios url: https://github.com/element-hq/compound-ios