diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index a8bb00fcb..ce8aed24d 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */; }; 0B1F80C2BF7D223159FBA82C /* ImageAnonymizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6045E825AE900A92D61FEFF0 /* ImageAnonymizerTests.swift */; }; 0C38C3E771B472E27295339D /* SessionVerificationModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BB9A17AC512A7EF4B106E5 /* SessionVerificationModels.swift */; }; + 0C601923A872A87C775B889A /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3689E6F87850DD65DAA45428 /* KeychainControllerProtocol.swift */; }; 0E8C480700870BB34A2A360F /* AppAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 4346F63D53A346271577FD9C /* AppAuth */; }; 0EA6537A07E2DC882AEA5962 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 187853A7E643995EE49FAD43 /* Localizable.stringsdict */; }; 0ED951768EC443A8728DE1D7 /* TimelineStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */; }; @@ -54,7 +55,6 @@ 19839F3526CE8C35AAF241AD /* ServerSelectionViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F52BF30D12BA3BD3D3DBB8F /* ServerSelectionViewModelProtocol.swift */; }; 1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; }; 1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; }; - 1CA5FC60B93D5AA60972ACFE /* UserSessionFlowCoordinatorStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04A526B2825F72617D57461 /* UserSessionFlowCoordinatorStateMachine.swift */; }; 1E59B77A0B2CE83DCC1B203C /* LoginViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05707BF550D770168A406DB /* LoginViewModelTests.swift */; }; 1F3232BD368DF430AB433907 /* DesignKit in Frameworks */ = {isa = PBXBuildFile; productRef = A5A56C4F47C368EBE5C5E870 /* DesignKit */; }; 1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBCB9676FCD1D0F13188DD /* StringTests.swift */; }; @@ -75,6 +75,7 @@ 29E20505F321071E8375F99B /* BuildSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263B3B811C2B900F12C6F695 /* BuildSettings.swift */; }; 29EE1791E0AFA1ABB7F23D2F /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = A981A4CA233FB5C13B9CA690 /* SwiftyBeaver */; }; 2A90D9F91A836E30B7D78838 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E438DBCBDC7A41B95DDDD9 /* MXLogObjcWrapper.m */; }; + 2B9AEEC12B1BBE5BD61D0F5E /* UserSessionFlowCoordinatorStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3429142FE11930422E7CC1A0 /* UserSessionFlowCoordinatorStateMachine.swift */; }; 2BA59D0AEFB4B82A2EC2A326 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 78A5A8DE1E2B09C978C7F3B0 /* KeychainAccess */; }; 2BAA5B222856068158D0B3C6 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = B1E8B697DF78FE7F61FC6CA4 /* MatrixRustSDK */; }; 2C0CE61E5DC177938618E0B1 /* RootRouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90733775209F4D4D366A268F /* RootRouterType.swift */; }; @@ -84,7 +85,6 @@ 30122AB3484AC6C3A7F6A717 /* ActivityIndicatorView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B64F3A3D0DF86ED5A241AB05 /* ActivityIndicatorView.xib */; }; 308BD9343B95657FAA583FB7 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = AD2AC190E55B2BD4D0F1D4A7 /* SwiftyBeaver */; }; 3097A0A867D2B19CE32DAE58 /* UIKitBackgroundTaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF1FFC3336EB23374BBBFCC /* UIKitBackgroundTaskService.swift */; }; - 313382FC5D38064EAAA35CB2 /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D1CC633517D695FEC54208 /* FileManager.swift */; }; 32BA37B01B05261FCF2D4B45 /* WeakDictionaryKeyReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090CA61A835C151CEDF8F372 /* WeakDictionaryKeyReference.swift */; }; 33CAC1226DFB8B5D8447D286 /* SwiftState in Frameworks */ = {isa = PBXBuildFile; productRef = 3853B78FB8531B83936C5DA6 /* SwiftState */; }; 344AF4CBB6D8786214878642 /* NavigationRouterStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9D5F812E5AD6DC786DBC9B /* NavigationRouterStoreProtocol.swift */; }; @@ -184,13 +184,13 @@ 78B71D53C1FC55FB7A9B75F0 /* RoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24B0C97D2F560BCB72BE73B1 /* RoomTimelineController.swift */; }; 78BF60C696FFED63AAF58D10 /* SoftLogoutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22D46DB0CC6C55EBA7AE67A3 /* SoftLogoutViewModel.swift */; }; 7963F98CDFDEAC75E072BD81 /* TextRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6A8C632CEF4600107792899 /* TextRoomTimelineItem.swift */; }; - 79A6E08ADE6E7C460A8A17A5 /* UserSessionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C37FB986891D90BEAA93EAE /* UserSessionStore.swift */; }; 7A54700193DC1F264368746A /* UserIndicatorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E077F76026C85ED96FEBB810 /* UserIndicatorPresenter.swift */; }; 7A71AEF419904209BB8C2833 /* UserAgentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */; }; 7AE1FFB132F2B84EB8A2AEBC /* TemplateViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3340ABAE3A4647E80163AE18 /* TemplateViewModelTests.swift */; }; 7BB31E67648CF32D2AB5E502 /* RoomScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE3C90E487B255B735D73C8 /* RoomScreenViewModel.swift */; }; 7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; }; 7D1DAAA364A9A29D554BD24E /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0950733DD4BA83EEE752E259 /* PlaceholderAvatarImage.swift */; }; + 7E91BAC17963ED41208F489B /* UserSessionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8BDC092D817B68CD9040C5 /* UserSessionStore.swift */; }; 7F08F4BC1312075E2B5EAEFA /* AuthenticationServiceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */; }; 7F19E97E7985F518C9018B83 /* RootRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF47564C584F614B7287F3EB /* RootRouter.swift */; }; 7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */; }; @@ -210,6 +210,7 @@ 8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BC7CA1BC1041E93077BBA1 /* HomeScreenModels.swift */; }; 890F0D453FE388756479AC97 /* AnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C687844F60BFF532D49A994C /* AnalyticsTests.swift */; }; 8AB8ED1051216546CB35FA0E /* UserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5E9C044BEB7C70B1378E91 /* UserSession.swift */; }; + 8B807DC963D1D4155A241BCC /* UserSessionFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F9E67AAB66638C69626866C /* UserSessionFlowCoordinator.swift */; }; 8BBD3AA589DEE02A1B0923B2 /* NoticeRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F49CDE349C490D617332770 /* NoticeRoomTimelineItem.swift */; }; 8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */; }; 8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */; }; @@ -251,6 +252,7 @@ A32517FB1CA0BBCE2BC75249 /* BugReportCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6C07DA7D3FF193F7419F55 /* BugReportCoordinator.swift */; }; A371629728E597C5FCA3C2B2 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73FC861755C6388F62B9280A /* Analytics.swift */; }; A37EED79941AD3B7140B3822 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287FC98AF2664EAD79C0D902 /* UIDevice.swift */; }; + A494741843F087881299ACF0 /* RestorationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3558A15CFB934F9229301527 /* RestorationToken.swift */; }; A4E885358D7DD5A072A06824 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = CCE5BF78B125320CBF3BB834 /* PostHog */; }; A50849766F056FD1DB942DEA /* AlertInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EEB64CC6F3DF5B68736A6B4 /* AlertInfo.swift */; }; A5C8F013ED9FB8AA6FEE18A7 /* InfoPlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A901D95158B02CA96C79C7F /* InfoPlist.swift */; }; @@ -265,8 +267,8 @@ AB34401E4E1CAD5D2EC3072B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9760103CF316DF68698BCFE6 /* LaunchScreen.storyboard */; }; AB4C5D62A21AD712811CE8CD /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68232D336E2B546AD95B78B5 /* XCUIElement.swift */; }; ABF3FAB234AD3565B214309B /* TimelineSenderAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC588051E6572A1AF51D738 /* TimelineSenderAvatarView.swift */; }; + AC69B6DF15FC451AB2945036 /* UserSessionStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */; }; ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */; }; - AE9EDA4805FCD42553255807 /* UserSessionFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 562B0F8048BB22FB0C086CB8 /* UserSessionFlowCoordinator.swift */; }; B037C365CF8A58A0D149A2DB /* AuthenticationIconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97755C01C3971474EFAD5367 /* AuthenticationIconImage.swift */; }; B064D42BA087649ACAE462E8 /* SoftLogoutUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55F30E764BED111C81739844 /* SoftLogoutUITests.swift */; }; B09514A0A3EB3C19A4FD0B71 /* SoftLogoutScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCBDE671A613B3EB70794C4 /* SoftLogoutScreen.swift */; }; @@ -325,6 +327,7 @@ DDB80FD2753FEAAE43CC2AAE /* ImageRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A63815AD6A5C306453342F2 /* ImageRoomTimelineItem.swift */; }; DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */; }; DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */; }; + DF790EF2E4D41D1091AEB263 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 317F02B15921BF5CC8486990 /* KeychainController.swift */; }; DFF7D6A6C26DDD40D00AE579 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = F012CB5EE3F2B67359F6CC52 /* target.yml */; }; E01373F2043E76393A0CE073 /* AnalyticsPromptViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11B74ACE8D71747E1044A9C /* AnalyticsPromptViewModel.swift */; }; E0A4DCA633D174EB43AD599F /* BackgroundTaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */; }; @@ -339,7 +342,6 @@ EA1E7949533E19C6D862680A /* MediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885D8C42DD17625B5261BEFF /* MediaProvider.swift */; }; EA31DD9043B91ECB8E45A9A6 /* ScreenshotDetectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03C9D319676F3C0DC6B0203 /* ScreenshotDetectorTests.swift */; }; EA65360A0EC026DD83AC0CF5 /* AuthenticationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6CA5F386C7701C129398945 /* AuthenticationCoordinator.swift */; }; - EBD6C79705B3DDB2F7E5F554 /* UserSessionStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1B52D0ABBA7091A991CAFE /* UserSessionStoreProtocol.swift */; }; EC280623A42904341363EAAF /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 886A0A498FA01E8EDD451D05 /* Sentry */; }; EC4C31963E755EEC77BD778C /* AnalyticsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B362E695A7103C11F64B185 /* AnalyticsSettings.swift */; }; EE4F5601356228FF72FC56B6 /* MockClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F40F48279322E504153AB0D /* MockClientProxy.swift */; }; @@ -348,8 +350,6 @@ EF99A92701E401C4CD5ADC50 /* SplashScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCE978A6118C131D7F2A04B3 /* SplashScreenModels.swift */; }; F040ABFEB0A2B142D948BA12 /* Untranslated.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = F75DF9500D69A3AAF8339E69 /* Untranslated.stringsdict */; }; F0F82C3C848C865C3098AA52 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 67E7A6F388D3BF85767609D9 /* Sentry */; }; - F2DD8661B5C0BA2BB526FA6C /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD51F9FDC91C231906D76C8 /* KeychainControllerProtocol.swift */; }; - F4C3FEDB1B3A05376A1723A3 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4427F9E0571B4E6E048A2B /* KeychainController.swift */; }; F508683B76EF7B23BB2CBD6D /* TimelineItemPlainStylerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94BCC8A9C73C1F838122C645 /* TimelineItemPlainStylerView.swift */; }; F56261126E368C831B3DE976 /* NavigationRouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 752DEC02D93AFF46BC13313A /* NavigationRouterType.swift */; }; F656F92A63D3DC1978D79427 /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = 2A3F7BCCB18C15B30CCA39A9 /* AnalyticsEvents */; }; @@ -361,6 +361,7 @@ FC6B7436C3A5B3D0565227D5 /* ActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF05352F28D4E7336228E9F4 /* ActivityIndicatorView.swift */; }; FCB640C576292BEAF7FA3B2E /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F395A2E917115C7AAF7F34 /* SplashViewController.swift */; }; FCD3F2B82CAB29A07887A127 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; }; + FD4706DC752744A0C91ED6FE /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B275C686F8253E655E42BA3 /* FileManager.swift */; }; FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1593DD87F974F8509BB619 /* ElementAnimations.swift */; }; FE79E2BCCF69E8BF4D21E15A /* RoomMessageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA154570F693D93513E584C1 /* RoomMessageFactory.swift */; }; FFD3E4FF948E06C7585317FC /* TimelineStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892E29C98C4E8182C9037F84 /* TimelineStyler.swift */; }; @@ -411,9 +412,9 @@ 0BC588051E6572A1AF51D738 /* TimelineSenderAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSenderAvatarView.swift; sourceTree = ""; }; 0C13A92C1E9C79F055B8133D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ar; path = ar.lproj/Localizable.stringsdict; sourceTree = ""; }; 0CB569EAA5017B5B23970655 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = ""; }; - 0CD51F9FDC91C231906D76C8 /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = ""; }; 0DD16CE9A66C9040B066AD60 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Localizable.stringsdict; sourceTree = ""; }; 0E7062F88E9D5F79C8A80524 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = th; path = th.lproj/Localizable.stringsdict; sourceTree = ""; }; + 0E8BDC092D817B68CD9040C5 /* UserSessionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStore.swift; sourceTree = ""; }; 0EE9EAF0309A2A1D67D8FAF5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Localizable.stringsdict; sourceTree = ""; }; 0F52BF30D12BA3BD3D3DBB8F /* ServerSelectionViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelProtocol.swift; sourceTree = ""; }; 0F7A812F160E75B69A9181A2 /* SplashScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenCoordinator.swift; sourceTree = ""; }; @@ -477,6 +478,7 @@ 2EEB64CC6F3DF5B68736A6B4 /* AlertInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertInfo.swift; sourceTree = ""; }; 2F1B28C596DE541DA0AFD16C /* lo */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lo; path = lo.lproj/Localizable.stringsdict; sourceTree = ""; }; 304FFD608DB6E612075AB1B4 /* WeakDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionary.swift; sourceTree = ""; }; + 317F02B15921BF5CC8486990 /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = ""; }; 31B01468022EC826CB2FD2C0 /* LoginModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginModels.swift; sourceTree = ""; }; 31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModel.swift; sourceTree = ""; }; 325A2B3278875554DDEB8A9B /* SplashScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenUITests.swift; sourceTree = ""; }; @@ -484,14 +486,16 @@ 32CE6D4FF64C9A3C18619224 /* SplashScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreen.swift; sourceTree = ""; }; 3340ABAE3A4647E80163AE18 /* TemplateViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateViewModelTests.swift; sourceTree = ""; }; 33E49C5C6F802B4D94CA78D1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; + 3429142FE11930422E7CC1A0 /* UserSessionFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinatorStateMachine.swift; sourceTree = ""; }; 351E89CE2ED9B73C5CC47955 /* TimelineReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReactionsView.swift; sourceTree = ""; }; + 3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = ""; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; + 3689E6F87850DD65DAA45428 /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = ""; }; 3747C96188856006F784BF49 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ko; path = ko.lproj/Localizable.stringsdict; sourceTree = ""; }; 3782C506F4FF1AADF61B6212 /* tlh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tlh; path = tlh.lproj/Localizable.strings; sourceTree = ""; }; 398817652FA8ABAE0A31AC6D /* ReadableFrameModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadableFrameModifier.swift; sourceTree = ""; }; 399427358A80BA2848E698A2 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = ""; }; 39EBB6903EFD4236B8D11A42 /* fr-CA */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "fr-CA"; path = "fr-CA.lproj/Localizable.stringsdict"; sourceTree = ""; }; - 3A4427F9E0571B4E6E048A2B /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = ""; }; 3ACBDC1D28EFB7789EB467E0 /* MockRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomProxy.swift; sourceTree = ""; }; 3B5B535DA49C54523FF7A412 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nn; path = nn.lproj/Localizable.strings; sourceTree = ""; }; 3BFEC43A1A0769F1EAC62873 /* MXLogObjcWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXLogObjcWrapper.h; sourceTree = ""; }; @@ -503,6 +507,7 @@ 3DD6E7C1D8B53F47789778CD /* fr-CA */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-CA"; path = "fr-CA.lproj/Localizable.strings"; sourceTree = ""; }; 3DF1FFC3336EB23374BBBFCC /* UIKitBackgroundTaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitBackgroundTaskService.swift; sourceTree = ""; }; 3F40F48279322E504153AB0D /* MockClientProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockClientProxy.swift; sourceTree = ""; }; + 3F9E67AAB66638C69626866C /* UserSessionFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinator.swift; sourceTree = ""; }; 3FAA6438B00FDB130F404E31 /* UserIndicatorStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorStore.swift; sourceTree = ""; }; 3FDFF4C1153D263BAB93C1F3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 3FEE631F3A4AFDC6652DD9DA /* RoomTimelineViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewFactory.swift; sourceTree = ""; }; @@ -550,11 +555,9 @@ 541542F5AC323709D8563458 /* AnalyticsPrompt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPrompt.swift; sourceTree = ""; }; 5445FCE0CE15E634FDC1A2E2 /* AnalyticsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsService.swift; sourceTree = ""; }; 54E438DBCBDC7A41B95DDDD9 /* MXLogObjcWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXLogObjcWrapper.m; sourceTree = ""; }; - 551DAED7F623AA5366E79927 /* repository */ = {isa = PBXFileReference; lastKnownFileType = folder; name = repository; path = .; sourceTree = SOURCE_ROOT; }; 55BC11560C8A2598964FFA4C /* bs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bs; path = bs.lproj/Localizable.strings; sourceTree = ""; }; 55D7187F6B0C0A651AC3DFFA /* in */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = in; path = in.lproj/Localizable.strings; sourceTree = ""; }; 55F30E764BED111C81739844 /* SoftLogoutUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutUITests.swift; sourceTree = ""; }; - 562B0F8048BB22FB0C086CB8 /* UserSessionFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinator.swift; sourceTree = ""; }; 56F01DD1BBD4450E18115916 /* LabelledActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelledActivityIndicatorView.swift; sourceTree = ""; }; 5773C86AF04AEF26515AD00C /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Localizable.strings; sourceTree = ""; }; 5872785B9C7934940146BFBA /* MXLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXLogger.h; sourceTree = ""; }; @@ -589,6 +592,7 @@ 6A6C4BE591FE5C38CE9C7EF3 /* UserProperties+Element.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserProperties+Element.swift"; sourceTree = ""; }; 6A901D95158B02CA96C79C7F /* InfoPlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPlist.swift; sourceTree = ""; }; 6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegex.swift; sourceTree = ""; }; + 6B275C686F8253E655E42BA3 /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = ""; }; 6B73A8C3118EAC7BF3F3EE7A /* SplashScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenViewModelProtocol.swift; sourceTree = ""; }; 6BC38904A9663F7FAFD47457 /* SoftLogoutViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutViewModelProtocol.swift; sourceTree = ""; }; 6D4777F0142E330A75C46FE4 /* SessionVerificationUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationUITests.swift; sourceTree = ""; }; @@ -641,7 +645,6 @@ 8AC1A01C3A745BDF1D3697D3 /* SessionVerificationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreen.swift; sourceTree = ""; }; 8B9A55AC2FB0FE0AEAA3DF1F /* LICENSE */ = {isa = PBXFileReference; path = LICENSE; sourceTree = ""; }; 8C0AA893D6F8A2F563E01BB9 /* in */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = in; path = in.lproj/Localizable.stringsdict; sourceTree = ""; }; - 8C37FB986891D90BEAA93EAE /* UserSessionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStore.swift; sourceTree = ""; }; 8D6094DEAAEB388E1AE118C6 /* MockRoomTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineProvider.swift; sourceTree = ""; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = ""; }; @@ -692,7 +695,6 @@ A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = ""; }; A72232816DCE2B76D48E1367 /* nb-NO */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "nb-NO"; path = "nb-NO.lproj/Localizable.strings"; sourceTree = ""; }; A8903A9F615BBD0E6D7CD133 /* ApplicationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationProtocol.swift; sourceTree = ""; }; - A8D1CC633517D695FEC54208 /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = ""; }; A8F48EB9B52E70285A4BCB07 /* ur */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ur; path = ur.lproj/Localizable.strings; sourceTree = ""; }; A9873374E72AA53260AE90A2 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Localizable.strings; sourceTree = ""; }; A9FAFE1C2149E6AC8156ED2B /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; }; @@ -737,10 +739,9 @@ BB3073CCD77D906B330BC1D6 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; BC9B05D6B293A039EB963CA7 /* az */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = az; path = az.lproj/Localizable.strings; sourceTree = ""; }; BE6C10032A77AE7DC5AA4C50 /* MessageComposerTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageComposerTextField.swift; sourceTree = ""; }; + BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStoreProtocol.swift; sourceTree = ""; }; BEE6BF9BA63FF42F8AF6EEEA /* sr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sr; path = sr.lproj/Localizable.stringsdict; sourceTree = ""; }; - BF1B52D0ABBA7091A991CAFE /* UserSessionStoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStoreProtocol.swift; sourceTree = ""; }; C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementXAttributeScope.swift; sourceTree = ""; }; - C04A526B2825F72617D57461 /* UserSessionFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionFlowCoordinatorStateMachine.swift; sourceTree = ""; }; C06FCD42EEFEFC220F14EAC5 /* SessionVerificationStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationStateMachine.swift; sourceTree = ""; }; C070FD43DC6BF4E50217965A /* LocalizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationTests.swift; sourceTree = ""; }; C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenModels.swift; sourceTree = ""; }; @@ -780,6 +781,7 @@ D0ADFDC712027931F2216668 /* WeakKeyDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakKeyDictionary.swift; sourceTree = ""; }; D1A9CCCF53495CF3D7B19FCE /* MockSessionVerificationControllerProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSessionVerificationControllerProxy.swift; sourceTree = ""; }; D29EBCBFEC6FD0941749404D /* NavigationRouterStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouterStore.swift; sourceTree = ""; }; + D31DC8105C6233E5FFD9B84C /* element-x-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "element-x-ios"; path = .; sourceTree = SOURCE_ROOT; }; D33116993D54FADC0C721C1F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; D4DA544B2520BFA65D6DB4BB /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenCoordinator.swift; sourceTree = ""; }; @@ -951,7 +953,7 @@ 82D5AD3EAE3A5C1068A44A88 /* Session */, 5329E48968EB951235E83DAE /* SessionVerification */, FCDF06BDB123505F0334B4F9 /* Timeline */, - 90C85A862720155C0CF63B02 /* UserSessionStore */, + CBBF6127C313A5412E438BC6 /* UserSession */, ); path = Services; sourceTree = ""; @@ -1485,18 +1487,6 @@ path = HTMLParsing; sourceTree = ""; }; - 90C85A862720155C0CF63B02 /* UserSessionStore */ = { - isa = PBXGroup; - children = ( - A8D1CC633517D695FEC54208 /* FileManager.swift */, - 3A4427F9E0571B4E6E048A2B /* KeychainController.swift */, - 0CD51F9FDC91C231906D76C8 /* KeychainControllerProtocol.swift */, - 8C37FB986891D90BEAA93EAE /* UserSessionStore.swift */, - BF1B52D0ABBA7091A991CAFE /* UserSessionStoreProtocol.swift */, - ); - path = UserSessionStore; - sourceTree = ""; - }; 90F48FEF84016ED42A94BA24 /* LoginScreen */ = { isa = PBXGroup; children = ( @@ -1514,7 +1504,7 @@ 9413F680ECDFB2B0DDB0DEF2 /* Packages */ = { isa = PBXGroup; children = ( - 551DAED7F623AA5366E79927 /* repository */, + D31DC8105C6233E5FFD9B84C /* element-x-ios */, ); name = Packages; sourceTree = SOURCE_ROOT; @@ -1715,15 +1705,6 @@ path = SoftLogout; sourceTree = ""; }; - BA21F24D618D719E70E1EDAE /* UserSession */ = { - isa = PBXGroup; - children = ( - 562B0F8048BB22FB0C086CB8 /* UserSessionFlowCoordinator.swift */, - C04A526B2825F72617D57461 /* UserSessionFlowCoordinatorStateMachine.swift */, - ); - path = UserSession; - sourceTree = ""; - }; C0937E3B06A8F0E2DB7C8241 /* Other */ = { isa = PBXGroup; children = ( @@ -1758,6 +1739,21 @@ path = UITests; sourceTree = ""; }; + CBBF6127C313A5412E438BC6 /* UserSession */ = { + isa = PBXGroup; + children = ( + 6B275C686F8253E655E42BA3 /* FileManager.swift */, + 317F02B15921BF5CC8486990 /* KeychainController.swift */, + 3689E6F87850DD65DAA45428 /* KeychainControllerProtocol.swift */, + 3558A15CFB934F9229301527 /* RestorationToken.swift */, + 3F9E67AAB66638C69626866C /* UserSessionFlowCoordinator.swift */, + 3429142FE11930422E7CC1A0 /* UserSessionFlowCoordinatorStateMachine.swift */, + 0E8BDC092D817B68CD9040C5 /* UserSessionStore.swift */, + BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */, + ); + path = UserSession; + sourceTree = ""; + }; CCD48459CA34A1928EC7A26A /* Supplementary */ = { isa = PBXGroup; children = ( @@ -1854,7 +1850,6 @@ isa = PBXGroup; children = ( A78C2592419CA4C76FBA8FD2 /* Application */, - BA21F24D618D719E70E1EDAE /* UserSession */, 0787F81684E503024BD0C051 /* Services */, E59565F441830B19DBAE567C /* Screens */, C0937E3B06A8F0E2DB7C8241 /* Other */, @@ -2425,7 +2420,7 @@ 6647430A45B4A8E692909A8F /* EmoteRoomTimelineItem.swift in Sources */, 68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */, 02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */, - 313382FC5D38064EAAA35CB2 /* FileManager.swift in Sources */, + FD4706DC752744A0C91ED6FE /* FileManager.swift in Sources */, A0A0D2A9564BDA3FDE2E360F /* FormattedBodyText.swift in Sources */, 85AFBB433AD56704A880F8A0 /* FramePreferenceKey.swift in Sources */, 6A367F3D7A437A79B7D9A31C /* FullscreenLoadingViewPresenter.swift in Sources */, @@ -2442,8 +2437,8 @@ D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */, A5C8F013ED9FB8AA6FEE18A7 /* InfoPlist.swift in Sources */, E3CA565A4B9704F191B191F0 /* JoinedRoomSize+MemberCount.swift in Sources */, - F4C3FEDB1B3A05376A1723A3 /* KeychainController.swift in Sources */, - F2DD8661B5C0BA2BB526FA6C /* KeychainControllerProtocol.swift in Sources */, + DF790EF2E4D41D1091AEB263 /* KeychainController.swift in Sources */, + 0C601923A872A87C775B889A /* KeychainControllerProtocol.swift in Sources */, 9C9E48A627C7C166084E3F5B /* LabelledActivityIndicatorView.swift in Sources */, 15D867E638BFD0E5E71DB1EF /* List.swift in Sources */, 83E5054739949181CA981193 /* LoginCoordinator.swift in Sources */, @@ -2493,6 +2488,7 @@ 53B9C2240C2F5533246EE230 /* RectangleToastView.swift in Sources */, 00EA14F62DCEF62CDE4808D6 /* RedactedRoomTimelineItem.swift in Sources */, 13853973A5E24374FCEDE8A3 /* RedactedRoomTimelineView.swift in Sources */, + A494741843F087881299ACF0 /* RestorationToken.swift in Sources */, BFD1AC03B6F8C5F5897D5B55 /* ReversedScrollView.swift in Sources */, 04A16B45228F7678A027C079 /* RoomHeaderView.swift in Sources */, FE79E2BCCF69E8BF4D21E15A /* RoomMessageFactory.swift in Sources */, @@ -2602,11 +2598,11 @@ 80E04BE80A89A78FBB4863BB /* UserIndicatorViewPresentable.swift in Sources */, 9CCC77C31CB399661A034739 /* UserProperties+Element.swift in Sources */, 8AB8ED1051216546CB35FA0E /* UserSession.swift in Sources */, - AE9EDA4805FCD42553255807 /* UserSessionFlowCoordinator.swift in Sources */, - 1CA5FC60B93D5AA60972ACFE /* UserSessionFlowCoordinatorStateMachine.swift in Sources */, + 8B807DC963D1D4155A241BCC /* UserSessionFlowCoordinator.swift in Sources */, + 2B9AEEC12B1BBE5BD61D0F5E /* UserSessionFlowCoordinatorStateMachine.swift in Sources */, 978BB24F2A5D31EE59EEC249 /* UserSessionProtocol.swift in Sources */, - 79A6E08ADE6E7C460A8A17A5 /* UserSessionStore.swift in Sources */, - EBD6C79705B3DDB2F7E5F554 /* UserSessionStoreProtocol.swift in Sources */, + 7E91BAC17963ED41208F489B /* UserSessionStore.swift in Sources */, + AC69B6DF15FC451AB2945036 /* UserSessionStoreProtocol.swift in Sources */, 6FC10A00D268FCD48B631E37 /* ViewFrameReader.swift in Sources */, 6DF37000571B1BC6D134CC9E /* WeakDictionary.swift in Sources */, 32BA37B01B05261FCF2D4B45 /* WeakDictionaryKeyReference.swift in Sources */, @@ -3236,7 +3232,7 @@ repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = "1.0.16-alpha"; + version = "1.0.17-alpha"; }; }; 96495DD8554E2F39D3954354 /* XCRemoteSwiftPackageReference "posthog-ios" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4369aa5ec..2a5c097b5 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -86,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-rust-components-swift", "state" : { - "revision" : "af6683ca5ddd9da7f582de4258e4d6ebb8a8caff", - "version" : "1.0.16-alpha" + "revision" : "85335b5f6766753100983dced122731dfa5fa308", + "version" : "1.0.17-alpha" } }, { diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 7d54262a3..6130cfe10 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -303,7 +303,7 @@ class AppCoordinator: Coordinator { self.stateMachine.processEvent(.remoteSignOut(isSoft: isSoftLogout)) case .updateRestoreTokenNeeded: if let userSession = self.userSession { - _ = self.userSessionStore.refreshRestoreToken(for: userSession) + _ = self.userSessionStore.refreshRestorationToken(for: userSession) } default: break diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index 7ec910a0f..8d3dce2fa 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -95,7 +95,7 @@ class ClientProxy: ClientProxyProtocol { .build() self.slidingSync = try slidingSyncBuilder - .addView(view: slidingSyncView) + .addView(v: slidingSyncView) .withCommonExtensions() .build() @@ -136,9 +136,9 @@ class ClientProxy: ClientProxyProtocol { client.homeserver() } - var restoreToken: String? { + var restorationToken: RestorationToken? { do { - return try client.restoreToken() + return try RestorationToken(session: client.session()) } catch { MXLog.error("Failed retrieving restore token with error: \(error)") return nil diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index 30f694c20..7f9430304 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -44,7 +44,7 @@ protocol ClientProxyProtocol { var homeserver: String { get } - var restoreToken: String? { get } + var restorationToken: RestorationToken? { get } var roomSummaryProvider: RoomSummaryProviderProtocol { get } diff --git a/ElementX/Sources/Services/Client/MockClientProxy.swift b/ElementX/Sources/Services/Client/MockClientProxy.swift index d13e445ac..3adab27b6 100644 --- a/ElementX/Sources/Services/Client/MockClientProxy.swift +++ b/ElementX/Sources/Services/Client/MockClientProxy.swift @@ -24,7 +24,7 @@ struct MockClientProxy: ClientProxyProtocol { let isSoftLogout = false let deviceId: String? = nil let homeserver = "" - let restoreToken: String? = nil + let restorationToken: RestorationToken? = nil var roomSummaryProvider: RoomSummaryProviderProtocol = MockRoomSummaryProvider() diff --git a/ElementX/Sources/Services/UserSessionStore/FileManager.swift b/ElementX/Sources/Services/UserSession/FileManager.swift similarity index 100% rename from ElementX/Sources/Services/UserSessionStore/FileManager.swift rename to ElementX/Sources/Services/UserSession/FileManager.swift diff --git a/ElementX/Sources/Services/UserSession/KeychainController.swift b/ElementX/Sources/Services/UserSession/KeychainController.swift new file mode 100644 index 000000000..e6e3d72e1 --- /dev/null +++ b/ElementX/Sources/Services/UserSession/KeychainController.swift @@ -0,0 +1,85 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import KeychainAccess + +class KeychainController: KeychainControllerProtocol { + private let keychain: Keychain + + init(identifier: String) { + keychain = Keychain(service: identifier) + } + + func setRestorationToken(_ restorationToken: RestorationToken, forUsername username: String) { + do { + let tokenData = try JSONEncoder().encode(restorationToken) + try keychain.set(tokenData, key: username) + } catch { + MXLog.error("Failed storing user restore token with error: \(error)") + } + } + + func restorationTokenForUsername(_ username: String) -> RestorationToken? { + do { + guard let tokenData = try keychain.getData(username) else { + return nil + } + + // Handle the previous restoration token format as we don't want users to have to log in again + // It will automatically be updated to the new version after login + if let legacyRestorationToken = try? JSONDecoder().decode(LegacyRestorationToken.self, from: tokenData) { + return .init(session: .init(accessToken: legacyRestorationToken.session.accessToken, + refreshToken: nil, + userId: legacyRestorationToken.session.userId, + deviceId: legacyRestorationToken.session.deviceId, + homeserverUrl: legacyRestorationToken.homeURL, + isSoftLogout: legacyRestorationToken.isSoftLogout ?? false)) + } + + return try JSONDecoder().decode(RestorationToken.self, from: tokenData) + } catch { + MXLog.error("Failed retrieving user restore token") + return nil + } + } + + func restorationTokens() -> [KeychainCredentials] { + keychain.allKeys().compactMap { username in + guard let restorationToken = restorationTokenForUsername(username) else { + return nil + } + + return KeychainCredentials(userID: username, restorationToken: restorationToken) + } + } + + func removeRestorationTokenForUsername(_ username: String) { + do { + try keychain.remove(username) + } catch { + MXLog.error("Failed removing restore token with error: \(error)") + } + } + + func removeAllRestorationTokens() { + do { + try keychain.removeAll() + } catch { + MXLog.error("Failed removing all tokens") + } + } +} diff --git a/ElementX/Sources/Services/UserSessionStore/KeychainControllerProtocol.swift b/ElementX/Sources/Services/UserSession/KeychainControllerProtocol.swift similarity index 66% rename from ElementX/Sources/Services/UserSessionStore/KeychainControllerProtocol.swift rename to ElementX/Sources/Services/UserSession/KeychainControllerProtocol.swift index e367f98d7..c7d21a6fe 100644 --- a/ElementX/Sources/Services/UserSessionStore/KeychainControllerProtocol.swift +++ b/ElementX/Sources/Services/UserSession/KeychainControllerProtocol.swift @@ -18,13 +18,13 @@ import Foundation struct KeychainCredentials { let userID: String - let restoreToken: String + let restorationToken: RestorationToken } protocol KeychainControllerProtocol { - func setRestoreToken(_ accessToken: String, forUsername username: String) - func restoreTokenForUsername(_ username: String) -> String? - func restoreTokens() -> [KeychainCredentials] - func removeRestoreTokenForUsername(_ username: String) - func removeAllRestoreTokens() + func setRestorationToken(_ restorationToken: RestorationToken, forUsername: String) + func restorationTokenForUsername(_ username: String) -> RestorationToken? + func restorationTokens() -> [KeychainCredentials] + func removeRestorationTokenForUsername(_ username: String) + func removeAllRestorationTokens() } diff --git a/ElementX/Sources/Services/UserSession/RestorationToken.swift b/ElementX/Sources/Services/UserSession/RestorationToken.swift new file mode 100644 index 000000000..0cfbcc51e --- /dev/null +++ b/ElementX/Sources/Services/UserSession/RestorationToken.swift @@ -0,0 +1,76 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import MatrixRustSDK + +struct RestorationToken: Codable, Equatable { + let session: MatrixRustSDK.Session +} + +extension MatrixRustSDK.Session: Codable { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self = .init(accessToken: try container.decode(String.self, forKey: .accessToken), + refreshToken: try container.decodeIfPresent(String.self, forKey: .refreshToken), + userId: try container.decode(String.self, forKey: .userId), + deviceId: try container.decode(String.self, forKey: .deviceId), + homeserverUrl: try container.decode(String.self, forKey: .homeserverUrl), + isSoftLogout: try container.decode(Bool.self, forKey: .isSoftLogout)) + } + + 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(isSoftLogout, forKey: .isSoftLogout) + } + + enum CodingKeys: String, CodingKey { + case accessToken, refreshToken, userId, deviceId, homeserverUrl, isSoftLogout + } +} + +#warning("Remove this in a couple of releases - sceriu 03.11.2022") +struct LegacyRestorationToken: Decodable { + let isGuest: Bool? + let isSoftLogout: Bool? + let homeURL: String + let session: Session + + enum CodingKeys: String, CodingKey { + case isGuest = "is_guest" + case isSoftLogout = "is_soft_logout" + case homeURL = "homeurl" + case session + } + + struct Session: Decodable { + let accessToken: String + let userId: String + let deviceId: String + + // swiftlint:disable:next nesting + enum CodingKeys: String, CodingKey { + case accessToken = "access_token" + case userId = "user_id" + case deviceId = "device_id" + } + } +} diff --git a/ElementX/Sources/UserSession/UserSessionFlowCoordinator.swift b/ElementX/Sources/Services/UserSession/UserSessionFlowCoordinator.swift similarity index 100% rename from ElementX/Sources/UserSession/UserSessionFlowCoordinator.swift rename to ElementX/Sources/Services/UserSession/UserSessionFlowCoordinator.swift diff --git a/ElementX/Sources/UserSession/UserSessionFlowCoordinatorStateMachine.swift b/ElementX/Sources/Services/UserSession/UserSessionFlowCoordinatorStateMachine.swift similarity index 100% rename from ElementX/Sources/UserSession/UserSessionFlowCoordinatorStateMachine.swift rename to ElementX/Sources/Services/UserSession/UserSessionFlowCoordinatorStateMachine.swift diff --git a/ElementX/Sources/Services/UserSessionStore/UserSessionStore.swift b/ElementX/Sources/Services/UserSession/UserSessionStore.swift similarity index 86% rename from ElementX/Sources/Services/UserSessionStore/UserSessionStore.swift rename to ElementX/Sources/Services/UserSession/UserSessionStore.swift index 02af03d81..8d835345c 100644 --- a/ElementX/Sources/Services/UserSessionStore/UserSessionStore.swift +++ b/ElementX/Sources/Services/UserSession/UserSessionStore.swift @@ -23,7 +23,7 @@ class UserSessionStore: UserSessionStoreProtocol { private let backgroundTaskService: BackgroundTaskServiceProtocol /// Whether or not there are sessions in the store. - var hasSessions: Bool { !keychainController.restoreTokens().isEmpty } + var hasSessions: Bool { !keychainController.restorationTokens().isEmpty } /// The base directory where all session data is stored. private(set) lazy var baseDirectory: URL = { @@ -49,7 +49,7 @@ class UserSessionStore: UserSessionStoreProtocol { } func restoreUserSession() async -> Result { - let availableCredentials = keychainController.restoreTokens() + let availableCredentials = keychainController.restorationTokens() guard let credentials = availableCredentials.first else { return .failure(.missingCredentials) @@ -65,7 +65,7 @@ class UserSessionStore: UserSessionStoreProtocol { MXLog.error("Failed restoring login with error: \(error)") // On any restoration failure reset the token and restart - keychainController.removeAllRestoreTokens() + keychainController.removeAllRestorationTokens() deleteSessionDirectory(for: credentials.userID) return .failure(error) @@ -85,19 +85,19 @@ class UserSessionStore: UserSessionStoreProtocol { } } - func refreshRestoreToken(for userSession: UserSessionProtocol) -> Result { - guard let accessToken = userSession.clientProxy.restoreToken else { + func refreshRestorationToken(for userSession: UserSessionProtocol) -> Result { + guard let restorationToken = userSession.clientProxy.restorationToken else { return .failure(.failedRefreshingRestoreToken) } - keychainController.setRestoreToken(accessToken, forUsername: userSession.clientProxy.userIdentifier) + keychainController.setRestorationToken(restorationToken, forUsername: userSession.clientProxy.userIdentifier) return .success(()) } func logout(userSession: UserSessionProtocol) { let userID = userSession.clientProxy.userIdentifier - keychainController.removeRestoreTokenForUsername(userID) + keychainController.removeRestorationTokenForUsername(userID) deleteSessionDirectory(for: userID) } @@ -109,12 +109,13 @@ class UserSessionStore: UserSessionStoreProtocol { let builder = ClientBuilder() .basePath(path: baseDirectory.path) .username(username: credentials.userID) + .homeserverUrl(url: credentials.restorationToken.session.homeserverUrl) .userAgent(userAgent: UserAgentBuilder.makeASCIIUserAgent() ?? "unknown") do { let client: Client = try await Task.dispatch(on: .global()) { let client = try builder.build() - try client.restoreLogin(restoreToken: credentials.restoreToken) + try client.restoreSession(session: credentials.restorationToken.session) return client } return await setupProxyForClient(client) @@ -126,10 +127,10 @@ class UserSessionStore: UserSessionStoreProtocol { private func setupProxyForClient(_ client: Client) async -> Result { do { - let accessToken = try client.restoreToken() + let session = try client.session() let userId = try client.userId() - keychainController.setRestoreToken(accessToken, forUsername: userId) + keychainController.setRestorationToken(RestorationToken(session: session), forUsername: userId) } catch { MXLog.error("Failed setting up user session with error: \(error)") return .failure(.failedSettingUpSession) diff --git a/ElementX/Sources/Services/UserSessionStore/UserSessionStoreProtocol.swift b/ElementX/Sources/Services/UserSession/UserSessionStoreProtocol.swift similarity index 93% rename from ElementX/Sources/Services/UserSessionStore/UserSessionStoreProtocol.swift rename to ElementX/Sources/Services/UserSession/UserSessionStoreProtocol.swift index f6facad68..c402ee2fb 100644 --- a/ElementX/Sources/Services/UserSessionStore/UserSessionStoreProtocol.swift +++ b/ElementX/Sources/Services/UserSession/UserSessionStoreProtocol.swift @@ -38,7 +38,7 @@ protocol UserSessionStoreProtocol { func userSession(for client: Client) async -> Result /// Refresh the restore token of the client for a given session. - func refreshRestoreToken(for userSession: UserSessionProtocol) -> Result + func refreshRestorationToken(for userSession: UserSessionProtocol) -> Result /// Logs out of the specified session. func logout(userSession: UserSessionProtocol) diff --git a/ElementX/Sources/Services/UserSessionStore/KeychainController.swift b/ElementX/Sources/Services/UserSessionStore/KeychainController.swift deleted file mode 100644 index 5c69877cc..000000000 --- a/ElementX/Sources/Services/UserSessionStore/KeychainController.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation -import KeychainAccess - -class KeychainController: KeychainControllerProtocol { - private let keychain: Keychain - - init(identifier: String) { - keychain = Keychain(service: identifier) - } - - func setRestoreToken(_ restoreToken: String, forUsername username: String) { - do { - try keychain.set(restoreToken, key: username) - } catch { - MXLog.error("Failed storing user restore token with error: \(error)") - } - } - - func restoreTokenForUsername(_ username: String) -> String? { - do { - return try keychain.get(username) - } catch { - MXLog.error("Failed retrieving user restore token") - return nil - } - } - - func restoreTokens() -> [KeychainCredentials] { - keychain.allKeys().compactMap { username in - guard let restoreToken = restoreTokenForUsername(username) else { - return nil - } - - return KeychainCredentials(userID: username, restoreToken: restoreToken) - } - } - - func removeRestoreTokenForUsername(_ username: String) { - do { - try keychain.remove(username) - } catch { - MXLog.error("Failed removing restore token with error: \(error)") - } - } - - func removeAllRestoreTokens() { - do { - try keychain.removeAll() - } catch { - MXLog.error("Failed removing all tokens") - } - } -} diff --git a/UnitTests/Sources/KeychainControllerTests.swift b/UnitTests/Sources/KeychainControllerTests.swift index 58901faba..2647294bb 100644 --- a/UnitTests/Sources/KeychainControllerTests.swift +++ b/UnitTests/Sources/KeychainControllerTests.swift @@ -22,68 +22,70 @@ class KeychainControllerTests: XCTestCase { override func setUp() { keychain = KeychainController(identifier: "\(ElementInfoPlist.cfBundleIdentifier).tests") - keychain.removeAllRestoreTokens() + keychain.removeAllRestorationTokens() } - func testAddRestoreToken() { + func testAddRestorationToken() { // Given an empty keychain. - XCTAssertTrue(keychain.restoreTokens().isEmpty, "The keychain should be empty to begin with.") + XCTAssertTrue(keychain.restorationTokens().isEmpty, "The keychain should be empty to begin with.") - // When adding an restore token. + // When adding an restoration token. let username = "@test:example.com" - let restoreToken = UUID().uuidString - keychain.setRestoreToken(restoreToken, forUsername: username) + let restorationToken = RestorationToken(session: .init(accessToken: "accessToken", refreshToken: "refreshToken", userId: "userId", deviceId: "deviceId", homeserverUrl: "homeserverUrl", isSoftLogout: false)) + keychain.setRestorationToken(restorationToken, forUsername: username) - // Then the restore token should be stored in the keychain. - XCTAssertEqual(keychain.restoreTokenForUsername(username), restoreToken, "The retrieved restore token should match the value that was stored.") + // Then the restoration token should be stored in the keychain. + XCTAssertEqual(keychain.restorationTokenForUsername(username), restorationToken, "The retrieved restoration token should match the value that was stored.") } - func testRemovingRestoreToken() { - // Given a keychain with a stored restore token. + func testRemovingRestorationToken() { + // Given a keychain with a stored restoration token. let username = "@test:example.com" - let restoreToken = UUID().uuidString - keychain.setRestoreToken(restoreToken, forUsername: username) - XCTAssertEqual(keychain.restoreTokens().count, 1, "The keychain should have 1 restore token.") - XCTAssertEqual(keychain.restoreTokenForUsername(username), restoreToken, "The initial restore token should match the value that was stored.") + let restorationToken = RestorationToken(session: .init(accessToken: "accessToken", refreshToken: "refreshToken", userId: "userId", deviceId: "deviceId", homeserverUrl: "homeserverUrl", isSoftLogout: false)) + keychain.setRestorationToken(restorationToken, forUsername: username) + 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.") - // When deleting the restore token. - keychain.removeRestoreTokenForUsername(username) + // When deleting the restoration token. + keychain.removeRestorationTokenForUsername(username) // Then the keychain should be empty. - XCTAssertTrue(keychain.restoreTokens().isEmpty, "The keychain should be empty after deleting the token.") - XCTAssertNil(keychain.restoreTokenForUsername(username), "There restore token should not be returned after removal.") + XCTAssertTrue(keychain.restorationTokens().isEmpty, "The keychain should be empty after deleting the token.") + XCTAssertNil(keychain.restorationTokenForUsername(username), "There restoration token should not be returned after removal.") } - func testRemovingAllRestoreTokens() { - // Given a keychain with 5 stored restore tokens. + func testRemovingAllRestorationTokens() { + // Given a keychain with 5 stored restoration tokens. for index in 0..<5 { - keychain.setRestoreToken(UUID().uuidString, forUsername: "@test\(index):example.com") + let restorationToken = RestorationToken(session: .init(accessToken: "accessToken", refreshToken: "refreshToken", userId: "userId", deviceId: "deviceId", homeserverUrl: "homeserverUrl", isSoftLogout: false)) + keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") } - XCTAssertEqual(keychain.restoreTokens().count, 5, "The keychain should have 5 restore tokens.") + XCTAssertEqual(keychain.restorationTokens().count, 5, "The keychain should have 5 restoration tokens.") - // When deleting all of the restore tokens. - keychain.removeAllRestoreTokens() + // When deleting all of the restoration tokens. + keychain.removeAllRestorationTokens() // Then the keychain should be empty. - XCTAssertTrue(keychain.restoreTokens().isEmpty, "The keychain should be empty after deleting the token.") + XCTAssertTrue(keychain.restorationTokens().isEmpty, "The keychain should be empty after deleting the token.") } - func testRemovingSingleRestoreTokens() { - // Given a keychain with 5 stored restore tokens. + func testRemovingSingleRestorationTokens() { + // Given a keychain with 5 stored restoration tokens. for index in 0..<5 { - keychain.setRestoreToken(UUID().uuidString, forUsername: "@test\(index):example.com") + let restorationToken = RestorationToken(session: .init(accessToken: "accessToken", refreshToken: "refreshToken", userId: "userId", deviceId: "deviceId", homeserverUrl: "homeserverUrl", isSoftLogout: false)) + keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") } - XCTAssertEqual(keychain.restoreTokens().count, 5, "The keychain should have 5 restore tokens.") + XCTAssertEqual(keychain.restorationTokens().count, 5, "The keychain should have 5 restoration tokens.") - // When deleting one of the restore tokens. - keychain.removeRestoreTokenForUsername("@test2:example.com") + // When deleting one of the restoration tokens. + keychain.removeRestorationTokenForUsername("@test2:example.com") // Then the other 4 items should remain untouched. - XCTAssertEqual(keychain.restoreTokens().count, 4, "The keychain have 4 remaining restore tokens.") - XCTAssertNotNil(keychain.restoreTokenForUsername("@test0:example.com"), "The restore token should not have been deleted.") - XCTAssertNotNil(keychain.restoreTokenForUsername("@test1:example.com"), "The restore token should not have been deleted.") - XCTAssertNil(keychain.restoreTokenForUsername("@test2:example.com"), "The restore token should have been deleted.") - XCTAssertNotNil(keychain.restoreTokenForUsername("@test3:example.com"), "The restore token should not have been deleted.") - XCTAssertNotNil(keychain.restoreTokenForUsername("@test4:example.com"), "The restore token should not have been deleted.") + XCTAssertEqual(keychain.restorationTokens().count, 4, "The keychain have 4 remaining restoration tokens.") + XCTAssertNotNil(keychain.restorationTokenForUsername("@test0:example.com"), "The restoration token should not have been deleted.") + XCTAssertNotNil(keychain.restorationTokenForUsername("@test1:example.com"), "The restoration token should not have been deleted.") + XCTAssertNil(keychain.restorationTokenForUsername("@test2:example.com"), "The restoration token should have been deleted.") + XCTAssertNotNil(keychain.restorationTokenForUsername("@test3:example.com"), "The restoration token should not have been deleted.") + XCTAssertNotNil(keychain.restorationTokenForUsername("@test4:example.com"), "The restoration token should not have been deleted.") } } diff --git a/changelog.d/239.bugfix b/changelog.d/239.bugfix new file mode 100644 index 000000000..48fb564dc --- /dev/null +++ b/changelog.d/239.bugfix @@ -0,0 +1 @@ +Allow session restoration even while offline \ No newline at end of file diff --git a/project.yml b/project.yml index fa6a12fe0..abc58d9b5 100644 --- a/project.yml +++ b/project.yml @@ -35,7 +35,7 @@ include: packages: MatrixRustSDK: url: https://github.com/matrix-org/matrix-rust-components-swift - exactVersion: 1.0.16-alpha + exactVersion: 1.0.17-alpha # path: ../matrix-rust-components-swift DesignKit: path: ./