Simplify authentication logic

matrix.org now supports MAS so we don't need the web registration helper anymore.
This commit is contained in:
Doug
2025-04-10 15:09:40 +01:00
committed by Doug
parent 76001001c6
commit 2461933993
32 changed files with 86 additions and 709 deletions

View File

@@ -295,7 +295,6 @@
386720B603F87D156DB01FB2 /* VoiceMessageMediaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */; };
388D39ED9FE1122EA6D76BF2 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1BC84BA0AF11C2128D58ABD /* Common.swift */; };
3895969759E68FAB90C63EF7 /* ElementCallServiceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 406C90AF8C3E98DF5D4E5430 /* ElementCallServiceConstants.swift */; };
38CC67C7673FA97C21CCD5B5 /* WebRegistrationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */; };
3982C505960006B341CFD0C6 /* UserDetailsEditScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */; };
3982E60F9C126437D5E488A3 /* PillContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A6314FDC51DA25712D9A81 /* PillContextTests.swift */; };
39A987B3E41B976D1DF944C6 /* CallScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */; };
@@ -326,7 +325,6 @@
3F2148F11164C7C5609984EB /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 2B788C81F6369D164ADEB917 /* GZIP */; };
3F327A62D233933F54F0F33A /* SwiftOGG in Frameworks */ = {isa = PBXBuildFile; productRef = 3FE40E79C36E7903121E6E3B /* SwiftOGG */; };
3F70E237CE4C3FAB02FC227F /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C830A64609CBD152F06E0457 /* NotificationConstants.swift */; };
3F997171C3C79A45E92BF9EF /* ElementWellKnown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79FAC366FF299BCC555D756E /* ElementWellKnown.swift */; };
401BB28CD6B7DD6B4E7863E7 /* ServerConfirmationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9342F5D6729627B6393AF853 /* ServerConfirmationScreenModels.swift */; };
407DCE030E0F9B7C9861D38A /* LoremSwiftum in Frameworks */ = {isa = PBXBuildFile; productRef = 1A6B622CCFDEFB92D9CF1CA5 /* LoremSwiftum */; };
40B79D20A873620F7F128A2C /* UserPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35FA991289149D31F4286747 /* UserPreference.swift */; };
@@ -524,7 +522,6 @@
6586E1F1D5F0651D0638FFAF /* UserSessionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4469F6AE311BDC439B3A5EC /* UserSessionMock.swift */; };
659E5B766F76FDEC1BF393A4 /* RoomDetailsEditScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E413F4CBD7BF0588F394A9DD /* RoomDetailsEditScreenViewModel.swift */; };
661EF50C1F7D4B0BC8A7AAE3 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44ABA63DBE7F76C58260B43B /* EmoteRoomTimelineView.swift */; };
66357ECB73B1290E5490A012 /* WebRegistrationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F418426410F3823F3EB0828 /* WebRegistrationScreenViewModelProtocol.swift */; };
663E198678778F7426A9B27D /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FAFE1C2149E6AC8156ED2B /* Collection.swift */; };
6681D6D3ADF69EBD2625F29A /* KnockedRoomProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E8F4D7D61B80EBD5CB92F8A /* KnockedRoomProxyMock.swift */; };
66832DE7B5C2E861045265DC /* RoomSelectionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D879DC5515B1D42577F96C94 /* RoomSelectionScreen.swift */; };
@@ -821,7 +818,6 @@
9F11E743EA01482E78A438B0 /* GlobalSearchScreenCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DB19219E6CC4D002E15D48 /* GlobalSearchScreenCell.swift */; };
9FB41B0E8B2AA9B404E52C8B /* AppLockSetupBiometricsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCC6C31102E1D8B9106DEDE /* AppLockSetupBiometricsScreenViewModelProtocol.swift */; };
9FBE1FB20171012260A32492 /* TimelineSenderAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53FCCE44F96E0BC411A6CF0 /* TimelineSenderAvatarView.swift */; };
9FC820C410ED733CE6FC6616 /* WebRegistrationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */; };
A009BDFB0A6816D4C392ADCB /* SettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF715D4FD4710EBB637D661 /* SettingsScreenViewModelProtocol.swift */; };
A021827B528F1EDC9101CA58 /* AppCoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBC776F301D374A3298C69DA /* AppCoordinatorProtocol.swift */; };
A0601810597769B81C2358AF /* EncryptionResetPasswordScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2B5274C1D3D2999D643786 /* EncryptionResetPasswordScreenViewModelProtocol.swift */; };
@@ -834,7 +830,6 @@
A17FAD2EBC53E17B5FD384DB /* InviteUsersScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22730A30C50AC2E3D5BA8642 /* InviteUsersScreenViewModelProtocol.swift */; };
A1BA8D6BABAFA9BAAEAA3FFD /* NotificationSettingsProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FDD775CFD72DD2D3C8A8390 /* NotificationSettingsProxyProtocol.swift */; };
A1DF0E1E526A981ED6D5DF44 /* UserIndicatorControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */; };
A20364EE08D902E647C11FB3 /* WebRegistrationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D851A10FDA55579960DC61 /* WebRegistrationScreenCoordinator.swift */; };
A216C83ADCF32BA5EF8A6FBC /* InviteUsersViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845DDBDE5A0887E73D38B826 /* InviteUsersViewModelTests.swift */; };
A2172B5A26976F9174228B8A /* AppHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E4AB573FAEBB7B853DD04C /* AppHooks.swift */; };
A2357AA4A188BC37085BC6F0 /* EditRoomAddressScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5FDFAA04174CC99FB66391C /* EditRoomAddressScreenViewModel.swift */; };
@@ -855,7 +850,6 @@
A4C29D373986AFE4559696D5 /* SecureBackupKeyBackupScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4525E8C0FBDD27D1ACE90952 /* SecureBackupKeyBackupScreenViewModelProtocol.swift */; };
A4E885358D7DD5A072A06824 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = CCE5BF78B125320CBF3BB834 /* PostHog */; };
A51C65E5A3C9F2464A91A380 /* AuthenticationClientBuilderFactoryMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0554FEA301486A8CFA475D5A /* AuthenticationClientBuilderFactoryMock.swift */; };
A52090A4FE0DB826578DFC03 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0724EBDFE8BB4C9E5547C57D /* Client.swift */; };
A588572ED0EB18D947B32A5E /* SendInviteConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F276F31C1AEC19E52B951B62 /* SendInviteConfirmationView.swift */; };
A5B455D1A6DADF7476F7B417 /* EmojiProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BCCE3D12B0A9C6E559B5B5A /* EmojiProviderProtocol.swift */; };
A5B9EF45C7B8ACEB4954AE36 /* LoginScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9780389F8A53E4D26E23DD03 /* LoginScreenViewModelProtocol.swift */; };
@@ -1207,7 +1201,6 @@
F07D88421A9BC4D03D4A5055 /* VideoRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */; };
F08F7BC07CA9AEF5CD157918 /* Snapshotting.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF17EA323AD0205A6AB621AA /* Snapshotting.swift */; };
F0A26CD502C3A5868353B0FA /* ServerConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24DEE0682C95F897B6C7CB0D /* ServerConfirmationScreenViewModel.swift */; };
F0C2C49D707839F5273BFC6D /* WebRegistrationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C161B06F417CA5D1F1E088 /* WebRegistrationScreenModels.swift */; };
F0DACC95F24128A54CD537E4 /* GlobalSearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24B8177BD2AF45A286F5DA31 /* GlobalSearchScreen.swift */; };
F0F82C3C848C865C3098AA52 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 21C83087604B154AA30E9A8F /* SnapshotTesting */; };
F103924DED414ADFE398CE99 /* RoomPollsHistoryScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A130A2251A15A7AACC84FD37 /* RoomPollsHistoryScreenViewModelProtocol.swift */; };
@@ -1272,7 +1265,6 @@
FBF09B6C900415800DDF2A21 /* EmojiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C113E0CB7E15E9765B1817A /* EmojiProvider.swift */; };
FC0EEFF630F34899953BB950 /* BigIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01FD1171FF40E34D707FD00 /* BigIcon.swift */; };
FC10228E73323BDC09526F97 /* Mapbox in Frameworks */ = {isa = PBXBuildFile; productRef = C1BF15833233CD3BDB7E2B1D /* Mapbox */; };
FC8B95EC506E6BB5793D81CE /* ClientProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34685D186453E429ADEE58E /* ClientProtocolTests.swift */; };
FCD3F2B82CAB29A07887A127 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; };
FD29471C72872F8B7580E3E1 /* KeychainControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C0D861FC397AC34BCF089E /* KeychainControllerMock.swift */; };
FD4C21F8DA1E273DE94FCD1A /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */; };
@@ -1404,7 +1396,6 @@
06B098A612DCB5A7358EECD5 /* DeveloperOptionsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenModels.swift; sourceTree = "<group>"; };
06F27F588F9059128E17C669 /* WindowManagerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManagerProtocol.swift; sourceTree = "<group>"; };
06FAE373A7F20780BA84B59C /* MessageForwardingScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenCoordinator.swift; sourceTree = "<group>"; };
0724EBDFE8BB4C9E5547C57D /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
07579F9C29001E40715F3014 /* NotificationSettingsChatType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsChatType.swift; sourceTree = "<group>"; };
077B01C13BBA2996272C5FB5 /* ProcessInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessInfo.swift; sourceTree = "<group>"; };
077D7C3BE199B6E5DDEC07EC /* AppCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinatorStateMachine.swift; sourceTree = "<group>"; };
@@ -1491,7 +1482,6 @@
1A13364350970987B93F6018 /* JoinRoomByAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomByAddressView.swift; sourceTree = "<group>"; };
1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+Untranslated.swift"; sourceTree = "<group>"; };
1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoURITests.swift; sourceTree = "<group>"; };
1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreen.swift; sourceTree = "<group>"; };
1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineItem.swift; sourceTree = "<group>"; };
1B30CD19ED6243FEDFBA8400 /* ManageRoomMemberSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageRoomMemberSheetView.swift; sourceTree = "<group>"; };
1B53D6C5C0D14B04D3AB3F6E /* PillAttachmentViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillAttachmentViewProvider.swift; sourceTree = "<group>"; };
@@ -1897,7 +1887,6 @@
6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BindableState.swift; sourceTree = "<group>"; };
6F1C3CBBC62C566DDF5E84C1 /* TimelineItemMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenuAction.swift; sourceTree = "<group>"; };
6F3DFE5B444F131648066F05 /* StateStoreViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateStoreViewModel.swift; sourceTree = "<group>"; };
6F418426410F3823F3EB0828 /* WebRegistrationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
6F65E4BB9E82EB8373207CF8 /* MediaProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderMock.swift; sourceTree = "<group>"; };
6F6E6EDC4BBF962B2ED595A4 /* MessageForwardingScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelTests.swift; sourceTree = "<group>"; };
6FA38E813BE14149F173F461 /* PinnedEventsBannerStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsBannerStateTests.swift; sourceTree = "<group>"; };
@@ -1941,7 +1930,6 @@
7893780A1FD6E3F38B3E9049 /* UserIndicatorControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerMock.swift; sourceTree = "<group>"; };
78BBDF7A05CF53B5CDC13682 /* landscape_test_video.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = landscape_test_video.mov; sourceTree = "<group>"; };
796CBD0C56FA0D3AEDAB255B /* SessionVerificationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenCoordinator.swift; sourceTree = "<group>"; };
79FAC366FF299BCC555D756E /* ElementWellKnown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementWellKnown.swift; sourceTree = "<group>"; };
7A03E073077D92AA19C43DCF /* IdentityConfirmationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenCoordinator.swift; sourceTree = "<group>"; };
7AAD8C633AA57948B34EDCF7 /* RoomChangeRolesScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenViewModelProtocol.swift; sourceTree = "<group>"; };
7AC0CD1CAFD3F8B057F9AEA5 /* ClientBuilderHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientBuilderHook.swift; sourceTree = "<group>"; };
@@ -2159,7 +2147,6 @@
A436057DBEA1A23CA8CB1FD7 /* UIFont+AttributedStringBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIFont+AttributedStringBuilder.h"; sourceTree = "<group>"; };
A443FAE2EE820A5790C35C8D /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = "<group>"; };
A54AAF72E821B4084B7E4298 /* PinnedEventsTimelineFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineFlowCoordinator.swift; sourceTree = "<group>"; };
A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenViewModel.swift; sourceTree = "<group>"; };
A69869844D2B6F5BD9AABF85 /* OIDCConfigurationProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCConfigurationProxy.swift; sourceTree = "<group>"; };
A6B19D10B102956066AF117B /* PollOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionView.swift; sourceTree = "<group>"; };
A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = "<group>"; };
@@ -2340,7 +2327,6 @@
C75EF87651B00A176AB08E97 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C75FE3F524B575D53787868C /* TimelineMediaPreviewRedactConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewRedactConfirmationView.swift; sourceTree = "<group>"; };
C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomList.swift; sourceTree = "<group>"; };
C7D851A10FDA55579960DC61 /* WebRegistrationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenCoordinator.swift; sourceTree = "<group>"; };
C830A64609CBD152F06E0457 /* NotificationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationConstants.swift; sourceTree = "<group>"; };
C833673B334A0651AB46F30B /* StaticLocationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenViewModelTests.swift; sourceTree = "<group>"; };
C90514BE9B8ACCBCF0AD2489 /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; };
@@ -2465,7 +2451,6 @@
E2F96CCBEAAA7F2185BFA354 /* ClientProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxyMock.swift; sourceTree = "<group>"; };
E3059CFA00C67D8787273B20 /* ServerSelectionScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenViewModel.swift; sourceTree = "<group>"; };
E321E840DCC63790049984F4 /* ElementCallServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallServiceMock.swift; sourceTree = "<group>"; };
E34685D186453E429ADEE58E /* ClientProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProtocolTests.swift; sourceTree = "<group>"; };
E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = "<group>"; };
E3B97591B2D3D4D67553506D /* AnalyticsClientProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsClientProtocol.swift; sourceTree = "<group>"; };
E4103AB4340F2974D690A12A /* CallScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreen.swift; sourceTree = "<group>"; };
@@ -2567,7 +2552,6 @@
F64A8582F65567AC38C2976A /* PollFormScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenViewModel.swift; sourceTree = "<group>"; };
F72EFC8C634469F9262659C7 /* NSItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSItemProvider.swift; sourceTree = "<group>"; };
F7478623CECC9438014244BA /* ServerConfirmationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreen.swift; sourceTree = "<group>"; };
F7C161B06F417CA5D1F1E088 /* WebRegistrationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenModels.swift; sourceTree = "<group>"; };
F875D71347DC81EAE7687446 /* NavigationRootCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRootCoordinatorTests.swift; sourceTree = "<group>"; };
F899D02CF26EA7675EEBE74C /* UserSessionScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionScreenTests.swift; sourceTree = "<group>"; };
F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreen.swift; sourceTree = "<group>"; };
@@ -3063,14 +3047,6 @@
path = Progress;
sourceTree = "<group>";
};
25A88085FB8D8227DCDB0C9C /* View */ = {
isa = PBXGroup;
children = (
1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */,
);
path = View;
sourceTree = "<group>";
};
26397A1EDB867FD573821532 /* MediaEventsTimelineScreen */ = {
isa = PBXGroup;
children = (
@@ -4290,7 +4266,6 @@
7EECE8B331CD169790EF284F /* BugReportScreenViewModelTests.swift */,
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */,
E34685D186453E429ADEE58E /* ClientProtocolTests.swift */,
D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */,
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */,
69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */,
@@ -4606,10 +4581,8 @@
8039515BAA53B7C3275AC64A /* Client */ = {
isa = PBXGroup;
children = (
0724EBDFE8BB4C9E5547C57D /* Client.swift */,
18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */,
6033779EB37259F27F938937 /* ClientProxyProtocol.swift */,
79FAC366FF299BCC555D756E /* ElementWellKnown.swift */,
);
path = Client;
sourceTree = "<group>";
@@ -5647,18 +5620,6 @@
path = RoomChangeRolesScreen;
sourceTree = "<group>";
};
D847C12EC9B19A5FCDF2C815 /* WebRegistrationScreen */ = {
isa = PBXGroup;
children = (
C7D851A10FDA55579960DC61 /* WebRegistrationScreenCoordinator.swift */,
F7C161B06F417CA5D1F1E088 /* WebRegistrationScreenModels.swift */,
A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */,
6F418426410F3823F3EB0828 /* WebRegistrationScreenViewModelProtocol.swift */,
25A88085FB8D8227DCDB0C9C /* View */,
);
path = WebRegistrationScreen;
sourceTree = "<group>";
};
D977D4E565C06D3F41C8F8FC /* Virtual */ = {
isa = PBXGroup;
children = (
@@ -5906,7 +5867,6 @@
BA1938A75D8C780F694CEB62 /* ServerConfirmationScreen */,
2D0D49B0533C4C2EB889BF3A /* ServerSelectionScreen */,
5B2C520AB9863B8CBC8EB3CA /* SoftLogoutScreen */,
D847C12EC9B19A5FCDF2C815 /* WebRegistrationScreen */,
);
path = Authentication;
sourceTree = "<group>";
@@ -6778,7 +6738,6 @@
1B2F9F368619FFF8C63C87CC /* BugReportScreenViewModelTests.swift in Sources */,
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */,
FC8B95EC506E6BB5793D81CE /* ClientProtocolTests.swift in Sources */,
B5321A1F5B26A0F3EC54909E /* CollapsibleFlowLayoutTests.swift in Sources */,
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */,
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */,
@@ -7069,7 +7028,6 @@
E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */,
DF8F1211F2B0B56F0FCCA5C2 /* CertificateValidatorHook.swift in Sources */,
D885B783B95AD7832D4EF5DD /* CharacterSet.swift in Sources */,
A52090A4FE0DB826578DFC03 /* Client.swift in Sources */,
C80E06ED97CE52704A46C148 /* ClientBuilder.swift in Sources */,
87CEA3E07B602705BC2D2A20 /* ClientBuilderHook.swift in Sources */,
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */,
@@ -7144,7 +7102,6 @@
07CC13C5729C24255348CBBD /* ElementCallWidgetDriver.swift in Sources */,
370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */,
A87DC550659C5176AC1829DE /* ElementTextFieldStyle.swift in Sources */,
3F997171C3C79A45E92BF9EF /* ElementWellKnown.swift in Sources */,
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */,
3A08584ECDD4A4541DBF21F8 /* EmojiLoaderProtocol.swift in Sources */,
340D39DB87F3800D53A6A621 /* EmojiPickerScreen.swift in Sources */,
@@ -7828,11 +7785,6 @@
CA12AE0DCD57D49CD96C699A /* WaveformCursorView.swift in Sources */,
63CDC201A5980F304F6D0A1C /* WaveformInteractionModifier.swift in Sources */,
B773ACD8881DB18E876D950C /* WaveformSource.swift in Sources */,
38CC67C7673FA97C21CCD5B5 /* WebRegistrationScreen.swift in Sources */,
A20364EE08D902E647C11FB3 /* WebRegistrationScreenCoordinator.swift in Sources */,
F0C2C49D707839F5273BFC6D /* WebRegistrationScreenModels.swift in Sources */,
9FC820C410ED733CE6FC6616 /* WebRegistrationScreenViewModel.swift in Sources */,
66357ECB73B1290E5490A012 /* WebRegistrationScreenViewModelProtocol.swift in Sources */,
08CB4BD12CEEDE6AAE4A18DD /* WindowManager.swift in Sources */,
AE5AAD9E32511544FDFA5560 /* WindowManagerProtocol.swift in Sources */,
80F1B442DB5E2C362ACDD8E2 /* ZoomTransition.swift in Sources */,

View File

@@ -210,8 +210,10 @@ final class AppSettings {
contacts: [supportEmailAddress],
staticRegistrations: oidcStaticRegistrations.mapKeys { $0.absoluteString })
/// A temporary hack to allow registration on matrix.org until MAS is deployed.
let webRegistrationEnabled = true
/// Whether or not the Create Account button is shown on the start screen.
///
/// **Note:** Setting this to false doesn't prevent someone from creating an account when the selected homeserver's MAS allows registration.
let showCreateAccountButton = true
// MARK: - Notifications

View File

@@ -68,7 +68,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
// MARK: - Private
private func showStartScreen() {
let parameters = AuthenticationStartScreenParameters(webRegistrationEnabled: appSettings.webRegistrationEnabled,
let parameters = AuthenticationStartScreenParameters(showCreateAccountButton: appSettings.showCreateAccountButton,
isBugReportServiceEnabled: bugReportService.isEnabled)
let coordinator = AuthenticationStartScreenCoordinator(parameters: parameters)
@@ -145,10 +145,8 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
switch action {
case .continue(let window):
if authenticationService.homeserver.value.loginMode == .oidc, let window {
if authenticationService.homeserver.value.loginMode.supportsOIDCFlow, let window {
showOIDCAuthentication(presentationAnchor: window)
} else if authenticationFlow == .register {
showWebRegistration()
} else {
showLoginScreen()
}
@@ -187,26 +185,6 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
navigationStackCoordinator.setSheetCoordinator(navigationCoordinator)
}
private func showWebRegistration() {
let parameters = WebRegistrationScreenCoordinatorParameters(authenticationService: authenticationService,
userIndicatorController: userIndicatorController)
let coordinator = WebRegistrationScreenCoordinator(parameters: parameters)
coordinator.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .cancel:
navigationStackCoordinator.setSheetCoordinator(nil)
case .signedIn(let userSession):
userHasSignedIn(userSession: userSession)
}
}
.store(in: &cancellables)
navigationStackCoordinator.setSheetCoordinator(coordinator)
}
private func showOIDCAuthentication(presentationAnchor: UIWindow) {
startLoading()

View File

@@ -15,19 +15,21 @@ extension AuthenticationClientBuilderMock {
"example.com": ClientSDKMock(configuration: .init(serverAddress: "example.com",
homeserverURL: "https://matrix.example.com",
slidingSyncVersion: .native,
supportsPasswordLogin: true,
elementWellKnown: "")),
oidcLoginURL: nil,
supportsOIDCCreatePrompt: false,
supportsPasswordLogin: true)),
"company.com": ClientSDKMock(configuration: .init(serverAddress: "company.com",
homeserverURL: "https://matrix.company.com",
slidingSyncVersion: .native,
oidcLoginURL: "https://auth.company.com/oidc",
supportsPasswordLogin: false,
elementWellKnown: "")),
supportsOIDCCreatePrompt: false,
supportsPasswordLogin: false)),
"server.net": ClientSDKMock(configuration: .init(serverAddress: "server.net",
homeserverURL: "https://matrix.example.com",
slidingSyncVersion: .native,
supportsPasswordLogin: false,
elementWellKnown: ""))
oidcLoginURL: nil,
supportsOIDCCreatePrompt: false,
supportsPasswordLogin: false))
]
var qrCodeClient = ClientSDKMock(configuration: .init())
}

View File

@@ -76,8 +76,6 @@ extension ClientProxyMock {
recentlyVisitedRoomsReturnValue = .success([])
recentConversationCounterpartsReturnValue = []
getElementWellKnownReturnValue = .success(nil)
loadMediaContentForSourceThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
loadMediaThumbnailForSourceWidthHeightThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
loadMediaFileForSourceFilenameThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)

View File

@@ -4281,70 +4281,6 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
return isAliasAvailableReturnValue
}
}
//MARK: - getElementWellKnown
var getElementWellKnownUnderlyingCallsCount = 0
var getElementWellKnownCallsCount: Int {
get {
if Thread.isMainThread {
return getElementWellKnownUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = getElementWellKnownUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
getElementWellKnownUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
getElementWellKnownUnderlyingCallsCount = newValue
}
}
}
}
var getElementWellKnownCalled: Bool {
return getElementWellKnownCallsCount > 0
}
var getElementWellKnownUnderlyingReturnValue: Result<ElementWellKnown?, ClientProxyError>!
var getElementWellKnownReturnValue: Result<ElementWellKnown?, ClientProxyError>! {
get {
if Thread.isMainThread {
return getElementWellKnownUnderlyingReturnValue
} else {
var returnValue: Result<ElementWellKnown?, ClientProxyError>? = nil
DispatchQueue.main.sync {
returnValue = getElementWellKnownUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
getElementWellKnownUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
getElementWellKnownUnderlyingReturnValue = newValue
}
}
}
}
var getElementWellKnownClosure: (() async -> Result<ElementWellKnown?, ClientProxyError>)?
func getElementWellKnown() async -> Result<ElementWellKnown?, ClientProxyError> {
getElementWellKnownCallsCount += 1
if let getElementWellKnownClosure = getElementWellKnownClosure {
return await getElementWellKnownClosure()
} else {
return getElementWellKnownReturnValue
}
}
//MARK: - clearCaches
var clearCachesUnderlyingCallsCount = 0

View File

@@ -15,9 +15,9 @@ extension ClientSDKMock {
var serverAddress = "matrix.org"
var homeserverURL = "https://matrix-client.matrix.org"
var slidingSyncVersion = SlidingSyncVersion.native
var oidcLoginURL: String?
var oidcLoginURL: String? = "https://account.matrix.org/authorize"
var supportsOIDCCreatePrompt = true
var supportsPasswordLogin = true
var elementWellKnown = "{\"registration_helper_url\":\"https://develop.element.io/#/mobile_register\"}"
var validCredentials = (username: "alice", password: "12345678")
// MARK: Session
@@ -41,7 +41,6 @@ extension ClientSDKMock {
slidingSyncVersionReturnValue = configuration.slidingSyncVersion
userIdServerNameThrowableError = MockError.generic
serverReturnValue = "https://\(configuration.serverAddress)"
getUrlUrlReturnValue = configuration.elementWellKnown
urlForOidcOidcConfigurationPromptReturnValue = OAuthAuthorizationDataSDKMock(configuration: configuration)
loginUsernamePasswordInitialDeviceNameDeviceIdClosure = { username, password, _, _ in
guard username == configuration.validCredentials.username,
@@ -62,6 +61,11 @@ extension HomeserverLoginDetailsSDKMock {
slidingSyncVersionReturnValue = configuration.slidingSyncVersion
supportsPasswordLoginReturnValue = configuration.supportsPasswordLogin
supportsOidcLoginReturnValue = configuration.oidcLoginURL != nil
supportedOidcPromptsReturnValue = switch (configuration.oidcLoginURL, configuration.supportsOIDCCreatePrompt) {
case (.none, _): []
case (.some, true): [.consent, .create]
case (.some, false): [.consent]
}
urlReturnValue = configuration.homeserverURL
}
}

View File

@@ -13,21 +13,13 @@ struct LoginHomeserver: Equatable {
let address: String
/// The types login supported by the homeserver.
var loginMode: LoginMode
/// A temporary helper URL that can be used for registration.
var registrationHelperURL: URL?
/// Creates a new homeserver value.
init(address: String, loginMode: LoginMode, registrationHelperURL: URL? = nil) {
init(address: String, loginMode: LoginMode) {
let address = Self.sanitized(address).components(separatedBy: "://").last ?? address
self.address = address
self.loginMode = loginMode
self.registrationHelperURL = registrationHelperURL
}
/// Whether or not the app is able to register on this homeserver.
var supportsRegistration: Bool {
loginMode == .oidc || (address == "matrix.org" && registrationHelperURL != nil)
}
/// Sanitizes a user entered homeserver address with the following rules
@@ -53,7 +45,7 @@ struct LoginHomeserver: Equatable {
extension LoginHomeserver {
/// A mock homeserver that is configured just like matrix.org.
static var mockMatrixDotOrg: LoginHomeserver {
LoginHomeserver(address: "matrix.org", loginMode: .password, registrationHelperURL: "https://develop.element.io/#/mobile_register")
LoginHomeserver(address: "matrix.org", loginMode: .oidc(supportsCreatePrompt: true))
}
/// A mock homeserver that supports login and registration via a password but has no SSO providers.
@@ -63,7 +55,7 @@ extension LoginHomeserver {
/// A mock homeserver that supports only supports authentication via a single SSO provider.
static var mockOIDC: LoginHomeserver {
LoginHomeserver(address: "company.com", loginMode: .oidc)
LoginHomeserver(address: "company.com", loginMode: .oidc(supportsCreatePrompt: false))
}
/// A mock homeserver that only with no supported login flows.

View File

@@ -12,7 +12,7 @@ enum LoginMode: Equatable {
/// The login mode hasn't been determined yet.
case unknown
/// The homeserver supports login via OpenID Connect.
case oidc
case oidc(supportsCreatePrompt: Bool)
/// The homeserver supports login with a password.
case password
/// The homeserver only allows login with unsupported mechanisms. Use fallback instead.

View File

@@ -69,7 +69,7 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
Task {
switch await authenticationService.configure(for: homeserverDomain, flow: .login) {
case .success:
if authenticationService.homeserver.value.loginMode == .oidc {
if authenticationService.homeserver.value.loginMode.supportsOIDCFlow {
actionsSubject.send(.configuredForOIDC)
}
stopLoading()

View File

@@ -1,139 +0,0 @@
//
// Copyright 2022-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 Compound
import SwiftUI
import WebKit
struct WebRegistrationScreen: View {
@ObservedObject var context: WebRegistrationScreenViewModel.Context
var body: some View {
NavigationStack {
WebRegistrationWebView(url: context.viewState.url, viewModelContext: context)
.navigationTitle(L10n.screenCreateAccountTitle)
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(L10n.actionCancel) {
context.send(viewAction: .cancel)
}
}
}
}
}
}
struct WebRegistrationWebView: UIViewRepresentable {
let url: URL
let viewModelContext: WebRegistrationScreenViewModel.Context
func makeUIView(context: Context) -> WKWebView {
context.coordinator.webView
}
func updateUIView(_ webView: WKWebView, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(url: url, viewModelContext: viewModelContext)
}
class Coordinator: NSObject, WKUIDelegate {
private let url: URL
private let viewModelContext: WebRegistrationScreenViewModel.Context
private(set) var webView: WKWebView!
init(url: URL, viewModelContext: WebRegistrationScreenViewModel.Context) {
self.url = url
self.viewModelContext = viewModelContext
super.init()
let eventHandlerName = "elementx"
let userContentController = WKUserContentController()
userContentController.add(WKScriptMessageHandlerWrapper(self), name: eventHandlerName)
let eventHandlerScript = """
window.addEventListener(
"mobileregistrationresponse",
(event) => {
window.webkit.messageHandlers.\(eventHandlerName).postMessage(JSON.stringify(event.detail));
},
false,
);
"""
let userScript = WKUserScript(source: eventHandlerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
webView = WKWebView(frame: .zero, configuration: configuration)
webView.uiDelegate = self
webView.load(URLRequest(url: url))
}
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let jsonString = message.body as? String, let jsonData = jsonString.data(using: .utf8) else {
MXLog.error("Unexpected response.")
return
}
guard let credentials = try? JSONDecoder().decode(WebRegistrationCredentials.self, from: jsonData) else {
MXLog.error("Invalid response.")
return
}
MXLog.info("Received login credentials.")
viewModelContext.send(viewAction: .signedIn(credentials))
}
// MARK: WKUIDelegate
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if let url = navigationAction.request.url, UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return nil
}
}
/// Avoids retain loops between the configuration and webView coordinator
private class WKScriptMessageHandlerWrapper: NSObject, WKScriptMessageHandler {
private weak var coordinator: Coordinator?
init(_ coordinator: Coordinator) {
self.coordinator = coordinator
}
// MARK: WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
coordinator?.userContentController(userContentController, didReceive: message)
}
}
}
// MARK: - Previews
struct WebRegistrationScreen_Previews: PreviewProvider {
static let viewModel = WebRegistrationScreenViewModel(registrationHelperURL: "https://develop.element.io/#/mobile_register")
static var previews: some View {
NavigationStack {
WebRegistrationScreen(context: viewModel.context)
}
}
}

View File

@@ -1,83 +0,0 @@
//
// Copyright 2022-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 MatrixRustSDK
import SwiftUI
struct WebRegistrationScreenCoordinatorParameters {
/// The service used to authenticate the user.
let authenticationService: AuthenticationServiceProtocol
let userIndicatorController: UserIndicatorControllerProtocol
}
enum WebRegistrationScreenCoordinatorAction: CustomStringConvertible {
case cancel
case signedIn(UserSessionProtocol)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
// Note: This code was based on the LoginScreen, we should move the authentication service logic into the view model.
final class WebRegistrationScreenCoordinator: CoordinatorProtocol {
private let parameters: WebRegistrationScreenCoordinatorParameters
private let viewModel: WebRegistrationScreenViewModelProtocol
private var cancellables = Set<AnyCancellable>()
private let actionsSubject: PassthroughSubject<WebRegistrationScreenCoordinatorAction, Never> = .init()
var actionsPublisher: AnyPublisher<WebRegistrationScreenCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(parameters: WebRegistrationScreenCoordinatorParameters) {
self.parameters = parameters
guard let registrationHelperURL = parameters.authenticationService.homeserver.value.registrationHelperURL else {
MXLog.error("Attempted registration without a helper URL.")
fatalError("A helper URL is required.")
}
viewModel = WebRegistrationScreenViewModel(registrationHelperURL: registrationHelperURL)
}
func start() {
viewModel.actionsPublisher.sink { [weak self] action in
MXLog.info("Coordinator: received view model action: \(action)")
guard let self else { return }
switch action {
case .cancel:
actionsSubject.send(.cancel)
case .signedIn(let credentials):
Task { await self.completeRegistration(using: credentials) }
}
}
.store(in: &cancellables)
}
func toPresentable() -> AnyView {
AnyView(WebRegistrationScreen(context: viewModel.context))
}
// MARK: - Private
private func completeRegistration(using credentials: WebRegistrationCredentials) async {
switch await parameters.authenticationService.completeWebRegistration(using: credentials) {
case .success(let userSession):
actionsSubject.send(.signedIn(userSession))
case .failure(let error):
MXLog.error("Failed registration: \(error)")
parameters.userIndicatorController.alertInfo = .init(id: UUID(), title: L10n.errorUnknown, message: String(describing: error))
}
}
}

View File

@@ -1,51 +0,0 @@
//
// Copyright 2022-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 Foundation
enum WebRegistrationScreenViewModelAction: CustomStringConvertible {
case cancel
case signedIn(WebRegistrationCredentials)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
struct WebRegistrationScreenViewState: BindableState {
var url: URL
var bindings = WebRegistrationScreenViewStateBindings()
}
struct WebRegistrationScreenViewStateBindings { }
enum WebRegistrationScreenViewAction: CustomStringConvertible {
case cancel
case signedIn(WebRegistrationCredentials)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
struct WebRegistrationCredentials: Decodable {
let userID: String
let accessToken: String
let deviceID: String
enum CodingKeys: String, CodingKey {
case userID = "user_id"
case accessToken = "access_token"
case deviceID = "device_id"
}
}

View File

@@ -1,34 +0,0 @@
//
// Copyright 2022-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 MatrixRustSDK
import SwiftUI
typealias WebRegistrationScreenViewModelType = StateStoreViewModel<WebRegistrationScreenViewState, WebRegistrationScreenViewAction>
class WebRegistrationScreenViewModel: WebRegistrationScreenViewModelType, WebRegistrationScreenViewModelProtocol {
private let actionsSubject: PassthroughSubject<WebRegistrationScreenViewModelAction, Never> = .init()
var actionsPublisher: AnyPublisher<WebRegistrationScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(registrationHelperURL: URL) {
super.init(initialViewState: WebRegistrationScreenViewState(url: registrationHelperURL))
}
override func process(viewAction: WebRegistrationScreenViewAction) {
MXLog.info("View model: received view action: \(viewAction)")
switch viewAction {
case .cancel:
actionsSubject.send(.cancel)
case .signedIn(let credentials):
actionsSubject.send(.signedIn(credentials))
}
}
}

View File

@@ -1,14 +0,0 @@
//
// Copyright 2022-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
@MainActor
protocol WebRegistrationScreenViewModelProtocol {
var actionsPublisher: AnyPublisher<WebRegistrationScreenViewModelAction, Never> { get }
var context: WebRegistrationScreenViewModelType.Context { get }
}

View File

@@ -9,7 +9,7 @@ import Combine
import SwiftUI
struct AuthenticationStartScreenParameters {
let webRegistrationEnabled: Bool
let showCreateAccountButton: Bool
let isBugReportServiceEnabled: Bool
}
@@ -23,7 +23,7 @@ final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
}
init(parameters: AuthenticationStartScreenParameters) {
viewModel = AuthenticationStartScreenViewModel(webRegistrationEnabled: parameters.webRegistrationEnabled,
viewModel = AuthenticationStartScreenViewModel(showCreateAccountButton: parameters.showCreateAccountButton,
isBugReportServiceEnabled: parameters.isBugReportServiceEnabled)
}

View File

@@ -24,7 +24,7 @@ enum AuthenticationStartScreenViewModelAction {
}
struct AuthenticationStartScreenViewState: BindableState {
let isWebRegistrationEnabled: Bool
let showCreateAccountButton: Bool
let isQRCodeLoginEnabled: Bool
let isBugReportServiceEnabled: Bool
}

View File

@@ -17,8 +17,8 @@ class AuthenticationStartScreenViewModel: AuthenticationStartScreenViewModelType
actionsSubject.eraseToAnyPublisher()
}
init(webRegistrationEnabled: Bool, isBugReportServiceEnabled: Bool) {
super.init(initialViewState: AuthenticationStartScreenViewState(isWebRegistrationEnabled: webRegistrationEnabled,
init(showCreateAccountButton: Bool, isBugReportServiceEnabled: Bool) {
super.init(initialViewState: AuthenticationStartScreenViewState(showCreateAccountButton: showCreateAccountButton,
isQRCodeLoginEnabled: !ProcessInfo.processInfo.isiOSAppOnMac,
isBugReportServiceEnabled: isBugReportServiceEnabled))
}

View File

@@ -102,7 +102,7 @@ struct AuthenticationStartScreen: View {
.buttonStyle(.compound(.primary))
.accessibilityIdentifier(A11yIdentifiers.authenticationStartScreen.signIn)
if context.viewState.isWebRegistrationEnabled {
if context.viewState.showCreateAccountButton {
Button { context.send(viewAction: .register) } label: {
Text(L10n.screenCreateAccountTitle)
.padding(14)
@@ -129,7 +129,7 @@ struct AuthenticationStartScreen_Previews: PreviewProvider, TestablePreview {
}
static func makeViewModel(isBugReportServiceEnabled: Bool = true) -> AuthenticationStartScreenViewModel {
AuthenticationStartScreenViewModel(webRegistrationEnabled: true,
AuthenticationStartScreenViewModel(showCreateAccountButton: true,
isBugReportServiceEnabled: isBugReportServiceEnabled)
}
}

View File

@@ -292,7 +292,6 @@ private struct CallView: UIViewRepresentable {
struct CallScreen_Previews: PreviewProvider {
static let viewModel = {
let clientProxy = ClientProxyMock()
clientProxy.getElementWellKnownReturnValue = .success(nil)
clientProxy.deviceID = "call-device-id"
let roomProxy = JoinedRoomProxyMock()

View File

@@ -48,27 +48,21 @@ class AuthenticationService: AuthenticationServiceProtocol {
let client = try await makeClientBuilder().build(homeserverAddress: homeserverAddress)
let loginDetails = await client.homeserverLoginDetails()
let elementWellKnown = await client.getElementWellKnown()
MXLog.info("Sliding sync: \(client.slidingSyncVersion())")
homeserver.loginMode = if loginDetails.supportsOidcLogin() {
.oidc
.oidc(supportsCreatePrompt: loginDetails.supportedOidcPrompts().contains(.create))
} else if loginDetails.supportsPasswordLogin() {
.password
} else {
.unsupported
}
homeserver.registrationHelperURL = switch elementWellKnown {
case .success(let wellKnown): wellKnown.registrationHelperUrl.flatMap(URL.init)
case .failure: nil
}
if flow == .login, homeserver.loginMode == .unsupported {
return .failure(.loginNotSupported)
}
if flow == .register, !homeserver.supportsRegistration {
if flow == .register, !homeserver.loginMode.supportsOIDCFlow {
return .failure(.registrationNotSupported)
}
@@ -91,6 +85,8 @@ class AuthenticationService: AuthenticationServiceProtocol {
func urlForOIDCLogin() async -> Result<OIDCAuthorizationDataProxy, AuthenticationServiceError> {
guard let client else { return .failure(.oidcError(.urlFailure)) }
do {
// The create prompt is broken: https://github.com/element-hq/matrix-authentication-service/issues/3429
// let prompt: OidcPrompt = flow == .register ? .create : .consent
let oidcData = try await client.urlForOidc(oidcConfiguration: appSettings.oidcConfiguration.rustValue,
prompt: .consent)
return .success(OIDCAuthorizationDataProxy(underlyingData: oidcData))
@@ -148,25 +144,6 @@ class AuthenticationService: AuthenticationServiceProtocol {
}
}
func completeWebRegistration(using credentials: WebRegistrationCredentials) async -> Result<any UserSessionProtocol, AuthenticationServiceError> {
guard let client else { return .failure(.failedLoggingIn) }
let session = Session(accessToken: credentials.accessToken,
refreshToken: nil,
userId: credentials.userID,
deviceId: credentials.deviceID,
homeserverUrl: client.homeserver(),
oidcData: nil,
slidingSyncVersion: client.slidingSyncVersion())
do {
try await client.restoreSession(session: session)
return await userSession(for: client)
} catch {
MXLog.error("Failed restoring the client using the provided credentials.")
return .failure(.failedUsingWebCredentials)
}
}
func reset() {
homeserverSubject.send(LoginHomeserver(address: appSettings.defaultHomeserverAddress, loginMode: .unknown))
flow = .login

View File

@@ -48,8 +48,6 @@ protocol AuthenticationServiceProtocol {
func loginWithOIDCCallback(_ callbackURL: URL) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Performs a password login using the current homeserver.
func login(username: String, password: String, initialDeviceName: String?, deviceID: String?) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Completes registration using the credentials obtained via the helper URL.
func completeWebRegistration(using credentials: WebRegistrationCredentials) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Resets the current configuration requiring `configure(for:flow:)` to be called again.
func reset()

View File

@@ -1,32 +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 Foundation
import MatrixRustSDK
extension ClientProtocol {
func getElementWellKnown() async -> Result<MatrixRustSDK.ElementWellKnown, ClientProxyError> {
do {
let serverName = if let userIDServerName = try? userIdServerName() {
"https://\(userIDServerName)"
} else {
server()
}
guard let serverName,
let url = URL(string: serverName)?.appending(path: "/.well-known/element/element.json") else {
return .failure(.invalidServerName)
}
let response = try await getUrl(url: url.absoluteString)
let wellKnown = try makeElementWellKnown(string: response)
return .success(wellKnown)
} catch {
return .failure(.sdkError(error))
}
}
}

View File

@@ -703,10 +703,6 @@ class ClientProxy: ClientProxyProtocol {
}
}
func getElementWellKnown() async -> Result<ElementWellKnown?, ClientProxyError> {
await client.getElementWellKnown().map(ElementWellKnown.init)
}
func clearCaches() async -> Result<Void, ClientProxyError> {
do {
return try await .success(client.clearCaches())

View File

@@ -182,8 +182,6 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
func isAliasAvailable(_ alias: String) async -> Result<Bool, ClientProxyError>
func getElementWellKnown() async -> Result<ElementWellKnown?, ClientProxyError>
@discardableResult func clearCaches() async -> Result<Void, ClientProxyError>
// MARK: - Ignored users

View File

@@ -1,17 +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 Foundation
import MatrixRustSDK
struct ElementWellKnown {
let registrationHelperURL: URL?
init?(_ wellKnown: MatrixRustSDK.ElementWellKnown) {
registrationHelperURL = wellKnown.registrationHelperUrl.flatMap(URL.init)
}
}

View File

@@ -16,10 +16,10 @@ class AuthenticationServiceTests: XCTestCase {
var service: AuthenticationService!
func testLogin() async {
setupMocks()
func testPasswordLogin() async {
setupMocks(serverAddress: "example.com")
switch await service.configure(for: "matrix.org", flow: .login) {
switch await service.configure(for: "example.com", flow: .login) {
case .success:
break
case .failure(let error):
@@ -27,7 +27,7 @@ class AuthenticationServiceTests: XCTestCase {
}
XCTAssertEqual(service.flow, .login)
XCTAssertEqual(service.homeserver.value, .mockMatrixDotOrg)
XCTAssertEqual(service.homeserver.value, .mockBasicServer)
switch await service.login(username: "alice", password: "12345678", initialDeviceName: nil, deviceID: nil) {
case .success:
@@ -40,7 +40,21 @@ class AuthenticationServiceTests: XCTestCase {
}
}
func testConfigureRegister() async {
func testConfigureLoginWithOIDC() async {
setupMocks()
switch await service.configure(for: "matrix.org", flow: .login) {
case .success:
break
case .failure(let error):
XCTFail("Unexpected failure: \(error)")
}
XCTAssertEqual(service.flow, .login)
XCTAssertEqual(service.homeserver.value, .mockMatrixDotOrg)
}
func testConfigureRegisterWithOIDC() async {
setupMocks()
switch await service.configure(for: "matrix.org", flow: .register) {

View File

@@ -1,70 +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 XCTest
@testable import ElementX
@testable import MatrixRustSDK
class ClientProtocolTests: XCTestCase {
let server = "https://matrix.org"
let userIDServerName = "matrix.org"
let wellKnownURL = "https://matrix.org/.well-known/element/element.json"
var client: ClientProtocol!
func testWellKnownLoggedOut() async {
// Given a client that is logged out but has discovered a server.
let client = ClientSDKMock()
client.userIdServerNameThrowableError = MockError.notAvailable
client.serverReturnValue = server
// When discovering a server that contains the registration helper URL.
client.getUrlUrlClosure = { [wellKnownURL] url in
guard url == wellKnownURL else {
XCTFail("An unexpected URL was used.")
throw MockError.notAvailable
}
return "{\"registration_helper_url\":\"https://develop.element.io/#/mobile_register\"}"
}
guard case let .success(wellKnown) = await client.getElementWellKnown() else {
XCTFail("The request should succeed.")
return
}
// Then the well-known should include that URL.
XCTAssertEqual(wellKnown, .init(call: nil, registrationHelperUrl: "https://develop.element.io/#/mobile_register"))
}
func testWellKnownLoggedIn() async {
// Given a client that is logged in.
let client = ClientSDKMock()
client.userIdServerNameReturnValue = userIDServerName
// When discovering a server that contains a custom call widget URL.
client.getUrlUrlClosure = { [wellKnownURL] url in
guard url == wellKnownURL else {
XCTFail("An unexpected URL was used.")
throw MockError.notAvailable
}
return "{\"call\":{\"widget_url\":\"https://call.element.dev\"}}"
}
guard case let .success(wellKnown) = await client.getElementWellKnown() else {
XCTFail("The request should succeed.")
return
}
// Then the well-known should include that URL.
XCTAssertEqual(wellKnown, .init(call: .init(widgetUrl: "https://call.element.dev"), registrationHelperUrl: nil))
}
enum MockError: Error {
case notAvailable
}
}

View File

@@ -17,7 +17,7 @@ class LoginScreenViewModelTests: XCTestCase {
var clientBuilderFactory: AuthenticationClientBuilderFactoryMock!
var service: AuthenticationServiceProtocol!
private func setupViewModel(homeserverAddress: String = "matrix.org") async {
private func setupViewModel(homeserverAddress: String = "example.com") async {
clientBuilderFactory = AuthenticationClientBuilderFactoryMock(configuration: .init())
service = AuthenticationService(userSessionStore: UserSessionStoreMock(configuration: .init()),
encryptionKeyProvider: EncryptionKeyProvider(),
@@ -36,18 +36,9 @@ class LoginScreenViewModelTests: XCTestCase {
analytics: ServiceLocator.shared.analytics)
}
func testMatrixDotOrg() async {
// Given the initial view model configured for matrix.org.
await setupViewModel()
// Then the view state should contain a homeserver that matches matrix.org and show the login form.
XCTAssertEqual(context.viewState.homeserver, .mockMatrixDotOrg, "The homeserver data should match the default homeserver.")
XCTAssertEqual(context.viewState.loginMode, .password, "The login form should be shown.")
}
func testBasicServer() async {
// Given the view model configured for a basic server example.com that only supports password authentication.
await setupViewModel(homeserverAddress: "example.com")
await setupViewModel()
// Then the view state should be updated with the homeserver and show the login form.
XCTAssertEqual(context.viewState.homeserver, .mockBasicServer, "The homeserver data should should match the new homeserver.")

View File

@@ -89,9 +89,9 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
func testRegistrationNotSupportedAlert() async throws {
// Given a view model for registration using a service that hasn't been configured and the default server doesn't support registration.
setupViewModel(authenticationFlow: .register, supportsRegistrationHelper: false)
// Note: We don't currently take the create prompt into account when determining registration support.
setupViewModel(authenticationFlow: .register, supportsOIDC: false, supportsOIDCCreatePrompt: false)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertFalse(service.homeserver.value.supportsRegistration)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertNil(context.alertInfo)
@@ -100,16 +100,15 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
context.send(viewAction: .confirm)
try await deferred.fulfill()
// Then the configured homeserver should be used and no additional call should be made to the service.
// Then the configuration should fail with an alert about not supporting registration.
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 1)
XCTAssertEqual(context.alertInfo?.id, .registration)
}
func testLoginNotSupportedAlert() async throws {
// Given a view model for login using a service that hasn't been configured and the default server doesn't support login.
setupViewModel(authenticationFlow: .login, supportsRegistrationHelper: false, supportsPasswordLogin: false)
setupViewModel(authenticationFlow: .login, supportsOIDC: false, supportsOIDCCreatePrompt: false, supportsPasswordLogin: false)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertFalse(service.homeserver.value.supportsRegistration)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertNil(context.alertInfo)
@@ -125,14 +124,11 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
// MARK: - Helpers
private func setupViewModel(authenticationFlow: AuthenticationFlow, supportsRegistrationHelper: Bool = true, supportsPasswordLogin: Bool = true) {
private func setupViewModel(authenticationFlow: AuthenticationFlow, supportsOIDC: Bool = true, supportsOIDCCreatePrompt: Bool = true, supportsPasswordLogin: Bool = true) {
// Manually create a configuration as the default homeserver address setting is immutable.
let clientConfiguration: ClientSDKMock.Configuration = if supportsRegistrationHelper {
.init(supportsPasswordLogin: supportsPasswordLogin)
} else {
.init(supportsPasswordLogin: supportsPasswordLogin, elementWellKnown: "")
}
let client = ClientSDKMock(configuration: clientConfiguration)
let client = ClientSDKMock(configuration: .init(oidcLoginURL: supportsOIDC ? "https://account.matrix.org/authorize" : nil,
supportsOIDCCreatePrompt: supportsOIDCCreatePrompt,
supportsPasswordLogin: supportsPasswordLogin))
let configuration = AuthenticationClientBuilderMock.Configuration(homeserverClients: ["matrix.org": client],
qrCodeClient: client)

View File

@@ -21,7 +21,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
// Given a view model for login.
setupViewModel(authenticationFlow: .login)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertFalse(service.homeserver.value.supportsRegistration)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
// When selecting matrix.org.
@@ -39,7 +38,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
// Given a view model for login.
setupViewModel(authenticationFlow: .login)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertFalse(service.homeserver.value.supportsRegistration)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertNil(context.alertInfo)
@@ -58,7 +56,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
// Given a view model for registration.
setupViewModel(authenticationFlow: .register)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertFalse(service.homeserver.value.supportsRegistration)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
// When selecting matrix.org.
@@ -76,7 +73,6 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
// Given a view model for registration.
setupViewModel(authenticationFlow: .register)
XCTAssertEqual(service.homeserver.value.loginMode, .unknown)
XCTAssertFalse(service.homeserver.value.supportsRegistration)
XCTAssertEqual(clientBuilderFactory.makeBuilderSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksCallsCount, 0)
XCTAssertNil(context.alertInfo)

View File

@@ -9,39 +9,14 @@ import XCTest
@testable import ElementX
@MainActor
class SoftLogoutViewModelTests: XCTestCase {
let credentials = SoftLogoutScreenCredentials(userID: "mock_user_id",
homeserverName: "https://matrix.org",
homeserverName: "https://example.com",
userDisplayName: "mock_username",
deviceID: "ABCDEFGH")
@MainActor func testInitialStateForMatrixOrg() {
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
homeserver: .mockMatrixDotOrg,
keyBackupNeeded: true)
let context = viewModel.context
// Given a view model where the user hasn't yet sent the verification email.
XCTAssert(context.password.isEmpty, "The view model should start with an empty password.")
XCTAssertFalse(context.viewState.canSubmit, "The view model should start with an invalid password.")
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
XCTAssert(context.viewState.showRecoverEncryptionKeysMessage, "The view model should show recover encryption keys message.")
}
@MainActor func testInitialStateForMatrixOrgPasswordEntered() {
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
homeserver: .mockMatrixDotOrg,
keyBackupNeeded: true,
password: "12345678")
let context = viewModel.context
// Given a view model where the user hasn't yet sent the verification email.
XCTAssertTrue(context.viewState.canSubmit, "The view model should start with a valid password.")
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
XCTAssert(context.viewState.showRecoverEncryptionKeysMessage, "The view model should show recover encryption keys message.")
}
@MainActor func testInitialStateForBasicServer() {
func testInitialStateForBasicServer() {
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
homeserver: .mockBasicServer,
keyBackupNeeded: false)
@@ -53,10 +28,23 @@ class SoftLogoutViewModelTests: XCTestCase {
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
XCTAssertFalse(context.viewState.showRecoverEncryptionKeysMessage, "The view model should not show recover encryption keys message.")
}
@MainActor func testInitialStateForOIDC() {
func testInitialStateForBasicServerPasswordEntered() {
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
homeserver: .mockOIDC,
homeserver: .mockBasicServer,
keyBackupNeeded: true,
password: "12345678")
let context = viewModel.context
// Given a view model where the user hasn't yet sent the verification email.
XCTAssertTrue(context.viewState.canSubmit, "The view model should start with a valid password.")
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
XCTAssert(context.viewState.showRecoverEncryptionKeysMessage, "The view model should show recover encryption keys message.")
}
func testInitialStateForOIDC() {
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
homeserver: .mockMatrixDotOrg,
keyBackupNeeded: false)
let context = viewModel.context
@@ -67,7 +55,7 @@ class SoftLogoutViewModelTests: XCTestCase {
XCTAssertFalse(context.viewState.showRecoverEncryptionKeysMessage, "The view model should not show recover encryption keys message.")
}
@MainActor func testInitialStateForUnsupported() {
func testInitialStateForUnsupported() {
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
homeserver: .mockUnsupported,
keyBackupNeeded: false)