diff --git a/CHANGES.md b/CHANGES.md index 8605fe8212..00324a763e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,19 @@ +## Changes in 0.26.2 (2023-03-21) + +🙌 Improvements + +- Crypto: Always update tracked users when sharing keys ([#1733](https://github.com/matrix-org/matrix-ios-sdk/pull/1733)) +- CryptoV2: Fully deprecate MXCryptoStore ([#1735](https://github.com/matrix-org/matrix-ios-sdk/pull/1735)) +- Make CallKit maximumCallGroups configurable. ([#1738](https://github.com/matrix-org/matrix-ios-sdk/pull/1738)) +- Crypto: Simplify user verification state ([#1740](https://github.com/matrix-org/matrix-ios-sdk/pull/1740)) +- Rageshakes: Identify crypto module ([#1742](https://github.com/matrix-org/matrix-ios-sdk/pull/1742)) +- Session: Improved session startup progress ([#7417](https://github.com/vector-im/element-ios/issues/7417)) + +🐛 Bugfixes + +- MXCallManager: Make call transfer requests sequential. ([#1739](https://github.com/matrix-org/matrix-ios-sdk/pull/1739)) + + ## Changes in 0.26.1 (2023-03-13) 🐛 Bugfixes diff --git a/MatrixSDK.podspec b/MatrixSDK.podspec index 4bbb2f6f57..de6a606fc1 100644 --- a/MatrixSDK.podspec +++ b/MatrixSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MatrixSDK" - s.version = "0.26.1" + s.version = "0.26.2" s.summary = "The iOS SDK to build apps compatible with Matrix (https://www.matrix.org)" s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| ss.dependency 'OLMKit', '~> 3.2.5' ss.dependency 'Realm', '10.27.0' ss.dependency 'libbase58', '~> 0.1.4' - ss.dependency 'MatrixSDKCrypto', '0.2.1', :configurations => ["DEBUG", "RELEASE"], :inhibit_warnings => true + ss.dependency 'MatrixSDKCrypto', '0.3.0', :configurations => ["DEBUG", "RELEASE"], :inhibit_warnings => true end s.subspec 'JingleCallStack' do |ss| diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 605bd26367..be7aa34a65 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -276,10 +276,6 @@ 325653831A2E14ED00CC0423 /* MXStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 325653821A2E14ED00CC0423 /* MXStoreTests.m */; }; 3256E3811DCB91EB003C9718 /* MXCryptoConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 3256E37F1DCB91EB003C9718 /* MXCryptoConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3256E3821DCB91EB003C9718 /* MXCryptoConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 3256E3801DCB91EB003C9718 /* MXCryptoConstants.m */; }; - 32581DE823C8C0C900832EAA /* MXUserTrustLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = 32581DE623C8C0C900832EAA /* MXUserTrustLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32581DE923C8C0C900832EAA /* MXUserTrustLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = 32581DE623C8C0C900832EAA /* MXUserTrustLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 32581DEA23C8C0C900832EAA /* MXUserTrustLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = 32581DE723C8C0C900832EAA /* MXUserTrustLevel.m */; }; - 32581DEB23C8C0C900832EAA /* MXUserTrustLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = 32581DE723C8C0C900832EAA /* MXUserTrustLevel.m */; }; 3259CD531DF860C300186944 /* MXRealmCryptoStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 3259CD511DF860C300186944 /* MXRealmCryptoStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3259CD541DF860C300186944 /* MXRealmCryptoStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 3259CD521DF860C300186944 /* MXRealmCryptoStore.m */; }; 3259CFE626026A6F00C365DB /* MXRestClient+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3259CFE526026A6F00C365DB /* MXRestClient+Extensions.swift */; }; @@ -1850,6 +1846,8 @@ ED356530281153480002BF6A /* MXMegolmSessionDataUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED35652E281153480002BF6A /* MXMegolmSessionDataUnitTests.swift */; }; ED36ED8628DD9E2200C86416 /* MXCryptoKeyBackupEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED36ED8528DD9E2100C86416 /* MXCryptoKeyBackupEngine.swift */; }; ED36ED8728DD9E2200C86416 /* MXCryptoKeyBackupEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED36ED8528DD9E2100C86416 /* MXCryptoKeyBackupEngine.swift */; }; + ED3C934229C0CD39008E3C5D /* MXTrustSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED3C934129C0CD39008E3C5D /* MXTrustSummary.swift */; }; + ED3C934329C0CD39008E3C5D /* MXTrustSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED3C934129C0CD39008E3C5D /* MXTrustSummary.swift */; }; ED4114E8292E496C00728459 /* MXBackgroundCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4114E7292E496C00728459 /* MXBackgroundCrypto.swift */; }; ED4114E9292E496C00728459 /* MXBackgroundCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4114E7292E496C00728459 /* MXBackgroundCrypto.swift */; }; ED4114EB292E498100728459 /* MXBackgroundCryptoV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4114EA292E498100728459 /* MXBackgroundCryptoV2.swift */; }; @@ -1864,6 +1862,10 @@ ED44F01528180EAB00452A5D /* MXSharedHistoryKeyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED44F01328180EAB00452A5D /* MXSharedHistoryKeyManager.swift */; }; ED44F01A28180F4000452A5D /* MXSharedHistoryKeyManagerUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED44F01728180F1C00452A5D /* MXSharedHistoryKeyManagerUnitTests.swift */; }; ED44F01B28180F4000452A5D /* MXSharedHistoryKeyManagerUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED44F01728180F1C00452A5D /* MXSharedHistoryKeyManagerUnitTests.swift */; }; + ED463ECB29B0B75800957941 /* EventEncryptionAlgorithm+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED463ECA29B0B75800957941 /* EventEncryptionAlgorithm+String.swift */; }; + ED463ECC29B0B75800957941 /* EventEncryptionAlgorithm+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED463ECA29B0B75800957941 /* EventEncryptionAlgorithm+String.swift */; }; + ED463ECE29B0B8E000957941 /* MXRoomSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED463ECD29B0B8E000957941 /* MXRoomSettings.swift */; }; + ED463ECF29B0B8E000957941 /* MXRoomSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED463ECD29B0B8E000957941 /* MXRoomSettings.swift */; }; ED47CB6D28523995004FD755 /* MXCryptoV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED47CB6C28523995004FD755 /* MXCryptoV2.swift */; }; ED47CB6E28523995004FD755 /* MXCryptoV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED47CB6C28523995004FD755 /* MXCryptoV2.swift */; }; ED505DC028E1FD160079A3D3 /* MXCryptoKeyBackupEngineUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED505DBD28E1FD130079A3D3 /* MXCryptoKeyBackupEngineUnitTests.swift */; }; @@ -1975,6 +1977,10 @@ ED76A4AE28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED76A4AC28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift */; }; ED79B9852940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */; }; ED79B9862940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */; }; + ED7AA21729C31DDE001293AA /* MXTrustSummaryUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7AA21629C31DDE001293AA /* MXTrustSummaryUnitTests.swift */; }; + ED7AA21829C31DDE001293AA /* MXTrustSummaryUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7AA21629C31DDE001293AA /* MXTrustSummaryUnitTests.swift */; }; + ED7AA21D29C34A1C001293AA /* MXCrossSigningInfo_v0 in Resources */ = {isa = PBXBuildFile; fileRef = ED7AA21C29C34A1C001293AA /* MXCrossSigningInfo_v0 */; }; + ED7AA21E29C34A1C001293AA /* MXCrossSigningInfo_v0 in Resources */ = {isa = PBXBuildFile; fileRef = ED7AA21C29C34A1C001293AA /* MXCrossSigningInfo_v0 */; }; ED825F8F29014EDA006A614E /* MXSession+LegacyCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */; }; ED825F9029014EDA006A614E /* MXSession+LegacyCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */; }; ED88999127F2065D00718486 /* MXRoomAliasResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -2066,6 +2072,8 @@ EDF1B6942876CD8600BBBCEE /* MXTaskQueueUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF1B6922876CD8600BBBCEE /* MXTaskQueueUnitTests.swift */; }; EDF4678727E3331D00435913 /* EventsEnumeratorDataSourceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF4678627E3331D00435913 /* EventsEnumeratorDataSourceStub.swift */; }; EDF4678827E3331D00435913 /* EventsEnumeratorDataSourceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF4678627E3331D00435913 /* EventsEnumeratorDataSourceStub.swift */; }; + EDF9306A29BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF9306929BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift */; }; + EDF9306B29BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF9306929BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift */; }; F0173EAC1FCF0E8900B5F6A3 /* MXGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = F0173EAA1FCF0E8800B5F6A3 /* MXGroup.h */; settings = {ATTRIBUTES = (Public, ); }; }; F0173EAD1FCF0E8900B5F6A3 /* MXGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = F0173EAB1FCF0E8900B5F6A3 /* MXGroup.m */; }; F03EF4FE1DF014D9009DF592 /* MXMediaLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = F03EF4FA1DF014D9009DF592 /* MXMediaLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -2319,8 +2327,6 @@ 325653821A2E14ED00CC0423 /* MXStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXStoreTests.m; sourceTree = ""; }; 3256E37F1DCB91EB003C9718 /* MXCryptoConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXCryptoConstants.h; sourceTree = ""; }; 3256E3801DCB91EB003C9718 /* MXCryptoConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXCryptoConstants.m; sourceTree = ""; }; - 32581DE623C8C0C900832EAA /* MXUserTrustLevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXUserTrustLevel.h; sourceTree = ""; }; - 32581DE723C8C0C900832EAA /* MXUserTrustLevel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXUserTrustLevel.m; sourceTree = ""; }; 3259CD511DF860C300186944 /* MXRealmCryptoStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRealmCryptoStore.h; sourceTree = ""; }; 3259CD521DF860C300186944 /* MXRealmCryptoStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXRealmCryptoStore.m; sourceTree = ""; }; 3259CFE526026A6F00C365DB /* MXRestClient+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MXRestClient+Extensions.swift"; sourceTree = ""; }; @@ -3086,6 +3092,7 @@ ED35652B281150310002BF6A /* MXOlmInboundGroupSessionUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXOlmInboundGroupSessionUnitTests.swift; sourceTree = ""; }; ED35652E281153480002BF6A /* MXMegolmSessionDataUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXMegolmSessionDataUnitTests.swift; sourceTree = ""; }; ED36ED8528DD9E2100C86416 /* MXCryptoKeyBackupEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoKeyBackupEngine.swift; sourceTree = ""; }; + ED3C934129C0CD39008E3C5D /* MXTrustSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXTrustSummary.swift; sourceTree = ""; }; ED4114E7292E496C00728459 /* MXBackgroundCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXBackgroundCrypto.swift; sourceTree = ""; }; ED4114EA292E498100728459 /* MXBackgroundCryptoV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXBackgroundCryptoV2.swift; sourceTree = ""; }; ED4114ED292E49C000728459 /* MXLegacyBackgroundCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLegacyBackgroundCrypto.swift; sourceTree = ""; }; @@ -3093,6 +3100,8 @@ ED44F01028180BCC00452A5D /* MXSharedHistoryKeyRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSharedHistoryKeyRequest.swift; sourceTree = ""; }; ED44F01328180EAB00452A5D /* MXSharedHistoryKeyManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSharedHistoryKeyManager.swift; sourceTree = ""; }; ED44F01728180F1C00452A5D /* MXSharedHistoryKeyManagerUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSharedHistoryKeyManagerUnitTests.swift; sourceTree = ""; }; + ED463ECA29B0B75800957941 /* EventEncryptionAlgorithm+String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EventEncryptionAlgorithm+String.swift"; sourceTree = ""; }; + ED463ECD29B0B8E000957941 /* MXRoomSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXRoomSettings.swift; sourceTree = ""; }; ED47CB6C28523995004FD755 /* MXCryptoV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoV2.swift; sourceTree = ""; }; ED505DBD28E1FD130079A3D3 /* MXCryptoKeyBackupEngineUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCryptoKeyBackupEngineUnitTests.swift; sourceTree = ""; }; ED505DC328E206FC0079A3D3 /* MXKeyBackupVersion+Stub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXKeyBackupVersion+Stub.swift"; sourceTree = ""; }; @@ -3147,6 +3156,8 @@ ED751DAD28EDEC7E003748C3 /* MXKeyVerificationStateResolverUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationStateResolverUnitTests.swift; sourceTree = ""; }; ED76A4AC28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationStateResolver.swift; sourceTree = ""; }; ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXToDevicePayloadUnitTests.swift; sourceTree = ""; }; + ED7AA21629C31DDE001293AA /* MXTrustSummaryUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXTrustSummaryUnitTests.swift; sourceTree = ""; }; + ED7AA21C29C34A1C001293AA /* MXCrossSigningInfo_v0 */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = MXCrossSigningInfo_v0; sourceTree = ""; }; ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXSession+LegacyCrypto.swift"; sourceTree = ""; }; ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRoomAliasResolution.h; sourceTree = ""; }; ED88999027F2065D00718486 /* MXRoomAliasResolution.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXRoomAliasResolution.m; sourceTree = ""; }; @@ -3193,6 +3204,7 @@ EDF1B68F2876CD2C00BBBCEE /* MXTaskQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXTaskQueue.swift; sourceTree = ""; }; EDF1B6922876CD8600BBBCEE /* MXTaskQueueUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXTaskQueueUnitTests.swift; sourceTree = ""; }; EDF4678627E3331D00435913 /* EventsEnumeratorDataSourceStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsEnumeratorDataSourceStub.swift; sourceTree = ""; }; + EDF9306929BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventEncryptionAlgorithmUnitTests.swift; sourceTree = ""; }; F0173EAA1FCF0E8800B5F6A3 /* MXGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXGroup.h; sourceTree = ""; }; F0173EAB1FCF0E8900B5F6A3 /* MXGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXGroup.m; sourceTree = ""; }; F03EF4FA1DF014D9009DF592 /* MXMediaLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXMediaLoader.h; sourceTree = ""; }; @@ -3485,8 +3497,7 @@ children = ( 32261B8823C74A230018F1E2 /* MXDeviceTrustLevel.h */, 32261B8923C74A230018F1E2 /* MXDeviceTrustLevel.m */, - 32581DE623C8C0C900832EAA /* MXUserTrustLevel.h */, - 32581DE723C8C0C900832EAA /* MXUserTrustLevel.m */, + ED3C934129C0CD39008E3C5D /* MXTrustSummary.swift */, B14766B523D9D9410091F721 /* MXUsersTrustLevelSummary.h */, B14766B623D9D9410091F721 /* MXUsersTrustLevelSummary.m */, EDD578DD2881C37C006739DD /* MXTrustLevelSource.swift */, @@ -4163,6 +4174,7 @@ 32E402B821C957D2004E87A6 /* MXOlmSession.m */, 3AC13800264482A100EE1E74 /* MXExportedOlmDevice.h */, 3AC13801264482A100EE1E74 /* MXExportedOlmDevice.m */, + ED463ECD29B0B8E000957941 /* MXRoomSettings.swift */, ); path = Data; sourceTree = ""; @@ -5472,6 +5484,7 @@ ED2DD11A286C4F3100F06731 /* CryptoMachine */ = { isa = PBXGroup; children = ( + EDF9306829BB48800082A335 /* Extensions */, ED8F1D332885ADE200F897E7 /* MXCryptoProtocolStubs.swift */, EDA6933F290BA92E00223252 /* MXCryptoMachineUnitTests.swift */, ED2DD11B286C4F3E00F06731 /* MXCryptoRequestsUnitTests.swift */, @@ -5590,6 +5603,7 @@ ED5EF148297AB29F00A5ADDA /* MXDeviceVerification+LocalTrust.swift */, ED5EF14A297AB29F00A5ADDA /* MXEventDecryptionResult+DecryptedEvent.swift */, ED5EF149297AB29F00A5ADDA /* MXRoomHistoryVisibility+HistoryVisibility.swift */, + ED463ECA29B0B75800957941 /* EventEncryptionAlgorithm+String.swift */, ); path = Extensions; sourceTree = ""; @@ -5713,6 +5727,7 @@ ED8F1D1528857FDA00F897E7 /* Data */ = { isa = PBXGroup; children = ( + ED7AA21C29C34A1C001293AA /* MXCrossSigningInfo_v0 */, ED8F1D1628857FE600F897E7 /* MXCrossSigningInfoUnitTests.swift */, ); path = Data; @@ -5761,6 +5776,7 @@ isa = PBXGroup; children = ( ED8F1D2F2885AB0300F897E7 /* MXTrustLevelSourceUnitTests.swift */, + ED7AA21629C31DDE001293AA /* MXTrustSummaryUnitTests.swift */, ); path = Trust; sourceTree = ""; @@ -5806,6 +5822,14 @@ path = Engine; sourceTree = ""; }; + EDF9306829BB48800082A335 /* Extensions */ = { + isa = PBXGroup; + children = ( + EDF9306929BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift */, + ); + path = Extensions; + sourceTree = ""; + }; F03EF4F91DF014D9009DF592 /* Media */ = { isa = PBXGroup; children = ( @@ -5858,7 +5882,6 @@ 32114A8F1A262ECB00FF2EC4 /* MXNoStore.h in Headers */, 32D776811A27877300FC4AA2 /* MXMemoryRoomStore.h in Headers */, B146D4E621A5AEF200D8C2C6 /* MXRealmMediaScan.h in Headers */, - 32581DE823C8C0C900832EAA /* MXUserTrustLevel.h in Headers */, B146D4EF21A5AF7F00D8C2C6 /* MXRealmEventScan.h in Headers */, B146D49C21A5A04300D8C2C6 /* MXMediaScanStoreDelegate.h in Headers */, 32322A4B1E575F65005DD155 /* MXAllowedCertificates.h in Headers */, @@ -6271,7 +6294,6 @@ B14EF2A62397E90400758AF0 /* MXAggregations.h in Headers */, 8EC511052568216B00EC4E5B /* MXTaggedEventInfo.h in Headers */, B14EF2A72397E90400758AF0 /* MXPushRuleConditionChecker.h in Headers */, - 32581DE923C8C0C900832EAA /* MXUserTrustLevel.h in Headers */, EC403835289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */, B14EF2A82397E90400758AF0 /* MXServiceTermsRestClient.h in Headers */, EC8A53DB25B1BCC6004E0802 /* MXThirdPartyUsersResponse.h in Headers */, @@ -6742,6 +6764,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + ED7AA21D29C34A1C001293AA /* MXCrossSigningInfo_v0 in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6762,6 +6785,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + ED7AA21E29C34A1C001293AA /* MXCrossSigningInfo_v0 in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -7011,6 +7035,7 @@ 32AF9286240EA2430008A0FD /* MXSecretShareRequest.m in Sources */, ED5C754428B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */, ED47CB6D28523995004FD755 /* MXCryptoV2.swift in Sources */, + ED463ECB29B0B75800957941 /* EventEncryptionAlgorithm+String.swift in Sources */, EDF154E1296C203E004D7FFE /* MXCryptoMachineStore.swift in Sources */, 32A1513A1DAD292400400192 /* MXMegolmEncryption.m in Sources */, EC60EDFE265CFFD200B39A4E /* MXInvitedGroupSync.m in Sources */, @@ -7086,6 +7111,7 @@ EC0B94242718E3EE00B4D440 /* MXCoreDataRoomListDataFetcher.swift in Sources */, C6F935881E5B3BE600FC34BF /* MX3PID.swift in Sources */, B16C2458283AB10B00F5D1FE /* MXRealmBeaconInfoSummary.swift in Sources */, + ED3C934229C0CD39008E3C5D /* MXTrustSummary.swift in Sources */, B146D47821A5950800D8C2C6 /* MXMediaScan.m in Sources */, 3A108AA425810FE5005EEBE9 /* MXRawDataKey.m in Sources */, C6F9358A1E5B3BE600FC34BF /* MXEvent.swift in Sources */, @@ -7093,7 +7119,6 @@ 329E808D224E2E1B00A48C3A /* MXOutgoingSASTransaction.m in Sources */, 1838927A2702F553003F0C4F /* MXSendReplyEventDefaultStringLocalizer.m in Sources */, EC0B941E27186C3500B4D440 /* MXRoomListDataSortable.swift in Sources */, - 32581DEA23C8C0C900832EAA /* MXUserTrustLevel.m in Sources */, 66AC9D25278CE627002E9B8F /* MXRefreshTokenData.m in Sources */, 3271878A1DA7DCE50071C818 /* MXOlmEncryption.m in Sources */, 327187861DA7D0220071C818 /* MXOlmDecryption.m in Sources */, @@ -7223,6 +7248,7 @@ 3240969E1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.m in Sources */, 71DE22E01BC7C51200284153 /* MXReceiptData.m in Sources */, B14766B923D9D9420091F721 /* MXUsersTrustLevelSummary.m in Sources */, + ED463ECE29B0B8E000957941 /* MXRoomSettings.swift in Sources */, 323547D92226D5D600F15F94 /* MXWellKnownBaseConfig.m in Sources */, EC0B94272718E64500B4D440 /* CoreDataContextable.swift in Sources */, 324BE4691E3FADB1008D99D4 /* MXMegolmExportEncryption.m in Sources */, @@ -7406,6 +7432,7 @@ 323C5A081A70E53500FB0549 /* MXToolsUnitTests.m in Sources */, 3281E89E19E299C000976E1A /* MXErrorUnitTests.m in Sources */, ED1FE9062912D2EB0046F722 /* MXRoomEventDecryptionUnitTests.swift in Sources */, + EDF9306A29BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift in Sources */, ED1FE90B2912E13A0046F722 /* DecryptedEvent+Stub.swift in Sources */, EC51019D26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */, EDB4209527DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift in Sources */, @@ -7439,6 +7466,7 @@ ECB6FA8E267CFF4300A941E4 /* MXCredentialsUnitTests.swift in Sources */, ED7019F52886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift in Sources */, ED6DAC1128C788A700ECDCB6 /* MXRoomKeyInfoFactoryUnitTests.swift in Sources */, + ED7AA21729C31DDE001293AA /* MXTrustSummaryUnitTests.swift in Sources */, 3A108E6725826F52005EEBE9 /* MXKeyProviderUnitTests.m in Sources */, 3A858DE8275511A4006322C1 /* MXRoomAliasAvailabilityCheckerResultTests.swift in Sources */, EC116593270FB6970089FA56 /* MXBackgroundTaskUnitTests.swift in Sources */, @@ -7669,7 +7697,6 @@ B14EF2032397E90400758AF0 /* MXMegolmEncryption.m in Sources */, B14EECDA2577DE7B00448735 /* MXLoginSSOIdentityProvider.m in Sources */, B14EF2042397E90400758AF0 /* MXIncomingRoomKeyRequest.m in Sources */, - 32581DEB23C8C0C900832EAA /* MXUserTrustLevel.m in Sources */, EC0C51752559388C00F2CC66 /* MXStopwatch.swift in Sources */, EC403855289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m in Sources */, 3259D0092603705300C365DB /* Array.swift in Sources */, @@ -7679,6 +7706,7 @@ 3297913123AA126500F7BB9B /* MXKeyVerificationStatusResolver.m in Sources */, ED5C754528B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */, ED47CB6E28523995004FD755 /* MXCryptoV2.swift in Sources */, + ED463ECC29B0B75800957941 /* EventEncryptionAlgorithm+String.swift in Sources */, EDF154E2296C203E004D7FFE /* MXCryptoMachineStore.swift in Sources */, B14EF2082397E90400758AF0 /* MX3PidAddManager.m in Sources */, ECD2899026EB3B3400F268CF /* MXRoomListData.swift in Sources */, @@ -7754,6 +7782,7 @@ B14EF22A2397E90400758AF0 /* MXReplyEventFormattedBodyParts.m in Sources */, ECD2899626EB3B4200F268CF /* MXStoreRoomListDataFetcher.swift in Sources */, B16C2459283AB10B00F5D1FE /* MXRealmBeaconInfoSummary.swift in Sources */, + ED3C934329C0CD39008E3C5D /* MXTrustSummary.swift in Sources */, 324AAC7A2399140D00380A66 /* MXKeyVerificationMac.m in Sources */, B14EF22B2397E90400758AF0 /* MXFileStoreMetaData.m in Sources */, EC8A53A825B1BC77004E0802 /* MXCallCapabilitiesModel.m in Sources */, @@ -7891,6 +7920,7 @@ B14EF2612397E90400758AF0 /* MXRealmAggregationsStore.m in Sources */, EC383BB72541C518002FBBE6 /* MXBackgroundPushRulesManager.swift in Sources */, 3259CFE726026A6F00C365DB /* MXRestClient+Extensions.swift in Sources */, + ED463ECF29B0B8E000957941 /* MXRoomSettings.swift in Sources */, B105CDD9261F54C8006EB204 /* MXSpaceChildContent.m in Sources */, B14EF2622397E90400758AF0 /* MXAntivirusScanStatusFormatter.m in Sources */, EC0B94282718E64500B4D440 /* CoreDataContextable.swift in Sources */, @@ -8074,6 +8104,7 @@ 32CEEF3E23AD134A0039BA98 /* MXCrossSigningTests.m in Sources */, 32EEA8402603CA140041425B /* MXRestClientExtensionsTests.m in Sources */, ED1FE9072912D2EB0046F722 /* MXRoomEventDecryptionUnitTests.swift in Sources */, + EDF9306B29BB488D0082A335 /* EventEncryptionAlgorithmUnitTests.swift in Sources */, ED1FE90C2912E13A0046F722 /* DecryptedEvent+Stub.swift in Sources */, EC51019E26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */, EDB4209627DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift in Sources */, @@ -8107,6 +8138,7 @@ B1E09A462397FD990057C069 /* MXMediaScanStoreUnitTests.m in Sources */, ED7019F62886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift in Sources */, ED6DAC1228C788A700ECDCB6 /* MXRoomKeyInfoFactoryUnitTests.swift in Sources */, + ED7AA21829C31DDE001293AA /* MXTrustSummaryUnitTests.swift in Sources */, ECB6FA8F267CFF4300A941E4 /* MXCredentialsUnitTests.swift in Sources */, 3A858DE9275511A4006322C1 /* MXRoomAliasAvailabilityCheckerResultTests.swift in Sources */, ED7019DF2886C25600FC31B9 /* MXDeviceInfoUnitTests.swift in Sources */, diff --git a/MatrixSDK/Crypto/Algorithms/RoomEvent/MXRoomEventEncryption.swift b/MatrixSDK/Crypto/Algorithms/RoomEvent/MXRoomEventEncryption.swift index 8475e44e7d..fe9fa93268 100644 --- a/MatrixSDK/Crypto/Algorithms/RoomEvent/MXRoomEventEncryption.swift +++ b/MatrixSDK/Crypto/Algorithms/RoomEvent/MXRoomEventEncryption.swift @@ -47,24 +47,19 @@ struct MXRoomEventEncryption: MXRoomEventEncrypting { private static let keyRotationPeriodSec: Int = 7 * 24 * 3600 // Rotate room keys each week private let handler: MXCryptoRoomEventEncrypting - private let legacyStore: MXCryptoStore private let getRoomAction: GetRoomAction private let log = MXNamedLog(name: "MXRoomEventEncryption") init( handler: MXCryptoRoomEventEncrypting, - legacyStore: MXCryptoStore, getRoomAction: @escaping GetRoomAction ) { self.handler = handler - self.legacyStore = legacyStore self.getRoomAction = getRoomAction } func isRoomEncrypted(roomId: String) -> Bool { - // State of room encryption is not yet implemented in `MatrixSDKCrypto` - // Will be moved to `MatrixSDKCrypto` eventually - return legacyStore.algorithm(forRoom: roomId) != nil + return handler.roomSettings(roomId: roomId)?.algorithm != nil } func ensureRoomKeysShared(roomId: String) async throws { @@ -108,7 +103,7 @@ struct MXRoomEventEncryption: MXRoomEventEncrypting { for: room, historyVisibility: state.historyVisibility ) - handler.addTrackedUsers(users) + handler.updateTrackedUsers(users) } // MARK: - Private @@ -128,6 +123,12 @@ struct MXRoomEventEncryption: MXRoomEventEncrypting { historyVisibility: state.historyVisibility ) + // Room membership events should ensure that we are always tracking users as soon as possible, + // but there are rare edge-cases where this does not always happen. To add a safety mechanism + // we will always update tracked users when sharing keys (which does nothing if a user is + // already tracked), triggering a key request for missing users in the next sync loop. + handler.updateTrackedUsers(users) + let settings = try encryptionSettings(for: state) try await handler.shareRoomKeysIfNecessary( roomId: roomId, @@ -138,37 +139,23 @@ struct MXRoomEventEncryption: MXRoomEventEncrypting { /// Make sure that we recognize (and store if necessary) the claimed room encryption algorithm private func ensureRoomEncryption(roomId: String, algorithm: String?) throws { - let existingAlgorithm = legacyStore.algorithm(forRoom: roomId) - if existingAlgorithm != nil && existingAlgorithm == algorithm { - // Encryption in room is already set to the correct algorithm - return - } + log.debug("Attempting to set algorithm to \(algorithm ?? "empty")") - guard let algorithm = algorithm else { - if existingAlgorithm != nil { - log.error("Resetting encryption is not allowed") - return + do { + let algorithm = try EventEncryptionAlgorithm(string: algorithm) + try handler.setRoomAlgorithm(roomId: roomId, algorithm: algorithm) + } catch { + if let existing = handler.roomSettings(roomId: roomId)?.algorithm { + log.error("Failed to set algorithm, but another room algorithm already stored", context: [ + "existing": existing, + "new": algorithm ?? "empty" + ]) } else { - throw Error.invalidEncryptionAlgorithm + log.error("Failed to set algorithm", context: error) + throw error } } - let supportedAlgorithms = Set([kMXCryptoMegolmAlgorithm]) - guard supportedAlgorithms.contains(algorithm) else { - log.error("Ignoring invalid room algorithm", context: [ - "room_id": roomId, - "algorithm": algorithm - ]) - throw Error.invalidEncryptionAlgorithm - } - - if let existing = existingAlgorithm, existing != algorithm { - log.warning("New m.room.encryption event in \(roomId) with an algorithm change from \(existing) to \(algorithm)") - } else { - log.debug("New m.room.encryption event with algorithm \(algorithm)") - } - - legacyStore.storeAlgorithm(forRoom: roomId, algorithm: algorithm) } /// Get user ids for all room members that should be able to decrypt events, based on the history visibility setting @@ -202,7 +189,7 @@ struct MXRoomEventEncryption: MXRoomEventEncrypting { } private func onlyTrustedDevices(in roomId: String) -> Bool { - return legacyStore.globalBlacklistUnverifiedDevices || legacyStore.blacklistUnverifiedDevices(inRoom: roomId) + return handler.onlyAllowTrustedDevices || handler.roomSettings(roomId: roomId)?.onlyAllowTrustedDevices == true } private func room(for roomId: String) throws -> MXRoom { diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h index e366bb3ca8..f312846d1a 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h @@ -17,7 +17,6 @@ #import #import "MXCrossSigningKey.h" -#import "MXUserTrustLevel.h" @class MXCryptoUserIdentityWrapper; @@ -56,7 +55,7 @@ extern NSString *const MXCrossSigningInfoTrustLevelDidChangeNotification; #pragma mark - Additional information -@property (nonatomic, readonly) MXUserTrustLevel *trustLevel; +@property (nonatomic, readonly) BOOL isVerified; @end diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m index 90d99fefb2..a717799ed0 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m @@ -21,6 +21,38 @@ NSString *const MXCrossSigningInfoTrustLevelDidChangeNotification = @"MXCrossSigningInfoTrustLevelDidChangeNotification"; +#pragma mark - Deprecated user trust + +/** + Deprecated model of user trust that distinguished local vs cross-signing verification + + This model is no longer used and is replaced by a combined `isVerified` property on `MXCrossSigningInfo`. + For backwards compatibility (reading archived values) the model needs to be kept around, albeit as private only. + */ +@interface MXDeprecatedUserTrustLevel : NSObject +@property (nonatomic, readonly) BOOL isCrossSigningVerified; +@end + +@implementation MXDeprecatedUserTrustLevel +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super init]; + if (self) + { + // We ignore `isLocallyVerified` field and only consider `isCrossSigningVerified` + _isCrossSigningVerified = [aDecoder decodeBoolForKey:@"isCrossSigningVerified"]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + MXLogFailure(@"[MXDeprecatedUserTrustLevel] encode: This model should only be used for decoding existing data, not encoding new data"); +} +@end + +#pragma mark - CrossSigningInfo + @implementation MXCrossSigningInfo - (instancetype)initWithUserIdentity:(MXCryptoUserIdentityWrapper *)userIdentity @@ -43,7 +75,7 @@ - (instancetype)initWithUserIdentity:(MXCryptoUserIdentityWrapper *)userIdentity keys[MXCrossSigningKeyType.userSigning] = userIdentity.userSignedKeys; } _keys = keys.copy; - _trustLevel = userIdentity.trustLevel; + _isVerified = userIdentity.isVerified; } return self; } @@ -92,7 +124,22 @@ - (id)initWithCoder:(NSCoder *)aDecoder { _userId = [aDecoder decodeObjectForKey:@"userId"]; _keys = [aDecoder decodeObjectForKey:@"keys"]; - _trustLevel = [aDecoder decodeObjectForKey:@"trustLevel"]; + + // Initial version (i.e. version 0) of the model stored user trust via `MXUserTrustLevel` submodel. + // If we are reading this version out we need to decode verification state from this model before + // migrating it over to `isVerified` + NSInteger version = [aDecoder decodeIntegerForKey:@"version"]; + if (version == 0) + { + [NSKeyedUnarchiver setClass:MXDeprecatedUserTrustLevel.class forClassName:@"MXUserTrustLevel"]; + MXDeprecatedUserTrustLevel *trust = [aDecoder decodeObjectForKey:@"trustLevel"]; + // Only convert cross-signed verification status, not local verification status + _isVerified = trust.isCrossSigningVerified; + } + else + { + _isVerified = [aDecoder decodeBoolForKey:@"isVerified"]; + } } return self; } @@ -101,7 +148,8 @@ - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:_userId forKey:@"userId"]; [aCoder encodeObject:_keys forKey:@"keys"]; - [aCoder encodeObject:_trustLevel forKey:@"trustLevel"]; + [aCoder encodeBool:_isVerified forKey:@"isVerified"]; + [aCoder encodeInteger:1 forKey:@"version"]; } @@ -113,31 +161,23 @@ - (instancetype)initWithUserId:(NSString *)userId if (self) { _userId = userId; - _trustLevel = [MXUserTrustLevel new]; + _isVerified = NO; } return self; } -- (void)setTrustLevel:(MXUserTrustLevel*)trustLevel -{ - _trustLevel = trustLevel; -} - -- (BOOL)updateTrustLevel:(MXUserTrustLevel*)trustLevel +- (void)setIsVerified:(BOOL)isVerified { - BOOL updated = NO; - - if (![_trustLevel isEqual:trustLevel]) + if (_isVerified == isVerified) { - _trustLevel = trustLevel; - updated = YES; - [self didUpdateTrustLevel]; + return; } - - return updated; + + _isVerified = isVerified; + [self didUpdateVerificationState]; } -- (void)didUpdateTrustLevel +- (void)didUpdateVerificationState { dispatch_async(dispatch_get_main_queue(),^{ [[NSNotificationCenter defaultCenter] postNotificationName:MXCrossSigningInfoTrustLevelDidChangeNotification object:self userInfo:nil]; @@ -158,7 +198,7 @@ - (void)addCrossSigningKey:(MXCrossSigningKey*)crossSigningKey type:(NSString*)t - (NSString *)description { - return [NSString stringWithFormat:@" Trusted: %@\nMSK: %@\nSSK: %@\nUSK: %@", self, @(self.trustLevel.isCrossSigningVerified), self.masterKeys, self.selfSignedKeys, self.userSignedKeys]; + return [NSString stringWithFormat:@" Verified: %@\nMSK: %@\nSSK: %@\nUSK: %@", self, @(self.isVerified), self.masterKeys, self.selfSignedKeys, self.userSignedKeys]; } @end diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo_Private.h b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo_Private.h index bc88c50c20..092538906f 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo_Private.h +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo_Private.h @@ -23,8 +23,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithUserId:(NSString *)userId; -- (void)setTrustLevel:(MXUserTrustLevel*)trustLevel; -- (BOOL)updateTrustLevel:(MXUserTrustLevel*)trustLevel; +- (void)setIsVerified:(BOOL)isVerified; - (void)addCrossSigningKey:(MXCrossSigningKey*)crossSigningKey type:(NSString*)type; @end diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift b/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift index f444ca2eb2..1423bd9322 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift @@ -27,7 +27,7 @@ import MatrixSDKCrypto public let masterKeys: MXCrossSigningKey? public let selfSignedKeys: MXCrossSigningKey? public let userSignedKeys: MXCrossSigningKey? - public let trustLevel: MXUserTrustLevel + public let isVerified: Bool internal init(identity: UserIdentity, isVerified: Bool) { switch identity { @@ -43,13 +43,7 @@ import MatrixSDKCrypto self.selfSignedKeys = .init(jsonString: selfSigningKey) self.userSignedKeys = nil } - - // `MatrixSDKCrypto` does not distinguish local and cross-signed - // verification status for users - trustLevel = MXUserTrustLevel( - crossSigningVerified: isVerified, - locallyVerified: isVerified - ) + self.isVerified = isVerified } } diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigning.m b/MatrixSDK/Crypto/CrossSigning/MXCrossSigning.m index fc077033e3..c53ba4849f 100644 --- a/MatrixSDK/Crypto/CrossSigning/MXCrossSigning.m +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigning.m @@ -135,7 +135,7 @@ - (void)setupWithAuthParams:(NSDictionary*)authParams [self.crypto.matrixRestClient uploadDeviceSigningKeys:signingKeys authParams:authParams success:^{ // Store our user's keys - [keys updateTrustLevel:[MXUserTrustLevel trustLevelWithCrossSigningVerified:YES locallyVerified:YES]]; + [keys setIsVerified:YES]; [self.crypto.store storeCrossSigningKeys:keys]; // Cross-signing is bootstrapped @@ -585,7 +585,7 @@ - (BOOL)isDeviceVerified:(MXDeviceInfo*)device BOOL isDeviceVerified = NO; MXCrossSigningInfo *userCrossSigning = [self.crypto.store crossSigningKeysForUser:device.userId]; - MXUserTrustLevel *userTrustLevel = [self.crypto trustLevelForUser:device.userId]; + BOOL isUserVerified = [self.crypto isUserVerified:device.userId]; MXCrossSigningKey *userSSK = userCrossSigning.selfSignedKeys; if (!userSSK) @@ -610,7 +610,7 @@ - (BOOL)isDeviceVerified:(MXDeviceInfo*)device // ...then we trust this device as much as far as we trust the user if (userSSKVerify && deviceVerify) { - isDeviceVerified = userTrustLevel.isCrossSigningVerified; + isDeviceVerified = isUserVerified; } return isDeviceVerified; @@ -685,17 +685,14 @@ - (void)resetTrust for (MXCrossSigningInfo *crossSigningInfo in self.crypto.store.crossSigningKeys) { BOOL isCrossSigningVerified = [self isUserWithCrossSigningKeysVerified:crossSigningInfo]; - if (crossSigningInfo.trustLevel.isCrossSigningVerified != isCrossSigningVerified) + if (crossSigningInfo.isVerified != isCrossSigningVerified) { MXLogDebug(@"[MXCrossSigning] resetTrust: Change trust for %@: %@ -> %@", crossSigningInfo.userId, - @(crossSigningInfo.trustLevel.isCrossSigningVerified), + @(crossSigningInfo.isVerified), @(isCrossSigningVerified)); - MXUserTrustLevel *newTrustLevel = [MXUserTrustLevel trustLevelWithCrossSigningVerified:isCrossSigningVerified locallyVerified:crossSigningInfo.trustLevel.isLocallyVerified]; - if ([crossSigningInfo updateTrustLevel:newTrustLevel]) - { - [self.crypto.store storeCrossSigningKeys:crossSigningInfo]; - } + [crossSigningInfo setIsVerified:isCrossSigningVerified]; + [self.crypto.store storeCrossSigningKeys:crossSigningInfo]; // Update trust on associated devices [self checkTrustLevelForDevicesOfUser:crossSigningInfo.userId]; @@ -745,42 +742,32 @@ - (BOOL)isSelfTrusted NSString *myUserId = _crypto.mxSession.myUserId; - // Is the master key trusted? - MXCrossSigningInfo *myCrossSigningInfo = [_crypto.store crossSigningKeysForUser:myUserId]; - if (myCrossSigningInfo && myCrossSigningInfo.trustLevel.isLocallyVerified) + // Is it signed by a locally trusted device? + NSDictionary *myUserSignatures = myMasterKey.signatures.map[myUserId]; + for (NSString *publicKeyId in myUserSignatures) { - isMasterKeyTrusted = YES; - } - else - { - // Is it signed by a locally trusted device? - NSDictionary *myUserSignatures = myMasterKey.signatures.map[myUserId]; - for (NSString *publicKeyId in myUserSignatures) + MXKey *key = [[MXKey alloc] initWithKeyFullId:publicKeyId value:myUserSignatures[publicKeyId]]; + if ([key.type isEqualToString:kMXKeyEd25519Type]) { - MXKey *key = [[MXKey alloc] initWithKeyFullId:publicKeyId value:myUserSignatures[publicKeyId]]; - if ([key.type isEqualToString:kMXKeyEd25519Type]) + MXDeviceInfo *device = [self.crypto.store deviceWithDeviceId:key.keyId forUser:myUserId]; + if (device && device.trustLevel.isLocallyVerified) { - MXDeviceInfo *device = [self.crypto.store deviceWithDeviceId:key.keyId forUser:myUserId]; - if (device && device.trustLevel.isLocallyVerified) + // Check signature validity + NSError *error; + isMasterKeyTrusted = [_crypto.olmDevice verifySignature:device.fingerprint JSON:myMasterKey.signalableJSONDictionary signature:key.value error:&error]; + + if (isMasterKeyTrusted) { - // Check signature validity - NSError *error; - isMasterKeyTrusted = [_crypto.olmDevice verifySignature:device.fingerprint JSON:myMasterKey.signalableJSONDictionary signature:key.value error:&error]; - - if (isMasterKeyTrusted) - { - break; - } + break; } } } } - if (!isMasterKeyTrusted) { MXLogDebug(@"[MXCrossSigning] isSelfTrusted: NO (MSK not trusted). MSK: %@", myMasterKey); - MXLogDebug(@"[MXCrossSigning] isSelfTrusted: My cross-signing info: %@", myCrossSigningInfo); + MXLogDebug(@"[MXCrossSigning] isSelfTrusted: My cross-signing info: %@", [self.crypto.store crossSigningKeysForUser:myUserId]); MXLogDebug(@"[MXCrossSigning] isSelfTrusted: My user devices: %@", [self.crypto.store devicesForUser:myUserId]); return NO; diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift index 6fb1a7fb06..071d651edb 100644 --- a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift @@ -28,7 +28,7 @@ class MXCrossSigningV2: NSObject, MXCrossSigning { return .notBootstrapped } - if info.trustLevel.isVerified { + if info.isVerified { return hasAllPrivateKeys ? .canCrossSign : .trustCrossSigning } else { return .crossSigningExists @@ -217,17 +217,11 @@ class MXCrossSigningV2: NSObject, MXCrossSigning { } extension MXCrossSigningV2: MXRecoveryServiceDelegate { - func setUserVerification( - _ verificationStatus: Bool, - forUser userId: String, + func setUserVerificationForUserId( + _ userId: String, success: @escaping () -> Void, failure: @escaping (Swift.Error?) -> Void ) { - guard verificationStatus else { - log.failure("Cannot unset user trust") - failure(Error.cannotUnsetTrust) - return - } signUser(withUserId: userId, success: success, failure: failure) } } diff --git a/MatrixSDK/Crypto/CryptoMachine/Extensions/EventEncryptionAlgorithm+String.swift b/MatrixSDK/Crypto/CryptoMachine/Extensions/EventEncryptionAlgorithm+String.swift new file mode 100644 index 0000000000..21f5919733 --- /dev/null +++ b/MatrixSDK/Crypto/CryptoMachine/Extensions/EventEncryptionAlgorithm+String.swift @@ -0,0 +1,40 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// 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 MatrixSDKCrypto + +extension EventEncryptionAlgorithm { + enum Error: Swift.Error { + case cannotResetEncryption + case invalidAlgorithm + } + + init(string: String?) throws { + guard let string = string else { + throw Error.cannotResetEncryption + } + + switch string { + case kMXCryptoOlmAlgorithm: + self = .olmV1Curve25519AesSha2 + case kMXCryptoMegolmAlgorithm: + self = .megolmV1AesSha2 + default: + throw Error.invalidAlgorithm + } + } +} diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index 38563d7cf7..d0c15b9b3f 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -364,6 +364,24 @@ extension MXCryptoMachine: MXCryptoUserIdentitySource { } extension MXCryptoMachine: MXCryptoRoomEventEncrypting { + var onlyAllowTrustedDevices: Bool { + get { + do { + return try machine.getOnlyAllowTrustedDevices() + } catch { + log.error("Failed getting value", context: error) + return false + } + } + set { + do { + try machine.setOnlyAllowTrustedDevices(onlyAllowTrustedDevices: newValue) + } catch { + log.error("Failed setting value", context: error) + } + } + } + func isUserTracked(userId: String) -> Bool { do { return try machine.isUserTracked(userId: userId) @@ -373,7 +391,7 @@ extension MXCryptoMachine: MXCryptoRoomEventEncrypting { } } - func addTrackedUsers(_ users: [String]) { + func updateTrackedUsers(_ users: [String]) { do { try machine.updateTrackedUsers(users: users) } catch { @@ -381,6 +399,23 @@ extension MXCryptoMachine: MXCryptoRoomEventEncrypting { } } + func roomSettings(roomId: String) -> RoomSettings? { + do { + return try machine.getRoomSettings(roomId: roomId) + } catch { + log.error("Failed getting room settings", context: error) + return nil + } + } + + func setRoomAlgorithm(roomId: String, algorithm: EventEncryptionAlgorithm) throws { + try machine.setRoomAlgorithm(roomId: roomId, algorithm: algorithm) + } + + func setOnlyAllowTrustedDevices(for roomId: String, onlyAllowTrustedDevices: Bool) throws { + try machine.setRoomOnlyAllowTrustedDevices(roomId: roomId, onlyAllowTrustedDevices: onlyAllowTrustedDevices) + } + func shareRoomKeysIfNecessary( roomId: String, users: [String], @@ -478,7 +513,7 @@ extension MXCryptoMachine: MXCryptoRoomEventDecrypting { roomId: roomId, // Handling verification events automatically during event decryption is now a deprecated behavior, // all verification events are handled manually via `receiveVerificationEvent` - handleVerificatonEvents: false + handleVerificationEvents: false ) } diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift index 4f5170c5e6..38f442a666 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift @@ -63,8 +63,13 @@ protocol MXCryptoUserIdentitySource: MXCryptoIdentity { /// Room event encryption protocol MXCryptoRoomEventEncrypting: MXCryptoIdentity { + var onlyAllowTrustedDevices: Bool { get set } + func isUserTracked(userId: String) -> Bool - func addTrackedUsers(_ users: [String]) + func updateTrackedUsers(_ users: [String]) + func roomSettings(roomId: String) -> RoomSettings? + func setRoomAlgorithm(roomId: String, algorithm: EventEncryptionAlgorithm) throws + func setOnlyAllowTrustedDevices(for roomId: String, onlyAllowTrustedDevices: Bool) throws func shareRoomKeysIfNecessary(roomId: String, users: [String], settings: EncryptionSettings) async throws func encryptRoomEvent(content: [AnyHashable: Any], roomId: String, eventType: String) throws -> [String: Any] func discardRoomKey(roomId: String) diff --git a/MatrixSDK/Crypto/Data/MXDeviceListOperationsPool.m b/MatrixSDK/Crypto/Data/MXDeviceListOperationsPool.m index 6b54fb3ada..ee2fc9540a 100644 --- a/MatrixSDK/Crypto/Data/MXDeviceListOperationsPool.m +++ b/MatrixSDK/Crypto/Data/MXDeviceListOperationsPool.m @@ -137,24 +137,11 @@ - (void)doKeyDownloadForUsers:(NSArray *)users token:(NSString *)tok MXLogDebug(@"[MXDeviceListOperationsPool] doKeyDownloadForUsers: Detected cross-signing keys rotation"); myUserCrossSigningKeysChanged = YES; } - - // Use current trust level - MXUserTrustLevel *oldTrustLevel = storedCrossSigningKeys.trustLevel; - if (myUserCrossSigningKeysChanged) - { - // Except if we cannot trust it anymore - oldTrustLevel = [MXUserTrustLevel new]; - } - - [crossSigningKeys setTrustLevel:oldTrustLevel]; // Compute trust on this user // Note this overwrites the previous value BOOL isCrossSigningVerified = [self.crossSigning isUserWithCrossSigningKeysVerified:crossSigningKeys]; - MXUserTrustLevel *newTrustLevel = [MXUserTrustLevel trustLevelWithCrossSigningVerified:isCrossSigningVerified - locallyVerified:oldTrustLevel.isLocallyVerified]; - - [crossSigningKeys updateTrustLevel:newTrustLevel]; + [crossSigningKeys setIsVerified:isCrossSigningVerified]; // Note that keys which aren't in the response will be removed from the store [self->crypto.store storeCrossSigningKeys:crossSigningKeys]; diff --git a/MatrixSDK/Crypto/Data/MXRoomSettings.swift b/MatrixSDK/Crypto/Data/MXRoomSettings.swift new file mode 100644 index 0000000000..6b7b415c3e --- /dev/null +++ b/MatrixSDK/Crypto/Data/MXRoomSettings.swift @@ -0,0 +1,46 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// 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 + +// Object containing stored room settings, such as algorithm used +// and additional crypto options +@objc public class MXRoomSettings: NSObject { + enum Error: Swift.Error { + case missingParameters + } + + public let roomId: String + public let algorithm: String + public let blacklistUnverifiedDevices: Bool + + @objc public init( + roomId: String!, + algorithm: String!, + blacklistUnverifiedDevices: Bool + ) throws { + guard + let roomId = roomId, + let algorithm = algorithm + else { + throw Error.missingParameters + } + + self.roomId = roomId + self.algorithm = algorithm + self.blacklistUnverifiedDevices = blacklistUnverifiedDevices + } +} diff --git a/MatrixSDK/Crypto/Data/Store/MXCryptoStore.h b/MatrixSDK/Crypto/Data/Store/MXCryptoStore.h index f530cab7c4..aa2206d5d4 100644 --- a/MatrixSDK/Crypto/Data/Store/MXCryptoStore.h +++ b/MatrixSDK/Crypto/Data/Store/MXCryptoStore.h @@ -35,6 +35,7 @@ @class OLMAccount; @class OLMOutboundGroupSession; +@class MXRoomSettings; /** The `MXCryptoStore` protocol defines an interface that must be implemented in order to store @@ -247,6 +248,11 @@ */ - (NSString*)algorithmForRoom:(NSString*)roomId; +/** + Fetch all stored room settings, containing room algorithm and other crypto options + */ +- (NSArray *)roomSettings; + /** Store a session between this device and another device. diff --git a/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m b/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m index a81bf408a5..277553c20a 100644 --- a/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m +++ b/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m @@ -820,6 +820,23 @@ - (MXRealmRoomAlgorithm *)realmRoomAlgorithmForRoom:(NSString*)roomId inRealm:(R return [MXRealmRoomAlgorithm objectInRealm:realm forPrimaryKey:roomId]; } +- (NSArray *)roomSettings +{ + NSMutableArray *objects = [NSMutableArray array]; + for (MXRealmRoomAlgorithm *item in [MXRealmRoomAlgorithm allObjectsInRealm:self.realm]) { + NSError *error = nil; + MXRoomSettings *settings = [[MXRoomSettings alloc] initWithRoomId:item.roomId + algorithm:item.algorithm + blacklistUnverifiedDevices:item.blacklistUnverifiedDevices + error:&error]; + if (settings) { + [objects addObject:settings]; + } else { + MXLogErrorDetails(@"[MXRealmCryptoStore] roomSettings: Cannot create settings", error); + } + } + return objects.copy; +} - (void)storeSession:(MXOlmSession*)session { diff --git a/MatrixSDK/Crypto/MXCrypto.h b/MatrixSDK/Crypto/MXCrypto.h index d638850b0d..7f87d54fae 100644 --- a/MatrixSDK/Crypto/MXCrypto.h +++ b/MatrixSDK/Crypto/MXCrypto.h @@ -229,19 +229,22 @@ extern NSString *const MXDeviceListDidUpdateUsersDevicesNotification; failure:(nullable void (^)(NSError *error))failure; /** - Update the verification state of the given user. + Verify the given user via cross-signing - @param verificationStatus the new verification status. @param userId the user. @param success A block object called when the operation succeeds. @param failure A block object called when the operation fails. */ -- (void)setUserVerification:(BOOL)verificationStatus forUser:(NSString*)userId - success:(nullable void (^)(void))success - failure:(nullable void (^)(NSError *error))failure; +- (void)setUserVerificationForUserId:(NSString*)userId + success:(nullable void (^)(void))success + failure:(nullable void (^)(NSError *error))failure; + +/** + Is the user verified via cross-signing + */ +- (BOOL)isUserVerified:(NSString *)userId; -- (MXUserTrustLevel*)trustLevelForUser:(NSString*)userId; - (nullable MXDeviceTrustLevel*)deviceTrustLevelForDevice:(NSString*)deviceId ofUser:(NSString*)userId; /** diff --git a/MatrixSDK/Crypto/MXCrypto.m b/MatrixSDK/Crypto/MXCrypto.m index 6066b74c7f..268b8d1009 100644 --- a/MatrixSDK/Crypto/MXCrypto.m +++ b/MatrixSDK/Crypto/MXCrypto.m @@ -1148,16 +1148,13 @@ - (void)setDevicesKnown:(MXUsersDevicesMap *)devices complete:(v #endif } -- (void)setUserVerification:(BOOL)verificationStatus forUser:(NSString*)userId - success:(void (^)(void))success - failure:(void (^)(NSError *error))failure +- (void)setUserVerificationForUserId:(NSString*)userId + success:(void (^)(void))success + failure:(void (^)(NSError *error))failure { - // We cannot remove cross-signing trust for a user in the matrix spec - NSParameterAssert(verificationStatus); - #ifdef MX_CRYPTO dispatch_async(_cryptoQueue, ^{ - [self setUserVerification2:verificationStatus forUser:userId downloadIfNeeded:YES success:success failure:failure]; + [self setUserVerificationForUserId2:userId downloadIfNeeded:YES success:success failure:failure]; }); #else if (success) @@ -1167,10 +1164,10 @@ - (void)setUserVerification:(BOOL)verificationStatus forUser:(NSString*)userId #endif } -- (void)setUserVerification2:(BOOL)verificationStatus forUser:(NSString*)userId - downloadIfNeeded:(BOOL)downloadIfNeeded - success:(void (^)(void))success - failure:(void (^)(NSError *error))failure +- (void)setUserVerificationForUserId2:(NSString*)userId + downloadIfNeeded:(BOOL)downloadIfNeeded + success:(void (^)(void))success + failure:(void (^)(NSError *error))failure { #ifdef MX_CRYPTO MXCrossSigningInfo *crossSigningInfo = [self.store crossSigningKeysForUser:userId]; @@ -1182,7 +1179,7 @@ - (void)setUserVerification2:(BOOL)verificationStatus forUser:(NSString*)userId { MXLogDebug(@"[MXCrypto] setUserVerification: Unknown user. Try to download user's keys for %@", userId); [self.deviceList downloadKeys:@[userId] forceDownload:YES success:^(MXUsersDevicesMap *usersDevicesInfoMap, NSDictionary *crossSigningKeysMap) { - [self setUserVerification2:verificationStatus forUser:userId downloadIfNeeded:NO success:success failure:failure]; + [self setUserVerificationForUserId2:userId downloadIfNeeded:NO success:success failure:failure]; } failure:^(NSError *error) { if (failure) { @@ -1205,17 +1202,8 @@ - (void)setUserVerification2:(BOOL)verificationStatus forUser:(NSString*)userId return; } - // Store information locally - if (verificationStatus != crossSigningInfo.trustLevel.isLocallyVerified) - { - MXUserTrustLevel *newTrustLevel = [MXUserTrustLevel trustLevelWithCrossSigningVerified:crossSigningInfo.trustLevel.isCrossSigningVerified - locallyVerified:verificationStatus];; - [crossSigningInfo updateTrustLevel:newTrustLevel]; - [_store storeCrossSigningKeys:crossSigningInfo]; - } - // Cross-sign if possible - if (verificationStatus != crossSigningInfo.trustLevel.isCrossSigningVerified) + if (!crossSigningInfo.isVerified) { if (self.crossSigning.canCrossSign) { @@ -1245,9 +1233,9 @@ - (void)setUserVerification2:(BOOL)verificationStatus forUser:(NSString*)userId #pragma mark - Cross-signing trust -- (MXUserTrustLevel*)trustLevelForUser:(NSString*)userId +- (BOOL)isUserVerified:(NSString *)userId { - return [self.store crossSigningKeysForUser:userId].trustLevel ?: [MXUserTrustLevel new]; + return [self.store crossSigningKeysForUser:userId].isVerified; } - (MXDeviceTrustLevel*)deviceTrustLevelForDevice:(NSString*)deviceId ofUser:(NSString*)userId; @@ -1287,8 +1275,7 @@ - (void)trustLevelSummaryForUserIds:(NSArray*)userIds onComplete:(voi { usersCount++; - MXUserTrustLevel *userTrustLevel = [self trustLevelForUser:userId]; - if (userTrustLevel.isVerified) + if ([self isUserVerified:userId]) { trustedUsersCount++; @@ -1303,14 +1290,12 @@ - (void)trustLevelSummaryForUserIds:(NSArray*)userIds onComplete:(voi } } - NSProgress *trustedUsersProgress = [NSProgress progressWithTotalUnitCount:usersCount]; - trustedUsersProgress.completedUnitCount = trustedUsersCount; - - NSProgress *trustedDevicesProgress = [NSProgress progressWithTotalUnitCount:devicesCount]; - trustedDevicesProgress.completedUnitCount = trustedDevicesCount; - - MXUsersTrustLevelSummary *trustLevelSummary = [[MXUsersTrustLevelSummary alloc] initWithTrustedUsersProgress:trustedUsersProgress - andTrustedDevicesProgress:trustedDevicesProgress]; + MXTrustSummary *usersTrust = [[MXTrustSummary alloc] initWithTrustedCount:trustedUsersCount + totalCount:usersCount]; + MXTrustSummary *devicesTrust = [[MXTrustSummary alloc] initWithTrustedCount:trustedDevicesCount + totalCount:devicesCount]; + MXUsersTrustLevelSummary *trustLevelSummary = [[MXUsersTrustLevelSummary alloc] initWithUsersTrust:usersTrust + devicesTrust:devicesTrust]; dispatch_async(dispatch_get_main_queue(), ^{ onComplete(trustLevelSummary); diff --git a/MatrixSDK/Crypto/MXCryptoV2.swift b/MatrixSDK/Crypto/MXCryptoV2.swift index 0d2e574429..3dc0c67589 100644 --- a/MatrixSDK/Crypto/MXCryptoV2.swift +++ b/MatrixSDK/Crypto/MXCryptoV2.swift @@ -28,7 +28,6 @@ class MXCryptoV2: NSObject, MXCrypto { // MARK: - Private properties private weak var session: MXSession? - private let legacyStore: MXCryptoStore private let machine: MXCryptoMachine private let encryptor: MXRoomEventEncrypting @@ -46,6 +45,7 @@ class MXCryptoV2: NSObject, MXCrypto { // MARK: - Public properties var version: String { + // Will be moved into the olm machine as API let sdkVersion = Bundle(for: OlmMachine.self).infoDictionary?["CFBundleShortVersionString"] ?? "" return "Matrix Crypto SDK \(sdkVersion)" @@ -69,11 +69,9 @@ class MXCryptoV2: NSObject, MXCrypto { userId: String, deviceId: String, session: MXSession, - restClient: MXRestClient, - legacyStore: MXCryptoStore + restClient: MXRestClient ) throws { self.session = session - self.legacyStore = legacyStore let getRoomAction: (String) -> MXRoom? = { [weak session] in session?.room(withRoomId: $0) @@ -88,7 +86,6 @@ class MXCryptoV2: NSObject, MXCrypto { encryptor = MXRoomEventEncryption( handler: machine, - legacyStore: legacyStore, getRoomAction: getRoomAction ) decryptor = MXRoomEventDecryption(handler: machine) @@ -424,18 +421,11 @@ class MXCryptoV2: NSObject, MXCrypto { } } - public func setUserVerification( - _ verificationStatus: Bool, - forUser userId: String, + func setUserVerificationForUserId( + _ userId: String, success: (() -> Void)?, - failure: ((Swift.Error) -> Void)? - ) { - guard verificationStatus else { - log.failure("Cannot unset user trust") - failure?(Error.cannotUnsetTrust) - return - } - + failure: ((Swift.Error) -> Void)?) + { log.debug("Signing user") crossSigning.signUser( withUserId: userId, @@ -448,8 +438,8 @@ class MXCryptoV2: NSObject, MXCrypto { ) } - public func trustLevel(forUser userId: String) -> MXUserTrustLevel { - return trustLevelSource.userTrustLevel(userId: userId) + func isUserVerified(_ userId: String) -> Bool { + return trustLevelSource.isUserVerified(userId: userId) } public func deviceTrustLevel(forDevice deviceId: String, ofUser userId: String) -> MXDeviceTrustLevel? { @@ -599,19 +589,23 @@ class MXCryptoV2: NSObject, MXCrypto { public var globalBlacklistUnverifiedDevices: Bool { get { - return legacyStore.globalBlacklistUnverifiedDevices + return machine.onlyAllowTrustedDevices } set { - legacyStore.globalBlacklistUnverifiedDevices = newValue + machine.onlyAllowTrustedDevices = newValue } } public func isBlacklistUnverifiedDevices(inRoom roomId: String) -> Bool { - return legacyStore.blacklistUnverifiedDevices(inRoom: roomId) + return machine.roomSettings(roomId: roomId)?.onlyAllowTrustedDevices == true } public func setBlacklistUnverifiedDevicesInRoom(_ roomId: String, blacklist: Bool) { - legacyStore.storeBlacklistUnverifiedDevices(inRoom: roomId, blacklist: blacklist) + do { + try machine.setOnlyAllowTrustedDevices(for: roomId, onlyAllowTrustedDevices: blacklist) + } catch { + log.error("Failed blocking unverified devices", context: error) + } } // MARK: - Private @@ -661,7 +655,7 @@ class MXCryptoV2: NSObject, MXCrypto { } log.debug("Tracking new user `\(userId)` due to \(member.membership) event") - machine.addTrackedUsers([userId]) + machine.updateTrackedUsers([userId]) } private func restoreBackupIfPossible(event: MXEvent) { diff --git a/MatrixSDK/Crypto/MXCryptoV2Factory.swift b/MatrixSDK/Crypto/MXCryptoV2Factory.swift index 2226aabef5..bc14bcfbd8 100644 --- a/MatrixSDK/Crypto/MXCryptoV2Factory.swift +++ b/MatrixSDK/Crypto/MXCryptoV2Factory.swift @@ -19,12 +19,15 @@ import Foundation @objc public class MXCryptoV2Factory: NSObject { enum Error: Swift.Error { case cryptoNotAvailable - case storeNotAvailable } @objc public static let shared = MXCryptoV2Factory() private let log = MXNamedLog(name: "MXCryptoV2Factory") + private var lastDeprecatedVersion: MXCryptoVersion { + .deprecated2 + } + @objc public func buildCrypto( session: MXSession!, migrationProgress: ((Double) -> Void)?, @@ -48,17 +51,19 @@ import Foundation guard let self = self else { return } do { - let store = try await self.createOrOpenLegacyStore(credentials: credentials) - self.migrateIfNecessary(legacyStore: store) { + try self.deprecateLegacyStoreIfNecessary(credentials: credentials) { migrationProgress?($0) } - + } catch { + self.log.error("Failed to migrate / deprecate legacy store", context: error) + } + + do { let crypto = try await MXCryptoV2( userId: userId, deviceId: deviceId, session: session, - restClient: restClient, - legacyStore: store + restClient: restClient ) await MainActor.run { success(crypto) @@ -72,48 +77,48 @@ import Foundation } } - // A few features (e.g. global untrusted users blacklist) are not yet implemented in `MatrixSDKCrypto` - // so they have to be stored in a legacy database. Will be moved to `MatrixSDKCrypto` eventually - private func createOrOpenLegacyStore(credentials: MXCredentials) async throws -> MXCryptoStore { - MXRealmCryptoStore.deleteReadonlyStore(with: credentials) - - if + private func deprecateLegacyStoreIfNecessary( + credentials: MXCredentials, + updateProgress: @escaping ((Double) -> Void) + ) throws { + guard MXRealmCryptoStore.hasData(for: credentials), let legacyStore = MXRealmCryptoStore(credentials: credentials) - { - log.debug("Legacy crypto store exists") - return legacyStore - - } else { - log.debug("Creating new legacy crypto store") - - MXRealmCryptoStore.delete(with: credentials) - guard let legacyStore = MXRealmCryptoStore.createStore(with: credentials) else { - log.failure("Cannot create legacy store") - throw Error.storeNotAvailable - } - legacyStore.cryptoVersion = MXCryptoVersion.versionLegacyDeprecated - - log.debug("Legacy crypto store created") - return legacyStore + else { + log.debug("Legacy crypto store does not exist") + return } + + log.debug("Legacy crypto store exists") + try migrateIfNecessary(legacyStore: legacyStore, updateProgress: updateProgress) + + log.debug("Deleting legacy store after successfull migration") + MXRealmCryptoStore.delete(with: credentials) } - private func migrateIfNecessary(legacyStore: MXCryptoStore, updateProgress: @escaping (Double) -> Void) { - guard legacyStore.cryptoVersion.rawValue < MXCryptoVersion.versionLegacyDeprecated.rawValue else { + private func migrateIfNecessary( + legacyStore: MXCryptoStore, + updateProgress: @escaping (Double) -> Void + ) throws { + let legacyVersion = legacyStore.cryptoVersion.rawValue + guard legacyVersion < lastDeprecatedVersion.rawValue else { log.debug("Legacy crypto has already been deprecated, no need to migrate") return } - log.debug("Requires migration from legacy crypto") + log.debug("Requires migration from legacy crypto version \(legacyVersion) to version \(lastDeprecatedVersion.rawValue)") let migration = MXCryptoMigrationV2(legacyStore: legacyStore) - do { - try migration.migrateCrypto(updateProgress: updateProgress) - log.debug("Marking legacy crypto as deprecated") - legacyStore.cryptoVersion = MXCryptoVersion.versionLegacyDeprecated - } catch { - log.error("Failed to migrate crypto", context: error) - } + + if legacyVersion < MXCryptoVersion.deprecated1.rawValue { + log.debug("Full migration of crypto data") + try migration.migrateAllData(updateProgress: updateProgress) + + } else if legacyVersion < MXCryptoVersion.deprecated2.rawValue { + log.debug("Partial migration of room and global settings") + try migration.migrateRoomAndGlobalSettingsOnly(updateProgress: updateProgress) + } else { + log.failure("Unhandled crypto version", context: legacyStore.cryptoVersion.rawValue) + } } } diff --git a/MatrixSDK/Crypto/MXCryptoV2Feature.swift b/MatrixSDK/Crypto/MXCryptoV2Feature.swift index 0af26c28a1..a5d6c16613 100644 --- a/MatrixSDK/Crypto/MXCryptoV2Feature.swift +++ b/MatrixSDK/Crypto/MXCryptoV2Feature.swift @@ -19,6 +19,8 @@ import Foundation /// Feature representing the availability of the external rust-based Crypto SDK /// whilst it is not fully available to everyone and / or is an optional feature. @objc public protocol MXCryptoV2Feature { + /// Current version of the rust-based Crypto SDK + var version: String { get } /// Is Crypto SDK currently enabled /// diff --git a/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift b/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift index 17c092f701..6465ee00d9 100644 --- a/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift +++ b/MatrixSDK/Crypto/Migration/Data/MXCryptoMigrationStore.swift @@ -19,12 +19,24 @@ import OLMKit import MatrixSDKCrypto struct MXCryptoMigrationStore { + struct GlobalSettings { + let onlyAllowTrustedDevices: Bool + } + enum Error: Swift.Error { case missingAccount } let legacyStore: MXCryptoStore + var userId: String? { + legacyStore.userId() + } + + var deviceId: String? { + legacyStore.deviceId() + } + var olmSessionCount: UInt { legacyStore.sessionsCount() } @@ -33,6 +45,10 @@ struct MXCryptoMigrationStore { legacyStore.inboundGroupSessionsCount(false) } + var globalSettings: GlobalSettings { + .init(onlyAllowTrustedDevices: legacyStore.globalBlacklistUnverifiedDevices) + } + func extractData(with pickleKey: Data) throws -> MigrationData { return .init( account: try pickledAccount(pickleKey: pickleKey), @@ -42,7 +58,8 @@ struct MXCryptoMigrationStore { backupRecoveryKey: backupRecoveryKey(), pickleKey: [UInt8](pickleKey), crossSigning: crossSigning(), - trackedUsers: trackedUsers() + trackedUsers: trackedUsers(), + roomSettings: extractRoomSettings() ) } @@ -86,6 +103,24 @@ struct MXCryptoMigrationStore { } } + func extractRoomSettings() -> [String: RoomSettings] { + return legacyStore + .roomSettings() + .reduce(into: [String: RoomSettings]()) { dict, item in + do { + let algorithm = try EventEncryptionAlgorithm(string: item.algorithm) + dict[item.roomId] = RoomSettings( + algorithm: algorithm, + onlyAllowTrustedDevices: item.blacklistUnverifiedDevices + ) + } catch { + MXLog.error("[MXCryptoMigrationStore] cannot extract room settings", context: error) + } + } + } + + // MARK: - Private + private func pickledAccount(pickleKey: Data) throws -> PickledAccount { guard let userId = legacyStore.userId(), diff --git a/MatrixSDK/Crypto/Migration/MXCryptoMigrationV2.swift b/MatrixSDK/Crypto/Migration/MXCryptoMigrationV2.swift index a15784d633..3c047bffbf 100644 --- a/MatrixSDK/Crypto/Migration/MXCryptoMigrationV2.swift +++ b/MatrixSDK/Crypto/Migration/MXCryptoMigrationV2.swift @@ -20,6 +20,7 @@ import MatrixSDKCrypto class MXCryptoMigrationV2: NSObject { enum Error: Swift.Error { + case missingCredentials case unknownPickleKey } @@ -39,7 +40,7 @@ class MXCryptoMigrationV2: NSObject { store = .init(legacyStore: legacyStore) } - func migrateCrypto(updateProgress: @escaping (Double) -> Void) throws { + func migrateAllData(updateProgress: @escaping (Double) -> Void) throws { log.debug("Starting migration") let startDate = Date() @@ -64,6 +65,8 @@ class MXCryptoMigrationV2: NSObject { - backup_key : \(data.backupRecoveryKey != nil ? "true" : "false") - cross_signing : \(data.crossSigning.masterKey != nil ? "true" : "false") - tracked_users : \(data.trackedUsers.count) + - room_settings : \(data.roomSettings.count) + - global_settings : \(store.globalSettings) """ log.debug(details) @@ -84,7 +87,7 @@ class MXCryptoMigrationV2: NSObject { updateProgress(progress * olmToMegolmRatio) do { - try self?.migrateSessions( + try self?.migrateSessionsBatch( data: data, sessions: batch, url: url, @@ -101,7 +104,7 @@ class MXCryptoMigrationV2: NSObject { updateProgress(olmToMegolmRatio + progress * (1 - olmToMegolmRatio)) do { - try self?.migrateSessions( + try self?.migrateSessionsBatch( data: data, inboundGroupSessions: batch, url: url, @@ -112,11 +115,56 @@ class MXCryptoMigrationV2: NSObject { } } + log.debug("Migrating global settings") + try migrateGlobalSettings( + userId: data.account.userId, + deviceId: data.account.deviceId, + url: url, + passphrase: passphrase + ) + let duration = Date().timeIntervalSince(startDate) * 1000 log.debug("Migration completed in \(duration) ms") updateProgress(1) } + func migrateRoomAndGlobalSettingsOnly(updateProgress: @escaping (Double) -> Void) throws { + guard let userId = store.userId, let deviceId = store.deviceId else { + throw Error.missingCredentials + } + + let url = try MXCryptoMachineStore.storeURL(for: userId) + let passphrase = try MXCryptoMachineStore.storePassphrase() + let settings = store.extractRoomSettings() + + let details = """ + Settings migration summary + - user id : \(userId) + - device id : \(deviceId) + - room_settings : \(settings.count) + - global_settings : \(store.globalSettings) + """ + log.debug(details) + updateProgress(0) + + try migrateRoomSettings( + roomSettings: settings, + path: url.path, + passphrase: passphrase + ) + + log.debug("Migrating global settings") + try migrateGlobalSettings( + userId: userId, + deviceId: deviceId, + url: url, + passphrase: passphrase + ) + + log.debug("Migration completed") + updateProgress(1) + } + private func legacyPickleKey() throws -> Data { guard let key = OLMKit.sharedInstance().pickleKeyDelegate?.pickleKey() else { throw Error.unknownPickleKey @@ -124,32 +172,45 @@ class MXCryptoMigrationV2: NSObject { return key } - // To migrate sessions in batches and keep memory under control we are repeatedly calling `migrate` - // function whilst only passing data for sessions and account, keeping the rest empty. - // This API will be improved in `MatrixCryptoSDK` in the future. - private func migrateSessions( + private func migrateSessionsBatch( data: MigrationData, sessions: [PickledSession] = [], inboundGroupSessions: [PickledInboundGroupSession] = [], url: URL, passphrase: String ) throws { - try migrate( + try migrateSessions( data: .init( - account: data.account, + userId: data.account.userId, + deviceId: data.account.deviceId, + curve25519Key: legacyDevice.deviceCurve25519Key, + ed25519Key: legacyDevice.deviceEd25519Key, sessions: sessions, inboundGroupSessions: inboundGroupSessions, - backupVersion: data.backupVersion, - backupRecoveryKey: data.backupRecoveryKey, - pickleKey: data.pickleKey, - crossSigning: data.crossSigning, - trackedUsers: data.trackedUsers + pickleKey: data.pickleKey ), path: url.path, passphrase: passphrase, progressListener: self ) } + + private func migrateGlobalSettings( + userId: String, + deviceId: String, + url: URL, + passphrase: String + ) throws { + let machine = try OlmMachine( + userId: userId, + deviceId: deviceId, + path: url.path, + passphrase: passphrase + ) + + let onlyTrusted = store.globalSettings.onlyAllowTrustedDevices + try machine.setOnlyAllowTrustedDevices(onlyAllowTrustedDevices: onlyTrusted) + } } extension MXCryptoMigrationV2: ProgressListener { diff --git a/MatrixSDK/Crypto/Migration/MXCryptoVersion.h b/MatrixSDK/Crypto/Migration/MXCryptoVersion.h index 6fd9a648a8..2ede9ef7ff 100644 --- a/MatrixSDK/Crypto/Migration/MXCryptoVersion.h +++ b/MatrixSDK/Crypto/Migration/MXCryptoVersion.h @@ -36,12 +36,19 @@ typedef NS_ENUM(NSInteger, MXCryptoVersion) // It is used to compute MXCryptoVersionLast. MXCryptoVersionCount, +#pragma mark - Deprecated versions + // The internal crypto module has been deprecated in favour of `MatrixCryptoSDK` - // The value is set manually to leave room for intermediate version 3, 4 ... - MXCryptoVersionLegacyDeprecated = 1000, + // The value is set manually to a large number in order to leave room for possible + // intermediate valid version 3, 4 ... with bug fixes of the legacy store + MXCryptoDeprecated1 = 1000, + + // Deprecated version that migrates room settings from the legacy store, which were + // not included in the deprecated v1 + MXCryptoDeprecated2, }; -// The current version of MXCrypto +// The current version of non-deprecated MXCrypto #define MXCryptoVersionLast (MXCryptoVersionCount - 1) #endif /* MXCryptoVersion_h */ diff --git a/MatrixSDK/Crypto/Recovery/MXRecoveryService.h b/MatrixSDK/Crypto/Recovery/MXRecoveryService.h index 8c18a85a99..539b85c6e4 100644 --- a/MatrixSDK/Crypto/Recovery/MXRecoveryService.h +++ b/MatrixSDK/Crypto/Recovery/MXRecoveryService.h @@ -37,10 +37,9 @@ typedef NS_ENUM(NSInteger, MXRecoveryServiceErrorCode) }; @protocol MXRecoveryServiceDelegate -- (void)setUserVerification:(BOOL)verificationStatus - forUser:(NSString*)userId - success:(void (^)(void))success - failure:(void (^)( NSError * _Nullable error))failure; +- (void)setUserVerificationForUserId:(NSString*)userId + success:(void (^)(void))success + failure:(void (^)( NSError * _Nullable error))failure; @end /** diff --git a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m index 37cbf8c71c..655f3fa97c 100644 --- a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m +++ b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m @@ -748,8 +748,8 @@ - (void)recoverCrossSigningWithSuccess:(void (^)(void))success return; } - // Mark our user MSK as verified locally - [self.delegate setUserVerification:YES forUser:self.dependencies.credentials.userId success:^{ + // Mark our user MSK as verified + [self.delegate setUserVerificationForUserId:self.dependencies.credentials.userId success:^{ // Cross sign our current device [self.dependencies.crossSigning crossSignDeviceWithDeviceId:self.dependencies.credentials.deviceId success:^{ diff --git a/MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift b/MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift index 62d094929e..8be466fa91 100644 --- a/MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift +++ b/MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift @@ -27,15 +27,8 @@ struct MXTrustLevelSource { self.devicesSource = devicesSource } - func userTrustLevel(userId: String) -> MXUserTrustLevel { - let isVerified = userIdentitySource.isUserVerified(userId: userId) - - // `MatrixSDKCrypto` does not distinguish local and cross-signed - // verification status for users - return .init( - crossSigningVerified: isVerified, - locallyVerified: isVerified - ) + func isUserVerified(userId: String) -> Bool { + userIdentitySource.isUserVerified(userId: userId) } func deviceTrustLevel(userId: String, deviceId: String) -> MXDeviceTrustLevel? { @@ -49,32 +42,34 @@ struct MXTrustLevelSource { } func trustLevelSummary(userIds: [String]) -> MXUsersTrustLevelSummary { - return .init( - trustedUsersProgress: trustedUsers(userIds: userIds), - andTrustedDevicesProgress: trustedDevices(userIds: userIds) + .init( + usersTrust: usersTrust(userIds: userIds), + devicesTrust: devicesTrust(userIds: userIds) ) } - private func trustedUsers(userIds: [String]) -> Progress { + private func usersTrust(userIds: [String]) -> MXTrustSummary { let verifiedUsers = userIds.filter { userIdentitySource.isUserVerified(userId: $0) } - let progress = Progress(totalUnitCount: Int64(userIds.count)) - progress.completedUnitCount = Int64(verifiedUsers.count) - return progress + return .init( + trustedCount: verifiedUsers.count, + totalCount: userIds.count + ) } - private func trustedDevices(userIds: [String]) -> Progress { + private func devicesTrust(userIds: [String]) -> MXTrustSummary { let devices = userIds.flatMap { devicesSource.devices(userId: $0) } let trustedDevices = devices.filter { $0.crossSigningTrusted || $0.locallyTrusted } - - let progress = Progress(totalUnitCount: Int64(devices.count)) - progress.completedUnitCount = Int64(trustedDevices.count) - return progress + + return .init( + trustedCount: trustedDevices.count, + totalCount: devices.count + ) } } diff --git a/MatrixSDK/Crypto/Trust/MXTrustSummary.swift b/MatrixSDK/Crypto/Trust/MXTrustSummary.swift new file mode 100644 index 0000000000..9ca6cffe65 --- /dev/null +++ b/MatrixSDK/Crypto/Trust/MXTrustSummary.swift @@ -0,0 +1,37 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// 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 + +/// Convenience object summarizing trusted vs total number of entitites +/// such as users or devices +@objcMembers public class MXTrustSummary: NSObject { + public var trustedCount: Int + public var totalCount: Int + + public var areAllTrusted: Bool { + return trustedCount == totalCount + } + + public init(trustedCount: Int, totalCount: Int) { + if trustedCount > totalCount { + MXLog.error("[MXTrustSummary] trusted count is higher than total count") + } + + self.trustedCount = trustedCount + self.totalCount = max(totalCount, trustedCount) + } +} diff --git a/MatrixSDK/Crypto/Trust/MXUserTrustLevel.h b/MatrixSDK/Crypto/Trust/MXUserTrustLevel.h deleted file mode 100644 index b6a1537783..0000000000 --- a/MatrixSDK/Crypto/Trust/MXUserTrustLevel.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2020 The Matrix.org Foundation C.I.C - - 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 - -NS_ASSUME_NONNULL_BEGIN - -@interface MXUserTrustLevel : NSObject - -/** - YES if this user is verified via any means. - */ -@property (nonatomic, readonly) BOOL isVerified; - -/** - YES if this user is verified via cross signing. - */ -@property (nonatomic, readonly) BOOL isCrossSigningVerified; - -/** - YES if this user is verified locally. - */ -@property (nonatomic, readonly) BOOL isLocallyVerified; - -@end - - -#pragma mark - Factory - -@interface MXUserTrustLevel() - -+ (MXUserTrustLevel*)trustLevelWithCrossSigningVerified:(BOOL)crossSigningVerified locallyVerified:(BOOL)locallyVerified; - -@end - -NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/Trust/MXUserTrustLevel.m b/MatrixSDK/Crypto/Trust/MXUserTrustLevel.m deleted file mode 100644 index b171064c48..0000000000 --- a/MatrixSDK/Crypto/Trust/MXUserTrustLevel.m +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright 2020 The Matrix.org Foundation C.I.C - - 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 "MXUserTrustLevel.h" - -@implementation MXUserTrustLevel - -- (instancetype)init -{ - self = [super init]; - if (self) - { - _isCrossSigningVerified = NO; - _isLocallyVerified = NO; - } - return self; -} - -+ (MXUserTrustLevel *)trustLevelWithCrossSigningVerified:(BOOL)crossSigningVerified locallyVerified:(BOOL)locallyVerified -{ - MXUserTrustLevel *trustLevel = [MXUserTrustLevel new]; - trustLevel->_isCrossSigningVerified = crossSigningVerified; - trustLevel->_isLocallyVerified = locallyVerified; - - return trustLevel; -} - - -- (BOOL)isVerified -{ - return _isCrossSigningVerified || _isLocallyVerified; -} - - -- (BOOL)isEqual:(id)object -{ - if (self == object) - { - return YES; - } - - BOOL isEqual = NO; - - if ([object isKindOfClass:MXUserTrustLevel.class]) - { - MXUserTrustLevel *other = object; - isEqual = other.isCrossSigningVerified == self.isCrossSigningVerified; - isEqual &= other.isLocallyVerified == self.isLocallyVerified; - } - - return isEqual; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"MXUserTrustLevel: local: %@ - cross-signing: %@", @(_isLocallyVerified), @(_isCrossSigningVerified)]; -} - -#pragma mark - NSCoding - -- (id)initWithCoder:(NSCoder *)aDecoder -{ - self = [super init]; - if (self) - { - _isCrossSigningVerified = [aDecoder decodeBoolForKey:@"isCrossSigningVerified"]; - _isLocallyVerified = [aDecoder decodeBoolForKey:@"isLocallyVerified"]; - } - return self; -} - -- (void)encodeWithCoder:(NSCoder *)aCoder -{ - [aCoder encodeBool:_isCrossSigningVerified forKey:@"isCrossSigningVerified"]; - [aCoder encodeBool:_isLocallyVerified forKey:@"isLocallyVerified"]; -} - -@end diff --git a/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.h b/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.h index cd0b3b8506..710fe4b36f 100644 --- a/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.h +++ b/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.h @@ -16,7 +16,7 @@ #import -@class MXUsersTrustLevelSummaryMO; +@class MXTrustSummary, MXUsersTrustLevelSummaryMO; NS_ASSUME_NONNULL_BEGIN @@ -25,13 +25,18 @@ NS_ASSUME_NONNULL_BEGIN */ @interface MXUsersTrustLevelSummary : NSObject -// The ratio of trusted users -@property (nonatomic, strong, readonly) NSProgress *trustedUsersProgress; +/** + The summary of trusted users + */ +@property (nonatomic, strong, readonly) MXTrustSummary *usersTrust; -// The ratio of trusted devices for trusted users -@property (nonatomic, strong, readonly) NSProgress *trustedDevicesProgress; +/** + The summary of trusted devices for trusted users + */ +@property (nonatomic, strong, readonly) MXTrustSummary *devicesTrust; -- (instancetype)initWithTrustedUsersProgress:(NSProgress*)trustedUsersProgress andTrustedDevicesProgress:(NSProgress*)trustedDevicesProgress; +- (instancetype)initWithUsersTrust:(MXTrustSummary *)usersTrust + devicesTrust:(MXTrustSummary *)devicesTrust; #pragma mark - CoreData Model diff --git a/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.m b/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.m index f16810dd6c..65baeca27b 100644 --- a/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.m +++ b/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.m @@ -19,20 +19,21 @@ @interface MXUsersTrustLevelSummary() -@property (nonatomic, strong, readwrite) NSProgress *trustedUsersProgress; -@property (nonatomic, strong, readwrite) NSProgress *trustedDevicesProgress; +@property (nonatomic, strong, readwrite) MXTrustSummary *usersTrust; +@property (nonatomic, strong, readwrite) MXTrustSummary *devicesTrust; @end @implementation MXUsersTrustLevelSummary -- (instancetype)initWithTrustedUsersProgress:(NSProgress*)trustedUsersProgress andTrustedDevicesProgress:(NSProgress*)trustedDevicesProgress +- (instancetype)initWithUsersTrust:(MXTrustSummary *)usersTrust + devicesTrust:(MXTrustSummary *)devicesTrust { self = [super init]; if (self) { - self.trustedUsersProgress = trustedUsersProgress; - self.trustedDevicesProgress = trustedDevicesProgress; + self.usersTrust = usersTrust; + self.devicesTrust = devicesTrust; } return self; } @@ -43,11 +44,11 @@ - (instancetype)initWithManagedObject:(MXUsersTrustLevelSummaryMO *)model { if (self = [super init]) { - self.trustedUsersProgress = [NSProgress progressWithTotalUnitCount:model.s_usersCount]; - self.trustedUsersProgress.completedUnitCount = model.s_trustedUsersCount; + self.usersTrust = [[MXTrustSummary alloc] initWithTrustedCount:model.s_trustedUsersCount + totalCount:model.s_usersCount]; - self.trustedDevicesProgress = [NSProgress progressWithTotalUnitCount:model.s_devicesCount]; - self.trustedDevicesProgress.completedUnitCount = model.s_trustedDevicesCount; + self.devicesTrust = [[MXTrustSummary alloc] initWithTrustedCount:model.s_trustedDevicesCount + totalCount:model.s_devicesCount]; } return self; } @@ -61,24 +62,21 @@ - (id)initWithCoder:(NSCoder *)aDecoder { NSUInteger usersCount = [aDecoder decodeIntegerForKey:@"usersCount"]; NSUInteger trustedUsersCount = [aDecoder decodeIntegerForKey:@"trustedUsersCount"]; + self.usersTrust = [[MXTrustSummary alloc] initWithTrustedCount:trustedUsersCount totalCount:usersCount]; + NSUInteger devicesCount = [aDecoder decodeIntegerForKey:@"devicesCount"]; NSUInteger trustedDevicesCount = [aDecoder decodeIntegerForKey:@"trustedDevicesCount"]; - - self.trustedUsersProgress = [NSProgress progressWithTotalUnitCount:usersCount]; - self.trustedUsersProgress.completedUnitCount = trustedUsersCount; - - self.trustedDevicesProgress = [NSProgress progressWithTotalUnitCount:devicesCount]; - self.trustedDevicesProgress.completedUnitCount = trustedDevicesCount; + self.devicesTrust = [[MXTrustSummary alloc] initWithTrustedCount:trustedDevicesCount totalCount:devicesCount]; } return self; } - (void)encodeWithCoder:(NSCoder *)aCoder { - [aCoder encodeInteger:self.trustedUsersProgress.totalUnitCount forKey:@"usersCount"]; - [aCoder encodeInteger:self.trustedUsersProgress.completedUnitCount forKey:@"trustedUsersCount"]; - [aCoder encodeInteger:self.trustedDevicesProgress.totalUnitCount forKey:@"devicesCount"]; - [aCoder encodeInteger:self.trustedDevicesProgress.completedUnitCount forKey:@"trustedDevicesCount"]; + [aCoder encodeInteger:self.usersTrust.totalCount forKey:@"usersCount"]; + [aCoder encodeInteger:self.usersTrust.trustedCount forKey:@"trustedUsersCount"]; + [aCoder encodeInteger:self.devicesTrust.totalCount forKey:@"devicesCount"]; + [aCoder encodeInteger:self.devicesTrust.trustedCount forKey:@"trustedDevicesCount"]; } diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m index 1596bb9a31..785f61ff17 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m @@ -1963,11 +1963,10 @@ - (MXQRCodeData*)createQRCodeDataWithTransactionId:(NSString*)transactionId othe MXQRCodeData *qrCodeData; NSString *currentUserId = self.crypto.mxSession.myUserId; - MXUserTrustLevel *currentUserTrustLevel = [self.crypto trustLevelForUser:currentUserId]; if ([otherUserId isEqualToString:currentUserId]) { - if (currentUserTrustLevel.isCrossSigningVerified) + if ([self.crypto isUserVerified:currentUserId]) { // This is a self verification and I am the old device (Osborne2) qrCodeData = [self createSelfVerifyingMasterKeyTrustedQRCodeDataWithTransactionId:transactionId otherDeviceId:otherDeviceId]; diff --git a/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransaction.m b/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransaction.m index cf05f1c8f6..eccf76239f 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransaction.m +++ b/MatrixSDK/Crypto/Verification/Transactions/QRCode/MXQRCodeTransaction.m @@ -326,7 +326,7 @@ - (void)trustOtherUserWithId:(NSString*)otherUserId andDeviceId:(NSString*)other [self.manager.crypto setDeviceVerification:MXDeviceVerified forDevice:otherDeviceId ofUser:otherUserId success:^{ // Mark user as verified - [self.manager.crypto setUserVerification:YES forUser:otherUserId success:^{ + [self.manager.crypto setUserVerificationForUserId:otherUserId success:^{ [self sendVerified]; } failure:^(NSError *error) { diff --git a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m index 4388bc3037..78c3be9319 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m +++ b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m @@ -421,7 +421,7 @@ - (void)verifyMacs // Mark user as verified MXLogDebug(@"[MXKeyVerification][MXSASTransaction] verifyMacs: Mark user %@ as verified", self.otherDevice.userId); dispatch_group_enter(group); - [self.manager.crypto setUserVerification:YES forUser:self.otherDevice.userId success:^{ + [self.manager.crypto setUserVerificationForUserId:self.otherDevice.userId success:^{ dispatch_group_leave(group); } failure:^(NSError *error) { diff --git a/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXUsersTrustLevelSummaryMO.swift b/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXUsersTrustLevelSummaryMO.swift index e212b22d62..bfed9ee448 100644 --- a/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXUsersTrustLevelSummaryMO.swift +++ b/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXUsersTrustLevelSummaryMO.swift @@ -40,10 +40,10 @@ public class MXUsersTrustLevelSummaryMO: NSManagedObject { } internal func update(withUsersTrustLevelSummary usersTrustLevelSummary: MXUsersTrustLevelSummary) { - s_usersCount = Int32(usersTrustLevelSummary.trustedUsersProgress.totalUnitCount) - s_trustedUsersCount = Int32(usersTrustLevelSummary.trustedUsersProgress.completedUnitCount) - s_devicesCount = Int32(usersTrustLevelSummary.trustedDevicesProgress.totalUnitCount) - s_trustedDevicesCount = Int32(usersTrustLevelSummary.trustedDevicesProgress.completedUnitCount) + s_usersCount = Int32(usersTrustLevelSummary.usersTrust.totalCount) + s_trustedUsersCount = Int32(usersTrustLevelSummary.usersTrust.trustedCount) + s_devicesCount = Int32(usersTrustLevelSummary.devicesTrust.totalCount) + s_trustedDevicesCount = Int32(usersTrustLevelSummary.devicesTrust.trustedCount) } } diff --git a/MatrixSDK/MXSDKOptions.h b/MatrixSDK/MXSDKOptions.h index 1d59459e0b..929b183655 100644 --- a/MatrixSDK/MXSDKOptions.h +++ b/MatrixSDK/MXSDKOptions.h @@ -217,6 +217,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, readonly) BOOL enableCryptoSDK; +/** + The text-based identifier for the crypto module being used (e.g. native vs rust) + */ +@property (nonatomic, readonly) NSString *cryptoModuleId; + /** Enable symmetric room key backups @@ -232,12 +237,12 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) BOOL enableNewClientInformationFeature; /** - Enable the calculating of progress during session startup, incl counting the number - of attempts to sync with the server and percentage of response data processed. + Enable the calculating and display of progress during session startup, incl store migration, + syncing and response processing. - @remark the value currently depends on `enableCryptoSDK` being `YES` + @remark YES by default */ -@property (nonatomic, readonly) BOOL enableStartupProgress; +@property (nonatomic) BOOL enableStartupProgress; @end diff --git a/MatrixSDK/MXSDKOptions.m b/MatrixSDK/MXSDKOptions.m index 69d7df7c3b..f9acfda590 100644 --- a/MatrixSDK/MXSDKOptions.m +++ b/MatrixSDK/MXSDKOptions.m @@ -56,6 +56,7 @@ - (instancetype)init _enableRoomSharedHistoryOnInvite = NO; _enableSymmetricBackup = NO; _enableNewClientInformationFeature = NO; + _enableStartupProgress = YES; } return self; @@ -71,12 +72,9 @@ - (BOOL)enableCryptoSDK return self.cryptoSDKFeature.isEnabled; } -- (BOOL)enableStartupProgress +- (NSString *)cryptoModuleId { - // The value of `enableStartupProgress` depends on `enableCryptoSDK` as the latter provides some new UX elements - // such as initial data migration. It is a good opportunity to enable startup progress as well, before it becomes - // default to all. - return self.enableCryptoSDK; + return self.enableCryptoSDK ? @"rust" : @"native"; } - (void)setRoomListDataManagerClass:(Class)roomListDataManagerClass diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index faccbdf74f..051b41d122 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -401,7 +401,7 @@ -(void)setStore:(id)store success:(void (^)(void))onStoreDataReady fail [MXLegacyCrypto initializeCryptoWithMatrixSession:self migrationProgress:^(double progress) { if (MXSDKOptions.sharedInstance.enableStartupProgress) { - [self.startupProgress updateMigrationProgress:progress]; + [self.startupProgress updateProgressForStage:MXSessionStartupStageStoreMigration progress:progress]; } } complete:^(id crypto, NSError *error) { @@ -593,8 +593,8 @@ - (void)handleSyncResponse:(MXSyncResponse *)syncResponse if (MXSDKOptions.sharedInstance.enableStartupProgress && progress) { + progress([self.startupProgress overallProgressForStep:completedRooms totalCount:totalRooms progress:1]); completedRooms += 1; - progress([self startupProgressForCompleted:completedRooms total:totalRooms]); } }; @@ -1461,7 +1461,9 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout BOOL shoulReportStartupProgress = MXSDKOptions.sharedInstance.enableStartupProgress && !self.isEventStreamInitialised; if (shoulReportStartupProgress) { - [self.startupProgress incrementSyncAttempt]; + // There is no way to track percentage progress when syncing with the server, so we always use 0% + // and only care about the `.serverSyncing` stage + [self.startupProgress updateProgressForStage:MXSessionStartupStageServerSyncing progress:0]; } dispatch_group_t initialSyncDispatchGroup = dispatch_group_create(); @@ -1562,11 +1564,20 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout nextServerTimeout = 0; } + // A few local constants used to calculate overall progress for a number of different steps + // that occur during processing of sync response + NSInteger syncResponseStep = 0; + NSInteger roomSummariesStep = 1; + NSInteger processingStepsCount = 2; + [self handleSyncResponse:syncResponse progress:^(CGFloat progress) { if (shoulReportStartupProgress) { - [self.startupProgress updateProcessingProgress:progress forPhase:MXSessionProcessingResponsePhaseSyncResponse]; + double overallProgress = [self.startupProgress overallProgressForStep:syncResponseStep + totalCount:processingStepsCount + progress:progress]; + [self.startupProgress updateProgressForStage:MXSessionStartupStageProcessingResponse progress:overallProgress]; } } completion:^{ @@ -1581,7 +1592,10 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout progress:^(CGFloat progress) { if (shoulReportStartupProgress) { - [self.startupProgress updateProcessingProgress:progress forPhase:MXSessionProcessingResponsePhaseRoomSummaries]; + double overallProgress = [self.startupProgress overallProgressForStep:roomSummariesStep + totalCount:processingStepsCount + progress:progress]; + [self.startupProgress updateProgressForStage:MXSessionStartupStageProcessingResponse progress:overallProgress]; } } completion:^{ @@ -2158,7 +2172,7 @@ - (void)handleBackgroundSyncCacheIfRequiredWithCompletion:(void (^)(void))comple BOOL isInValidState = _state == MXSessionStateStoreDataReady || _state == MXSessionStatePaused; if (!isInValidState) { NSString *message = [NSString stringWithFormat:@"[MXSession] handleBackgroundSyncCacheIfRequired: state %@ is not valid to handle background sync cache, investigate why the method was called", [MXTools readableSessionState:_state]]; - MXLogFailure(message); + MXLogError(message); if (completion) { completion(); @@ -2286,11 +2300,6 @@ - (void)handleOutdatedSyncResponse:(MXSyncResponse *)syncResponse } } -- (CGFloat)startupProgressForCompleted:(NSInteger)completed total:(NSInteger)total -{ - return total > 0 ? (CGFloat)completed/(CGFloat)total : 0; -} - #pragma mark - Options - (void)enableVoIPWithCallStack:(id)callStack { @@ -3408,8 +3417,8 @@ - (void)fixRoomsSummariesLastMessageWithMaxServerPaginationCount:(NSUInteger)max dispatch_group_leave(dispatchGroup); if (MXSDKOptions.sharedInstance.enableStartupProgress && progress) { + progress([self.startupProgress overallProgressForStep:completedRooms totalCount:self.rooms.count progress:1]); completedRooms += 1; - progress([self startupProgressForCompleted:completedRooms total:self.rooms.count]); } }; @@ -4191,20 +4200,8 @@ - (MXHTTPOperation *)unIgnoreUsers:(NSArray *)userIds success:(void NSDictionary *data = @{ kMXAccountDataKeyIgnoredUser: ignoredUsersDict }; -// __weak __typeof(self)weakSelf = self; return [self setAccountData:data forType:kMXAccountDataTypeIgnoredUserList success:^{ - -// __strong __typeof(weakSelf)strongSelf = weakSelf; - - // Update self.ignoredUsers right now -// Commented as it created race condition with /sync response handling -// NSMutableArray *newIgnoredUsers = [NSMutableArray arrayWithArray:strongSelf->_ignoredUsers]; -// for (NSString *userId in userIds) -// { -// [newIgnoredUsers removeObject:userId]; -// } -// strongSelf->_ignoredUsers = newIgnoredUsers; - + if (success) { success(); diff --git a/MatrixSDK/MXSessionStartupProgress.swift b/MatrixSDK/MXSessionStartupProgress.swift index 19150beb43..06601b2ce8 100644 --- a/MatrixSDK/MXSessionStartupProgress.swift +++ b/MatrixSDK/MXSessionStartupProgress.swift @@ -19,74 +19,86 @@ import Foundation /// Different stages of starting up a session that may complete /// in non-trivial amount of time. These stages can be observed /// and used to update the user interface during session loading. -public enum MXSessionStartupStage { +@objc public enum MXSessionStartupStage: Int, CaseIterable { /// Migrating data to a new store version - case migratingData(progress: Double) + case storeMigration - /// Syncing with the server as Nth attempt - case serverSyncing(attempt: Int) + /// Syncing with the server + case serverSyncing /// Processing server response - case processingResponse(progress: Double) + case processingResponse } -/// Delegate that receives stage updates +/// Delegate that receives progress state updates public protocol MXSessionStartupProgressDelegate: AnyObject { - func sessionDidUpdateStartupStage(_ stage: MXSessionStartupStage) + func sessionDidUpdateStartupProgress(state: MXSessionStartupProgress.State) } -/// Distinct phases of the `processingResponse` stage that report -/// their own local progress separately and complete in a given order -@objc public enum MXSessionProcessingResponsePhase: Int, CaseIterable { - - /// Processing the response from the server - case syncResponse - - /// Updating room summaries - case roomSummaries -} - -/// `MXSessionStartupProgress` tracks individual stages and per-stage progress -/// during a session startup, where the application may be blocking user interactions. +/// `MXSessionStartupProgress` tracks progress for individual stages during a session startup, +/// where the application may be blocking user interactions. @objc public class MXSessionStartupProgress: NSObject { - private var syncAttempts = 0 - private var stage: MXSessionStartupStage? { - didSet { - if let state = stage { - delegate?.sessionDidUpdateStartupStage(state) - } - } + public struct State { + public let progress: Double + public let showDelayWarning: Bool } public weak var delegate: MXSessionStartupProgressDelegate? { didSet { - if let state = stage { - delegate?.sessionDidUpdateStartupStage(state) + if let state = state { + delegate?.sessionDidUpdateStartupProgress(state: state) } } } - /// Update the progress of the `migratingData` stage - @objc public func updateMigrationProgress(_ progress: Double) { - stage = .migratingData(progress: progress) + private var updatedStages = Set() + private var state: State? { + didSet { + if let state = state { + delegate?.sessionDidUpdateStartupProgress(state: state) + } + } } - /// Increment the total number of sync attempts during the `serverSyncing` stage - @objc public func incrementSyncAttempt() { - syncAttempts += 1 - stage = .serverSyncing(attempt: syncAttempts) + /// Update progress for a given stage as a number between 0.0-1.0 + /// + /// The update will inform a delegate with a new progress state containing the overall calculated + /// progress, depending on total number of startup stages. + @objc public func updateProgressForStage(_ stage: MXSessionStartupStage, progress: Double) { + switch stage { + case .storeMigration: + state = State( + // Migration contributes to half of the overall progress + progress: progress / 2, + showDelayWarning: false + ) + case .serverSyncing: + state = State( + // If we have previously migrated, we start at 0.5, otherwise at 0 + progress: updatedStages.contains(.storeMigration) ? 0.5 : 0, + // We display delay warning if this is second or higher sync attempt + showDelayWarning: updatedStages.contains(.serverSyncing) + ) + case .processingResponse: + state = State( + // If we have previously migrated, we start at 0.5, otherwise we take up the entire progress + progress: updatedStages.contains(.storeMigration) ? 0.5 + progress / 2 : progress, + showDelayWarning: false + ) + } + + updatedStages.insert(stage) } - /// Update the local progress of a specific phase within `processingResponse` - /// - /// The overal progress will be computed and reported automatically - @objc public func updateProcessingProgress(_ progress: Double, forPhase phase: MXSessionProcessingResponsePhase) { - let totalPhases = Double(MXSessionProcessingResponsePhase.allCases.count) - let currentPhaseProgress = progress / totalPhases - let previousPhasesProgress = Double(phase.rawValue) / totalPhases - let totalProgress = previousPhasesProgress + currentPhaseProgress + /// Calculate the overall progress for a given step out of total steps + @objc public func overallProgressForStep(_ currentStep: Int, totalCount: Int, progress: Double) -> Double { + guard totalCount > 0 else { + return 0 + } - stage = .processingResponse(progress: totalProgress) + let currentStepProgress = progress / Double(totalCount) + let previousStepProgress = Double(currentStep) / Double(totalCount) + return previousStepProgress + currentStepProgress } } diff --git a/MatrixSDK/MatrixSDK.h b/MatrixSDK/MatrixSDK.h index 799b21c13b..71f342706f 100644 --- a/MatrixSDK/MatrixSDK.h +++ b/MatrixSDK/MatrixSDK.h @@ -177,6 +177,7 @@ FOUNDATION_EXPORT NSString *MatrixSDKVersion; #import "MXCryptoTools.h" #import "MXRecoveryKey.h" #import "MXSecretShareSend.h" +#import "MXUsersTrustLevelSummary.h" // Sync response models #import "MXSyncResponse.h" diff --git a/MatrixSDK/MatrixSDKVersion.m b/MatrixSDK/MatrixSDKVersion.m index e4e64876ee..66223f4ac9 100644 --- a/MatrixSDK/MatrixSDKVersion.m +++ b/MatrixSDK/MatrixSDKVersion.m @@ -16,4 +16,4 @@ #import -NSString *const MatrixSDKVersion = @"0.26.1"; +NSString *const MatrixSDKVersion = @"0.26.2"; diff --git a/MatrixSDK/Utils/MXBugReportRestClient.m b/MatrixSDK/Utils/MXBugReportRestClient.m index 7e09f9c0a3..022df50f61 100644 --- a/MatrixSDK/Utils/MXBugReportRestClient.m +++ b/MatrixSDK/Utils/MXBugReportRestClient.m @@ -21,6 +21,7 @@ #import #import +#import "MatrixSDKSwiftHeader.h" #if TARGET_OS_IPHONE #import @@ -207,7 +208,16 @@ -(void)sendBugReport:(NSString *)text sendFiles:(NSArray*)files attachGi [formData appendPartWithFormData:[MatrixSDKVersion dataUsingEncoding:NSUTF8StringEncoding] name:@"matrix_sdk_version"]; #ifdef MX_CRYPTO - [formData appendPartWithFormData:[[OLMKit versionString] dataUsingEncoding:NSUTF8StringEncoding] name:@"olm_kit_version"]; + [formData appendPartWithFormData:[MXSDKOptions.sharedInstance.cryptoModuleId dataUsingEncoding:NSUTF8StringEncoding] name:@"crypto_module"]; + if (MXSDKOptions.sharedInstance.enableCryptoSDK) + { + + [formData appendPartWithFormData:[MXSDKOptions.sharedInstance.cryptoSDKFeature.version dataUsingEncoding:NSUTF8StringEncoding] name:@"matrix_sdk_crypto_version"]; + } + else + { + [formData appendPartWithFormData:[[OLMKit versionString] dataUsingEncoding:NSUTF8StringEncoding] name:@"olm_kit_version"]; + } #endif if (self.deviceModel) diff --git a/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m b/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m index e4cfb2516c..84ea69a403 100644 --- a/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m +++ b/MatrixSDK/VoIP/CallKit/MXCallKitAdapter.m @@ -52,7 +52,7 @@ - (instancetype)initWithConfiguration:(MXCallKitConfiguration *)configuration { CXProviderConfiguration *providerConfiguration = [[CXProviderConfiguration alloc] initWithLocalizedName:configuration.name]; providerConfiguration.ringtoneSound = configuration.ringtoneName; - providerConfiguration.maximumCallGroups = 1; + providerConfiguration.maximumCallGroups = configuration.maximumCallGroups; providerConfiguration.maximumCallsPerCallGroup = 1; providerConfiguration.supportedHandleTypes = [NSSet setWithObject:@(CXHandleTypeGeneric)]; providerConfiguration.supportsVideo = configuration.supportsVideo; diff --git a/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.h b/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.h index 02aa7bc837..283a58ed43 100644 --- a/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.h +++ b/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.h @@ -51,6 +51,13 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic) BOOL supportsVideo; +/** + The maximum number of call groups. + + Defaults is 1. + */ +@property (nonatomic) NSUInteger maximumCallGroups; + - (instancetype)initWithName:(NSString *)name ringtoneName:(nullable NSString *)ringtoneName diff --git a/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.m b/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.m index e059c49481..3ae92673f2 100644 --- a/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.m +++ b/MatrixSDK/VoIP/CallKit/MXCallKitConfiguration.m @@ -38,6 +38,7 @@ - (instancetype)initWithName:(NSString *)name _ringtoneName = [ringtoneName copy]; _iconName = [iconName copy]; _supportsVideo = supportsVideo; + _maximumCallGroups = 1; } return self; diff --git a/MatrixSDK/VoIP/MXCallManager.m b/MatrixSDK/VoIP/MXCallManager.m index 9430dcb1b2..cea1111f83 100644 --- a/MatrixSDK/VoIP/MXCallManager.m +++ b/MatrixSDK/VoIP/MXCallManager.m @@ -882,36 +882,37 @@ - (void)transferCall:(MXCall *)callWithTransferee // generate a new call id NSString *newCallId = [[NSUUID UUID] UUIDString]; - dispatch_group_t dispatchGroupReplaces = dispatch_group_create(); + dispatch_group_t dispatchGroup = dispatch_group_create(); + dispatch_group_enter(dispatchGroup); if (callWithTarget) { // send replaces event to target - dispatch_group_enter(dispatchGroupReplaces); [callWithTarget transferToRoom:nil user:transferee createCall:nil awaitCall:newCallId success:^(NSString * _Nonnull eventId) { - dispatch_group_leave(dispatchGroupReplaces); + dispatch_group_leave(dispatchGroup); } failure:failure]; } + else + { + dispatch_group_leave(dispatchGroup); + } - dispatch_group_enter(dispatchGroupReplaces); - // send replaces event to transferee - [callWithTransferee transferToRoom:nil - user:target - createCall:newCallId - awaitCall:nil - success:^(NSString * _Nonnull eventId) { - dispatch_group_leave(dispatchGroupReplaces); - } failure:failure]; - - dispatch_group_notify(dispatchGroupReplaces, dispatch_get_main_queue(), ^{ - if (success) - { - success(newCallId); - } + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + // send replaces event to transferee + [callWithTransferee transferToRoom:nil + user:target + createCall:newCallId + awaitCall:nil + success:^(NSString * _Nonnull eventId) { + if (success) + { + success(newCallId); + } + } failure:failure]; }); } } @@ -947,49 +948,50 @@ - (void)transferCall:(MXCall *)callWithTransferee // generate a new call id NSString *newCallId = [[NSUUID UUID] UUIDString]; - dispatch_group_t dispatchGroupReplaces = dispatch_group_create(); - + dispatch_group_t dispatchGroup = dispatch_group_create(); + dispatch_group_enter(dispatchGroup); + if (callWithTarget) { [callWithTarget hangup]; // send replaces event to target - dispatch_group_enter(dispatchGroupReplaces); [callWithTarget transferToRoom:transferRoom.roomId user:transferee createCall:nil awaitCall:newCallId success:^(NSString * _Nonnull eventId) { - dispatch_group_leave(dispatchGroupReplaces); + dispatch_group_leave(dispatchGroup); } failure:failure]; } - - dispatch_group_enter(dispatchGroupReplaces); - if (callWithTransferee.isOnHold) + else { - [callWithTransferee hold:NO]; + dispatch_group_leave(dispatchGroup); } - // send replaces event to transferee - [callWithTransferee transferToRoom:transferRoom.roomId - user:target - createCall:newCallId - awaitCall:nil - success:^(NSString * _Nonnull eventId) { - dispatch_group_leave(dispatchGroupReplaces); - } failure:failure]; - dispatch_group_notify(dispatchGroupReplaces, dispatch_get_main_queue(), ^{ - if (isNewRoom) - { - // if was a newly created room, send invites after replaces events - [transferRoom inviteUser:target.userId success:nil failure:failure]; - [transferRoom inviteUser:transferee.userId success:nil failure:failure]; - } - - if (success) + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + if (callWithTransferee.isOnHold) { - success(newCallId); + [callWithTransferee hold:NO]; } + // send replaces event to transferee + [callWithTransferee transferToRoom:transferRoom.roomId + user:target + createCall:newCallId + awaitCall:nil + success:^(NSString * _Nonnull eventId) { + if (isNewRoom) + { + // if was a newly created room, send invites after replaces events + [transferRoom inviteUser:target.userId success:nil failure:failure]; + [transferRoom inviteUser:transferee.userId success:nil failure:failure]; + } + + if (success) + { + success(newCallId); + } + } failure:failure]; }); } diff --git a/MatrixSDKTests/Crypto/Algorithms/RoomEvents/MXRoomEventEncryptionUnitTests.swift b/MatrixSDKTests/Crypto/Algorithms/RoomEvents/MXRoomEventEncryptionUnitTests.swift index e7c1e1adae..8dc292a901 100644 --- a/MatrixSDKTests/Crypto/Algorithms/RoomEvents/MXRoomEventEncryptionUnitTests.swift +++ b/MatrixSDKTests/Crypto/Algorithms/RoomEvents/MXRoomEventEncryptionUnitTests.swift @@ -82,15 +82,36 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { } class EncryptorStub: CryptoIdentityStub, MXCryptoRoomEventEncrypting { + var onlyAllowTrustedDevices: Bool = false + var trackedUsers: Set = [] func isUserTracked(userId: String) -> Bool { return trackedUsers.contains(userId) } - func addTrackedUsers(_ users: [String]) { + func updateTrackedUsers(_ users: [String]) { trackedUsers = trackedUsers.union(users) } + var stubbedRoomSettings: [String: RoomSettings] = [:] + func roomSettings(roomId: String) -> RoomSettings? { + return stubbedRoomSettings[roomId] + } + + func setRoomAlgorithm(roomId: String, algorithm: EventEncryptionAlgorithm) throws { + stubbedRoomSettings[roomId] = .init( + algorithm: algorithm, + onlyAllowTrustedDevices: stubbedRoomSettings[roomId]?.onlyAllowTrustedDevices ?? false + ) + } + + func setOnlyAllowTrustedDevices(for roomId: String, onlyAllowTrustedDevices: Bool) throws { + stubbedRoomSettings[roomId] = .init( + algorithm: stubbedRoomSettings[roomId]?.algorithm ?? .megolmV1AesSha2, + onlyAllowTrustedDevices: onlyAllowTrustedDevices + ) + } + var sharedUsers = [String]() var sharedSettings: EncryptionSettings? func shareRoomKeysIfNecessary(roomId: String, users: [String], settings: EncryptionSettings) async throws { @@ -110,7 +131,6 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { } var handler: EncryptorStub! - var store: MXMemoryCryptoStore! var encryptor: MXRoomEventEncryption! var roomId = "ABC" var room: RoomStub! @@ -119,7 +139,6 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { override func setUp() { handler = EncryptorStub() - store = MXMemoryCryptoStore(credentials: MXCredentials()) room = .init(roomId: roomId, andMatrixSession: nil) state = .init(roomId: roomId, andMatrixSession: nil, andDirection: true) members = .init() @@ -129,7 +148,6 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { encryptor = MXRoomEventEncryption( handler: handler, - legacyStore: store, getRoomAction: { id in id == self.room.roomId ? self.room : nil } @@ -140,7 +158,12 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { func test_isRoomEncrypted() { XCTAssertFalse(encryptor.isRoomEncrypted(roomId: roomId)) - store.storeAlgorithm(forRoom: roomId, algorithm: "megolm") + + handler.stubbedRoomSettings[roomId] = .init( + algorithm: .megolmV1AesSha2, + onlyAllowTrustedDevices: false + ) + XCTAssertTrue(encryptor.isRoomEncrypted(roomId: roomId)) } @@ -162,7 +185,7 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { } func test_ensureRoomKeysShared_correctEncryptionAlgorithm() async throws { - XCTAssertNil(store.algorithm(forRoom: roomId)) + XCTAssertNil(handler.roomSettings(roomId: roomId)) // No algorithm -> throws + nothing stored state.stubbedAlgorithm = nil @@ -170,7 +193,7 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { try await encryptor.ensureRoomKeysShared(roomId: roomId) XCTFail("Should not succeed") } catch { - XCTAssertNil(store.algorithm(forRoom: roomId)) + XCTAssertNil(handler.roomSettings(roomId: roomId)) } // Invalid algorithm -> throws + nothing stored @@ -179,27 +202,23 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { try await encryptor.ensureRoomKeysShared(roomId: roomId) XCTFail("Should not succeed") } catch { - XCTAssertNil(store.algorithm(forRoom: roomId)) + XCTAssertNil(handler.roomSettings(roomId: roomId)) } // Valid -> algorithm stored state.stubbedAlgorithm = kMXCryptoMegolmAlgorithm try await encryptor.ensureRoomKeysShared(roomId: roomId) - XCTAssertEqual(store.algorithm(forRoom: roomId), kMXCryptoMegolmAlgorithm) + XCTAssertEqual(handler.roomSettings(roomId: roomId)?.algorithm, .megolmV1AesSha2) - // Another invalid algorithm -> throws + previous algorithm stored + // Another invalid algorithm -> previous algorithm kept without throwing state.stubbedAlgorithm = "blabla" - do { - try await encryptor.ensureRoomKeysShared(roomId: roomId) - XCTFail("Should not succeed") - } catch { - XCTAssertEqual(store.algorithm(forRoom: roomId), kMXCryptoMegolmAlgorithm) - } + try await encryptor.ensureRoomKeysShared(roomId: roomId) + XCTAssertEqual(handler.roomSettings(roomId: roomId)?.algorithm, .megolmV1AesSha2) // Another valid -> succeeds - state.stubbedAlgorithm = kMXCryptoMegolmAlgorithm + state.stubbedAlgorithm = kMXCryptoOlmAlgorithm try await encryptor.ensureRoomKeysShared(roomId: roomId) - XCTAssertEqual(store.algorithm(forRoom: roomId), kMXCryptoMegolmAlgorithm) + XCTAssertEqual(handler.roomSettings(roomId: roomId)?.algorithm, .olmV1Curve25519AesSha2) } func test_ensureRoomKeysShared_correctSettings() async throws { @@ -236,8 +255,11 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { ] for ((global, perRoom), settings) in storeToSettings { - store.globalBlacklistUnverifiedDevices = global - store.storeBlacklistUnverifiedDevices(inRoom: roomId, blacklist: perRoom) + handler.onlyAllowTrustedDevices = global + handler.stubbedRoomSettings[roomId] = .init( + algorithm: .megolmV1AesSha2, + onlyAllowTrustedDevices: perRoom + ) try await encryptor.ensureRoomKeysShared(roomId: roomId) @@ -254,9 +276,24 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { members.eligibleUsers = ["Alice", "Carol"] try await encryptor.ensureRoomKeysShared(roomId: roomId) + XCTAssertEqual(handler.sharedUsers, ["Alice", "Carol"]) } + func test_ensureRoomKeysShared_tracksMissingUsers() async throws { + members.stubbedMembers = [ + .init(userId: "Alice"), + .init(userId: "Bob"), + .init(userId: "Carol"), + ] + members.eligibleUsers = ["Alice", "Bob", "Carol"] + handler.trackedUsers = ["Alice"] + + try await encryptor.ensureRoomKeysShared(roomId: roomId) + + XCTAssertEqual(handler.trackedUsers, ["Alice", "Bob", "Carol"]) + } + // MARK: - Encrypt func test_encrypt_ensuresEncryptionAndKeys() async throws { @@ -269,7 +306,7 @@ class MXRoomEventEncryptionUnitTests: XCTestCase { ) XCTAssertNotNil(handler.sharedSettings) - XCTAssertEqual(store.algorithm(forRoom: roomId), kMXCryptoMegolmAlgorithm) + XCTAssertEqual(handler.roomSettings(roomId: roomId)?.algorithm, .megolmV1AesSha2) } func test_encrypt_returnsEncryptedContent() async throws { diff --git a/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift index 9de46d0e37..a91f5411b6 100644 --- a/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift +++ b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift @@ -51,10 +51,7 @@ class MXCrossSigningInfoUnitTests: XCTestCase { XCTAssertKeysEqual(info.masterKeys, masterKeys) XCTAssertKeysEqual(info.selfSignedKeys, selfSigningKeys) XCTAssertKeysEqual(info.userSignedKeys, userSigningKeys) - XCTAssertEqual( - info.trustLevel, - MXUserTrustLevel(crossSigningVerified: false, locallyVerified: false) - ) + XCTAssertFalse(info.isVerified) } func test_canCreateInfo_withOtherUserIdentity() { @@ -77,10 +74,82 @@ class MXCrossSigningInfoUnitTests: XCTestCase { XCTAssertKeysEqual(info.masterKeys, masterKeys) XCTAssertKeysEqual(info.selfSignedKeys, selfSigningKeys) XCTAssertNil(info.userSignedKeys) - XCTAssertEqual( - info.trustLevel, - MXUserTrustLevel(crossSigningVerified: true, locallyVerified: true) - ) + XCTAssertTrue(info.isVerified) + } + + func test_canDecodeDeprecatedModel() throws { + // In this test we ensure that we can decode a list of `MXCrossSigningInfo` which were created + // using a previous version of the model (and saved into a file). This model contained separate + // fields for local vs cross-signing verification, whereas the new model flattens these into + // a single `isVerified` boolean. + + // Load up previously saved data using version 0 of the model + let bundle = Bundle(for: MXCrossSigningInfoUnitTests.self) + guard let url = bundle.url(forResource: "MXCrossSigningInfo_v0", withExtension: nil) else { + XCTFail("Missing migration data") + return + } + let data = try Data(contentsOf: url) + + // Unarchive using current model + guard let unarchived = NSKeyedUnarchiver.unarchiveObject(with: data) as? [MXCrossSigningInfo] else { + XCTFail("Failed to unarchive data") + return + } + + // This data should contain 4 cross signing info objects + XCTAssertEqual(unarchived.count, 4) + + // Alice had both crossSigningVerified and locallyVerified set to false => is not verified + XCTAssertEqual(unarchived[0].userId, "Alice") + XCTAssertFalse(unarchived[0].isVerified) + + // Bob had crossSigningVerified set to true and locallyVerified set to false => is verified + XCTAssertEqual(unarchived[1].userId, "Bob") + XCTAssertTrue(unarchived[1].isVerified) + + // Carol had crossSigningVerified set to false and locallyVerified set to true => is not verified + XCTAssertEqual(unarchived[2].userId, "Carol") + XCTAssertFalse(unarchived[2].isVerified) + + // Alice had both crossSigningVerified and locallyVerified set to true => is verified + XCTAssertEqual(unarchived[3].userId, "Dave") + XCTAssertTrue(unarchived[3].isVerified) + } + + func test_canEncodeDeprecatedModel() throws { + // In this test we ensure that once unarchived a deprecated model, we can archive it using the current + // schema, ie storing the `isVerified` property directly, which is asserted by unarchiving once again. + + // Load up previously saved data using version 0 of the model + let bundle = Bundle(for: MXCrossSigningInfoUnitTests.self) + guard let url = bundle.url(forResource: "MXCrossSigningInfo_v0", withExtension: nil) else { + XCTFail("Missing migration data") + return + } + + // Unarchive from deprecated to current, re-archive via current model, and then once again unarchive + let data = try Data(contentsOf: url) + guard let unarchived1 = NSKeyedUnarchiver.unarchiveObject(with: data) as? [MXCrossSigningInfo] else { + XCTFail("Failed to unarchive data") + return + } + let archived = NSKeyedArchiver.archivedData(withRootObject: unarchived1) + guard let unarchived2 = NSKeyedUnarchiver.unarchiveObject(with: archived) as? [MXCrossSigningInfo] else { + XCTFail("Failed to unarchive data") + return + } + + // We expect all of the values to match the original data + XCTAssertEqual(unarchived2.count, 4) + XCTAssertEqual(unarchived2[0].userId, "Alice") + XCTAssertFalse(unarchived2[0].isVerified) + XCTAssertEqual(unarchived2[1].userId, "Bob") + XCTAssertTrue(unarchived2[1].isVerified) + XCTAssertEqual(unarchived2[2].userId, "Carol") + XCTAssertFalse(unarchived2[2].isVerified) + XCTAssertEqual(unarchived2[3].userId, "Dave") + XCTAssertTrue(unarchived2[3].isVerified) } private func XCTAssertKeysEqual(_ key1: MXCrossSigningKey?, _ key2: MXCrossSigningKey?, file: StaticString = #file, line: UInt = #line) { diff --git a/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfo_v0 b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfo_v0 new file mode 100644 index 0000000000..d9aeae663b Binary files /dev/null and b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfo_v0 differ diff --git a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift index 4ed6168f50..fdf9503adf 100644 --- a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift +++ b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift @@ -50,6 +50,6 @@ class MXCrossSigningInfoSourceUnitTests: XCTestCase { let info = source.crossSigningInfo(userId: "Alice") XCTAssertEqual(info?.userId, "Alice") - XCTAssertEqual(info?.trustLevel.isVerified, true) + XCTAssertEqual(info?.isVerified, true) } } diff --git a/MatrixSDKTests/Crypto/CryptoMachine/Extensions/EventEncryptionAlgorithmUnitTests.swift b/MatrixSDKTests/Crypto/CryptoMachine/Extensions/EventEncryptionAlgorithmUnitTests.swift new file mode 100644 index 0000000000..8bcae0ddf4 --- /dev/null +++ b/MatrixSDKTests/Crypto/CryptoMachine/Extensions/EventEncryptionAlgorithmUnitTests.swift @@ -0,0 +1,52 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// 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 XCTest +import MatrixSDKCrypto +@testable import MatrixSDK + +class EventEncryptionAlgorithmUnitTests: XCTestCase { + func test_nil() { + do { + _ = try EventEncryptionAlgorithm(string: nil) + } catch EventEncryptionAlgorithm.Error.cannotResetEncryption { + XCTAssertTrue(true) + } catch { + XCTFail("Unexpected error - \(error)") + } + } + + func test_invalidString() { + do { + _ = try EventEncryptionAlgorithm(string: "Blabla") + } catch EventEncryptionAlgorithm.Error.invalidAlgorithm { + XCTAssertTrue(true) + } catch { + XCTFail("Unexpected error - \(error)") + } + } + + func test_olm() throws { + let algorithm = try EventEncryptionAlgorithm(string: "m.olm.v1.curve25519-aes-sha2") + XCTAssertEqual(algorithm, .olmV1Curve25519AesSha2) + } + + func test_megolm() throws { + let algorithm = try EventEncryptionAlgorithm(string: "m.megolm.v1.aes-sha2") + XCTAssertEqual(algorithm, .megolmV1AesSha2) + } +} diff --git a/MatrixSDKTests/Crypto/Data/Store/MXMemoryCryptoStore.swift b/MatrixSDKTests/Crypto/Data/Store/MXMemoryCryptoStore.swift index 50a67eef6b..2b1c240c56 100644 --- a/MatrixSDKTests/Crypto/Data/Store/MXMemoryCryptoStore.swift +++ b/MatrixSDKTests/Crypto/Data/Store/MXMemoryCryptoStore.swift @@ -183,6 +183,23 @@ public class MXMemoryCryptoStore: NSObject, MXCryptoStore { public func algorithm(forRoom roomId: String!) -> String! { algorithms[roomId]?.algorithm } + + // MARK: - Room Settings + + public func roomSettings() -> [MXRoomSettings]! { + return algorithms.compactMap { roomId, item in + do { + return try MXRoomSettings( + roomId: roomId, + algorithm: item.algorithm, + blacklistUnverifiedDevices: item.blacklistUnverifiedDevices + ) + } catch { + MXLog.debug("[MXMemoryCryptoStore] roomSettings: Failed creating algorithm", context: error) + return nil + } + } + } // MARK: - OLM Session diff --git a/MatrixSDKTests/Crypto/MXCryptoV2FactoryTests.swift b/MatrixSDKTests/Crypto/MXCryptoV2FactoryTests.swift index fb5057ff58..f6b074894f 100644 --- a/MatrixSDKTests/Crypto/MXCryptoV2FactoryTests.swift +++ b/MatrixSDKTests/Crypto/MXCryptoV2FactoryTests.swift @@ -72,20 +72,19 @@ class MXCryptoV2FactoryTests: XCTestCase { XCTAssertNotNil(crypto) XCTAssertFalse(hasMigrated) - // Assert we have created legacy store (for remaining functionality) and marked it as deprecated + // Assert that we have not created any legacy store for this user let legacyStore = MXRealmCryptoStore.init(credentials: session.credentials) - XCTAssertNotNil(legacyStore) - XCTAssertEqual(legacyStore?.cryptoVersion, .versionLegacyDeprecated) + XCTAssertNil(legacyStore) await env.close() } - func test_migratesExistingUser() async throws { + func test_fullyMigratesLegacyUser() async throws { let env = try await e2eData.startE2ETest() let session = env.session - let legacyStore = session.legacyCrypto?.store + var legacyStore = session.legacyCrypto?.store - // Assert that we have a legacy store that has not yet been depreacted + // Assert that we have a legacy store that has not yet been deprecated XCTAssertNotNil(legacyStore) XCTAssertEqual(legacyStore?.cryptoVersion, .version2) @@ -94,9 +93,30 @@ class MXCryptoV2FactoryTests: XCTestCase { XCTAssertNotNil(crypto) XCTAssertTrue(hasMigrated) - // Assert we still have legacy store but it is now marked as deprecated + // Assert that we no longer have a legacy store for this user + legacyStore = MXRealmCryptoStore.init(credentials: session.credentials) + XCTAssertNil(legacyStore) + + await env.close() + } + + func test_migratesPartiallyMigratedUser() async throws { + let env = try await e2eData.startE2ETest() + let session = env.session + + // We set the legacy store as partially deprecated + var legacyStore = session.legacyCrypto?.store XCTAssertNotNil(legacyStore) - XCTAssertEqual(legacyStore?.cryptoVersion, .versionLegacyDeprecated) + legacyStore?.cryptoVersion = .deprecated1 + + // Build crypto and assert migration has been performed + let (crypto, hasMigrated) = try await buildCrypto(session: session) + XCTAssertNotNil(crypto) + XCTAssertTrue(hasMigrated) + + // Assert that we no longer have a legacy store for this user + legacyStore = MXRealmCryptoStore.init(credentials: session.credentials) + XCTAssertNil(legacyStore) await env.close() } @@ -105,19 +125,19 @@ class MXCryptoV2FactoryTests: XCTestCase { let env = try await e2eData.startE2ETest() let session = env.session - // We set the legacy store as deprecated - let legacyStore = session.legacyCrypto?.store + // We set the legacy store as fully deprecated + var legacyStore = session.legacyCrypto?.store XCTAssertNotNil(legacyStore) - legacyStore?.cryptoVersion = .versionLegacyDeprecated + legacyStore?.cryptoVersion = .deprecated2 // Build crypto and assert no migration has been performed let (crypto, hasMigrated) = try await buildCrypto(session: session) XCTAssertNotNil(crypto) XCTAssertFalse(hasMigrated) - // Assert we still have legacy store which is still marked as deprecated - XCTAssertNotNil(legacyStore) - XCTAssertEqual(legacyStore?.cryptoVersion, .versionLegacyDeprecated) + // Assert that we no longer have a legacy store for this user + legacyStore = MXRealmCryptoStore.init(credentials: session.credentials) + XCTAssertNil(legacyStore) await env.close() } diff --git a/MatrixSDKTests/Crypto/Migration/Data/MXCryptoMigrationStoreUnitTests.swift b/MatrixSDKTests/Crypto/Migration/Data/MXCryptoMigrationStoreUnitTests.swift index 181a9ca004..1197fc26ff 100644 --- a/MatrixSDKTests/Crypto/Migration/Data/MXCryptoMigrationStoreUnitTests.swift +++ b/MatrixSDKTests/Crypto/Migration/Data/MXCryptoMigrationStoreUnitTests.swift @@ -89,6 +89,19 @@ class MXCryptoMigrationStoreUnitTests: XCTestCase { // MARK: - Tests + func test_credentials() { + XCTAssertEqual(store.userId, "Alice") + XCTAssertEqual(store.deviceId, "ABC") + } + + func test_trustedSettings() { + legacyStore.globalBlacklistUnverifiedDevices = false + XCTAssertFalse(store.globalSettings.onlyAllowTrustedDevices) + + legacyStore.globalBlacklistUnverifiedDevices = true + XCTAssertTrue(store.globalSettings.onlyAllowTrustedDevices) + } + func test_missingAccountFailsExtraction() { legacyStore.setAccount(nil) do { @@ -250,4 +263,22 @@ class MXCryptoMigrationStoreUnitTests: XCTestCase { XCTAssertEqual(Set(trackedUsers), ["Bob", "Carol", "Dave"]) } + + func test_extractsRoomSettings() throws { + legacyStore.storeAlgorithm(forRoom: "room1", algorithm: kMXCryptoOlmAlgorithm) + legacyStore.storeBlacklistUnverifiedDevices(inRoom: "room1", blacklist: true) + + legacyStore.storeAlgorithm(forRoom: "room2", algorithm: kMXCryptoMegolmAlgorithm) + legacyStore.storeBlacklistUnverifiedDevices(inRoom: "room2", blacklist: false) + + legacyStore.storeAlgorithm(forRoom: "room3", algorithm: "something invalid") + legacyStore.storeBlacklistUnverifiedDevices(inRoom: "room3", blacklist: true) + + let settings = try extractData().roomSettings + + XCTAssertEqual(settings, [ + "room1": RoomSettings(algorithm: .olmV1Curve25519AesSha2, onlyAllowTrustedDevices: true), + "room2": RoomSettings(algorithm: .megolmV1AesSha2, onlyAllowTrustedDevices: false), + ]) + } } diff --git a/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2Tests.swift b/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2Tests.swift index e20e41541a..39793b0718 100644 --- a/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2Tests.swift +++ b/MatrixSDKTests/Crypto/Migration/MXCryptoMigrationV2Tests.swift @@ -47,7 +47,7 @@ class MXCryptoMigrationV2Tests: XCTestCase { // MARK: - Helpers - private func migratedOlmMachine(session: MXSession) throws -> MXCryptoMachine { + private func fullyMigratedOlmMachine(session: MXSession) throws -> MXCryptoMachine { guard let store = session.legacyCrypto?.store, let restClient = session.matrixRestClient @@ -57,7 +57,29 @@ class MXCryptoMigrationV2Tests: XCTestCase { MXKeyProvider.sharedInstance().delegate = KeyProvider() let migration = MXCryptoMigrationV2(legacyStore: store) - try migration.migrateCrypto { _ in } + try migration.migrateAllData { _ in } + let machine = try MXCryptoMachine( + userId: store.userId(), + deviceId: store.deviceId(), + restClient: restClient, + getRoomAction: { _ in + return nil + }) + MXKeyProvider.sharedInstance().delegate = nil + return machine + } + + private func partiallyMigratedOlmMachine(session: MXSession) throws -> MXCryptoMachine { + guard + let store = session.legacyCrypto?.store, + let restClient = session.matrixRestClient + else { + throw Error.missingDependencies + } + + MXKeyProvider.sharedInstance().delegate = KeyProvider() + let migration = MXCryptoMigrationV2(legacyStore: store) + try migration.migrateRoomAndGlobalSettingsOnly { _ in } let machine = try MXCryptoMachine( userId: store.userId(), deviceId: store.deviceId(), @@ -75,7 +97,7 @@ class MXCryptoMigrationV2Tests: XCTestCase { let env = try await e2eData.startE2ETest() let legacySession = env.session - let machine = try self.migratedOlmMachine(session: env.session) + let machine = try self.fullyMigratedOlmMachine(session: env.session) XCTAssertEqual(machine.userId, legacySession.myUserId) XCTAssertEqual(machine.deviceId, legacySession.myDeviceId) @@ -102,7 +124,7 @@ class MXCryptoMigrationV2Tests: XCTestCase { XCTAssertNotNil(event.content["ciphertext"]) // Migrate the session to crypto v2 - let machine = try self.migratedOlmMachine(session: env.session) + let machine = try self.fullyMigratedOlmMachine(session: env.session) // Decrypt the event using crypto v2 let decrypted = try machine.decryptRoomEvent(event) @@ -125,7 +147,7 @@ class MXCryptoMigrationV2Tests: XCTestCase { XCTAssertFalse(legacyCrossSigning.hasAllPrivateKeys) // We then migrate the user into crypto v2 - let machine = try migratedOlmMachine(session: env.session) + let machine = try fullyMigratedOlmMachine(session: env.session) let crossSigningV2 = MXCrossSigningV2(crossSigning: machine, restClient: env.session.matrixRestClient) try await crossSigningV2.refreshState() @@ -146,7 +168,7 @@ class MXCryptoMigrationV2Tests: XCTestCase { XCTAssertTrue(legacyCrossSigning.hasAllPrivateKeys) // We now migrate the data into crypto v2 - let machine = try migratedOlmMachine(session: env.session) + let machine = try fullyMigratedOlmMachine(session: env.session) let crossSigningV2 = MXCrossSigningV2(crossSigning: machine, restClient: env.session.matrixRestClient) try await crossSigningV2.refreshState() @@ -156,6 +178,74 @@ class MXCryptoMigrationV2Tests: XCTestCase { await env.close() } + + func test_migratesRoomSettings() async throws { + let env = try await e2eData.startE2ETest() + + // We start with user and encrypted room with some settings + let legacyCrypto = env.session.crypto! + try await legacyCrypto.ensureEncryption(roomId: env.roomId) + legacyCrypto.setBlacklistUnverifiedDevicesInRoom(env.roomId, blacklist: true) + XCTAssertTrue(legacyCrypto.isRoomEncrypted(env.roomId)) + XCTAssertTrue(legacyCrypto.isBlacklistUnverifiedDevices(inRoom: env.roomId)) + + // We now migrate the data into crypto v2 + let machine = try fullyMigratedOlmMachine(session: env.session) + + // And confirm that room settings have been migrated + let settings = machine.roomSettings(roomId: env.roomId) + XCTAssertEqual(settings, .init(algorithm: .megolmV1AesSha2, onlyAllowTrustedDevices: true)) + + await env.close() + } + + func test_migratesRoomSettingsInPartialMigration() async throws { + let env = try await e2eData.startE2ETest() + + // We start with user and encrypted room with some settings + let legacyCrypto = env.session.crypto! + try await legacyCrypto.ensureEncryption(roomId: env.roomId) + legacyCrypto.setBlacklistUnverifiedDevicesInRoom(env.roomId, blacklist: true) + XCTAssertTrue(legacyCrypto.isRoomEncrypted(env.roomId)) + XCTAssertTrue(legacyCrypto.isBlacklistUnverifiedDevices(inRoom: env.roomId)) + + // We now migrate the data into crypto v2 + let machine = try partiallyMigratedOlmMachine(session: env.session) + + // And confirm that room settings have been migrated + let settings = machine.roomSettings(roomId: env.roomId) + XCTAssertEqual(settings, .init(algorithm: .megolmV1AesSha2, onlyAllowTrustedDevices: true)) + + await env.close() + } + + func test_migratesGlobalSettings() async throws { + let env1 = try await e2eData.startE2ETest() + env1.session.crypto.globalBlacklistUnverifiedDevices = true + let machine1 = try fullyMigratedOlmMachine(session: env1.session) + XCTAssertTrue(machine1.onlyAllowTrustedDevices) + await env1.close() + + let env2 = try await e2eData.startE2ETest() + env2.session.crypto.globalBlacklistUnverifiedDevices = false + let machine2 = try fullyMigratedOlmMachine(session: env2.session) + XCTAssertFalse(machine2.onlyAllowTrustedDevices) + await env2.close() + } + + func test_test_migratesGlobalSettingsInPartialMigration() async throws { + let env1 = try await e2eData.startE2ETest() + env1.session.crypto.globalBlacklistUnverifiedDevices = true + let machine1 = try partiallyMigratedOlmMachine(session: env1.session) + XCTAssertTrue(machine1.onlyAllowTrustedDevices) + await env1.close() + + let env2 = try await e2eData.startE2ETest() + env2.session.crypto.globalBlacklistUnverifiedDevices = false + let machine2 = try partiallyMigratedOlmMachine(session: env2.session) + XCTAssertFalse(machine2.onlyAllowTrustedDevices) + await env2.close() + } } private extension MXCrypto { @@ -166,6 +256,14 @@ private extension MXCrypto { } } } + + func ensureEncryption(roomId: String) async throws { + return try await withCheckedThrowingContinuation { continuation in + ensureEncryption(inRoom: roomId) { + continuation.resume() + } + } + } } private extension MXCrossSigning { diff --git a/MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift b/MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift index dc53091a9f..2053a4962f 100644 --- a/MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift +++ b/MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift @@ -30,14 +30,14 @@ class MXTrustLevelSourceUnitTests: XCTestCase { source = MXTrustLevelSource(userIdentitySource: userIdentitySource, devicesSource: devicesSource) } - func test_userTrustLevel() { + func test_isUserVerified() { userIdentitySource.verification = [ - "Alice": true + "Alice": true, + "Bob": false, ] - let trustLevel = source.userTrustLevel(userId: "Alice") - - XCTAssertEqual(trustLevel, MXUserTrustLevel(crossSigningVerified: true, locallyVerified: true)) + XCTAssertTrue(source.isUserVerified(userId: "Alice")) + XCTAssertFalse(source.isUserVerified(userId: "Bob")) } func test_deviceTrustLevel() { @@ -69,10 +69,10 @@ class MXTrustLevelSourceUnitTests: XCTestCase { let summary = source.trustLevelSummary(userIds: ["Alice", "Bob"]) - XCTAssertEqual(summary.trustedUsersProgress.totalUnitCount, 2) - XCTAssertEqual(summary.trustedUsersProgress.completedUnitCount, 1) + XCTAssertEqual(summary.usersTrust.totalCount, 2) + XCTAssertEqual(summary.usersTrust.trustedCount, 1) - XCTAssertEqual(summary.trustedDevicesProgress.totalUnitCount, 3) - XCTAssertEqual(summary.trustedDevicesProgress.completedUnitCount, 2) + XCTAssertEqual(summary.devicesTrust.totalCount, 3) + XCTAssertEqual(summary.devicesTrust.trustedCount, 2) } } diff --git a/MatrixSDKTests/Crypto/Trust/MXTrustSummaryUnitTests.swift b/MatrixSDKTests/Crypto/Trust/MXTrustSummaryUnitTests.swift new file mode 100644 index 0000000000..2f993b78a1 --- /dev/null +++ b/MatrixSDKTests/Crypto/Trust/MXTrustSummaryUnitTests.swift @@ -0,0 +1,56 @@ +// +// Copyright 2023 The Matrix.org Foundation C.I.C +// +// 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 XCTest +@testable import MatrixSDK + +class MXTrustSummaryUnitTests: XCTestCase { + func test_init_empty() { + let summary1 = MXTrustSummary(trustedCount: 0, totalCount: 0) + XCTAssertEqual(summary1.trustedCount, 0) + XCTAssertEqual(summary1.totalCount, 0) + + let summary2 = MXTrustSummary(trustedCount: 5, totalCount: 10) + XCTAssertEqual(summary2.trustedCount, 5) + XCTAssertEqual(summary2.totalCount, 10) + } + + func test_init_totalNeverLowerThanTrusted() { + let summary1 = MXTrustSummary(trustedCount: 1, totalCount: 0) + XCTAssertEqual(summary1.trustedCount, 1) + XCTAssertEqual(summary1.totalCount, 1) + + let summary2 = MXTrustSummary(trustedCount: 20, totalCount: 10) + XCTAssertEqual(summary2.trustedCount, 20) + XCTAssertEqual(summary2.totalCount, 20) + } + + func test_areAllTrusted() { + let summaryToTrusted: [(MXTrustSummary, Bool)] = [ + (.init(trustedCount: 0, totalCount: 0), true), + (.init(trustedCount: 0, totalCount: 1), false), + (.init(trustedCount: 1, totalCount: 1), true), + (.init(trustedCount: 5, totalCount: 10), false), + (.init(trustedCount: 9, totalCount: 10), false), + (.init(trustedCount: 10, totalCount: 10), true), + ] + + for (summary, trusted) in summaryToTrusted { + XCTAssertEqual(summary.areAllTrusted, trusted) + } + } +} diff --git a/MatrixSDKTests/MXCrossSigningTests.m b/MatrixSDKTests/MXCrossSigningTests.m index 79c4ac3f71..e3d989b5b4 100644 --- a/MatrixSDKTests/MXCrossSigningTests.m +++ b/MatrixSDKTests/MXCrossSigningTests.m @@ -364,9 +364,7 @@ - (void)testBootstrapWithPassword // -> Alice must see their cross-signing info trusted MXCrossSigningInfo *aliceCrossSigningInfo = [aliceSession.crypto.crossSigning crossSigningKeysForUser:aliceSession.myUserId]; XCTAssertNotNil(aliceCrossSigningInfo); - XCTAssertTrue(aliceCrossSigningInfo.trustLevel.isVerified); - XCTAssertTrue(aliceCrossSigningInfo.trustLevel.isLocallyVerified); - XCTAssertTrue(aliceCrossSigningInfo.trustLevel.isCrossSigningVerified); + XCTAssertTrue(aliceCrossSigningInfo.isVerified); [expectation fulfill]; @@ -643,17 +641,17 @@ - (void)testMXCrossSigningInfoStorage XCTAssertNotNil(storedKeys); XCTAssertEqualObjects(storedKeys.userId, keys.userId); - XCTAssertFalse(storedKeys.trustLevel.isVerified); + XCTAssertFalse(storedKeys.isVerified); XCTAssertEqual(storedKeys.keys.count, keys.keys.count); XCTAssertEqualObjects(storedKeys.masterKeys.JSONDictionary, keys.masterKeys.JSONDictionary); XCTAssertEqualObjects(storedKeys.selfSignedKeys.JSONDictionary, keys.selfSignedKeys.JSONDictionary); XCTAssertEqualObjects(storedKeys.userSignedKeys.JSONDictionary, keys.userSignedKeys.JSONDictionary); // - Update keys test - [keys updateTrustLevel:[MXUserTrustLevel trustLevelWithCrossSigningVerified:YES locallyVerified:NO]]; + [keys setIsVerified:YES]; [aliceSession.legacyCrypto.store storeCrossSigningKeys:keys]; storedKeys = [aliceSession.legacyCrypto.store crossSigningKeysForUser:aliceUserId]; - XCTAssertTrue(storedKeys.trustLevel.isVerified); + XCTAssertTrue(storedKeys.isVerified); [expectation fulfill]; }]; @@ -793,14 +791,12 @@ - (void)testSignUser2 [bobSession.crypto.crossSigning signUserWithUserId:alice0Creds.userId success:^{ // -> Check bob trust alice as a user - MXUserTrustLevel *aliceTrust = [bobSession.crypto trustLevelForUser:alice0Creds.userId]; - XCTAssertNotNil(aliceTrust); - XCTAssertTrue(aliceTrust.isCrossSigningVerified); + BOOL isAliceVerified = [bobSession.crypto isUserVerified:alice0Creds.userId]; + XCTAssertTrue(isAliceVerified); // -> Check bob trust bob as a user - MXUserTrustLevel *bobTrust = [bobSession.crypto trustLevelForUser:bobSession.myUser.userId]; - XCTAssertNotNil(bobTrust); - XCTAssertTrue(bobTrust.isCrossSigningVerified); + BOOL isBobVerified = [bobSession.crypto isUserVerified:bobSession.myUser.userId]; + XCTAssertTrue(isBobVerified); // -> Check bob trusts now alice devices MXDeviceTrustLevel *aliceDevice0Trust = [bobSession.crypto deviceTrustLevelForDevice:alice0Creds.deviceId ofUser:alice0Creds.userId]; @@ -941,25 +937,25 @@ - (void)testTrustsBetweenBobAndAliceWithTwoDevices // -> Bob should see all devices in the party as trusted thanks to cross-signing XCTAssertEqual(bobSession.crypto.crossSigning.state, MXCrossSigningStateCanCrossSign); - XCTAssertTrue([bobSession.crypto trustLevelForUser:bobUserId].isCrossSigningVerified); + XCTAssertTrue([bobSession.crypto isUserVerified:bobUserId]); XCTAssertTrue([bobSession.crypto deviceTrustLevelForDevice:bobDeviceId ofUser:bobUserId].isCrossSigningVerified); - XCTAssertTrue([bobSession.crypto trustLevelForUser:aliceUserId].isCrossSigningVerified); + XCTAssertTrue([bobSession.crypto isUserVerified:aliceUserId]); XCTAssertTrue([bobSession.crypto deviceTrustLevelForDevice:aliceSession1DeviceId ofUser:aliceUserId].isCrossSigningVerified); XCTAssertTrue([bobSession.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); // -> Alice1 should see all devices in the party as trusted thanks to cross-signing XCTAssertEqual(aliceSession1.crypto.crossSigning.state, MXCrossSigningStateCanCrossSign); - XCTAssertTrue([aliceSession1.crypto trustLevelForUser:aliceUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession1.crypto isUserVerified:aliceUserId]); XCTAssertTrue([aliceSession1.crypto deviceTrustLevelForDevice:aliceSession1DeviceId ofUser:aliceUserId].isCrossSigningVerified); - XCTAssertTrue([aliceSession1.crypto trustLevelForUser:bobUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession1.crypto isUserVerified:bobUserId]); XCTAssertTrue([aliceSession1.crypto deviceTrustLevelForDevice:bobDeviceId ofUser:bobUserId].isCrossSigningVerified); XCTAssertTrue([aliceSession1.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); // -> Alice2 should see all devices in the party as trusted thanks to cross-signing XCTAssertEqual(aliceSession2.crypto.crossSigning.state, MXCrossSigningStateCanCrossSign); - XCTAssertTrue([aliceSession2.crypto trustLevelForUser:aliceUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession2.crypto isUserVerified:aliceUserId]); XCTAssertTrue([aliceSession2.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); - XCTAssertTrue([aliceSession2.crypto trustLevelForUser:bobUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession2.crypto isUserVerified:bobUserId]); XCTAssertTrue([aliceSession2.crypto deviceTrustLevelForDevice:bobDeviceId ofUser:bobUserId].isCrossSigningVerified); XCTAssertTrue([aliceSession2.crypto deviceTrustLevelForDevice:aliceSession1DeviceId ofUser:aliceUserId].isCrossSigningVerified); @@ -998,14 +994,14 @@ - (void)xtestTrustChain // This simulates a self verification and trigger cross-signing behind the shell [aliceSession2.crypto setDeviceVerification:MXDeviceVerified forDevice:aliceSession3DeviceId ofUser:aliceUserId success:^{ [aliceSession3.crypto setDeviceVerification:MXDeviceVerified forDevice:aliceSession2DeviceId ofUser:aliceUserId success:^{ - [aliceSession3.crypto setUserVerification:YES forUser:aliceUserId success:^{ + [aliceSession3.crypto setUserVerificationForUserId:aliceUserId success:^{ // Wait a bit to make background requests for cross-signing happen dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ // -> Alice3 should see all devices in the party as trusted thanks to cross-signing XCTAssertEqual(aliceSession3.crypto.crossSigning.state, MXCrossSigningStateCanCrossSign); - XCTAssertTrue([aliceSession3.crypto trustLevelForUser:aliceUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession3.crypto isUserVerified:aliceUserId]); XCTAssertTrue([aliceSession3.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); XCTAssertTrue([aliceSession3.crypto deviceTrustLevelForDevice:aliceSession1DeviceId ofUser:aliceUserId].isCrossSigningVerified); XCTAssertTrue([aliceSession3.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); @@ -1019,7 +1015,7 @@ - (void)xtestTrustChain // -> Alice3 should see Bob as trusted thanks to cross-signing [aliceSession3.crypto downloadKeys:@[bobUserId] forceDownload:NO success:^(MXUsersDevicesMap *usersDevicesInfoMap, NSDictionary *crossSigningKeysMap) { - XCTAssertTrue([aliceSession3.crypto trustLevelForUser:bobUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession3.crypto isUserVerified:bobUserId]); XCTAssertTrue([aliceSession3.crypto deviceTrustLevelForDevice:bobDeviceId ofUser:bobUserId].isCrossSigningVerified); [expectation fulfill]; @@ -1071,12 +1067,12 @@ - (void)testCrossSigningRotation // -> Alice1 should not trust anymore Alice2 and Bob XCTAssertEqual(aliceSession1.crypto.crossSigning.state, MXCrossSigningStateCanCrossSign); - XCTAssertFalse([aliceSession1.crypto trustLevelForUser:bobUserId].isCrossSigningVerified); + XCTAssertFalse([aliceSession1.crypto isUserVerified:bobUserId]); XCTAssertFalse([aliceSession1.crypto deviceTrustLevelForDevice:bobDeviceId ofUser:bobUserId].isCrossSigningVerified); XCTAssertFalse([aliceSession1.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); // but it should still trust itself - XCTAssertTrue([aliceSession1.crypto trustLevelForUser:aliceUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession1.crypto isUserVerified:aliceUserId]); XCTAssertTrue([aliceSession1.crypto deviceTrustLevelForDevice:aliceSession1DeviceId ofUser:aliceUserId].isCrossSigningVerified); @@ -1086,23 +1082,23 @@ - (void)testCrossSigningRotation XCTAssertFalse([aliceSession2.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); - XCTAssertFalse([aliceSession2.crypto trustLevelForUser:bobUserId].isCrossSigningVerified); + XCTAssertFalse([aliceSession2.crypto isUserVerified:bobUserId]); XCTAssertFalse([aliceSession2.crypto deviceTrustLevelForDevice:bobDeviceId ofUser:bobUserId].isCrossSigningVerified); // aliceSession2 trusts the new cross-signing reset by aliceSession1 because it trusts this device locally // This explains expected results in tests below. They may be arguable but this is the reason XCTAssertEqual(aliceSession2.crypto.crossSigning.state, MXCrossSigningStateTrustCrossSigning); - XCTAssertTrue([aliceSession2.crypto trustLevelForUser:aliceUserId].isCrossSigningVerified); + XCTAssertTrue([aliceSession2.crypto isUserVerified:aliceUserId]); XCTAssertTrue([aliceSession2.crypto deviceTrustLevelForDevice:aliceSession1DeviceId ofUser:aliceUserId].isCrossSigningVerified); // -> Bob should not trust anymore Alice1 and Alice2 XCTAssertEqual(bobSession.crypto.crossSigning.state, MXCrossSigningStateCanCrossSign); - XCTAssertFalse([bobSession.crypto trustLevelForUser:aliceUserId].isCrossSigningVerified); + XCTAssertFalse([bobSession.crypto isUserVerified:aliceUserId]); XCTAssertFalse([bobSession.crypto deviceTrustLevelForDevice:aliceSession1DeviceId ofUser:aliceUserId].isCrossSigningVerified); XCTAssertFalse([bobSession.crypto deviceTrustLevelForDevice:aliceSession2DeviceId ofUser:aliceUserId].isCrossSigningVerified); // He should still trust himself - XCTAssertTrue([bobSession.crypto trustLevelForUser:bobUserId].isCrossSigningVerified); + XCTAssertTrue([bobSession.crypto isUserVerified:bobUserId]); XCTAssertTrue([bobSession.crypto deviceTrustLevelForDevice:bobDeviceId ofUser:bobUserId].isCrossSigningVerified); [expectation fulfill]; diff --git a/MatrixSDKTests/MXCrossSigningVerificationTests.m b/MatrixSDKTests/MXCrossSigningVerificationTests.m index 2d38c3d957..e4fd3037e8 100644 --- a/MatrixSDKTests/MXCrossSigningVerificationTests.m +++ b/MatrixSDKTests/MXCrossSigningVerificationTests.m @@ -277,10 +277,8 @@ - (void)testSelfVerificationWithSAS MXCrossSigningInfo *aliceFromAlice1POV = [aliceSession1.legacyCrypto.store crossSigningKeysForUser:alice.userId]; MXCrossSigningInfo *aliceFromAlice2POV = [aliceSession2.legacyCrypto.store crossSigningKeysForUser:alice.userId]; - XCTAssertTrue(aliceFromAlice1POV.trustLevel.isCrossSigningVerified); - XCTAssertTrue(aliceFromAlice1POV.trustLevel.isLocallyVerified); - XCTAssertTrue(aliceFromAlice2POV.trustLevel.isCrossSigningVerified); - XCTAssertTrue(aliceFromAlice2POV.trustLevel.isLocallyVerified); + XCTAssertTrue(aliceFromAlice1POV.isVerified); + XCTAssertTrue(aliceFromAlice2POV.isVerified); // -> Transaction must not be listed anymore XCTAssertNil([(MXLegacyKeyVerificationManager *)aliceSession1.crypto.keyVerificationManager transactionWithTransactionId:sasTransactionFromAlicePOV.transactionId]); @@ -484,10 +482,8 @@ - (void)xtestVerificationByDMFullFlow MXCrossSigningInfo *bobFromAlicePOV = [aliceSession.legacyCrypto.store crossSigningKeysForUser:bob.userId]; MXCrossSigningInfo *aliceFromBobPOV = [bobSession.legacyCrypto.store crossSigningKeysForUser:alice.userId]; - XCTAssertTrue(bobFromAlicePOV.trustLevel.isCrossSigningVerified); - XCTAssertTrue(bobFromAlicePOV.trustLevel.isLocallyVerified); - XCTAssertTrue(aliceFromBobPOV.trustLevel.isCrossSigningVerified); - XCTAssertTrue(aliceFromBobPOV.trustLevel.isLocallyVerified); + XCTAssertTrue(bobFromAlicePOV.isVerified); + XCTAssertTrue(aliceFromBobPOV.isVerified); // -> Transaction must not be listed anymore XCTAssertNil([(MXLegacyKeyVerificationManager *)aliceSession.crypto.keyVerificationManager transactionWithTransactionId:sasTransactionFromAlicePOV.transactionId]); @@ -711,10 +707,8 @@ - (void)xtestVerifyingAnotherUserQRCodeVerificationFullFlow MXCrossSigningInfo *bobFromAlicePOV = [aliceSession.legacyCrypto.store crossSigningKeysForUser:bob.userId]; MXCrossSigningInfo *aliceFromBobPOV = [bobSession.legacyCrypto.store crossSigningKeysForUser:alice.userId]; - XCTAssertTrue(bobFromAlicePOV.trustLevel.isCrossSigningVerified); - XCTAssertTrue(bobFromAlicePOV.trustLevel.isLocallyVerified); - XCTAssertTrue(aliceFromBobPOV.trustLevel.isCrossSigningVerified); - XCTAssertTrue(aliceFromBobPOV.trustLevel.isLocallyVerified); + XCTAssertTrue(bobFromAlicePOV.isVerified); + XCTAssertTrue(aliceFromBobPOV.isVerified); // -> Transaction must not be listed anymore XCTAssertNil([(MXLegacyKeyVerificationManager *)aliceSession.crypto.keyVerificationManager transactionWithTransactionId:qrCodeTransactionFromAlicePOV.transactionId]); diff --git a/MatrixSDKTests/MXRoomSummaryTrustTests.m b/MatrixSDKTests/MXRoomSummaryTrustTests.m index 1d0f92aceb..b14272d4b6 100644 --- a/MatrixSDKTests/MXRoomSummaryTrustTests.m +++ b/MatrixSDKTests/MXRoomSummaryTrustTests.m @@ -16,6 +16,7 @@ #import +#import "MatrixSDKTestsSwiftHeader.h" #import "MatrixSDKTestsData.h" #import "MatrixSDKTestsE2EData.h" @@ -81,13 +82,11 @@ - (void)testNoCrossSigningNoTrust MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; XCTAssertNotNil(trust); - XCTAssertEqual(trust.trustedUsersProgress.totalUnitCount, 2); - XCTAssertEqual(trust.trustedUsersProgress.completedUnitCount, 0); - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 0); + XCTAssertEqual(trust.usersTrust.totalCount, 2); + XCTAssertEqual(trust.usersTrust.trustedCount, 0); - XCTAssertEqual(trust.trustedDevicesProgress.totalUnitCount, 0); - XCTAssertEqual(trust.trustedDevicesProgress.completedUnitCount, 0); - XCTAssertEqual(trust.trustedDevicesProgress.fractionCompleted, 0); + XCTAssertEqual(trust.devicesTrust.totalCount, 0); + XCTAssertEqual(trust.devicesTrust.trustedCount, 0); [expectation fulfill]; }); @@ -110,13 +109,11 @@ - (void)testAllTrusted MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; XCTAssertNotNil(trust); - XCTAssertEqual(trust.trustedUsersProgress.totalUnitCount, 2); - XCTAssertEqual(trust.trustedUsersProgress.completedUnitCount, 2); - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); + XCTAssertEqual(trust.usersTrust.totalCount, 2); + XCTAssertEqual(trust.usersTrust.trustedCount, 2); - XCTAssertEqual(trust.trustedDevicesProgress.totalUnitCount, 3); - XCTAssertEqual(trust.trustedDevicesProgress.completedUnitCount, 3); - XCTAssertEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertEqual(trust.devicesTrust.totalCount, 3); + XCTAssertEqual(trust.devicesTrust.trustedCount, 3); [expectation fulfill]; }); @@ -142,13 +139,11 @@ - (void)testNotFullyTrusted MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; XCTAssertNotNil(trust); - XCTAssertEqual(trust.trustedUsersProgress.totalUnitCount, 2); - XCTAssertEqual(trust.trustedUsersProgress.completedUnitCount, 2); - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); + XCTAssertEqual(trust.usersTrust.totalCount, 2); + XCTAssertEqual(trust.usersTrust.trustedCount, 2); - XCTAssertEqual(trust.trustedDevicesProgress.totalUnitCount, 4); - XCTAssertEqual(trust.trustedDevicesProgress.completedUnitCount, 3); - XCTAssertNotEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertEqual(trust.devicesTrust.totalCount, 4); + XCTAssertEqual(trust.devicesTrust.trustedCount, 3); [expectation fulfill]; }); @@ -173,8 +168,8 @@ - (void)testTrustChangeAfterUserSignInOnNewDevice // -> All must be trusted MXRoom *roomFromAlicePOV = [aliceSession1 roomWithRoomId:roomId]; MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); - XCTAssertEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertTrue(trust.usersTrust.areAllTrusted); + XCTAssertTrue(trust.devicesTrust.areAllTrusted); // - Bob signs in on a new device [matrixSDKTestsE2EData loginUserOnANewDevice:self credentials:bobSession1.matrixRestClient.credentials withPassword:MXTESTS_BOB_PWD onComplete:^(MXSession *bobSession2) { @@ -184,8 +179,8 @@ - (void)testTrustChangeAfterUserSignInOnNewDevice id observer = [[NSNotificationCenter defaultCenter] addObserverForName:kMXRoomSummaryDidChangeNotification object:roomFromAlicePOV.summary queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); - XCTAssertNotEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertTrue(trust.usersTrust.areAllTrusted); + XCTAssertFalse(trust.devicesTrust.areAllTrusted); [expectation fulfill]; }]; @@ -214,8 +209,8 @@ - (void)testTrustChangeAfterUserCompleteSecurity // -> Not all must be trusted MXRoom *roomFromAlicePOV = [aliceSession1 roomWithRoomId:roomId]; MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); - XCTAssertNotEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertTrue(trust.usersTrust.areAllTrusted); + XCTAssertFalse(trust.devicesTrust.areAllTrusted); // - Bob trusts the new device [bobSession1.crypto setDeviceVerification:MXDeviceVerified forDevice:bobSession2.myDeviceId ofUser:bobSession2.myUserId success:^{ @@ -228,10 +223,10 @@ - (void)testTrustChangeAfterUserCompleteSecurity id observer = [[NSNotificationCenter defaultCenter] addObserverForName:kMXRoomSummaryDidChangeNotification object:roomFromAlicePOV.summary queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; - if (trust.trustedDevicesProgress.fractionCompleted == 1) // It could take for the SDK to update the trust right + if (trust.devicesTrust.areAllTrusted) // It could take for the SDK to update the trust right { - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); - XCTAssertEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertTrue(trust.usersTrust.areAllTrusted); + XCTAssertTrue(trust.devicesTrust.areAllTrusted); [expectation fulfill]; } }]; @@ -258,8 +253,8 @@ - (void)testTrustChangeAfterUserRotateMSK // -> All must be trusted MXRoom *roomFromAlicePOV = [aliceSession1 roomWithRoomId:roomId]; MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); - XCTAssertEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertTrue(trust.usersTrust.areAllTrusted); + XCTAssertTrue(trust.devicesTrust.areAllTrusted); // - Bob rotates their cross-signing [bobSession1.crypto.crossSigning setupWithPassword:MXTESTS_BOB_PWD success:^{ @@ -272,8 +267,8 @@ - (void)testTrustChangeAfterUserRotateMSK id observer = [[NSNotificationCenter defaultCenter] addObserverForName:kMXRoomSummaryDidChangeNotification object:roomFromAlicePOV.summary queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { MXUsersTrustLevelSummary *trust = roomFromAlicePOV.summary.trust; - XCTAssertNotEqual(trust.trustedUsersProgress.fractionCompleted, 1); - XCTAssertEqual(trust.trustedDevicesProgress.fractionCompleted, 1); // 100% Because all devices of trusted users are verified + XCTAssertFalse(trust.usersTrust.areAllTrusted); + XCTAssertTrue(trust.devicesTrust.areAllTrusted); // 100% Because all devices of trusted users are verified [expectation fulfill]; }]; @@ -355,8 +350,8 @@ - (void)testEnableTrustTracking // -> Trust be available and everything should be green MXUsersTrustLevelSummary *trust = roomSummaryFromAlicePOV.trust; - XCTAssertEqual(trust.trustedUsersProgress.fractionCompleted, 1); - XCTAssertEqual(trust.trustedDevicesProgress.fractionCompleted, 1); + XCTAssertTrue(trust.usersTrust.areAllTrusted); + XCTAssertTrue(trust.devicesTrust.areAllTrusted); [expectation fulfill]; }]; diff --git a/MatrixSDKTests/MXSessionStartupProgressUnitTests.swift b/MatrixSDKTests/MXSessionStartupProgressUnitTests.swift index 5c1b79107e..5a8b17f39a 100644 --- a/MatrixSDKTests/MXSessionStartupProgressUnitTests.swift +++ b/MatrixSDKTests/MXSessionStartupProgressUnitTests.swift @@ -19,9 +19,9 @@ import MatrixSDK class MXSessionStartupProgressUnitTests: XCTestCase { class SpyDelegate: MXSessionStartupProgressDelegate { - var stage: MXSessionStartupStage? - func sessionDidUpdateStartupStage(_ stage: MXSessionStartupStage) { - self.stage = stage + var state: MXSessionStartupProgress.State! + func sessionDidUpdateStartupProgress(state: MXSessionStartupProgress.State) { + self.state = state } } @@ -33,78 +33,98 @@ class MXSessionStartupProgressUnitTests: XCTestCase { progress.delegate = delegate } - func testUpdatesMigrationProgress() { - XCTAssertNil(delegate.stage) + // MARK: - updateProgressForStage + + func test_updateProgress_storeMigration_isHalfOfTotalProgress() { + progress.updateProgressForStage(.storeMigration, progress: 0) + XCTAssertEqual(delegate.state.progress, 0) - progress.updateMigrationProgress(0) - XCTAssertMigratingProgress(0, stage: delegate.stage) + progress.updateProgressForStage(.storeMigration, progress: 0.5) + XCTAssertEqual(delegate.state.progress, 0.25) - progress.updateMigrationProgress(0.5) - XCTAssertMigratingProgress(0.5, stage: delegate.stage) + progress.updateProgressForStage(.storeMigration, progress: 1) + XCTAssertEqual(delegate.state.progress, 0.5) } + func test_updateProgress_serverSyncingWithoutMigration_isZero() { + progress.updateProgressForStage(.serverSyncing, progress: 0) + XCTAssertEqual(delegate.state.progress, 0) + } - func testIncrementsSyncAttempt() { - XCTAssertNil(delegate.stage) - - progress.incrementSyncAttempt() - XCTAssertIsNthSyncingAttempt(1, stage: delegate.stage) + func test_updateProgress_serverSyncingAfterMigration_isHalfOfTotalProgress() { + progress.updateProgressForStage(.storeMigration, progress: 0) + progress.updateProgressForStage(.serverSyncing, progress: 0) + XCTAssertEqual(delegate.state.progress, 0.5) + } + + func test_updateProgress_repeatedServerSyncing_showsDelayWarning() { + progress.updateProgressForStage(.serverSyncing, progress: 0) + XCTAssertFalse(delegate.state.showDelayWarning) - progress.incrementSyncAttempt() - XCTAssertIsNthSyncingAttempt(2, stage: delegate.stage) + progress.updateProgressForStage(.serverSyncing, progress: 0) + XCTAssertTrue(delegate.state.showDelayWarning) - progress.incrementSyncAttempt() - XCTAssertIsNthSyncingAttempt(3, stage: delegate.stage) + progress.updateProgressForStage(.serverSyncing, progress: 0) + progress.updateProgressForStage(.serverSyncing, progress: 0) + XCTAssertTrue(delegate.state.showDelayWarning) } - func testUpdatesProcessingProgressForMultiplePhases() { - XCTAssertNil(delegate.stage) + func test_updateProgress_processingResponseWithoutMigration_isEntireProgress() { + progress.updateProgressForStage(.processingResponse, progress: 0) + XCTAssertEqual(delegate.state.progress, 0) - progress.updateProcessingProgress(0, forPhase: .syncResponse) - XCTAssertProcessingProgress(0, stage: delegate.stage) + progress.updateProgressForStage(.processingResponse, progress: 0.5) + XCTAssertEqual(delegate.state.progress, 0.5) - // Sync response is one of 2 possible phases, so its progress contributes 50% to the overal progress - progress.updateProcessingProgress(0.5, forPhase: .syncResponse) - XCTAssertProcessingProgress(0.25, stage: delegate.stage) + progress.updateProgressForStage(.processingResponse, progress: 1) + XCTAssertEqual(delegate.state.progress, 1) + } + + func test_updateProgress_processingResponseAfterMigration_isHalfOfTotalProgress() { + progress.updateProgressForStage(.storeMigration, progress: 0) - // Reporting progress for next phase assumes the previous phase has completed, - progress.updateProcessingProgress(0.5, forPhase: .roomSummaries) - XCTAssertProcessingProgress(0.75, stage: delegate.stage) + progress.updateProgressForStage(.processingResponse, progress: 0) + XCTAssertEqual(delegate.state.progress, 0.5) - // Full progress for the last phase means the overal progres is complete as well - progress.updateProcessingProgress(1, forPhase: .roomSummaries) - XCTAssertProcessingProgress(1, stage: delegate.stage) + progress.updateProgressForStage(.processingResponse, progress: 0.5) + XCTAssertEqual(delegate.state.progress, 0.75) + + progress.updateProgressForStage(.processingResponse, progress: 1) + XCTAssertEqual(delegate.state.progress, 1) } - // MARK: - Assertion helpers + // MARK: - overalProgressForStep - private func XCTAssertMigratingProgress(_ expectedProgress: Double, stage: MXSessionStartupStage?, file: StaticString = #file, line: UInt = #line) { - if case .migratingData(let progress) = stage { - XCTAssertEqual(progress, expectedProgress, file: file, line: line) - } else if let stage = stage { - XCTFail("Unexpected stage \(stage)", file: file, line: line) - } else { - XCTFail("stage is nil", file: file, line: line) - } + private func overallProgress(step: Int, count: Int, progress: Double) -> Double { + self.progress.overallProgressForStep(step, totalCount: count, progress: progress) } - private func XCTAssertIsNthSyncingAttempt(_ expectedAttempt: Int, stage: MXSessionStartupStage?, file: StaticString = #file, line: UInt = #line) { - if case .serverSyncing(let attempt) = stage { - XCTAssertEqual(attempt, expectedAttempt, file: file, line: line) - } else if let stage = stage { - XCTFail("Unexpected stage \(stage)", file: file, line: line) - } else { - XCTFail("stage is nil", file: file, line: line) - } + func test_overallProgressForStep_oneStep() { + XCTAssertEqual(overallProgress(step: 0, count: 1, progress: 0), 0) + XCTAssertEqual(overallProgress(step: 0, count: 1, progress: 0.5), 0.5) + XCTAssertEqual(overallProgress(step: 0, count: 1, progress: 1), 1) } - private func XCTAssertProcessingProgress(_ expectedProgress: Double, stage: MXSessionStartupStage?, file: StaticString = #file, line: UInt = #line) { - if case .processingResponse(let progress) = stage { - XCTAssertEqual(progress, expectedProgress, file: file, line: line) - } else if let stage = stage { - XCTFail("Unexpected stage \(stage)", file: file, line: line) - } else { - XCTFail("stage is nil", file: file, line: line) - } + func test_overallProgress_twoSteps() { + XCTAssertEqual(overallProgress(step: 0, count: 2, progress: 0), 0) + XCTAssertEqual(overallProgress(step: 0, count: 2, progress: 0.5), 0.25) + XCTAssertEqual(overallProgress(step: 0, count: 2, progress: 1), 0.5) + + XCTAssertEqual(overallProgress(step: 1, count: 2, progress: 0), 0.5) + XCTAssertEqual(overallProgress(step: 1, count: 2, progress: 0.5), 0.75) + XCTAssertEqual(overallProgress(step: 1, count: 2, progress: 1), 1) + } + + func test_overallProgress_tenSteps() { + XCTAssertEqual(overallProgress(step: 0, count: 10, progress: 0), 0) + XCTAssertEqual(overallProgress(step: 0, count: 10, progress: 1), 0.1) + + XCTAssertEqual(overallProgress(step: 3, count: 10, progress: 0.5), 0.35) + + XCTAssertEqual(overallProgress(step: 4, count: 10, progress: 1), 0.5) + + XCTAssertEqual(overallProgress(step: 7, count: 10, progress: 0.25), 0.725) + + XCTAssertEqual(overallProgress(step: 9, count: 10, progress: 1), 1) } } diff --git a/MatrixSDKTests/TestPlans/UnitTests.xctestplan b/MatrixSDKTests/TestPlans/UnitTests.xctestplan index f3645e682f..d67025e02e 100644 --- a/MatrixSDKTests/TestPlans/UnitTests.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTests.xctestplan @@ -29,6 +29,7 @@ "testTargets" : [ { "selectedTests" : [ + "EventEncryptionAlgorithmUnitTests", "MXAesUnitTests", "MXAggregatedEditsUnitTests", "MXAggregatedReferenceUnitTests", @@ -97,6 +98,7 @@ "MXToDevicePayloadUnitTests", "MXToolsUnitTests", "MXTrustLevelSourceUnitTests", + "MXTrustSummaryUnitTests", "MXUnrequestedForwardedRoomKeyManagerUnitTests" ], "target" : { diff --git a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan index 2ca30c4c4c..9897219411 100644 --- a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan @@ -39,6 +39,7 @@ "testTargets" : [ { "selectedTests" : [ + "EventEncryptionAlgorithmUnitTests", "MXAesUnitTests", "MXAggregatedEditsUnitTests", "MXAggregatedReferenceUnitTests", @@ -105,6 +106,7 @@ "MXToDevicePayloadUnitTests", "MXToolsUnitTests", "MXTrustLevelSourceUnitTests", + "MXTrustSummaryUnitTests", "MXUnrequestedForwardedRoomKeyManagerUnitTests" ], "target" : { diff --git a/Podfile b/Podfile index 6a5f5ca52e..3533c35a59 100644 --- a/Podfile +++ b/Podfile @@ -16,7 +16,7 @@ abstract_target 'MatrixSDK' do pod 'Realm', '10.27.0' pod 'libbase58', '~> 0.1.4' - pod 'MatrixSDKCrypto', "0.2.1", :inhibit_warnings => true + pod 'MatrixSDKCrypto', "0.3.0", :inhibit_warnings => true target 'MatrixSDK-iOS' do platform :ios, '11.0' diff --git a/Podfile.lock b/Podfile.lock index d34cb15956..f08ccdbe24 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -16,7 +16,7 @@ PODS: - AFNetworking/NSURLSession - GZIP (1.3.0) - libbase58 (0.1.4) - - MatrixSDKCrypto (0.2.1) + - MatrixSDKCrypto (0.3.0) - OHHTTPStubs (9.1.0): - OHHTTPStubs/Default (= 9.1.0) - OHHTTPStubs/Core (9.1.0) @@ -44,7 +44,7 @@ DEPENDENCIES: - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - - MatrixSDKCrypto (= 0.2.1) + - MatrixSDKCrypto (= 0.3.0) - OHHTTPStubs (~> 9.1.0) - OLMKit (~> 3.2.5) - Realm (= 10.27.0) @@ -65,12 +65,12 @@ SPEC CHECKSUMS: AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3 libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd - MatrixSDKCrypto: 477d818bf2cc37b6cf702a290eb647bc8cf3cb1b + MatrixSDKCrypto: 05ebe373ccebf40f8a0cff37d8f8b24fd01b9883 OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 OLMKit: da115f16582e47626616874e20f7bb92222c7a51 Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 SwiftyBeaver: 84069991dd5dca07d7069100985badaca7f0ce82 -PODFILE CHECKSUM: e6ea6492ce460203d61def97cf6ceb27f8827d70 +PODFILE CHECKSUM: 8bb882cb5f6c537792581a49410afe8c2f848364 COCOAPODS: 1.11.3