Add tests for loading Classic accounts.
Tidy up warnings and fix a few bugs that were revealed.
This commit is contained in:
BIN
DevelopmentAssets/ClassicAppFixtures/accountsV2
Normal file
BIN
DevelopmentAssets/ClassicAppFixtures/accountsV2
Normal file
Binary file not shown.
BIN
DevelopmentAssets/ClassicAppFixtures/users/94
Normal file
BIN
DevelopmentAssets/ClassicAppFixtures/users/94
Normal file
Binary file not shown.
@@ -193,6 +193,7 @@
|
|||||||
1D69E31913DF66426985909B /* EmojiPickerScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */; };
|
1D69E31913DF66426985909B /* EmojiPickerScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */; };
|
||||||
1DC227816777A2F3A19657E5 /* RoomDirectorySearchScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCF71646898A2F720C5BFDF5 /* RoomDirectorySearchScreenViewModel.swift */; };
|
1DC227816777A2F3A19657E5 /* RoomDirectorySearchScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCF71646898A2F720C5BFDF5 /* RoomDirectorySearchScreenViewModel.swift */; };
|
||||||
1ECE584D2CFA0FEF0ADE458C /* TestablePreviewsDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA723686F23EF45E2B398FBC /* TestablePreviewsDictionary.swift */; };
|
1ECE584D2CFA0FEF0ADE458C /* TestablePreviewsDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA723686F23EF45E2B398FBC /* TestablePreviewsDictionary.swift */; };
|
||||||
|
1F1BCEE81056FD9F344F3B0E /* ClassicAppAccountManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80935ADC7ED867226225F965 /* ClassicAppAccountManagerTests.swift */; };
|
||||||
1F3232BD368DF430AB433907 /* Compound in Frameworks */ = {isa = PBXBuildFile; productRef = 07FEEEDB11543A7DED420F04 /* Compound */; };
|
1F3232BD368DF430AB433907 /* Compound in Frameworks */ = {isa = PBXBuildFile; productRef = 07FEEEDB11543A7DED420F04 /* Compound */; };
|
||||||
1FE593ECEC40A43789105D80 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */; };
|
1FE593ECEC40A43789105D80 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */; };
|
||||||
1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBCB9676FCD1D0F13188DD /* StringTests.swift */; };
|
1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBCB9676FCD1D0F13188DD /* StringTests.swift */; };
|
||||||
@@ -847,6 +848,7 @@
|
|||||||
92720AB0DA9AB5EEF1DAF56B /* SecureBackupLogoutConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DC017C3CB6B0F7C63F460F2 /* SecureBackupLogoutConfirmationScreenViewModel.swift */; };
|
92720AB0DA9AB5EEF1DAF56B /* SecureBackupLogoutConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DC017C3CB6B0F7C63F460F2 /* SecureBackupLogoutConfirmationScreenViewModel.swift */; };
|
||||||
9278EC51D24E57445B290521 /* AudioSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */; };
|
9278EC51D24E57445B290521 /* AudioSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */; };
|
||||||
9295F1F5E04484E10780BCE8 /* CharacterSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8C01DEEA83903D45069BBD /* CharacterSet.swift */; };
|
9295F1F5E04484E10780BCE8 /* CharacterSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8C01DEEA83903D45069BBD /* CharacterSet.swift */; };
|
||||||
|
92A0309B6F490B86C10B603B /* accountsV2 in Resources */ = {isa = PBXBuildFile; fileRef = 2A7BE2B89310058659E6F459 /* accountsV2 */; };
|
||||||
92D9088B901CEBB1A99ECA4E /* RoomMemberProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */; };
|
92D9088B901CEBB1A99ECA4E /* RoomMemberProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */; };
|
||||||
92FE657CDFAFE3031576EB43 /* LinkNewDeviceScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED096460D7F26F10168FA33B /* LinkNewDeviceScreenViewModelProtocol.swift */; };
|
92FE657CDFAFE3031576EB43 /* LinkNewDeviceScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED096460D7F26F10168FA33B /* LinkNewDeviceScreenViewModelProtocol.swift */; };
|
||||||
9312F5A17AE59A9E910C51D6 /* NotificationItemProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */; };
|
9312F5A17AE59A9E910C51D6 /* NotificationItemProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */; };
|
||||||
@@ -1061,6 +1063,7 @@
|
|||||||
B796A25F282C0A340D1B9C12 /* ImageRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B5EDCD05D50BA9B815C66C /* ImageRoomTimelineItemContent.swift */; };
|
B796A25F282C0A340D1B9C12 /* ImageRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B5EDCD05D50BA9B815C66C /* ImageRoomTimelineItemContent.swift */; };
|
||||||
B79E8AB83EBBDCD476D0362F /* PollFormScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D622EC7898469BB1D0881CDD /* PollFormScreen.swift */; };
|
B79E8AB83EBBDCD476D0362F /* PollFormScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D622EC7898469BB1D0881CDD /* PollFormScreen.swift */; };
|
||||||
B7C9E07F4F9CCC8DD7156A20 /* CallScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28146817C61423CACCF942F5 /* CallScreenModels.swift */; };
|
B7C9E07F4F9CCC8DD7156A20 /* CallScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28146817C61423CACCF942F5 /* CallScreenModels.swift */; };
|
||||||
|
B7DA25BCB68A38AD903AEB06 /* 94 in Resources */ = {isa = PBXBuildFile; fileRef = 1BC752C2A4606C4C2D1ADB41 /* 94 */; };
|
||||||
B7F58D6903F9D509EDAB9E4F /* MediaEventsTimelineScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7033218DA395B003F7AB29A2 /* MediaEventsTimelineScreenModels.swift */; };
|
B7F58D6903F9D509EDAB9E4F /* MediaEventsTimelineScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7033218DA395B003F7AB29A2 /* MediaEventsTimelineScreenModels.swift */; };
|
||||||
B81840E45D8746A4692DA774 /* Tracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B574805B9812C111D6215D /* Tracing.swift */; };
|
B81840E45D8746A4692DA774 /* Tracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B574805B9812C111D6215D /* Tracing.swift */; };
|
||||||
B818580464CFB5400A3EF6AE /* TimelineModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029D5701F80A9AF7167BB4D0 /* TimelineModels.swift */; };
|
B818580464CFB5400A3EF6AE /* TimelineModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029D5701F80A9AF7167BB4D0 /* TimelineModels.swift */; };
|
||||||
@@ -1720,6 +1723,7 @@
|
|||||||
1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreenModels.swift; sourceTree = "<group>"; };
|
1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreenModels.swift; sourceTree = "<group>"; };
|
||||||
1BA5A62DA4B543827FF82354 /* LAContextMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LAContextMock.swift; sourceTree = "<group>"; };
|
1BA5A62DA4B543827FF82354 /* LAContextMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LAContextMock.swift; sourceTree = "<group>"; };
|
||||||
1BA8082E26C77A2C587B34B3 /* MockTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTimelineController.swift; sourceTree = "<group>"; };
|
1BA8082E26C77A2C587B34B3 /* MockTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTimelineController.swift; sourceTree = "<group>"; };
|
||||||
|
1BC752C2A4606C4C2D1ADB41 /* 94 */ = {isa = PBXFileReference; path = 94; sourceTree = "<group>"; };
|
||||||
1C21A715237F2B6D6E80998C /* SecureBackupControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerProtocol.swift; sourceTree = "<group>"; };
|
1C21A715237F2B6D6E80998C /* SecureBackupControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerProtocol.swift; sourceTree = "<group>"; };
|
||||||
1C25B6EBEB414431187D73B7 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
|
1C25B6EBEB414431187D73B7 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
|
||||||
1C78111573987B1D79ED0868 /* LinkMetadataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkMetadataProvider.swift; sourceTree = "<group>"; };
|
1C78111573987B1D79ED0868 /* LinkMetadataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkMetadataProvider.swift; sourceTree = "<group>"; };
|
||||||
@@ -1809,6 +1813,7 @@
|
|||||||
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
|
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
|
||||||
2A2BB38DF61F5100B8723112 /* TimelineMediaPreviewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModels.swift; sourceTree = "<group>"; };
|
2A2BB38DF61F5100B8723112 /* TimelineMediaPreviewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModels.swift; sourceTree = "<group>"; };
|
||||||
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
||||||
|
2A7BE2B89310058659E6F459 /* accountsV2 */ = {isa = PBXFileReference; path = accountsV2; sourceTree = "<group>"; };
|
||||||
2A95C9B8299A36A6495DECA6 /* TracingHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingHook.swift; sourceTree = "<group>"; };
|
2A95C9B8299A36A6495DECA6 /* TracingHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingHook.swift; sourceTree = "<group>"; };
|
||||||
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
|
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
|
||||||
2ADF12A50186B75C68017B61 /* DeclineAndBlockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenViewModelTests.swift; sourceTree = "<group>"; };
|
2ADF12A50186B75C68017B61 /* DeclineAndBlockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -1987,7 +1992,7 @@
|
|||||||
4A2B5274C1D3D2999D643786 /* EncryptionResetPasswordScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
4A2B5274C1D3D2999D643786 /* EncryptionResetPasswordScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockTimerTests.swift; sourceTree = "<group>"; };
|
4A5B4CD611DE7E94F5BA87B2 /* AppLockTimerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockTimerTests.swift; sourceTree = "<group>"; };
|
||||||
4AB29A2D95D3469B5F016655 /* SecureBackupControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerMock.swift; sourceTree = "<group>"; };
|
4AB29A2D95D3469B5F016655 /* SecureBackupControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupControllerMock.swift; sourceTree = "<group>"; };
|
||||||
4B1F71AC585827E6C416C15A /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = wrapper.icon; path = AppIcon.icon; sourceTree = "<group>"; };
|
4B1F71AC585827E6C416C15A /* AppIcon.icon */ = {isa = PBXFileReference; path = AppIcon.icon; sourceTree = "<group>"; };
|
||||||
4B2B564CA6570E1487A7C7CC /* SpaceRoomListProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceRoomListProxy.swift; sourceTree = "<group>"; };
|
4B2B564CA6570E1487A7C7CC /* SpaceRoomListProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceRoomListProxy.swift; sourceTree = "<group>"; };
|
||||||
4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = "<group>"; };
|
4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
|
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
|
||||||
@@ -2253,6 +2258,7 @@
|
|||||||
7FB2253D36E81E045E1CB432 /* Duration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Duration.swift; sourceTree = "<group>"; };
|
7FB2253D36E81E045E1CB432 /* Duration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Duration.swift; sourceTree = "<group>"; };
|
||||||
7FDF541AE914059942B575B4 /* IdentityConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenModels.swift; sourceTree = "<group>"; };
|
7FDF541AE914059942B575B4 /* IdentityConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenModels.swift; sourceTree = "<group>"; };
|
||||||
8063E65441E771200108C558 /* ReadReceiptsSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadReceiptsSummaryView.swift; sourceTree = "<group>"; };
|
8063E65441E771200108C558 /* ReadReceiptsSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadReceiptsSummaryView.swift; sourceTree = "<group>"; };
|
||||||
|
80935ADC7ED867226225F965 /* ClassicAppAccountManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassicAppAccountManagerTests.swift; sourceTree = "<group>"; };
|
||||||
80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageEventStringBuilder.swift; sourceTree = "<group>"; };
|
80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageEventStringBuilder.swift; sourceTree = "<group>"; };
|
||||||
80F04B12FA231E797B7151A8 /* LinkNewDeviceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceTests.swift; sourceTree = "<group>"; };
|
80F04B12FA231E797B7151A8 /* LinkNewDeviceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceTests.swift; sourceTree = "<group>"; };
|
||||||
810133CF215075C285FC6F3A /* test_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = test_image.png; sourceTree = "<group>"; };
|
810133CF215075C285FC6F3A /* test_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = test_image.png; sourceTree = "<group>"; };
|
||||||
@@ -3990,13 +3996,6 @@
|
|||||||
path = SupportingFiles;
|
path = SupportingFiles;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
4001FC7CD65776AB3745245C /* ClassicAppAccountConfirmationScreen */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
path = ClassicAppAccountConfirmationScreen;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
4044C040B64B9F077298C947 /* View */ = {
|
4044C040B64B9F077298C947 /* View */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -4791,6 +4790,7 @@
|
|||||||
7EECE8B331CD169790EF284F /* BugReportScreenViewModelTests.swift */,
|
7EECE8B331CD169790EF284F /* BugReportScreenViewModelTests.swift */,
|
||||||
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
|
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
|
||||||
0328F54E0C3AAEDDF3E05D9D /* ChatsTabFlowCoordinatorTests.swift */,
|
0328F54E0C3AAEDDF3E05D9D /* ChatsTabFlowCoordinatorTests.swift */,
|
||||||
|
80935ADC7ED867226225F965 /* ClassicAppAccountManagerTests.swift */,
|
||||||
D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */,
|
D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */,
|
||||||
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */,
|
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */,
|
||||||
69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */,
|
69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */,
|
||||||
@@ -5783,6 +5783,7 @@
|
|||||||
A8002CB4F20B6282850A614C /* DevelopmentAssets */ = {
|
A8002CB4F20B6282850A614C /* DevelopmentAssets */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
B3C5F21498CA4E4F255D596B /* ClassicAppFixtures */,
|
||||||
DDAF2AD15C368A2809857B6A /* Media */,
|
DDAF2AD15C368A2809857B6A /* Media */,
|
||||||
);
|
);
|
||||||
path = DevelopmentAssets;
|
path = DevelopmentAssets;
|
||||||
@@ -5847,6 +5848,14 @@
|
|||||||
path = NSE;
|
path = NSE;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B0863C1541E34EBE22549125 /* users */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
1BC752C2A4606C4C2D1ADB41 /* 94 */,
|
||||||
|
);
|
||||||
|
path = users;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
B1FC81662045E2369B0C4A0E /* Other */ = {
|
B1FC81662045E2369B0C4A0E /* Other */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -5903,6 +5912,15 @@
|
|||||||
path = SettingsScreen;
|
path = SettingsScreen;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B3C5F21498CA4E4F255D596B /* ClassicAppFixtures */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
2A7BE2B89310058659E6F459 /* accountsV2 */,
|
||||||
|
B0863C1541E34EBE22549125 /* users */,
|
||||||
|
);
|
||||||
|
path = ClassicAppFixtures;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
B470504BE2DC95FAC94FDD79 /* ReadReceipts */ = {
|
B470504BE2DC95FAC94FDD79 /* ReadReceipts */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -6618,7 +6636,6 @@
|
|||||||
children = (
|
children = (
|
||||||
92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */,
|
92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */,
|
||||||
9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */,
|
9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */,
|
||||||
4001FC7CD65776AB3745245C /* ClassicAppAccountConfirmationScreen */,
|
|
||||||
90F48FEF84016ED42A94BA24 /* LoginScreen */,
|
90F48FEF84016ED42A94BA24 /* LoginScreen */,
|
||||||
BA1938A75D8C780F694CEB62 /* ServerConfirmationScreen */,
|
BA1938A75D8C780F694CEB62 /* ServerConfirmationScreen */,
|
||||||
2D0D49B0533C4C2EB889BF3A /* ServerSelectionScreen */,
|
2D0D49B0533C4C2EB889BF3A /* ServerSelectionScreen */,
|
||||||
@@ -7198,6 +7215,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 7AE41FCCF9D1352E2770D1F9 /* Build configuration list for PBXProject "ElementX" */;
|
buildConfigurationList = 7AE41FCCF9D1352E2770D1F9 /* Build configuration list for PBXProject "ElementX" */;
|
||||||
|
compatibilityVersion = "Xcode 14.0";
|
||||||
developmentRegion = en;
|
developmentRegion = en;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
@@ -7273,7 +7291,6 @@
|
|||||||
C89CF7729E028671C5DC461E /* XCLocalSwiftPackageReference "compound-ios" */,
|
C89CF7729E028671C5DC461E /* XCLocalSwiftPackageReference "compound-ios" */,
|
||||||
);
|
);
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
productRefGroup = 681566846AF307E9BA4C72C6 /* Products */;
|
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
@@ -7364,6 +7381,8 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
B7DA25BCB68A38AD903AEB06 /* 94 in Resources */,
|
||||||
|
92A0309B6F490B86C10B603B /* accountsV2 in Resources */,
|
||||||
F252C0EA49088801F4CA6006 /* landscape_test_image.jpg in Resources */,
|
F252C0EA49088801F4CA6006 /* landscape_test_image.jpg in Resources */,
|
||||||
F4582042AA4225CC1E4B8A1E /* landscape_test_video.mov in Resources */,
|
F4582042AA4225CC1E4B8A1E /* landscape_test_video.mov in Resources */,
|
||||||
8F3AD08F2E706AA60F1A1D4D /* portrait_test_image.jpg in Resources */,
|
8F3AD08F2E706AA60F1A1D4D /* portrait_test_image.jpg in Resources */,
|
||||||
@@ -7667,6 +7686,7 @@
|
|||||||
1B2F9F368619FFF8C63C87CC /* BugReportScreenViewModelTests.swift in Sources */,
|
1B2F9F368619FFF8C63C87CC /* BugReportScreenViewModelTests.swift in Sources */,
|
||||||
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
|
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
|
||||||
4BD5AB54A6982CF19F5CC7C4 /* ChatsTabFlowCoordinatorTests.swift in Sources */,
|
4BD5AB54A6982CF19F5CC7C4 /* ChatsTabFlowCoordinatorTests.swift in Sources */,
|
||||||
|
1F1BCEE81056FD9F344F3B0E /* ClassicAppAccountManagerTests.swift in Sources */,
|
||||||
B5321A1F5B26A0F3EC54909E /* CollapsibleFlowLayoutTests.swift in Sources */,
|
B5321A1F5B26A0F3EC54909E /* CollapsibleFlowLayoutTests.swift in Sources */,
|
||||||
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */,
|
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */,
|
||||||
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */,
|
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */,
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
|||||||
|
|
||||||
private func startAuthentication() {
|
private func startAuthentication() {
|
||||||
let encryptionKeyProvider = EncryptionKeyProvider()
|
let encryptionKeyProvider = EncryptionKeyProvider()
|
||||||
let classicAppManager = makeClassicAppManager()
|
let classicAppManager = ClassicAppManager()
|
||||||
let authenticationService = AuthenticationService(userSessionStore: userSessionStore,
|
let authenticationService = AuthenticationService(userSessionStore: userSessionStore,
|
||||||
encryptionKeyProvider: encryptionKeyProvider,
|
encryptionKeyProvider: encryptionKeyProvider,
|
||||||
classicAppManager: classicAppManager,
|
classicAppManager: classicAppManager,
|
||||||
@@ -630,19 +630,6 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeClassicAppManager() -> ClassicAppManagerProtocol? {
|
|
||||||
guard let classicAppGroupIdentifier = InfoPlistReader.main.classicAppGroupIdentifier,
|
|
||||||
let classicAppKeychainServiceIdentifier = InfoPlistReader.main.classicAppKeychainServiceIdentifier,
|
|
||||||
let classicAppKeychainAccessGroupIdentifier = InfoPlistReader.main.classicAppKeychainAccessGroupIdentifier else {
|
|
||||||
MXLog.info("Classic App IDs not set, manager disabled.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return ClassicAppManager(classicAppGroupIdentifier: classicAppGroupIdentifier,
|
|
||||||
classicAppKeychainServiceIdentifier: classicAppKeychainServiceIdentifier,
|
|
||||||
classicAppKeychainAccessGroupIdentifier: classicAppKeychainAccessGroupIdentifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func runPostSessionSetupTasks() async {
|
private func runPostSessionSetupTasks() async {
|
||||||
guard let userSession, let userSessionFlowCoordinator else {
|
guard let userSession, let userSessionFlowCoordinator else {
|
||||||
fatalError("User session not setup")
|
fatalError("User session not setup")
|
||||||
@@ -675,7 +662,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
|||||||
|
|
||||||
let authenticationService = AuthenticationService(userSessionStore: userSessionStore,
|
let authenticationService = AuthenticationService(userSessionStore: userSessionStore,
|
||||||
encryptionKeyProvider: EncryptionKeyProvider(),
|
encryptionKeyProvider: EncryptionKeyProvider(),
|
||||||
classicAppManager: makeClassicAppManager(),
|
classicAppManager: ClassicAppManager(),
|
||||||
appSettings: appSettings,
|
appSettings: appSettings,
|
||||||
appHooks: appHooks)
|
appHooks: appHooks)
|
||||||
_ = await authenticationService.configure(for: userSession.clientProxy.homeserver, flow: .login)
|
_ = await authenticationService.configure(for: userSession.clientProxy.homeserver, flow: .login)
|
||||||
|
|||||||
@@ -25,16 +25,16 @@ class ClassicAppAccountManager {
|
|||||||
func loadAccounts() {
|
func loadAccounts() {
|
||||||
MXLog.info("Loading accounts from Classic app.")
|
MXLog.info("Loading accounts from Classic app.")
|
||||||
|
|
||||||
|
// First we need to load the accounts file, which contains an array of MXKAccounts (a super class of MXAccount).
|
||||||
let accountFile = accountFile()
|
let accountFile = accountFile()
|
||||||
if FileManager.default.fileExists(atPath: accountFile.path(percentEncoded: false)) {
|
if FileManager.default.fileExists(atPath: accountFile.path(percentEncoded: false)) {
|
||||||
let startDate = Date()
|
let startDate = Date()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let fileContent = try Data(contentsOf: accountFile, options: [.alwaysMapped, .uncached])
|
let fileContent = try Data(contentsOf: accountFile, options: [.alwaysMapped, .uncached])
|
||||||
|
|
||||||
// Decrypt data if encryption method is provided
|
|
||||||
let unciphered = try ClassicAppAES.decrypt(fileContent, aesKey: aesKey, iv: iv)
|
let unciphered = try ClassicAppAES.decrypt(fileContent, aesKey: aesKey, iv: iv)
|
||||||
let decoder = NSKeyedUnarchiver(forReadingWith: unciphered)
|
let decoder = try NSKeyedUnarchiver(forReadingFrom: unciphered)
|
||||||
|
decoder.requiresSecureCoding = false
|
||||||
decoder.setClass(ClassicAppMXAccount.self, forClassName: "MXKAccount")
|
decoder.setClass(ClassicAppMXAccount.self, forClassName: "MXKAccount")
|
||||||
|
|
||||||
guard let mxAccounts = decoder.decodeObject(forKey: "mxAccounts") as? [ClassicAppMXAccount] else {
|
guard let mxAccounts = decoder.decodeObject(forKey: "mxAccounts") as? [ClassicAppMXAccount] else {
|
||||||
@@ -44,6 +44,8 @@ class ClassicAppAccountManager {
|
|||||||
|
|
||||||
MXLog.info("\(mxAccounts.count) accounts loaded in \(Date().timeIntervalSince(startDate) * 1000)ms.")
|
MXLog.info("\(mxAccounts.count) accounts loaded in \(Date().timeIntervalSince(startDate) * 1000)ms.")
|
||||||
|
|
||||||
|
// Only consider active accounts using the same logic as Element Classic and then
|
||||||
|
// combine the MXAccount data with its profile and crypto store details.
|
||||||
accounts = mxAccounts
|
accounts = mxAccounts
|
||||||
.filter(\.isActive)
|
.filter(\.isActive)
|
||||||
.compactMap(makeAccount)
|
.compactMap(makeAccount)
|
||||||
@@ -57,9 +59,10 @@ class ClassicAppAccountManager {
|
|||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
|
/// Combines an MXAccount with its profile and crypto store details.
|
||||||
private func makeAccount(for mxAccount: ClassicAppMXAccount) -> ClassicAppAccount? {
|
private func makeAccount(for mxAccount: ClassicAppMXAccount) -> ClassicAppAccount? {
|
||||||
let userID = mxAccount.userID
|
let userID = mxAccount.userID
|
||||||
let user = loadUser(for: mxAccount)
|
let user = loadUser(for: mxAccount) // We need an MXUser for the profile as MXAccount doesn't contain that data.
|
||||||
|
|
||||||
guard let serverName = serverName(for: userID) else { return nil }
|
guard let serverName = serverName(for: userID) else { return nil }
|
||||||
|
|
||||||
@@ -72,13 +75,21 @@ class ClassicAppAccountManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func loadUser(for mxAccount: ClassicAppMXAccount) -> ClassicAppMXUser? {
|
private func loadUser(for mxAccount: ClassicAppMXAccount) -> ClassicAppMXUser? {
|
||||||
|
// Users are stored across multiple files, so first find the right file for this particular user.
|
||||||
let userID = mxAccount.userID
|
let userID = mxAccount.userID
|
||||||
let groupID = String(userID.hash % 100)
|
let groupID = String(UInt(bitPattern: userID.hash) % 100) // Swift's .hash is Int whereas Objective-C's is UInt.
|
||||||
let groupFile = storeUsersPath(for: userID).appendingPathComponent(groupID)
|
let groupFile = storeUsersPath(for: userID).appending(component: groupID)
|
||||||
|
|
||||||
|
guard FileManager.default.fileExists(atPath: groupFile.path(percentEncoded: false)) else {
|
||||||
|
MXLog.warning("Missing users group \(groupID) file for \(mxAccount.userID).")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
// And then load that file and find the user within its data.
|
||||||
let fileContent = try Data(contentsOf: groupFile)
|
let fileContent = try Data(contentsOf: groupFile)
|
||||||
let decoder = NSKeyedUnarchiver(forReadingWith: fileContent)
|
let decoder = try NSKeyedUnarchiver(forReadingFrom: fileContent)
|
||||||
|
decoder.requiresSecureCoding = false
|
||||||
decoder.setClass(ClassicAppMXUser.self, forClassName: "MXUser")
|
decoder.setClass(ClassicAppMXUser.self, forClassName: "MXUser")
|
||||||
decoder.setClass(ClassicAppMXUser.self, forClassName: "MXMyUser")
|
decoder.setClass(ClassicAppMXUser.self, forClassName: "MXMyUser")
|
||||||
|
|
||||||
@@ -92,7 +103,6 @@ class ClassicAppAccountManager {
|
|||||||
|
|
||||||
/// The server name extracted from the user's ID.
|
/// The server name extracted from the user's ID.
|
||||||
private func serverName(for userID: String) -> String? {
|
private func serverName(for userID: String) -> String? {
|
||||||
#warning("Expose a serverName method for this from the SDK?")
|
|
||||||
let components = userID.components(separatedBy: ":")
|
let components = userID.components(separatedBy: ":")
|
||||||
guard components.count > 1 else { return nil }
|
guard components.count > 1 else { return nil }
|
||||||
return components[1] // Directly use [1] as .last may be the port number.
|
return components[1] // Directly use [1] as .last may be the port number.
|
||||||
@@ -107,17 +117,17 @@ class ClassicAppAccountManager {
|
|||||||
private static let kMXFileStoreUsersFolder = "users"
|
private static let kMXFileStoreUsersFolder = "users"
|
||||||
|
|
||||||
/// The file URL that contains the app's `MXAccounts` array.
|
/// The file URL that contains the app's `MXAccounts` array.
|
||||||
private func accountFile() -> URL {
|
func accountFile() -> URL {
|
||||||
cacheFolder.appending(component: Self.matrixKitFolder).appending(component: Self.kMXKAccountsKey)
|
cacheFolder.appending(component: Self.matrixKitFolder).appending(component: Self.kMXKAccountsKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The database file URL as defined in `MXCryptoMachineStore`.
|
/// The database file URL as defined in `MXCryptoMachineStore`.
|
||||||
private func cryptoStoreURL(for userID: String) -> URL {
|
func cryptoStoreURL(for userID: String) -> URL {
|
||||||
cacheFolder.appending(component: Self.cryptoStoreFolder).appending(component: userID)
|
cacheFolder.appending(component: Self.cryptoStoreFolder).appending(component: userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This store contains all of the users known to the specific user ID.
|
/// This store contains all of the users known to the specific user ID.
|
||||||
private func storeUsersPath(for userID: String) -> URL {
|
func storeUsersPath(for userID: String) -> URL {
|
||||||
storePath(for: userID).appending(component: Self.kMXFileStoreUsersFolder)
|
storePath(for: userID).appending(component: Self.kMXFileStoreUsersFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ClassicAppAccount {
|
struct ClassicAppAccount: Equatable {
|
||||||
let userID: String
|
let userID: String
|
||||||
let displayName: String?
|
let displayName: String?
|
||||||
let avatarURL: URL?
|
let avatarURL: URL?
|
||||||
@@ -18,7 +18,7 @@ struct ClassicAppAccount {
|
|||||||
|
|
||||||
// MARK: NSCoding Types
|
// MARK: NSCoding Types
|
||||||
|
|
||||||
class ClassicAppMXAccount: NSObject, NSCoding {
|
final class ClassicAppMXAccount: NSObject, NSCoding {
|
||||||
/// The obtained user ID.
|
/// The obtained user ID.
|
||||||
var userID: String
|
var userID: String
|
||||||
/// The homeserver url (ex: "https://matrix.org").
|
/// The homeserver url (ex: "https://matrix.org").
|
||||||
@@ -83,7 +83,7 @@ class ClassicAppMXAccount: NSObject, NSCoding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `MXUser` represents a user in Matrix.
|
/// `MXUser` represents a user in Matrix.
|
||||||
class ClassicAppMXUser: NSObject, NSCoding {
|
final class ClassicAppMXUser: NSObject, NSCoding {
|
||||||
/// The user id.
|
/// The user id.
|
||||||
let userID: String
|
let userID: String
|
||||||
/// The user display name.
|
/// The user display name.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ enum ClassicAppManagerError: Error {
|
|||||||
case missingCryptoStorePassphrase
|
case missingCryptoStorePassphrase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads accounts from Element Classic's shared storage.
|
||||||
final class ClassicAppManager: ClassicAppManagerProtocol {
|
final class ClassicAppManager: ClassicAppManagerProtocol {
|
||||||
private enum KeychainKeys: String {
|
private enum KeychainKeys: String {
|
||||||
case cryptoSDKStoreKey
|
case cryptoSDKStoreKey
|
||||||
@@ -29,16 +30,28 @@ final class ClassicAppManager: ClassicAppManagerProtocol {
|
|||||||
private let classicAppGroupIdentifier: String
|
private let classicAppGroupIdentifier: String
|
||||||
private let keychain: Keychain
|
private let keychain: Keychain
|
||||||
|
|
||||||
init(classicAppGroupIdentifier: String, classicAppKeychainServiceIdentifier: String, classicAppKeychainAccessGroupIdentifier: String) {
|
/// Creates an instance using the Classic app identifiers specified in the `Info.plist` file.
|
||||||
|
/// Returns `nil` when a Classic app has not been configured in the project.
|
||||||
|
init?(classicAppGroupIdentifier: String? = InfoPlistReader.main.classicAppGroupIdentifier,
|
||||||
|
classicAppKeychainServiceIdentifier: String? = InfoPlistReader.main.classicAppKeychainServiceIdentifier,
|
||||||
|
classicAppKeychainAccessGroupIdentifier: String? = InfoPlistReader.main.classicAppKeychainAccessGroupIdentifier) {
|
||||||
|
guard let classicAppGroupIdentifier, let classicAppKeychainServiceIdentifier, let classicAppKeychainAccessGroupIdentifier else {
|
||||||
|
MXLog.info("Classic App IDs not available, skipping initialisation.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
self.classicAppGroupIdentifier = classicAppGroupIdentifier
|
self.classicAppGroupIdentifier = classicAppGroupIdentifier
|
||||||
keychain = Keychain(service: classicAppKeychainServiceIdentifier, accessGroup: classicAppKeychainAccessGroupIdentifier)
|
keychain = Keychain(service: classicAppKeychainServiceIdentifier, accessGroup: classicAppKeychainAccessGroupIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads all of the active accounts from the Classic app.
|
||||||
func loadAccounts() throws -> [ClassicAppAccount] {
|
func loadAccounts() throws -> [ClassicAppAccount] {
|
||||||
|
// The account data is stored in the App Group container.
|
||||||
guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: classicAppGroupIdentifier) else {
|
guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: classicAppGroupIdentifier) else {
|
||||||
throw ClassicAppManagerError.invalidAppGroupIdentifier(classicAppGroupIdentifier)
|
throw ClassicAppManagerError.invalidAppGroupIdentifier(classicAppGroupIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// And the data is encrypted with keys that are stored in the Keychain.
|
||||||
guard let accountIV = try keychain.getData(KeychainKeys.accountIV.rawValue),
|
guard let accountIV = try keychain.getData(KeychainKeys.accountIV.rawValue),
|
||||||
let accountAESKey = try keychain.getData(KeychainKeys.accountAESKey.rawValue) else {
|
let accountAESKey = try keychain.getData(KeychainKeys.accountAESKey.rawValue) else {
|
||||||
throw ClassicAppManagerError.missingAccountKeys
|
throw ClassicAppManagerError.missingAccountKeys
|
||||||
|
|||||||
83
UnitTests/Sources/ClassicAppAccountManagerTests.swift
Normal file
83
UnitTests/Sources/ClassicAppAccountManagerTests.swift
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2026 Element Creations Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
@testable import ElementX
|
||||||
|
import Foundation
|
||||||
|
import Testing
|
||||||
|
|
||||||
|
final class ClassicAppAccountManagerTests {
|
||||||
|
let testDirectory: URL = .temporaryDirectory.appending(component: UUID().uuidString)
|
||||||
|
let accountAESKey: Data
|
||||||
|
let accountIV: Data
|
||||||
|
let cryptoStorePassphrase: Data
|
||||||
|
|
||||||
|
let classicAppAccountManager: ClassicAppAccountManager
|
||||||
|
|
||||||
|
init() throws {
|
||||||
|
accountAESKey = try #require(Data(base64Encoded: "BzaSCm5i8QhJr6wGBPj7MDvqBwkwuHLqkRxprVV2zJE="))
|
||||||
|
accountIV = try #require(Data(base64Encoded: "dMmg6H2dYTRBE8PwjfAbAQ=="))
|
||||||
|
cryptoStorePassphrase = try #require(Data(base64Encoded: "ERE/ZXw8rlY3Lv3MBG9sV9g+euOuJnrJaSuvrAMWPrI="))
|
||||||
|
|
||||||
|
classicAppAccountManager = ClassicAppAccountManager(cacheFolder: testDirectory,
|
||||||
|
aesKey: accountAESKey,
|
||||||
|
iv: accountIV,
|
||||||
|
cryptoStorePassphrase: cryptoStorePassphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func noAccounts() {
|
||||||
|
classicAppAccountManager.loadAccounts()
|
||||||
|
|
||||||
|
#expect(classicAppAccountManager.accounts.isEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func activeAccount() throws {
|
||||||
|
let account = ClassicAppAccount.mock(classicAppAccountManager: classicAppAccountManager,
|
||||||
|
cryptoStorePassphrase: cryptoStorePassphrase)
|
||||||
|
|
||||||
|
try setupFixtures(for: account)
|
||||||
|
|
||||||
|
classicAppAccountManager.loadAccounts()
|
||||||
|
|
||||||
|
#expect(classicAppAccountManager.accounts.count == 1)
|
||||||
|
#expect(classicAppAccountManager.accounts.first == account)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
|
||||||
|
private func setupFixtures(for account: ClassicAppAccount) throws {
|
||||||
|
let bundle = Bundle(for: Self.self)
|
||||||
|
|
||||||
|
// Copy the accountsV2 file (contains the MXKAccount for the signed in user).
|
||||||
|
let accountFileSource = try #require(bundle.url(forResource: "accountsV2", withExtension: nil))
|
||||||
|
let accountFileDestination = classicAppAccountManager.accountFile()
|
||||||
|
try FileManager.default.createDirectory(at: accountFileDestination.deletingLastPathComponent(), withIntermediateDirectories: true)
|
||||||
|
try FileManager.default.copyItem(at: accountFileSource, to: accountFileDestination)
|
||||||
|
|
||||||
|
// Copy the required users file (contains a subset of known MXUsers including the signed in user).
|
||||||
|
let userFileName = "94" // UInt(bitPattern: account.userID.hash) % 100
|
||||||
|
let userFileSource = try #require(bundle.url(forResource: userFileName, withExtension: nil))
|
||||||
|
let usersDestination = classicAppAccountManager.storeUsersPath(for: account.userID)
|
||||||
|
try FileManager.default.createDirectory(at: usersDestination, withIntermediateDirectories: true)
|
||||||
|
try FileManager.default.copyItem(at: userFileSource, to: usersDestination.appending(component: userFileName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ClassicAppAccount {
|
||||||
|
/// Creates a mock account based on the fixtures used by this test.
|
||||||
|
static func mock(classicAppAccountManager: ClassicAppAccountManager, cryptoStorePassphrase: Data) -> ClassicAppAccount {
|
||||||
|
let userID = "@classicappaccount:matrix.org"
|
||||||
|
|
||||||
|
return ClassicAppAccount(userID: userID,
|
||||||
|
displayName: "Classic App Account",
|
||||||
|
avatarURL: "mxc://matrix.org/LYIzLOiILkjQJCqsgzAOUirs",
|
||||||
|
serverName: "matrix.org",
|
||||||
|
cryptoStoreURL: classicAppAccountManager.cryptoStoreURL(for: userID),
|
||||||
|
cryptoStorePassphrase: cryptoStorePassphrase)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,7 +49,9 @@ targets:
|
|||||||
sources:
|
sources:
|
||||||
- path: ../Sources
|
- path: ../Sources
|
||||||
- path: ../SupportingFiles
|
- path: ../SupportingFiles
|
||||||
- path: ../../DevelopmentAssets
|
- path: ../../DevelopmentAssets/Media
|
||||||
|
- path: ../../DevelopmentAssets/ClassicAppFixtures
|
||||||
|
buildPhase: resources # Necessary to add binary files to the target.
|
||||||
- path: ../../ElementX/Sources/Other/Extensions/Publisher.swift
|
- path: ../../ElementX/Sources/Other/Extensions/Publisher.swift
|
||||||
- path: ../../ElementX/Sources/Other/Extensions/XCTestCase.swift
|
- path: ../../ElementX/Sources/Other/Extensions/XCTestCase.swift
|
||||||
- path: ../../ElementX/Sources/Other/InfoPlistReader.swift
|
- path: ../../ElementX/Sources/Other/InfoPlistReader.swift
|
||||||
|
|||||||
Reference in New Issue
Block a user