From bf791112673d656432472924cf066487ec2bcdc9 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 18 Jul 2022 16:56:21 +0100 Subject: [PATCH 01/65] Hide CryptoMachine behind smaller protocols --- MatrixSDK.xcodeproj/project.pbxproj | 12 +- .../MXCryptoMachine.swift | 133 ++++++++++-------- .../CryptoMachine/MXCryptoProtocols.swift | 49 +++++++ .../MXCryptoRequests.swift | 0 ...EventDecryptionResult+DecryptedEvent.swift | 0 5 files changed, 129 insertions(+), 65 deletions(-) rename MatrixSDK/Crypto/{V2 => CryptoMachine}/MXCryptoMachine.swift (97%) create mode 100644 MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift rename MatrixSDK/Crypto/{V2 => CryptoMachine}/MXCryptoRequests.swift (100%) rename MatrixSDK/Crypto/{V2 => CryptoMachine}/MXEventDecryptionResult+DecryptedEvent.swift (100%) diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index abfac02851..cad7f5a8ff 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1817,6 +1817,8 @@ ED88999427F2065D00718486 /* MXRoomAliasResolution.m in Sources */ = {isa = PBXBuildFile; fileRef = ED88999027F2065D00718486 /* MXRoomAliasResolution.m */; }; ED8943D427E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8943D327E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift */; }; ED8943D527E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8943D327E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift */; }; + ED8F1D382885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */; }; + ED8F1D392885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */; }; EDB4209227DF77390036AF39 /* MXEventsEnumeratorOnArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB4209027DF77310036AF39 /* MXEventsEnumeratorOnArrayTests.swift */; }; EDB4209327DF77390036AF39 /* MXEventsEnumeratorOnArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB4209027DF77310036AF39 /* MXEventsEnumeratorOnArrayTests.swift */; }; EDB4209527DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB4209427DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift */; }; @@ -2839,6 +2841,7 @@ 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 = ""; }; ED8943D327E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXMemoryRoomStoreUnitTests.swift; sourceTree = ""; }; + ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCryptoProtocols.swift; sourceTree = ""; }; EDB4209027DF77310036AF39 /* MXEventsEnumeratorOnArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXEventsEnumeratorOnArrayTests.swift; sourceTree = ""; }; EDB4209427DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXEventsByTypesEnumeratorOnArrayTests.swift; sourceTree = ""; }; EDB4209827DF842F0036AF39 /* MXEventFixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXEventFixtures.swift; sourceTree = ""; }; @@ -3176,7 +3179,7 @@ 324DD296246AD25E00377005 /* SecretStorage */, 324BE4651E3FADB1008D99D4 /* Utils */, 3252DCAB224BE59E0032264F /* Verification */, - ED2DD110286C450600F06731 /* V2 */, + ED2DD110286C450600F06731 /* CryptoMachine */, 322A51B41D9AB15900C8536D /* MXCrypto.h */, 322A51B51D9AB15900C8536D /* MXCrypto.m */, ED47CB6C28523995004FD755 /* MXCryptoV2.swift */, @@ -4997,14 +5000,15 @@ path = Megolm; sourceTree = ""; }; - ED2DD110286C450600F06731 /* V2 */ = { + ED2DD110286C450600F06731 /* CryptoMachine */ = { isa = PBXGroup; children = ( ED2DD111286C450600F06731 /* MXCryptoMachine.swift */, + ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */, ED2DD112286C450600F06731 /* MXEventDecryptionResult+DecryptedEvent.swift */, ED2DD113286C450600F06731 /* MXCryptoRequests.swift */, ); - path = V2; + path = CryptoMachine; sourceTree = ""; }; ED2DD11A286C4F3100F06731 /* V2 */ = { @@ -6209,6 +6213,7 @@ EC0B942127186D4600B4D440 /* MXRoomListDataFilterable.swift in Sources */, 324DD2B8246C21C700377005 /* MXSecretStorageKeyCreationInfo.m in Sources */, EC1165C027107E330089FA56 /* MXSuggestedRoomListDataCache.swift in Sources */, + ED8F1D382885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */, ECD2897726E8ED0900F268CF /* MXRoomListDataFetchOptions.swift in Sources */, EC0B941B2718654B00B4D440 /* NSManagedObject+MatrixSDK.swift in Sources */, 327E9AE82285A8C400A98BC1 /* MXAggregationPaginatedResponse.m in Sources */, @@ -6775,6 +6780,7 @@ EC0B942227186D4600B4D440 /* MXRoomListDataFilterable.swift in Sources */, 32F00ABE2488E1CD00131741 /* MXRecoveryService.m in Sources */, B14EF1FB2397E90400758AF0 /* MXEnumConstants.swift in Sources */, + ED8F1D392885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */, B14EF1FC2397E90400758AF0 /* MXEventRelations.m in Sources */, EC0B941C2718654B00B4D440 /* NSManagedObject+MatrixSDK.swift in Sources */, EC8A53E325B1BCC6004E0802 /* MXThirdPartyUserInstance.m in Sources */, diff --git a/MatrixSDK/Crypto/V2/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift similarity index 97% rename from MatrixSDK/Crypto/V2/MXCryptoMachine.swift rename to MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index 2acd23a044..3a391c7047 100644 --- a/MatrixSDK/Crypto/V2/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -45,22 +45,6 @@ class MXCryptoMachine { case nothingToEncrypt } - var deviceCurve25519Key: String? { - guard let key = machine.identityKeys()["curve25519"] else { - log(error: "Cannot get device curve25519 key") - return nil - } - return key - } - - var deviceEd25519Key: String? { - guard let key = machine.identityKeys()["ed25519"] else { - log(error: "Cannot get device ed25519 key") - return nil - } - return key - } - private let machine: OlmMachine private let requests: MXCryptoRequests private let serialQueue = MXTaskQueue() @@ -94,7 +78,10 @@ class MXCryptoMachine { .appendingPathComponent(Self.storeFolder) .appendingPathComponent(userId) } - +} + +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoSyncing { func handleSyncResponse( toDevice: MXToDeviceSyncResponse?, deviceLists: MXDeviceListResponse?, @@ -126,38 +113,7 @@ class MXCryptoMachine { } } - func shareRoomKeysIfNecessary(roomId: String, users: [String]) async throws { - try await serialQueue.sync { [weak self] in - try await self?.updateTrackedUsers(users: users) - try await self?.getMissingSessions(users: users) - } - - let roomQueue = await roomQueues.getQueue(for: roomId) - try await roomQueue.sync { [weak self] in - try await self?.shareRoomKey(roomId: roomId, users: users) - } - } - - func encrypt(_ content: [AnyHashable: Any], roomId: String, eventType: String, users: [String]) async throws -> [String: Any] { - guard let content = MXTools.serialiseJSONObject(content) else { - throw Error.nothingToEncrypt - } - - try await shareRoomKeysIfNecessary(roomId: roomId, users: users) - let event = try machine.encrypt(roomId: roomId, eventType: eventType as String, content: content) - return MXTools.deserialiseJSONString(event) as? [String: Any] ?? [:] - } - - func decryptEvent(_ event: MXEvent) throws -> MXEventDecryptionResult { - guard let roomId = event.roomId, let event = event.jsonString() else { - throw Error.invalidEvent - } - - let result = try machine.decryptRoomEvent(event: event, roomId: roomId) - return try MXEventDecryptionResult(event: result) - } - - // MARK: - Requests + // MARK: - Private private func handleRequest(_ request: Request) async throws { switch request { @@ -192,6 +148,72 @@ class MXCryptoMachine { try self.machine.markRequestAsSent(requestId: requestId, requestType: requestType, response: response?.jsonString() ?? "") } + private func processOutgoingRequests() async throws { + let requests = try machine.outgoingRequests() + await withThrowingTaskGroup(of: Void.self) { [weak self] group in + guard let self = self else { return } + + for request in requests { + group.addTask { + try await self.handleRequest(request) + } + } + } + } +} + +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoDevicesSource { + var deviceCurve25519Key: String? { + guard let key = machine.identityKeys()["curve25519"] else { + log(error: "Cannot get device curve25519 key") + return nil + } + return key + } + + var deviceEd25519Key: String? { + guard let key = machine.identityKeys()["ed25519"] else { + log(error: "Cannot get device ed25519 key") + return nil + } + return key + } +} + +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoEventEncrypting { + func shareRoomKeysIfNecessary(roomId: String, users: [String]) async throws { + try await serialQueue.sync { [weak self] in + try await self?.updateTrackedUsers(users: users) + try await self?.getMissingSessions(users: users) + } + + let roomQueue = await roomQueues.getQueue(for: roomId) + try await roomQueue.sync { [weak self] in + try await self?.shareRoomKey(roomId: roomId, users: users) + } + } + + func encrypt(_ content: [AnyHashable: Any], roomId: String, eventType: String, users: [String]) async throws -> [String: Any] { + guard let content = MXTools.serialiseJSONObject(content) else { + throw Error.nothingToEncrypt + } + + try await shareRoomKeysIfNecessary(roomId: roomId, users: users) + let event = try machine.encrypt(roomId: roomId, eventType: eventType as String, content: content) + return MXTools.deserialiseJSONString(event) as? [String: Any] ?? [:] + } + + func decryptEvent(_ event: MXEvent) throws -> MXEventDecryptionResult { + guard let roomId = event.roomId, let event = event.jsonString() else { + throw Error.invalidEvent + } + + let result = try machine.decryptRoomEvent(event: event, roomId: roomId) + return try MXEventDecryptionResult(event: result) + } + // MARK: - Private private func updateTrackedUsers(users: [String]) async throws { @@ -225,19 +247,6 @@ class MXCryptoMachine { } } } - - private func processOutgoingRequests() async throws { - let requests = try machine.outgoingRequests() - await withThrowingTaskGroup(of: Void.self) { [weak self] group in - guard let self = self else { return } - - for request in requests { - group.addTask { - try await self.handleRequest(request) - } - } - } - } } @available(iOS 13.0.0, *) diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift new file mode 100644 index 0000000000..5eedaa92a6 --- /dev/null +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift @@ -0,0 +1,49 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +/// A set of protocols defining the functionality in `MatrixSDKCrypto` and separating them into logical units + +@available(iOS 13.0.0, *) +protocol MXCryptoSyncing { + func handleSyncResponse( + toDevice: MXToDeviceSyncResponse?, + deviceLists: MXDeviceListResponse?, + deviceOneTimeKeysCounts: [String: NSNumber], + unusedFallbackKeys: [String]? + ) throws + + func completeSync() async throws +} + +protocol MXCryptoDevicesSource { + var deviceCurve25519Key: String? { get } + var deviceEd25519Key: String? { get } +} + +@available(iOS 13.0.0, *) +protocol MXCryptoEventEncrypting { + func shareRoomKeysIfNecessary(roomId: String, users: [String]) async throws + func encrypt(_ content: [AnyHashable: Any], roomId: String, eventType: String, users: [String]) async throws -> [String: Any] + func decryptEvent(_ event: MXEvent) throws -> MXEventDecryptionResult +} + +#endif diff --git a/MatrixSDK/Crypto/V2/MXCryptoRequests.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift similarity index 100% rename from MatrixSDK/Crypto/V2/MXCryptoRequests.swift rename to MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift diff --git a/MatrixSDK/Crypto/V2/MXEventDecryptionResult+DecryptedEvent.swift b/MatrixSDK/Crypto/CryptoMachine/MXEventDecryptionResult+DecryptedEvent.swift similarity index 100% rename from MatrixSDK/Crypto/V2/MXEventDecryptionResult+DecryptedEvent.swift rename to MatrixSDK/Crypto/CryptoMachine/MXEventDecryptionResult+DecryptedEvent.swift From 824e4a42ec43ffe2081ba0e800fc4e02c9361755 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 18 Jul 2022 17:53:40 +0100 Subject: [PATCH 02/65] Wait longer with integration tests --- MatrixSDKTests/MXCrossSigningVerificationTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MatrixSDKTests/MXCrossSigningVerificationTests.m b/MatrixSDKTests/MXCrossSigningVerificationTests.m index 917e706abf..fa78d97933 100644 --- a/MatrixSDKTests/MXCrossSigningVerificationTests.m +++ b/MatrixSDKTests/MXCrossSigningVerificationTests.m @@ -664,7 +664,7 @@ - (void)testVerifyingAnotherUserQRCodeVerificationFullFlow // - Alice accepts it and creates a QR code transaction // Wait a bit - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ // - Alice accepts the incoming request id requestFromAlicePOV = aliceSession.crypto.keyVerificationManager.pendingRequests.firstObject; XCTAssertNotNil(requestFromAlicePOV); From 70ea7d12ec15c2ad72a67d93bc01ac226d23ff75 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 17:18:58 +0300 Subject: [PATCH 03/65] Define key backup algorithms --- MatrixSDK/Crypto/Data/MXCryptoConstants.h | 10 ++++++++-- MatrixSDK/Crypto/Data/MXCryptoConstants.m | 9 +++++---- MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersion.h | 4 ++-- MatrixSDKTests/MXCryptoBackupTests.m | 6 +++--- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/MatrixSDK/Crypto/Data/MXCryptoConstants.h b/MatrixSDK/Crypto/Data/MXCryptoConstants.h index 55060d43e8..ef9b004674 100644 --- a/MatrixSDK/Crypto/Data/MXCryptoConstants.h +++ b/MatrixSDK/Crypto/Data/MXCryptoConstants.h @@ -29,9 +29,14 @@ FOUNDATION_EXPORT NSString *const kMXCryptoOlmAlgorithm; FOUNDATION_EXPORT NSString *const kMXCryptoMegolmAlgorithm; /** - Matrix algorithm tag for megolm keys backup. + Matrix Curve25519 algorithm tag for key backup. */ -FOUNDATION_EXPORT NSString *const kMXCryptoMegolmBackupAlgorithm; +FOUNDATION_EXPORT NSString *const kMXCryptoCurve25519KeyBackupAlgorithm; + +/** + Matrix Aes256 algorithm tag for key backup. + */ +FOUNDATION_EXPORT NSString *const kMXCryptoAes256KeyBackupAlgorithm; /** MXKeyProvider identifier for a 32 bytes long key to pickle secrets managed by the olm library. @@ -73,5 +78,6 @@ typedef enum : NSUInteger MXKeyBackupErrorMissingPrivateKeySaltCode, MXKeyBackupErrorMissingAuthDataCode, MXKeyBackupErrorInvalidOrMissingLocalPrivateKey, + MXKeyBackupErrorUnknownAlgorithm } MXKeyBackupErrorCode; diff --git a/MatrixSDK/Crypto/Data/MXCryptoConstants.m b/MatrixSDK/Crypto/Data/MXCryptoConstants.m index 6a83e73831..a804a41479 100644 --- a/MatrixSDK/Crypto/Data/MXCryptoConstants.m +++ b/MatrixSDK/Crypto/Data/MXCryptoConstants.m @@ -17,10 +17,11 @@ #import "MXCryptoConstants.h" -NSString *const kMXCryptoOlmAlgorithm = @"m.olm.v1.curve25519-aes-sha2"; -NSString *const kMXCryptoMegolmAlgorithm = @"m.megolm.v1.aes-sha2"; -NSString *const kMXCryptoMegolmBackupAlgorithm = @"m.megolm_backup.v1.curve25519-aes-sha2"; -NSString *const MXCryptoOlmPickleKeyDataType = @"org.matrix.sdk.olm.pickle.key"; +NSString *const kMXCryptoOlmAlgorithm = @"m.olm.v1.curve25519-aes-sha2"; +NSString *const kMXCryptoMegolmAlgorithm = @"m.megolm.v1.aes-sha2"; +NSString *const kMXCryptoCurve25519KeyBackupAlgorithm = @"m.megolm_backup.v1.curve25519-aes-sha2"; +NSString *const kMXCryptoAes256KeyBackupAlgorithm = @"org.matrix.msc3270.v1.aes-hmac-sha2"; +NSString *const MXCryptoOlmPickleKeyDataType = @"org.matrix.sdk.olm.pickle.key"; #pragma mark - Encrypting error diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersion.h b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersion.h index b7b4582e89..cf3207590f 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersion.h +++ b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersion.h @@ -27,12 +27,12 @@ NS_ASSUME_NONNULL_BEGIN /** The algorithm used for storing backups. - Currently, only kMXCryptoMegolmBackupAlgorithm (m.megolm_backup.v1.curve25519-aes-sha2) is defined. + Currently, kMXCryptoCurve25519KeyBackupAlgorithm (m.megolm_backup.v1.curve25519-aes-sha2) and kMXCryptoAes256KeyBackupAlgorithm (org.matrix.msc3270.v1.aes-hmac-sha2) are defined. */ @property (nonatomic) NSString *algorithm; /** - Algorithm-dependent data. + Algorithm-dependent auth data. */ @property (nonatomic) NSDictionary *authData; diff --git a/MatrixSDKTests/MXCryptoBackupTests.m b/MatrixSDKTests/MXCryptoBackupTests.m index e5499f9725..53aeb0267d 100644 --- a/MatrixSDKTests/MXCryptoBackupTests.m +++ b/MatrixSDKTests/MXCryptoBackupTests.m @@ -67,7 +67,7 @@ - (void)tearDown - (MXKeyBackupVersion*)fakeKeyBackupVersion { return [MXKeyBackupVersion modelFromJSON:@{ - @"algorithm": kMXCryptoMegolmBackupAlgorithm, + @"algorithm": kMXCryptoCurve25519KeyBackupAlgorithm, @"auth_data": @{ @"public_key": @"abcdefg", @"signatures": @{ @@ -382,7 +382,7 @@ - (void)testPrepareKeyBackupVersion [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { XCTAssertNotNil(keyBackupCreationInfo); - XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoMegolmBackupAlgorithm); + XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); XCTAssertNotNil(keyBackupCreationInfo.authData.publicKey); XCTAssertNotNil(keyBackupCreationInfo.authData.signatures); XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); @@ -409,7 +409,7 @@ - (void)testCreateKeyBackupVersion [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { - XCTAssertEqualObjects(keyBackupVersion.algorithm, kMXCryptoMegolmBackupAlgorithm); + XCTAssertEqualObjects(keyBackupVersion.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); XCTAssertEqualObjects(keyBackupVersion.authData, keyBackupCreationInfo.authData.JSONDictionary); XCTAssertNotNil(keyBackupVersion.version); From 380012b7bfdf6cccf5f400e5d5daa87c4db87797 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 17:23:16 +0300 Subject: [PATCH 04/65] Define `MXBaseKeyBackupAuthData` protocol and implement for different algorithms --- .../Data/Aes256/MXAes256BackupAuthData.h | 41 +++++++++ .../Data/Aes256/MXAes256BackupAuthData.m | 88 +++++++++++++++++++ .../MXCurve25519BackupAuthData.h} | 28 +----- .../MXCurve25519BackupAuthData.m} | 10 ++- .../KeyBackup/Data/MXBaseKeyBackupAuthData.h | 58 ++++++++++++ .../Data/MXMegolmBackupCreationInfo.h | 8 +- MatrixSDK/JSONModels/MXJSONModels.h | 1 - 7 files changed, 201 insertions(+), 33 deletions(-) create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m rename MatrixSDK/Crypto/KeyBackup/Data/{MXMegolmBackupAuthData.h => Curve25519/MXCurve25519BackupAuthData.h} (55%) rename MatrixSDK/Crypto/KeyBackup/Data/{MXMegolmBackupAuthData.m => Curve25519/MXCurve25519BackupAuthData.m} (87%) create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h new file mode 100644 index 0000000000..6f01b8f1de --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h @@ -0,0 +1,41 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +#import "MXJSONModel.h" +#import "MXBaseKeyBackupAuthData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Data model for MXKeyBackupVersion.authData in case of kMXCryptoAes256KeyBackupAlgorithm. + */ +@interface MXAes256BackupAuthData : MXJSONModel + +/** + The identity vector used to encrypt the backups. + */ +@property (nonatomic, nullable) NSString *iv; + +/** + The mac used to encrypt the backups. + */ +@property (nonatomic, nullable) NSString *mac; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m new file mode 100644 index 0000000000..d25d1cfe99 --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m @@ -0,0 +1,88 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXAes256BackupAuthData.h" + +@implementation MXAes256BackupAuthData + +@synthesize privateKeySalt = _privateKeySalt; +@synthesize privateKeyIterations = _privateKeyIterations; +@synthesize signatures = _signatures; + +#pragma mark - MXJSONModel + ++ (id)modelFromJSON:(NSDictionary *)JSONDictionary +{ + MXAes256BackupAuthData *megolmBackupAuthData = [MXAes256BackupAuthData new]; + if (megolmBackupAuthData) + { + MXJSONModelSetString(megolmBackupAuthData.iv, JSONDictionary[@"iv"]); + MXJSONModelSetString(megolmBackupAuthData.mac, JSONDictionary[@"mac"]); + MXJSONModelSetString(megolmBackupAuthData.privateKeySalt, JSONDictionary[@"private_key_salt"]); + MXJSONModelSetUInteger(megolmBackupAuthData.privateKeyIterations, JSONDictionary[@"private_key_iterations"]); + MXJSONModelSetDictionary(megolmBackupAuthData.signatures, JSONDictionary[@"signatures"]); + } + + return megolmBackupAuthData; +} + +- (NSDictionary *)JSONDictionary +{ + NSMutableDictionary *JSONDictionary = [NSMutableDictionary dictionary]; + + JSONDictionary[@"iv"] = _iv; + + JSONDictionary[@"mac"] = _mac; + + if (_privateKeySalt) + { + JSONDictionary[@"private_key_salt"] = _privateKeySalt; + } + + if (_privateKeySalt) + { + JSONDictionary[@"private_key_iterations"] = @(_privateKeyIterations); + } + + if (_signatures) + { + JSONDictionary[@"signatures"] = _signatures; + } + + return JSONDictionary; +} + +- (NSDictionary *)signalableJSONDictionary +{ + NSMutableDictionary *signalableJSONDictionary = [NSMutableDictionary dictionary]; + + signalableJSONDictionary[@"iv"] = _iv; + signalableJSONDictionary[@"mac"] = _mac; + + if (_privateKeySalt) + { + signalableJSONDictionary[@"private_key_salt"] = _privateKeySalt; + } + + if (_privateKeySalt) + { + signalableJSONDictionary[@"private_key_iterations"] = @(_privateKeyIterations); + } + + return signalableJSONDictionary; +} + +@end diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupAuthData.h b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h similarity index 55% rename from MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupAuthData.h rename to MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h index bd3237fca4..aaa354b316 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupAuthData.h +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h @@ -17,42 +17,20 @@ #import #import "MXJSONModel.h" +#import "MXBaseKeyBackupAuthData.h" NS_ASSUME_NONNULL_BEGIN /** - Data model for MXKeyBackupVersion.authData in case of kMXCryptoMegolmBackupAlgorithm. + Data model for MXKeyBackupVersion.authData in case of kMXCryptoCurve25519KeyBackupAlgorithm. */ -@interface MXMegolmBackupAuthData : MXJSONModel +@interface MXCurve25519BackupAuthData : MXJSONModel /** The curve25519 public key used to encrypt the backups. */ @property (nonatomic) NSString *publicKey; -/** - In case of a backup created from a password, the salt associated with the backup - private key. - */ -@property (nonatomic, nullable) NSString *privateKeySalt; - -/** - In case of a backup created from a password, the number of key derivations. - */ -@property (nonatomic) NSUInteger privateKeyIterations; - -/** - Signatures of the public key. - userId -> (deviceSignKeyId -> signature) - */ -@property (nonatomic) NSDictionary *signatures; - -/** - Same as the parent [MXJSONModel JSONDictionary] but return only - data that must be signed. - */ -@property (nonatomic, readonly) NSDictionary *signalableJSONDictionary; - @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupAuthData.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m similarity index 87% rename from MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupAuthData.m rename to MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m index 46db64482a..c70d62f59b 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupAuthData.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m @@ -14,15 +14,19 @@ limitations under the License. */ -#import "MXMegolmBackupAuthData.h" +#import "MXCurve25519BackupAuthData.h" -@implementation MXMegolmBackupAuthData +@implementation MXCurve25519BackupAuthData + +@synthesize privateKeySalt = _privateKeySalt; +@synthesize privateKeyIterations = _privateKeyIterations; +@synthesize signatures = _signatures; #pragma mark - MXJSONModel + (id)modelFromJSON:(NSDictionary *)JSONDictionary { - MXMegolmBackupAuthData *megolmBackupAuthData = [MXMegolmBackupAuthData new]; + MXCurve25519BackupAuthData *megolmBackupAuthData = [MXCurve25519BackupAuthData new]; if (megolmBackupAuthData) { MXJSONModelSetString(megolmBackupAuthData.publicKey, JSONDictionary[@"public_key"]); diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h b/MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h new file mode 100644 index 0000000000..e33cf156e6 --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h @@ -0,0 +1,58 @@ +// +// Copyright 2022 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 + +#ifndef MXBaseKeyBackupAuthData_h +#define MXBaseKeyBackupAuthData_h + +NS_ASSUME_NONNULL_BEGIN + +@protocol MXBaseKeyBackupAuthData + +/** + In case of a backup created from a password, the salt associated with the backup + private key. + */ +@property (nonatomic, nullable) NSString *privateKeySalt; + +/** + In case of a backup created from a password, the number of key derivations. + */ +@property (nonatomic) NSUInteger privateKeyIterations; + +/** + Signatures of the public key. + userId -> (deviceSignKeyId -> signature) + */ +@property (nonatomic) NSDictionary *signatures; + +/** + Same as [MXJSONModel JSONDictionary]. + */ +@property (nonatomic, readonly) NSDictionary *JSONDictionary; + +/** + Same as the parent [MXJSONModel JSONDictionary] but return only + data that must be signed. + */ +@property (nonatomic, readonly) NSDictionary *signalableJSONDictionary; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* MXBaseKeyBackupAuthData_h */ diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupCreationInfo.h b/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupCreationInfo.h index 334c337005..09df7f533d 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupCreationInfo.h +++ b/MatrixSDK/Crypto/KeyBackup/Data/MXMegolmBackupCreationInfo.h @@ -16,7 +16,7 @@ #import -#import "MXMegolmBackupAuthData.h" +@protocol MXBaseKeyBackupAuthData; NS_ASSUME_NONNULL_BEGIN @@ -27,14 +27,14 @@ NS_ASSUME_NONNULL_BEGIN @interface MXMegolmBackupCreationInfo : NSObject /** - The algorithm used for storing backups (kMXCryptoMegolmBackupAlgorithm). + The algorithm used for storing backups. */ @property (nonatomic) NSString *algorithm; /** - Authentication data. + Algorthm-dependent authentication data. */ -@property (nonatomic) MXMegolmBackupAuthData *authData; +@property (nonatomic) id authData; /** The Base58 recovery key. diff --git a/MatrixSDK/JSONModels/MXJSONModels.h b/MatrixSDK/JSONModels/MXJSONModels.h index 5784d4a213..e79bc194ee 100644 --- a/MatrixSDK/JSONModels/MXJSONModels.h +++ b/MatrixSDK/JSONModels/MXJSONModels.h @@ -21,7 +21,6 @@ #import "MXUsersDevicesMap.h" #import "MXKeyBackupVersion.h" #import "MXKeyBackupData.h" -#import "MXMegolmBackupAuthData.h" #import "MXLoginTerms.h" #import "MXWellKnown.h" #import "MXCrossSigningInfo.h" From c413c23bb01e3eb1a2fcebda653b7f67e2b381fb Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 17:24:25 +0300 Subject: [PATCH 05/65] Add `untrusted` field to megolm session data --- MatrixSDK/Crypto/Data/MXMegolmSessionData.h | 10 ++++++ MatrixSDK/Crypto/Data/MXMegolmSessionData.m | 38 ++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/MatrixSDK/Crypto/Data/MXMegolmSessionData.h b/MatrixSDK/Crypto/Data/MXMegolmSessionData.h index 3fa74cf60d..b1695e56b3 100644 --- a/MatrixSDK/Crypto/Data/MXMegolmSessionData.h +++ b/MatrixSDK/Crypto/Data/MXMegolmSessionData.h @@ -67,4 +67,14 @@ */ @property NSString *algorithm; +/** + Flag indicating that this session data is untrusted. + */ +@property (getter=isUntrusted) BOOL untrusted; + +/** + Check the data fields before encryption, to see whether it contains required fields or not. + */ +- (BOOL)checkFieldsBeforeEncryption; + @end diff --git a/MatrixSDK/Crypto/Data/MXMegolmSessionData.m b/MatrixSDK/Crypto/Data/MXMegolmSessionData.m index bc0e5d9805..f2ed48e9cd 100644 --- a/MatrixSDK/Crypto/Data/MXMegolmSessionData.m +++ b/MatrixSDK/Crypto/Data/MXMegolmSessionData.m @@ -36,6 +36,15 @@ + (id)modelFromJSON:(NSDictionary *)JSONDictionary } MXJSONModelSetString(sessionData.algorithm, JSONDictionary[@"algorithm"]); MXJSONModelSetArray(sessionData.forwardingCurve25519KeyChain, JSONDictionary[@"forwarding_curve25519_key_chain"]) + if (JSONDictionary[@"untrusted"]) + { + MXJSONModelSetBoolean(sessionData.untrusted, JSONDictionary[@"untrusted"]); + } + else + { + // if "untrusted" is omitted, mark it as trusted + sessionData.untrusted = NO; + } } return sessionData; @@ -51,8 +60,35 @@ - (NSDictionary *)JSONDictionary @"session_key":_sessionKey, kMXSharedHistoryKeyName: @(_sharedHistory), @"algorithm": _algorithm, - @"forwarding_curve25519_key_chain": _forwardingCurve25519KeyChain ? _forwardingCurve25519KeyChain : @[] + @"forwarding_curve25519_key_chain": _forwardingCurve25519KeyChain ?: @[], + @"untrusted": @(_untrusted) }; } +- (BOOL)checkFieldsBeforeEncryption +{ + if (!_algorithm) + { + MXLogDebug(@"[MXMegolmSessionData] checkFieldsBeforeEncryption: missing algorithm"); + return NO; + } + if (!_senderKey) + { + MXLogDebug(@"[MXMegolmSessionData] checkFieldsBeforeEncryption: missing senderKey"); + return NO; + } + if (!_senderClaimedKeys) + { + MXLogDebug(@"[MXMegolmSessionData] checkFieldsBeforeEncryption: missing senderClaimedKeys"); + return NO; + } + if (!_sessionKey) + { + MXLogDebug(@"[MXMegolmSessionData] checkFieldsBeforeEncryption: missing sessionKey"); + return NO; + } + + return YES; +} + @end From d9730fec78c76c8f5a2f594d406edda251aaac3f Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 17:46:40 +0300 Subject: [PATCH 06/65] Define key backup algorithm interface --- .../Data/MXKeyBackupPreparationInfo.h | 38 ++++++++ .../Data/MXKeyBackupPreparationInfo.m | 39 +++++++++ .../Crypto/KeyBackup/MXKeyBackupAlgorithm.h | 86 +++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.h create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.m create mode 100644 MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.h b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.h new file mode 100644 index 0000000000..48483f6b01 --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.h @@ -0,0 +1,38 @@ +// +// Copyright 2022 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 +#import "MXBaseKeyBackupAuthData.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Preparation info for a key backup algorithm +@interface MXKeyBackupPreparationInfo : NSObject + +/// Generated private key +@property (nonatomic, readonly) NSData *privateKey; + +/// Generated auth data +@property (nonatomic, readonly) id authData; + +/// Initializer +/// @param privateKey private key +/// @param authData auth data +- (instancetype)initWithPrivateKey:(NSData*)privateKey authData:(id)authData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.m b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.m new file mode 100644 index 0000000000..a6b0b1a24d --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupPreparationInfo.m @@ -0,0 +1,39 @@ +// +// Copyright 2022 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 "MXKeyBackupPreparationInfo.h" + +@interface MXKeyBackupPreparationInfo () + +@property (nonatomic, readwrite) NSData *privateKey; + +@property (nonatomic, readwrite) id authData; + +@end + +@implementation MXKeyBackupPreparationInfo + +- (instancetype)initWithPrivateKey:(NSData*)privateKey authData:(id)authData +{ + if (self = [super init]) + { + self.privateKey = privateKey; + self.authData = authData; + } + return self; +} + +@end diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h new file mode 100644 index 0000000000..36618a6814 --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h @@ -0,0 +1,86 @@ +// +// Copyright 2022 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 "MXBaseKeyBackupAuthData.h" +#import "MXKeyBackupPreparationInfo.h" + +@class MXKeyBackupData; +@class MXOlmInboundGroupSession; +@class MXMegolmSessionData; +@class MXCrypto; +@class MXKeyBackupVersion; + +#ifndef MXKeyBackupAlgorithm_h +#define MXKeyBackupAlgorithm_h + +NS_ASSUME_NONNULL_BEGIN + +/// Block to get a private key to be called when required +typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); + +/// Protocol defining an algorithm for key backup operations. +@protocol MXKeyBackupAlgorithm + +/// Name of the algorithm. Constants defined in `MXCryptoConstants`. +@property (class, nonatomic, readonly) NSString *algorithName; + +/// Flag indicating the algorithm is untrusted or not. +@property (nonatomic, readonly, getter=isUntrusted) BOOL untrusted; + + +/// Initializer. Returns nil if the given auth data is invalid. +/// @param crypto crypto instance +/// @param authData auth data instance +/// @param keyGetterBlock block to be called when private key is required. +- (nullable instancetype)initWithCrypto:(MXCrypto*)crypto + authData:(id)authData + keyGetterBlock:(MXKeyBackupPrivateKeyGetterBlock)keyGetterBlock; + +/// Prepare a private key and auth data for a given password for the algorithm. Returns a preparation info if successful, otherwise returns nil. +/// @param password password to use +/// @param error error instance to be set on errors ++ (nullable MXKeyBackupPreparationInfo*)prepareWith:(NSString*)password error:(NSError *__autoreleasing _Nullable *)error; + +/// Method to check a private key against receiver's internal auth data (the one given at initialization) +/// @param privateKey private key to check +/// @param error error instance to be set on errors +- (BOOL)keyMatches:(NSData*)privateKey error:(NSError *__autoreleasing _Nullable *)error; + +/// Method to check a private key against a given auth data +/// @param privateKey private key to check +/// @param authData auth data to check against +/// @param error error instance to be set on errors ++ (BOOL)keyMatches:(NSData*)privateKey withAuthData:(NSDictionary*)authData error:(NSError *__autoreleasing _Nullable *)error; + +/// Encrypt group session with the receiver algorithm. +/// @param session session instance to encrypt. +- (nullable MXKeyBackupData*)encryptGroupSession:(MXOlmInboundGroupSession*)session; + +/// Decrypt key backup data +/// @param keyBackupData key backup data +/// @param sessionId session id to use +/// @param roomId room id to use +- (nullable MXMegolmSessionData*)decryptKeyBackupData:(MXKeyBackupData*)keyBackupData forSession:(NSString*)sessionId inRoom:(NSString*)roomId; + +/// Method to check the algorithm against a given key backup version +/// @param backupVersion key backup version to check against ++ (BOOL)checkBackupVersion:(MXKeyBackupVersion *)backupVersion; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* MXKeyBackupAlgorithm_h */ From 68b97b56e8c77a8010f181efcae3f41afa3d5002 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 18:03:31 +0300 Subject: [PATCH 07/65] Make aes-hmac-sha2 encryption methods from `MXSecretStorage` available in SDK --- .../Crypto/SecretStorage/MXSecretStorage_Private.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MatrixSDK/Crypto/SecretStorage/MXSecretStorage_Private.h b/MatrixSDK/Crypto/SecretStorage/MXSecretStorage_Private.h index 34383ebf23..8e565a6c87 100644 --- a/MatrixSDK/Crypto/SecretStorage/MXSecretStorage_Private.h +++ b/MatrixSDK/Crypto/SecretStorage/MXSecretStorage_Private.h @@ -17,6 +17,7 @@ #import "MXSecretStorage.h" @class MXSession; +@class MXEncryptedSecretContent; NS_ASSUME_NONNULL_BEGIN @@ -29,6 +30,15 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithMatrixSession:(MXSession *)mxSession processingQueue:(dispatch_queue_t)processingQueue; +- (nullable MXEncryptedSecretContent *)encryptedZeroStringWithPrivateKey:(NSData*)privateKey iv:(nullable NSData*)iv error:(NSError**)error; + +- (nullable MXEncryptedSecretContent *)encryptSecret:(NSString*)unpaddedBase64Secret withSecretId:(nullable NSString*)secretId privateKey:(NSData*)privateKey iv:(nullable NSData*)iv error:(NSError**)error; + +- (nullable NSString *)decryptSecretWithSecretId:(NSString*)secretId + secretContent:(MXEncryptedSecretContent*)secretContent + withPrivateKey:(NSData*)privateKey + error:(NSError**)error; + @end NS_ASSUME_NONNULL_END From ed141cc406077113b146819c9621e0d529b8d85a Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 18:04:09 +0300 Subject: [PATCH 08/65] Implement algorithms --- .../Data/Aes256/MXAes256KeyBackupAlgorithm.h | 26 ++ .../Data/Aes256/MXAes256KeyBackupAlgorithm.m | 276 ++++++++++++++++++ .../MXCurve25519KeyBackupAlgorithm.h | 26 ++ .../MXCurve25519KeyBackupAlgorithm.m | 234 +++++++++++++++ 4 files changed, 562 insertions(+) create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.h create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.h create mode 100644 MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.h new file mode 100644 index 0000000000..ab29b8879e --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.h @@ -0,0 +1,26 @@ +// +// Copyright 2022 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 +#import "MXKeyBackupAlgorithm.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MXAes256KeyBackupAlgorithm : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m new file mode 100644 index 0000000000..191ac2ba16 --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -0,0 +1,276 @@ +// +// Copyright 2022 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 "MXAes256KeyBackupAlgorithm.h" +#import "MXKeyBackup_Private.h" + +#import "MXCrypto_Private.h" + +#import +#import "MXRecoveryKey.h" +#import "MXKeyBackupPassword.h" +#import "MXSession.h" +#import "MXTools.h" +#import "MXBase64Tools.h" +#import "MXError.h" +#import "MXKeyProvider.h" +#import "MXRawDataKey.h" +#import "MXCrossSigning_Private.h" +#import "MXSharedHistoryKeyService.h" +#import "MXAes256BackupAuthData.h" +#import "MXAes.h" +#import "MatrixSDKSwiftHeader.h" +#import "MXSecretStorage_Private.h" +#import "MXEncryptedSecretContent.h" + +@interface MXAes256KeyBackupAlgorithm () + +@property (nonatomic, strong) MXCrypto *crypto; + +@property (nonatomic, strong) MXAes256BackupAuthData *authData; + +@property (nonatomic, copy) NSData *privateKey; + +@end + +@implementation MXAes256KeyBackupAlgorithm + ++ (NSString *)algorithName +{ + return kMXCryptoAes256KeyBackupAlgorithm; +} + +- (instancetype)initWithCrypto:(MXCrypto *)crypto authData:(id)authData keyGetterBlock:(nonnull MXKeyBackupPrivateKeyGetterBlock)keyGetterBlock +{ + if (self = [super init]) + { + if (authData == nil || ![authData isKindOfClass:MXAes256BackupAuthData.class]) + { + MXLogError(@"[MXAes256KeyBackupAlgorithm] init: auth data missing required information"); + return nil; + } + NSData *privateKey = keyGetterBlock(); + if (!privateKey) + { + MXLogError(@"[MXAes256KeyBackupAlgorithm] init: missing private key"); + return nil; + } + if (![self.class keyMatches:privateKey withAuthData:authData.JSONDictionary error:nil]) + { + MXLogError(@"[MXAes256KeyBackupAlgorithm] init: Private key does not match"); + return nil; + } + self.crypto = crypto; + NSParameterAssert([authData isKindOfClass:MXAes256BackupAuthData.class]); + self.authData = (MXAes256BackupAuthData *)authData; + self.privateKey = privateKey; + } + return self; +} + ++ (MXKeyBackupPreparationInfo *)prepareWith:(NSString*)password error:(NSError *__autoreleasing _Nullable *)error +{ + NSString *salt; + NSUInteger iterations; + NSData *privateKey = [MXKeyBackupPassword generatePrivateKeyWithPassword:password salt:&salt iterations:&iterations error:error]; + + if (*error) + { + MXLogError(@"[MXAes256KeyBackupAlgorithm] prepare: error: %@", *error); + return nil; + } + + MXAes256BackupAuthData *authData = [MXAes256BackupAuthData new]; + authData.privateKeySalt = salt; + authData.privateKeyIterations = iterations; + + MXEncryptedSecretContent *outSecret = [self.class calculateKeyCheck:privateKey iv:nil]; + authData.iv = outSecret.iv; + authData.mac = outSecret.mac; + + return [[MXKeyBackupPreparationInfo alloc] initWithPrivateKey:privateKey authData:authData]; +} + +- (BOOL)keyMatches:(NSData *)privateKey error:(NSError *__autoreleasing _Nullable *)error +{ + return [self.class keyMatches:privateKey withAuthData:_authData.JSONDictionary error:error]; +} + ++ (BOOL)keyMatches:(NSData *)privateKey withAuthData:(NSDictionary *)authData error:(NSError *__autoreleasing _Nullable *)error +{ + if (authData[@"mac"]) + { + MXEncryptedSecretContent *encrypted = [self.class calculateKeyCheck:privateKey iv:authData[@"iv"]]; + + // MACs should match + // Compare bytes instead of base64 strings to avoid base64 padding issue + NSData *authDataMac = [MXBase64Tools dataFromBase64:authData[@"mac"]]; + NSData *encryptedMac = encrypted.mac ? [MXBase64Tools dataFromBase64:encrypted.mac] : nil; + + return [authDataMac isEqualToData:encryptedMac]; + } + else + { + // if we have no information, we have to assume the key is right + return YES; + } +} + +- (BOOL)isUntrusted +{ + return NO; +} + +- (MXKeyBackupData *)encryptGroupSession:(MXOlmInboundGroupSession *)session +{ + // Build the m.megolm_backup.v1.aes-hmac-sha2 data as defined at + // https://github.com/uhoreg/matrix-doc/blob/symmetric-backups/proposals/3270-symmetric-megolm-backup.md#encryption + MXMegolmSessionData *sessionData = session.exportSessionData; + if (![sessionData checkFieldsBeforeEncryption]) + { + MXLogDebug(@"[MXAes256KeyBackupAlgorithm] encryptGroupSession: Error: Invalid MXMegolmSessionData for %@", session.senderKey); + return nil; + } + + BOOL sharedHistory = MXSDKOptions.sharedInstance.enableRoomSharedHistoryOnInvite && sessionData.sharedHistory; + NSDictionary *sessionBackupData = @{ + @"algorithm": sessionData.algorithm, + @"sender_key": sessionData.senderKey, + @"sender_claimed_keys": sessionData.senderClaimedKeys, + @"forwarding_curve25519_key_chain": sessionData.forwardingCurve25519KeyChain ?: @[], + @"session_key": sessionData.sessionKey, + kMXSharedHistoryKeyName: @(sharedHistory), + @"untrusted": @(sessionData.isUntrusted) + }; + + MXSecretStorage *storage = [[MXSecretStorage alloc] init]; + NSString *secret = [MXTools serialiseJSONObject:sessionBackupData]; + + NSError *error; + MXEncryptedSecretContent *encryptedSessionBackupData = [storage encryptSecret:secret + withSecretId:session.session.sessionIdentifier + privateKey:_privateKey + iv:nil + error:&error]; + + if (![self checkEncryptedSecretContent:encryptedSessionBackupData]) + { + MXLogDebug(@"[MXAes256KeyBackupAlgorithm] encryptGroupSession: Error: Invalid MXEncryptedSecretContent for %@", session.senderKey); + return nil; + } + + // Gather information for each key + MXDeviceInfo *device = [_crypto.deviceList deviceWithIdentityKey:session.senderKey andAlgorithm:kMXCryptoMegolmAlgorithm]; + + // Build backup data for that key + MXKeyBackupData *keyBackupData = [MXKeyBackupData new]; + keyBackupData.firstMessageIndex = session.session.firstKnownIndex; + keyBackupData.forwardedCount = session.forwardingCurve25519KeyChain.count; + keyBackupData.verified = device ? device.trustLevel.isVerified : NO; + keyBackupData.sessionData = @{ + @"ciphertext": encryptedSessionBackupData.ciphertext, + @"mac": encryptedSessionBackupData.mac, + @"iv": encryptedSessionBackupData.iv, + }; + + return keyBackupData; +} + +- (MXMegolmSessionData *)decryptKeyBackupData:(MXKeyBackupData *)keyBackupData forSession:(NSString *)sessionId inRoom:(NSString *)roomId +{ + MXMegolmSessionData *sessionData; + + MXEncryptedSecretContent *encryptedSecret = [MXEncryptedSecretContent new]; + + MXJSONModelSetString(encryptedSecret.ciphertext, keyBackupData.sessionData[@"ciphertext"]); + MXJSONModelSetString(encryptedSecret.mac, keyBackupData.sessionData[@"mac"]); + MXJSONModelSetString(encryptedSecret.iv, keyBackupData.sessionData[@"iv"]); + + if ([self checkEncryptedSecretContent:encryptedSecret]) + { + MXSecretStorage *secretStorage = [MXSecretStorage new]; + + NSError *error; + NSString *text = [secretStorage decryptSecretWithSecretId:sessionId secretContent:encryptedSecret withPrivateKey:_privateKey error:&error]; + + if (!error) + { + NSDictionary *sessionBackupData = [MXTools deserialiseJSONString:text]; + + if (sessionBackupData) + { + MXJSONModelSetMXJSONModel(sessionData, MXMegolmSessionData, sessionBackupData); + + sessionData.sessionId = sessionId; + sessionData.roomId = roomId; + } + } + else + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] decryptKeyBackupData: Failed to decrypt session from backup. Error: %@", error); + } + } + + return sessionData; +} + ++ (BOOL)checkBackupVersion:(MXKeyBackupVersion *)backupVersion +{ + NSString *iv = backupVersion.authData[@"iv"]; + NSString *mac = backupVersion.authData[@"mac"]; + return iv != nil && mac != nil; +} + +#pragma mark - Private + +// Sanity checks on MXEncryptedSecretContent +- (BOOL)checkEncryptedSecretContent:(MXEncryptedSecretContent*)encryptedSecret +{ + if (!encryptedSecret.ciphertext) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkEncryptedSecretContent: missing ciphertext"); + return NO; + } + if (!encryptedSecret.mac) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkEncryptedSecretContent: missing mac"); + return NO; + } + if (!encryptedSecret.iv) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkEncryptedSecretContent: missing iv"); + return NO; + } + + return YES; +} + +/// Calculate the MAC for checking the key. +/// @param key the key to use +/// @param iv The initialization vector as a base64-encoded string. If not provided, a random initialization vector will be created. ++ (MXEncryptedSecretContent *)calculateKeyCheck:(NSData *)key iv:(NSString *)iv +{ + MXSecretStorage *storage = [[MXSecretStorage alloc] init]; + NSData *ivData = [MXBase64Tools dataFromBase64:iv]; + if (ivData.length == 0) + { + ivData = nil; + } + NSError *error; + return [storage encryptedZeroStringWithPrivateKey:key iv:ivData error:&error]; +} + +@end diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.h new file mode 100644 index 0000000000..d9eb3de215 --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.h @@ -0,0 +1,26 @@ +// +// Copyright 2022 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 +#import "MXKeyBackupAlgorithm.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MXCurve25519KeyBackupAlgorithm : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m new file mode 100644 index 0000000000..8f5cce8556 --- /dev/null +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m @@ -0,0 +1,234 @@ +// +// Copyright 2022 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 "MXCurve25519KeyBackupAlgorithm.h" +#import "MXKeyBackup_Private.h" + +#import "MXCrypto_Private.h" + +#import +#import "MXRecoveryKey.h" +#import "MXKeyBackupPassword.h" +#import "MXSession.h" +#import "MXTools.h" +#import "MXBase64Tools.h" +#import "MXError.h" +#import "MXKeyProvider.h" +#import "MXRawDataKey.h" +#import "MXCrossSigning_Private.h" +#import "MXSharedHistoryKeyService.h" + +@interface MXCurve25519KeyBackupAlgorithm () + +@property (nonatomic, strong) MXCrypto *crypto; + +/** + The backup key being used. + */ +@property (nonatomic, nullable) OLMPkEncryption *backupKey; + +@property (nonatomic, strong) MXCurve25519BackupAuthData *authData; + +@property (nonatomic, copy) MXKeyBackupPrivateKeyGetterBlock keyGetterBlock; + +@end + +@implementation MXCurve25519KeyBackupAlgorithm + ++ (NSString *)algorithName +{ + return kMXCryptoCurve25519KeyBackupAlgorithm; +} + +- (instancetype)initWithCrypto:(nonnull MXCrypto *)crypto + authData:(nonnull id)authData + keyGetterBlock:(nonnull MXKeyBackupPrivateKeyGetterBlock)keyGetterBlock +{ + if (self = [super init]) + { + if (authData == nil || ![authData isKindOfClass:MXCurve25519BackupAuthData.class] || ((MXCurve25519BackupAuthData *)authData).publicKey == nil) + { + MXLogError(@"[MXCurve25519KeyBackupAlgorithm] init: auth data missing required information"); + return nil; + } + self.crypto = crypto; + self.authData = (MXCurve25519BackupAuthData *)authData; + self.backupKey = [OLMPkEncryption new]; + [self.backupKey setRecipientKey:self.authData.publicKey]; + self.keyGetterBlock = keyGetterBlock; + } + return self; +} + ++ (MXKeyBackupPreparationInfo *)prepareWith:(NSString*)password error:(NSError *__autoreleasing _Nullable *)error +{ + OLMPkDecryption *decryption = [OLMPkDecryption new]; + NSString *salt; + NSUInteger iterations; + NSData *privateKey = [MXKeyBackupPassword generatePrivateKeyWithPassword:password salt:&salt iterations:&iterations error:error]; + + MXCurve25519BackupAuthData *authData = [MXCurve25519BackupAuthData new]; + authData.privateKeySalt = salt; + authData.privateKeyIterations = iterations; + authData.publicKey = [decryption setPrivateKey:privateKey error:error]; + + if (*error) + { + MXLogError(@"[MXCurve25519KeyBackupAlgorithm] prepare: error: %@", *error); + return nil; + } + return [[MXKeyBackupPreparationInfo alloc] initWithPrivateKey:decryption.privateKey authData:authData]; +} + +- (BOOL)keyMatches:(NSData *)privateKey error:(NSError *__autoreleasing _Nullable *)error +{ + return [self.class keyMatches:privateKey withAuthData:_authData.JSONDictionary error:error]; +} + ++ (BOOL)keyMatches:(NSData *)privateKey withAuthData:(NSDictionary *)authData error:(NSError *__autoreleasing _Nullable *)error +{ + // Built the PK decryption with it + OLMPkDecryption *decryption = [OLMPkDecryption new]; + NSString *publicKey = [decryption setPrivateKey:privateKey error:error]; + + return [publicKey isEqualToString:authData[@"public_key"]]; +} + +- (BOOL)isUntrusted +{ + return YES; +} + +- (MXKeyBackupData *)encryptGroupSession:(MXOlmInboundGroupSession *)session +{ + // Build the m.megolm_backup.v1.curve25519-aes-sha2 data as defined at + // https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md#mmegolm_backupv1curve25519-aes-sha2-key-format + MXMegolmSessionData *sessionData = session.exportSessionData; + if (![sessionData checkFieldsBeforeEncryption]) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] encryptGroupSession: Error: Invalid MXMegolmSessionData for %@", session.senderKey); + return nil; + } + + BOOL sharedHistory = MXSDKOptions.sharedInstance.enableRoomSharedHistoryOnInvite && sessionData.sharedHistory; + NSDictionary *sessionBackupData = @{ + @"algorithm": sessionData.algorithm, + @"sender_key": sessionData.senderKey, + @"sender_claimed_keys": sessionData.senderClaimedKeys, + @"forwarding_curve25519_key_chain": sessionData.forwardingCurve25519KeyChain ? sessionData.forwardingCurve25519KeyChain : @[], + @"session_key": sessionData.sessionKey, + kMXSharedHistoryKeyName: @(sharedHistory) + }; + OLMPkMessage *encryptedSessionBackupData = [_backupKey encryptMessage:[MXTools serialiseJSONObject:sessionBackupData] error:nil]; + if (![self checkOLMPkMessage:encryptedSessionBackupData]) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] encryptGroupSession: Error: Invalid OLMPkMessage for %@", session.senderKey); + return nil; + } + + // Gather information for each key + MXDeviceInfo *device = [_crypto.deviceList deviceWithIdentityKey:session.senderKey andAlgorithm:kMXCryptoMegolmAlgorithm]; + + // Build backup data for that key + MXKeyBackupData *keyBackupData = [MXKeyBackupData new]; + keyBackupData.firstMessageIndex = session.session.firstKnownIndex; + keyBackupData.forwardedCount = session.forwardingCurve25519KeyChain.count; + keyBackupData.verified = device ? device.trustLevel.isVerified : NO; + keyBackupData.sessionData = @{ + @"ciphertext": encryptedSessionBackupData.ciphertext, + @"mac": encryptedSessionBackupData.mac, + @"ephemeral": encryptedSessionBackupData.ephemeralKey, + }; + + return keyBackupData; +} + +- (MXMegolmSessionData *)decryptKeyBackupData:(MXKeyBackupData *)keyBackupData forSession:(NSString *)sessionId inRoom:(NSString *)roomId +{ + MXMegolmSessionData *sessionData; + + NSString *ciphertext, *mac, *ephemeralKey; + + MXJSONModelSetString(ciphertext, keyBackupData.sessionData[@"ciphertext"]); + MXJSONModelSetString(mac, keyBackupData.sessionData[@"mac"]); + MXJSONModelSetString(ephemeralKey, keyBackupData.sessionData[@"ephemeral"]); + + if (ciphertext && mac && ephemeralKey) + { + OLMPkMessage *encrypted = [[OLMPkMessage alloc] initWithCiphertext:ciphertext mac:mac ephemeralKey:ephemeralKey]; + + OLMPkDecryption *decryption = [OLMPkDecryption new]; + NSError *error; + NSData *privateKey = self.keyGetterBlock(); + if (!privateKey) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] decryptKeyBackupData: No private key."); + return nil; + } + [decryption setPrivateKey:privateKey error:&error]; + NSString *text = [decryption decryptMessage:encrypted error:&error]; + + if (!error) + { + NSDictionary *sessionBackupData = [MXTools deserialiseJSONString:text]; + + if (sessionBackupData) + { + MXJSONModelSetMXJSONModel(sessionData, MXMegolmSessionData, sessionBackupData); + + sessionData.sessionId = sessionId; + sessionData.roomId = roomId; + } + } + else + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] decryptKeyBackupData: Failed to decrypt session from backup. Error: %@", error); + } + } + + return sessionData; +} + ++ (BOOL)checkBackupVersion:(MXKeyBackupVersion *)backupVersion +{ + return backupVersion.authData[@"public_key"] != nil; +} + +#pragma mark - Private + +// Sanity checks on OLMPkMessage +- (BOOL)checkOLMPkMessage:(OLMPkMessage*)message +{ + if (!message.ciphertext) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkOLMPkMessage: missing ciphertext"); + return NO; + } + if (!message.mac) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkOLMPkMessage: missing mac"); + return NO; + } + if (!message.ephemeralKey) + { + MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkOLMPkMessage: missing ephemeralKey"); + return NO; + } + + return YES; +} + +@end From f0dc499d76d30b9d761fded95f7ea323221676f3 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 18:04:48 +0300 Subject: [PATCH 09/65] Refactoring on key backup module to use new algorithm implementations --- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h | 8 +- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 574 +++++++++-------------- 2 files changed, 215 insertions(+), 367 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h index 00ade2f34b..87569c4c33 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h @@ -20,7 +20,7 @@ #import "MXMegolmBackupCreationInfo.h" #import "MXKeyBackupVersionTrust.h" -@class OLMPkEncryption; +@protocol MXKeyBackupAlgorithm; NS_ASSUME_NONNULL_BEGIN @@ -140,11 +140,13 @@ FOUNDATION_EXPORT NSString *const kMXKeyBackupDidStateChangeNotification; @param password an optional passphrase string that can be entered by the user when restoring the backup as an alternative to entering the recovery key. + @param algorithm desired algorithm to use. Will fail if provided an unknown algorithm. @param success A block object called when the operation succeeds. @param failure A block object called when the operation fails */ - (void)prepareKeyBackupVersionWithPassword:(nullable NSString *)password + algorithm:(nullable NSString *)algorithm success:(void (^)(MXMegolmBackupCreationInfo *keyBackupCreationInfo))success failure:(nullable void (^)(NSError *error))failure; @@ -394,9 +396,9 @@ FOUNDATION_EXPORT NSString *const kMXKeyBackupDidStateChangeNotification; @property (nonatomic, readonly, nullable) MXKeyBackupVersion *keyBackupVersion; /** - The backup key being used. + The backup algorithm being used. Nil if key backup not enabled yet. */ -@property (nonatomic, readonly, nullable) OLMPkEncryption *backupKey; +@property (nonatomic, readonly, nullable) id keyBackupAlgorithm; /** Indicate if their are keys to backup. diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index 38a79697fa..b225f7ac90 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -30,6 +30,11 @@ #import "MXRawDataKey.h" #import "MXCrossSigning_Private.h" #import "MXSharedHistoryKeyService.h" +#import "MXCurve25519BackupAuthData.h" +#import "MXAes256BackupAuthData.h" +#import "MXKeyBackupAlgorithm.h" +#import "MXCurve25519KeyBackupAlgorithm.h" +#import "MXAes256KeyBackupAlgorithm.h" #pragma mark - Constants definitions @@ -45,6 +50,8 @@ */ NSUInteger const kMXKeyBackupSendKeysMaxCount = 100; +static NSDictionary> *AlgorithmClassesByName; +static Class DefaultAlgorithmClass; @interface MXKeyBackup () { @@ -66,6 +73,15 @@ @implementation MXKeyBackup #pragma mark - SDK-Private methods - ++ (void)initialize +{ + AlgorithmClassesByName = @{ + kMXCryptoCurve25519KeyBackupAlgorithm: MXCurve25519KeyBackupAlgorithm.class, + kMXCryptoAes256KeyBackupAlgorithm: MXAes256KeyBackupAlgorithm.class + }; + DefaultAlgorithmClass = MXCurve25519KeyBackupAlgorithm.class; +} + - (instancetype)initWithCrypto:(MXCrypto *)theCrypto { self = [self init]; @@ -108,7 +124,18 @@ - (void)checkAndStartKeyBackup - (void)checkAndStartWithKeyBackupVersion:(nullable MXKeyBackupVersion*)keyBackupVersion { MXLogDebug(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: %@", keyBackupVersion.version); - + + Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; + if (algorithmClass == NULL) + { + MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: unknown algorithm: %@", keyBackupVersion.algorithm); + return; + } + if (![algorithmClass checkBackupVersion:keyBackupVersion]) + { + MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: invalid backup data returned"); + return; + } self->_keyBackupVersion = keyBackupVersion; if (!self.keyBackupVersion) { @@ -134,11 +161,12 @@ - (void)checkAndStartWithKeyBackupVersion:(nullable MXKeyBackupVersion*)keyBacku // Check private keys if (self.hasPrivateKeyInCryptoStore) { - NSString *pKDecryptionPublicKey = [self pkDecrytionPublicKeyFromCryptoStore]; - - if (![self checkPkDecryptionPublicKey:pKDecryptionPublicKey forKeyBackupVersion:keyBackupVersion]) + NSData *privateKey = self.privateKeyFromCryptoStore; + NSError *error; + BOOL keyMatches = [algorithmClass keyMatches:privateKey withAuthData:keyBackupVersion.authData error:&error]; + if (error || !keyMatches) { - MXLogDebug(@"[MXKeyBackup] -> clean local private key (%@)", pKDecryptionPublicKey); + MXLogDebug(@"[MXKeyBackup] -> clean local private key (%@)", privateKey); [crypto.store deleteSecretWithSecretId:MXSecretId.keyBackup]; } } @@ -169,13 +197,26 @@ - (void)checkAndStartWithKeyBackupVersion:(nullable MXKeyBackupVersion*)keyBacku - (NSError*)enableKeyBackup:(MXKeyBackupVersion*)version { NSError *error; - MXMegolmBackupAuthData *authData = [self megolmBackupAuthDataFromKeyBackupVersion:version error:&error]; + id authData = [self megolmBackupAuthDataFromKeyBackupVersion:version error:&error]; if (!error) { _keyBackupVersion = version; - self->crypto.store.backupVersion = version.version; - _backupKey = [OLMPkEncryption new]; - [_backupKey setRecipientKey:authData.publicKey]; + crypto.store.backupVersion = version.version; + Class algorithmClass = AlgorithmClassesByName[version.algorithm]; + if (algorithmClass == NULL) + { + MXLogError(@"[MXKeyBackup] enableKeyBackup: unknown algorithm: %@", version.algorithm); + error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorUnknownAlgorithm + userInfo:@{ + NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Unknown algorithm (%@) to enable backup", version.algorithm] + }]; + return error; + } + // store the desired backup algorithm + _keyBackupAlgorithm = [[algorithmClass alloc] initWithCrypto:crypto authData:authData keyGetterBlock:^NSData * _Nullable{ + return self.privateKeyFromCryptoStore; + }]; self.state = MXKeyBackupStateReadyToBackUp; @@ -193,7 +234,7 @@ - (void)resetKeyBackupData self->crypto.store.backupVersion = nil; [self->crypto.store deleteSecretWithSecretId:MXSecretId.keyBackup]; - _backupKey = nil; + _keyBackupAlgorithm = nil; // Reset backup markers [self->crypto.store resetBackupMarkers]; @@ -252,7 +293,7 @@ - (void)sendKeyBackup } // Sanity check - if (!self.enabled || !_backupKey || !_keyBackupVersion) + if (!self.enabled || !_keyBackupAlgorithm || !_keyBackupVersion) { MXLogDebug(@"[MXKeyBackup] sendKeyBackup: Invalid state: %@", @(_state)); if (backupAllGroupSessionsFailure) @@ -278,7 +319,7 @@ - (void)sendKeyBackup for (MXOlmInboundGroupSession *session in sessions) { - MXKeyBackupData *keyBackupData = [self encryptGroupSession:session]; + MXKeyBackupData *keyBackupData = [_keyBackupAlgorithm encryptGroupSession:session]; if (keyBackupData) { @@ -405,10 +446,12 @@ - (void)restoreKeyBackupAutomaticallyWithPrivateKey:(void (^)(void))onComplete } // Check private keys validity - NSString *pKDecryptionPublicKey = [self pkDecrytionPublicKeyFromCryptoStore]; - if (![self checkPkDecryptionPublicKey:pKDecryptionPublicKey forKeyBackupVersion:self.keyBackupVersion]) + NSData *privateKey = self.privateKeyFromCryptoStore; + NSError *error; + BOOL keyMatches = [_keyBackupAlgorithm keyMatches:privateKey error:&error]; + if (error || !keyMatches) { - MXLogDebug(@"[MXKeyBackup] restoreKeyBackupAutomatically. Error: Invalid private key (%@)", pKDecryptionPublicKey); + MXLogDebug(@"[MXKeyBackup] restoreKeyBackupAutomatically. Error: Invalid private key (%@)", privateKey); [crypto.store deleteSecretWithSecretId:MXSecretId.keyBackup]; onComplete(); return; @@ -472,6 +515,7 @@ - (MXHTTPOperation *)versionFromCryptoQueue:(NSString *)version success:(void (^ } - (void)prepareKeyBackupVersionWithPassword:(NSString *)password + algorithm:(NSString *)algorithm success:(void (^)(MXMegolmBackupCreationInfo * _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure { @@ -479,31 +523,24 @@ - (void)prepareKeyBackupVersionWithPassword:(NSString *)password dispatch_async(cryptoQueue, ^{ MXStrongifyAndReturnIfNil(self); - OLMPkDecryption *decryption = [OLMPkDecryption new]; - - NSError *error; - __block MXMegolmBackupAuthData *authData = [MXMegolmBackupAuthData new]; - if (password) + Class algorithmClass = algorithm ? AlgorithmClassesByName[algorithm] : DefaultAlgorithmClass; + if (algorithmClass == NULL) { - // Generate a private key from the password - NSString *salt; - NSUInteger iterations; - NSData *privateKey = [MXKeyBackupPassword generatePrivateKeyWithPassword:password - salt:&salt - iterations:&iterations - error:&error]; - if (!error) + if (failure) { - authData.publicKey = [decryption setPrivateKey:privateKey error:&error]; - authData.privateKeySalt = salt; - authData.privateKeyIterations = iterations; + dispatch_async(dispatch_get_main_queue(), ^{ + NSError *error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorUnknownAlgorithm + userInfo:@{ + NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Unknown algorithm (%@) to prepare the backup", algorithm] + }]; + failure(error); + }); } + return; } - else - { - authData.publicKey = [decryption generateKey:&error]; - } - + NSError *error; + MXKeyBackupPreparationInfo *preparationInfo = [algorithmClass prepareWith:password error:&error]; if (error) { if (failure) @@ -514,11 +551,12 @@ - (void)prepareKeyBackupVersionWithPassword:(NSString *)password } return; } + id authData = preparationInfo.authData; MXMegolmBackupCreationInfo *keyBackupCreationInfo = [MXMegolmBackupCreationInfo new]; - keyBackupCreationInfo.algorithm = kMXCryptoMegolmBackupAlgorithm; + keyBackupCreationInfo.algorithm = [algorithmClass algorithName]; keyBackupCreationInfo.authData = authData; - keyBackupCreationInfo.recoveryKey = [MXRecoveryKey encode:decryption.privateKey]; + keyBackupCreationInfo.recoveryKey = [MXRecoveryKey encode:preparationInfo.privateKey]; NSString *myUserId = self->crypto.matrixRestClient.credentials.userId; NSMutableDictionary *signatures = [NSMutableDictionary dictionary]; @@ -875,8 +913,9 @@ - (MXHTTPOperation*)restoreKeyBackup:(MXKeyBackupVersion*)keyBackupVersion // Check if the recovery is valid before going any further NSError *error; - [self isValidRecoveryKey:recoveryKey forKeyBackupVersion:keyBackupVersion error:&error]; - if (error) + BOOL isValidRecoveryKey = [self isValidRecoveryKey:recoveryKey forKeyBackupVersion:keyBackupVersion error:&error]; + NSData *privateKey = [MXRecoveryKey decode:recoveryKey error:&error]; + if (error || !isValidRecoveryKey || !privateKey) { MXLogDebug(@"[MXKeyBackup] restoreKeyBackup: Invalid recovery key. Error: %@", error); if (failure) @@ -888,37 +927,28 @@ - (MXHTTPOperation*)restoreKeyBackup:(MXKeyBackupVersion*)keyBackupVersion return; } - // Get the PK decryption instance - // The operation always succeeds if the recovery key is valid - OLMPkDecryption *decryption = [self pkDecryptionFromRecoveryKey:recoveryKey error:&error]; - if (decryption) - { - MXHTTPOperation *operation2 = [self restoreKeyBackup:keyBackupVersion withPkDecryption:decryption room:roomId session:sessionId success:^(NSUInteger total, NSUInteger imported) { - - // Catch the private key from the recovery key and store it locally - if ([self.keyBackupVersion.version isEqualToString:keyBackupVersion.version]) - { - [self storePrivateKeyWithRecoveryKey:recoveryKey]; - } - - if (success) - { - success(total, imported); - } - } failure:failure]; - [operation mutateTo:operation2]; - } - else if (failure) - { - failure(error); - } + MXHTTPOperation *operation2 = [self restoreKeyBackup:keyBackupVersion withPrivateKey:privateKey room:roomId session:sessionId success:^(NSUInteger total, NSUInteger imported) { + + // Catch the private key from the recovery key and store it locally + if ([self.keyBackupVersion.version isEqualToString:keyBackupVersion.version]) + { + [self storePrivateKeyWithRecoveryKey:recoveryKey]; + } + + if (success) + { + success(total, imported); + } + } failure:failure]; + + [operation mutateTo:operation2]; }); return operation; } - (MXHTTPOperation*)restoreKeyBackup:(MXKeyBackupVersion*)keyBackupVersion - withPkDecryption:(OLMPkDecryption*)decryption + withPrivateKey:(NSData*)privateKey room:(nullable NSString*)roomId session:(nullable NSString*)sessionId success:(nullable void (^)(NSUInteger total, NSUInteger imported))success @@ -939,8 +969,9 @@ - (MXHTTPOperation*)restoreKeyBackup:(MXKeyBackupVersion*)keyBackupVersion { sessionsFromHSCount++; MXKeyBackupData *keyBackupData = keysBackupData.rooms[roomId].sessions[sessionId]; - - MXMegolmSessionData *sessionData = [self decryptKeyBackupData:keyBackupData forSession:sessionId inRoom:roomId withPkDecryption:decryption]; + + id algorithm = [self getOrCreateKeyBackupAlgorithmFor:keyBackupVersion privateKey:privateKey]; + MXMegolmSessionData *sessionData = [algorithm decryptKeyBackupData:keyBackupData forSession:sessionId inRoom:roomId]; if (sessionData) { @@ -1029,38 +1060,28 @@ - (MXHTTPOperation*)restoreUsingPrivateKeyKeyBackup:(MXKeyBackupVersion*)keyBack MXWeakify(self); dispatch_async(cryptoQueue, ^{ MXStrongifyAndReturnIfNil(self); - - // Get the PK decryption instance - OLMPkDecryption *decryption = [self pkDecryptionFromCryptoStore]; - - // Validate the local private key - if (decryption) + + NSData *privateKey = self.privateKeyFromCryptoStore; + NSError *error; + if (error || ![self.keyBackupAlgorithm keyMatches:privateKey error:&error]) { - NSString *pKDecryptionPublicKey = [self pkDecrytionPublicKeyFromCryptoStore]; - if (![self checkPkDecryptionPublicKey:pKDecryptionPublicKey forKeyBackupVersion:keyBackupVersion]) + MXLogDebug(@"[MXKeyBackup] restoreUsingPrivateKeyKeyBackup. Error: Invalid private key (%@) for %@", privateKey, keyBackupVersion); + if (failure) { - MXLogDebug(@"[MXKeyBackup] restoreUsingPrivateKeyKeyBackup. Error: Invalid private key (%@) for %@", pKDecryptionPublicKey, keyBackupVersion); - decryption = nil; + dispatch_async(dispatch_get_main_queue(), ^{ + NSError *error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorInvalidOrMissingLocalPrivateKey + userInfo:@{ + NSLocalizedDescriptionKey: @"Backup: No valid private key" + }]; + failure(error); + }); } } - - if (decryption) - { - // Launch the restore - MXHTTPOperation *operation2 = [self restoreKeyBackup:keyBackupVersion withPkDecryption:decryption room:roomId session:sessionId success:success failure:failure]; - [operation mutateTo:operation2]; - } - else if (failure) - { - dispatch_async(dispatch_get_main_queue(), ^{ - NSError *error = [NSError errorWithDomain:MXKeyBackupErrorDomain - code:MXKeyBackupErrorInvalidOrMissingLocalPrivateKey - userInfo:@{ - NSLocalizedDescriptionKey: @"Backup: No valid private key" - }]; - failure(error); - }); - } + + // Launch the restore + MXHTTPOperation *operation2 = [self restoreKeyBackup:keyBackupVersion withPrivateKey:privateKey room:roomId session:sessionId success:success failure:failure]; + [operation mutateTo:operation2]; }); return operation; @@ -1093,7 +1114,7 @@ - (MXKeyBackupVersionTrust *)trustForKeyBackupVersionFromCryptoQueue:(MXKeyBacku MXKeyBackupVersionTrust *keyBackupVersionTrust = [MXKeyBackupVersionTrust new]; NSError *error; - MXMegolmBackupAuthData *authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:&error]; + id authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:&error]; if (error) { MXLogDebug(@"[MXKeyBackup] trustForKeyBackupVersion: Key backup is absent or missing required data"); @@ -1185,7 +1206,7 @@ - (MXHTTPOperation *)trustKeyBackupVersion:(MXKeyBackupVersion *)keyBackupVersio // Get auth data to update it NSError *error; - MXMegolmBackupAuthData *authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:&error]; + id authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:&error]; if (error) { MXLogDebug(@"[MXKeyBackup] trustKeyBackupVersion:trust: Key backup is missing required data"); @@ -1361,19 +1382,10 @@ - (void)requestPrivateKeysToDeviceIds:(nullable NSArray*)deviceIds - (BOOL)isSecretValid:(NSString*)secret forKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion { - BOOL isSecretValid = NO; - NSData *privateKey = [MXBase64Tools dataFromBase64:secret]; - NSString *pKDecryptionPublicKey = [self pkDecrytionPublicKeyFromPrivateKey:privateKey]; - if ([self checkPkDecryptionPublicKey:pKDecryptionPublicKey forKeyBackupVersion:keyBackupVersion]) - { - isSecretValid = YES; - } - - return isSecretValid; + return [_keyBackupAlgorithm keyMatches:privateKey error:nil]; } - #pragma mark - Backup state - (BOOL)enabled @@ -1389,6 +1401,37 @@ - (BOOL)hasKeysToBackup #pragma mark - Private methods - +- (id)getOrCreateKeyBackupAlgorithmFor:(MXKeyBackupVersion*)keyBackupVersion privateKey:(NSData*)privateKey +{ + if (self.enabled + && [_keyBackupVersion.JSONDictionary isEqualToDictionary:keyBackupVersion.JSONDictionary] + && [self.privateKeyFromCryptoStore isEqualToData:privateKey]) + { + return _keyBackupAlgorithm; + } + Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; + if (algorithmClass == NULL) + { + MXLogError(@"[MXKeyBackup] getOrCreateKeyBackupAlgorithmFor: unknown algorithm: %@", keyBackupVersion.algorithm); + return nil; + } + if (![algorithmClass checkBackupVersion:keyBackupVersion]) + { + MXLogError(@"[MXKeyBackup] getOrCreateKeyBackupAlgorithmFor: invalid backup data returned"); + return nil; + } + NSError *error; + id authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:&error]; + if (error) + { + MXLogError(@"[MXKeyBackup] getOrCreateKeyBackupAlgorithmFor: invalid auth data"); + return nil; + } + return [[algorithmClass.class alloc] initWithCrypto:crypto authData:authData keyGetterBlock:^NSData * _Nullable{ + return privateKey; + }]; +} + - (void)setState:(MXKeyBackupState)state { MXLogDebug(@"[MXKeyBackup] setState: %@ -> %@", @(_state), @(state)); @@ -1465,24 +1508,6 @@ - (OLMPkDecryption*)pkDecryptionFromRecoveryKey:(NSString*)recoveryKey error:(NS return decryption; } -- (NSString*)pkPublicKeyFromRecoveryKey:(NSString*)recoveryKey error:(NSError **)error -{ - NSString *pkPublicKey; - - // Extract the private key - NSData *privateKey = [MXRecoveryKey decode:recoveryKey error:error]; - - // Built the PK decryption with it - OLMPkDecryption *decryption; - if (privateKey) - { - decryption = [OLMPkDecryption new]; - pkPublicKey = [decryption setPrivateKey:privateKey error:error]; - } - - return pkPublicKey; -} - - (void)storePrivateKeyWithRecoveryKey:(NSString*)recoveryKey { NSError *error; @@ -1499,257 +1524,74 @@ - (void)storePrivateKeyWithRecoveryKey:(NSString*)recoveryKey - (nullable NSData*)privateKeyFromCryptoStore { - NSString *privateKeyBase64 = [self->crypto.store secretWithSecretId:MXSecretId.keyBackup]; + NSString *privateKeyBase64 = [crypto.store secretWithSecretId:MXSecretId.keyBackup]; if (!privateKeyBase64) { - MXLogDebug(@"[MXCrossSigning] privateKeyFromCryptoStore. Error: No secret in crypto store"); + MXLogDebug(@"[MXKeyBackup] privateKeyFromCryptoStore. Error: No secret in crypto store"); return nil; } - - return [MXBase64Tools dataFromBase64:privateKeyBase64]; -} - -- (nullable OLMPkDecryption*)pkDecryptionFromCryptoStore -{ - NSData *privateKey = self.privateKeyFromCryptoStore; - - // Built the PK decryption with it - OLMPkDecryption *decryption; - if (privateKey) - { - NSError *error; - decryption = [OLMPkDecryption new]; - [decryption setPrivateKey:privateKey error:&error]; - - if (error) - { - MXLogDebug(@"[MXCrossSigning] pkDecryptionFromCryptoStore failed. Error: %@", error); - } - } - return decryption; + return [MXBase64Tools dataFromBase64:privateKeyBase64]; } -- (nullable NSString*)pkDecrytionPublicKeyFromCryptoStore -{ - NSData *privateKey = self.privateKeyFromCryptoStore; - return [self pkDecrytionPublicKeyFromPrivateKey:privateKey]; -} +/** + Extract megolm back up authentication data from a backup. -- (nullable NSString*)pkDecrytionPublicKeyFromPrivateKey:(NSData*)privateKey + @param keyBackupVersion the key backup + @param error the encountered error in case of failure. + @return the authentication if found and valid. + */ +- (nullable id)megolmBackupAuthDataFromKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion error:(NSError**)error { - NSString *pkPublicKey; - - // Built the PK decryption with it - OLMPkDecryption *decryption; - if (privateKey) + if ([keyBackupVersion.algorithm isEqualToString:kMXCryptoCurve25519KeyBackupAlgorithm]) { - NSError *error; - decryption = [OLMPkDecryption new]; - pkPublicKey = [decryption setPrivateKey:privateKey error:&error]; - - if (error) + MXCurve25519BackupAuthData *authData = [MXCurve25519BackupAuthData modelFromJSON:keyBackupVersion.authData]; + if (keyBackupVersion.algorithm && authData.publicKey && authData.signatures) { - MXLogDebug(@"[MXCrossSigning] pkDecrytionPublicKeyFromPrivateKey failed. Error: %@", error); + return authData; } - } - - return pkPublicKey; -} - -- (BOOL)checkPkDecryptionPublicKey:(NSString*)pKDecryptionPublicKey forKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion -{ - BOOL checkPkDecryptionPublicKey = NO; - - NSError *error; - MXMegolmBackupAuthData *authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:&error]; - if ([pKDecryptionPublicKey isEqualToString:authData.publicKey]) - { - checkPkDecryptionPublicKey = YES; - } - - if (error) - { - MXLogDebug(@"[MXCrossSigning] checkPkDecryptionPublicKey: Error: %@", error); - } - - return checkPkDecryptionPublicKey; -} - -- (nullable OLMPkSigning*)pkSigningFromPrivateKey:(NSData*)privateKey withExpectedPublicKey:(NSString*)expectedPublicKey -{ - NSError *error; - OLMPkSigning *pkSigning = [[OLMPkSigning alloc] init]; - NSString *gotPublicKey = [pkSigning doInitWithSeed:privateKey error:&error]; - if (error) - { - MXLogDebug(@"[MXCrossSigning] pkSigningFromPrivateKey failed to build PK signing. Error: %@", error); - return nil; - } - - if (![gotPublicKey isEqualToString:expectedPublicKey]) - { - MXLogDebug(@"[MXCrossSigning] pkSigningFromPrivateKey failed. Keys do not match: %@ vs %@", gotPublicKey, expectedPublicKey); - return nil; - } - - return pkSigning; -} - -- (MXKeyBackupData*)encryptGroupSession:(MXOlmInboundGroupSession*)session -{ - // Build the m.megolm_backup.v1.curve25519-aes-sha2 data as defined at - // https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md#mmegolm_backupv1curve25519-aes-sha2-key-format - MXMegolmSessionData *sessionData = session.exportSessionData; - if (![self checkMXMegolmSessionData:sessionData]) - { - MXLogDebug(@"[MXKeyBackup] encryptGroupSession: Error: Invalid MXMegolmSessionData for %@", session.senderKey); - return nil; - } - - BOOL sharedHistory = MXSDKOptions.sharedInstance.enableRoomSharedHistoryOnInvite && sessionData.sharedHistory; - NSDictionary *sessionBackupData = @{ - @"algorithm": sessionData.algorithm, - @"sender_key": sessionData.senderKey, - @"sender_claimed_keys": sessionData.senderClaimedKeys, - @"forwarding_curve25519_key_chain": sessionData.forwardingCurve25519KeyChain ? sessionData.forwardingCurve25519KeyChain : @[], - @"session_key": sessionData.sessionKey, - kMXSharedHistoryKeyName: @(sharedHistory) - }; - OLMPkMessage *encryptedSessionBackupData = [_backupKey encryptMessage:[MXTools serialiseJSONObject:sessionBackupData] error:nil]; - if (![self checkOLMPkMessage:encryptedSessionBackupData]) - { - MXLogDebug(@"[MXKeyBackup] encryptGroupSession: Error: Invalid OLMPkMessage for %@", session.senderKey); - return nil; - } - - // Gather information for each key - MXDeviceInfo *device = [crypto.deviceList deviceWithIdentityKey:session.senderKey andAlgorithm:kMXCryptoMegolmAlgorithm]; - - // Build backup data for that key - MXKeyBackupData *keyBackupData = [MXKeyBackupData new]; - keyBackupData.firstMessageIndex = session.session.firstKnownIndex; - keyBackupData.forwardedCount = session.forwardingCurve25519KeyChain.count; - keyBackupData.verified = device ? device.trustLevel.isVerified : NO; - keyBackupData.sessionData = @{ - @"ciphertext": encryptedSessionBackupData.ciphertext, - @"mac": encryptedSessionBackupData.mac, - @"ephemeral": encryptedSessionBackupData.ephemeralKey, - }; - - return keyBackupData; -} + else + { + MXLogError(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup is missing required data"); -// Sanity checks on MXMegolmSessionData -- (BOOL)checkMXMegolmSessionData:(MXMegolmSessionData*)sessionData -{ - if (!sessionData.algorithm) - { - MXLogDebug(@"[MXKeyBackup] checkMXMegolmSessionData: missing algorithm"); - return NO; - } - if (!sessionData.senderKey) - { - MXLogDebug(@"[MXKeyBackup] checkMXMegolmSessionData: missing senderKey"); - return NO; - } - if (!sessionData.senderClaimedKeys) - { - MXLogDebug(@"[MXKeyBackup] checkMXMegolmSessionData: missing senderClaimedKeys"); - return NO; - } - if (!sessionData.sessionKey) - { - MXLogDebug(@"[MXKeyBackup] checkMXMegolmSessionData: missing sessionKey"); - return NO; - } - - return YES; -} + *error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorMissingAuthDataCode + userInfo:@{ + NSLocalizedDescriptionKey: @"Key backup is missing required data" + }]; -// Sanity checks on OLMPkMessage -- (BOOL)checkOLMPkMessage:(OLMPkMessage*)message -{ - if (!message.ciphertext) - { - MXLogDebug(@"[MXKeyBackup] checkOLMPkMessage: missing ciphertext"); - return NO; - } - if (!message.mac) - { - MXLogDebug(@"[MXKeyBackup] checkOLMPkMessage: missing mac"); - return NO; - } - if (!message.ephemeralKey) - { - MXLogDebug(@"[MXKeyBackup] checkOLMPkMessage: missing ephemeralKey"); - return NO; + return nil; + } } - - return YES; -} - -- (MXMegolmSessionData*)decryptKeyBackupData:(MXKeyBackupData*)keyBackupData forSession:(NSString*)sessionId inRoom:(NSString*)roomId withPkDecryption:(OLMPkDecryption*)decryption -{ - MXMegolmSessionData *sessionData; - - NSString *ciphertext, *mac, *ephemeralKey; - - MXJSONModelSetString(ciphertext, keyBackupData.sessionData[@"ciphertext"]); - MXJSONModelSetString(mac, keyBackupData.sessionData[@"mac"]); - MXJSONModelSetString(ephemeralKey, keyBackupData.sessionData[@"ephemeral"]); - - if (ciphertext && mac && ephemeralKey) + else if ([keyBackupVersion.algorithm isEqualToString:kMXCryptoAes256KeyBackupAlgorithm]) { - OLMPkMessage *encrypted = [[OLMPkMessage alloc] initWithCiphertext:ciphertext mac:mac ephemeralKey:ephemeralKey]; - - NSError *error; - NSString *text = [decryption decryptMessage:encrypted error:&error]; - - if (!error) + MXAes256BackupAuthData *authData = [MXAes256BackupAuthData modelFromJSON:keyBackupVersion.authData]; + if (keyBackupVersion.algorithm && authData.iv && authData.mac) { - NSDictionary *sessionBackupData = [MXTools deserialiseJSONString:text]; - - if (sessionBackupData) - { - MXJSONModelSetMXJSONModel(sessionData, MXMegolmSessionData, sessionBackupData); - - sessionData.sessionId = sessionId; - sessionData.roomId = roomId; - } + return authData; } else { - MXLogDebug(@"[MXKeyBackup] decryptKeyBackupData: Failed to decrypt session from backup. Error: %@", error); - } - } - - return sessionData; -} + MXLogError(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup is missing required data"); -/** - Extract megolm back up authentication data from a backup. + *error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorMissingAuthDataCode + userInfo:@{ + NSLocalizedDescriptionKey: @"Key backup is missing required data" + }]; - @param keyBackupVersion the key backup - @param error the encountered error in case of failure. - @return the authentication if found and valid. - */ -- (nullable MXMegolmBackupAuthData *)megolmBackupAuthDataFromKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion error:(NSError**)error -{ - MXMegolmBackupAuthData *authData = [MXMegolmBackupAuthData modelFromJSON:keyBackupVersion.authData]; - if (keyBackupVersion.algorithm && authData.publicKey && authData.signatures) - { - return authData; + return nil; + } } else { - MXLogDebug(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup is missing required data"); + MXLogError(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup for unknown algorithm: %@", keyBackupVersion.algorithm); *error = [NSError errorWithDomain:MXKeyBackupErrorDomain - code:MXKeyBackupErrorMissingAuthDataCode + code:MXKeyBackupErrorUnknownAlgorithm userInfo:@{ - NSLocalizedDescriptionKey: @"Key backup is missing required data" - }]; + NSLocalizedDescriptionKey: @"Key backup for unknown algorithm" + }]; return nil; } @@ -1765,8 +1607,8 @@ - (nullable MXMegolmBackupAuthData *)megolmBackupAuthDataFromKeyBackupVersion:(M */ - (nullable NSString*)recoveryKeyFromPassword:(NSString*)password inKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion error:(NSError **)error { - // Extract MXMegolmBackupAuthData - MXMegolmBackupAuthData *authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:error]; + // Extract MXCurve25519BackupAuthData + id authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:error]; if (*error) { return nil; @@ -1805,8 +1647,8 @@ - (nullable NSString*)recoveryKeyFromPassword:(NSString*)password inKeyBackupVer */ - (BOOL)isValidRecoveryKey:(NSString*)recoveryKey forKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion error:(NSError **)error { - // Build PK decryption instance with the recovery key - NSString *publicKey = [self pkPublicKeyFromRecoveryKey:recoveryKey error:error]; + NSData *privateKey = [MXRecoveryKey decode:recoveryKey error:error]; + if (*error) { MXLogDebug(@"[MXKeyBackup] isValidRecoveryKey: Invalid recovery key. Error: %@", *error); @@ -1815,33 +1657,37 @@ - (BOOL)isValidRecoveryKey:(NSString*)recoveryKey forKeyBackupVersion:(MXKeyBack *error = [NSError errorWithDomain:MXKeyBackupErrorDomain code:MXKeyBackupErrorInvalidRecoveryKeyCode userInfo:@{ - NSLocalizedDescriptionKey: @"Invalid recovery key or password" - }]; + NSLocalizedDescriptionKey: @"Invalid recovery key or password" + }]; return NO; } - // Get the public key defined in the backup - MXMegolmBackupAuthData *authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:error]; - if (*error) + Class algorithm = AlgorithmClassesByName[keyBackupVersion.algorithm]; + if (algorithm == NULL) { - MXLogDebug(@"[MXKeyBackup] isValidRecoveryKey: Key backup is missing required data"); + MXLogDebug(@"[MXKeyBackup] isValidRecoveryKey: unknown algorithm: %@", keyBackupVersion.algorithm); + + *error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorUnknownAlgorithm + userInfo:@{ + NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Unknown algorithm (%@)", keyBackupVersion.algorithm] + }]; return NO; } + BOOL result = [algorithm keyMatches:privateKey withAuthData:keyBackupVersion.authData error:error]; - // Compare both - if (![publicKey isEqualToString:authData.publicKey]) + if (!result) { MXLogDebug(@"[MXKeyBackup] isValidRecoveryKey: Public keys mismatch"); *error = [NSError errorWithDomain:MXKeyBackupErrorDomain code:MXKeyBackupErrorInvalidRecoveryKeyCode userInfo:@{ - NSLocalizedDescriptionKey: @"Invalid recovery key or password" - }]; - return NO; + NSLocalizedDescriptionKey: @"Invalid recovery key or password: public keys mismatch" + }]; } - return YES; + return result; } @end From f0f7c8c7c9374de1b91d257f6b27e333a6193e4c Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 18:05:21 +0300 Subject: [PATCH 10/65] Adapt to new classes and methods --- MatrixSDK.xcodeproj/project.pbxproj | 92 ++++++++++++++++--- MatrixSDK/Crypto/Recovery/MXRecoveryService.m | 2 +- MatrixSDKTests/MXCryptoBackupTests.m | 69 ++++++-------- MatrixSDKTests/MXCryptoRecoveryServiceTests.m | 2 +- MatrixSDKTests/MXCryptoShareTests.m | 2 +- 5 files changed, 113 insertions(+), 54 deletions(-) diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 88b2d6d746..107e7949b1 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -71,8 +71,8 @@ 3209683426396385005D64ED /* UnitTestsWithSanitizers.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 3209683026396385005D64ED /* UnitTestsWithSanitizers.xctestplan */; }; 320A883C217F4E35002EA952 /* MXMegolmBackupCreationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 320A883A217F4E35002EA952 /* MXMegolmBackupCreationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 320A883D217F4E35002EA952 /* MXMegolmBackupCreationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 320A883B217F4E35002EA952 /* MXMegolmBackupCreationInfo.m */; }; - 320A8840217F4E3F002EA952 /* MXMegolmBackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = 320A883E217F4E3E002EA952 /* MXMegolmBackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 320A8841217F4E3F002EA952 /* MXMegolmBackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = 320A883F217F4E3F002EA952 /* MXMegolmBackupAuthData.m */; }; + 320A8840217F4E3F002EA952 /* MXCurve25519BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = 320A883E217F4E3E002EA952 /* MXCurve25519BackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 320A8841217F4E3F002EA952 /* MXCurve25519BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = 320A883F217F4E3F002EA952 /* MXCurve25519BackupAuthData.m */; }; 320B3934239FA56900BE2C06 /* MXKeyVerificationByDMRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 320B3932239FA56900BE2C06 /* MXKeyVerificationByDMRequest.h */; }; 320B3935239FA56900BE2C06 /* MXKeyVerificationByDMRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 320B3932239FA56900BE2C06 /* MXKeyVerificationByDMRequest.h */; }; 320B3936239FA56900BE2C06 /* MXKeyVerificationByDMRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 320B3933239FA56900BE2C06 /* MXKeyVerificationByDMRequest.m */; }; @@ -860,7 +860,7 @@ B14EF1D52397E90400758AF0 /* MXEventAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 327E9AD42284803100A98BC1 /* MXEventAnnotation.m */; }; B14EF1D62397E90400758AF0 /* MXPusher.m in Sources */ = {isa = PBXBuildFile; fileRef = 32999DDE22DCD183004FF987 /* MXPusher.m */; }; B14EF1D72397E90400758AF0 /* MXMediaLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF4FB1DF014D9009DF592 /* MXMediaLoader.m */; }; - B14EF1D82397E90400758AF0 /* MXMegolmBackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = 320A883F217F4E3F002EA952 /* MXMegolmBackupAuthData.m */; }; + B14EF1D82397E90400758AF0 /* MXCurve25519BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = 320A883F217F4E3F002EA952 /* MXCurve25519BackupAuthData.m */; }; B14EF1D92397E90400758AF0 /* MXReactionCount.m in Sources */ = {isa = PBXBuildFile; fileRef = 327E9AF52289D53800A98BC1 /* MXReactionCount.m */; }; B14EF1DA2397E90400758AF0 /* MXRecoveryKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FFB4EF217E146A00C96002 /* MXRecoveryKey.m */; }; B14EF1DB2397E90400758AF0 /* MXPushRuleEventMatchConditionChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 32DC15D31A8CF874006F9AD3 /* MXPushRuleEventMatchConditionChecker.m */; }; @@ -1234,7 +1234,7 @@ B14EF35E2397E90400758AF0 /* MXMegolmBackupCreationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 320A883A217F4E35002EA952 /* MXMegolmBackupCreationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF35F2397E90400758AF0 /* MXCryptoConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 3256E37F1DCB91EB003C9718 /* MXCryptoConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF3602397E90400758AF0 /* MXHTTPClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 320DFDD719DD99B60068622A /* MXHTTPClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B14EF3612397E90400758AF0 /* MXMegolmBackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = 320A883E217F4E3E002EA952 /* MXMegolmBackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B14EF3612397E90400758AF0 /* MXCurve25519BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = 320A883E217F4E3E002EA952 /* MXCurve25519BackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF3622397E90400758AF0 /* MXReactionCountChange.h in Headers */ = {isa = PBXBuildFile; fileRef = 3213301F228BF7BC0070BA9B /* MXReactionCountChange.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF3632397E90400758AF0 /* MXScanRealmFileProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B146D4C621A5A44E00D8C2C6 /* MXScanRealmFileProvider.h */; }; B14EF3642397E90400758AF0 /* MXRoom.h in Headers */ = {isa = PBXBuildFile; fileRef = 320DFDCA19DD99B60068622A /* MXRoom.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1548,6 +1548,22 @@ EC383BB72541C518002FBBE6 /* MXBackgroundPushRulesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC383BB52540E15E002FBBE6 /* MXBackgroundPushRulesManager.swift */; }; EC383BBF2542F1E3002FBBE6 /* MXBackgroundSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC383BBD2542F141002FBBE6 /* MXBackgroundSyncServiceTests.swift */; }; EC383BC02542F1E4002FBBE6 /* MXBackgroundSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC383BBD2542F141002FBBE6 /* MXBackgroundSyncServiceTests.swift */; }; + EC403834289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */; }; + EC403835289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */; }; + EC403837289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */; }; + EC403838289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */; }; + EC403844289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */; }; + EC403845289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */; }; + EC403846289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403843289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m */; }; + EC403847289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403843289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m */; }; + EC40384A289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */; }; + EC40384B289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */; }; + EC40384C289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403849289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m */; }; + EC40384D289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403849289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m */; }; + EC403854289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403853289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m */; }; + EC403855289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403853289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m */; }; + EC403856289B263F0067D5B8 /* MXBaseKeyBackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC40384E289A906A0067D5B8 /* MXBaseKeyBackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC403857289B26400067D5B8 /* MXBaseKeyBackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC40384E289A906A0067D5B8 /* MXBaseKeyBackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC51019D26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC51019E26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC5C560A2798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h in Headers */ = {isa = PBXBuildFile; fileRef = EC5C56082798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h */; }; @@ -1937,8 +1953,8 @@ 3209683026396385005D64ED /* UnitTestsWithSanitizers.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = UnitTestsWithSanitizers.xctestplan; sourceTree = ""; }; 320A883A217F4E35002EA952 /* MXMegolmBackupCreationInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXMegolmBackupCreationInfo.h; sourceTree = ""; }; 320A883B217F4E35002EA952 /* MXMegolmBackupCreationInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXMegolmBackupCreationInfo.m; sourceTree = ""; }; - 320A883E217F4E3E002EA952 /* MXMegolmBackupAuthData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXMegolmBackupAuthData.h; sourceTree = ""; }; - 320A883F217F4E3F002EA952 /* MXMegolmBackupAuthData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXMegolmBackupAuthData.m; sourceTree = ""; }; + 320A883E217F4E3E002EA952 /* MXCurve25519BackupAuthData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXCurve25519BackupAuthData.h; sourceTree = ""; }; + 320A883F217F4E3F002EA952 /* MXCurve25519BackupAuthData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXCurve25519BackupAuthData.m; sourceTree = ""; }; 320B3932239FA56900BE2C06 /* MXKeyVerificationByDMRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKeyVerificationByDMRequest.h; sourceTree = ""; }; 320B3933239FA56900BE2C06 /* MXKeyVerificationByDMRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXKeyVerificationByDMRequest.m; sourceTree = ""; }; 320B3938239FD15E00BE2C06 /* MXKeyVerificationRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKeyVerificationRequest.h; sourceTree = ""; }; @@ -2701,6 +2717,16 @@ EC383BB52540E15E002FBBE6 /* MXBackgroundPushRulesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXBackgroundPushRulesManager.swift; sourceTree = ""; }; EC383BBD2542F141002FBBE6 /* MXBackgroundSyncServiceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXBackgroundSyncServiceTests.swift; sourceTree = ""; }; EC383BC12542F251002FBBE6 /* MatrixSDKTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MatrixSDKTests-Bridging-Header.h"; sourceTree = ""; }; + EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXAes256BackupAuthData.h; sourceTree = ""; }; + EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXAes256BackupAuthData.m; sourceTree = ""; }; + EC403841289A70FC0067D5B8 /* MXKeyBackupAlgorithm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKeyBackupAlgorithm.h; sourceTree = ""; }; + EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXCurve25519KeyBackupAlgorithm.h; sourceTree = ""; }; + EC403843289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXCurve25519KeyBackupAlgorithm.m; sourceTree = ""; }; + EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXAes256KeyBackupAlgorithm.h; sourceTree = ""; }; + EC403849289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXAes256KeyBackupAlgorithm.m; sourceTree = ""; }; + EC40384E289A906A0067D5B8 /* MXBaseKeyBackupAuthData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXBaseKeyBackupAuthData.h; sourceTree = ""; }; + EC403852289ACDBB0067D5B8 /* MXKeyBackupPreparationInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKeyBackupPreparationInfo.h; sourceTree = ""; }; + EC403853289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXKeyBackupPreparationInfo.m; sourceTree = ""; }; EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSyncResponseUnitTests.swift; sourceTree = ""; }; EC5C56082798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+MutableDeepCopy.h"; sourceTree = ""; }; EC5C56092798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+MutableDeepCopy.m"; sourceTree = ""; }; @@ -3873,6 +3899,7 @@ 32BBAE652178E99100D85F46 /* Data */, 32BBAE722179CF4000D85F46 /* MXKeyBackup.h */, 32BBAE732179CF4000D85F46 /* MXKeyBackup.m */, + EC403841289A70FC0067D5B8 /* MXKeyBackupAlgorithm.h */, 32FFB4ED217DC0E900C96002 /* MXKeyBackup_Private.h */, 32FFB4EE217E146A00C96002 /* MXRecoveryKey.h */, 32FFB4EF217E146A00C96002 /* MXRecoveryKey.m */, @@ -3891,10 +3918,13 @@ 32BBAE692178E99100D85F46 /* MXKeyBackupVersion.m */, 328BCB3121947BE200A976D3 /* MXKeyBackupVersionTrust.h */, 328BCB3221947BE200A976D3 /* MXKeyBackupVersionTrust.m */, - 320A883E217F4E3E002EA952 /* MXMegolmBackupAuthData.h */, - 320A883F217F4E3F002EA952 /* MXMegolmBackupAuthData.m */, 320A883A217F4E35002EA952 /* MXMegolmBackupCreationInfo.h */, 320A883B217F4E35002EA952 /* MXMegolmBackupCreationInfo.m */, + EC403852289ACDBB0067D5B8 /* MXKeyBackupPreparationInfo.h */, + EC403853289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m */, + EC40384E289A906A0067D5B8 /* MXBaseKeyBackupAuthData.h */, + EC40383F289A68880067D5B8 /* Curve25519 */, + EC403840289A68990067D5B8 /* Aes256 */, ); path = Data; sourceTree = ""; @@ -4770,6 +4800,28 @@ path = SyncResponseFileStore; sourceTree = ""; }; + EC40383F289A68880067D5B8 /* Curve25519 */ = { + isa = PBXGroup; + children = ( + 320A883E217F4E3E002EA952 /* MXCurve25519BackupAuthData.h */, + 320A883F217F4E3F002EA952 /* MXCurve25519BackupAuthData.m */, + EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */, + EC403843289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m */, + ); + path = Curve25519; + sourceTree = ""; + }; + EC403840289A68990067D5B8 /* Aes256 */ = { + isa = PBXGroup; + children = ( + EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */, + EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */, + EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */, + EC403849289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m */, + ); + path = Aes256; + sourceTree = ""; + }; EC60ED5A265CFBD000B39A4E /* Sync */ = { isa = PBXGroup; children = ( @@ -5149,6 +5201,7 @@ B146D49C21A5A04300D8C2C6 /* MXMediaScanStoreDelegate.h in Headers */, 32322A4B1E575F65005DD155 /* MXAllowedCertificates.h in Headers */, B14EECD72577DE7A00448735 /* MXLoginSSOIdentityProvider.h in Headers */, + EC403844289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */, 3213301D228B190F0070BA9B /* MXRealmAggregationsMapper.h in Headers */, 32A1515B1DB525DA00400192 /* NSObject+sortedKeys.h in Headers */, 329D3E621E251027002E2F1E /* MXRoomSummaryUpdater.h in Headers */, @@ -5202,6 +5255,7 @@ 327A5F4B239805F600ED6329 /* MXKeyVerificationCancel.h in Headers */, 327F8DB21C6112BA00581CA3 /* MXRoomThirdPartyInvite.h in Headers */, B19A309E240424BD00FB6F35 /* MXQRCodeTransaction_Private.h in Headers */, + EC40384A289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */, 32BBAE742179CF4000D85F46 /* MXKeyBackup.h in Headers */, 181FD5D42660C791008EC084 /* MXLogObjcWrapper.h in Headers */, 92634B821EF2E3C400DB9F60 /* MXCallKitConfiguration.h in Headers */, @@ -5307,6 +5361,7 @@ B19A30D424042F2700FB6F35 /* MXSelfVerifyingMasterKeyNotTrustedQRCodeData.h in Headers */, 323F3F9420D3F0C700D26D6A /* MXRoomEventFilter.h in Headers */, 32A9E8251EF4026E0081358A /* MXUIKitBackgroundModeHandler.h in Headers */, + EC403834289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */, B19A30BC2404268600FB6F35 /* MXQRCodeDataCoder.h in Headers */, 325D1C261DFECE0D0070B8BF /* MXCrypto_Private.h in Headers */, B10AFB4322A970060092E6AF /* MXEventReplace.h in Headers */, @@ -5408,6 +5463,7 @@ 32BED28F1B00A23F00E668FE /* MXCallStack.h in Headers */, EC8A53D625B1BCC6004E0802 /* MXThirdPartyUserInstance.h in Headers */, F03EF4FE1DF014D9009DF592 /* MXMediaLoader.h in Headers */, + EC403856289B263F0067D5B8 /* MXBaseKeyBackupAuthData.h in Headers */, 3264DB911CEC528D00B99881 /* MXAccountData.h in Headers */, EC8A53BB25B1BC77004E0802 /* MXCallSelectAnswerEventContent.h in Headers */, EC8A53C125B1BC77004E0802 /* MXCallCapabilitiesModel.h in Headers */, @@ -5481,7 +5537,7 @@ 3256E3811DCB91EB003C9718 /* MXCryptoConstants.h in Headers */, EC60ED9A265CFE1700B39A4E /* MXRoomSyncState.h in Headers */, 320DFDE619DD99B60068622A /* MXHTTPClient.h in Headers */, - 320A8840217F4E3F002EA952 /* MXMegolmBackupAuthData.h in Headers */, + 320A8840217F4E3F002EA952 /* MXCurve25519BackupAuthData.h in Headers */, 32133021228BF7BC0070BA9B /* MXReactionCountChange.h in Headers */, 320DFDDB19DD99B60068622A /* MXRoom.h in Headers */, 3294FDA022F321B0007F1E60 /* MXServiceTerms.h in Headers */, @@ -5498,6 +5554,7 @@ B14EF33E2397E90400758AF0 /* MXOlmInboundGroupSession.h in Headers */, B14EF2FB2397E90400758AF0 /* MXOlmSession.h in Headers */, B14EF3282397E90400758AF0 /* MXMegolmDecryption.h in Headers */, + EC403845289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */, B14EF31E2397E90400758AF0 /* MXOlmDevice.h in Headers */, B14EF2DF2397E90400758AF0 /* MXDecryptionResult.h in Headers */, EC60ED68265CFC7200B39A4E /* MXPresenceSyncResponse.h in Headers */, @@ -5543,6 +5600,7 @@ 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 */, B14EF2A92397E90400758AF0 /* MXServerNoticeContent.h in Headers */, @@ -5598,6 +5656,7 @@ 1838928927031D1D003F0C4F /* MXSendReplyEventStringLocalizerProtocol.h in Headers */, EC60EDDB265CFF0600B39A4E /* MXInvitedRoomSync.h in Headers */, B14EF2C82397E90400758AF0 /* MXCallManager.h in Headers */, + EC40384B289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */, B14EF2C92397E90400758AF0 /* MXRealmReactionRelation.h in Headers */, 91F0685E2767CA430079F8FA /* MXTaskProfileName.h in Headers */, B14EF2CA2397E90400758AF0 /* MXAnalyticsDelegate.h in Headers */, @@ -5707,6 +5766,7 @@ 32261B8B23C74A230018F1E2 /* MXDeviceTrustLevel.h in Headers */, 324DD2B7246C21C700377005 /* MXSecretStorageKeyCreationInfo.h in Headers */, B14EF3102397E90400758AF0 /* MXEmojiRepresentation.h in Headers */, + EC403857289B26400067D5B8 /* MXBaseKeyBackupAuthData.h in Headers */, EC116596270FBF090089FA56 /* MXApplicationProtocol.h in Headers */, ECF29BCD264194AE0053E6D6 /* MXCallAssertedIdentityEventContent.h in Headers */, B14EF3112397E90400758AF0 /* MXMegolmExportEncryption.h in Headers */, @@ -5846,7 +5906,7 @@ 323F879725554FF2009E9E67 /* MXTaskProfile_Private.h in Headers */, 32C78B6D256CFC4D008130B1 /* MXCryptoMigration.h in Headers */, 32F00AC12488FB3600131741 /* MXRecoveryService_Private.h in Headers */, - B14EF3612397E90400758AF0 /* MXMegolmBackupAuthData.h in Headers */, + B14EF3612397E90400758AF0 /* MXCurve25519BackupAuthData.h in Headers */, EC8A53B225B1BC77004E0802 /* MXCallReplacesEventContent.h in Headers */, B14EF3622397E90400758AF0 /* MXReactionCountChange.h in Headers */, 324DD29A246AD2B500377005 /* MXSecretStorage.h in Headers */, @@ -6168,7 +6228,7 @@ 32999DE022DCD183004FF987 /* MXPusher.m in Sources */, F03EF4FF1DF014D9009DF592 /* MXMediaLoader.m in Sources */, ECDA763227B293D9000C48CF /* MXThreadProtocol.swift in Sources */, - 320A8841217F4E3F002EA952 /* MXMegolmBackupAuthData.m in Sources */, + 320A8841217F4E3F002EA952 /* MXCurve25519BackupAuthData.m in Sources */, B1A0270226162110001AADFF /* MXSpaceChildrenResponse.m in Sources */, 66398BA527A4085B00466E89 /* MXRefreshResponse.m in Sources */, 327E9AF72289D53800A98BC1 /* MXReactionCount.m in Sources */, @@ -6230,6 +6290,7 @@ 324DD2B8246C21C700377005 /* MXSecretStorageKeyCreationInfo.m in Sources */, EC1165C027107E330089FA56 /* MXSuggestedRoomListDataCache.swift in Sources */, ECD2897726E8ED0900F268CF /* MXRoomListDataFetchOptions.swift in Sources */, + EC403846289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */, EC0B941B2718654B00B4D440 /* NSManagedObject+MatrixSDK.swift in Sources */, 327E9AE82285A8C400A98BC1 /* MXAggregationPaginatedResponse.m in Sources */, B10AFB4422A970060092E6AF /* MXEventReplace.m in Sources */, @@ -6253,6 +6314,7 @@ EC60EDB4265CFE6200B39A4E /* MXRoomSyncEphemeral.m in Sources */, 32BBAE6F2178E99100D85F46 /* MXKeyBackupVersion.m in Sources */, 326056861C76FDF2009D44AD /* MXRoomEventTimeline.m in Sources */, + EC403854289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m in Sources */, 327A5F4F239805F600ED6329 /* MXKeyVerificationAccept.m in Sources */, B19A30BA2404268600FB6F35 /* MXQRCodeData.m in Sources */, B105CDD8261F54C8006EB204 /* MXSpaceChildContent.m in Sources */, @@ -6263,6 +6325,7 @@ EC60EDFE265CFFD200B39A4E /* MXInvitedGroupSync.m in Sources */, 8EC5110C256822B400EC4E5B /* MXTaggedEvents.m in Sources */, B16C2452283AB08E00F5D1FE /* MXRealmBeaconInfo.swift in Sources */, + EC403837289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */, 32F945F71FAB83D900622468 /* MXIncomingRoomKeyRequest.m in Sources */, 32D2CC09234336D6002BD8CA /* MX3PidAddManager.swift in Sources */, F0173EAD1FCF0E8900B5F6A3 /* MXGroup.m in Sources */, @@ -6307,6 +6370,7 @@ 18121F78273E6E1E00B68ADF /* PollBuilder.swift in Sources */, 327A5F50239805F600ED6329 /* MXKeyVerificationKey.m in Sources */, B16C56E2261D0A9D00604765 /* MXSpaceChildInfo.swift in Sources */, + EC40384C289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m in Sources */, ECBF658726DE3DF800AA3A99 /* MXFileRoomOutgoingMessagesStore.m in Sources */, 3AC13804264482A100EE1E74 /* MXExportedOlmDevice.m in Sources */, 321CFDFE2254E8C4004D31DF /* MXEmojiRepresentation.m in Sources */, @@ -6725,7 +6789,7 @@ B14EF1D72397E90400758AF0 /* MXMediaLoader.m in Sources */, 32549AF823F2E2790002576B /* MXKeyVerificationReady.m in Sources */, B1EE98DD280865A200AB63F0 /* MXBeaconAggregations.swift in Sources */, - B14EF1D82397E90400758AF0 /* MXMegolmBackupAuthData.m in Sources */, + B14EF1D82397E90400758AF0 /* MXCurve25519BackupAuthData.m in Sources */, B14EF1D92397E90400758AF0 /* MXReactionCount.m in Sources */, B14EF1DA2397E90400758AF0 /* MXRecoveryKey.m in Sources */, B14EF1DB2397E90400758AF0 /* MXPushRuleEventMatchConditionChecker.m in Sources */, @@ -6799,6 +6863,7 @@ 32F00ABE2488E1CD00131741 /* MXRecoveryService.m in Sources */, B14EF1FB2397E90400758AF0 /* MXEnumConstants.swift in Sources */, B14EF1FC2397E90400758AF0 /* MXEventRelations.m in Sources */, + EC403847289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */, EC0B941C2718654B00B4D440 /* NSManagedObject+MatrixSDK.swift in Sources */, EC8A53E325B1BCC6004E0802 /* MXThirdPartyUserInstance.m in Sources */, EC383BB12540688B002FBBE6 /* MXBackgroundSyncService.swift in Sources */, @@ -6822,6 +6887,7 @@ 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 */, B14EF2052397E90400758AF0 /* MX3PidAddManager.swift in Sources */, B14EF2062397E90400758AF0 /* MXGroup.m in Sources */, @@ -6832,6 +6898,7 @@ ECD2899026EB3B3400F268CF /* MXRoomListData.swift in Sources */, B14EF2092397E90400758AF0 /* MXCallKitConfiguration.m in Sources */, B16C2453283AB08E00F5D1FE /* MXRealmBeaconInfo.swift in Sources */, + EC403838289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */, 324DD2A9246AE81300377005 /* MXSecretStorageKeyContent.m in Sources */, B14EF20A2397E90400758AF0 /* MXRoomState.m in Sources */, 3AF85F9326FC7AE800A9E67B /* MXSpaceNotificationState.swift in Sources */, @@ -6876,6 +6943,7 @@ EC383BB325406892002FBBE6 /* MXSyncResponseStore.swift in Sources */, ECBF658826DE3DF800AA3A99 /* MXFileRoomOutgoingMessagesStore.m in Sources */, B14EF2222397E90400758AF0 /* MXMediaScan.m in Sources */, + EC40384D289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m in Sources */, B14EF2232397E90400758AF0 /* MXEvent.swift in Sources */, B14EF2242397E90400758AF0 /* MXEventScan.m in Sources */, B14EF2252397E90400758AF0 /* MXOutgoingSASTransaction.m in Sources */, diff --git a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m index 49794f355f..90dd4e35d7 100644 --- a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m +++ b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m @@ -395,7 +395,7 @@ - (void)createKeyBackupWithSuccess:(void (^)(void))success } // Setup the key backup - [keyBackup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [keyBackup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [keyBackup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [keyBackup backupAllGroupSessions:^{ diff --git a/MatrixSDKTests/MXCryptoBackupTests.m b/MatrixSDKTests/MXCryptoBackupTests.m index 53aeb0267d..7fc8265f34 100644 --- a/MatrixSDKTests/MXCryptoBackupTests.m +++ b/MatrixSDKTests/MXCryptoBackupTests.m @@ -25,15 +25,7 @@ #import "MXKeybackupPassword.h" #import "MXOutboundSessionInfo.h" #import "MXCrossSigning_Private.h" - -@interface MXKeyBackup (Testing) - -- (OLMPkDecryption*)pkDecryptionFromRecoveryKey:(NSString*)recoveryKey error:(NSError **)error; -- (MXKeyBackupData*)encryptGroupSession:(MXOlmInboundGroupSession*)session; -- (MXMegolmSessionData*)decryptKeyBackupData:(MXKeyBackupData*)keyBackupData forSession:(NSString*)sessionId inRoom:(NSString*)roomId withPkDecryption:(OLMPkDecryption*)decryption; - -@end - +#import "MXKeyBackupAlgorithm.h" // Do not bother with retain cycles warnings in tests #pragma clang diagnostic push @@ -379,12 +371,14 @@ - (void)testPrepareKeyBackupVersion XCTAssertFalse(aliceSession.crypto.backup.enabled); // Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { XCTAssertNotNil(keyBackupCreationInfo); XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); - XCTAssertNotNil(keyBackupCreationInfo.authData.publicKey); - XCTAssertNotNil(keyBackupCreationInfo.authData.signatures); + XCTAssertTrue([keyBackupCreationInfo.authData isKindOfClass:MXCurve25519BackupAuthData.class]); + MXCurve25519BackupAuthData *authData = (MXCurve25519BackupAuthData*) keyBackupCreationInfo.authData; + XCTAssertNotNil(authData.publicKey); + XCTAssertNotNil(authData.signatures); XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); [expectation fulfill]; @@ -406,11 +400,11 @@ - (void)testCreateKeyBackupVersion XCTAssertFalse(aliceSession.crypto.backup.enabled); // Check that `[MXKeyBackup createKeyBackupVersion` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { XCTAssertEqualObjects(keyBackupVersion.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); - XCTAssertEqualObjects(keyBackupVersion.authData, keyBackupCreationInfo.authData.JSONDictionary); + XCTAssertTrue([keyBackupVersion.authData isEqualToDictionary:keyBackupCreationInfo.authData.JSONDictionary]); XCTAssertNotNil(keyBackupVersion.version); // Backup must be enable now @@ -437,7 +431,7 @@ - (void)testBackupAfterCreateKeyBackupVersion { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { // Check that `[MXKeyBackup createKeyBackupVersion` launches the backup @@ -482,7 +476,7 @@ - (void)testTrustForKeyBackupVersion // - Create a backup version [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { // - Check the returned MXKeyBackupVersion is trusted @@ -528,7 +522,7 @@ - (void)testCrossSigningMSKTrustForKeyBackupVersion [aliceSession.crypto.crossSigning setupWithPassword:MXTESTS_ALICE_PWD success:^{ // - Alice creates a backup - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo *keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo *keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion *keyBackupVersion) { // - Check the returned MXKeyBackupVersion is trusted @@ -579,7 +573,7 @@ - (void)testBackupAllGroupSessions [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // Check that `[MXKeyBackup backupAllGroupSessions]` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { NSUInteger keys = [aliceSession.crypto.store inboundGroupSessionsCount:NO]; @@ -629,20 +623,16 @@ - (void)testEncryptAndDecryptKeyBackupData // - Pick a megolm key MXOlmInboundGroupSession *session = [aliceSession.crypto.store inboundGroupSessionsToBackup:1].firstObject; - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { - // - Check [MXKeyBackup encryptGroupSession] returns stg - MXKeyBackupData *keyBackupData = [aliceSession.crypto.backup encryptGroupSession:session]; + // - Check [MXKeyBackupAlgorithm encryptGroupSession] returns stg + MXKeyBackupData *keyBackupData = [aliceSession.crypto.backup.keyBackupAlgorithm encryptGroupSession:session]; XCTAssertNotNil(keyBackupData); XCTAssertNotNil(keyBackupData.sessionData); - // - Check [MXKeyBackup pkDecryptionFromRecoveryKey] is able to create a OLMPkDecryption - OLMPkDecryption *decryption = [aliceSession.crypto.backup pkDecryptionFromRecoveryKey:keyBackupCreationInfo.recoveryKey error:nil]; - XCTAssertNotNil(decryption); - - // - Check [MXKeyBackup decryptKeyBackupData] returns stg - MXMegolmSessionData *sessionData = [aliceSession.crypto.backup decryptKeyBackupData:keyBackupData forSession:session.session.sessionIdentifier inRoom:roomId withPkDecryption:decryption]; + // - Check [MXKeyBackupAlgorithm decryptKeyBackupData] returns stg + MXMegolmSessionData *sessionData = [aliceSession.crypto.backup.keyBackupAlgorithm decryptKeyBackupData:keyBackupData forSession:session.session.sessionIdentifier inRoom:roomId]; XCTAssertNotNil(sessionData); // - Compare the decrypted megolm key with the original one @@ -673,13 +663,13 @@ - (void)createKeyBackupScenarioWithPassword:(NSString*)password readyToTest:(voi NSArray *aliceKeys = [aliceSession.crypto.store inboundGroupSessionsToBackup:100]; // - Do an e2e backup to the homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession.crypto.backup backupAllGroupSessions:^{ // - Log Alice on a new device [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - [matrixSDKTestsData relogUserSessionWithNewDevice:self session:aliceSession withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { + [self->matrixSDKTestsData relogUserSessionWithNewDevice:self session:aliceSession withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; // Test check: aliceSession2 has no keys at login @@ -742,7 +732,8 @@ - (void)testRestoreKeyBackup // - Restore the e2e backup with recovery key [aliceSession.crypto.backup restoreKeyBackup:aliceSession.crypto.backup.keyBackupVersion withRecoveryKey:keyBackupCreationInfo.recoveryKey - room:nil session:nil + room:nil + session:nil success:^(NSUInteger total, NSUInteger imported) { // - Restore must be successful @@ -937,7 +928,7 @@ - (void)testCheckAndStartKeyBackupWhenRestartingAMatrixSession XCTAssertFalse(aliceSession.crypto.backup.enabled); - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { XCTAssertTrue(aliceSession.crypto.backup.enabled); @@ -989,7 +980,7 @@ - (void)testBackupWhenAnotherBackupWasCreated [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Make alice back up her keys to her homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { XCTAssertTrue(aliceSession.crypto.backup.enabled); @@ -1044,7 +1035,7 @@ - (void)testBackupAfterVerifyingADevice [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Do an e2e backup to the homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession.crypto.backup backupAllGroupSessions:^{ @@ -1146,7 +1137,7 @@ - (void)testRestoreKeyBackupAndKeyShareRequests [self createKeyBackupScenarioWithPassword:nil readyToTest:^(NSString *version, MXMegolmBackupCreationInfo *keyBackupCreationInfo, NSArray *aliceKeys, MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Check the SDK sent key share requests - [matrixSDKTestsE2EData outgoingRoomKeyRequestInSession:aliceSession complete:^(MXOutgoingRoomKeyRequest *outgoingRoomKeyRequest) { + [self->matrixSDKTestsE2EData outgoingRoomKeyRequestInSession:aliceSession complete:^(MXOutgoingRoomKeyRequest *outgoingRoomKeyRequest) { XCTAssertNotNil(outgoingRoomKeyRequest); @@ -1163,7 +1154,7 @@ - (void)testRestoreKeyBackupAndKeyShareRequests dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ // - There must be no more pending key share requests - [matrixSDKTestsE2EData outgoingRoomKeyRequestInSession:aliceSession complete:^(MXOutgoingRoomKeyRequest *outgoingRoomKeyRequest) { + [self->matrixSDKTestsE2EData outgoingRoomKeyRequestInSession:aliceSession complete:^(MXOutgoingRoomKeyRequest *outgoingRoomKeyRequest) { XCTAssertNil(outgoingRoomKeyRequest); @@ -1437,7 +1428,7 @@ - (void)testLocalPrivateKey [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Do an e2e backup to the homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession.crypto.backup backupAllGroupSessions:^{ @@ -1446,7 +1437,7 @@ - (void)testLocalPrivateKey // - Restart the session MXSession *aliceSession2 = [[MXSession alloc] initWithMatrixRestClient:aliceSession.matrixRestClient]; - [matrixSDKTestsData retain:aliceSession2]; + [self->matrixSDKTestsData retain:aliceSession2]; [aliceSession close]; [aliceSession2 start:^{ XCTAssertTrue(aliceSession2.crypto.backup.hasPrivateKeyInCryptoStore); @@ -1508,7 +1499,7 @@ - (void)testCatchPrivateKeyOnRecoverWithPassword // - Do an e2e backup to the homeserver NSString *password = @"qwerty"; - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { NSString *backupSecret = [aliceSession.crypto.store secretWithSecretId:MXSecretId.keyBackup]; @@ -1558,7 +1549,7 @@ - (void)testGossipKey [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession1, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Do an e2e backup to the homeserver - [aliceSession1.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession1.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession1.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession1.crypto.backup backupAllGroupSessions:^{ diff --git a/MatrixSDKTests/MXCryptoRecoveryServiceTests.m b/MatrixSDKTests/MXCryptoRecoveryServiceTests.m index 86a12cb155..461992c571 100644 --- a/MatrixSDKTests/MXCryptoRecoveryServiceTests.m +++ b/MatrixSDKTests/MXCryptoRecoveryServiceTests.m @@ -90,7 +90,7 @@ - (void)doTestWithAliceWithCrossSigningAndKeyBackup:(XCTestCase*)testCase [self doTestWithAliceWithCrossSigning:testCase readyToTest:^(MXSession *aliceSession, NSString *roomId, XCTestExpectation *expectation) { // - Setup key backup - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession.crypto.backup backupAllGroupSessions:^{ diff --git a/MatrixSDKTests/MXCryptoShareTests.m b/MatrixSDKTests/MXCryptoShareTests.m index 4137c82b26..966479f100 100644 --- a/MatrixSDKTests/MXCryptoShareTests.m +++ b/MatrixSDKTests/MXCryptoShareTests.m @@ -359,7 +359,7 @@ - (void)xtestNoKeyShareRequestIfThereIsABackup [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession1, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Alice set up a backup - [aliceSession1.crypto.backup prepareKeyBackupVersionWithPassword:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession1.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession1.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession1.crypto.backup backupAllGroupSessions:^{ From 704ae0ab28b91e337bcd26485acd19a5fce69997 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 20:28:26 +0300 Subject: [PATCH 11/65] Fix import issues --- MatrixSDK.xcodeproj/project.pbxproj | 12 ++++++++++-- .../Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m | 1 + MatrixSDK/MatrixSDK.h | 3 +++ MatrixSDKTests/MXCryptoBackupTests.m | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 107e7949b1..b4dbc0a32b 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1548,8 +1548,8 @@ EC383BB72541C518002FBBE6 /* MXBackgroundPushRulesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC383BB52540E15E002FBBE6 /* MXBackgroundPushRulesManager.swift */; }; EC383BBF2542F1E3002FBBE6 /* MXBackgroundSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC383BBD2542F141002FBBE6 /* MXBackgroundSyncServiceTests.swift */; }; EC383BC02542F1E4002FBBE6 /* MXBackgroundSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC383BBD2542F141002FBBE6 /* MXBackgroundSyncServiceTests.swift */; }; - EC403834289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */; }; - EC403835289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */; }; + EC403834289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC403835289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC403837289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */; }; EC403838289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */; }; EC403844289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */; }; @@ -1564,6 +1564,10 @@ EC403855289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403853289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m */; }; EC403856289B263F0067D5B8 /* MXBaseKeyBackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC40384E289A906A0067D5B8 /* MXBaseKeyBackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC403857289B26400067D5B8 /* MXBaseKeyBackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC40384E289A906A0067D5B8 /* MXBaseKeyBackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC403858289C38BA0067D5B8 /* MXKeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403841289A70FC0067D5B8 /* MXKeyBackupAlgorithm.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC403859289C38BB0067D5B8 /* MXKeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403841289A70FC0067D5B8 /* MXKeyBackupAlgorithm.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC40385A289C38FB0067D5B8 /* MXKeyBackupPreparationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403852289ACDBB0067D5B8 /* MXKeyBackupPreparationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC40385B289C38FB0067D5B8 /* MXKeyBackupPreparationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403852289ACDBB0067D5B8 /* MXKeyBackupPreparationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC51019D26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC51019E26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC5C560A2798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h in Headers */ = {isa = PBXBuildFile; fileRef = EC5C56082798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h */; }; @@ -5249,7 +5253,9 @@ 325380E8228DAD4A00ADDEFA /* MXAggregatedReactions.h in Headers */, 327E9AE72285A8C400A98BC1 /* MXAggregationPaginatedResponse.h in Headers */, 32CEEF4923B0A8170039BA98 /* MXCrossSigningTools.h in Headers */, + EC403858289C38BA0067D5B8 /* MXKeyBackupAlgorithm.h in Headers */, EC8A53DA25B1BCC6004E0802 /* MXThirdPartyUsersResponse.h in Headers */, + EC40385A289C38FB0067D5B8 /* MXKeyBackupPreparationInfo.h in Headers */, 323E0C5B1A306D7A00A31D73 /* MXEvent.h in Headers */, 323F8773255460B5009E9E67 /* MXProfiler.h in Headers */, 327A5F4B239805F600ED6329 /* MXKeyVerificationCancel.h in Headers */, @@ -5675,6 +5681,7 @@ B1DDC9D72418098200D208E3 /* MXIncomingSASTransaction_Private.h in Headers */, B14EF2D22397E90400758AF0 /* MXReplyEventParts.h in Headers */, B14EF2D32397E90400758AF0 /* MXRoomMembersCount.h in Headers */, + EC403859289C38BB0067D5B8 /* MXKeyBackupAlgorithm.h in Headers */, 32AF929024110ADD0008A0FD /* MXSecretShareManager_Private.h in Headers */, B19A30C52404268600FB6F35 /* MXVerifyingAnotherUserQRCodeData.h in Headers */, B14EF2D42397E90400758AF0 /* MatrixSDK.h in Headers */, @@ -5750,6 +5757,7 @@ B14EF3032397E90400758AF0 /* MXEventsByTypesEnumeratorOnArray.h in Headers */, EC60ED90265CFD3B00B39A4E /* MXRoomSync.h in Headers */, B14EF3042397E90400758AF0 /* MXKeyVerificationTransaction.h in Headers */, + EC40385B289C38FB0067D5B8 /* MXKeyBackupPreparationInfo.h in Headers */, B14EF3052397E90400758AF0 /* MXIdentityServerHashDetails.h in Headers */, 180F858527A2AF3000F4E5A5 /* MXWellKnownTileServerConfig.h in Headers */, 324AAC7D2399143400380A66 /* MXKeyVerificationAccept.h in Headers */, diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m index 8f5cce8556..5f8c351683 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m @@ -30,6 +30,7 @@ #import "MXRawDataKey.h" #import "MXCrossSigning_Private.h" #import "MXSharedHistoryKeyService.h" +#import "MXCurve25519BackupAuthData.h" @interface MXCurve25519KeyBackupAlgorithm () diff --git a/MatrixSDK/MatrixSDK.h b/MatrixSDK/MatrixSDK.h index d9a130bb09..dd949540f2 100644 --- a/MatrixSDK/MatrixSDK.h +++ b/MatrixSDK/MatrixSDK.h @@ -73,6 +73,9 @@ FOUNDATION_EXPORT NSString *MatrixSDKVersion; #import "MXKeyVerificationRequestByDMJSONModel.h" #import "MXSASKeyVerificationStart.h" #import "MXQRCodeKeyVerificationStart.h" +#import "MXKeyBackupAlgorithm.h" +#import "MXCurve25519BackupAuthData.h" +#import "MXAes256BackupAuthData.h" #import "MXAes.h" diff --git a/MatrixSDKTests/MXCryptoBackupTests.m b/MatrixSDKTests/MXCryptoBackupTests.m index 7fc8265f34..9874bf9287 100644 --- a/MatrixSDKTests/MXCryptoBackupTests.m +++ b/MatrixSDKTests/MXCryptoBackupTests.m @@ -26,6 +26,7 @@ #import "MXOutboundSessionInfo.h" #import "MXCrossSigning_Private.h" #import "MXKeyBackupAlgorithm.h" +#import "MXCurve25519BackupAuthData.h" // Do not bother with retain cycles warnings in tests #pragma clang diagnostic push From cf218d9ca727c0916d7a3a1c5e62003e34594a8b Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 4 Aug 2022 20:38:40 +0300 Subject: [PATCH 12/65] Implement untrusted on inbound group session --- MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.h | 5 +++++ MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.h b/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.h index 502d15f676..c7143a79fb 100644 --- a/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.h +++ b/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.h @@ -74,6 +74,11 @@ */ @property (nonatomic) BOOL sharedHistory; +/** + Flag indicating this session is untrusted or not. + */ +@property (nonatomic, getter=isUntrusted) BOOL untrusted; + #pragma mark - import/export diff --git a/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m b/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m index a862c184cb..0a1c11faf7 100644 --- a/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m +++ b/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m @@ -58,6 +58,7 @@ - (MXMegolmSessionData *)exportSessionDataAtMessageIndex:(NSUInteger)messageInde sessionData.sessionKey = sessionKey; sessionData.algorithm = kMXCryptoMegolmAlgorithm; sessionData.sharedHistory = _sharedHistory; + sessionData.untrusted = _untrusted; } else { @@ -99,6 +100,7 @@ - (instancetype)initWithImportedSessionData:(MXMegolmSessionData *)data _keysClaimed = data.senderClaimedKeys; _roomId = data.roomId; _sharedHistory = data.sharedHistory; + _untrusted = data.isUntrusted; } return self; } @@ -116,6 +118,8 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder _forwardingCurve25519KeyChain = [aDecoder decodeObjectForKey:@"forwardingCurve25519KeyChain"]; _keysClaimed = [aDecoder decodeObjectForKey:@"keysClaimed"]; _sharedHistory = [[aDecoder decodeObjectForKey:@"sharedHistory_v2"] boolValue]; + // if "untrusted" is not encoded, mark it as untrusted + _untrusted = [aDecoder decodeObjectForKey:@"untrusted"] ? [aDecoder decodeBoolForKey:@"untrusted"] : YES; } return self; } @@ -128,6 +132,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder [aCoder encodeObject:_keysClaimed forKey:@"keysClaimed"]; [aCoder encodeObject:_forwardingCurve25519KeyChain forKey:@"forwardingCurve25519KeyChain"]; [aCoder encodeObject:@(_sharedHistory) forKey:@"sharedHistory_v2"]; + [aCoder encodeBool:_untrusted forKey:@"untrusted"]; } @end From 2310ee52398c2aafd522ad293f4119f0bba62a2a Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Fri, 5 Aug 2022 01:54:47 +0300 Subject: [PATCH 13/65] Fix algorithm preparations & use local trust as js-sdk did --- .../Crypto/Data/MXOlmInboundGroupSession.m | 2 +- .../Data/Aes256/MXAes256KeyBackupAlgorithm.m | 28 ++++++---- .../MXCurve25519KeyBackupAlgorithm.m | 40 +++++++++----- .../KeyBackup/Data/MXKeyBackupVersionTrust.h | 5 ++ .../KeyBackup/Data/MXKeyBackupVersionTrust.m | 1 + MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 52 +++++++++++++------ .../Crypto/KeyBackup/MXKeyBackupAlgorithm.h | 4 +- MatrixSDKTests/MXCryptoRecoveryServiceTests.m | 2 +- 8 files changed, 90 insertions(+), 44 deletions(-) diff --git a/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m b/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m index 0a1c11faf7..1f2ec6d96d 100644 --- a/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m +++ b/MatrixSDK/Crypto/Data/MXOlmInboundGroupSession.m @@ -119,7 +119,7 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder _keysClaimed = [aDecoder decodeObjectForKey:@"keysClaimed"]; _sharedHistory = [[aDecoder decodeObjectForKey:@"sharedHistory_v2"] boolValue]; // if "untrusted" is not encoded, mark it as untrusted - _untrusted = [aDecoder decodeObjectForKey:@"untrusted"] ? [aDecoder decodeBoolForKey:@"untrusted"] : YES; + _untrusted = [aDecoder containsValueForKey:@"untrusted"] ? [aDecoder decodeBoolForKey:@"untrusted"] : YES; } return self; } diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index 191ac2ba16..ee573fbe7d 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -83,9 +83,21 @@ - (instancetype)initWithCrypto:(MXCrypto *)crypto authData:(id *signatures; +/** + Flag indicating the backup trusted locally. + */ +@property (nonatomic, getter=isTrustedLocally) BOOL trustedLocally; + @end diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersionTrust.m b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersionTrust.m index 44981fe2d8..e286fca1f0 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersionTrust.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/MXKeyBackupVersionTrust.m @@ -25,6 +25,7 @@ - (instancetype)init { _usable = NO; _signatures = [NSArray new]; + _trustedLocally = NO; } return self; } diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index b225f7ac90..9be7e66350 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -125,17 +125,6 @@ - (void)checkAndStartWithKeyBackupVersion:(nullable MXKeyBackupVersion*)keyBacku { MXLogDebug(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: %@", keyBackupVersion.version); - Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; - if (algorithmClass == NULL) - { - MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: unknown algorithm: %@", keyBackupVersion.algorithm); - return; - } - if (![algorithmClass checkBackupVersion:keyBackupVersion]) - { - MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: invalid backup data returned"); - return; - } self->_keyBackupVersion = keyBackupVersion; if (!self.keyBackupVersion) { @@ -161,6 +150,18 @@ - (void)checkAndStartWithKeyBackupVersion:(nullable MXKeyBackupVersion*)keyBacku // Check private keys if (self.hasPrivateKeyInCryptoStore) { + Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; + if (algorithmClass == NULL) + { + MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: unknown algorithm: %@", keyBackupVersion.algorithm); + return; + } + if (![algorithmClass checkBackupVersion:keyBackupVersion]) + { + MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: invalid backup data returned"); + return; + } + NSData *privateKey = self.privateKeyFromCryptoStore; NSError *error; BOOL keyMatches = [algorithmClass keyMatches:privateKey withAuthData:keyBackupVersion.authData error:&error]; @@ -1128,6 +1129,17 @@ - (MXKeyBackupVersionTrust *)trustForKeyBackupVersionFromCryptoQueue:(MXKeyBacku return keyBackupVersionTrust; } + NSData *privateKey = self.privateKeyFromCryptoStore; + if (privateKey) + { + id algorithm = [self getOrCreateKeyBackupAlgorithmFor:keyBackupVersion privateKey:privateKey]; + if ([algorithm keyMatches:privateKey error:nil]) + { + MXLogDebug(@"[MXKeyBackup] trustForKeyBackupVersionFromCryptoQueue: Backup is trusted locally"); + keyBackupVersionTrust.trustedLocally = YES; + } + } + NSMutableArray *signatures = [NSMutableArray array]; for (NSString *keyId in mySigs) { @@ -1153,10 +1165,6 @@ - (MXKeyBackupVersionTrust *)trustForKeyBackupVersionFromCryptoQueue:(MXKeyBacku { MXLogDebug(@"[MXKeyBackup] trustForKeyBackupVersion: Bad signature from device %@: %@", device.deviceId, error); } - else if (device.trustLevel.isVerified) - { - keyBackupVersionTrust.usable = YES; - } MXKeyBackupVersionTrustSignature *signature = [MXKeyBackupVersionTrustSignature new]; signature.deviceId = deviceId; @@ -1186,6 +1194,15 @@ - (MXKeyBackupVersionTrust *)trustForKeyBackupVersionFromCryptoQueue:(MXKeyBacku keyBackupVersionTrust.signatures = signatures; + for (MXKeyBackupVersionTrustSignature *signature in keyBackupVersionTrust.signatures) + { + if (signature.valid && signature.device && signature.device.trustLevel.isVerified) + { + keyBackupVersionTrust.usable = YES; + } + } + keyBackupVersionTrust.usable = keyBackupVersionTrust.usable || keyBackupVersionTrust.isTrustedLocally; + return keyBackupVersionTrust; } @@ -1383,7 +1400,8 @@ - (void)requestPrivateKeysToDeviceIds:(nullable NSArray*)deviceIds - (BOOL)isSecretValid:(NSString*)secret forKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion { NSData *privateKey = [MXBase64Tools dataFromBase64:secret]; - return [_keyBackupAlgorithm keyMatches:privateKey error:nil]; + id algorithm = [self getOrCreateKeyBackupAlgorithmFor:keyBackupVersion privateKey:privateKey]; + return [algorithm keyMatches:privateKey error:nil]; } #pragma mark - Backup state @@ -1607,7 +1625,7 @@ - (nullable NSData*)privateKeyFromCryptoStore */ - (nullable NSString*)recoveryKeyFromPassword:(NSString*)password inKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion error:(NSError **)error { - // Extract MXCurve25519BackupAuthData + // Extract MXBaseKeyBackupAuthData id authData = [self megolmBackupAuthDataFromKeyBackupVersion:keyBackupVersion error:error]; if (*error) { diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h index 36618a6814..a690c0297d 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h @@ -50,9 +50,9 @@ typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); keyGetterBlock:(MXKeyBackupPrivateKeyGetterBlock)keyGetterBlock; /// Prepare a private key and auth data for a given password for the algorithm. Returns a preparation info if successful, otherwise returns nil. -/// @param password password to use +/// @param password password to use. If not provided, a new one will be generated. /// @param error error instance to be set on errors -+ (nullable MXKeyBackupPreparationInfo*)prepareWith:(NSString*)password error:(NSError *__autoreleasing _Nullable *)error; ++ (nullable MXKeyBackupPreparationInfo*)prepareWith:(nullable NSString*)password error:(NSError *__autoreleasing _Nullable *)error; /// Method to check a private key against receiver's internal auth data (the one given at initialization) /// @param privateKey private key to check diff --git a/MatrixSDKTests/MXCryptoRecoveryServiceTests.m b/MatrixSDKTests/MXCryptoRecoveryServiceTests.m index 461992c571..16fd9c5da5 100644 --- a/MatrixSDKTests/MXCryptoRecoveryServiceTests.m +++ b/MatrixSDKTests/MXCryptoRecoveryServiceTests.m @@ -394,7 +394,7 @@ - (void)testRecoverServicesAssociatedWithSecrets // - Log Alice on a new device [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - [matrixSDKTestsData relogUserSessionWithNewDevice:self session:aliceSession withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { + [self->matrixSDKTestsData relogUserSessionWithNewDevice:self session:aliceSession withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; [aliceSession2.crypto.crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) { From b1d3d10098392c2923cfabc039d164b22b1a3393 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Fri, 5 Aug 2022 01:55:46 +0300 Subject: [PATCH 14/65] Fix recovery service tests with timing of key backup refresh --- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h | 5 +++ MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 4 +++ MatrixSDK/Crypto/Recovery/MXRecoveryService.m | 34 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h index 87569c4c33..99bee89c80 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.h @@ -405,6 +405,11 @@ FOUNDATION_EXPORT NSString *const kMXKeyBackupDidStateChangeNotification; */ @property (nonatomic, readonly) BOOL hasKeysToBackup; +/** + Flag indicating the backup can be refreshed, by `forceRefresh:failure:` method. + */ +@property (nonatomic, readonly) BOOL canBeRefreshed; + @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index 9be7e66350..2ec4582bbe 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -1416,6 +1416,10 @@ - (BOOL)hasKeysToBackup return [crypto.store inboundGroupSessionsToBackup:1].count > 0; } +- (BOOL)canBeRefreshed +{ + return _state != MXKeyBackupStateUnknown && _state != MXKeyBackupStateCheckingBackUpOnHomeserver; +} #pragma mark - Private methods - diff --git a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m index 90dd4e35d7..bd2bca4b9c 100644 --- a/MatrixSDK/Crypto/Recovery/MXRecoveryService.m +++ b/MatrixSDK/Crypto/Recovery/MXRecoveryService.m @@ -370,6 +370,40 @@ - (void)createKeyBackupWithSuccess:(void (^)(void))success success(); return; } + + if (!keyBackup.canBeRefreshed) + { + // cannot refresh key backup now, wait for another state + MXWeakify(self); + __block id observer; + observer = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKeyBackupDidStateChangeNotification + object:keyBackup + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification * _Nonnull notification) { + MXStrongifyAndReturnIfNil(self); + + if (keyBackup.canBeRefreshed) + { + [[NSNotificationCenter defaultCenter] removeObserver:observer]; + observer = nil; + + [self createKeyBackupWithSuccess:success failure:failure]; + } + }]; + + // also add a timer to avoid infinite waiting + [NSTimer scheduledTimerWithTimeInterval:10.0 repeats:NO block:^(NSTimer * _Nonnull timer) { + if (observer) + { + [[NSNotificationCenter defaultCenter] removeObserver:observer]; + observer = nil; + } + [self createKeyBackupWithSuccess:success failure:failure]; + [timer invalidate]; + }]; + + return; + } [keyBackup forceRefresh:^(BOOL usingLastVersion) { From cd15a0d7a73f16f744a8d9fe1e793d8a75855c4b Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 13:18:06 +0300 Subject: [PATCH 15/65] Fixes on auth data fields and simplify signalable JSON generation --- .../Data/Aes256/MXAes256BackupAuthData.m | 27 +++++++------------ .../Curve25519/MXCurve25519BackupAuthData.m | 16 ++--------- .../KeyBackup/Data/MXBaseKeyBackupAuthData.h | 2 +- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m index d25d1cfe99..9a8f398c75 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m @@ -43,9 +43,15 @@ - (NSDictionary *)JSONDictionary { NSMutableDictionary *JSONDictionary = [NSMutableDictionary dictionary]; - JSONDictionary[@"iv"] = _iv; + if (_iv) + { + JSONDictionary[@"iv"] = _iv; + } - JSONDictionary[@"mac"] = _mac; + if (_mac) + { + JSONDictionary[@"mac"] = _mac; + } if (_privateKeySalt) { @@ -67,21 +73,8 @@ - (NSDictionary *)JSONDictionary - (NSDictionary *)signalableJSONDictionary { - NSMutableDictionary *signalableJSONDictionary = [NSMutableDictionary dictionary]; - - signalableJSONDictionary[@"iv"] = _iv; - signalableJSONDictionary[@"mac"] = _mac; - - if (_privateKeySalt) - { - signalableJSONDictionary[@"private_key_salt"] = _privateKeySalt; - } - - if (_privateKeySalt) - { - signalableJSONDictionary[@"private_key_iterations"] = @(_privateKeyIterations); - } - + NSMutableDictionary *signalableJSONDictionary = [NSMutableDictionary dictionaryWithDictionary:self.JSONDictionary]; + [signalableJSONDictionary removeObjectForKey:@"signatures"]; return signalableJSONDictionary; } diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m index c70d62f59b..2a9887738c 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m @@ -64,20 +64,8 @@ - (NSDictionary *)JSONDictionary - (NSDictionary *)signalableJSONDictionary { - NSMutableDictionary *signalableJSONDictionary = [NSMutableDictionary dictionary]; - - signalableJSONDictionary[@"public_key"] = _publicKey; - - if (_privateKeySalt) - { - signalableJSONDictionary[@"private_key_salt"] = _privateKeySalt; - } - - if (_privateKeySalt) - { - signalableJSONDictionary[@"private_key_iterations"] = @(_privateKeyIterations); - } - + NSMutableDictionary *signalableJSONDictionary = [NSMutableDictionary dictionaryWithDictionary:self.JSONDictionary]; + [signalableJSONDictionary removeObjectForKey:@"signatures"]; return signalableJSONDictionary; } diff --git a/MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h b/MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h index e33cf156e6..21f9f3821d 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h +++ b/MatrixSDK/Crypto/KeyBackup/Data/MXBaseKeyBackupAuthData.h @@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN Signatures of the public key. userId -> (deviceSignKeyId -> signature) */ -@property (nonatomic) NSDictionary *signatures; +@property (nonatomic, nullable) NSDictionary *signatures; /** Same as [MXJSONModel JSONDictionary]. From 5b883975593bccf5ec676534e090122bf9ff663f Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 13:19:42 +0300 Subject: [PATCH 16/65] Define a new method to generate auth data for different algorithm and implement --- .../Data/Aes256/MXAes256KeyBackupAlgorithm.m | 29 ++++++++++-- .../MXCurve25519KeyBackupAlgorithm.m | 21 +++++++++ MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 47 ++----------------- .../Crypto/KeyBackup/MXKeyBackupAlgorithm.h | 5 ++ 4 files changed, 56 insertions(+), 46 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index ee573fbe7d..8b417a5850 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -228,7 +228,7 @@ - (MXMegolmSessionData *)decryptKeyBackupData:(MXKeyBackupData *)keyBackupData f } else { - MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] decryptKeyBackupData: Failed to decrypt session from backup. Error: %@", error); + MXLogDebug(@"[MXAes256KeyBackupAlgorithm] decryptKeyBackupData: Failed to decrypt session from backup. Error: %@", error); } } @@ -242,6 +242,27 @@ + (BOOL)checkBackupVersion:(MXKeyBackupVersion *)backupVersion return iv != nil && mac != nil; } ++ (id)authDataFromJSON:(NSDictionary *)JSON error:(NSError *__autoreleasing _Nullable *)error +{ + MXAes256BackupAuthData *authData = [MXAes256BackupAuthData modelFromJSON:JSON]; + if (authData.iv && authData.mac) + { + return authData; + } + else + { + MXLogError(@"[MXAes256KeyBackupAlgorithm] authDataFromJSON: Auth data is missing required data"); + + *error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorMissingAuthDataCode + userInfo:@{ + NSLocalizedDescriptionKey: @"Auth data is missing required data" + }]; + + return nil; + } +} + #pragma mark - Private // Sanity checks on MXEncryptedSecretContent @@ -249,17 +270,17 @@ - (BOOL)checkEncryptedSecretContent:(MXEncryptedSecretContent*)encryptedSecret { if (!encryptedSecret.ciphertext) { - MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkEncryptedSecretContent: missing ciphertext"); + MXLogDebug(@"[MXAes256KeyBackupAlgorithm] checkEncryptedSecretContent: missing ciphertext"); return NO; } if (!encryptedSecret.mac) { - MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkEncryptedSecretContent: missing mac"); + MXLogDebug(@"[MXAes256KeyBackupAlgorithm] checkEncryptedSecretContent: missing mac"); return NO; } if (!encryptedSecret.iv) { - MXLogDebug(@"[MXCurve25519KeyBackupAlgorithm] checkEncryptedSecretContent: missing iv"); + MXLogDebug(@"[MXAes256KeyBackupAlgorithm] checkEncryptedSecretContent: missing iv"); return NO; } diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m index e312d1f01c..57785045b1 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m @@ -211,6 +211,27 @@ + (BOOL)checkBackupVersion:(MXKeyBackupVersion *)backupVersion return backupVersion.authData[@"public_key"] != nil; } ++ (id)authDataFromJSON:(NSDictionary *)JSON error:(NSError *__autoreleasing _Nullable *)error +{ + MXCurve25519BackupAuthData *authData = [MXCurve25519BackupAuthData modelFromJSON:JSON]; + if (authData.publicKey && authData.signatures) + { + return authData; + } + else + { + MXLogError(@"[MXCurve25519KeyBackupAlgorithm] authDataFromJSON: Auth data is missing required data"); + + *error = [NSError errorWithDomain:MXKeyBackupErrorDomain + code:MXKeyBackupErrorMissingAuthDataCode + userInfo:@{ + NSLocalizedDescriptionKey: @"Auth data is missing required data" + }]; + + return nil; + } +} + #pragma mark - Private + (NSString*)publicKeyFrom:(NSData*)privateKey diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index 2ec4582bbe..f8a6acfedb 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -1565,58 +1565,21 @@ - (nullable NSData*)privateKeyFromCryptoStore */ - (nullable id)megolmBackupAuthDataFromKeyBackupVersion:(MXKeyBackupVersion*)keyBackupVersion error:(NSError**)error { - if ([keyBackupVersion.algorithm isEqualToString:kMXCryptoCurve25519KeyBackupAlgorithm]) - { - MXCurve25519BackupAuthData *authData = [MXCurve25519BackupAuthData modelFromJSON:keyBackupVersion.authData]; - if (keyBackupVersion.algorithm && authData.publicKey && authData.signatures) - { - return authData; - } - else - { - MXLogError(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup is missing required data"); - - *error = [NSError errorWithDomain:MXKeyBackupErrorDomain - code:MXKeyBackupErrorMissingAuthDataCode - userInfo:@{ - NSLocalizedDescriptionKey: @"Key backup is missing required data" - }]; - - return nil; - } - } - else if ([keyBackupVersion.algorithm isEqualToString:kMXCryptoAes256KeyBackupAlgorithm]) - { - MXAes256BackupAuthData *authData = [MXAes256BackupAuthData modelFromJSON:keyBackupVersion.authData]; - if (keyBackupVersion.algorithm && authData.iv && authData.mac) - { - return authData; - } - else - { - MXLogError(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup is missing required data"); - - *error = [NSError errorWithDomain:MXKeyBackupErrorDomain - code:MXKeyBackupErrorMissingAuthDataCode - userInfo:@{ - NSLocalizedDescriptionKey: @"Key backup is missing required data" - }]; - - return nil; - } - } - else + Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; + if (algorithmClass == NULL) { MXLogError(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup for unknown algorithm: %@", keyBackupVersion.algorithm); *error = [NSError errorWithDomain:MXKeyBackupErrorDomain code:MXKeyBackupErrorUnknownAlgorithm userInfo:@{ - NSLocalizedDescriptionKey: @"Key backup for unknown algorithm" + NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Unknown algorithm (%@) for the backup", keyBackupVersion.algorithm] }]; return nil; } + + return [algorithmClass authDataFromJSON:keyBackupVersion.authData error:error]; } /** diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h index a690c0297d..fe04ac0c90 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h @@ -79,6 +79,11 @@ typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); /// @param backupVersion key backup version to check against + (BOOL)checkBackupVersion:(MXKeyBackupVersion *)backupVersion; +/// Generate auth data from a given dictionary. Returns nil if there is missing data in the dictionary. +/// @param JSON Auth data dictionary object +/// @param error error instance to be set on errors ++ (nullable id)authDataFromJSON:(NSDictionary*)JSON error:(NSError**)error; + @end NS_ASSUME_NONNULL_END From a8879c3ad4e7a47eac22282a48c8adbecde3b0c3 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 13:20:09 +0300 Subject: [PATCH 17/65] Use temporary algorithm for restoration, fix tests --- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index f8a6acfedb..2e384ef14b 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -1064,7 +1064,7 @@ - (MXHTTPOperation*)restoreUsingPrivateKeyKeyBackup:(MXKeyBackupVersion*)keyBack NSData *privateKey = self.privateKeyFromCryptoStore; NSError *error; - if (error || ![self.keyBackupAlgorithm keyMatches:privateKey error:&error]) + if (error || ![[self getOrCreateKeyBackupAlgorithmFor:keyBackupVersion privateKey:privateKey] keyMatches:privateKey error:&error]) { MXLogDebug(@"[MXKeyBackup] restoreUsingPrivateKeyKeyBackup. Error: Invalid private key (%@) for %@", privateKey, keyBackupVersion); if (failure) From 012708acb69f7c24bbcd17d9b5f00006b571f931 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 15:40:58 +0300 Subject: [PATCH 18/65] Remove redundant algorithm check --- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index 2e384ef14b..911c48ccad 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -204,16 +204,6 @@ - (NSError*)enableKeyBackup:(MXKeyBackupVersion*)version _keyBackupVersion = version; crypto.store.backupVersion = version.version; Class algorithmClass = AlgorithmClassesByName[version.algorithm]; - if (algorithmClass == NULL) - { - MXLogError(@"[MXKeyBackup] enableKeyBackup: unknown algorithm: %@", version.algorithm); - error = [NSError errorWithDomain:MXKeyBackupErrorDomain - code:MXKeyBackupErrorUnknownAlgorithm - userInfo:@{ - NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Unknown algorithm (%@) to enable backup", version.algorithm] - }]; - return error; - } // store the desired backup algorithm _keyBackupAlgorithm = [[algorithmClass alloc] initWithCrypto:crypto authData:authData keyGetterBlock:^NSData * _Nullable{ return self.privateKeyFromCryptoStore; From 4927e4972f47a9e685d97678ad2888827b731706 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 15:41:18 +0300 Subject: [PATCH 19/65] Align with the js-sdk on key backup trust --- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index 911c48ccad..ca6d8029ee 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -225,7 +225,7 @@ - (void)resetKeyBackupData self->crypto.store.backupVersion = nil; [self->crypto.store deleteSecretWithSecretId:MXSecretId.keyBackup]; - _keyBackupAlgorithm = nil; + _keyBackupAlgorithm = nil; // Reset backup markers [self->crypto.store resetBackupMarkers]; @@ -1112,13 +1112,6 @@ - (MXKeyBackupVersionTrust *)trustForKeyBackupVersionFromCryptoQueue:(MXKeyBacku return keyBackupVersionTrust; } - NSDictionary *mySigs = authData.signatures[myUserId]; - if (mySigs.count == 0) - { - MXLogDebug(@"[MXKeyBackup] trustForKeyBackupVersion: Ignoring key backup because it lacks any signatures from this user"); - return keyBackupVersionTrust; - } - NSData *privateKey = self.privateKeyFromCryptoStore; if (privateKey) { @@ -1130,6 +1123,7 @@ - (MXKeyBackupVersionTrust *)trustForKeyBackupVersionFromCryptoQueue:(MXKeyBacku } } + NSDictionary *mySigs = authData.signatures[myUserId]; NSMutableArray *signatures = [NSMutableArray array]; for (NSString *keyId in mySigs) { From e026523aa11d2923061cf07d5c0aca9eda72e258 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 15:41:50 +0300 Subject: [PATCH 20/65] Check signatures on auth data for Aes256 --- .../Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index 8b417a5850..c4846c7ab0 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -245,7 +245,7 @@ + (BOOL)checkBackupVersion:(MXKeyBackupVersion *)backupVersion + (id)authDataFromJSON:(NSDictionary *)JSON error:(NSError *__autoreleasing _Nullable *)error { MXAes256BackupAuthData *authData = [MXAes256BackupAuthData modelFromJSON:JSON]; - if (authData.iv && authData.mac) + if (authData.iv && authData.mac && authData.signatures) { return authData; } From b30d96a813551afc5c99d068537eb34b01b5d2d2 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 16:44:24 +0300 Subject: [PATCH 21/65] Use algorithm untrusted value on decryption --- .../Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m | 3 ++- .../KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m | 3 ++- MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index c4846c7ab0..418706a490 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -137,7 +137,7 @@ + (BOOL)keyMatches:(NSData *)privateKey withAuthData:(NSDictionary *)authData er } } -- (BOOL)isUntrusted ++ (BOOL)isUntrusted { return NO; } @@ -224,6 +224,7 @@ - (MXMegolmSessionData *)decryptKeyBackupData:(MXKeyBackupData *)keyBackupData f sessionData.sessionId = sessionId; sessionData.roomId = roomId; + sessionData.untrusted |= self.class.isUntrusted; } } else diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m index 57785045b1..3b9584ea4f 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m @@ -111,7 +111,7 @@ + (BOOL)keyMatches:(NSData *)privateKey withAuthData:(NSDictionary *)authData er return [[self.class publicKeyFrom:privateKey] isEqualToString:authData[@"public_key"]]; } -- (BOOL)isUntrusted ++ (BOOL)isUntrusted { return YES; } @@ -195,6 +195,7 @@ - (MXMegolmSessionData *)decryptKeyBackupData:(MXKeyBackupData *)keyBackupData f sessionData.sessionId = sessionId; sessionData.roomId = roomId; + sessionData.untrusted |= self.class.isUntrusted; } } else diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h index fe04ac0c90..a892305014 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h @@ -38,7 +38,7 @@ typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); @property (class, nonatomic, readonly) NSString *algorithName; /// Flag indicating the algorithm is untrusted or not. -@property (nonatomic, readonly, getter=isUntrusted) BOOL untrusted; +@property (class, nonatomic, readonly, getter=isUntrusted) BOOL untrusted; /// Initializer. Returns nil if the given auth data is invalid. From 90c9066c48cdf9d2bc6217226c67f76483dde9d7 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 8 Aug 2022 16:48:34 +0300 Subject: [PATCH 22/65] Pass untrusted flag to the event --- .../Background/MXBackgroundSyncService.swift | 1 + .../Crypto/Algorithms/MXDecryptionResult.h | 5 +++++ .../Crypto/Algorithms/MXEventDecryptionResult.h | 5 +++++ .../Algorithms/Megolm/MXMegolmDecryption.m | 1 + MatrixSDK/Crypto/MXOlmDevice.m | 3 +++ MatrixSDK/JSONModels/MXEvent.h | 6 ++++++ MatrixSDK/JSONModels/MXEvent.m | 17 +++++++++++++++++ 7 files changed, 38 insertions(+) diff --git a/MatrixSDK/Background/MXBackgroundSyncService.swift b/MatrixSDK/Background/MXBackgroundSyncService.swift index 06f7ab9d95..b1d4ab1899 100644 --- a/MatrixSDK/Background/MXBackgroundSyncService.swift +++ b/MatrixSDK/Background/MXBackgroundSyncService.swift @@ -450,6 +450,7 @@ public enum MXBackgroundSyncServiceError: Error { decryptionResult.senderCurve25519Key = olmResult.senderKey decryptionResult.claimedEd25519Key = olmResult.keysClaimed["ed25519"] as? String decryptionResult.forwardingCurve25519KeyChain = olmResult.forwardingCurve25519KeyChain + decryptionResult.isUntrusted = olmResult.isUntrusted event.setClearData(decryptionResult) } else if decryptorClass == MXOlmDecryption.self { guard let ciphertextDict = event.content["ciphertext"] as? [AnyHashable: Any], diff --git a/MatrixSDK/Crypto/Algorithms/MXDecryptionResult.h b/MatrixSDK/Crypto/Algorithms/MXDecryptionResult.h index a5f2eb36ca..d43bd2fb74 100644 --- a/MatrixSDK/Crypto/Algorithms/MXDecryptionResult.h +++ b/MatrixSDK/Crypto/Algorithms/MXDecryptionResult.h @@ -84,4 +84,9 @@ FOUNDATION_EXPORT NSString* const MXDecryptingErrorMissingPropertyReason; */ @property NSArray *forwardingCurve25519KeyChain; +/** + Flag indicating the decrpytion was made with an untrusted session. + */ +@property (nonatomic, getter=isUntrusted) BOOL untrusted; + @end diff --git a/MatrixSDK/Crypto/Algorithms/MXEventDecryptionResult.h b/MatrixSDK/Crypto/Algorithms/MXEventDecryptionResult.h index e0c353baff..ead490aeeb 100644 --- a/MatrixSDK/Crypto/Algorithms/MXEventDecryptionResult.h +++ b/MatrixSDK/Crypto/Algorithms/MXEventDecryptionResult.h @@ -50,4 +50,9 @@ */ @property (nonatomic) NSError *error; +/** + Flag indicating the decryption was made with an untrusted session. + */ +@property (nonatomic, getter=isUntrusted) BOOL untrusted; + @end diff --git a/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m b/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m index d41b6009d5..5c112331e4 100644 --- a/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m +++ b/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m @@ -116,6 +116,7 @@ - (MXEventDecryptionResult *)decryptEvent:(MXEvent*)event inTimeline:(NSString*) result.senderCurve25519Key = olmResult.senderKey; result.claimedEd25519Key = olmResult.keysClaimed[@"ed25519"]; result.forwardingCurve25519KeyChain = olmResult.forwardingCurve25519KeyChain; + result.untrusted = olmResult.isUntrusted; } else { diff --git a/MatrixSDK/Crypto/MXOlmDevice.m b/MatrixSDK/Crypto/MXOlmDevice.m index 596c067365..a3b9aa0383 100644 --- a/MatrixSDK/Crypto/MXOlmDevice.m +++ b/MatrixSDK/Crypto/MXOlmDevice.m @@ -458,6 +458,7 @@ - (MXDecryptionResult *)decryptGroupMessage:(NSString *)body __block NSString *payloadString; __block NSDictionary *keysClaimed; __block NSArray *forwardingCurve25519KeyChain; + __block BOOL untrusted; MXDecryptionResult *result; @@ -474,6 +475,7 @@ - (MXDecryptionResult *)decryptGroupMessage:(NSString *)body payloadString = [session.session decryptMessage:body messageIndex:&messageIndex error:error]; keysClaimed = session.keysClaimed; forwardingCurve25519KeyChain = session.forwardingCurve25519KeyChain; + untrusted = session.isUntrusted; } }]; @@ -513,6 +515,7 @@ - (MXDecryptionResult *)decryptGroupMessage:(NSString *)body result.keysClaimed = keysClaimed; result.senderKey = senderKey; result.forwardingCurve25519KeyChain = forwardingCurve25519KeyChain; + result.untrusted = untrusted; } return result; diff --git a/MatrixSDK/JSONModels/MXEvent.h b/MatrixSDK/JSONModels/MXEvent.h index 675c34d6c1..aa3c38124f 100644 --- a/MatrixSDK/JSONModels/MXEvent.h +++ b/MatrixSDK/JSONModels/MXEvent.h @@ -670,6 +670,12 @@ extern NSString *const kMXEventIdentifierKey; */ @property (nonatomic, readonly) MXEvent *clearEvent; +/** + Flag indicating the event was decrypted with an untrusted key. + If the event cannot be decrypted yet or the event not encrypted at all, this flag would be NO. + */ +@property (nonatomic, readonly, getter=isUntrusted) BOOL untrusted; + /** The curve25519 key for the device that we think sent this event. diff --git a/MatrixSDK/JSONModels/MXEvent.m b/MatrixSDK/JSONModels/MXEvent.m index c1fcd18faa..80d15868fe 100644 --- a/MatrixSDK/JSONModels/MXEvent.m +++ b/MatrixSDK/JSONModels/MXEvent.m @@ -226,6 +226,11 @@ megolm session (for megolm) claims to own. See `forwardingCurve25519KeyChain` property. */ NSArray *forwardingCurve25519KeyChain; + + /** + Untrusted flag for clear events. + */ + BOOL untrusted; } @end @@ -242,6 +247,7 @@ - (instancetype)init if (self) { _ageLocalTs = -1; + untrusted = NO; } return self; @@ -1024,6 +1030,7 @@ - (void)setClearData:(MXEventDecryptionResult *)decryptionResult _clearEvent->senderCurve25519Key = decryptionResult.senderCurve25519Key; _clearEvent->claimedEd25519Key = decryptionResult.claimedEd25519Key; _clearEvent->forwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain ? decryptionResult.forwardingCurve25519KeyChain : @[]; + _clearEvent->untrusted = decryptionResult.isUntrusted; } // Notify only for events that are lately decrypted @@ -1143,6 +1150,7 @@ - (MXEventDecryptionResult*)decryptionResult decryptionResult.senderCurve25519Key = _clearEvent->senderCurve25519Key; decryptionResult.claimedEd25519Key = _clearEvent->claimedEd25519Key; decryptionResult.forwardingCurve25519KeyChain = _clearEvent->forwardingCurve25519KeyChain; + decryptionResult.untrusted = _clearEvent.isUntrusted; } decryptionResult.error = _decryptionError; @@ -1150,6 +1158,15 @@ - (MXEventDecryptionResult*)decryptionResult return decryptionResult; } +- (BOOL)isUntrusted +{ + if (self.isEncrypted && _clearEvent) + { + return _clearEvent.isUntrusted; + } + return untrusted; +} + #pragma mark - private - (NSMutableDictionary*)filterInEventWithKeys:(NSArray*)keys { From e86955313bfd274ff61e5af680e865f77009939f Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Tue, 9 Aug 2022 10:40:44 +0300 Subject: [PATCH 23/65] Fix issues in Aes algorithm, log algorithm in key backup --- .../Data/Aes256/MXAes256KeyBackupAlgorithm.m | 49 +++++++++++++------ MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 1 + 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index 418706a490..6ef9e7b7f7 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -42,7 +42,7 @@ @interface MXAes256KeyBackupAlgorithm () @property (nonatomic, strong) MXAes256BackupAuthData *authData; -@property (nonatomic, copy) NSData *privateKey; +@property (nonatomic, copy) MXKeyBackupPrivateKeyGetterBlock keyGetterBlock; @end @@ -62,21 +62,10 @@ - (instancetype)initWithCrypto:(MXCrypto *)crypto authData:(id Date: Tue, 9 Aug 2022 10:45:15 +0300 Subject: [PATCH 24/65] Refactor key backup tests to allow different algorithms --- MatrixSDK.xcodeproj/project.pbxproj | 26 +- MatrixSDKTests/MXAes256KeyBackupTests.m | 91 +++++ MatrixSDKTests/MXBaseKeyBackupTests.h | 35 ++ ...toBackupTests.m => MXBaseKeyBackupTests.m} | 369 +++++++++--------- MatrixSDKTests/MXCurve25519KeyBackupTests.m | 125 ++++++ 5 files changed, 449 insertions(+), 197 deletions(-) create mode 100644 MatrixSDKTests/MXAes256KeyBackupTests.m create mode 100644 MatrixSDKTests/MXBaseKeyBackupTests.h rename MatrixSDKTests/{MXCryptoBackupTests.m => MXBaseKeyBackupTests.m} (88%) create mode 100644 MatrixSDKTests/MXCurve25519KeyBackupTests.m diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index b4dbc0a32b..00b5d513f2 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -424,7 +424,7 @@ 3291DC8423DF52E20009732F /* MXRoomCreationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 3291DC8123DF52E10009732F /* MXRoomCreationParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3291DC8523DF52E20009732F /* MXRoomCreationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 3291DC8223DF52E10009732F /* MXRoomCreationParameters.m */; }; 3291DC8623DF52E20009732F /* MXRoomCreationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 3291DC8223DF52E10009732F /* MXRoomCreationParameters.m */; }; - 32935F61216FA49D00A1BC24 /* MXCryptoBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32935F60216FA49D00A1BC24 /* MXCryptoBackupTests.m */; }; + 32935F61216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32935F60216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m */; }; 3293C700214BBA4F009B3DDB /* MXPeekingRoomSummary.h in Headers */ = {isa = PBXBuildFile; fileRef = 3293C6FE214BBA4F009B3DDB /* MXPeekingRoomSummary.h */; }; 3293C701214BBA4F009B3DDB /* MXPeekingRoomSummary.m in Sources */ = {isa = PBXBuildFile; fileRef = 3293C6FF214BBA4F009B3DDB /* MXPeekingRoomSummary.m */; }; 3294FD9D22F321B0007F1E60 /* MXServiceTermsRestClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 3294FD9922F321B0007F1E60 /* MXServiceTermsRestClient.m */; }; @@ -1356,7 +1356,7 @@ B1E09A1D2397FCE90057C069 /* MXCryptoKeyVerificationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 329E808E22512DF500A48C3A /* MXCryptoKeyVerificationTests.m */; }; B1E09A1E2397FCE90057C069 /* MXCryptoShareTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 322D01C322492B0700150C68 /* MXCryptoShareTests.m */; }; B1E09A1F2397FCE90057C069 /* MXAutoDiscoveryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32720DA1222EB5650086FFF5 /* MXAutoDiscoveryTests.m */; }; - B1E09A202397FCE90057C069 /* MXCryptoBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32935F60216FA49D00A1BC24 /* MXCryptoBackupTests.m */; }; + B1E09A202397FCE90057C069 /* MXCurve25519KeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32935F60216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m */; }; B1E09A212397FCE90057C069 /* DirectRoomTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32C03CB52123076F00D92712 /* DirectRoomTests.m */; }; B1E09A222397FCE90057C069 /* MXRoomSummaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 320E1BC01E0AD674009635F5 /* MXRoomSummaryTests.m */; }; B1E09A242397FCE90057C069 /* MXPeekingRoomTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E226A81D081CE200E6CA54 /* MXPeekingRoomTests.m */; }; @@ -1568,6 +1568,10 @@ EC403859289C38BB0067D5B8 /* MXKeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403841289A70FC0067D5B8 /* MXKeyBackupAlgorithm.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC40385A289C38FB0067D5B8 /* MXKeyBackupPreparationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403852289ACDBB0067D5B8 /* MXKeyBackupPreparationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC40385B289C38FB0067D5B8 /* MXKeyBackupPreparationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403852289ACDBB0067D5B8 /* MXKeyBackupPreparationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC40385D28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EC40385C28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m */; }; + EC40385E28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EC40385C28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m */; }; + EC40386128A1A3830067D5B8 /* MXBaseKeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */; }; + EC40386228A1A3830067D5B8 /* MXBaseKeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */; }; EC51019D26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC51019E26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC5C560A2798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h in Headers */ = {isa = PBXBuildFile; fileRef = EC5C56082798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h */; }; @@ -2242,7 +2246,7 @@ 3291D4D31A68FFEB00C3BA41 /* MXFileRoomStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXFileRoomStore.m; sourceTree = ""; }; 3291DC8123DF52E10009732F /* MXRoomCreationParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXRoomCreationParameters.h; sourceTree = ""; }; 3291DC8223DF52E10009732F /* MXRoomCreationParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXRoomCreationParameters.m; sourceTree = ""; }; - 32935F60216FA49D00A1BC24 /* MXCryptoBackupTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXCryptoBackupTests.m; sourceTree = ""; }; + 32935F60216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXCurve25519KeyBackupTests.m; sourceTree = ""; }; 3293C6FE214BBA4F009B3DDB /* MXPeekingRoomSummary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXPeekingRoomSummary.h; sourceTree = ""; }; 3293C6FF214BBA4F009B3DDB /* MXPeekingRoomSummary.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXPeekingRoomSummary.m; sourceTree = ""; }; 3294FD9922F321B0007F1E60 /* MXServiceTermsRestClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXServiceTermsRestClient.m; sourceTree = ""; }; @@ -2731,6 +2735,9 @@ EC40384E289A906A0067D5B8 /* MXBaseKeyBackupAuthData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXBaseKeyBackupAuthData.h; sourceTree = ""; }; EC403852289ACDBB0067D5B8 /* MXKeyBackupPreparationInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKeyBackupPreparationInfo.h; sourceTree = ""; }; EC403853289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXKeyBackupPreparationInfo.m; sourceTree = ""; }; + EC40385C28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXAes256KeyBackupTests.m; sourceTree = ""; }; + EC40385F28A1A25C0067D5B8 /* MXBaseKeyBackupTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXBaseKeyBackupTests.h; sourceTree = ""; }; + EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXBaseKeyBackupTests.m; sourceTree = ""; }; EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSyncResponseUnitTests.swift; sourceTree = ""; }; EC5C56082798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+MutableDeepCopy.h"; sourceTree = ""; }; EC5C56092798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+MutableDeepCopy.m"; sourceTree = ""; }; @@ -4046,7 +4053,10 @@ 329E808E22512DF500A48C3A /* MXCryptoKeyVerificationTests.m */, 322D01C322492B0700150C68 /* MXCryptoShareTests.m */, 32720DA1222EB5650086FFF5 /* MXAutoDiscoveryTests.m */, - 32935F60216FA49D00A1BC24 /* MXCryptoBackupTests.m */, + EC40385F28A1A25C0067D5B8 /* MXBaseKeyBackupTests.h */, + EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */, + 32935F60216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m */, + EC40385C28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m */, 32C03CB52123076F00D92712 /* DirectRoomTests.m */, 320E1BC01E0AD674009635F5 /* MXRoomSummaryTests.m */, 32322A471E57264E005DD155 /* MXSelfSignedHomeserverTests.m */, @@ -6676,6 +6686,7 @@ 3281E89E19E299C000976E1A /* MXErrorUnitTests.m in Sources */, EC51019D26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */, EDB4209527DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift in Sources */, + EC40385D28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m in Sources */, 3265CB3B1A151C3800E24B2F /* MXRoomStateTests.m in Sources */, B135066927EA100000BD3276 /* MXBeaconInfoUnitTests.swift in Sources */, EC0B944627206D0B00B4D440 /* MXCoreDataRoomListDataManagerUnitTests.swift in Sources */, @@ -6684,6 +6695,7 @@ EC1165CE27107F3E0089FA56 /* MXRoomListDataManagerTests.swift in Sources */, 324BE45B1E3FA7A8008D99D4 /* MXMegolmExportEncryptionUnitTests.m in Sources */, 327E9ACF2284783E00A98BC1 /* MXEventAnnotationUnitTests.swift in Sources */, + EC40386128A1A3830067D5B8 /* MXBaseKeyBackupTests.m in Sources */, 32EEA84A2603FDD60041425B /* MXResponseUnitTests.swift in Sources */, 32322A481E57264E005DD155 /* MXSelfSignedHomeserverTests.m in Sources */, 325653831A2E14ED00CC0423 /* MXStoreTests.m in Sources */, @@ -6710,7 +6722,7 @@ 32B0E3E423A384D40054FF1A /* MXAggregatedReferenceTests.m in Sources */, 32D5D16323E400A600E3E37C /* MXRoomSummaryTrustTests.m in Sources */, C61A4AF41E5DD88400442158 /* Dummy.swift in Sources */, - 32935F61216FA49D00A1BC24 /* MXCryptoBackupTests.m in Sources */, + 32935F61216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m in Sources */, B1F04B162811EFF700103EBE /* MXBeaconAggregationsTests.swift in Sources */, 328DDEC11A07E57E008C7DC8 /* MXJSONModelTests.m in Sources */, 32832B5C1BCC048300241108 /* MXStoreFileStoreTests.m in Sources */, @@ -7222,7 +7234,7 @@ 322985D326FC9E61001890BC /* MXSessionTracker.swift in Sources */, B1E09A392397FD7D0057C069 /* MXMyUserTests.m in Sources */, 322985D026FBAE7B001890BC /* TestObserver.swift in Sources */, - B1E09A202397FCE90057C069 /* MXCryptoBackupTests.m in Sources */, + B1E09A202397FCE90057C069 /* MXCurve25519KeyBackupTests.m in Sources */, ED51943A28462D130006EEC6 /* MXRoomStateUnitTests.swift in Sources */, B1E09A3B2397FD820057C069 /* MXStoreNoStoreTests.m in Sources */, EDB4209327DF77390036AF39 /* MXEventsEnumeratorOnArrayTests.swift in Sources */, @@ -7249,6 +7261,7 @@ 32EEA8402603CA140041425B /* MXRestClientExtensionsTests.m in Sources */, EC51019E26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */, EDB4209627DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift in Sources */, + EC40385E28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m in Sources */, 32B477AA2638186000EA5800 /* MXHTTPAdditionalHeadersUnitTests.m in Sources */, B135066A27EA100100BD3276 /* MXBeaconInfoUnitTests.swift in Sources */, EC0B944727206D0B00B4D440 /* MXCoreDataRoomListDataManagerUnitTests.swift in Sources */, @@ -7257,6 +7270,7 @@ EC1165CF27107F3E0089FA56 /* MXRoomListDataManagerTests.swift in Sources */, B1E09A3E2397FD820057C069 /* MXToolsUnitTests.m in Sources */, 32B477912638133D00EA5800 /* MXAggregatedEditsUnitTests.m in Sources */, + EC40386228A1A3830067D5B8 /* MXBaseKeyBackupTests.m in Sources */, B1E09A1E2397FCE90057C069 /* MXCryptoShareTests.m in Sources */, B1E09A422397FD820057C069 /* MXCryptoTests.m in Sources */, B1E09A382397FD7D0057C069 /* MXUserTests.m in Sources */, diff --git a/MatrixSDKTests/MXAes256KeyBackupTests.m b/MatrixSDKTests/MXAes256KeyBackupTests.m new file mode 100644 index 0000000000..b6280f3935 --- /dev/null +++ b/MatrixSDKTests/MXAes256KeyBackupTests.m @@ -0,0 +1,91 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXBaseKeyBackupTests.h" + +#import "MXAes256BackupAuthData.h" +#import "MXAes256KeyBackupAlgorithm.h" + +// Do not bother with retain cycles warnings in tests +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + +@interface MXAes256KeyBackupTests : MXBaseKeyBackupTests + +@end + +@implementation MXAes256KeyBackupTests + +- (NSString *)algorithm +{ + return kMXCryptoAes256KeyBackupAlgorithm; +} + +- (BOOL)isUntrusted +{ + return MXAes256KeyBackupAlgorithm.isUntrusted; +} + +- (MXKeyBackupVersion*)fakeKeyBackupVersion +{ + return [MXKeyBackupVersion modelFromJSON:@{ + @"algorithm": self.algorithm, + @"auth_data": @{ + @"iv": @"abcdefg", + @"mac": @"bvnzmzxbnm", + @"signatures": @{ + @"something": @{ + @"ed25519:something": @"hijklmnop" + } + } + } + }]; +} + +/** + Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data + */ +- (void)testPrepareKeyBackupVersion +{ + [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { + + XCTAssertNotNil(aliceSession.crypto.backup); + XCTAssertFalse(aliceSession.crypto.backup.enabled); + + // Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + + XCTAssertNotNil(keyBackupCreationInfo); + XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoAes256KeyBackupAlgorithm); + XCTAssertTrue([keyBackupCreationInfo.authData isKindOfClass:MXAes256BackupAuthData.class]); + MXAes256BackupAuthData *authData = (MXAes256BackupAuthData*) keyBackupCreationInfo.authData; + XCTAssertNotNil(authData.iv); + XCTAssertNotNil(authData.mac); + XCTAssertNotNil(authData.signatures); + XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); + + [expectation fulfill]; + + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + }]; +} + +@end + +#pragma clang diagnostic pop diff --git a/MatrixSDKTests/MXBaseKeyBackupTests.h b/MatrixSDKTests/MXBaseKeyBackupTests.h new file mode 100644 index 0000000000..6a67861c3b --- /dev/null +++ b/MatrixSDKTests/MXBaseKeyBackupTests.h @@ -0,0 +1,35 @@ +// +// Copyright 2022 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 + +#import "MatrixSDKTestsData.h" +#import "MatrixSDKTestsE2EData.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MXBaseKeyBackupTests : XCTestCase +{ + MatrixSDKTestsData *matrixSDKTestsData; + MatrixSDKTestsE2EData *matrixSDKTestsE2EData; +} + +- (NSString*)algorithm; +- (MXKeyBackupVersion*)fakeKeyBackupVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MatrixSDKTests/MXCryptoBackupTests.m b/MatrixSDKTests/MXBaseKeyBackupTests.m similarity index 88% rename from MatrixSDKTests/MXCryptoBackupTests.m rename to MatrixSDKTests/MXBaseKeyBackupTests.m index 9874bf9287..1c36a38645 100644 --- a/MatrixSDKTests/MXCryptoBackupTests.m +++ b/MatrixSDKTests/MXBaseKeyBackupTests.m @@ -14,10 +14,7 @@ limitations under the License. */ -#import - -#import "MatrixSDKTestsData.h" -#import "MatrixSDKTestsE2EData.h" +#import "MXBaseKeyBackupTests.h" #import "MXCrypto_Private.h" #import "MXCryptoStore.h" @@ -26,20 +23,9 @@ #import "MXOutboundSessionInfo.h" #import "MXCrossSigning_Private.h" #import "MXKeyBackupAlgorithm.h" -#import "MXCurve25519BackupAuthData.h" - -// Do not bother with retain cycles warnings in tests -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-retain-cycles" +#import "MXAes256BackupAuthData.h" -@interface MXCryptoBackupTests : XCTestCase -{ - MatrixSDKTestsData *matrixSDKTestsData; - MatrixSDKTestsE2EData *matrixSDKTestsE2EData; -} -@end - -@implementation MXCryptoBackupTests +@implementation MXBaseKeyBackupTests - (void)setUp { @@ -57,22 +43,50 @@ - (void)tearDown [super tearDown]; } ++ (XCTestSuite *)defaultTestSuite +{ + XCTestSuite *suite = [[XCTestSuite alloc] initWithName:NSStringFromClass(self)]; + + if ([NSStringFromClass(self.superclass) isEqualToString:NSStringFromClass(XCTestCase.class)]) + { + NSLog(@"[MXBaseKeyBackupTests] This test case is not supposed to run, please run sub test cases."); + // this is the base class, do not run tests on it + return suite; + } + + for (NSInvocation *invocation in self.testInvocations) + { + XCTest *test = [[self alloc] initWithInvocation:invocation]; + [suite addTest:test]; + } + + return suite; +} + +- (NSString *)algorithm +{ + XCTFail(@"Method must be overridden"); + + return @""; +} + +- (BOOL)isUntrusted +{ + XCTFail(@"Method must be overridden"); + + return YES; +} + - (MXKeyBackupVersion*)fakeKeyBackupVersion { + XCTFail(@"Method must be overridden"); + return [MXKeyBackupVersion modelFromJSON:@{ - @"algorithm": kMXCryptoCurve25519KeyBackupAlgorithm, - @"auth_data": @{ - @"public_key": @"abcdefg", - @"signatures": @{ - @"something": @{ - @"ed25519:something": @"hijklmnop" - } - } - } - }]; + @"algorithm": @"", + @"auth_data": @{} + }]; } - /** - Create a backup version on the server - Get the current version from the server @@ -96,7 +110,7 @@ - (void)testRESTCreateKeyBackupVersion XCTAssertEqualObjects(keyBackupVersion2.authData, keyBackupVersion.authData); [expectation fulfill]; - + } failure:^(NSError *error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; @@ -127,8 +141,8 @@ - (void)testRESTBackupKeys keyBackupData.forwardedCount = 2; keyBackupData.verified = YES; keyBackupData.sessionData = @{ - @"key": @"value" - }; + @"key": @"value" + }; NSString *roomId = @"!aRoomId:matrix.org"; NSString *sessionId = @"ASession"; @@ -180,8 +194,8 @@ - (void)testRESTDeleteBackupKeys keyBackupData.forwardedCount = 2; keyBackupData.verified = YES; keyBackupData.sessionData = @{ - @"key": @"value" - }; + @"key": @"value" + }; NSString *roomId = @"!aRoomId:matrix.org"; NSString *sessionId = @"ASession"; @@ -221,10 +235,10 @@ - (void)testRESTDeleteBackupKeys /** -- From doE2ETestWithAliceAndBobInARoomWithCryptedMessages, we should have no backed up keys -- Check backup keys after having marked one as backed up -- Reset keys backup markers -*/ + - From doE2ETestWithAliceAndBobInARoomWithCryptedMessages, we should have no backed up keys + - Check backup keys after having marked one as backed up + - Reset keys backup markers + */ - (void)testBackupStore { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { @@ -350,7 +364,7 @@ - (void)testPasswordInteroperability 195, 154, 64, 158, 184, 148, 20, 85 }; NSData *privateKey = [NSData dataWithBytes:privateKeyBytes length:sizeof(privateKeyBytes)]; - + NSError *error; NSData *retrievedPrivateKey = [MXKeyBackupPassword retrievePrivateKeyWithPassword:password salt:salt iterations:iterations error:&error]; XCTAssertNil(error); @@ -361,36 +375,6 @@ - (void)testPasswordInteroperability XCTAssertEqualObjects(retrievedPrivateKey, privateKey); } -/** - Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data - */ -- (void)testPrepareKeyBackupVersion -{ - [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - - XCTAssertNotNil(aliceSession.crypto.backup); - XCTAssertFalse(aliceSession.crypto.backup.enabled); - - // Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { - - XCTAssertNotNil(keyBackupCreationInfo); - XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); - XCTAssertTrue([keyBackupCreationInfo.authData isKindOfClass:MXCurve25519BackupAuthData.class]); - MXCurve25519BackupAuthData *authData = (MXCurve25519BackupAuthData*) keyBackupCreationInfo.authData; - XCTAssertNotNil(authData.publicKey); - XCTAssertNotNil(authData.signatures); - XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); - - [expectation fulfill]; - - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - }]; -} - /** Check that `[MXKeyBackup createKeyBackupVersion` returns valid data */ @@ -401,10 +385,10 @@ - (void)testCreateKeyBackupVersion XCTAssertFalse(aliceSession.crypto.backup.enabled); // Check that `[MXKeyBackup createKeyBackupVersion` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { - XCTAssertEqualObjects(keyBackupVersion.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); + XCTAssertEqualObjects(keyBackupVersion.algorithm, self.algorithm); XCTAssertTrue([keyBackupVersion.authData isEqualToDictionary:keyBackupCreationInfo.authData.JSONDictionary]); XCTAssertNotNil(keyBackupVersion.version); @@ -432,14 +416,14 @@ - (void)testBackupAfterCreateKeyBackupVersion { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { // Check that `[MXKeyBackup createKeyBackupVersion` launches the backup XCTAssert(aliceSession.crypto.backup.state == MXKeyBackupStateEnabling || aliceSession.crypto.backup.state == MXKeyBackupStateWillBackUp); - NSUInteger keys = [aliceSession.crypto.store inboundGroupSessionsCount:NO]; + NSUInteger keys = [aliceSession.crypto.store inboundGroupSessionsCount:NO]; __block id observer; observer = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKeyBackupDidStateChangeNotification object:aliceSession.crypto.backup queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { @@ -477,7 +461,7 @@ - (void)testTrustForKeyBackupVersion // - Create a backup version [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { // - Check the returned MXKeyBackupVersion is trusted @@ -518,22 +502,22 @@ - (void)testCrossSigningMSKTrustForKeyBackupVersion { // - Alice and Bob have messages in a room [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - + // - Alice has cross-signing enabled [aliceSession.crypto.crossSigning setupWithPassword:MXTESTS_ALICE_PWD success:^{ - + // - Alice creates a backup - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo *keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo *keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion *keyBackupVersion) { - + // - Check the returned MXKeyBackupVersion is trusted [aliceSession.crypto.backup trustForKeyBackupVersion:keyBackupVersion onComplete:^(MXKeyBackupVersionTrust *keyBackupVersionTrust) { - + // -> It must be trusted by 2 entities XCTAssertNotNil(keyBackupVersionTrust); XCTAssertTrue(keyBackupVersionTrust.usable); XCTAssertEqual(keyBackupVersionTrust.signatures.count, 2); - + [keyBackupVersionTrust.signatures enumerateObjectsUsingBlock:^(MXKeyBackupVersionTrustSignature *signature, NSUInteger idx, BOOL *stop) { if (signature.keys) { // Check if valid MSK signature @@ -546,10 +530,10 @@ - (void)testCrossSigningMSKTrustForKeyBackupVersion XCTAssertEqualObjects(signature.device.deviceId, aliceSession.matrixRestClient.credentials.deviceId); } }]; - + [expectation fulfill]; }]; - + } failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; @@ -558,7 +542,7 @@ - (void)testCrossSigningMSKTrustForKeyBackupVersion XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; }]; - + } failure:^(NSError * _Nonnull error) { XCTFail(@"Cannot set up initial test conditions - error: %@", error); [expectation fulfill]; @@ -574,7 +558,7 @@ - (void)testBackupAllGroupSessions [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // Check that `[MXKeyBackup backupAllGroupSessions]` returns valid data - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { NSUInteger keys = [aliceSession.crypto.store inboundGroupSessionsCount:NO]; @@ -623,8 +607,9 @@ - (void)testEncryptAndDecryptKeyBackupData // - Pick a megolm key MXOlmInboundGroupSession *session = [aliceSession.crypto.store inboundGroupSessionsToBackup:1].firstObject; + session.untrusted = self.isUntrusted; - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { // - Check [MXKeyBackupAlgorithm encryptGroupSession] returns stg @@ -662,9 +647,13 @@ - (void)createKeyBackupScenarioWithPassword:(NSString*)password readyToTest:(voi [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { NSArray *aliceKeys = [aliceSession.crypto.store inboundGroupSessionsToBackup:100]; + for (MXOlmInboundGroupSession *key in aliceKeys) + { + key.untrusted = self.isUntrusted; + } // - Do an e2e backup to the homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession.crypto.backup backupAllGroupSessions:^{ @@ -737,15 +726,15 @@ - (void)testRestoreKeyBackup session:nil success:^(NSUInteger total, NSUInteger imported) { - // - Restore must be successful - [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; + // - Restore must be successful + [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; - [expectation fulfill]; + [expectation fulfill]; - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; }]; } @@ -767,19 +756,19 @@ - (void)testRestoreKeyBackupWithAWrongRecoveryKey room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - // - It must fail - XCTFail(@"It must fail"); + // - It must fail + XCTFail(@"It must fail"); - [expectation fulfill]; + [expectation fulfill]; - } failure:^(NSError * _Nonnull error) { + } failure:^(NSError * _Nonnull error) { - // - It must fail - XCTAssertEqualObjects(error.domain, MXKeyBackupErrorDomain); - XCTAssertEqual(error.code, MXKeyBackupErrorInvalidRecoveryKeyCode); + // - It must fail + XCTAssertEqualObjects(error.domain, MXKeyBackupErrorDomain); + XCTAssertEqual(error.code, MXKeyBackupErrorInvalidRecoveryKeyCode); - [expectation fulfill]; - }]; + [expectation fulfill]; + }]; }]; } @@ -803,15 +792,15 @@ - (void)testRestoreKeyBackupWithPassword room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - // - Restore must be successful - [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; + // - Restore must be successful + [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; - [expectation fulfill]; + [expectation fulfill]; - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; }]; } @@ -833,19 +822,19 @@ - (void)testRestoreKeyBackupWithAWrongPassword room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - // - It must fail - XCTFail(@"It must fail"); + // - It must fail + XCTFail(@"It must fail"); - [expectation fulfill]; + [expectation fulfill]; - } failure:^(NSError * _Nonnull error) { + } failure:^(NSError * _Nonnull error) { - // - It must fail - XCTAssertEqualObjects(error.domain, MXKeyBackupErrorDomain); - XCTAssertEqual(error.code, MXKeyBackupErrorInvalidRecoveryKeyCode); + // - It must fail + XCTAssertEqualObjects(error.domain, MXKeyBackupErrorDomain); + XCTAssertEqual(error.code, MXKeyBackupErrorInvalidRecoveryKeyCode); - [expectation fulfill]; - }]; + [expectation fulfill]; + }]; }]; } @@ -869,15 +858,15 @@ - (void)testUseRecoveryKeyToRestoreAPasswordKeyKeyBackup room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - // - Restore must be successful - [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; + // - Restore must be successful + [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; - [expectation fulfill]; + [expectation fulfill]; - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; }]; } @@ -899,19 +888,19 @@ - (void)testUsePasswordToRestoreARecoveryKeyKeyBackup room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - // - It must fail - XCTFail(@"Restoring with a password a backup created with only a recovery key must fail"); + // - It must fail + XCTFail(@"Restoring with a password a backup created with only a recovery key must fail"); - [expectation fulfill]; + [expectation fulfill]; - } failure:^(NSError * _Nonnull error) { + } failure:^(NSError * _Nonnull error) { - // - It must fail - XCTAssertEqualObjects(error.domain, MXKeyBackupErrorDomain); - XCTAssertEqual(error.code, MXKeyBackupErrorMissingPrivateKeySaltCode); + // - It must fail + XCTAssertEqualObjects(error.domain, MXKeyBackupErrorDomain); + XCTAssertEqual(error.code, MXKeyBackupErrorMissingPrivateKeySaltCode); - [expectation fulfill]; - }]; + [expectation fulfill]; + }]; }]; } @@ -929,14 +918,14 @@ - (void)testCheckAndStartKeyBackupWhenRestartingAMatrixSession XCTAssertFalse(aliceSession.crypto.backup.enabled); - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { XCTAssertTrue(aliceSession.crypto.backup.enabled); // - Restart alice session MXSession *aliceSession2 = [[MXSession alloc] initWithMatrixRestClient:aliceSession.matrixRestClient]; - [matrixSDKTestsData retain:aliceSession2]; + [self->matrixSDKTestsData retain:aliceSession2]; [aliceSession close]; [aliceSession2 start:nil failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); @@ -981,7 +970,7 @@ - (void)testBackupWhenAnotherBackupWasCreated [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Make alice back up her keys to her homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { XCTAssertTrue(aliceSession.crypto.backup.enabled); @@ -1036,16 +1025,16 @@ - (void)testBackupAfterVerifyingADevice [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // - Do an e2e backup to the homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession.crypto.backup backupAllGroupSessions:^{ NSString *oldDeviceId = aliceSession.matrixRestClient.credentials.deviceId; - MXKeyBackupVersion *oldKeyBackupVersion = aliceSession.crypto.backup.keyBackupVersion; + MXKeyBackupVersion *oldKeyBackupVersion = keyBackupVersion; // - Log Alice on a new device [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - [matrixSDKTestsData relogUserSessionWithNewDevice:self session:aliceSession withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { + [self->matrixSDKTestsData relogUserSessionWithNewDevice:self session:aliceSession withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; // - Post a message to have a new megolm session @@ -1148,26 +1137,26 @@ - (void)testRestoreKeyBackupAndKeyShareRequests room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - // - Restore must be successful - [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; + // - Restore must be successful + [self checkRestoreSuccess:aliceKeys aliceSession:aliceSession total:total imported:imported]; - // Wait to check that no notification happens - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + // Wait to check that no notification happens + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - // - There must be no more pending key share requests - [self->matrixSDKTestsE2EData outgoingRoomKeyRequestInSession:aliceSession complete:^(MXOutgoingRoomKeyRequest *outgoingRoomKeyRequest) { + // - There must be no more pending key share requests + [self->matrixSDKTestsE2EData outgoingRoomKeyRequestInSession:aliceSession complete:^(MXOutgoingRoomKeyRequest *outgoingRoomKeyRequest) { - XCTAssertNil(outgoingRoomKeyRequest); + XCTAssertNil(outgoingRoomKeyRequest); - [expectation fulfill]; - }]; + [expectation fulfill]; + }]; - }); + }); - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; }]; }]; @@ -1427,15 +1416,15 @@ - (void)testTrustKeyBackupVersionWithWrongPassword - (void)testLocalPrivateKey { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - + // - Do an e2e backup to the homeserver - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession.crypto.backup backupAllGroupSessions:^{ - + // -> We must have the backup private key locally XCTAssertTrue(aliceSession.crypto.backup.hasPrivateKeyInCryptoStore); - + // - Restart the session MXSession *aliceSession2 = [[MXSession alloc] initWithMatrixRestClient:aliceSession.matrixRestClient]; [self->matrixSDKTestsData retain:aliceSession2]; @@ -1446,36 +1435,36 @@ - (void)testLocalPrivateKey XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; }]; - + // -> The restarted alice session must still have the private key __block id observer; observer = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKeyBackupDidStateChangeNotification object:aliceSession2.crypto.backup queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { - + if (observer && aliceSession2.crypto.backup.state == MXKeyBackupStateReadyToBackUp) { [[NSNotificationCenter defaultCenter] removeObserver:observer]; observer = nil; - + XCTAssertTrue(aliceSession2.crypto.backup.hasPrivateKeyInCryptoStore); - + // -> It must be able to restore the backup using this local key [aliceSession2.crypto.backup restoreUsingPrivateKeyKeyBackup:aliceSession2.crypto.backup.keyBackupVersion room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - + XCTAssertGreaterThan(total, 0); [expectation fulfill]; - + } failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; }]; } }]; - + } progress:nil failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; }]; - + } failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; @@ -1497,35 +1486,35 @@ - (void)testLocalPrivateKey - (void)testCatchPrivateKeyOnRecoverWithPassword { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - + // - Do an e2e backup to the homeserver NSString *password = @"qwerty"; - [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:password algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { - + NSString *backupSecret = [aliceSession.crypto.store secretWithSecretId:MXSecretId.keyBackup]; XCTAssertTrue(aliceSession.crypto.backup.hasPrivateKeyInCryptoStore); - + // - Erase local private key locally (that simulates usage of the backup from another device) [aliceSession.crypto.store deleteSecretWithSecretId:MXSecretId.keyBackup]; XCTAssertFalse(aliceSession.crypto.backup.hasPrivateKeyInCryptoStore); - + // - Restore the backup with a password [aliceSession.crypto.backup restoreKeyBackup:keyBackupVersion withPassword:password room:nil session:nil success:^(NSUInteger total, NSUInteger imported) { - + // -> We should have now the private key locally XCTAssertTrue(aliceSession.crypto.backup.hasPrivateKeyInCryptoStore); - + NSString *backupSecret2 = [aliceSession.crypto.store secretWithSecretId:MXSecretId.keyBackup]; XCTAssertEqualObjects(backupSecret, backupSecret2); - + [expectation fulfill]; - + } failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; }]; - + } failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; @@ -1548,40 +1537,40 @@ - (void)testCatchPrivateKeyOnRecoverWithPassword - (void)testGossipKey { [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession1, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { - + // - Do an e2e backup to the homeserver - [aliceSession1.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + [aliceSession1.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { [aliceSession1.crypto.backup createKeyBackupVersion:keyBackupCreationInfo success:^(MXKeyBackupVersion * _Nonnull keyBackupVersion) { [aliceSession1.crypto.backup backupAllGroupSessions:^{ - - [matrixSDKTestsE2EData loginUserOnANewDevice:self credentials:aliceSession1.matrixRestClient.credentials withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { - + + [self->matrixSDKTestsE2EData loginUserOnANewDevice:self credentials:aliceSession1.matrixRestClient.credentials withPassword:MXTESTS_ALICE_PWD onComplete:^(MXSession *aliceSession2) { + // -> We must have the backup private key locally XCTAssertFalse(aliceSession2.crypto.backup.hasPrivateKeyInCryptoStore); - + NSString *aliceUserId = aliceSession1.matrixRestClient.credentials.userId; NSString *aliceSession1DeviceId = aliceSession1.matrixRestClient.credentials.deviceId; NSString *aliceSession2DeviceId = aliceSession2.matrixRestClient.credentials.deviceId; - + // - Make each Alice device trust each other // This simulates a self verification and trigger backup restore in background [aliceSession1.crypto setDeviceVerification:MXDeviceVerified forDevice:aliceSession2DeviceId ofUser:aliceUserId success:^{ [aliceSession2.crypto setDeviceVerification:MXDeviceVerified forDevice:aliceSession1DeviceId ofUser:aliceUserId success:^{ - + // Wait a bit to make background requests happen dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - + // -> Alice2 should have the private backup key thanks to gossiping XCTAssertTrue(aliceSession2.crypto.backup.hasPrivateKeyInCryptoStore); - + // -> Alice2 should have all her history decrypted NSUInteger inboundGroupSessionsCount = [aliceSession2.crypto.store inboundGroupSessionsCount:NO]; XCTAssertGreaterThan(inboundGroupSessionsCount, 0); XCTAssertEqual(inboundGroupSessionsCount, [aliceSession1.crypto.store inboundGroupSessionsCount:NO]); - + [expectation fulfill]; }); - + } failure:^(NSError *error) { XCTFail(@"Cannot set up intial test conditions - error: %@", error); [expectation fulfill]; @@ -1590,9 +1579,9 @@ - (void)testGossipKey XCTFail(@"Cannot set up intial test conditions - error: %@", error); [expectation fulfill]; }]; - + }]; - + } progress:nil failure:^(NSError * _Nonnull error) { XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; @@ -1609,5 +1598,3 @@ - (void)testGossipKey } @end - -#pragma clang diagnostic pop diff --git a/MatrixSDKTests/MXCurve25519KeyBackupTests.m b/MatrixSDKTests/MXCurve25519KeyBackupTests.m new file mode 100644 index 0000000000..d53842898d --- /dev/null +++ b/MatrixSDKTests/MXCurve25519KeyBackupTests.m @@ -0,0 +1,125 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXBaseKeyBackupTests.h" + +#import "MXCrypto_Private.h" +#import "MXCryptoStore.h" +#import "MXRecoveryKey.h" +#import "MXKeybackupPassword.h" +#import "MXOutboundSessionInfo.h" +#import "MXCrossSigning_Private.h" +#import "MXCurve25519BackupAuthData.h" +#import "MXCurve25519KeyBackupAlgorithm.h" + +// Do not bother with retain cycles warnings in tests +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + +@interface MXCurve25519KeyBackupTests : MXBaseKeyBackupTests + +@end + +@implementation MXCurve25519KeyBackupTests + +- (NSString *)algorithm +{ + return kMXCryptoCurve25519KeyBackupAlgorithm; +} + +- (BOOL)isUntrusted +{ + return MXCurve25519KeyBackupAlgorithm.isUntrusted; +} + +- (MXKeyBackupVersion*)fakeKeyBackupVersion +{ + return [MXKeyBackupVersion modelFromJSON:@{ + @"algorithm": self.algorithm, + @"auth_data": @{ + @"public_key": @"abcdefg", + @"signatures": @{ + @"something": @{ + @"ed25519:something": @"hijklmnop" + } + } + } + }]; +} + +/** + Check that `[MXKeyBackup prepareKeyBackupVersion]` uses Curve25519 algorithm by default + */ +- (void)testPrepareKeyBackupVersionWithDefaultAlgorithm +{ + [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { + + XCTAssertNotNil(aliceSession.crypto.backup); + XCTAssertFalse(aliceSession.crypto.backup.enabled); + + // Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:nil success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + + XCTAssertNotNil(keyBackupCreationInfo); + XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); + XCTAssertTrue([keyBackupCreationInfo.authData isKindOfClass:MXCurve25519BackupAuthData.class]); + MXCurve25519BackupAuthData *authData = (MXCurve25519BackupAuthData*) keyBackupCreationInfo.authData; + XCTAssertNotNil(authData.publicKey); + XCTAssertNotNil(authData.signatures); + XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); + + [expectation fulfill]; + + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + }]; +} + +/** + Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data + */ +- (void)testPrepareKeyBackupVersion +{ + [matrixSDKTestsE2EData doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { + + XCTAssertNotNil(aliceSession.crypto.backup); + XCTAssertFalse(aliceSession.crypto.backup.enabled); + + // Check that `[MXKeyBackup prepareKeyBackupVersion` returns valid data + [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { + + XCTAssertNotNil(keyBackupCreationInfo); + XCTAssertEqualObjects(keyBackupCreationInfo.algorithm, kMXCryptoCurve25519KeyBackupAlgorithm); + XCTAssertTrue([keyBackupCreationInfo.authData isKindOfClass:MXCurve25519BackupAuthData.class]); + MXCurve25519BackupAuthData *authData = (MXCurve25519BackupAuthData*) keyBackupCreationInfo.authData; + XCTAssertNotNil(authData.publicKey); + XCTAssertNotNil(authData.signatures); + XCTAssertNotNil(keyBackupCreationInfo.recoveryKey); + + [expectation fulfill]; + + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + }]; +} + +@end + +#pragma clang diagnostic pop From 4c86194a634d3f79dc474af8d455a41e98dcd2a5 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Tue, 9 Aug 2022 10:46:24 +0300 Subject: [PATCH 25/65] Add changelog --- changelog.d/pr-1542.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-1542.feature diff --git a/changelog.d/pr-1542.feature b/changelog.d/pr-1542.feature new file mode 100644 index 0000000000..36ba0c237e --- /dev/null +++ b/changelog.d/pr-1542.feature @@ -0,0 +1 @@ +MXKeyBackup: Add support for symmetric key backups. From c7c8f2181175b00713f6c29d4d2965a9cc8bd5b5 Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 9 Aug 2022 11:37:26 +0100 Subject: [PATCH 26/65] Prepare for new sprint From 7284210182e06b5407a2a03a31bec90ed4b70407 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Tue, 9 Aug 2022 15:47:09 +0300 Subject: [PATCH 27/65] Optimize imports --- .../KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m | 9 --------- .../Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m | 7 ------- MatrixSDK/MatrixSDK.h | 3 +++ MatrixSDKTests/MatrixSDKTests-Bridging-Header.h | 7 +++++++ 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index 6ef9e7b7f7..3d8e5919f9 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -15,24 +15,15 @@ // #import "MXAes256KeyBackupAlgorithm.h" -#import "MXKeyBackup_Private.h" #import "MXCrypto_Private.h" #import -#import "MXRecoveryKey.h" #import "MXKeyBackupPassword.h" -#import "MXSession.h" #import "MXTools.h" #import "MXBase64Tools.h" -#import "MXError.h" -#import "MXKeyProvider.h" -#import "MXRawDataKey.h" -#import "MXCrossSigning_Private.h" #import "MXSharedHistoryKeyService.h" #import "MXAes256BackupAuthData.h" -#import "MXAes.h" -#import "MatrixSDKSwiftHeader.h" #import "MXSecretStorage_Private.h" #import "MXEncryptedSecretContent.h" diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m index 3b9584ea4f..6f3048117a 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m @@ -15,20 +15,13 @@ // #import "MXCurve25519KeyBackupAlgorithm.h" -#import "MXKeyBackup_Private.h" #import "MXCrypto_Private.h" - #import -#import "MXRecoveryKey.h" #import "MXKeyBackupPassword.h" -#import "MXSession.h" #import "MXTools.h" #import "MXBase64Tools.h" #import "MXError.h" -#import "MXKeyProvider.h" -#import "MXRawDataKey.h" -#import "MXCrossSigning_Private.h" #import "MXSharedHistoryKeyService.h" #import "MXCurve25519BackupAuthData.h" diff --git a/MatrixSDK/MatrixSDK.h b/MatrixSDK/MatrixSDK.h index dd949540f2..b2308292df 100644 --- a/MatrixSDK/MatrixSDK.h +++ b/MatrixSDK/MatrixSDK.h @@ -76,6 +76,9 @@ FOUNDATION_EXPORT NSString *MatrixSDKVersion; #import "MXKeyBackupAlgorithm.h" #import "MXCurve25519BackupAuthData.h" #import "MXAes256BackupAuthData.h" +#import "MXCurve25519KeyBackupAlgorithm.h" +#import "MXAes256KeyBackupAlgorithm.h" +#import "MXKeyBackupPassword.h" #import "MXAes.h" diff --git a/MatrixSDKTests/MatrixSDKTests-Bridging-Header.h b/MatrixSDKTests/MatrixSDKTests-Bridging-Header.h index 7a11f57c82..cc92091b65 100644 --- a/MatrixSDKTests/MatrixSDKTests-Bridging-Header.h +++ b/MatrixSDKTests/MatrixSDKTests-Bridging-Header.h @@ -25,5 +25,12 @@ #import "MXApplicationProtocol.h" #import "MXCrypto_Private.h" #import "MXRestClientStub.h" +#import "MXCurve25519KeyBackupAlgorithm.h" +#import "MXAes256KeyBackupAlgorithm.h" +#import "MXCurve25519BackupAuthData.h" +#import "MXAes256BackupAuthData.h" +#import "MXKeyBackupPassword.h" +#import "MXSecretStorage_Private.h" +#import "MXEncryptedSecretContent.h" #endif /* MatrixSDKTests_Bridging_Header_h */ From 0a84f6cfdf2d26ec6c050c76d6a52e5caef85747 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Tue, 9 Aug 2022 15:47:24 +0300 Subject: [PATCH 28/65] Fix failing unit tests --- .../Data/MXMegolmSessionDataUnitTests.swift | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/MatrixSDKTests/Crypto/Data/MXMegolmSessionDataUnitTests.swift b/MatrixSDKTests/Crypto/Data/MXMegolmSessionDataUnitTests.swift index 4f4fef51b2..cbbb04308b 100644 --- a/MatrixSDKTests/Crypto/Data/MXMegolmSessionDataUnitTests.swift +++ b/MatrixSDKTests/Crypto/Data/MXMegolmSessionDataUnitTests.swift @@ -32,16 +32,20 @@ class MXMegolmSessionDataUnitTests: XCTestCase { "forwarding_curve25519_key_chain": ["H", "I"] ] - let data = MXMegolmSessionData(fromJSON: jsonDictionary) + guard let data = MXMegolmSessionData(fromJSON: jsonDictionary) else { + XCTFail("Failed to setup test conditions") + return + } - XCTAssertEqual(data?.senderKey, "A") - XCTAssertEqual(data?.senderClaimedKeys, ["B": "C"]) - XCTAssertEqual(data?.roomId, "D") - XCTAssertEqual(data?.sessionId, "E") - XCTAssertEqual(data?.sessionKey, "F") - XCTAssertEqual(data?.sharedHistory, true) - XCTAssertEqual(data?.algorithm, "G") - XCTAssertEqual(data?.forwardingCurve25519KeyChain, ["H", "I"]) + XCTAssertEqual(data.senderKey, "A") + XCTAssertEqual(data.senderClaimedKeys, ["B": "C"]) + XCTAssertEqual(data.roomId, "D") + XCTAssertEqual(data.sessionId, "E") + XCTAssertEqual(data.sessionKey, "F") + XCTAssertEqual(data.sharedHistory, true) + XCTAssertEqual(data.algorithm, "G") + XCTAssertEqual(data.forwardingCurve25519KeyChain, ["H", "I"]) + XCTAssertFalse(data.isUntrusted) } func testIgnoreSharedHistoryIfFlagDisabled() { @@ -77,7 +81,8 @@ class MXMegolmSessionDataUnitTests: XCTestCase { "session_key": "F", "org.matrix.msc3061.shared_history": true, "algorithm": "G", - "forwarding_curve25519_key_chain": ["H", "I"] + "forwarding_curve25519_key_chain": ["H", "I"], + "untrusted": false ]) } } From f7d1f70a4322f088118e26b5e75b14e7e1568aef Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Tue, 9 Aug 2022 15:48:00 +0300 Subject: [PATCH 29/65] Add new unit tests for key backup algorithms --- MatrixSDK.xcodeproj/project.pbxproj | 18 +- .../Crypto/KeyBackup/MXKeyBackupAlgorithm.h | 17 +- MatrixSDKTests/MXKeyBackupUnitTests.swift | 308 ++++++++++++++++++ 3 files changed, 332 insertions(+), 11 deletions(-) create mode 100644 MatrixSDKTests/MXKeyBackupUnitTests.swift diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 00b5d513f2..159cd87b79 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -201,7 +201,7 @@ 324095221AFA432F00D81C97 /* MXCallStackCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 3240951E1AFA432F00D81C97 /* MXCallStackCall.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3240969D1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 3240969B1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3240969E1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 3240969C1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.m */; }; - 32442FB121EDD21300D2411B /* MXKeyBackupPassword.h in Headers */ = {isa = PBXBuildFile; fileRef = 32442FAF21EDD21300D2411B /* MXKeyBackupPassword.h */; }; + 32442FB121EDD21300D2411B /* MXKeyBackupPassword.h in Headers */ = {isa = PBXBuildFile; fileRef = 32442FAF21EDD21300D2411B /* MXKeyBackupPassword.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32442FB221EDD21300D2411B /* MXKeyBackupPassword.m in Sources */ = {isa = PBXBuildFile; fileRef = 32442FB021EDD21300D2411B /* MXKeyBackupPassword.m */; }; 3245A7501AF7B2930001D8A7 /* MXCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 3245A74C1AF7B2930001D8A7 /* MXCall.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3245A7511AF7B2930001D8A7 /* MXCall.m in Sources */ = {isa = PBXBuildFile; fileRef = 3245A74D1AF7B2930001D8A7 /* MXCall.m */; }; @@ -1170,7 +1170,7 @@ B14EF31D2397E90400758AF0 /* MXEventDecryptionResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F634A91FC5E3470054EF49 /* MXEventDecryptionResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF31E2397E90400758AF0 /* MXOlmDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 322A51C51D9BBD3C00C8536D /* MXOlmDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF31F2397E90400758AF0 /* MXPusherData.h in Headers */ = {isa = PBXBuildFile; fileRef = 32999DE122DCD1AD004FF987 /* MXPusherData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B14EF3202397E90400758AF0 /* MXKeyBackupPassword.h in Headers */ = {isa = PBXBuildFile; fileRef = 32442FAF21EDD21300D2411B /* MXKeyBackupPassword.h */; }; + B14EF3202397E90400758AF0 /* MXKeyBackupPassword.h in Headers */ = {isa = PBXBuildFile; fileRef = 32442FAF21EDD21300D2411B /* MXKeyBackupPassword.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF3212397E90400758AF0 /* MXRestClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 320DFDD419DD99B60068622A /* MXRestClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF3222397E90400758AF0 /* MXKeyVerificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3252DCAC224BE5D40032264F /* MXKeyVerificationManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF3232397E90400758AF0 /* MXRoomState.h in Headers */ = {isa = PBXBuildFile; fileRef = 3265CB361A14C43E00E24B2F /* MXRoomState.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1552,12 +1552,12 @@ EC403835289A672A0067D5B8 /* MXAes256BackupAuthData.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403833289A672A0067D5B8 /* MXAes256BackupAuthData.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC403837289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */; }; EC403838289A67440067D5B8 /* MXAes256BackupAuthData.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403836289A67440067D5B8 /* MXAes256BackupAuthData.m */; }; - EC403844289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */; }; - EC403845289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */; }; + EC403844289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC403845289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403842289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC403846289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403843289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m */; }; EC403847289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403843289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m */; }; - EC40384A289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */; }; - EC40384B289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */; }; + EC40384A289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC40384B289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = EC403848289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h */; settings = {ATTRIBUTES = (Public, ); }; }; EC40384C289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403849289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m */; }; EC40384D289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403849289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.m */; }; EC403854289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EC403853289ACF5E0067D5B8 /* MXKeyBackupPreparationInfo.m */; }; @@ -1572,6 +1572,8 @@ EC40385E28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EC40385C28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m */; }; EC40386128A1A3830067D5B8 /* MXBaseKeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */; }; EC40386228A1A3830067D5B8 /* MXBaseKeyBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */; }; + EC40386728A279220067D5B8 /* MXKeyBackupUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC40386628A279210067D5B8 /* MXKeyBackupUnitTests.swift */; }; + EC40386828A279220067D5B8 /* MXKeyBackupUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC40386628A279210067D5B8 /* MXKeyBackupUnitTests.swift */; }; EC51019D26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC51019E26C41981007D6D88 /* MXSyncResponseUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */; }; EC5C560A2798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h in Headers */ = {isa = PBXBuildFile; fileRef = EC5C56082798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h */; }; @@ -2738,6 +2740,7 @@ EC40385C28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXAes256KeyBackupTests.m; sourceTree = ""; }; EC40385F28A1A25C0067D5B8 /* MXBaseKeyBackupTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXBaseKeyBackupTests.h; sourceTree = ""; }; EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXBaseKeyBackupTests.m; sourceTree = ""; }; + EC40386628A279210067D5B8 /* MXKeyBackupUnitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXKeyBackupUnitTests.swift; sourceTree = ""; }; EC51019C26C41981007D6D88 /* MXSyncResponseUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSyncResponseUnitTests.swift; sourceTree = ""; }; EC5C56082798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+MutableDeepCopy.h"; sourceTree = ""; }; EC5C56092798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+MutableDeepCopy.m"; sourceTree = ""; }; @@ -4057,6 +4060,7 @@ EC40386028A1A3830067D5B8 /* MXBaseKeyBackupTests.m */, 32935F60216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m */, EC40385C28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m */, + EC40386628A279210067D5B8 /* MXKeyBackupUnitTests.swift */, 32C03CB52123076F00D92712 /* DirectRoomTests.m */, 320E1BC01E0AD674009635F5 /* MXRoomSummaryTests.m */, 32322A471E57264E005DD155 /* MXSelfSignedHomeserverTests.m */, @@ -6730,6 +6734,7 @@ 320E1BC11E0AD674009635F5 /* MXRoomSummaryTests.m in Sources */, 3281E8A219E2DE4300976E1A /* MXSessionTests.m in Sources */, 327137241A24BDDE00DB6757 /* MXUserTests.m in Sources */, + EC40386728A279220067D5B8 /* MXKeyBackupUnitTests.swift in Sources */, 32B0E3E723A3864C0054FF1A /* MXEventReferenceUnitTests.swift in Sources */, 32720DA2222EB5650086FFF5 /* MXAutoDiscoveryTests.m in Sources */, ED8943D427E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift in Sources */, @@ -7305,6 +7310,7 @@ B1E09A402397FD820057C069 /* MXVoIPTests.m in Sources */, 32B4778F2638133D00EA5800 /* MXJSONModelUnitTests.m in Sources */, B1F939F626289F2600D0E525 /* MXSpaceChildContentTests.swift in Sources */, + EC40386828A279220067D5B8 /* MXKeyBackupUnitTests.swift in Sources */, B1E09A412397FD820057C069 /* MXAccountDataTests.m in Sources */, B1E09A2D2397FD750057C069 /* MXRestClientNoAuthAPITests.m in Sources */, ED8943D527E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift in Sources */, diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h index a892305014..796f2225b2 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h @@ -52,18 +52,22 @@ typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); /// Prepare a private key and auth data for a given password for the algorithm. Returns a preparation info if successful, otherwise returns nil. /// @param password password to use. If not provided, a new one will be generated. /// @param error error instance to be set on errors -+ (nullable MXKeyBackupPreparationInfo*)prepareWith:(nullable NSString*)password error:(NSError *__autoreleasing _Nullable *)error; ++ (nullable MXKeyBackupPreparationInfo*)prepareWith:(nullable NSString*)password + error:(NSError *__autoreleasing _Nullable *)error; /// Method to check a private key against receiver's internal auth data (the one given at initialization) /// @param privateKey private key to check /// @param error error instance to be set on errors -- (BOOL)keyMatches:(NSData*)privateKey error:(NSError *__autoreleasing _Nullable *)error; +- (BOOL)keyMatches:(NSData*)privateKey + error:(NSError *__autoreleasing _Nullable *)error __attribute__((swift_error(nonnull_error))); /// Method to check a private key against a given auth data /// @param privateKey private key to check /// @param authData auth data to check against /// @param error error instance to be set on errors -+ (BOOL)keyMatches:(NSData*)privateKey withAuthData:(NSDictionary*)authData error:(NSError *__autoreleasing _Nullable *)error; ++ (BOOL)keyMatches:(NSData*)privateKey + withAuthData:(NSDictionary*)authData + error:(NSError *__autoreleasing _Nullable *)error __attribute__((swift_error(nonnull_error))); /// Encrypt group session with the receiver algorithm. /// @param session session instance to encrypt. @@ -73,7 +77,9 @@ typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); /// @param keyBackupData key backup data /// @param sessionId session id to use /// @param roomId room id to use -- (nullable MXMegolmSessionData*)decryptKeyBackupData:(MXKeyBackupData*)keyBackupData forSession:(NSString*)sessionId inRoom:(NSString*)roomId; +- (nullable MXMegolmSessionData*)decryptKeyBackupData:(MXKeyBackupData*)keyBackupData + forSession:(NSString*)sessionId + inRoom:(NSString*)roomId; /// Method to check the algorithm against a given key backup version /// @param backupVersion key backup version to check against @@ -82,7 +88,8 @@ typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); /// Generate auth data from a given dictionary. Returns nil if there is missing data in the dictionary. /// @param JSON Auth data dictionary object /// @param error error instance to be set on errors -+ (nullable id)authDataFromJSON:(NSDictionary*)JSON error:(NSError**)error; ++ (nullable id)authDataFromJSON:(NSDictionary*)JSON + error:(NSError**)error; @end diff --git a/MatrixSDKTests/MXKeyBackupUnitTests.swift b/MatrixSDKTests/MXKeyBackupUnitTests.swift new file mode 100644 index 0000000000..0f99b4cb7c --- /dev/null +++ b/MatrixSDKTests/MXKeyBackupUnitTests.swift @@ -0,0 +1,308 @@ +// +// Copyright 2022 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 XCTest + +@testable import MatrixSDK + +class MXKeyBackupUnitTests: XCTestCase { + + // MARK: - Curve25519 + + func testCurve25519AlgorithmClass() throws { + XCTAssertEqual(MXCurve25519KeyBackupAlgorithm.algorithName, kMXCryptoCurve25519KeyBackupAlgorithm) + XCTAssertTrue(MXCurve25519KeyBackupAlgorithm.isUntrusted) + } + + func testCurve25519AuthData() throws { + let publicKey = "abcdefg" + let privateKeySalt = "hijklmno" + let privateKeyIterations: UInt = 500000 + let signatures: [AnyHashable: Any] = [ + "something": [ + "ed25519:something": "hijklmnop" + ] + ] + + let json: [String: Any] = [ + "public_key": publicKey, + "private_key_salt": privateKeySalt, + "private_key_iterations": privateKeyIterations, + "signatures": signatures + ] + + guard let authData = MXCurve25519BackupAuthData(fromJSON: json), + let authDataSignatures = authData.signatures else { + XCTFail("Failed to setup test conditions") + return + } + + XCTAssertEqual(authData.publicKey, publicKey) + XCTAssertEqual(authData.privateKeySalt, privateKeySalt) + XCTAssertEqual(authData.privateKeyIterations, privateKeyIterations) + XCTAssertTrue(NSDictionary(dictionary: signatures).isEqual(to: NSDictionary(dictionary: authDataSignatures))) + XCTAssertTrue(NSDictionary(dictionary: authData.jsonDictionary()).isEqual(to: NSDictionary(dictionary: json))) + XCTAssertNil(authData.signalableJSONDictionary["signatures"]) + } + + func testCurve25519KeyMatch() throws { + var salt: NSString? = "" + var iterations: UInt = 0 + var error: NSError? = nil + let privateKey = try MXKeyBackupPassword.generatePrivateKey(withPassword: "password", + salt: &salt, + iterations: &iterations) + let olmPkDecryption = OLMPkDecryption() + let publicKey = olmPkDecryption.setPrivateKey(privateKey, error: &error) + + XCTAssertTrue(try MXCurve25519KeyBackupAlgorithm.keyMatches(privateKey, withAuthData: ["public_key": publicKey])) + } + + func testCurve25519PreparationWithNoPassword() throws { + let preparationInfoWithNoPass = try MXCurve25519KeyBackupAlgorithm.prepare(with: nil) + guard let authDataWithNoPass = preparationInfoWithNoPass.authData as? MXCurve25519BackupAuthData else { + return + } + XCTAssertFalse(authDataWithNoPass.publicKey.isEmpty) + XCTAssertNil(authDataWithNoPass.privateKeySalt) + XCTAssertEqual(authDataWithNoPass.privateKeyIterations, 0) + } + + func testCurve25519PreparationWithPassword() throws { + let preparationInfoWithPass = try MXCurve25519KeyBackupAlgorithm.prepare(with: "password") + guard let authDataWithPass = preparationInfoWithPass.authData as? MXCurve25519BackupAuthData else { + return + } + XCTAssertFalse(authDataWithPass.publicKey.isEmpty) + XCTAssertNotNil(authDataWithPass.privateKeySalt) + XCTAssertNotEqual(authDataWithPass.privateKeyIterations, 0) + } + + func testCurve25519AuthDataGeneration() throws { + let json: [String: Any] = [ + "public_key": "abcdefg", + "signatures": [ + "something": [ + "ed25519:something": "hijklmnop" + ] + ] + ] + + guard let authData = try MXCurve25519KeyBackupAlgorithm.authData(fromJSON: json) as? MXCurve25519BackupAuthData, + let signatures = authData.signatures else { + XCTFail("Failed to setup test conditions") + return + } + XCTAssertFalse(authData.publicKey.isEmpty) + XCTAssertFalse(signatures.isEmpty) + } + + func testCurve25519KeyBackupVersionCheck() throws { + let json: [String: Any] = [ + "algorithm": kMXCryptoCurve25519KeyBackupAlgorithm, + "auth_data": [ + "public_key": "abcdefg" + ], + "version": "1" + ] + + guard let keyBackupVersion = MXKeyBackupVersion(fromJSON: json) else { + XCTFail("Failed to setup test conditions") + return + } + XCTAssertTrue(MXCurve25519KeyBackupAlgorithm.check(keyBackupVersion)) + } + + func testCurve25519AlgorithmInstance() throws { + var salt: NSString? = "" + var iterations: UInt = 0 + let privateKey = try MXKeyBackupPassword.generatePrivateKey(withPassword: "password", salt: &salt, iterations: &iterations) + + let olmPkDecryption = OLMPkDecryption() + var error: NSError? = nil + let publicKey = olmPkDecryption.setPrivateKey(privateKey, error: &error) + + let crypto = MXCrypto() + let json: [String: Any] = [ + "public_key": publicKey, + "signatures": [ + "something": [ + "ed25519:something": "hijklmnop" + ] + ] + ] + + let authData = try MXCurve25519KeyBackupAlgorithm.authData(fromJSON: json) + guard let algorithm = MXCurve25519KeyBackupAlgorithm(crypto: crypto, + authData: authData, + keyGetterBlock: { return privateKey }) else { + return + } + XCTAssertTrue(try algorithm.keyMatches(privateKey)) + } + + // MARK: - Aes256 + + func testAes256AlgorithmClass() throws { + XCTAssertEqual(MXAes256KeyBackupAlgorithm.algorithName, kMXCryptoAes256KeyBackupAlgorithm) + XCTAssertFalse(MXAes256KeyBackupAlgorithm.isUntrusted) + } + + func testAes256AuthData() throws { + let iv = "abcdefg" + let mac = "abcdefgtyu" + let privateKeySalt = "hijklmno" + let privateKeyIterations: UInt = 500000 + let signatures: [AnyHashable: Any] = [ + "something": [ + "ed25519:something": "hijklmnop" + ] + ] + + let json: [String: Any] = [ + "iv": iv, + "mac": mac, + "private_key_salt": privateKeySalt, + "private_key_iterations": privateKeyIterations, + "signatures": signatures + ] + + guard let authData = MXAes256BackupAuthData(fromJSON: json), + let authDataSignatures = authData.signatures else { + XCTFail("Failed to setup test conditions") + return + } + + XCTAssertEqual(authData.iv, iv) + XCTAssertEqual(authData.mac, mac) + XCTAssertEqual(authData.privateKeySalt, privateKeySalt) + XCTAssertEqual(authData.privateKeyIterations, privateKeyIterations) + XCTAssertTrue(NSDictionary(dictionary: signatures).isEqual(to: NSDictionary(dictionary: authDataSignatures))) + XCTAssertTrue(NSDictionary(dictionary: authData.jsonDictionary()).isEqual(to: NSDictionary(dictionary: json))) + XCTAssertNil(authData.signalableJSONDictionary["signatures"]) + } + + func testAes256KeyMatch() throws { + var salt: NSString? = "" + var iterations: UInt = 0 + let privateKey = try MXKeyBackupPassword.generatePrivateKey(withPassword: "password", + salt: &salt, + iterations: &iterations) + let secretContent = try MXSecretStorage().encryptedZeroString(withPrivateKey: privateKey, iv: nil) + + guard let mac = secretContent.mac, let iv = secretContent.iv else { + XCTFail("Failed to setup test conditions") + return + } + + XCTAssertTrue(try MXAes256KeyBackupAlgorithm.keyMatches(privateKey, withAuthData: [:])) + XCTAssertTrue(try MXAes256KeyBackupAlgorithm.keyMatches(privateKey, withAuthData: ["mac": mac, "iv": iv])) + } + + func testAes256PreparationWithNoPassword() throws { + let preparationInfoWithNoPass = try MXAes256KeyBackupAlgorithm.prepare(with: nil) + guard let authDataWithNoPass = preparationInfoWithNoPass.authData as? MXAes256BackupAuthData else { + return + } + XCTAssertNotNil(authDataWithNoPass.iv) + XCTAssertNotNil(authDataWithNoPass.mac) + XCTAssertNil(authDataWithNoPass.privateKeySalt) + XCTAssertEqual(authDataWithNoPass.privateKeyIterations, 0) + } + + func testAes256PreparationWithPassword() throws { + let preparationInfoWithPass = try MXAes256KeyBackupAlgorithm.prepare(with: "password") + guard let authDataWithPass = preparationInfoWithPass.authData as? MXAes256BackupAuthData else { + return + } + XCTAssertNotNil(authDataWithPass.iv) + XCTAssertNotNil(authDataWithPass.mac) + XCTAssertNotNil(authDataWithPass.privateKeySalt) + XCTAssertNotEqual(authDataWithPass.privateKeyIterations, 0) + } + + func testAes256AuthDataGeneration() throws { + let json: [String: Any] = [ + "iv": "abcdefg", + "mac": "asdbasdsd", + "signatures": [ + "something": [ + "ed25519:something": "hijklmnop" + ] + ] + ] + + guard let authData = try MXAes256KeyBackupAlgorithm.authData(fromJSON: json) as? MXAes256BackupAuthData, + let signatures = authData.signatures else { + XCTFail("Failed to setup test conditions") + return + } + XCTAssertNotNil(authData.iv) + XCTAssertNotNil(authData.mac) + XCTAssertFalse(signatures.isEmpty) + } + + func testAes256KeyBackupVersionCheck() throws { + let json: [String: Any] = [ + "algorithm": kMXCryptoAes256KeyBackupAlgorithm, + "auth_data": [ + "iv": "abcdefgh", + "mac": "zdkcsdfsdf" + ], + "version": "1" + ] + + guard let keyBackupVersion = MXKeyBackupVersion(fromJSON: json) else { + XCTFail("Failed to setup test conditions") + return + } + XCTAssertTrue(MXAes256KeyBackupAlgorithm.check(keyBackupVersion)) + } + + func testAes256AlgorithmInstance() throws { + var salt: NSString? = "" + var iterations: UInt = 0 + let privateKey = try MXKeyBackupPassword.generatePrivateKey(withPassword: "password", + salt: &salt, + iterations: &iterations) + let secretContent = try MXSecretStorage().encryptedZeroString(withPrivateKey: privateKey, iv: nil) + + guard let mac = secretContent.mac, let iv = secretContent.iv else { + XCTFail("Failed to setup test conditions") + return + } + + let crypto = MXCrypto() + let json: [String: Any] = [ + "iv": iv, + "mac": mac, + "signatures": [ + "something": [ + "ed25519:something": "hijklmnop" + ] + ] + ] + + let authData = try MXAes256KeyBackupAlgorithm.authData(fromJSON: json) + guard let algorithm = MXAes256KeyBackupAlgorithm(crypto: crypto, + authData: authData, + keyGetterBlock: { return privateKey }) else { + return + } + XCTAssertTrue(try algorithm.keyMatches(privateKey)) + } + +} From 1c4e001971e10889bcda748836b613ba33b70569 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Tue, 9 Aug 2022 15:48:22 +0300 Subject: [PATCH 30/65] Use tests in plans --- MatrixSDKTests/TestPlans/CryptoTests.xctestplan | 2 ++ MatrixSDKTests/TestPlans/UnitTests.xctestplan | 1 + MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan | 1 + 3 files changed, 4 insertions(+) diff --git a/MatrixSDKTests/TestPlans/CryptoTests.xctestplan b/MatrixSDKTests/TestPlans/CryptoTests.xctestplan index 56abccd52d..96ada03559 100644 --- a/MatrixSDKTests/TestPlans/CryptoTests.xctestplan +++ b/MatrixSDKTests/TestPlans/CryptoTests.xctestplan @@ -29,12 +29,14 @@ "testTargets" : [ { "selectedTests" : [ + "MXAes256KeyBackupTests", "MXCrossSigningTests", "MXCrossSigningVerificationTests", "MXCryptoKeyVerificationTests", "MXCryptoSecretStorageTests", "MXCryptoShareTests", "MXCryptoTests", + "MXCurve25519KeyBackupTests", "MXMegolmEncryptionTests" ], "target" : { diff --git a/MatrixSDKTests/TestPlans/UnitTests.xctestplan b/MatrixSDKTests/TestPlans/UnitTests.xctestplan index 5cc77dc45c..40f571db63 100644 --- a/MatrixSDKTests/TestPlans/UnitTests.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTests.xctestplan @@ -49,6 +49,7 @@ "MXFilterUnitTests", "MXHTTPAdditionalHeadersUnitTests", "MXJSONModelUnitTests", + "MXKeyBackupUnitTests", "MXKeyProviderUnitTests", "MXMediaScanStoreUnitTests", "MXMegolmDecryptionUnitTests", diff --git a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan index f42475856f..92b1fbf9a3 100644 --- a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan @@ -57,6 +57,7 @@ "MXFilterUnitTests", "MXHTTPAdditionalHeadersUnitTests", "MXJSONModelUnitTests", + "MXKeyBackupUnitTests", "MXKeyProviderUnitTests", "MXMediaScanStoreUnitTests", "MXMegolmDecryptionUnitTests", From 7474d43c149c14a8bc5e3ff8202601635be075e8 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 10 Aug 2022 15:09:18 +0100 Subject: [PATCH 31/65] Prepare for new sprint From 7934e04a4f96008d27cd5f92b975efeb818ee462 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 11 Aug 2022 01:37:09 +0300 Subject: [PATCH 32/65] Update copyright info --- MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h | 2 +- MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m | 2 +- .../KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h | 2 +- .../KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m | 2 +- MatrixSDKTests/MXAes256KeyBackupTests.m | 2 +- MatrixSDKTests/MXCurve25519KeyBackupTests.m | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h index 6f01b8f1de..338ba79049 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.h @@ -1,5 +1,5 @@ /* - Copyright 2018 New Vector Ltd + Copyright 2022 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. diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m index 9a8f398c75..50897f704b 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256BackupAuthData.m @@ -1,5 +1,5 @@ /* - Copyright 2018 New Vector Ltd + Copyright 2022 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. diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h index aaa354b316..923f2f98bf 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.h @@ -1,5 +1,5 @@ /* - Copyright 2018 New Vector Ltd + Copyright 2022 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. diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m index 2a9887738c..650591d645 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519BackupAuthData.m @@ -1,5 +1,5 @@ /* - Copyright 2018 New Vector Ltd + Copyright 2022 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. diff --git a/MatrixSDKTests/MXAes256KeyBackupTests.m b/MatrixSDKTests/MXAes256KeyBackupTests.m index b6280f3935..e37886848a 100644 --- a/MatrixSDKTests/MXAes256KeyBackupTests.m +++ b/MatrixSDKTests/MXAes256KeyBackupTests.m @@ -1,5 +1,5 @@ /* - Copyright 2018 New Vector Ltd + Copyright 2022 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. diff --git a/MatrixSDKTests/MXCurve25519KeyBackupTests.m b/MatrixSDKTests/MXCurve25519KeyBackupTests.m index d53842898d..346ff3a07f 100644 --- a/MatrixSDKTests/MXCurve25519KeyBackupTests.m +++ b/MatrixSDKTests/MXCurve25519KeyBackupTests.m @@ -1,5 +1,5 @@ /* - Copyright 2018 New Vector Ltd + Copyright 2022 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. From 1ea60bf218e64c9578eebd56326ef60d6a05f511 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 11 Aug 2022 01:37:31 +0300 Subject: [PATCH 33/65] Fix typo --- .../Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m | 2 +- .../Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m | 2 +- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 2 +- MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h | 2 +- MatrixSDKTests/MXKeyBackupUnitTests.swift | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index 3d8e5919f9..d9393414fb 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -39,7 +39,7 @@ @interface MXAes256KeyBackupAlgorithm () @implementation MXAes256KeyBackupAlgorithm -+ (NSString *)algorithName ++ (NSString *)algorithmName { return kMXCryptoAes256KeyBackupAlgorithm; } diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m index 6f3048117a..3c49f01d89 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m @@ -42,7 +42,7 @@ @interface MXCurve25519KeyBackupAlgorithm () @implementation MXCurve25519KeyBackupAlgorithm -+ (NSString *)algorithName ++ (NSString *)algorithmName { return kMXCryptoCurve25519KeyBackupAlgorithm; } diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index c59f206390..7583e2b2f2 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -546,7 +546,7 @@ - (void)prepareKeyBackupVersionWithPassword:(NSString *)password id authData = preparationInfo.authData; MXMegolmBackupCreationInfo *keyBackupCreationInfo = [MXMegolmBackupCreationInfo new]; - keyBackupCreationInfo.algorithm = [algorithmClass algorithName]; + keyBackupCreationInfo.algorithm = [algorithmClass algorithmName]; keyBackupCreationInfo.authData = authData; keyBackupCreationInfo.recoveryKey = [MXRecoveryKey encode:preparationInfo.privateKey]; diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h index 796f2225b2..f75038cbca 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackupAlgorithm.h @@ -35,7 +35,7 @@ typedef NSData* _Nullable (^MXKeyBackupPrivateKeyGetterBlock)(void); @protocol MXKeyBackupAlgorithm /// Name of the algorithm. Constants defined in `MXCryptoConstants`. -@property (class, nonatomic, readonly) NSString *algorithName; +@property (class, nonatomic, readonly) NSString *algorithmName; /// Flag indicating the algorithm is untrusted or not. @property (class, nonatomic, readonly, getter=isUntrusted) BOOL untrusted; diff --git a/MatrixSDKTests/MXKeyBackupUnitTests.swift b/MatrixSDKTests/MXKeyBackupUnitTests.swift index 0f99b4cb7c..5a541533cc 100644 --- a/MatrixSDKTests/MXKeyBackupUnitTests.swift +++ b/MatrixSDKTests/MXKeyBackupUnitTests.swift @@ -23,7 +23,7 @@ class MXKeyBackupUnitTests: XCTestCase { // MARK: - Curve25519 func testCurve25519AlgorithmClass() throws { - XCTAssertEqual(MXCurve25519KeyBackupAlgorithm.algorithName, kMXCryptoCurve25519KeyBackupAlgorithm) + XCTAssertEqual(MXCurve25519KeyBackupAlgorithm.algorithmName, kMXCryptoCurve25519KeyBackupAlgorithm) XCTAssertTrue(MXCurve25519KeyBackupAlgorithm.isUntrusted) } @@ -157,7 +157,7 @@ class MXKeyBackupUnitTests: XCTestCase { // MARK: - Aes256 func testAes256AlgorithmClass() throws { - XCTAssertEqual(MXAes256KeyBackupAlgorithm.algorithName, kMXCryptoAes256KeyBackupAlgorithm) + XCTAssertEqual(MXAes256KeyBackupAlgorithm.algorithmName, kMXCryptoAes256KeyBackupAlgorithm) XCTAssertFalse(MXAes256KeyBackupAlgorithm.isUntrusted) } From 9e5f498b0f7200684d259cf2a2db747653bff2f4 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 11 Aug 2022 02:04:34 +0300 Subject: [PATCH 34/65] Fix PR remarks --- .../KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m | 5 ++--- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 6 +++--- MatrixSDKTests/MXBaseKeyBackupTests.m | 2 ++ MatrixSDKTests/MXKeyBackupUnitTests.swift | 4 ++++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index d9393414fb..d53471fdb6 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -54,7 +54,6 @@ - (instancetype)initWithCrypto:(MXCrypto *)crypto authData:(id clean local private key (%@)", privateKey); + MXLogDebug(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: -> private key does not match: %@, will be removed", error); [crypto.store deleteSecretWithSecretId:MXSecretId.keyBackup]; } } @@ -443,7 +443,7 @@ - (void)restoreKeyBackupAutomaticallyWithPrivateKey:(void (^)(void))onComplete BOOL keyMatches = [_keyBackupAlgorithm keyMatches:privateKey error:&error]; if (error || !keyMatches) { - MXLogDebug(@"[MXKeyBackup] restoreKeyBackupAutomatically. Error: Invalid private key (%@)", privateKey); + MXLogDebug(@"[MXKeyBackup] restoreKeyBackupAutomatically. Error: Private key does not match: %@", error); [crypto.store deleteSecretWithSecretId:MXSecretId.keyBackup]; onComplete(); return; @@ -1057,7 +1057,7 @@ - (MXHTTPOperation*)restoreUsingPrivateKeyKeyBackup:(MXKeyBackupVersion*)keyBack NSError *error; if (error || ![[self getOrCreateKeyBackupAlgorithmFor:keyBackupVersion privateKey:privateKey] keyMatches:privateKey error:&error]) { - MXLogDebug(@"[MXKeyBackup] restoreUsingPrivateKeyKeyBackup. Error: Invalid private key (%@) for %@", privateKey, keyBackupVersion); + MXLogDebug(@"[MXKeyBackup] restoreUsingPrivateKeyKeyBackup. Error: Private key does not match: %@, for: %@", error, keyBackupVersion); if (failure) { dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/MatrixSDKTests/MXBaseKeyBackupTests.m b/MatrixSDKTests/MXBaseKeyBackupTests.m index 1c36a38645..4f170bda8d 100644 --- a/MatrixSDKTests/MXBaseKeyBackupTests.m +++ b/MatrixSDKTests/MXBaseKeyBackupTests.m @@ -607,6 +607,7 @@ - (void)testEncryptAndDecryptKeyBackupData // - Pick a megolm key MXOlmInboundGroupSession *session = [aliceSession.crypto.store inboundGroupSessionsToBackup:1].firstObject; + XCTAssertFalse(session.isUntrusted); session.untrusted = self.isUntrusted; [aliceSession.crypto.backup prepareKeyBackupVersionWithPassword:nil algorithm:self.algorithm success:^(MXMegolmBackupCreationInfo * _Nonnull keyBackupCreationInfo) { @@ -620,6 +621,7 @@ - (void)testEncryptAndDecryptKeyBackupData // - Check [MXKeyBackupAlgorithm decryptKeyBackupData] returns stg MXMegolmSessionData *sessionData = [aliceSession.crypto.backup.keyBackupAlgorithm decryptKeyBackupData:keyBackupData forSession:session.session.sessionIdentifier inRoom:roomId]; XCTAssertNotNil(sessionData); + XCTAssertEqual(sessionData.isUntrusted, self.isUntrusted); // - Compare the decrypted megolm key with the original one XCTAssertEqualObjects(session.exportSessionData.JSONDictionary, sessionData.JSONDictionary); diff --git a/MatrixSDKTests/MXKeyBackupUnitTests.swift b/MatrixSDKTests/MXKeyBackupUnitTests.swift index 5a541533cc..5ba646e363 100644 --- a/MatrixSDKTests/MXKeyBackupUnitTests.swift +++ b/MatrixSDKTests/MXKeyBackupUnitTests.swift @@ -74,6 +74,7 @@ class MXKeyBackupUnitTests: XCTestCase { func testCurve25519PreparationWithNoPassword() throws { let preparationInfoWithNoPass = try MXCurve25519KeyBackupAlgorithm.prepare(with: nil) guard let authDataWithNoPass = preparationInfoWithNoPass.authData as? MXCurve25519BackupAuthData else { + XCTFail("Failed to setup test conditions") return } XCTAssertFalse(authDataWithNoPass.publicKey.isEmpty) @@ -84,6 +85,7 @@ class MXKeyBackupUnitTests: XCTestCase { func testCurve25519PreparationWithPassword() throws { let preparationInfoWithPass = try MXCurve25519KeyBackupAlgorithm.prepare(with: "password") guard let authDataWithPass = preparationInfoWithPass.authData as? MXCurve25519BackupAuthData else { + XCTFail("Failed to setup test conditions") return } XCTAssertFalse(authDataWithPass.publicKey.isEmpty) @@ -215,6 +217,7 @@ class MXKeyBackupUnitTests: XCTestCase { func testAes256PreparationWithNoPassword() throws { let preparationInfoWithNoPass = try MXAes256KeyBackupAlgorithm.prepare(with: nil) guard let authDataWithNoPass = preparationInfoWithNoPass.authData as? MXAes256BackupAuthData else { + XCTFail("Failed to setup test conditions") return } XCTAssertNotNil(authDataWithNoPass.iv) @@ -226,6 +229,7 @@ class MXKeyBackupUnitTests: XCTestCase { func testAes256PreparationWithPassword() throws { let preparationInfoWithPass = try MXAes256KeyBackupAlgorithm.prepare(with: "password") guard let authDataWithPass = preparationInfoWithPass.authData as? MXAes256BackupAuthData else { + XCTFail("Failed to setup test conditions") return } XCTAssertNotNil(authDataWithPass.iv) From ca9a0ef48a5a3abb14b4af65437f72e49ef6deca Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 12 Aug 2022 06:27:25 -0500 Subject: [PATCH 35/65] (refactor) project settings update (#1543) --- AUTHORS.rst | 4 +++- MatrixSDK.xcodeproj/project.pbxproj | 4 +++- .../xcshareddata/xcschemes/MatrixSDK-iOS.xcscheme | 2 +- .../xcshareddata/xcschemes/MatrixSDK-macOS.xcscheme | 2 +- changelog.d/pr-1543.build | 1 + 5 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 changelog.d/pr-1543.build diff --git a/AUTHORS.rst b/AUTHORS.rst index 53843f77fb..8e67d14de0 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -45,4 +45,6 @@ Pierre Dubois John Flanagan * PR #463 Fix compatibility with Swift 4.0 (issue #393) * PR #465 SwiftMatrixSDK: Enum cleanup - \ No newline at end of file + +Michael Redig + * PR #1543 (refactor) project settings update diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 159cd87b79..c78a0f7a16 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -6028,7 +6028,7 @@ 32C6F92419DD814400EA4E9C /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1160; + LastUpgradeCheck = 1340; ORGANIZATIONNAME = matrix.org; TargetAttributes = { 32C6F92C19DD814400EA4E9C = { @@ -7392,6 +7392,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -7454,6 +7455,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; diff --git a/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-iOS.xcscheme b/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-iOS.xcscheme index b2e100f011..80e9624b62 100644 --- a/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-iOS.xcscheme +++ b/MatrixSDK.xcodeproj/xcshareddata/xcschemes/MatrixSDK-iOS.xcscheme @@ -1,6 +1,6 @@ Date: Wed, 17 Aug 2022 14:20:32 +0100 Subject: [PATCH 36/65] Fix `kickUser` to set `"leave"` membership There is no such thing as a `"kick"` membership in the spec. The fact that Synapse aliases `"kick"` to `"leave"` is unspecced behaviour. --- MatrixSDK/MXRestClient.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MatrixSDK/MXRestClient.m b/MatrixSDK/MXRestClient.m index a7cbf0cc09..8cbdca00e6 100644 --- a/MatrixSDK/MXRestClient.m +++ b/MatrixSDK/MXRestClient.m @@ -2632,7 +2632,7 @@ - (MXHTTPOperation*)kickUser:(NSString*)userId [MXTools encodeURIComponent:userId]]; NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; - parameters[@"membership"] = @"kick"; + parameters[@"membership"] = @"leave"; if (reason) { From c66166fa67c399615d8a6f3178cbd776ac375da2 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 18 Jul 2022 10:45:44 +0100 Subject: [PATCH 37/65] Crypto user and device identity --- MatrixSDK.xcodeproj/project.pbxproj | 168 +++++++++- .../Contrib/Swift/JSONModels/MXEvent.swift | 4 + .../CrossSigning/Data/MXCrossSigningInfo.h | 8 + .../CrossSigning/Data/MXCrossSigningInfo.m | 28 ++ .../Data/MXCryptoUserIdentityWrapper.swift | 65 ++++ .../MXCrossSigningInfoSource.swift | 53 +++ .../CrossSigning/MXCrossSigningV2.swift | 168 ++++++++++ .../CryptoMachine/MXCryptoMachine.swift | 166 +++++++-- .../CryptoMachine/MXCryptoProtocols.swift | 13 + .../CryptoMachine/MXCryptoRequests.swift | 96 +++++- .../Devices/Data/MXCryptoDeviceWrapper.swift | 52 +++ .../Crypto/{ => Devices}/Data/MXDeviceInfo.h | 11 +- .../Crypto/{ => Devices}/Data/MXDeviceInfo.m | 18 + .../{ => Devices}/Data/MXDeviceInfo_Private.h | 0 .../Crypto/Devices/MXDeviceInfoSource.swift | 55 +++ .../Crypto/{Data => Devices}/MXDeviceList.h | 0 .../Crypto/{Data => Devices}/MXDeviceList.m | 0 MatrixSDK/Crypto/MXCryptoV2.swift | 317 +++++++++++------- .../{Data => }/Trust/MXDeviceTrustLevel.h | 0 .../{Data => }/Trust/MXDeviceTrustLevel.m | 0 .../Crypto/Trust/MXTrustLevelSource.swift | 86 +++++ .../{Data => }/Trust/MXUserTrustLevel.h | 0 .../{Data => }/Trust/MXUserTrustLevel.m | 0 .../Trust/MXUsersTrustLevelSummary.h | 0 .../Trust/MXUsersTrustLevelSummary.m | 0 MatrixSDK/Utils/MXLog.swift | 37 ++ .../Data/MXCrossSigningInfoUnitTests.swift | 96 ++++++ .../MXCrossSigningInfoSourceUnitTests.swift | 84 +++++ .../Crypto/CryptoMachine/Device+Stub.swift | 50 +++ .../CryptoMachine/MXCryptoProtocolStubs.swift | 56 ++++ .../MXCryptoRequestsUnitTests.swift | 23 +- .../Devices/Data/MXDeviceInfoUnitTests.swift | 83 +++++ .../Devices/MXDeviceInfoSourceUnitTests.swift | 110 ++++++ .../Trust/MXTrustLevelSourceUnitTests.swift | 84 +++++ MatrixSDKTests/MXKeyBackupUnitTests.swift | 8 +- MatrixSDKTests/TestPlans/UnitTests.xctestplan | 7 +- .../UnitTestsWithSanitizers.xctestplan | 7 +- Podfile.lock | 2 +- changelog.d/pr-1531.misc | 1 + 39 files changed, 1787 insertions(+), 169 deletions(-) create mode 100644 MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift create mode 100644 MatrixSDK/Crypto/CrossSigning/MXCrossSigningInfoSource.swift create mode 100644 MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift create mode 100644 MatrixSDK/Crypto/Devices/Data/MXCryptoDeviceWrapper.swift rename MatrixSDK/Crypto/{ => Devices}/Data/MXDeviceInfo.h (90%) rename MatrixSDK/Crypto/{ => Devices}/Data/MXDeviceInfo.m (93%) rename MatrixSDK/Crypto/{ => Devices}/Data/MXDeviceInfo_Private.h (100%) create mode 100644 MatrixSDK/Crypto/Devices/MXDeviceInfoSource.swift rename MatrixSDK/Crypto/{Data => Devices}/MXDeviceList.h (100%) rename MatrixSDK/Crypto/{Data => Devices}/MXDeviceList.m (100%) rename MatrixSDK/Crypto/{Data => }/Trust/MXDeviceTrustLevel.h (100%) rename MatrixSDK/Crypto/{Data => }/Trust/MXDeviceTrustLevel.m (100%) create mode 100644 MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift rename MatrixSDK/Crypto/{Data => }/Trust/MXUserTrustLevel.h (100%) rename MatrixSDK/Crypto/{Data => }/Trust/MXUserTrustLevel.m (100%) rename MatrixSDK/Crypto/{Data => }/Trust/MXUsersTrustLevelSummary.h (100%) rename MatrixSDK/Crypto/{Data => }/Trust/MXUsersTrustLevelSummary.m (100%) create mode 100644 MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift create mode 100644 MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift create mode 100644 MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift create mode 100644 MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift rename MatrixSDKTests/Crypto/{V2 => CryptoMachine}/MXCryptoRequestsUnitTests.swift (77%) create mode 100644 MatrixSDKTests/Crypto/Devices/Data/MXDeviceInfoUnitTests.swift create mode 100644 MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift create mode 100644 MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift create mode 100644 changelog.d/pr-1531.misc diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 2b355bc4c8..232e802533 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1824,7 +1824,6 @@ ED2DD118286C450600F06731 /* MXCryptoRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2DD113286C450600F06731 /* MXCryptoRequests.swift */; }; ED2DD119286C450600F06731 /* MXCryptoRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2DD113286C450600F06731 /* MXCryptoRequests.swift */; }; ED2DD11D286C4F4400F06731 /* MXCryptoRequestsUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2DD11B286C4F3E00F06731 /* MXCryptoRequestsUnitTests.swift */; }; - ED2DD11E286C4F4400F06731 /* MXCryptoRequestsUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2DD11B286C4F3E00F06731 /* MXCryptoRequestsUnitTests.swift */; }; ED35652C281150310002BF6A /* MXOlmInboundGroupSessionUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED35652B281150310002BF6A /* MXOlmInboundGroupSessionUnitTests.swift */; }; ED35652D281150310002BF6A /* MXOlmInboundGroupSessionUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED35652B281150310002BF6A /* MXOlmInboundGroupSessionUnitTests.swift */; }; ED35652F281153480002BF6A /* MXMegolmSessionDataUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED35652E281153480002BF6A /* MXMegolmSessionDataUnitTests.swift */; }; @@ -1845,14 +1844,29 @@ ED5AE8C62816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = ED5AE8C22816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld */; }; ED5C95CE2833E85600843D82 /* MXOlmDeviceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */; }; ED5C95CF2833E85600843D82 /* MXOlmDeviceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */; }; + ED7019DD2886C24100FC31B9 /* MXCrossSigningInfoSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D242885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift */; }; + ED7019DE2886C24A00FC31B9 /* MXTrustLevelSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D2F2885AB0300F897E7 /* MXTrustLevelSourceUnitTests.swift */; }; + ED7019DF2886C25600FC31B9 /* MXDeviceInfoUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D1B2885909E00F897E7 /* MXDeviceInfoUnitTests.swift */; }; + ED7019E02886C26000FC31B9 /* MXDeviceInfoSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D2B2885A80B00F897E7 /* MXDeviceInfoSourceUnitTests.swift */; }; + ED7019E12886C26D00FC31B9 /* MXCryptoRequestsUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2DD11B286C4F3E00F06731 /* MXCryptoRequestsUnitTests.swift */; }; + ED7019E22886C28900FC31B9 /* MXCryptoProtocolStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D332885ADE200F897E7 /* MXCryptoProtocolStubs.swift */; }; + ED7019E32886C29400FC31B9 /* Device+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D312885AC5700F897E7 /* Device+Stub.swift */; }; ED88999127F2065D00718486 /* MXRoomAliasResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */; settings = {ATTRIBUTES = (Public, ); }; }; ED88999227F2065D00718486 /* MXRoomAliasResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */; settings = {ATTRIBUTES = (Public, ); }; }; ED88999327F2065D00718486 /* MXRoomAliasResolution.m in Sources */ = {isa = PBXBuildFile; fileRef = ED88999027F2065D00718486 /* MXRoomAliasResolution.m */; }; ED88999427F2065D00718486 /* MXRoomAliasResolution.m in Sources */ = {isa = PBXBuildFile; fileRef = ED88999027F2065D00718486 /* MXRoomAliasResolution.m */; }; ED8943D427E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8943D327E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift */; }; ED8943D527E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8943D327E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift */; }; - ED8F1D382885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */; }; - ED8F1D392885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */; }; + ED8F1D192885800000F897E7 /* MXCrossSigningInfoUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D1628857FE600F897E7 /* MXCrossSigningInfoUnitTests.swift */; }; + ED8F1D1E288590AF00F897E7 /* MXDeviceInfoUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D1B2885909E00F897E7 /* MXDeviceInfoUnitTests.swift */; }; + ED8F1D252885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D242885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift */; }; + ED8F1D2C2885A80B00F897E7 /* MXDeviceInfoSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D2B2885A80B00F897E7 /* MXDeviceInfoSourceUnitTests.swift */; }; + ED8F1D302885AB0300F897E7 /* MXTrustLevelSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D2F2885AB0300F897E7 /* MXTrustLevelSourceUnitTests.swift */; }; + ED8F1D322885AC5700F897E7 /* Device+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D312885AC5700F897E7 /* Device+Stub.swift */; }; + ED8F1D342885ADE200F897E7 /* MXCryptoProtocolStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D332885ADE200F897E7 /* MXCryptoProtocolStubs.swift */; }; + ED8F1D352885B07500F897E7 /* MXCrossSigningInfoUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D1628857FE600F897E7 /* MXCrossSigningInfoUnitTests.swift */; }; + ED8F1D3B2885BB2D00F897E7 /* MXCryptoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D3A2885BB2D00F897E7 /* MXCryptoProtocols.swift */; }; + ED8F1D3C2885BB2D00F897E7 /* MXCryptoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D3A2885BB2D00F897E7 /* MXCryptoProtocols.swift */; }; EDB4209227DF77390036AF39 /* MXEventsEnumeratorOnArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB4209027DF77310036AF39 /* MXEventsEnumeratorOnArrayTests.swift */; }; EDB4209327DF77390036AF39 /* MXEventsEnumeratorOnArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB4209027DF77310036AF39 /* MXEventsEnumeratorOnArrayTests.swift */; }; EDB4209527DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB4209427DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift */; }; @@ -1865,6 +1879,18 @@ EDBCF33A281A8D3D00ED5044 /* MXSharedHistoryKeyService.m in Sources */ = {isa = PBXBuildFile; fileRef = EDBCF338281A8D3D00ED5044 /* MXSharedHistoryKeyService.m */; }; EDC2A0E628369E740039F3D6 /* CryptoTests.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = EDC2A0E528369E740039F3D6 /* CryptoTests.xctestplan */; }; EDC2A0E728369E740039F3D6 /* CryptoTests.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = EDC2A0E528369E740039F3D6 /* CryptoTests.xctestplan */; }; + EDD578E12881C37C006739DD /* MXDeviceInfoSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DC2881C37C006739DD /* MXDeviceInfoSource.swift */; }; + EDD578E22881C37C006739DD /* MXDeviceInfoSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DC2881C37C006739DD /* MXDeviceInfoSource.swift */; }; + EDD578E32881C37C006739DD /* MXTrustLevelSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DD2881C37C006739DD /* MXTrustLevelSource.swift */; }; + EDD578E42881C37C006739DD /* MXTrustLevelSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DD2881C37C006739DD /* MXTrustLevelSource.swift */; }; + EDD578E52881C37C006739DD /* MXCrossSigningInfoSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DE2881C37C006739DD /* MXCrossSigningInfoSource.swift */; }; + EDD578E62881C37C006739DD /* MXCrossSigningInfoSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DE2881C37C006739DD /* MXCrossSigningInfoSource.swift */; }; + EDD578E72881C37C006739DD /* MXCryptoDeviceWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DF2881C37C006739DD /* MXCryptoDeviceWrapper.swift */; }; + EDD578E82881C37C006739DD /* MXCryptoDeviceWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578DF2881C37C006739DD /* MXCryptoDeviceWrapper.swift */; }; + EDD578E92881C37C006739DD /* MXCryptoUserIdentityWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578E02881C37C006739DD /* MXCryptoUserIdentityWrapper.swift */; }; + EDD578EA2881C37C006739DD /* MXCryptoUserIdentityWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578E02881C37C006739DD /* MXCryptoUserIdentityWrapper.swift */; }; + EDD578EC2881C38C006739DD /* MXCrossSigningV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578EB2881C38C006739DD /* MXCrossSigningV2.swift */; }; + EDD578ED2881C38C006739DD /* MXCrossSigningV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578EB2881C38C006739DD /* MXCrossSigningV2.swift */; }; EDF1B6902876CD2C00BBBCEE /* MXTaskQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF1B68F2876CD2C00BBBCEE /* MXTaskQueue.swift */; }; EDF1B6912876CD2C00BBBCEE /* MXTaskQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF1B68F2876CD2C00BBBCEE /* MXTaskQueue.swift */; }; EDF1B6932876CD8600BBBCEE /* MXTaskQueueUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF1B6922876CD8600BBBCEE /* MXTaskQueueUnitTests.swift */; }; @@ -2893,13 +2919,26 @@ 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 = ""; }; ED8943D327E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXMemoryRoomStoreUnitTests.swift; sourceTree = ""; }; - ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCryptoProtocols.swift; sourceTree = ""; }; + ED8F1D1628857FE600F897E7 /* MXCrossSigningInfoUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCrossSigningInfoUnitTests.swift; sourceTree = ""; }; + ED8F1D1B2885909E00F897E7 /* MXDeviceInfoUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXDeviceInfoUnitTests.swift; sourceTree = ""; }; + ED8F1D242885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCrossSigningInfoSourceUnitTests.swift; sourceTree = ""; }; + ED8F1D2B2885A80B00F897E7 /* MXDeviceInfoSourceUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXDeviceInfoSourceUnitTests.swift; sourceTree = ""; }; + ED8F1D2F2885AB0300F897E7 /* MXTrustLevelSourceUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXTrustLevelSourceUnitTests.swift; sourceTree = ""; }; + ED8F1D312885AC5700F897E7 /* Device+Stub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Device+Stub.swift"; sourceTree = ""; }; + ED8F1D332885ADE200F897E7 /* MXCryptoProtocolStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCryptoProtocolStubs.swift; sourceTree = ""; }; + ED8F1D3A2885BB2D00F897E7 /* MXCryptoProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoProtocols.swift; sourceTree = ""; }; EDB4209027DF77310036AF39 /* MXEventsEnumeratorOnArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXEventsEnumeratorOnArrayTests.swift; sourceTree = ""; }; EDB4209427DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXEventsByTypesEnumeratorOnArrayTests.swift; sourceTree = ""; }; EDB4209827DF842F0036AF39 /* MXEventFixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXEventFixtures.swift; sourceTree = ""; }; EDBCF335281A8AB900ED5044 /* MXSharedHistoryKeyService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXSharedHistoryKeyService.h; sourceTree = ""; }; EDBCF338281A8D3D00ED5044 /* MXSharedHistoryKeyService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXSharedHistoryKeyService.m; sourceTree = ""; }; EDC2A0E528369E740039F3D6 /* CryptoTests.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CryptoTests.xctestplan; sourceTree = ""; }; + EDD578DC2881C37C006739DD /* MXDeviceInfoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXDeviceInfoSource.swift; sourceTree = ""; }; + EDD578DD2881C37C006739DD /* MXTrustLevelSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXTrustLevelSource.swift; sourceTree = ""; }; + EDD578DE2881C37C006739DD /* MXCrossSigningInfoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCrossSigningInfoSource.swift; sourceTree = ""; }; + EDD578DF2881C37C006739DD /* MXCryptoDeviceWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoDeviceWrapper.swift; sourceTree = ""; }; + EDD578E02881C37C006739DD /* MXCryptoUserIdentityWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoUserIdentityWrapper.swift; sourceTree = ""; }; + EDD578EB2881C38C006739DD /* MXCrossSigningV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCrossSigningV2.swift; sourceTree = ""; }; 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 = ""; }; @@ -3201,6 +3240,7 @@ 32581DE723C8C0C900832EAA /* MXUserTrustLevel.m */, B14766B523D9D9410091F721 /* MXUsersTrustLevelSummary.h */, B14766B623D9D9410091F721 /* MXUsersTrustLevelSummary.m */, + EDD578DD2881C37C006739DD /* MXTrustLevelSource.swift */, ); path = Trust; sourceTree = ""; @@ -3221,6 +3261,8 @@ children = ( 322A51C01D9AC8FE00C8536D /* Algorithms */, 32CEEF3F23AD2A340039BA98 /* CrossSigning */, + ED8F1D272885A7B600F897E7 /* Devices */, + 32261B8723C749FB0018F1E2 /* Trust */, 32A1513B1DAF768D00400192 /* Data */, 3AC1379326432ED500EE1E74 /* Dehydration */, 32BBAE642178E99100D85F46 /* KeyBackup */, @@ -3530,6 +3572,7 @@ 325AD43D23BE3E7500FF5277 /* MXCrossSigningInfo.h */, 325AD43E23BE3E7500FF5277 /* MXCrossSigningInfo.m */, 329EEE4F23BE4D8400FBE484 /* MXCrossSigningInfo_Private.h */, + EDD578E02881C37C006739DD /* MXCryptoUserIdentityWrapper.swift */, ); path = Data; sourceTree = ""; @@ -3827,18 +3870,12 @@ isa = PBXGroup; children = ( 3284A59C1DB7C00600A09972 /* Store */, - 32261B8723C749FB0018F1E2 /* Trust */, 021AFBA02179E91800742B2C /* MXEncryptedContentFile.h */, 021AFBA32179E91800742B2C /* MXEncryptedContentFile.m */, 021AFBA22179E91800742B2C /* MXEncryptedContentKey.h */, 021AFBA12179E91800742B2C /* MXEncryptedContentKey.m */, 3256E37F1DCB91EB003C9718 /* MXCryptoConstants.h */, 3256E3801DCB91EB003C9718 /* MXCryptoConstants.m */, - 32A151401DAF7C0C00400192 /* MXDeviceInfo.h */, - 32FF948023CE077200DA5B15 /* MXDeviceInfo_Private.h */, - 32A151411DAF7C0C00400192 /* MXDeviceInfo.m */, - 32637ED21E5B00400011E20D /* MXDeviceList.h */, - 32637ED31E5B00400011E20D /* MXDeviceList.m */, 322691301E5EF77D00966A6E /* MXDeviceListOperation.h */, 322691311E5EF77D00966A6E /* MXDeviceListOperation.m */, 322691341E5EFF8700966A6E /* MXDeviceListOperationsPool.h */, @@ -4160,8 +4197,10 @@ 32CEEF4D23B0AB030039BA98 /* MXCrossSigning.h */, 32CEEF4E23B0AB030039BA98 /* MXCrossSigning.m */, 32CEEF5323B0AB1C0039BA98 /* MXCrossSigning_Private.h */, + EDD578EB2881C38C006739DD /* MXCrossSigningV2.swift */, 32CEEF4723B0A8170039BA98 /* MXCrossSigningTools.h */, 32CEEF4823B0A8170039BA98 /* MXCrossSigningTools.m */, + EDD578DE2881C37C006739DD /* MXCrossSigningInfoSource.swift */, ); path = CrossSigning; sourceTree = ""; @@ -5060,10 +5099,13 @@ ED21F67A28104B9A002FF83D /* Crypto */ = { isa = PBXGroup; children = ( + ED8F1D1428857FD300F897E7 /* CrossSigning */, + ED8F1D2E2885AAEB00F897E7 /* Trust */, + ED8F1D292885A7DF00F897E7 /* Devices */, ED44F01628180F1300452A5D /* KeySharing */, ED35652A281150230002BF6A /* Data */, ED21F67B28104BA1002FF83D /* Algorithms */, - ED2DD11A286C4F3100F06731 /* V2 */, + ED2DD11A286C4F3100F06731 /* CryptoMachine */, ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */, ); path = Crypto; @@ -5090,19 +5132,21 @@ isa = PBXGroup; children = ( ED2DD111286C450600F06731 /* MXCryptoMachine.swift */, - ED8F1D372885B99E00F897E7 /* MXCryptoProtocols.swift */, + ED8F1D3A2885BB2D00F897E7 /* MXCryptoProtocols.swift */, ED2DD112286C450600F06731 /* MXEventDecryptionResult+DecryptedEvent.swift */, ED2DD113286C450600F06731 /* MXCryptoRequests.swift */, ); path = CryptoMachine; sourceTree = ""; }; - ED2DD11A286C4F3100F06731 /* V2 */ = { + ED2DD11A286C4F3100F06731 /* CryptoMachine */ = { isa = PBXGroup; children = ( + ED8F1D332885ADE200F897E7 /* MXCryptoProtocolStubs.swift */, ED2DD11B286C4F3E00F06731 /* MXCryptoRequestsUnitTests.swift */, + ED8F1D312885AC5700F897E7 /* Device+Stub.swift */, ); - path = V2; + path = CryptoMachine; sourceTree = ""; }; ED35652A281150230002BF6A /* Data */ = { @@ -5138,6 +5182,70 @@ path = MXMemoryStore; sourceTree = ""; }; + ED8F1D1428857FD300F897E7 /* CrossSigning */ = { + isa = PBXGroup; + children = ( + ED8F1D1528857FDA00F897E7 /* Data */, + ED8F1D242885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift */, + ); + path = CrossSigning; + sourceTree = ""; + }; + ED8F1D1528857FDA00F897E7 /* Data */ = { + isa = PBXGroup; + children = ( + ED8F1D1628857FE600F897E7 /* MXCrossSigningInfoUnitTests.swift */, + ); + path = Data; + sourceTree = ""; + }; + ED8F1D272885A7B600F897E7 /* Devices */ = { + isa = PBXGroup; + children = ( + ED8F1D282885A7BC00F897E7 /* Data */, + 32637ED21E5B00400011E20D /* MXDeviceList.h */, + 32637ED31E5B00400011E20D /* MXDeviceList.m */, + EDD578DC2881C37C006739DD /* MXDeviceInfoSource.swift */, + ); + path = Devices; + sourceTree = ""; + }; + ED8F1D282885A7BC00F897E7 /* Data */ = { + isa = PBXGroup; + children = ( + 32A151401DAF7C0C00400192 /* MXDeviceInfo.h */, + 32A151411DAF7C0C00400192 /* MXDeviceInfo.m */, + 32FF948023CE077200DA5B15 /* MXDeviceInfo_Private.h */, + EDD578DF2881C37C006739DD /* MXCryptoDeviceWrapper.swift */, + ); + path = Data; + sourceTree = ""; + }; + ED8F1D292885A7DF00F897E7 /* Devices */ = { + isa = PBXGroup; + children = ( + ED8F1D2A2885A7E600F897E7 /* Data */, + ED8F1D2B2885A80B00F897E7 /* MXDeviceInfoSourceUnitTests.swift */, + ); + path = Devices; + sourceTree = ""; + }; + ED8F1D2A2885A7E600F897E7 /* Data */ = { + isa = PBXGroup; + children = ( + ED8F1D1B2885909E00F897E7 /* MXDeviceInfoUnitTests.swift */, + ); + path = Data; + sourceTree = ""; + }; + ED8F1D2E2885AAEB00F897E7 /* Trust */ = { + isa = PBXGroup; + children = ( + ED8F1D2F2885AB0300F897E7 /* MXTrustLevelSourceUnitTests.swift */, + ); + path = Trust; + sourceTree = ""; + }; EDB4208E27DF76C60036AF39 /* Data */ = { isa = PBXGroup; children = ( @@ -6303,6 +6411,7 @@ B1136965230AC9D900E2B2FA /* MXIdentityService.m in Sources */, 66836AB727CFA17200515780 /* MXEventStreamService.swift in Sources */, B11BD44922CB56790064D8B0 /* MXReplyEventParser.m in Sources */, + ED8F1D3B2885BB2D00F897E7 /* MXCryptoProtocols.swift in Sources */, EC0B941127184E8A00B4D440 /* MXRoomSummaryMO.swift in Sources */, EDBCF339281A8D3D00ED5044 /* MXSharedHistoryKeyService.m in Sources */, EC0B941327184E8A00B4D440 /* MXRoomMembersCountMO.swift in Sources */, @@ -6315,10 +6424,10 @@ EC0B942127186D4600B4D440 /* MXRoomListDataFilterable.swift in Sources */, 324DD2B8246C21C700377005 /* MXSecretStorageKeyCreationInfo.m in Sources */, EC1165C027107E330089FA56 /* MXSuggestedRoomListDataCache.swift in Sources */, - ED8F1D382885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */, ECD2897726E8ED0900F268CF /* MXRoomListDataFetchOptions.swift in Sources */, EC403846289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */, EC0B941B2718654B00B4D440 /* NSManagedObject+MatrixSDK.swift in Sources */, + EDD578E12881C37C006739DD /* MXDeviceInfoSource.swift in Sources */, 327E9AE82285A8C400A98BC1 /* MXAggregationPaginatedResponse.m in Sources */, B10AFB4422A970060092E6AF /* MXEventReplace.m in Sources */, EC383BB62540E15E002FBBE6 /* MXBackgroundPushRulesManager.swift in Sources */, @@ -6367,6 +6476,7 @@ 92634B831EF2E3C400DB9F60 /* MXCallKitConfiguration.m in Sources */, 3265CB391A14C43E00E24B2F /* MXRoomState.m in Sources */, EC619D9224DD834B00663A80 /* MXPushGatewayRestClient.m in Sources */, + EDD578EC2881C38C006739DD /* MXCrossSigningV2.swift in Sources */, 3281E8B819E42DFE00976E1A /* MXJSONModel.m in Sources */, 32AF929924115D8B0008A0FD /* MXPendingSecretShareRequest.m in Sources */, 327E9AE22285497100A98BC1 /* MXEventContentRelatesTo.m in Sources */, @@ -6458,6 +6568,7 @@ EC60EE08265CFFF400B39A4E /* MXGroupSyncProfile.m in Sources */, B1432B53282AB29A00737CA6 /* MXBeaconInfoSummaryPerRoomListener.swift in Sources */, B1D50DD5288EB34900DD1AA3 /* MXBeaconInfoSummaryDeletionPerRoomListener.swift in Sources */, + EDD578E92881C37C006739DD /* MXCryptoUserIdentityWrapper.swift in Sources */, B19A30A0240424BD00FB6F35 /* MXQRCodeTransaction.m in Sources */, C63E78B01F26588000AC692F /* MXRoomPowerLevels.swift in Sources */, EC0B943F271DB68F00B4D440 /* MXVoidRoomSummaryStore.m in Sources */, @@ -6465,6 +6576,7 @@ 32CEEF4523AD2A6C0039BA98 /* MXCrossSigningKey.m in Sources */, 327E9AF02289C61100A98BC1 /* MXAggregations.m in Sources */, B18B0E4A25FB783B00E32151 /* MXSpaceCreationParameters.swift in Sources */, + EDD578E52881C37C006739DD /* MXCrossSigningInfoSource.swift in Sources */, EC2EACFF266625170038B61F /* MXRoomLastMessage.m in Sources */, EDF1B6902876CD2C00BBBCEE /* MXTaskQueue.swift in Sources */, EC8A539525B1BC77004E0802 /* MXUserModel.m in Sources */, @@ -6567,6 +6679,7 @@ 324DD2AE246AEB7B00377005 /* MXSecretStoragePassphrase.m in Sources */, ECB5D98C2552C9B4000AD89C /* MXStopwatch.swift in Sources */, B1136964230AC9D900E2B2FA /* MXIdentityServerRestClient.m in Sources */, + EDD578E32881C37C006739DD /* MXTrustLevelSource.swift in Sources */, F0C34CBB1C18C93700C36F09 /* MXSDKOptions.m in Sources */, B16F35A225F916A00029AE98 /* MXRoomTypeMapper.swift in Sources */, ECD289BF26FDE5F700F268CF /* MXStoreRoomListDataCounts.swift in Sources */, @@ -6635,6 +6748,7 @@ B146D4F721A5BB9F00D8C2C6 /* MXRealmMediaScanStore.m in Sources */, 32999DE422DCD1AD004FF987 /* MXPusherData.m in Sources */, 322A51C81D9BBD3C00C8536D /* MXOlmDevice.m in Sources */, + EDD578E72881C37C006739DD /* MXCryptoDeviceWrapper.swift in Sources */, EC60ED5F265CFC2C00B39A4E /* MXSyncResponse.m in Sources */, EC383BA2253DE4B1002FBBE6 /* MXBackgroundSyncService.swift in Sources */, 18121F7D273E835D00B68ADF /* PollModels.swift in Sources */, @@ -6697,6 +6811,7 @@ EDB4209527DF822B0036AF39 /* MXEventsByTypesEnumeratorOnArrayTests.swift in Sources */, EC40385D28A16EDA0067D5B8 /* MXAes256KeyBackupTests.m in Sources */, 3265CB3B1A151C3800E24B2F /* MXRoomStateTests.m in Sources */, + ED8F1D302885AB0300F897E7 /* MXTrustLevelSourceUnitTests.swift in Sources */, B135066927EA100000BD3276 /* MXBeaconInfoUnitTests.swift in Sources */, EC0B944627206D0B00B4D440 /* MXCoreDataRoomListDataManagerUnitTests.swift in Sources */, 32CEEF3D23AD134A0039BA98 /* MXCrossSigningTests.m in Sources */, @@ -6720,6 +6835,7 @@ B11BD45C22CB8ABC0064D8B0 /* MXReplyEventParserUnitTests.m in Sources */, ECAE7AEC24ED75F1002FA813 /* MXHTTPAdditionalHeadersUnitTests.m in Sources */, 32AF9292241112850008A0FD /* MXCryptoSecretShareTests.m in Sources */, + ED8F1D342885ADE200F897E7 /* MXCryptoProtocolStubs.swift in Sources */, 3A7B8D0E267FCF7200D9DD96 /* MXDehydrationTests.m in Sources */, 3281E8A019E2CC1200976E1A /* MXHTTPClientTests.m in Sources */, 321809B919EEBF3000377451 /* MXEventTests.m in Sources */, @@ -6733,6 +6849,7 @@ C61A4AF41E5DD88400442158 /* Dummy.swift in Sources */, 32935F61216FA49D00A1BC24 /* MXCurve25519KeyBackupTests.m in Sources */, B1F04B162811EFF700103EBE /* MXBeaconAggregationsTests.swift in Sources */, + ED8F1D2C2885A80B00F897E7 /* MXDeviceInfoSourceUnitTests.swift in Sources */, 328DDEC11A07E57E008C7DC8 /* MXJSONModelTests.m in Sources */, 32832B5C1BCC048300241108 /* MXStoreFileStoreTests.m in Sources */, B1F939F526289F2600D0E525 /* MXSpaceChildContentTests.swift in Sources */, @@ -6748,7 +6865,9 @@ 18937E7C273A5AE500902626 /* MXPollRelationTests.m in Sources */, 32792BE12296C64200F4FC9D /* MXAggregatedEditsTests.m in Sources */, 329571931B0240CE00ABB3BA /* MXVoIPTests.m in Sources */, + ED8F1D322885AC5700F897E7 /* Device+Stub.swift in Sources */, EC746C56274E5197002AD24C /* MXThreadingServiceUnitTests.swift in Sources */, + ED8F1D252885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift in Sources */, 32A27D1F19EC335300BAFADE /* MXRoomTests.m in Sources */, 32D8CAC219DEE6ED002AF8A0 /* MXRestClientNoAuthAPITests.m in Sources */, 32FCAB4D19E578860049C555 /* MXRestClientTests.m in Sources */, @@ -6773,9 +6892,11 @@ 321EA11D24893A0400E35B02 /* MXCryptoRecoveryServiceTests.m in Sources */, 3A858DDD275121DB006322C1 /* MXHomeserverCapabilitiesTests.swift in Sources */, 3264DB941CECA72900B99881 /* MXAccountDataTests.m in Sources */, + ED8F1D1E288590AF00F897E7 /* MXDeviceInfoUnitTests.swift in Sources */, 32792BDF2296C59B00F4FC9D /* MXAggregatedReactionTests.m in Sources */, 322D01C422492B0700150C68 /* MXCryptoShareTests.m in Sources */, B1EE98D628048AEA00AB63F0 /* MXGeoURIComponentsUnitTests.swift in Sources */, + ED8F1D192885800000F897E7 /* MXCrossSigningInfoUnitTests.swift in Sources */, 323EF7471C7CB4C7000DC98C /* MXRoomEventTimelineTests.m in Sources */, 32E226A91D081CE200E6CA54 /* MXPeekingRoomTests.m in Sources */, EC383BBF2542F1E3002FBBE6 /* MXBackgroundSyncServiceTests.swift in Sources */, @@ -6880,6 +7001,7 @@ 3A108A8125810C96005EEBE9 /* MXKeyData.m in Sources */, 66836AB827CFA17200515780 /* MXEventStreamService.swift in Sources */, 3A59A4A025A7A16F00DDA1FC /* MXOlmOutboundGroupSession.m in Sources */, + ED8F1D3C2885BB2D00F897E7 /* MXCryptoProtocols.swift in Sources */, EC0B941227184E8A00B4D440 /* MXRoomSummaryMO.swift in Sources */, EDBCF33A281A8D3D00ED5044 /* MXSharedHistoryKeyService.m in Sources */, EC0B941427184E8A00B4D440 /* MXRoomMembersCountMO.swift in Sources */, @@ -6892,10 +7014,10 @@ EC0B942227186D4600B4D440 /* MXRoomListDataFilterable.swift in Sources */, 32F00ABE2488E1CD00131741 /* MXRecoveryService.m in Sources */, B14EF1FB2397E90400758AF0 /* MXEnumConstants.swift in Sources */, - ED8F1D392885B99E00F897E7 /* MXCryptoProtocols.swift in Sources */, B14EF1FC2397E90400758AF0 /* MXEventRelations.m in Sources */, EC403847289A7F0F0067D5B8 /* MXCurve25519KeyBackupAlgorithm.m in Sources */, EC0B941C2718654B00B4D440 /* NSManagedObject+MatrixSDK.swift in Sources */, + EDD578E22881C37C006739DD /* MXDeviceInfoSource.swift in Sources */, EC8A53E325B1BCC6004E0802 /* MXThirdPartyUserInstance.m in Sources */, EC383BB12540688B002FBBE6 /* MXBackgroundSyncService.swift in Sources */, 322AB587260CD5690017E964 /* MXCachedSyncResponse.m in Sources */, @@ -6944,6 +7066,7 @@ B14EF2132397E90400758AF0 /* MXUIKitBackgroundTask.m in Sources */, EC60EDFF265CFFD200B39A4E /* MXInvitedGroupSync.m in Sources */, B14EF2142397E90400758AF0 /* MXPeekingRoomSummary.m in Sources */, + EDD578ED2881C38C006739DD /* MXCrossSigningV2.swift in Sources */, B14EF2152397E90400758AF0 /* MXRoom.swift in Sources */, B14EF2162397E90400758AF0 /* MXOlmSession.m in Sources */, EC8A53A425B1BC77004E0802 /* MXCallEventContent.m in Sources */, @@ -7035,6 +7158,7 @@ B14EF23F2397E90400758AF0 /* MXEncryptedContentFile.m in Sources */, B1432B54282AB29A00737CA6 /* MXBeaconInfoSummaryPerRoomListener.swift in Sources */, B1D50DD6288EB34900DD1AA3 /* MXBeaconInfoSummaryDeletionPerRoomListener.swift in Sources */, + EDD578EA2881C37C006739DD /* MXCryptoUserIdentityWrapper.swift in Sources */, EC8A539625B1BC77004E0802 /* MXUserModel.m in Sources */, EC0B9440271DB68F00B4D440 /* MXVoidRoomSummaryStore.m in Sources */, B14EF2402397E90400758AF0 /* MXSessionEventListener.m in Sources */, @@ -7042,6 +7166,7 @@ ECD2899226EB3B3400F268CF /* MXRoomListDataFetcher.swift in Sources */, B18B0E5025FB783F00E32151 /* MXSpaceService.swift in Sources */, B14EF2412397E90400758AF0 /* MXRoomFilter.m in Sources */, + EDD578E62881C37C006739DD /* MXCrossSigningInfoSource.swift in Sources */, EC8A53D925B1BCC6004E0802 /* MXThirdPartyProtocolInstance.m in Sources */, EDF1B6912876CD2C00BBBCEE /* MXTaskQueue.swift in Sources */, B14EF2422397E90400758AF0 /* MXDeviceInfo.m in Sources */, @@ -7144,6 +7269,7 @@ EC60ED9D265CFE1700B39A4E /* MXRoomSyncState.m in Sources */, 324676ED25C15F4600EA855B /* MXMemory.swift in Sources */, EC60ED6A265CFC7200B39A4E /* MXPresenceSyncResponse.m in Sources */, + EDD578E42881C37C006739DD /* MXTrustLevelSource.swift in Sources */, 3A108AA525810FE5005EEBE9 /* MXRawDataKey.m in Sources */, 324DD29C246AD2B500377005 /* MXSecretStorage.m in Sources */, EC60EDC9265CFEA800B39A4E /* MXRoomSyncUnreadNotifications.m in Sources */, @@ -7212,6 +7338,7 @@ 3A108A9B25810F62005EEBE9 /* MXAesKeyData.m in Sources */, B14EF28A2397E90400758AF0 /* MXTools.m in Sources */, B14EF28B2397E90400758AF0 /* MXRoomSummaryUpdater.m in Sources */, + EDD578E82881C37C006739DD /* MXCryptoDeviceWrapper.swift in Sources */, B14EF28C2397E90400758AF0 /* MXScanRealmInMemoryProvider.m in Sources */, EC60ED92265CFD3B00B39A4E /* MXRoomSync.m in Sources */, B14EF28D2397E90400758AF0 /* MXMegolmSessionData.m in Sources */, @@ -7246,6 +7373,7 @@ B1E09A392397FD7D0057C069 /* MXMyUserTests.m in Sources */, 322985D026FBAE7B001890BC /* TestObserver.swift in Sources */, B1E09A202397FCE90057C069 /* MXCurve25519KeyBackupTests.m in Sources */, + ED7019DD2886C24100FC31B9 /* MXCrossSigningInfoSourceUnitTests.swift in Sources */, ED51943A28462D130006EEC6 /* MXRoomStateUnitTests.swift in Sources */, B1E09A3B2397FD820057C069 /* MXStoreNoStoreTests.m in Sources */, EDB4209327DF77390036AF39 /* MXEventsEnumeratorOnArrayTests.swift in Sources */, @@ -7259,7 +7387,6 @@ B1E09A442397FD940057C069 /* Dummy.swift in Sources */, 18121F76273E6D2400B68ADF /* MXPollBuilderTests.swift in Sources */, B1E09A1A2397FCE90057C069 /* MXAggregatedEditsTests.m in Sources */, - ED2DD11E286C4F4400F06731 /* MXCryptoRequestsUnitTests.swift in Sources */, B1E09A1F2397FCE90057C069 /* MXAutoDiscoveryTests.m in Sources */, EDB4209A27DF842F0036AF39 /* MXEventFixtures.swift in Sources */, B1E09A2E2397FD750057C069 /* MXRestClientTests.m in Sources */, @@ -7279,6 +7406,7 @@ B1E09A2B2397FD6B0057C069 /* MatrixSDKTestsE2EData.m in Sources */, B1E09A3C2397FD820057C069 /* MXStoreMemoryStoreTests.m in Sources */, EC1165CF27107F3E0089FA56 /* MXRoomListDataManagerTests.swift in Sources */, + ED7019E22886C28900FC31B9 /* MXCryptoProtocolStubs.swift in Sources */, B1E09A3E2397FD820057C069 /* MXToolsUnitTests.m in Sources */, 32B477912638133D00EA5800 /* MXAggregatedEditsUnitTests.m in Sources */, EC40386228A1A3830067D5B8 /* MXBaseKeyBackupTests.m in Sources */, @@ -7293,10 +7421,12 @@ B1E09A462397FD990057C069 /* MXMediaScanStoreUnitTests.m in Sources */, ECB6FA8F267CFF4300A941E4 /* MXCredentialsUnitTests.swift in Sources */, 3A858DE9275511A4006322C1 /* MXRoomAliasAvailabilityCheckerResultTests.swift in Sources */, + ED7019DF2886C25600FC31B9 /* MXDeviceInfoUnitTests.swift in Sources */, B1E09A292397FD080057C069 /* MXLoggerUnitTests.m in Sources */, B1E09A492398028D0057C069 /* MXSelfSignedHomeserverTests.m in Sources */, 32B0E3E523A384D40054FF1A /* MXAggregatedReferenceTests.m in Sources */, 3A7B8D13267FCF7300D9DD96 /* MXDehydrationTests.m in Sources */, + ED7019E32886C29400FC31B9 /* Device+Stub.swift in Sources */, 32D5D16423E400A600E3E37C /* MXRoomSummaryTrustTests.m in Sources */, B1E09A1B2397FCE90057C069 /* MXAggregatedReactionTests.m in Sources */, B1E09A3F2397FD820057C069 /* MXNotificationCenterTests.m in Sources */, @@ -7308,6 +7438,8 @@ B1E09A342397FD750057C069 /* MXRoomStateDynamicTests.m in Sources */, B1E09A272397FD010057C069 /* MXMockCallStack.m in Sources */, B14EECEF2578FE3F00448735 /* MXAuthenticationSessionUnitTests.swift in Sources */, + ED7019DE2886C24A00FC31B9 /* MXTrustLevelSourceUnitTests.swift in Sources */, + ED7019E02886C26000FC31B9 /* MXDeviceInfoSourceUnitTests.swift in Sources */, B1E09A432397FD820057C069 /* MXMegolmExportEncryptionUnitTests.m in Sources */, B1F04B172811EFF700103EBE /* MXBeaconAggregationsTests.swift in Sources */, 32B477AF263818BA00EA5800 /* MXKeyProviderUnitTests.m in Sources */, @@ -7336,6 +7468,7 @@ EC131B1A2779D8D500712964 /* MXThreadEventTimelineUnitTests.swift in Sources */, B135067527EB201E00BD3276 /* MXLocationServiceTests.swift in Sources */, ED51943D284630090006EEC6 /* MXRestClientStub.m in Sources */, + ED7019E12886C26D00FC31B9 /* MXCryptoRequestsUnitTests.swift in Sources */, 18C26C50273C0EB400805154 /* MXPollAggregatorTests.swift in Sources */, ED356530281153480002BF6A /* MXMegolmSessionDataUnitTests.swift in Sources */, 32C78BA8256D227D008130B1 /* MXCryptoMigrationTests.m in Sources */, @@ -7353,6 +7486,7 @@ B1E09A372397FD7D0057C069 /* MXRoomMemberTests.m in Sources */, B1E09A2C2397FD6F0057C069 /* MXFilterTests.m in Sources */, B1EE98D728048AEA00AB63F0 /* MXGeoURIComponentsUnitTests.swift in Sources */, + ED8F1D352885B07500F897E7 /* MXCrossSigningInfoUnitTests.swift in Sources */, B1E09A252397FCE90057C069 /* MXRoomEventTimelineTests.m in Sources */, B1E09A362397FD7D0057C069 /* MXJSONModelTests.m in Sources */, B1E09A192397FCE90057C069 /* MXReplyEventParserUnitTests.m in Sources */, diff --git a/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift b/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift index 4b816948d0..856ba65138 100644 --- a/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift +++ b/MatrixSDK/Contrib/Swift/JSONModels/MXEvent.swift @@ -65,6 +65,8 @@ public enum MXEventType: Equatable, Hashable { case reaction case receipt case roomTombStone + case keyVerificationRequest + case keyVerificationReady case keyVerificationStart case keyVerificationAccept case keyVerificationKey @@ -122,6 +124,8 @@ public enum MXEventType: Equatable, Hashable { case .reaction: return kMXEventTypeStringReaction case .receipt: return kMXEventTypeStringReceipt case .roomTombStone: return kMXEventTypeStringRoomTombStone + case .keyVerificationRequest: return kMXEventTypeStringKeyVerificationRequest + case .keyVerificationReady: return kMXEventTypeStringKeyVerificationReady case .keyVerificationStart: return kMXEventTypeStringKeyVerificationStart case .keyVerificationAccept: return kMXEventTypeStringKeyVerificationAccept case .keyVerificationKey: return kMXEventTypeStringKeyVerificationKey diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h index 7c9808f37b..68576f67fc 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h @@ -19,6 +19,7 @@ #import "MXCrossSigningKey.h" #import "MXUserTrustLevel.h" +@class MXCryptoUserIdentityWrapper; NS_ASSUME_NONNULL_BEGIN @@ -32,6 +33,13 @@ extern NSString *const MXCrossSigningInfoTrustLevelDidChangeNotification; */ @interface MXCrossSigningInfo : NSObject +#if DEBUG && TARGET_OS_IPHONE +/** + Initialize cross signing with MatrixSDKCrypto user identity + */ +- (instancetype)initWithUserIdentity:(MXCryptoUserIdentityWrapper *)userIdentity; +#endif + /** The user's id. */ diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m index 5afb793829..172ac1ed17 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m @@ -15,6 +15,7 @@ */ #import "MXCrossSigningInfo_Private.h" +#import "MatrixSDKSwiftHeader.h" #pragma mark - Constants @@ -22,6 +23,33 @@ @implementation MXCrossSigningInfo +#if DEBUG && TARGET_OS_IPHONE +- (instancetype)initWithUserIdentity:(MXCryptoUserIdentityWrapper *)userIdentity +{ + self = [self init]; + if (self) + { + _userId = userIdentity.userId; + NSMutableDictionary *keys = [NSMutableDictionary dictionary]; + if (userIdentity.masterKeys) + { + keys[MXCrossSigningKeyType.master] = userIdentity.masterKeys; + } + if (userIdentity.selfSignedKeys) + { + keys[MXCrossSigningKeyType.selfSigning] = userIdentity.selfSignedKeys; + } + if (userIdentity.userSignedKeys) + { + keys[MXCrossSigningKeyType.userSigning] = userIdentity.userSignedKeys; + } + _keys = keys.copy; + _trustLevel = userIdentity.trustLevel; + } + return self; +} +#endif + - (MXCrossSigningKey *)masterKeys { return _keys[MXCrossSigningKeyType.master]; diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift b/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift new file mode 100644 index 0000000000..9eca4f571d --- /dev/null +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCryptoUserIdentityWrapper.swift @@ -0,0 +1,65 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +/// Convenience wrapper around `MatrixSDKCrypto`'s `UserIdentity` +/// which can be used to create `MatrixSDK`s `MXCrossSigningInfo` +/// +/// Note: The class is marked as final with internal initializer, +/// meaning it cannot be created or subclassed from outside the SDK. +@objcMembers public final class MXCryptoUserIdentityWrapper: NSObject { + public let userId: String + public let masterKeys: MXCrossSigningKey? + public let selfSignedKeys: MXCrossSigningKey? + public let userSignedKeys: MXCrossSigningKey? + public let trustLevel: MXUserTrustLevel + + internal init(identity: UserIdentity, isVerified: Bool) { + switch identity { + case .own(let userId, _, let masterKey, let selfSigningKey, let userSigningKey): + self.userId = userId + // Note: `trustsOurOwnDevice` is not currently used, instead using second `isVerified` parameter + self.masterKeys = .init(jsonString: masterKey) + self.selfSignedKeys = .init(jsonString: selfSigningKey) + self.userSignedKeys = .init(jsonString: userSigningKey) + case .other(let userId, let masterKey, let selfSigningKey): + self.userId = userId + self.masterKeys = .init(jsonString: masterKey) + self.selfSignedKeys = .init(jsonString: selfSigningKey) + self.userSignedKeys = nil + } + trustLevel = MXUserTrustLevel( + crossSigningVerified: isVerified, + locallyVerified: false // Note: Local verification not yet implemented + ) + } +} + +private extension MXCrossSigningKey { + convenience init?(jsonString: String) { + guard let json = MXTools.deserialiseJSONString(jsonString) as? [AnyHashable: Any] else { + return nil + } + self.init(fromJSON: json) + } +} + +#endif diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningInfoSource.swift b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningInfoSource.swift new file mode 100644 index 0000000000..e50e94e64f --- /dev/null +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningInfoSource.swift @@ -0,0 +1,53 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +/// Convenience struct which transforms `MatrixSDKCrypto` cross signing info formats +/// into `MatrixSDK` `MXCrossSigningInfo` formats. +@available(iOS 13.0.0, *) +struct MXCrossSigningInfoSource { + private let source: MXCryptoUserIdentitySource + + init(source: MXCryptoUserIdentitySource) { + self.source = source + } + + func crossSigningInfo(userId: String) -> MXCrossSigningInfo? { + guard let identity = source.userIdentity(userId: userId) else { + return nil + } + let isVerified = source.isUserVerified(userId: userId) + return .init( + userIdentity: .init( + identity: identity, + isVerified: isVerified + ) + ) + } + + func crossSigningInfo(userIds: [String]) -> [String: MXCrossSigningInfo] { + return userIds + .compactMap(crossSigningInfo(userId:)) + .reduce(into: [String: MXCrossSigningInfo] ()) { dict, info in + return dict[info.userId] = info + } + } +} + +#endif diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift new file mode 100644 index 0000000000..49a92f1451 --- /dev/null +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift @@ -0,0 +1,168 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +/// A work-in-progress subclass of `MXCrossSigning` instantiated and used by `MXCryptoV2`. +/// +/// Note: `MXCrossSigning` will be defined as a protocol in the future to avoid subclasses. +@available(iOS 13.0.0, *) +class MXCrossSigningV2: MXCrossSigning { + enum Error: Swift.Error { + case missingAuthSession + } + + override var crypto: MXCrypto? { + assertionFailure("Crypto module should not be accessed directly") + return nil + } + + override var state: MXCrossSigningState { + log.debug("Only partial implementation") + return hasAllPrivateKeys ? .canCrossSign : .notBootstrapped + } + + override var canTrustCrossSigning: Bool { + return state.rawValue >= MXCrossSigningState.trustCrossSigning.rawValue + } + + override var canCrossSign: Bool { + return state.rawValue >= MXCrossSigningState.canCrossSign.rawValue + } + + override var hasAllPrivateKeys: Bool { + let status = machine.crossSigningStatus() + return status.hasMaster && status.hasSelfSigning && status.hasUserSigning + } + + private let machine: MXCryptoMachine + private let restClient: MXRestClient + private let log = MXNamedLog(name: "MXCrossSigningV2") + + init(machine: MXCryptoMachine, restClient: MXRestClient) { + self.machine = machine + self.restClient = restClient + } + + override func setup( + withPassword password: String, + success: @escaping () -> Void, + failure: @escaping (Swift.Error) -> Void + ) { + Task { + do { + let authParams = try await authParameters(password: password) + try await machine.bootstrapCrossSigning(authParams: authParams) + await MainActor.run { + success() + } + } catch { + log.error("Cannot setup cross signing", error: error) + await MainActor.run { + failure(error) + } + } + } + } + + override func setup( + withAuthParams authParams: [AnyHashable: Any], + success: @escaping () -> Void, + failure: @escaping (Swift.Error) -> Void + ) { + Task { + do { + try await machine.bootstrapCrossSigning(authParams: authParams) + await MainActor.run { + success() + } + } catch { + log.error("Cannot setup cross signing", error: error) + await MainActor.run { + failure(error) + } + } + } + } + + override func refreshState( + success: ((Bool) -> Void)?, + failure: ((Swift.Error) -> Void)? = nil + ) { + log.debug("Not implemented") + success?(true) + } + + override func crossSignDevice( + withDeviceId deviceId: String, + success: @escaping () -> Void, + failure: @escaping (Swift.Error) -> Void + ) { + log.debug("Not implemented") + success() + } + + override func signUser( + withUserId userId: String, + success: @escaping () -> Void, + failure: @escaping (Swift.Error) -> Void + ) { + log.debug("Not implemented") + success() + } + + override func requestPrivateKeys( + toDeviceIds deviceIds: [String]?, + success: @escaping () -> Void, + onPrivateKeysReceived: @escaping () -> Void, + failure: @escaping (Swift.Error) -> Void + ) { + log.debug("Not implemented") + success() + } + + // MARK: - Private + + private func authParameters(password: String) async throws -> [AnyHashable: Any] { + let authSession: MXAuthenticationSession? = try await performCallbackRequest { completion in + restClient.authSession { + completion(.success($0)) + } failure: { + completion(.failure($0 ?? Error.missingAuthSession)) + } + } + + guard + let authSession = authSession, + let session = authSession.session, + let userId = restClient.credentials?.userId + else { + log.error("Missing parameters") + throw Error.missingAuthSession + } + + return [ + "session": session, + "user": userId, + "password": password, + "type": kMXLoginFlowTypePassword + ] + } +} + +#endif diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index 3a391c7047..c4fe369be1 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -20,6 +20,8 @@ import Foundation import MatrixSDKCrypto +typealias GetRoomAction = (String) -> MXRoom? + /// Wrapper around Rust-based `OlmMachine`, providing a more convenient API. /// /// Two main responsibilities of the `MXCryptoMachine` are: @@ -43,16 +45,20 @@ class MXCryptoMachine { case invalidStorage case invalidEvent case nothingToEncrypt + case missingRoom } private let machine: OlmMachine private let requests: MXCryptoRequests - private let serialQueue = MXTaskQueue() + private let getRoomAction: GetRoomAction + + private let sessionsQueue = MXTaskQueue() + private let syncQueue = MXTaskQueue() private var roomQueues = RoomQueues() - - init(userId: String, deviceId: String, restClient: MXRestClient) throws { - requests = MXCryptoRequests(restClient: restClient) + private let log = MXNamedLog(name: "MXCryptoMachine") + + init(userId: String, deviceId: String, restClient: MXRestClient, getRoomAction: @escaping GetRoomAction) throws { let url = try Self.storeURL(for: userId) machine = try OlmMachine( userId: userId, @@ -60,6 +66,8 @@ class MXCryptoMachine { path: url.path, passphrase: nil ) + requests = MXCryptoRequests(restClient: restClient) + self.getRoomAction = getRoomAction setLogger(logger: self) } @@ -78,6 +86,11 @@ class MXCryptoMachine { .appendingPathComponent(Self.storeFolder) .appendingPathComponent(userId) } + + func deleteAllData() throws { + let url = try Self.storeURL(for: machine.userId()) + try FileManager.default.removeItem(at: url) + } } @available(iOS 13.0.0, *) @@ -108,7 +121,7 @@ extension MXCryptoMachine: MXCryptoSyncing { } func completeSync() async throws { - try await serialQueue.sync { [weak self] in + try await syncQueue.sync { [weak self] in try await self?.processOutgoingRequests() } } @@ -118,55 +131,88 @@ extension MXCryptoMachine: MXCryptoSyncing { private func handleRequest(_ request: Request) async throws { switch request { case .toDevice(let requestId, let eventType, let body): - try await requests.sendToDevice(request: .init(eventType: eventType, body: body)) + try await requests.sendToDevice( + request: .init(eventType: eventType, body: body) + ) try markRequestAsSent(requestId: requestId, requestType: .toDevice) case .keysUpload(let requestId, let body): - let response = try await requests.uploadKeys(request: .init(body: body, deviceId: machine.deviceId())) - try markRequestAsSent(requestId: requestId, requestType: .keysUpload, response: response) + let response = try await requests.uploadKeys( + request: .init(body: body, deviceId: machine.deviceId()) + ) + try markRequestAsSent(requestId: requestId, requestType: .keysUpload, response: response.jsonString()) case .keysQuery(let requestId, let users): let response = try await requests.queryKeys(users: users) - try markRequestAsSent(requestId: requestId, requestType: .keysQuery, response: response) + try markRequestAsSent(requestId: requestId, requestType: .keysQuery, response: response.jsonString()) case .keysClaim(let requestId, let oneTimeKeys): - let response = try await requests.claimKeys(request: .init(oneTimeKeys: oneTimeKeys)) - try markRequestAsSent(requestId: requestId, requestType: .keysClaim, response: response) + let response = try await requests.claimKeys( + request: .init(oneTimeKeys: oneTimeKeys) + ) + try markRequestAsSent(requestId: requestId, requestType: .keysClaim, response: response.jsonString()) case .keysBackup: - log(error: "Keys backup not implemented") + assertionFailure("Keys backup not implemented") - case .roomMessage: - log(error: "Room message not implemented") + case .roomMessage(let requestId, let roomId, let eventType, let content): + guard let eventID = try await sendRoomMessage(roomId: roomId, eventType: eventType, content: content) else { + throw Error.invalidEvent + } + let event = [ + "event_id": eventID + ] + try markRequestAsSent(requestId: requestId, requestType: .roomMessage, response: MXTools.serialiseJSONObject(event)) - case .signatureUpload: - log(error: "Signature upload not implemented") + case .signatureUpload(let requestId, let body): + try await requests.uploadSignatures( + request: .init(body: body) + ) + let event = [ + "failures": [:] + ] + try markRequestAsSent(requestId: requestId, requestType: .signatureUpload, response: MXTools.serialiseJSONObject(event)) } } - private func markRequestAsSent(requestId: String, requestType: RequestType, response: MXJSONModel? = nil) throws { - try self.machine.markRequestAsSent(requestId: requestId, requestType: requestType, response: response?.jsonString() ?? "") + private func markRequestAsSent(requestId: String, requestType: RequestType, response: String? = nil) throws { + try self.machine.markRequestAsSent(requestId: requestId, requestType: requestType, response: response ?? "") } private func processOutgoingRequests() async throws { let requests = try machine.outgoingRequests() - await withThrowingTaskGroup(of: Void.self) { [weak self] group in + + try await withThrowingTaskGroup(of: Void.self) { [weak self] group in guard let self = self else { return } - for request in requests { group.addTask { try await self.handleRequest(request) } } + + try await group.waitForAll() } } + + private func sendRoomMessage(roomId: String, eventType: String, content: String) async throws -> String? { + guard let room = getRoomAction(roomId) else { + throw Error.missingRoom + } + return try await requests.roomMessage( + request: .init( + room: room, + eventType: eventType, + content: content + ) + ) + } } @available(iOS 13.0.0, *) extension MXCryptoMachine: MXCryptoDevicesSource { var deviceCurve25519Key: String? { guard let key = machine.identityKeys()["curve25519"] else { - log(error: "Cannot get device curve25519 key") + log.error("Cannot get device curve25519 key") return nil } return key @@ -174,17 +220,56 @@ extension MXCryptoMachine: MXCryptoDevicesSource { var deviceEd25519Key: String? { guard let key = machine.identityKeys()["ed25519"] else { - log(error: "Cannot get device ed25519 key") + log.error("Cannot get device ed25519 key") return nil } return key } + + func devices(userId: String) -> [Device] { + do { + return try machine.getUserDevices(userId: userId, timeout: 0) + } catch { + log.error("Cannot fetch devices", error: error) + return [] + } + } + + func device(userId: String, deviceId: String) -> Device? { + do { + return try machine.getDevice(userId: userId, deviceId: deviceId, timeout: 0) + } catch { + log.error("Cannot fetch device", error: error) + return nil + } + } +} + +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoUserIdentitySource { + func isUserVerified(userId: String) -> Bool { + do { + return try machine.isIdentityVerified(userId: userId) + } catch { + log.error("Failed checking user verification status", error: error) + return false + } + } + + func userIdentity(userId: String) -> UserIdentity? { + do { + return try machine.getIdentity(userId: userId, timeout: 0) + } catch { + log.error("Failed fetching user identity") + return nil + } + } } @available(iOS 13.0.0, *) extension MXCryptoMachine: MXCryptoEventEncrypting { func shareRoomKeysIfNecessary(roomId: String, users: [String]) async throws { - try await serialQueue.sync { [weak self] in + try await sessionsQueue.sync { [weak self] in try await self?.updateTrackedUsers(users: users) try await self?.getMissingSessions(users: users) } @@ -218,7 +303,21 @@ extension MXCryptoMachine: MXCryptoEventEncrypting { private func updateTrackedUsers(users: [String]) async throws { machine.updateTrackedUsers(users: users) - try await processOutgoingRequests() + try await withThrowingTaskGroup(of: Void.self) { [weak self] group in + guard let self = self else { return } + + for request in try machine.outgoingRequests() { + guard case .keysQuery = request else { + continue + } + + group.addTask { + try await self.handleRequest(request) + } + } + + try await group.waitForAll() + } } private func getMissingSessions(users: [String]) async throws { @@ -233,7 +332,7 @@ extension MXCryptoMachine: MXCryptoEventEncrypting { private func shareRoomKey(roomId: String, users: [String]) async throws { let requests = try machine.shareRoomKey(roomId: roomId, users: users) - await withThrowingTaskGroup(of: Void.self) { [weak self] group in + try await withThrowingTaskGroup(of: Void.self) { [weak self] group in guard let self = self else { return } for request in requests { @@ -245,10 +344,27 @@ extension MXCryptoMachine: MXCryptoEventEncrypting { try await self.handleRequest(request) } } + + try await group.waitForAll() } } } +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoCrossSigning { + func crossSigningStatus() -> CrossSigningStatus { + return machine.crossSigningStatus() + } + + func bootstrapCrossSigning(authParams: [AnyHashable: Any]) async throws { + let result = try machine.bootstrapCrossSigning() + let _ = try await [ + requests.uploadSigningKeys(request: result.uploadSigningKeysRequest, authParams: authParams), + requests.uploadSignatures(request: result.signatureRequest) + ] + } +} + @available(iOS 13.0.0, *) extension MXCryptoMachine: Logger { func log(logLine: String) { diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift index 5eedaa92a6..fef27a17b7 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift @@ -37,6 +37,13 @@ protocol MXCryptoSyncing { protocol MXCryptoDevicesSource { var deviceCurve25519Key: String? { get } var deviceEd25519Key: String? { get } + func device(userId: String, deviceId: String) -> Device? + func devices(userId: String) -> [Device] +} + +protocol MXCryptoUserIdentitySource { + func userIdentity(userId: String) -> UserIdentity? + func isUserVerified(userId: String) -> Bool } @available(iOS 13.0.0, *) @@ -46,4 +53,10 @@ protocol MXCryptoEventEncrypting { func decryptEvent(_ event: MXEvent) throws -> MXEventDecryptionResult } +@available(iOS 13.0.0, *) +protocol MXCryptoCrossSigning { + func crossSigningStatus() -> CrossSigningStatus + func bootstrapCrossSigning(authParams: [AnyHashable: Any]) async throws +} + #endif diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift index 3b5a3cb97f..fe44647e1d 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift @@ -16,11 +16,13 @@ import Foundation -#if DEBUG +#if DEBUG && os(iOS) + +import MatrixSDKCrypto /// Convenience class to delegate network requests originating in Rust crypto module /// to the native REST API client -@available(iOS 13.0.0, macOS 10.15.0, *) +@available(iOS 13.0.0, *) struct MXCryptoRequests { private let restClient: MXRestClient init(restClient: MXRestClient) { @@ -50,6 +52,37 @@ struct MXCryptoRequests { } } + func uploadSigningKeys(request: UploadSigningKeysRequest, authParams: [AnyHashable: Any]) async throws { + let keys = try request.jsonKeys() + return try await performCallbackRequest { continuation in + restClient.uploadDeviceSigningKeys( + keys, + authParams: authParams, + success: { + continuation(.success(())) + }, + failure: { + continuation(.failure($0 ?? Error.unknownError)) + } + ) + } + } + + func uploadSignatures(request: SignatureUploadRequest) async throws { + let signatures = try request.jsonSignature() + return try await performCallbackRequest { continuation in + restClient.uploadKeySignatures( + signatures, + success: { + continuation(.success(())) + }, + failure: { + continuation(.failure($0 ?? Error.unknownError)) + } + ) + } + } + func queryKeys(users: [String]) async throws -> MXKeysQueryResponse { return try await performCallbackRequest { restClient.downloadKeys(forUsers: users, completion: $0) @@ -61,13 +94,26 @@ struct MXCryptoRequests { restClient.claimOneTimeKeys(for: request.devices, completion: $0) } } + + func roomMessage(request: RoomMessageRequest) async throws -> String? { + var event: MXEvent? + return try await performCallbackRequest { + request.room.sendEvent( + MXEventType(identifier: request.eventType), + content: request.content, + localEcho: &event, + completion: $0 + ) + } + } } /// Convenience structs mapping Rust requests to data for native REST API requests -@available(iOS 13.0.0, macOS 10.15.0, *) +@available(iOS 13.0.0, *) extension MXCryptoRequests { enum Error: Swift.Error { case cannotCreateRequest + case unknownError } struct ToDeviceRequest { @@ -115,6 +161,50 @@ extension MXCryptoRequests { self.devices = devices } } + + struct RoomMessageRequest { + let room: MXRoom + let eventType: String + let content: [String: Any] + + init(room: MXRoom, eventType: String, content: String) throws { + guard let json = MXTools.deserialiseJSONString(content) as? [String: Any] else { + throw Error.cannotCreateRequest + } + self.room = room + self.eventType = eventType + self.content = json + } + } +} + +@available(iOS 13.0.0, *) +extension UploadSigningKeysRequest { + func jsonKeys() throws -> [AnyHashable: Any] { + guard + let masterKeyJson = MXTools.deserialiseJSONString(masterKey), + let selfKeyJson = MXTools.deserialiseJSONString(selfSigningKey), + let userKeyJson = MXTools.deserialiseJSONString(userSigningKey) + else { + throw MXCryptoRequests.Error.cannotCreateRequest + } + + return [ + "master_key": masterKeyJson, + "self_signing_key": selfKeyJson, + "user_signing_key": userKeyJson + ] + } +} + +@available(iOS 13.0.0, *) +extension SignatureUploadRequest { + func jsonSignature() throws -> [AnyHashable: Any] { + guard let signatures = MXTools.deserialiseJSONString(body) as? [AnyHashable: Any] else { + throw MXCryptoRequests.Error.cannotCreateRequest + } + return signatures + } } #endif diff --git a/MatrixSDK/Crypto/Devices/Data/MXCryptoDeviceWrapper.swift b/MatrixSDK/Crypto/Devices/Data/MXCryptoDeviceWrapper.swift new file mode 100644 index 0000000000..e413f865b3 --- /dev/null +++ b/MatrixSDK/Crypto/Devices/Data/MXCryptoDeviceWrapper.swift @@ -0,0 +1,52 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +/// Convenience wrapper around `MatrixSDKCrypto`'s `Device` +/// which can be used to create `MatrixSDK`s `MXDeviceInfo` +/// +/// Note: The class is marked as final with internal initializer, +/// meaning it cannot be created or subclassed from outside the SDK. +@objcMembers public final class MXCryptoDeviceWrapper: NSObject { + public let userId: String + public let deviceId: String + public let algorithms: [String] + public let keys: [String: String] + public let unsignedData: [String: Any] + public let trustLevel: MXDeviceTrustLevel + + internal init(device: Device) { + userId = device.userId + deviceId = device.deviceId + algorithms = device.algorithms + keys = device.keys + unsignedData = [ + "device_display_name": device.displayName as Any + ] + trustLevel = MXDeviceTrustLevel( + // Note: currently not distinguishing between unknown and unverified + localVerificationStatus: device.locallyTrusted ? .verified : .unknown, + crossSigningVerified: device.crossSigningTrusted + ) + } +} + +#endif diff --git a/MatrixSDK/Crypto/Data/MXDeviceInfo.h b/MatrixSDK/Crypto/Devices/Data/MXDeviceInfo.h similarity index 90% rename from MatrixSDK/Crypto/Data/MXDeviceInfo.h rename to MatrixSDK/Crypto/Devices/Data/MXDeviceInfo.h index f72166895b..4d9816c9cb 100644 --- a/MatrixSDK/Crypto/Data/MXDeviceInfo.h +++ b/MatrixSDK/Crypto/Devices/Data/MXDeviceInfo.h @@ -20,6 +20,8 @@ #import "MXJSONModel.h" #import "MXDeviceTrustLevel.h" +@class MXCryptoDeviceWrapper; + /** Notification sent when the device trust level has been updated. */ @@ -30,7 +32,14 @@ extern NSString *const MXDeviceInfoTrustLevelDidChangeNotification; */ @interface MXDeviceInfo : MXJSONModel -- (instancetype)initWithDeviceId:(NSString*)deviceId; +- (instancetype)initWithDeviceId:(NSString *)deviceId; + +#if DEBUG && TARGET_OS_IPHONE +/** + Initialize device info with MatrixSDKCrypto device + */ +- (instancetype)initWithDevice:(MXCryptoDeviceWrapper *)device; +#endif /** The id of this device. diff --git a/MatrixSDK/Crypto/Data/MXDeviceInfo.m b/MatrixSDK/Crypto/Devices/Data/MXDeviceInfo.m similarity index 93% rename from MatrixSDK/Crypto/Data/MXDeviceInfo.m rename to MatrixSDK/Crypto/Devices/Data/MXDeviceInfo.m index 8fbd5d7d00..ca95042d6c 100644 --- a/MatrixSDK/Crypto/Data/MXDeviceInfo.m +++ b/MatrixSDK/Crypto/Devices/Data/MXDeviceInfo.m @@ -16,6 +16,7 @@ */ #import "MXDeviceInfo_Private.h" +#import "MatrixSDKSwiftHeader.h" #pragma mark - Constants @@ -34,6 +35,23 @@ - (instancetype)initWithDeviceId:(NSString *)deviceId return self; } +#if DEBUG && TARGET_OS_IPHONE +- (instancetype)initWithDevice:(MXCryptoDeviceWrapper *)device +{ + self = [super init]; + if (self) + { + _userId = device.userId; + _deviceId = device.deviceId; + _algorithms = device.algorithms; + _keys = device.keys; + _unsignedData = device.unsignedData; + _trustLevel = device.trustLevel; + } + return self; +} +#endif + - (NSString *)fingerprint { return _keys[[NSString stringWithFormat:@"ed25519:%@", _deviceId]]; diff --git a/MatrixSDK/Crypto/Data/MXDeviceInfo_Private.h b/MatrixSDK/Crypto/Devices/Data/MXDeviceInfo_Private.h similarity index 100% rename from MatrixSDK/Crypto/Data/MXDeviceInfo_Private.h rename to MatrixSDK/Crypto/Devices/Data/MXDeviceInfo_Private.h diff --git a/MatrixSDK/Crypto/Devices/MXDeviceInfoSource.swift b/MatrixSDK/Crypto/Devices/MXDeviceInfoSource.swift new file mode 100644 index 0000000000..7f94a6befd --- /dev/null +++ b/MatrixSDK/Crypto/Devices/MXDeviceInfoSource.swift @@ -0,0 +1,55 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +/// Convenience struct which transforms `MatrixSDKCrypto` device formats +/// into `MatrixSDK` `MXDeviceInfo` formats. +@available(iOS 13.0.0, *) +struct MXDeviceInfoSource { + private let source: MXCryptoDevicesSource + + init(source: MXCryptoDevicesSource) { + self.source = source + } + + func deviceInfo(userId: String, deviceId: String) -> MXDeviceInfo? { + guard let device = source.device(userId: userId, deviceId: deviceId) else { + return nil + } + return .init(device: .init(device: device)) + } + + func devicesInfo(userId: String) -> [String: MXDeviceInfo] { + return source + .devices(userId: userId) + .reduce(into: [String: MXDeviceInfo]()) { dict, device in + dict[device.deviceId] = .init(device: .init(device: device)) + } + } + + func devicesMap(userIds: [String]) -> MXUsersDevicesMap { + let map = MXUsersDevicesMap() + for userId in userIds { + map.setObjects(devicesInfo(userId: userId), forUser: userId) + } + return map + } +} + +#endif diff --git a/MatrixSDK/Crypto/Data/MXDeviceList.h b/MatrixSDK/Crypto/Devices/MXDeviceList.h similarity index 100% rename from MatrixSDK/Crypto/Data/MXDeviceList.h rename to MatrixSDK/Crypto/Devices/MXDeviceList.h diff --git a/MatrixSDK/Crypto/Data/MXDeviceList.m b/MatrixSDK/Crypto/Devices/MXDeviceList.m similarity index 100% rename from MatrixSDK/Crypto/Data/MXDeviceList.m rename to MatrixSDK/Crypto/Devices/MXDeviceList.m diff --git a/MatrixSDK/Crypto/MXCryptoV2.swift b/MatrixSDK/Crypto/MXCryptoV2.swift index 6c176455da..b0a1b4985e 100644 --- a/MatrixSDK/Crypto/MXCryptoV2.swift +++ b/MatrixSDK/Crypto/MXCryptoV2.swift @@ -25,6 +25,8 @@ public extension MXCrypto { /// - running on iOS /// - enabling `enableCryptoV2` feature flag @objc static func createCryptoV2IfAvailable(session: MXSession!) -> MXCrypto? { + let log = MXNamedLog(name: "MXCryptoV2") + #if os(iOS) guard #available(iOS 13.0.0, *) else { return nil @@ -39,14 +41,14 @@ public extension MXCrypto { let userId = restClient.credentials?.userId, let deviceId = restClient.credentials?.deviceId else { - MXLog.error("[MXCryptoV2] Cannot create Crypto V2, missing properties") + log.failure("Cannot create crypto V2, missing properties") return nil } do { return try MXCryptoV2(userId: userId, deviceId: deviceId, session: session, restClient: restClient) } catch { - MXLog.error("[MXCryptoV2] Error creating cryptoV2 \(error)") + log.failure("Error creating crypto V2", error: error) return nil } #else @@ -81,51 +83,72 @@ private class MXCryptoV2: MXCrypto { } public override var olmVersion: String! { - warnNotImplemented() + log.debug("Not implemented") return nil } public override var backup: MXKeyBackup! { - warnNotImplemented() + log.debug("Not implemented") return nil } public override var keyVerificationManager: MXKeyVerificationManager! { - warnNotImplemented() - return nil + log.debug("Not implemented") + return MXKeyVerificationManager() } public override var recoveryService: MXRecoveryService! { - warnNotImplemented() - return nil + log.debug("Not implemented") + return MXRecoveryService() } public override var secretStorage: MXSecretStorage! { - warnNotImplemented() - return nil + log.debug("Not implemented") + return MXSecretStorage() } public override var secretShareManager: MXSecretShareManager! { - warnNotImplemented() - return nil + log.debug("Not implemented") + return MXSecretShareManager() } public override var crossSigning: MXCrossSigning! { - warnNotImplemented() - return nil + return crossSign } - private let userId: String private weak var session: MXSession? + private let machine: MXCryptoMachine + private let deviceInfoSource: MXDeviceInfoSource + private let crossSigningInfoSource: MXCrossSigningInfoSource + private let trustLevelSource: MXTrustLevelSource + + private let crossSign: MXCrossSigningV2 + + private let log = MXNamedLog(name: "MXCryptoV2") public init(userId: String, deviceId: String, session: MXSession, restClient: MXRestClient) throws { self.userId = userId self.session = session + machine = try MXCryptoMachine( userId: userId, deviceId: deviceId, + restClient: restClient, + getRoomAction: { [weak session] roomId in + session?.room(withRoomId: roomId) + } + ) + deviceInfoSource = MXDeviceInfoSource(source: machine) + crossSigningInfoSource = MXCrossSigningInfoSource(source: machine) + trustLevelSource = MXTrustLevelSource( + userIdentitySource: machine, + devicesSource: machine + ) + + crossSign = MXCrossSigningV2( + machine: machine, restClient: restClient ) @@ -135,27 +158,31 @@ private class MXCryptoV2: MXCrypto { // MARK: - Factories public override class func createCrypto(withMatrixSession mxSession: MXSession!) -> MXCrypto! { - warnNotImplemented() + MXNamedLog(name: "MXCryptoV2").debug("Not implemented") return nil } + // MARK: - Class methods + public override class func check(withMatrixSession mxSession: MXSession!, complete: ((MXCrypto?) -> Void)!) { - warnNotImplemented() + MXNamedLog(name: "MXCryptoV2").debug("Not implemented") } public override class func rehydrateExportedOlmDevice(_ exportedOlmDevice: MXExportedOlmDevice!, with credentials: MXCredentials!, complete: ((Bool) -> Void)!) { - warnNotImplemented() + MXNamedLog(name: "MXCryptoV2").debug("Not implemented") } // MARK: - Start / close public override func start(_ onComplete: (() -> Void)!, failure: ((Error?) -> Void)!) { onComplete?() - warnNotImplemented() + log.debug("Not implemented") } public override func close(_ deleteStore: Bool) { - warnNotImplemented() + if deleteStore { + self.deleteStore(nil) + } } // MARK: - Encrypt / Decrypt @@ -167,17 +194,17 @@ private class MXCryptoV2: MXCrypto { success: (([AnyHashable : Any]?, String?) -> Void)!, failure: ((Error?) -> Void)! ) -> MXHTTPOperation! { - guard let content = eventContent, let eventType = eventType, let roomId = room.roomId else { - MXLog.debug("[MXCryptoV2] encryptEventContent: Missing data to encrypt") + guard let content = eventContent, let eventType = eventType, let roomId = room?.roomId else { + log.failure("Missing data to encrypt") return nil } guard isRoomEncrypted(roomId) else { - MXLog.error("[MXCryptoV2] encryptEventContent: attempting to encrypt event in room without encryption") + log.failure("Attempting to encrypt event in room without encryption") return nil } - MXLog.debug("[MXCryptoV2] encryptEventContent: Encrypting content") + log.debug("Encrypting content of type `\(eventType)`") Task { do { @@ -193,7 +220,7 @@ private class MXCryptoV2: MXCrypto { success?(result, kMXEventTypeStringRoomEncrypted) } } catch { - MXLog.error("[MXCryptoV2] encryptEventContent: Error encrypting content - \(error)") + log.error("Error encrypting content", error: error) await MainActor.run { failure?(error) } @@ -202,35 +229,46 @@ private class MXCryptoV2: MXCrypto { return MXHTTPOperation() } - public override func hasKeys(toDecryptEvent event: MXEvent!, onComplete: ((Bool) -> Void)!) { - warnNotImplemented() - } - - public override func decryptEvent(_ event: MXEvent!, inTimeline timeline: String!) -> MXEventDecryptionResult! { + public override func decryptEvent( + _ event: MXEvent!, + inTimeline timeline: String! + ) -> MXEventDecryptionResult! { guard let event = event else { - MXLog.debug("[MXCryptoV2] Missing event") + log.failure("Missing event") return nil } do { - return try machine.decryptEvent(event) + let result = try machine.decryptEvent(event) + let type = result.clearEvent["type"] ?? "" + log.debug("Decrypted event of type `\(type)`") + + return result } catch { - MXLog.error("[MXCryptoV2] decryptEvent: \(error)") + log.error("Error decrypting event", error: error) let result = MXEventDecryptionResult() result.error = error return result } } - public override func decryptEvents(_ events: [MXEvent]!, inTimeline timeline: String!, onComplete: (([MXEventDecryptionResult]?) -> Void)!) { + public override func decryptEvents( + _ events: [MXEvent]!, + inTimeline timeline: String!, + onComplete: (([MXEventDecryptionResult]?) -> Void)! + ) { let results = events?.compactMap { decryptEvent($0, inTimeline: timeline) } onComplete?(results) } - public override func ensureEncryption(inRoom roomId: String!, success: (() -> Void)!, failure: ((Error?) -> Void)!) -> MXHTTPOperation! { + public override func ensureEncryption( + inRoom roomId: String!, + success: (() -> Void)!, + failure: ((Error?) -> Void)! + ) -> MXHTTPOperation! { guard let roomId = roomId, let room = session?.room(withRoomId: roomId) else { - MXLog.debug("[MXCryptoV2] ensureEncryption: Missing room") + log.failure("Missing room") return nil } @@ -242,7 +280,7 @@ private class MXCryptoV2: MXCrypto { success?() } } catch { - MXLog.error("[MXCryptoV2] encryptEventContent: Error ensuring encryption - \(error)") + log.error("Error ensuring encryption", error: error) await MainActor.run { failure?(error) } @@ -253,12 +291,17 @@ private class MXCryptoV2: MXCrypto { } public override func discardOutboundGroupSessionForRoom(withRoomId roomId: String!, onComplete: (() -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } // MARK: - Sync public override func handle(_ syncResponse: MXSyncResponse!) { + guard let syncResponse = syncResponse else { + log.failure("Missing sync response") + return + } + do { try machine.handleSyncResponse( toDevice: syncResponse.toDevice, @@ -267,28 +310,24 @@ private class MXCryptoV2: MXCrypto { unusedFallbackKeys: syncResponse.unusedFallbackKeys ) } catch { - MXLog.error("[MXCryptoV2] handleSyncResponse: \(error)") + log.error("Cannot handle sync", error: error) } } public override func handleDeviceListsChanges(_ deviceLists: MXDeviceListResponse!) { - // Not implemented, will be handled by Rust - warnNotImplemented(ignore: true) + // Not implemented, handled automatically by CryptoMachine } public override func handleDeviceOneTimeKeysCount(_ deviceOneTimeKeysCount: [String : NSNumber]!) { - // Not implemented, will be handled by Rust - warnNotImplemented(ignore: true) + // Not implemented, handled automatically by CryptoMachine } public override func handleDeviceUnusedFallbackKeys(_ deviceUnusedFallbackKeys: [String]!) { - // Not implemented, will be handled by Rust - warnNotImplemented(ignore: true) + // Not implemented, handled automatically by CryptoMachine } public override func handleRoomKeyEvent(_ event: MXEvent!, onComplete: (() -> Void)!) { - // Not implemented, will be handled by Rust - warnNotImplemented(ignore: true) + // Not implemented, handled automatically by CryptoMachine } public override func onSyncCompleted(_ oldSyncToken: String!, nextSyncToken: String!, catchingUp: Bool) { @@ -296,184 +335,242 @@ private class MXCryptoV2: MXCrypto { do { try await machine.completeSync() } catch { - MXLog.error("[MXCryptoV2] onSyncCompleted: error processing outgoing requests \(error)") + log.failure("Error processing outgoing requests", error: error) } } } - // MARK: - Devices + // MARK: - Trust level - public override func eventDeviceInfo(_ event: MXEvent!) -> MXDeviceInfo! { - warnNotImplemented() - return nil + public override func trustLevel(forUser userId: String!) -> MXUserTrustLevel! { + guard let userId = userId else { + log.failure("Missing user id") + return nil + } + return trustLevelSource.userTrustLevel(userId: userId) } - public override func setDeviceVerification(_ verificationStatus: MXDeviceVerification, forDevice deviceId: String!, ofUser userId: String!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + public override func deviceTrustLevel(forDevice deviceId: String!, ofUser userId: String!) -> MXDeviceTrustLevel! { + guard let userId = userId, let deviceId = deviceId else { + log.failure("Missing user id or device id") + return nil + } + return trustLevelSource.deviceTrustLevel(userId: userId, deviceId: deviceId) } - public override func setDevicesKnown(_ devices: MXUsersDevicesMap!, complete: (() -> Void)!) { - warnNotImplemented() + public override func trustLevelSummary( + forUserIds userIds: [String]!, + success: ((MXUsersTrustLevelSummary?) -> Void)!, + failure: ((Error?) -> Void)! + ) { + guard let userIds = userIds else { + log.failure("Missing user ids") + failure?(nil) + return + } + + success?( + trustLevelSource.trustLevelSummary(userIds: userIds) + ) } - // MARK: - Other + public override func trustLevelSummary( + forUserIds userIds: [String]!, + onComplete: ((MXUsersTrustLevelSummary?) -> Void)! + ) { + trustLevelSummary( + forUserIds: userIds, + success: onComplete, + failure: { _ in + onComplete?(nil) + }) + } - public override func setUserVerification(_ verificationStatus: Bool, forUser userId: String!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + // MARK: - Users, devices and verification + + public override func eventDeviceInfo(_ event: MXEvent!) -> MXDeviceInfo! { + guard + let userId = event?.sender, + let deviceId = event?.wireContent["device_id"] as? String + else { + log.failure("Missing user id or device id") + return nil; + } + return device(withDeviceId: deviceId, ofUser: userId) } - public override func trustLevel(forUser userId: String!) -> MXUserTrustLevel! { - warnNotImplemented() - return nil + public override func setDeviceVerification(_ verificationStatus: MXDeviceVerification, forDevice deviceId: String!, ofUser userId: String!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { + log.debug("Not implemented") } - public override func deviceTrustLevel(forDevice deviceId: String!, ofUser userId: String!) -> MXDeviceTrustLevel! { - warnNotImplemented() - return nil + public override func setDevicesKnown(_ devices: MXUsersDevicesMap!, complete: (() -> Void)!) { + log.debug("Not implemented") } - public override func trustLevelSummary(forUserIds userIds: [String]!, success: ((MXUsersTrustLevelSummary?) -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + public override func setUserVerification(_ verificationStatus: Bool, forUser userId: String!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { + log.debug("Not implemented") } - public override func trustLevelSummary(forUserIds userIds: [String]!, onComplete: ((MXUsersTrustLevelSummary?) -> Void)!) { - warnNotImplemented() + public override func hasKeys(toDecryptEvent event: MXEvent!, onComplete: ((Bool) -> Void)!) { + log.debug("Not implemented") } - public override func downloadKeys(_ userIds: [String]!, forceDownload: Bool, success: ((MXUsersDevicesMap?, [String : MXCrossSigningInfo]?) -> Void)!, failure: ((Error?) -> Void)!) -> MXHTTPOperation! { - warnNotImplemented() - return nil + public override func downloadKeys( + _ userIds: [String]!, + forceDownload: Bool, + success: ((MXUsersDevicesMap?, [String: MXCrossSigningInfo]?) -> Void)!, + failure: ((Error?) -> Void)! + ) -> MXHTTPOperation! { + // Note: Download keys currently ignores the `forceDownload` flag and returns local data only + success?( + deviceInfoSource.devicesMap(userIds: userIds), + crossSigningInfoSource.crossSigningInfo(userIds: userIds) + ) + return MXHTTPOperation() } public override func crossSigningKeys(forUser userId: String!) -> MXCrossSigningInfo! { - warnNotImplemented() - return nil + guard let userId = userId else { + log.failure("Missing user id") + return nil + } + return crossSigningInfoSource.crossSigningInfo(userId: userId) } public override func devices(forUser userId: String!) -> [String : MXDeviceInfo]! { - warnNotImplemented() - return nil + guard let userId = userId else { + log.failure("Missing user id") + return [:] + } + return deviceInfoSource.devicesInfo(userId: userId) } public override func device(withDeviceId deviceId: String!, ofUser userId: String!) -> MXDeviceInfo! { - warnNotImplemented() - return nil + guard let userId = userId, let deviceId = deviceId else { + log.failure("Missing user id or device id") + return nil + } + return deviceInfoSource.deviceInfo(userId: userId, deviceId: deviceId) } public override func resetReplayAttackCheck(inTimeline timeline: String!) { - warnNotImplemented() + log.debug("Not implemented") } public override func resetDeviceKeys() { - warnNotImplemented() + log.debug("Not implemented") } public override func deleteStore(_ onComplete: (() -> Void)!) { - warnNotImplemented() + do { + try machine.deleteAllData() + } catch { + log.failure("Cannot delete crypto store", error: error) + } + onComplete?() } public override func requestAllPrivateKeys() { - warnNotImplemented() + log.debug("Not implemented") } public override func exportRoomKeys(_ success: (([[AnyHashable : Any]]?) -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func exportRoomKeys(withPassword password: String!, success: ((Data?) -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func importRoomKeys(_ keys: [[AnyHashable : Any]]!, success: ((UInt, UInt) -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func importRoomKeys(_ keyFile: Data!, withPassword password: String!, success: ((UInt, UInt) -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func pendingKeyRequests(_ onComplete: ((MXUsersDevicesMap?) -> Void)!) { - // Not implemented, will be handled by Rust - warnNotImplemented(ignore: true) + // Not implemented, handled automatically by CryptoMachine } public override func accept(_ keyRequest: MXIncomingRoomKeyRequest!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func acceptAllPendingKeyRequests(fromUser userId: String!, andDevice deviceId: String!, onComplete: (() -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func ignore(_ keyRequest: MXIncomingRoomKeyRequest!, onComplete: (() -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func ignoreAllPendingKeyRequests(fromUser userId: String!, andDevice deviceId: String!, onComplete: (() -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func setOutgoingKeyRequestsEnabled(_ enabled: Bool, onComplete: (() -> Void)!) { - warnNotImplemented() + log.debug("Not implemented") } public override func isOutgoingKeyRequestsEnabled() -> Bool { - warnNotImplemented() + log.debug("Not implemented") return false } public override var enableOutgoingKeyRequestsOnceSelfVerificationDone: Bool { get { - warnNotImplemented() + log.debug("Not implemented") return false } set { - warnNotImplemented() + log.debug("Not implemented") } } public override func reRequestRoomKey(for event: MXEvent!) { - warnNotImplemented() + log.debug("Not implemented") } public override var warnOnUnknowDevices: Bool { get { - warnNotImplemented() + log.debug("Not implemented") return false } set { - warnNotImplemented() + log.debug("Not implemented") } } public override var globalBlacklistUnverifiedDevices: Bool { get { - warnNotImplemented() + log.debug("Not implemented") return false } set { - warnNotImplemented() + log.debug("Not implemented") } } public override func isBlacklistUnverifiedDevices(inRoom roomId: String!) -> Bool { - warnNotImplemented() + log.debug("Not implemented") return false } public override func isRoomEncrypted(_ roomId: String!) -> Bool { - warnNotImplemented() + log.debug("Not implemented") // All rooms encrypted by default for now return true } public override func isRoomSharingHistory(_ roomId: String!) -> Bool { - warnNotImplemented() + log.debug("Not implemented") return false } public override func setBlacklistUnverifiedDevicesInRoom(_ roomId: String!, blacklist: Bool) { - warnNotImplemented() + log.debug("Not implemented") } // MARK: - Private @@ -483,16 +580,6 @@ private class MXCryptoV2: MXCrypto { .compactMap(\.userId) .filter { $0 != userId } ?? [] } - - /// Convenience function which logs methods that are being called by the application, - /// but are not yet implemented via the Rust component. - private static func warnNotImplemented(ignore: Bool = false, _ function: String = #function) { - MXLog.debug("[MXCryptoV2] function `\(function)` not implemented, ignored: \(ignore)") - } - - private func warnNotImplemented(ignore: Bool = false, _ function: String = #function) { - Self.warnNotImplemented(ignore: ignore, function) - } } #endif diff --git a/MatrixSDK/Crypto/Data/Trust/MXDeviceTrustLevel.h b/MatrixSDK/Crypto/Trust/MXDeviceTrustLevel.h similarity index 100% rename from MatrixSDK/Crypto/Data/Trust/MXDeviceTrustLevel.h rename to MatrixSDK/Crypto/Trust/MXDeviceTrustLevel.h diff --git a/MatrixSDK/Crypto/Data/Trust/MXDeviceTrustLevel.m b/MatrixSDK/Crypto/Trust/MXDeviceTrustLevel.m similarity index 100% rename from MatrixSDK/Crypto/Data/Trust/MXDeviceTrustLevel.m rename to MatrixSDK/Crypto/Trust/MXDeviceTrustLevel.m diff --git a/MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift b/MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift new file mode 100644 index 0000000000..566b909aa1 --- /dev/null +++ b/MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift @@ -0,0 +1,86 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +/// Convenience struct which transforms `MatrixSDKCrypto` trust levels +/// into `MatrixSDK` `MXUserTrustLevel`, `MXDeviceTrustLevel` and `MXUsersTrustLevelSummary` formats. +@available(iOS 13.0.0, *) +struct MXTrustLevelSource { + private let userIdentitySource: MXCryptoUserIdentitySource + private let devicesSource: MXCryptoDevicesSource + + init(userIdentitySource: MXCryptoUserIdentitySource, devicesSource: MXCryptoDevicesSource) { + self.userIdentitySource = userIdentitySource + self.devicesSource = devicesSource + } + + func userTrustLevel(userId: String) -> MXUserTrustLevel { + let isVerified = userIdentitySource.isUserVerified(userId: userId) + return .init( + crossSigningVerified: isVerified, + locallyVerified: false // Note: Local verification not yet implemented + ) + } + + func deviceTrustLevel(userId: String, deviceId: String) -> MXDeviceTrustLevel? { + guard let device = devicesSource.device(userId: userId, deviceId: deviceId) else { + return nil + } + return .init( + localVerificationStatus: device.locallyTrusted ? .verified : .unverified, + crossSigningVerified: device.crossSigningTrusted + ) + } + + func trustLevelSummary(userIds: [String]) -> MXUsersTrustLevelSummary? { + guard let devices = trustedDevices(userIds: userIds) else { + return nil + } + + return .init( + trustedUsersProgress: trustedUsers(userIds: userIds), + andTrustedDevicesProgress: devices + ) + } + + private func trustedUsers(userIds: [String]) -> Progress { + let verifiedUsers = userIds.filter { + userIdentitySource.isUserVerified(userId: $0) + } + + let progress = Progress(totalUnitCount: Int64(userIds.count)) + progress.completedUnitCount = Int64(verifiedUsers.count) + return progress + } + + private func trustedDevices(userIds: [String]) -> Progress? { + 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 + } +} + +#endif diff --git a/MatrixSDK/Crypto/Data/Trust/MXUserTrustLevel.h b/MatrixSDK/Crypto/Trust/MXUserTrustLevel.h similarity index 100% rename from MatrixSDK/Crypto/Data/Trust/MXUserTrustLevel.h rename to MatrixSDK/Crypto/Trust/MXUserTrustLevel.h diff --git a/MatrixSDK/Crypto/Data/Trust/MXUserTrustLevel.m b/MatrixSDK/Crypto/Trust/MXUserTrustLevel.m similarity index 100% rename from MatrixSDK/Crypto/Data/Trust/MXUserTrustLevel.m rename to MatrixSDK/Crypto/Trust/MXUserTrustLevel.m diff --git a/MatrixSDK/Crypto/Data/Trust/MXUsersTrustLevelSummary.h b/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.h similarity index 100% rename from MatrixSDK/Crypto/Data/Trust/MXUsersTrustLevelSummary.h rename to MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.h diff --git a/MatrixSDK/Crypto/Data/Trust/MXUsersTrustLevelSummary.m b/MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.m similarity index 100% rename from MatrixSDK/Crypto/Data/Trust/MXUsersTrustLevelSummary.m rename to MatrixSDK/Crypto/Trust/MXUsersTrustLevelSummary.m diff --git a/MatrixSDK/Utils/MXLog.swift b/MatrixSDK/Utils/MXLog.swift index 1b8da9f021..1c53f3c477 100644 --- a/MatrixSDK/Utils/MXLog.swift +++ b/MatrixSDK/Utils/MXLog.swift @@ -194,3 +194,40 @@ private var logger: SwiftyBeaver.Type = { return "\(message) - \(details)" } } + +/// Convenience wrapper around `MXLog` which formats all logs as "[Name] function: " +struct MXNamedLog { + let name: String + + func debug(_ message: String, function: String = #function) { + MXLog.debug(formattedMessage(message, function: function)) + } + + /// Logging errors requires a static message, all other details must be sent as additional parameters + func error(_ message: StaticString, error: Error? = nil, details: [String: Any]? = nil, function: String = #function) { + MXLog.error( + formattedMessage("\(message)", function: function), + details: formattedDetails(error, otherDetails: details) + ) + } + + /// Logging failures requires a static message, all other details must be sent as additional parameters + func failure(_ message: StaticString, error: Error? = nil, details: [String: Any]? = nil, function: String = #function) { + MXLog.failure( + formattedMessage("\(message)", function: function), + details: formattedDetails(error, otherDetails: details) + ) + } + + private func formattedMessage(_ message: String, function: String) -> String { + return "[\(name)] \(function): \(message)" + } + + private func formattedDetails(_ error: Error?, otherDetails: [String: Any]?) -> [String: Any]? { + var details = otherDetails ?? [:] + if let error = error { + details["error"] = error + } + return details.isEmpty ? nil : details + } +} diff --git a/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift new file mode 100644 index 0000000000..912320bff4 --- /dev/null +++ b/MatrixSDKTests/Crypto/CrossSigning/Data/MXCrossSigningInfoUnitTests.swift @@ -0,0 +1,96 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +class MXCrossSigningInfoUnitTests: XCTestCase { + func makeKey(type: String, user: String) -> MXCrossSigningKey { + return .init( + userId: user, + usage: ["master"], + keys: "\(user)'s master" + ) + } + + func test_canCreateInfo_withOwnUserIdentity() { + let masterKeys = makeKey(type: "master", user: "Alice") + let selfSigningKeys = makeKey(type: "self", user: "Alice") + let userSigningKeys = makeKey(type: "user", user: "Alice") + + let identity = UserIdentity.own( + userId: "Alice", + trustsOurOwnDevice: false, + masterKey: masterKeys.jsonString(), + selfSigningKey: selfSigningKeys.jsonString(), + userSigningKey: userSigningKeys.jsonString() + ) + let userIdentity = MXCryptoUserIdentityWrapper( + identity: identity, + isVerified: false + ) + + let info = MXCrossSigningInfo(userIdentity: userIdentity) + + XCTAssertEqual(info.userId, "Alice") + XCTAssertKeysEqual(info.masterKeys, masterKeys) + XCTAssertKeysEqual(info.selfSignedKeys, selfSigningKeys) + XCTAssertKeysEqual(info.userSignedKeys, userSigningKeys) + XCTAssertEqual( + info.trustLevel, + MXUserTrustLevel(crossSigningVerified: false, locallyVerified: false) + ) + } + + func test_canCreateInfo_withOtherUserIdentity() { + let masterKeys = makeKey(type: "master", user: "Bob") + let selfSigningKeys = makeKey(type: "self", user: "Bob") + + let identity = UserIdentity.other( + userId: "Bob", + masterKey: masterKeys.jsonString(), + selfSigningKey: selfSigningKeys.jsonString() + ) + let userIdentity = MXCryptoUserIdentityWrapper( + identity: identity, + isVerified: true + ) + + let info = MXCrossSigningInfo(userIdentity: userIdentity) + + XCTAssertEqual(info.userId, "Bob") + XCTAssertKeysEqual(info.masterKeys, masterKeys) + XCTAssertKeysEqual(info.selfSignedKeys, selfSigningKeys) + XCTAssertNil(info.userSignedKeys) + XCTAssertEqual( + info.trustLevel, + MXUserTrustLevel(crossSigningVerified: true, locallyVerified: false) + ) + } + + private func XCTAssertKeysEqual(_ key1: MXCrossSigningKey?, _ key2: MXCrossSigningKey?, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(key1?.userId, key2?.userId, file: file, line: line) + XCTAssertEqual(key1?.usage, key2?.usage, file: file, line: line) + XCTAssertEqual(key1?.keys, key2?.keys, file: file, line: line) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift new file mode 100644 index 0000000000..fe808c012a --- /dev/null +++ b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningInfoSourceUnitTests.swift @@ -0,0 +1,84 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +@available(iOS 13.0.0, *) +class MXCrossSigningInfoSourceUnitTests: XCTestCase { + var cryptoSource: UserIdentitySourceStub! + var source: MXCrossSigningInfoSource! + + override func setUp() { + cryptoSource = UserIdentitySourceStub() + source = MXCrossSigningInfoSource(source: cryptoSource) + } + + func test_crossSigningInfo_returnsNil_ifNoIdentity() { + let info = source.crossSigningInfo(userId: "Alice") + XCTAssertNil(info) + } + + func test_crossSigningInfo_returnsVerifiedIdentity() { + cryptoSource.identities = [ + "Alice": UserIdentity.own( + userId: "Alice", + trustsOurOwnDevice: true, + masterKey: "master", + selfSigningKey: "self", + userSigningKey: "user" + ) + ] + cryptoSource.verification = [ + "Alice": true + ] + + let info = source.crossSigningInfo(userId: "Alice") + + XCTAssertEqual(info?.userId, "Alice") + XCTAssertEqual(info?.trustLevel.isVerified, true) + } + + func test_crossSigningInfo_returnsMultipleIdentities() { + cryptoSource.identities = [ + "Bob": UserIdentity.own( + userId: "Bob", + trustsOurOwnDevice: true, + masterKey: "master", + selfSigningKey: "self", + userSigningKey: "user" + ), + "Charlie": UserIdentity.other( + userId: "Charlie", + masterKey: "master", + selfSigningKey: "self" + ) + ] + + let infos = source.crossSigningInfo(userIds: ["Alice", "Bob", "Charlie"]) + + XCTAssertEqual(infos.count, 2) + XCTAssertEqual(infos["Bob"]?.userId, "Bob") + XCTAssertEqual(infos["Charlie"]?.userId, "Charlie") + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift b/MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift new file mode 100644 index 0000000000..e990fb97f3 --- /dev/null +++ b/MatrixSDKTests/Crypto/CryptoMachine/Device+Stub.swift @@ -0,0 +1,50 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +extension Device { + static func stub( + userId: String = "Alice", + deviceId: String = "Device1", + displayName: String = "Alice's iPhone", + locallyTrusted: Bool = true, + crossSigningTrusted: Bool = true + ) -> Device { + return .init( + userId: userId, + deviceId: deviceId, + keys: [ + "ed25519:Device1": "ABC", + "curve25519:Device1": "XYZ", + ], + algorithms: [ + "ed25519", + "curve25519" + ], + displayName: displayName, + isBlocked: false, + locallyTrusted: locallyTrusted, + crossSigningTrusted: crossSigningTrusted + ) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift new file mode 100644 index 0000000000..1e90360acf --- /dev/null +++ b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift @@ -0,0 +1,56 @@ +// +// Copyright 2022 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 +@testable import MatrixSDK + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +class DevicesSourceStub: MXCryptoDevicesSource { + var deviceCurve25519Key: String? { + return nil + } + + var deviceEd25519Key: String? { + return nil + } + + var devices = [String: [String: Device]]() + + func device(userId: String, deviceId: String) -> Device? { + return devices[userId]?[deviceId] + } + + func devices(userId: String) -> [Device] { + return devices[userId]?.map { $0.value } ?? [] + } +} + +class UserIdentitySourceStub: MXCryptoUserIdentitySource { + var identities = [String: UserIdentity]() + func userIdentity(userId: String) -> UserIdentity? { + return identities[userId] + } + + var verification = [String: Bool]() + func isUserVerified(userId: String) -> Bool { + return verification[userId] ?? false + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/V2/MXCryptoRequestsUnitTests.swift b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoRequestsUnitTests.swift similarity index 77% rename from MatrixSDKTests/Crypto/V2/MXCryptoRequestsUnitTests.swift rename to MatrixSDKTests/Crypto/CryptoMachine/MXCryptoRequestsUnitTests.swift index 72ed6ba91f..e3a3c507ec 100644 --- a/MatrixSDKTests/Crypto/V2/MXCryptoRequestsUnitTests.swift +++ b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoRequestsUnitTests.swift @@ -17,7 +17,11 @@ import Foundation @testable import MatrixSDK -@available(iOS 13.0.0, macOS 10.15.0, *) +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +@available(iOS 13.0.0, *) class MXCryptoRequestsUnitTests: XCTestCase { func test_canCreateToDeviceRequest() { let body: [String: [String: NSDictionary]] = [ @@ -81,4 +85,21 @@ class MXCryptoRequestsUnitTests: XCTestCase { let request = MXCryptoRequests.ClaimKeysRequest(oneTimeKeys: keys) XCTAssertEqual(request.devices.map as? [String: [String: String]], keys) } + + func test_uploadSignatureKeysRequest_canGetJsonKeys() throws { + let request = UploadSigningKeysRequest( + masterKey: MXTools.serialiseJSONObject(["key": "A"]), + selfSigningKey: MXTools.serialiseJSONObject(["key": "B"]), + userSigningKey: MXTools.serialiseJSONObject(["key": "C"]) + ) + + let keys = try request.jsonKeys() + + XCTAssertEqual(keys.count, 3) + XCTAssertEqual(keys["master_key"] as? [String: String], ["key": "A"]) + XCTAssertEqual(keys["self_signing_key"] as? [String: String], ["key": "B"]) + XCTAssertEqual(keys["user_signing_key"] as? [String: String], ["key": "C"]) + } } + +#endif diff --git a/MatrixSDKTests/Crypto/Devices/Data/MXDeviceInfoUnitTests.swift b/MatrixSDKTests/Crypto/Devices/Data/MXDeviceInfoUnitTests.swift new file mode 100644 index 0000000000..cc815ddfe1 --- /dev/null +++ b/MatrixSDKTests/Crypto/Devices/Data/MXDeviceInfoUnitTests.swift @@ -0,0 +1,83 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +class MXDeviceInfoUnitTests: XCTestCase { + func test_canCreateInfo_withDevice() { + let device = Device.stub() + + let info = MXDeviceInfo(device: .init(device: device)) + + XCTAssertEqual(info?.userId, "Alice") + XCTAssertEqual(info?.deviceId, "Device1") + XCTAssertEqual(info?.algorithms, ["ed25519", "curve25519"]) + XCTAssertEqual(info?.keys as? [String: String], [ + "ed25519:Device1": "ABC", + "curve25519:Device1": "XYZ", + ]) + XCTAssertEqual(info?.fingerprint, "ABC") + XCTAssertEqual(info?.identityKey, "XYZ") + XCTAssertEqual(info?.displayName, "Alice's iPhone") + XCTAssertEqual( + info?.trustLevel, + MXDeviceTrustLevel( + localVerificationStatus: .verified, + crossSigningVerified: true + ) + ) + } + + func test_canCreateInfo_withCorrectTrustLevel() { + let device1 = Device.stub(locallyTrusted: true, crossSigningTrusted: true) + let info1 = MXDeviceInfo(device: .init(device: device1)) + XCTAssertEqual( + info1?.trustLevel, + MXDeviceTrustLevel( + localVerificationStatus: .verified, + crossSigningVerified: true + ) + ) + + let device2 = Device.stub(locallyTrusted: false, crossSigningTrusted: true) + let info2 = MXDeviceInfo(device: .init(device: device2)) + XCTAssertEqual( + info2?.trustLevel, + MXDeviceTrustLevel( + localVerificationStatus: .unknown, + crossSigningVerified: true + ) + ) + + let device3 = Device.stub(locallyTrusted: false, crossSigningTrusted: false) + let info3 = MXDeviceInfo(device: .init(device: device3)) + XCTAssertEqual( + info3?.trustLevel, + MXDeviceTrustLevel( + localVerificationStatus: .unknown, + crossSigningVerified: false + ) + ) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift b/MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift new file mode 100644 index 0000000000..299bc03223 --- /dev/null +++ b/MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift @@ -0,0 +1,110 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +@available(iOS 13.0.0, *) +class MXDeviceInfoSourceUnitTests: XCTestCase { + class SourceStub: MXCryptoDevicesSource { + var deviceCurve25519Key: String? { + return nil + } + + var deviceEd25519Key: String? { + return nil + } + + var devices = [String: [String: Device]]() + + func device(userId: String, deviceId: String) -> Device? { + return devices[userId]?[deviceId] + } + + func devices(userId: String) -> [Device] { + return devices[userId]?.map { $0.value } ?? [] + } + } + + var cryptoSource: SourceStub! + var source: MXDeviceInfoSource! + + override func setUp() { + cryptoSource = SourceStub() + source = MXDeviceInfoSource(source: cryptoSource) + } + + func test_device_returnsNil_ifNoDevice() { + let info = source.deviceInfo(userId: "A", deviceId: "B") + XCTAssertNil(info) + } + + func test_device_returnsUserDevice() { + cryptoSource.devices = [ + "Alice": [ + "Device1": Device.stub(userId: "Alice", deviceId: "Device1"), + "Device2": Device.stub(userId: "Alice", deviceId: "Device2"), + ] + ] + + let info = source.deviceInfo(userId: "Alice", deviceId: "Device2") + + XCTAssertEqual(info?.deviceId, "Device2") + } + + func test_devices_returnsAllUserDevices() { + cryptoSource.devices = [ + "Alice": [ + "Device1": Device.stub(userId: "Alice", deviceId: "Device1"), + "Device2": Device.stub(userId: "Alice", deviceId: "Device2"), + ], + "Bob": [ + "Device3": Device.stub(userId: "Bob", deviceId: "Device3"), + ], + ] + + let infos = source.devicesInfo(userId: "Alice") + + XCTAssertEqual(infos.count, 2) + XCTAssertEqual(infos["Device1"]?.deviceId, "Device1") + XCTAssertEqual(infos["Device2"]?.deviceId, "Device2") + } + + func test_devicesMap_returnsEverything() { + cryptoSource.devices = [ + "Alice": [ + "Device1": Device.stub(userId: "Alice", deviceId: "Device1"), + "Device2": Device.stub(userId: "Alice", deviceId: "Device2"), + ], + "Bob": [ + "Device3": Device.stub(userId: "Bob", deviceId: "Device3"), + ], + ] + + let map = source.devicesMap(userIds: ["Alice", "Bob"]) + + XCTAssertEqual(map.count, 3) + XCTAssertEqual(map.objects(forUser: "Alice").count, 2) + XCTAssertEqual(map.objects(forUser: "Bob").count, 1) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift b/MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift new file mode 100644 index 0000000000..69b6e5fc86 --- /dev/null +++ b/MatrixSDKTests/Crypto/Trust/MXTrustLevelSourceUnitTests.swift @@ -0,0 +1,84 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +@available(iOS 13.0.0, *) +class MXTrustLevelSourceUnitTests: XCTestCase { + var userIdentitySource: UserIdentitySourceStub! + var devicesSource: DevicesSourceStub! + var source: MXTrustLevelSource! + + override func setUp() { + userIdentitySource = UserIdentitySourceStub() + devicesSource = DevicesSourceStub() + source = MXTrustLevelSource(userIdentitySource: userIdentitySource, devicesSource: devicesSource) + } + + func test_userTrustLevel() { + userIdentitySource.verification = [ + "Alice": true + ] + + let trustLevel = source.userTrustLevel(userId: "Alice") + + XCTAssertEqual(trustLevel, MXUserTrustLevel(crossSigningVerified: true, locallyVerified: false)) + } + + func test_deviceTrustLevel() { + devicesSource.devices = [ + "Alice": [ + "Device1": Device.stub(locallyTrusted: true) + ] + ] + + let trustLevel = source.deviceTrustLevel(userId: "Alice", deviceId: "Device1") + + XCTAssertEqual(trustLevel, MXDeviceTrustLevel(localVerificationStatus: .verified, crossSigningVerified: true)) + } + + func test_trustLevelSummary() { + userIdentitySource.verification = [ + "Alice": true, + "Bob": false + ] + devicesSource.devices = [ + "Alice": [ + "Device1": Device.stub(locallyTrusted: false, crossSigningTrusted: true), + "Device2": Device.stub(locallyTrusted: false, crossSigningTrusted: false), + ], + "Bob": [ + "Device3": Device.stub(locallyTrusted: true, crossSigningTrusted: false), + ] + ] + + let summary = source.trustLevelSummary(userIds: ["Alice", "Bob"]) + + XCTAssertEqual(summary?.trustedUsersProgress.totalUnitCount, 2) + XCTAssertEqual(summary?.trustedUsersProgress.completedUnitCount, 1) + + XCTAssertEqual(summary?.trustedDevicesProgress.totalUnitCount, 3) + XCTAssertEqual(summary?.trustedDevicesProgress.completedUnitCount, 2) + } +} + +#endif diff --git a/MatrixSDKTests/MXKeyBackupUnitTests.swift b/MatrixSDKTests/MXKeyBackupUnitTests.swift index 5ba646e363..f3a876c608 100644 --- a/MatrixSDKTests/MXKeyBackupUnitTests.swift +++ b/MatrixSDKTests/MXKeyBackupUnitTests.swift @@ -53,8 +53,8 @@ class MXKeyBackupUnitTests: XCTestCase { XCTAssertEqual(authData.publicKey, publicKey) XCTAssertEqual(authData.privateKeySalt, privateKeySalt) XCTAssertEqual(authData.privateKeyIterations, privateKeyIterations) - XCTAssertTrue(NSDictionary(dictionary: signatures).isEqual(to: NSDictionary(dictionary: authDataSignatures))) - XCTAssertTrue(NSDictionary(dictionary: authData.jsonDictionary()).isEqual(to: NSDictionary(dictionary: json))) + XCTAssertTrue(NSDictionary(dictionary: signatures).isEqual(to: NSDictionary(dictionary: authDataSignatures) as! [AnyHashable : Any])) + XCTAssertTrue(NSDictionary(dictionary: authData.jsonDictionary()).isEqual(to: NSDictionary(dictionary: json) as! [AnyHashable : Any])) XCTAssertNil(authData.signalableJSONDictionary["signatures"]) } @@ -192,8 +192,8 @@ class MXKeyBackupUnitTests: XCTestCase { XCTAssertEqual(authData.mac, mac) XCTAssertEqual(authData.privateKeySalt, privateKeySalt) XCTAssertEqual(authData.privateKeyIterations, privateKeyIterations) - XCTAssertTrue(NSDictionary(dictionary: signatures).isEqual(to: NSDictionary(dictionary: authDataSignatures))) - XCTAssertTrue(NSDictionary(dictionary: authData.jsonDictionary()).isEqual(to: NSDictionary(dictionary: json))) + XCTAssertTrue(NSDictionary(dictionary: signatures).isEqual(to: NSDictionary(dictionary: authDataSignatures) as! [AnyHashable : Any])) + XCTAssertTrue(NSDictionary(dictionary: authData.jsonDictionary()).isEqual(to: NSDictionary(dictionary: json) as! [AnyHashable : Any])) XCTAssertNil(authData.signalableJSONDictionary["signatures"]) } diff --git a/MatrixSDKTests/TestPlans/UnitTests.xctestplan b/MatrixSDKTests/TestPlans/UnitTests.xctestplan index 40f571db63..962842e076 100644 --- a/MatrixSDKTests/TestPlans/UnitTests.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTests.xctestplan @@ -38,7 +38,11 @@ "MXBeaconInfoUnitTests", "MXCoreDataRoomListDataManagerUnitTests", "MXCredentialsUnitTests", + "MXCrossSigningInfoSourceUnitTests", + "MXCrossSigningInfoUnitTests", "MXCryptoRequestsUnitTests", + "MXDeviceInfoSourceUnitTests", + "MXDeviceInfoUnitTests", "MXDeviceListOperationsPoolUnitTests", "MXErrorUnitTests", "MXEventAnnotationUnitTests", @@ -66,10 +70,11 @@ "MXSharedHistoryKeyManagerUnitTests", "MXStoreRoomListDataManagerUnitTests", "MXSyncResponseUnitTests", + "MXTaskQueueUnitTests", "MXThreadEventTimelineUnitTests", "MXThreadingServiceUnitTests", "MXToolsUnitTests", - "MXTaskQueueUnitTests", + "MXTrustLevelSourceUnitTests" ], "target" : { "containerPath" : "container:MatrixSDK.xcodeproj", diff --git a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan index 92b1fbf9a3..54fe76fe10 100644 --- a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan @@ -48,7 +48,11 @@ "MXBeaconInfoUnitTests", "MXCoreDataRoomListDataManagerUnitTests", "MXCredentialsUnitTests", + "MXCrossSigningInfoSourceUnitTests", + "MXCrossSigningInfoUnitTests", "MXCryptoRequestsUnitTests", + "MXDeviceInfoSourceUnitTests", + "MXDeviceInfoUnitTests", "MXDeviceListOperationsPoolUnitTests", "MXErrorUnitTests", "MXEventAnnotationUnitTests", @@ -74,10 +78,11 @@ "MXSharedHistoryKeyManagerUnitTests", "MXStoreRoomListDataManagerUnitTests", "MXSyncResponseUnitTests", + "MXTaskQueueUnitTests", "MXThreadEventTimelineUnitTests", "MXThreadingServiceUnitTests", "MXToolsUnitTests", - "MXTaskQueueUnitTests", + "MXTrustLevelSourceUnitTests", ], "target" : { "containerPath" : "container:MatrixSDK.xcodeproj", diff --git a/Podfile.lock b/Podfile.lock index 9437bad9e1..c5e5f7f341 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -73,4 +73,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 8a21d32ad6a381e80ea32b6104daee39323c306c -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/changelog.d/pr-1531.misc b/changelog.d/pr-1531.misc new file mode 100644 index 0000000000..3ff9133769 --- /dev/null +++ b/changelog.d/pr-1531.misc @@ -0,0 +1 @@ +Crypto: User and device identity objects From 4c0af30e273210a39f4940fababd828b3bd7e4af Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Tue, 19 Jul 2022 12:30:17 +0100 Subject: [PATCH 38/65] Wait for all verification requests in integration tests --- .../MXCrossSigningVerificationTests.m | 7 +- MatrixSDKTests/MXCryptoKeyVerificationTests.m | 224 +++++++++--------- 2 files changed, 121 insertions(+), 110 deletions(-) diff --git a/MatrixSDKTests/MXCrossSigningVerificationTests.m b/MatrixSDKTests/MXCrossSigningVerificationTests.m index fa78d97933..4c9b66306e 100644 --- a/MatrixSDKTests/MXCrossSigningVerificationTests.m +++ b/MatrixSDKTests/MXCrossSigningVerificationTests.m @@ -662,9 +662,8 @@ - (void)testVerifyingAnotherUserQRCodeVerificationFullFlow XCTAssertNotNil(requestJSON); // - Alice accepts it and creates a QR code transaction - - // Wait a bit - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self observeKeyVerificationRequestInSession:aliceSession block:^(id _Nullable request) { + // - Alice accepts the incoming request id requestFromAlicePOV = aliceSession.crypto.keyVerificationManager.pendingRequests.firstObject; XCTAssertNotNil(requestFromAlicePOV); @@ -683,7 +682,7 @@ - (void)testVerifyingAnotherUserQRCodeVerificationFullFlow XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; }]; - }); + }]; } }]; diff --git a/MatrixSDKTests/MXCryptoKeyVerificationTests.m b/MatrixSDKTests/MXCryptoKeyVerificationTests.m index 43f1b4d89a..8c15d0cb40 100644 --- a/MatrixSDKTests/MXCryptoKeyVerificationTests.m +++ b/MatrixSDKTests/MXCryptoKeyVerificationTests.m @@ -201,25 +201,65 @@ - (void)testVerificationByToDeviceRequests */ - (void)checkVerificationByToDeviceFullFlowWithBobSession:(MXSession*)bobSession aliceSession:(MXSession*)aliceSession roomId:(NSString*)roomId expectation:(XCTestExpectation*)expectation { - __block NSString *requestId; + __block id requestFromBobPOV; + __block id requestFromAlicePOV; + __block MXOutgoingSASTransaction *sasTransactionFromAlicePOV; MXCredentials *alice = aliceSession.matrixRestClient.credentials; MXCredentials *bob = bobSession.matrixRestClient.credentials; NSArray *methods = @[MXKeyVerificationMethodSAS, @"toto"]; + void (^requestCompletionBlock)(void) = ^{ + // Wait until both parties have recieved the request + if (!requestFromBobPOV || !requestFromAlicePOV) { + return; + } + + XCTAssertNotNil(requestFromBobPOV.requestId); + XCTAssertNotNil(requestFromAlicePOV.requestId); + XCTAssertEqualObjects(requestFromBobPOV.requestId, requestFromAlicePOV.requestId); + + // - Alice accepts it + [requestFromAlicePOV acceptWithMethods:@[MXKeyVerificationMethodSAS] success:^{ + + id requestFromAlicePOV2 = aliceSession.crypto.keyVerificationManager.pendingRequests.firstObject; + XCTAssertNotNil(requestFromAlicePOV2); + XCTAssertEqualObjects(requestFromAlicePOV2.myMethods, @[MXKeyVerificationMethodSAS]); + + // - Alice begins a SAS verification + [aliceSession.crypto.keyVerificationManager beginKeyVerificationFromRequest:requestFromAlicePOV2 method:MXKeyVerificationMethodSAS success:^(id _Nonnull transactionFromAlicePOV) { + + XCTAssertEqualObjects(transactionFromAlicePOV.transactionId, requestFromAlicePOV.requestId); + + XCTAssert(transactionFromAlicePOV); + XCTAssertTrue([transactionFromAlicePOV isKindOfClass:MXOutgoingSASTransaction.class]); + sasTransactionFromAlicePOV = (MXOutgoingSASTransaction*)transactionFromAlicePOV; + + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + }; + // - Bob requests a verification of Alice in this Room [bobSession.crypto.keyVerificationManager requestVerificationByToDeviceWithUserId:alice.userId deviceIds:@[alice.deviceId] methods:@[MXKeyVerificationMethodSAS, @"toto"] - success:^(id requestFromBobPOV) + success:^(id request) { - XCTAssertNotNil(requestFromBobPOV); - XCTAssertNotNil(requestFromBobPOV.requestId); - requestId = requestFromBobPOV.requestId; - - XCTAssertEqualObjects(requestFromBobPOV.otherUser, alice.userId); - XCTAssertNil(requestFromBobPOV.otherDevice); + XCTAssertNotNil(request); + XCTAssertNotNil(request.requestId); + XCTAssertEqualObjects(request.otherUser, alice.userId); + XCTAssertNil(request.otherDevice); + + requestFromBobPOV = request; + requestCompletionBlock(); } failure:^(NSError * _Nonnull error) { @@ -227,54 +267,19 @@ - (void)checkVerificationByToDeviceFullFlowWithBobSession:(MXSession*)bobSession [expectation fulfill]; }]; - - __block MXOutgoingSASTransaction *sasTransactionFromAlicePOV; - // - Alice gets the requests notification - [self observeKeyVerificationRequestInSession:aliceSession block:^(id _Nullable requestFromAlicePOV) { + [self observeKeyVerificationRequestInSession:aliceSession block:^(id _Nullable request) { + XCTAssertNotNil(request); + XCTAssertNotNil(request.requestId); + XCTAssertEqualObjects(request.methods, methods); + XCTAssertEqualObjects(request.otherMethods, methods); + XCTAssertNil(request.myMethods); - // Wait a bit, `requestVerification` could complete after it sends out a few events observed by Alice's session - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - - XCTAssertNotNil(requestId); - XCTAssertNotNil(requestFromAlicePOV); - XCTAssertNotNil(requestFromAlicePOV.requestId); - - XCTAssertEqualObjects(requestFromAlicePOV.requestId, requestId); - - XCTAssertEqualObjects(requestFromAlicePOV.methods, methods); - XCTAssertEqualObjects(requestFromAlicePOV.otherMethods, methods); - XCTAssertNil(requestFromAlicePOV.myMethods); - - XCTAssertEqualObjects(requestFromAlicePOV.otherUser, bob.userId); - XCTAssertEqualObjects(requestFromAlicePOV.otherDevice, bob.deviceId); - - // - Alice accepts it - [requestFromAlicePOV acceptWithMethods:@[MXKeyVerificationMethodSAS] success:^{ - - id requestFromAlicePOV2 = aliceSession.crypto.keyVerificationManager.pendingRequests.firstObject; - XCTAssertNotNil(requestFromAlicePOV2); - XCTAssertEqualObjects(requestFromAlicePOV2.myMethods, @[MXKeyVerificationMethodSAS]); - - // - Alice begins a SAS verification - [aliceSession.crypto.keyVerificationManager beginKeyVerificationFromRequest:requestFromAlicePOV2 method:MXKeyVerificationMethodSAS success:^(id _Nonnull transactionFromAlicePOV) { - - XCTAssertEqualObjects(transactionFromAlicePOV.transactionId, requestFromAlicePOV.requestId); - - XCTAssert(transactionFromAlicePOV); - XCTAssertTrue([transactionFromAlicePOV isKindOfClass:MXOutgoingSASTransaction.class]); - sasTransactionFromAlicePOV = (MXOutgoingSASTransaction*)transactionFromAlicePOV; - - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - }); + XCTAssertEqualObjects(request.otherUser, bob.userId); + XCTAssertEqualObjects(request.otherDevice, bob.deviceId); + + requestFromAlicePOV = request; + requestCompletionBlock(); }]; @@ -990,23 +995,71 @@ - (void)testVerificationByDMFullFlow - (void)checkVerificationByDMFullFlowWithAliceSession:(MXSession*)aliceSession bobSession:(MXSession*)bobSession roomId:(NSString*)roomId expectation:(XCTestExpectation*)expectation { NSString *fallbackText = @"fallbackText"; - __block NSString *requestId; + __block id requestFromBobPOV; + __block id requestFromAlicePOV; + __block MXOutgoingSASTransaction *sasTransactionFromAlicePOV; MXCredentials *alice = aliceSession.matrixRestClient.credentials; MXCredentials *bob = bobSession.matrixRestClient.credentials; NSArray *methods = @[MXKeyVerificationMethodSAS, @"toto"]; + void (^requestCompletionBlock)(void) = ^{ + // Wait until both parties have recieved the request + if (!requestFromBobPOV || !requestFromAlicePOV) { + return; + } + + XCTAssertNotNil(requestFromAlicePOV); + + XCTAssertEqualObjects(requestFromAlicePOV.methods, methods); + XCTAssertEqualObjects(requestFromAlicePOV.otherMethods, methods); + XCTAssertNil(requestFromAlicePOV.myMethods); + + XCTAssertEqualObjects(requestFromAlicePOV.otherUser, bob.userId); + XCTAssertEqualObjects(requestFromAlicePOV.otherDevice, bob.deviceId); + + // - Alice accepts it + [requestFromAlicePOV acceptWithMethods:@[MXKeyVerificationMethodSAS] success:^{ + + id requestFromAlicePOV2 = aliceSession.crypto.keyVerificationManager.pendingRequests.firstObject; + XCTAssertNotNil(requestFromAlicePOV2); + XCTAssertEqualObjects(requestFromAlicePOV2.myMethods, @[MXKeyVerificationMethodSAS]); + + // - Alice begins a SAS verification + [aliceSession.crypto.keyVerificationManager beginKeyVerificationFromRequest:requestFromAlicePOV2 method:MXKeyVerificationMethodSAS success:^(id _Nonnull transactionFromAlicePOV) { + + XCTAssertEqualObjects(transactionFromAlicePOV.transactionId, requestFromAlicePOV.requestId); + + XCTAssert(transactionFromAlicePOV); + XCTAssertTrue([transactionFromAlicePOV isKindOfClass:MXOutgoingSASTransaction.class]); + sasTransactionFromAlicePOV = (MXOutgoingSASTransaction*)transactionFromAlicePOV; + + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + } failure:^(NSError * _Nonnull error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + }; + // - Bob requests a verification of Alice in this Room [bobSession.crypto.keyVerificationManager requestVerificationByDMWithUserId:alice.userId roomId:roomId fallbackText:fallbackText methods:methods - success:^(id requestFromBobPOV) + success:^(id request) { - requestId = requestFromBobPOV.requestId; - XCTAssertEqualObjects(requestFromBobPOV.otherUser, alice.userId); - XCTAssertNil(requestFromBobPOV.otherDevice); + XCTAssertNotNil(request); + XCTAssertNotNil(request.requestId); + XCTAssertEqualObjects(request.otherUser, alice.userId); + XCTAssertNil(request.otherDevice); + + requestFromBobPOV = request; + requestCompletionBlock(); } failure:^(NSError * _Nonnull error) { @@ -1014,66 +1067,25 @@ - (void)checkVerificationByDMFullFlowWithAliceSession:(MXSession*)aliceSession b [expectation fulfill]; }]; - - __block MXOutgoingSASTransaction *sasTransactionFromAlicePOV; - - + // Alice gets the request in the timeline [aliceSession listenToEventsOfTypes:@[kMXEventTypeStringRoomMessage] onEvent:^(MXEvent *event, MXTimelineDirection direction, id customObject) { if ([event.content[kMXMessageTypeKey] isEqualToString:kMXMessageTypeKeyVerificationRequest]) { - XCTAssertEqualObjects(event.eventId, requestId); - // Check verification by DM request format MXKeyVerificationRequestByDMJSONModel *requestJSON; MXJSONModelSetMXJSONModel(requestJSON, MXKeyVerificationRequestByDMJSONModel.class, event.content); XCTAssertNotNil(requestJSON); - // Wait a bit - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - - id requestFromAlicePOV = aliceSession.crypto.keyVerificationManager.pendingRequests.firstObject; - XCTAssertNotNil(requestFromAlicePOV); - - XCTAssertEqualObjects(requestFromAlicePOV.methods, methods); - XCTAssertEqualObjects(requestFromAlicePOV.otherMethods, methods); - XCTAssertNil(requestFromAlicePOV.myMethods); - - XCTAssertEqualObjects(requestFromAlicePOV.otherUser, bob.userId); - XCTAssertEqualObjects(requestFromAlicePOV.otherDevice, bob.deviceId); - - // - Alice accepts it - [requestFromAlicePOV acceptWithMethods:@[MXKeyVerificationMethodSAS] success:^{ - - id requestFromAlicePOV2 = aliceSession.crypto.keyVerificationManager.pendingRequests.firstObject; - XCTAssertNotNil(requestFromAlicePOV2); - XCTAssertEqualObjects(requestFromAlicePOV2.myMethods, @[MXKeyVerificationMethodSAS]); - - // - Alice begins a SAS verification - [aliceSession.crypto.keyVerificationManager beginKeyVerificationFromRequest:requestFromAlicePOV2 method:MXKeyVerificationMethodSAS success:^(id _Nonnull transactionFromAlicePOV) { - - XCTAssertEqualObjects(transactionFromAlicePOV.transactionId, event.eventId); - - XCTAssert(transactionFromAlicePOV); - XCTAssertTrue([transactionFromAlicePOV isKindOfClass:MXOutgoingSASTransaction.class]); - sasTransactionFromAlicePOV = (MXOutgoingSASTransaction*)transactionFromAlicePOV; - - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError * _Nonnull error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - }); + [self observeKeyVerificationRequestInSession:aliceSession block:^(id _Nullable request) { + requestFromAlicePOV = request; + requestCompletionBlock(); + }]; } }]; - [self observeSASIncomingTransactionInSession:bobSession block:^(MXIncomingSASTransaction * _Nullable transactionFromBobPOV) { // Final checks @@ -1171,7 +1183,7 @@ - (void)checkVerificationByDMFullFlowWithAliceSession:(MXSession*)aliceSession b if (doneDone.count == 4) { // Then, test MXKeyVerification - MXEvent *event = [aliceSession.store eventWithEventId:requestId inRoom:roomId]; + MXEvent *event = [aliceSession.store eventWithEventId:requestFromAlicePOV.requestId inRoom:roomId]; [aliceSession.crypto.keyVerificationManager keyVerificationFromKeyVerificationEvent:event success:^(MXKeyVerification * _Nonnull verificationFromAlicePOV) { XCTAssertEqual(verificationFromAlicePOV.state, MXKeyVerificationStateVerified); From 1771a87b57aebb41f4b3932946e11b2eeae3885e Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 18 Jul 2022 17:37:12 +0100 Subject: [PATCH 39/65] Outgoing SAS User Verification Flow --- MatrixSDK.xcodeproj/project.pbxproj | 74 ++++++ .../CrossSigning/Data/MXCrossSigningInfo.h | 2 +- .../CryptoMachine/MXCryptoMachine.swift | 101 ++++++++ .../CryptoMachine/MXCryptoProtocols.swift | 13 + MatrixSDK/Crypto/MXCryptoV2.swift | 43 ++-- .../Verification/MXKeyVerificationManager.m | 21 +- .../MXKeyVerificationManagerV2.swift | 238 ++++++++++++++++++ .../Requests/MXKeyVerificationRequest.h | 32 +-- .../Requests/MXKeyVerificationRequest.m | 1 + .../Requests/MXKeyVerificationRequestV2.swift | 128 ++++++++++ .../MXKeyVerificationRequest_Private.h | 5 + .../MXKeyVerificationTransaction.h | 44 ++-- .../Transactions/SAS/MXSASTransaction.h | 19 +- .../Transactions/SAS/MXSASTransaction.m | 5 + .../Transactions/SAS/MXSASTransactionV2.swift | 139 ++++++++++ .../SAS/MXSASTransaction_Private.h | 1 + .../MXKeyVerificationRequestV2UnitTests.swift | 140 +++++++++++ .../Requests/VerificationRequest+Stub.swift | 55 ++++ .../SAS/MXSASTransactionV2UnitTests.swift | 180 +++++++++++++ .../Transactions/SAS/Sas+Stub.swift | 55 ++++ changelog.d/6443.feature | 1 + 21 files changed, 1234 insertions(+), 63 deletions(-) create mode 100644 MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift create mode 100644 MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift create mode 100644 MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift create mode 100644 MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift create mode 100644 MatrixSDKTests/Crypto/Verification/Requests/VerificationRequest+Stub.swift create mode 100644 MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift create mode 100644 MatrixSDKTests/Crypto/Verification/Transactions/SAS/Sas+Stub.swift create mode 100644 changelog.d/6443.feature diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 232e802533..1f4342640f 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1851,6 +1851,20 @@ ED7019E12886C26D00FC31B9 /* MXCryptoRequestsUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2DD11B286C4F3E00F06731 /* MXCryptoRequestsUnitTests.swift */; }; ED7019E22886C28900FC31B9 /* MXCryptoProtocolStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D332885ADE200F897E7 /* MXCryptoProtocolStubs.swift */; }; ED7019E32886C29400FC31B9 /* Device+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D312885AC5700F897E7 /* Device+Stub.swift */; }; + ED7019E52886C32900FC31B9 /* MXSASTransactionV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019E42886C32900FC31B9 /* MXSASTransactionV2.swift */; }; + ED7019E62886C32900FC31B9 /* MXSASTransactionV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019E42886C32900FC31B9 /* MXSASTransactionV2.swift */; }; + ED7019E82886C33100FC31B9 /* MXKeyVerificationRequestV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019E72886C33100FC31B9 /* MXKeyVerificationRequestV2.swift */; }; + ED7019E92886C33100FC31B9 /* MXKeyVerificationRequestV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019E72886C33100FC31B9 /* MXKeyVerificationRequestV2.swift */; }; + ED7019EB2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019EA2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift */; }; + ED7019EC2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019EA2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift */; }; + ED7019F52886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019EF2886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift */; }; + ED7019F62886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019EF2886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift */; }; + ED7019F72886CA6C00FC31B9 /* VerificationRequest+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019F02886CA6C00FC31B9 /* VerificationRequest+Stub.swift */; }; + ED7019F82886CA6C00FC31B9 /* VerificationRequest+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019F02886CA6C00FC31B9 /* VerificationRequest+Stub.swift */; }; + ED7019F92886CA6C00FC31B9 /* Sas+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019F32886CA6C00FC31B9 /* Sas+Stub.swift */; }; + ED7019FA2886CA6C00FC31B9 /* Sas+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019F32886CA6C00FC31B9 /* Sas+Stub.swift */; }; + ED7019FB2886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019F42886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift */; }; + ED7019FC2886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7019F42886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift */; }; ED88999127F2065D00718486 /* MXRoomAliasResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */; settings = {ATTRIBUTES = (Public, ); }; }; ED88999227F2065D00718486 /* MXRoomAliasResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */; settings = {ATTRIBUTES = (Public, ); }; }; ED88999327F2065D00718486 /* MXRoomAliasResolution.m in Sources */ = {isa = PBXBuildFile; fileRef = ED88999027F2065D00718486 /* MXRoomAliasResolution.m */; }; @@ -2916,6 +2930,13 @@ ED5AE8C32816C8CF00105072 /* MXRoomSummaryCoreDataStore2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MXRoomSummaryCoreDataStore2.xcdatamodel; sourceTree = ""; }; ED5AE8C42816C8CF00105072 /* MXRoomSummaryCoreDataStore.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MXRoomSummaryCoreDataStore.xcdatamodel; sourceTree = ""; }; ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXOlmDeviceUnitTests.swift; sourceTree = ""; }; + ED7019E42886C32900FC31B9 /* MXSASTransactionV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSASTransactionV2.swift; sourceTree = ""; }; + ED7019E72886C33100FC31B9 /* MXKeyVerificationRequestV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationRequestV2.swift; sourceTree = ""; }; + ED7019EA2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationManagerV2.swift; sourceTree = ""; }; + ED7019EF2886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationRequestV2UnitTests.swift; sourceTree = ""; }; + ED7019F02886CA6C00FC31B9 /* VerificationRequest+Stub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "VerificationRequest+Stub.swift"; sourceTree = ""; }; + ED7019F32886CA6C00FC31B9 /* Sas+Stub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sas+Stub.swift"; sourceTree = ""; }; + ED7019F42886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSASTransactionV2UnitTests.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 = ""; }; ED8943D327E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXMemoryRoomStoreUnitTests.swift; sourceTree = ""; }; @@ -3063,6 +3084,7 @@ 320B3938239FD15E00BE2C06 /* MXKeyVerificationRequest.h */, 320B393E239FD48400BE2C06 /* MXKeyVerificationRequest_Private.h */, 320B3939239FD15E00BE2C06 /* MXKeyVerificationRequest.m */, + ED7019E72886C33100FC31B9 /* MXKeyVerificationRequestV2.swift */, 320B3932239FA56900BE2C06 /* MXKeyVerificationByDMRequest.h */, 320B3933239FA56900BE2C06 /* MXKeyVerificationByDMRequest.m */, 3274538823FD918800438328 /* MXKeyVerificationByToDeviceRequest.h */, @@ -3451,6 +3473,7 @@ 3252DCAC224BE5D40032264F /* MXKeyVerificationManager.h */, 3252DCAD224BE5D40032264F /* MXKeyVerificationManager.m */, 3252DCCF224D25810032264F /* MXKeyVerificationManager_Private.h */, + ED7019EA2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift */, ); path = Verification; sourceTree = ""; @@ -3528,6 +3551,7 @@ 321CFDE422525A49004D31DF /* MXSASTransaction.h */, 321CFDF022549C39004D31DF /* MXSASTransaction_Private.h */, 321CFDE522525A49004D31DF /* MXSASTransaction.m */, + ED7019E42886C32900FC31B9 /* MXSASTransactionV2.swift */, 321CFDE822525DED004D31DF /* MXIncomingSASTransaction.h */, B1DDC9D52418098200D208E3 /* MXIncomingSASTransaction_Private.h */, 321CFDE922525DEE004D31DF /* MXIncomingSASTransaction.m */, @@ -5106,6 +5130,7 @@ ED35652A281150230002BF6A /* Data */, ED21F67B28104BA1002FF83D /* Algorithms */, ED2DD11A286C4F3100F06731 /* CryptoMachine */, + ED7019ED2886CA6C00FC31B9 /* Verification */, ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */, ); path = Crypto; @@ -5166,6 +5191,41 @@ path = KeySharing; sourceTree = ""; }; + ED7019ED2886CA6C00FC31B9 /* Verification */ = { + isa = PBXGroup; + children = ( + ED7019EE2886CA6C00FC31B9 /* Requests */, + ED7019F12886CA6C00FC31B9 /* Transactions */, + ); + path = Verification; + sourceTree = ""; + }; + ED7019EE2886CA6C00FC31B9 /* Requests */ = { + isa = PBXGroup; + children = ( + ED7019EF2886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift */, + ED7019F02886CA6C00FC31B9 /* VerificationRequest+Stub.swift */, + ); + path = Requests; + sourceTree = ""; + }; + ED7019F12886CA6C00FC31B9 /* Transactions */ = { + isa = PBXGroup; + children = ( + ED7019F22886CA6C00FC31B9 /* SAS */, + ); + path = Transactions; + sourceTree = ""; + }; + ED7019F22886CA6C00FC31B9 /* SAS */ = { + isa = PBXGroup; + children = ( + ED7019F32886CA6C00FC31B9 /* Sas+Stub.swift */, + ED7019F42886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift */, + ); + path = SAS; + sourceTree = ""; + }; ED8943D127E3474A000FC39C /* Store */ = { isa = PBXGroup; children = ( @@ -6480,6 +6540,7 @@ 3281E8B819E42DFE00976E1A /* MXJSONModel.m in Sources */, 32AF929924115D8B0008A0FD /* MXPendingSecretShareRequest.m in Sources */, 327E9AE22285497100A98BC1 /* MXEventContentRelatesTo.m in Sources */, + ED7019EB2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift in Sources */, 32A1514B1DAF7C0C00400192 /* MXUsersDevicesMap.m in Sources */, 328BCB3421947BE200A976D3 /* MXKeyBackupVersionTrust.m in Sources */, 324AAC72239913AD00380A66 /* MXKeyVerificationRequestByDMJSONModel.m in Sources */, @@ -6590,6 +6651,7 @@ 3281E8BA19E42DFE00976E1A /* MXJSONModels.m in Sources */, 3245A7531AF7B2930001D8A7 /* MXCallManager.m in Sources */, 32E226A71D06AC9F00E6CA54 /* MXPeekingRoom.m in Sources */, + ED7019E82886C33100FC31B9 /* MXKeyVerificationRequestV2.swift in Sources */, 320F7D2C260A8E3B00EF8608 /* MXSyncResponseStoreMetaDataModel.swift in Sources */, 021AFBA72179E91900742B2C /* MXEncryptedContentFile.m in Sources */, 3220094619EFBF30008DE41D /* MXSessionEventListener.m in Sources */, @@ -6721,6 +6783,7 @@ B19A30C22404268600FB6F35 /* MXVerifyingAnotherUserQRCodeData.m in Sources */, EC8A53BD25B1BC77004E0802 /* MXCallRejectEventContent.m in Sources */, ECCA02BE27348FE300B6F34F /* MXThread.swift in Sources */, + ED7019E52886C32900FC31B9 /* MXSASTransactionV2.swift in Sources */, EC1848C72686174E00865E16 /* MXiOSAudioOutputRouteType.swift in Sources */, 3220093919EFA4C9008DE41D /* MXEventListener.m in Sources */, EC5C562A27A36EDB0014CBE9 /* MXInReplyTo.m in Sources */, @@ -6795,6 +6858,7 @@ EDF1B6932876CD8600BBBCEE /* MXTaskQueueUnitTests.swift in Sources */, 32684CB821085F770046D2F9 /* MXLazyLoadingTests.m in Sources */, 18121F75273E6D2400B68ADF /* MXPollBuilderTests.swift in Sources */, + ED7019F72886CA6C00FC31B9 /* VerificationRequest+Stub.swift in Sources */, B14EECEE2578FE3F00448735 /* MXAuthenticationSessionUnitTests.swift in Sources */, ED2DD11D286C4F4400F06731 /* MXCryptoRequestsUnitTests.swift in Sources */, 32832B5D1BCC048300241108 /* MXStoreMemoryStoreTests.m in Sources */, @@ -6829,6 +6893,7 @@ B19A30D82404335D00FB6F35 /* MXQRCodeDataUnitTests.m in Sources */, 32B477852638133C00EA5800 /* MXAggregatedEditsUnitTests.m in Sources */, ECB6FA8E267CFF4300A941E4 /* MXCredentialsUnitTests.swift in Sources */, + ED7019F52886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift in Sources */, 3A108E6725826F52005EEBE9 /* MXKeyProviderUnitTests.m in Sources */, 3A858DE8275511A4006322C1 /* MXRoomAliasAvailabilityCheckerResultTests.swift in Sources */, EC116593270FB6970089FA56 /* MXBackgroundTaskUnitTests.swift in Sources */, @@ -6857,6 +6922,7 @@ 3281E8A219E2DE4300976E1A /* MXSessionTests.m in Sources */, 327137241A24BDDE00DB6757 /* MXUserTests.m in Sources */, EC40386728A279220067D5B8 /* MXKeyBackupUnitTests.swift in Sources */, + ED7019FB2886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift in Sources */, 32B0E3E723A3864C0054FF1A /* MXEventReferenceUnitTests.swift in Sources */, 32720DA2222EB5650086FFF5 /* MXAutoDiscoveryTests.m in Sources */, ED8943D427E34762000FC39C /* MXMemoryRoomStoreUnitTests.swift in Sources */, @@ -6872,6 +6938,7 @@ 32D8CAC219DEE6ED002AF8A0 /* MXRestClientNoAuthAPITests.m in Sources */, 32FCAB4D19E578860049C555 /* MXRestClientTests.m in Sources */, 32C78BA7256D227D008130B1 /* MXCryptoMigrationTests.m in Sources */, + ED7019F92886CA6C00FC31B9 /* Sas+Stub.swift in Sources */, ED21F68528104DA2002FF83D /* MXMegolmEncryptionTests.swift in Sources */, ED44F01A28180F4000452A5D /* MXSharedHistoryKeyManagerUnitTests.swift in Sources */, 322985CB26FAF898001890BC /* MXSession.swift in Sources */, @@ -7070,6 +7137,7 @@ B14EF2152397E90400758AF0 /* MXRoom.swift in Sources */, B14EF2162397E90400758AF0 /* MXOlmSession.m in Sources */, EC8A53A425B1BC77004E0802 /* MXCallEventContent.m in Sources */, + ED7019EC2886C33A00FC31B9 /* MXKeyVerificationManagerV2.swift in Sources */, B14EF2172397E90400758AF0 /* MXMegolmDecryption.m in Sources */, 3A23A740256D322C00B9D00F /* MXAes.m in Sources */, B14EF2182397E90400758AF0 /* MXEmojiRepresentation.m in Sources */, @@ -7180,6 +7248,7 @@ B14EF2472397E90400758AF0 /* MXContentScanEncryptedBody.m in Sources */, 32CEEF4623AD2A6C0039BA98 /* MXCrossSigningKey.m in Sources */, B14EF2482397E90400758AF0 /* MXEncryptedAttachments.m in Sources */, + ED7019E92886C33100FC31B9 /* MXKeyVerificationRequestV2.swift in Sources */, EC05478525FF99450047ECD7 /* MXRoomAccountDataUpdater.m in Sources */, ECD289A926EBB0FE00F268CF /* MXRoomListDataFetcherDelegate.swift in Sources */, EC0B941027184E8A00B4D440 /* MXUsersTrustLevelSummaryMO.swift in Sources */, @@ -7311,6 +7380,7 @@ EC60ED60265CFC2C00B39A4E /* MXSyncResponse.m in Sources */, 3A108AB825812995005EEBE9 /* MXKeyProvider.m in Sources */, B14EF2822397E90400758AF0 /* MXDeviceList.m in Sources */, + ED7019E62886C32900FC31B9 /* MXSASTransactionV2.swift in Sources */, ECCA02BF27348FE300B6F34F /* MXThread.swift in Sources */, 320B3937239FA56900BE2C06 /* MXKeyVerificationByDMRequest.m in Sources */, B14EF2832397E90400758AF0 /* MXRoomCreateContent.m in Sources */, @@ -7385,6 +7455,7 @@ B1E09A262397FCE90057C069 /* MXPushRuleUnitTests.m in Sources */, EDF1B6942876CD8600BBBCEE /* MXTaskQueueUnitTests.swift in Sources */, B1E09A442397FD940057C069 /* Dummy.swift in Sources */, + ED7019F82886CA6C00FC31B9 /* VerificationRequest+Stub.swift in Sources */, 18121F76273E6D2400B68ADF /* MXPollBuilderTests.swift in Sources */, B1E09A1A2397FCE90057C069 /* MXAggregatedEditsTests.m in Sources */, B1E09A1F2397FCE90057C069 /* MXAutoDiscoveryTests.m in Sources */, @@ -7419,6 +7490,7 @@ B1E09A212397FCE90057C069 /* DirectRoomTests.m in Sources */, 32AF9293241112850008A0FD /* MXCryptoSecretShareTests.m in Sources */, B1E09A462397FD990057C069 /* MXMediaScanStoreUnitTests.m in Sources */, + ED7019F62886CA6C00FC31B9 /* MXKeyVerificationRequestV2UnitTests.swift in Sources */, ECB6FA8F267CFF4300A941E4 /* MXCredentialsUnitTests.swift in Sources */, 3A858DE9275511A4006322C1 /* MXRoomAliasAvailabilityCheckerResultTests.swift in Sources */, ED7019DF2886C25600FC31B9 /* MXDeviceInfoUnitTests.swift in Sources */, @@ -7446,6 +7518,7 @@ 32EEA84B2603FDD60041425B /* MXResponseUnitTests.swift in Sources */, 32B0E3E823A3864C0054FF1A /* MXEventReferenceUnitTests.swift in Sources */, B1E09A402397FD820057C069 /* MXVoIPTests.m in Sources */, + ED7019FC2886CA6C00FC31B9 /* MXSASTransactionV2UnitTests.swift in Sources */, 32B4778F2638133D00EA5800 /* MXJSONModelUnitTests.m in Sources */, B1F939F626289F2600D0E525 /* MXSpaceChildContentTests.swift in Sources */, EC40386828A279220067D5B8 /* MXKeyBackupUnitTests.swift in Sources */, @@ -7462,6 +7535,7 @@ 32B477902638133D00EA5800 /* MXAggregatedReferenceUnitTests.m in Sources */, EC116598270FCA8B0089FA56 /* MXBackgroundTaskUnitTests.swift in Sources */, B1E09A322397FD750057C069 /* MXRoomTests.m in Sources */, + ED7019FA2886CA6C00FC31B9 /* Sas+Stub.swift in Sources */, ED21F68628104DA2002FF83D /* MXMegolmEncryptionTests.swift in Sources */, ED44F01B28180F4000452A5D /* MXSharedHistoryKeyManagerUnitTests.swift in Sources */, 322985CC26FAF898001890BC /* MXSession.swift in Sources */, diff --git a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h index 68576f67fc..0abef4e8bc 100644 --- a/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h +++ b/MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h @@ -35,7 +35,7 @@ extern NSString *const MXCrossSigningInfoTrustLevelDidChangeNotification; #if DEBUG && TARGET_OS_IPHONE /** - Initialize cross signing with MatrixSDKCrypto user identity + Initialize cross signing with MatrixSDKCrypto user identity */ - (instancetype)initWithUserIdentity:(MXCryptoUserIdentityWrapper *)userIdentity; #endif diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index c4fe369be1..d35546d6be 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -46,6 +46,11 @@ class MXCryptoMachine { case invalidEvent case nothingToEncrypt case missingRoom + case missingVerificationContent + case missingVerificationRequest + case missingVerification + case missingEmojis + case cannotCancelVerification } private let machine: OlmMachine @@ -365,6 +370,102 @@ extension MXCryptoMachine: MXCryptoCrossSigning { } } +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoVerification { + func requestVerification(userId: String, roomId: String, methods: [String]) async throws -> VerificationRequest { + guard let content = try machine.verificationRequestContent(userId: userId, methods: methods) else { + throw Error.missingVerificationContent + } + + let eventId = try await sendRoomMessage( + roomId: roomId, + eventType: kMXEventTypeStringRoomMessage, + content: content + ) + guard let eventId = eventId else { + throw Error.invalidEvent + } + + let request = try machine.requestVerification( + userId: userId, + roomId: roomId, + eventId: eventId, + methods: methods + ) + + guard let request = request else { + throw Error.missingVerificationRequest + } + return request + } + + func verificationRequest(userId: String, flowId: String) -> VerificationRequest? { + return machine.getVerificationRequest(userId: userId, flowId: flowId) + } + + func verification(userId: String, flowId: String) -> Verification? { + return machine.getVerification(userId: userId, flowId: flowId) + } + + func beginSasVerification(userId: String, flowId: String) async throws -> Sas { + guard let result = try machine.startSasVerification(userId: userId, flowId: flowId) else { + throw Error.missingVerification + } + try await handleOutgoingVerificationRequest(result.request) + return result.sas + } + + func confirmVerification(userId: String, flowId: String) async throws { + let result = try machine.confirmVerification(userId: userId, flowId: flowId) + guard let result = result else { + throw Error.missingVerification + } + + if let request = result.signatureRequest { + try await requests.uploadSignatures(request: request) + } + + try await withThrowingTaskGroup(of: Void.self) { group in + for request in result.requests { + group.addTask { + try await self.handleOutgoingVerificationRequest(request) + } + } + + try await group.waitForAll() + } + } + + func cancelVerification(userId: String, flowId: String, cancelCode: String) async throws { + guard let request = machine.cancelVerification(userId: userId, flowId: flowId, cancelCode: cancelCode) else { + throw Error.cannotCancelVerification + } + try await handleOutgoingVerificationRequest(request) + } + + func emojiIndexes(sas: Sas) throws -> [Int] { + guard let indexes = machine.getEmojiIndex(userId: sas.otherUserId, flowId: sas.flowId) else { + throw Error.missingEmojis + } + return indexes.map(Int.init) + } + + // MARK: - Private + + private func handleOutgoingVerificationRequest(_ request: OutgoingVerificationRequest) async throws { + guard case .inRoom(let requestId, let roomId, let eventType, let content) = request else { + assertionFailure("Not yet implemented") + return + } + + let _ = try await sendRoomMessage( + roomId: roomId, + eventType: eventType, + content: content + ) + } +} + @available(iOS 13.0.0, *) extension MXCryptoMachine: Logger { func log(logLine: String) { diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift index fef27a17b7..be6a14d7c2 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift @@ -59,4 +59,17 @@ protocol MXCryptoCrossSigning { func bootstrapCrossSigning(authParams: [AnyHashable: Any]) async throws } +@available(iOS 13.0.0, *) +protocol MXCryptoVerification { + func requestVerification(userId: String, roomId: String, methods: [String]) async throws -> VerificationRequest + func verificationRequest(userId: String, flowId: String) -> VerificationRequest? + + func verification(userId: String, flowId: String) -> Verification? + func beginSasVerification(userId: String, flowId: String) async throws -> Sas + func confirmVerification(userId: String, flowId: String) async throws + func cancelVerification(userId: String, flowId: String, cancelCode: String) async throws + + func emojiIndexes(sas: Sas) throws -> [Int] +} + #endif diff --git a/MatrixSDK/Crypto/MXCryptoV2.swift b/MatrixSDK/Crypto/MXCryptoV2.swift index b0a1b4985e..693ac84885 100644 --- a/MatrixSDK/Crypto/MXCryptoV2.swift +++ b/MatrixSDK/Crypto/MXCryptoV2.swift @@ -73,6 +73,9 @@ import MatrixSDKCrypto /// for crypto-related functionality can still run (and eventually pass) without any changes. @available(iOS 13.0.0, *) private class MXCryptoV2: MXCrypto { + enum Error: Swift.Error { + case missingRoom + } public override var deviceCurve25519Key: String! { return machine.deviceCurve25519Key @@ -93,8 +96,7 @@ private class MXCryptoV2: MXCrypto { } public override var keyVerificationManager: MXKeyVerificationManager! { - log.debug("Not implemented") - return MXKeyVerificationManager() + return keyVerification } public override var recoveryService: MXRecoveryService! { @@ -125,6 +127,7 @@ private class MXCryptoV2: MXCrypto { private let trustLevelSource: MXTrustLevelSource private let crossSign: MXCrossSigningV2 + private let keyVerification: MXKeyVerificationManagerV2 private let log = MXNamedLog(name: "MXCryptoV2") @@ -152,6 +155,17 @@ private class MXCryptoV2: MXCrypto { restClient: restClient ) + keyVerification = MXKeyVerificationManagerV2( + verification: machine, + getOrCreateDMRoomId: { [weak session] userId in + // Note: assuming that DM already exists, fail otherwise. Will be updated in future PR + guard let roomId = session?.directJoinedRoom(withUserId: userId)?.roomId else { + throw Error.missingRoom + } + return roomId + } + ) + super.init() } @@ -174,7 +188,7 @@ private class MXCryptoV2: MXCrypto { // MARK: - Start / close - public override func start(_ onComplete: (() -> Void)!, failure: ((Error?) -> Void)!) { + public override func start(_ onComplete: (() -> Void)!, failure: ((Swift.Error?) -> Void)!) { onComplete?() log.debug("Not implemented") } @@ -192,7 +206,7 @@ private class MXCryptoV2: MXCrypto { withType eventType: String!, in room: MXRoom!, success: (([AnyHashable : Any]?, String?) -> Void)!, - failure: ((Error?) -> Void)! + failure: ((Swift.Error?) -> Void)! ) -> MXHTTPOperation! { guard let content = eventContent, let eventType = eventType, let roomId = room?.roomId else { log.failure("Missing data to encrypt") @@ -265,7 +279,7 @@ private class MXCryptoV2: MXCrypto { public override func ensureEncryption( inRoom roomId: String!, success: (() -> Void)!, - failure: ((Error?) -> Void)! + failure: ((Swift.Error?) -> Void)! ) -> MXHTTPOperation! { guard let roomId = roomId, let room = session?.room(withRoomId: roomId) else { log.failure("Missing room") @@ -338,6 +352,7 @@ private class MXCryptoV2: MXCrypto { log.failure("Error processing outgoing requests", error: error) } } + keyVerification.updatePendingRequests() } // MARK: - Trust level @@ -361,7 +376,7 @@ private class MXCryptoV2: MXCrypto { public override func trustLevelSummary( forUserIds userIds: [String]!, success: ((MXUsersTrustLevelSummary?) -> Void)!, - failure: ((Error?) -> Void)! + failure: ((Swift.Error?) -> Void)! ) { guard let userIds = userIds else { log.failure("Missing user ids") @@ -399,7 +414,7 @@ private class MXCryptoV2: MXCrypto { return device(withDeviceId: deviceId, ofUser: userId) } - public override func setDeviceVerification(_ verificationStatus: MXDeviceVerification, forDevice deviceId: String!, ofUser userId: String!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { + public override func setDeviceVerification(_ verificationStatus: MXDeviceVerification, forDevice deviceId: String!, ofUser userId: String!, success: (() -> Void)!, failure: ((Swift.Error?) -> Void)!) { log.debug("Not implemented") } @@ -407,7 +422,7 @@ private class MXCryptoV2: MXCrypto { log.debug("Not implemented") } - public override func setUserVerification(_ verificationStatus: Bool, forUser userId: String!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { + public override func setUserVerification(_ verificationStatus: Bool, forUser userId: String!, success: (() -> Void)!, failure: ((Swift.Error?) -> Void)!) { log.debug("Not implemented") } @@ -419,7 +434,7 @@ private class MXCryptoV2: MXCrypto { _ userIds: [String]!, forceDownload: Bool, success: ((MXUsersDevicesMap?, [String: MXCrossSigningInfo]?) -> Void)!, - failure: ((Error?) -> Void)! + failure: ((Swift.Error?) -> Void)! ) -> MXHTTPOperation! { // Note: Download keys currently ignores the `forceDownload` flag and returns local data only success?( @@ -474,19 +489,19 @@ private class MXCryptoV2: MXCrypto { log.debug("Not implemented") } - public override func exportRoomKeys(_ success: (([[AnyHashable : Any]]?) -> Void)!, failure: ((Error?) -> Void)!) { + public override func exportRoomKeys(_ success: (([[AnyHashable : Any]]?) -> Void)!, failure: ((Swift.Error?) -> Void)!) { log.debug("Not implemented") } - public override func exportRoomKeys(withPassword password: String!, success: ((Data?) -> Void)!, failure: ((Error?) -> Void)!) { + public override func exportRoomKeys(withPassword password: String!, success: ((Data?) -> Void)!, failure: ((Swift.Error?) -> Void)!) { log.debug("Not implemented") } - public override func importRoomKeys(_ keys: [[AnyHashable : Any]]!, success: ((UInt, UInt) -> Void)!, failure: ((Error?) -> Void)!) { + public override func importRoomKeys(_ keys: [[AnyHashable : Any]]!, success: ((UInt, UInt) -> Void)!, failure: ((Swift.Error?) -> Void)!) { log.debug("Not implemented") } - public override func importRoomKeys(_ keyFile: Data!, withPassword password: String!, success: ((UInt, UInt) -> Void)!, failure: ((Error?) -> Void)!) { + public override func importRoomKeys(_ keyFile: Data!, withPassword password: String!, success: ((UInt, UInt) -> Void)!, failure: ((Swift.Error?) -> Void)!) { log.debug("Not implemented") } @@ -494,7 +509,7 @@ private class MXCryptoV2: MXCrypto { // Not implemented, handled automatically by CryptoMachine } - public override func accept(_ keyRequest: MXIncomingRoomKeyRequest!, success: (() -> Void)!, failure: ((Error?) -> Void)!) { + public override func accept(_ keyRequest: MXIncomingRoomKeyRequest!, success: (() -> Void)!, failure: ((Swift.Error?) -> Void)!) { log.debug("Not implemented") } diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m index e86cdd7f64..e200b96ca2 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m @@ -771,7 +771,14 @@ - (void)cancelTransaction:(id)transaction [self sendToOtherInTransaction:transaction eventType:kMXEventTypeStringKeyVerificationCancel content:cancel.JSONDictionary success:^{ - transaction.reasonCancelCode = code; + if ([transaction isKindOfClass:[MXDefaultKeyVerificationTransaction class]]) + { + ((MXDefaultKeyVerificationTransaction *)transaction).reasonCancelCode = code; + } + else + { + MXLogFailure(@"[MXKeyVerification] cancelTransaction: Cannot set cancellation reason on unknown transaction type: %@", NSStringFromClass([transaction class])) + } if (success) { @@ -1700,7 +1707,7 @@ - (void)removePendingRequestWithRequestId:(NSString*)requestId - (nullable NSDate*)oldestRequestDate { NSDate *oldestRequestDate; - for (id request in pendingRequestsMap.allValues) + for (MXDefaultKeyVerificationRequest *request in pendingRequestsMap.allValues) { if (!oldestRequestDate || request.timestamp < oldestRequestDate.timeIntervalSince1970) @@ -1711,7 +1718,7 @@ - (nullable NSDate*)oldestRequestDate return oldestRequestDate; } -- (BOOL)isRequestStillValid:(id)request +- (BOOL)isRequestStillValid:(MXDefaultKeyVerificationRequest *)request { NSDate *requestDate = [NSDate dateWithTimeIntervalSince1970:(request.timestamp / 1000)]; return (requestDate.timeIntervalSinceNow > -_requestTimeout); @@ -1759,7 +1766,7 @@ - (void)onRequestTimeoutTimer - (void)checkRequestTimeoutsWithCompletion:(dispatch_block_t)completionBlock { dispatch_group_t group = dispatch_group_create(); - for (id request in pendingRequestsMap.allValues) + for (MXDefaultKeyVerificationRequest *request in pendingRequestsMap.allValues) { if (![self isRequestStillValid:request]) { @@ -1859,7 +1866,7 @@ - (void)removeTransactionWithTransactionId:(NSString*)transactionId - (nullable NSDate*)oldestTransactionCreationDate { NSDate *oldestCreationDate; - for (id transaction in transactions.allObjects) + for (MXDefaultKeyVerificationTransaction *transaction in transactions.allObjects) { if (!oldestCreationDate || transaction.creationDate.timeIntervalSince1970 < oldestCreationDate.timeIntervalSince1970) @@ -1870,7 +1877,7 @@ - (nullable NSDate*)oldestTransactionCreationDate return oldestCreationDate; } -- (BOOL)isCreationDateValid:(id)transaction +- (BOOL)isCreationDateValid:(MXDefaultKeyVerificationTransaction *)transaction { return (transaction.creationDate.timeIntervalSinceNow > -MXTransactionTimeout); } @@ -1934,7 +1941,7 @@ - (void)onTransactionTimeoutTimer - (void)checkTransactionTimeouts { - for (id transaction in transactions.allObjects) + for (MXDefaultKeyVerificationTransaction *transaction in transactions.allObjects) { if (![self isCreationDateValid:transaction]) { diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift b/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift new file mode 100644 index 0000000000..0f13d14365 --- /dev/null +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift @@ -0,0 +1,238 @@ +// +// MXKeyVerificationManagerV2.swift +// MatrixSDK +// +// Created by Element on 05/07/2022. +// + +import Foundation + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +@available(iOS 13.0.0, *) +class MXKeyVerificationManagerV2: MXKeyVerificationManager { + typealias GetOrCreateDMRoomId = (_ userId: String) async throws -> String + + override var requestTimeout: TimeInterval { + set { + log.debug("Not implemented") + } + get { + log.debug("Not implemented") + return 1000 + } + } + + private let verification: MXCryptoVerification + private let getOrCreateDMRoomId: GetOrCreateDMRoomId + + private var requests: [MXKeyVerificationRequestV2] + private var transactions: [MXSASTransactionV2] + + private let log = MXNamedLog(name: "MXKeyVerificationManagerV2") + + init(verification: MXCryptoVerification, getOrCreateDMRoomId: @escaping GetOrCreateDMRoomId) { + self.verification = verification + self.getOrCreateDMRoomId = getOrCreateDMRoomId + + self.requests = [] + self.transactions = [] + + super.init() + } + + func updatePendingRequests() { + for request in requests { + guard let req = verification.verificationRequest(userId: request.otherUser, flowId: request.requestId) else { + log.debug("No request found for id \(request.requestId)") + continue + } + request.update(request: req) + } + + for transaction in transactions { + guard let verification = verification.verification(userId: transaction.otherUserId, flowId: transaction.transactionId) else { + log.debug("No transaction found for id \(transaction.transactionId)") + continue + } + guard case .sasV1(let sas) = verification else { + assertionFailure("Not implemented") + continue + } + transaction.update(sas: sas) + } + } + + override func requestVerificationByToDevice( + withUserId userId: String, + deviceIds: [String]?, + methods: [String], + success: @escaping (MXKeyVerificationRequest) -> Void, + failure: @escaping (Error) -> Void + ) { + log.debug("Not implemented") + success(MXDefaultKeyVerificationRequest()) + } + + override func requestVerificationByDM( + withUserId userId: String, + roomId: String?, + fallbackText: String, + methods: [String], + success: @escaping (MXKeyVerificationRequest) -> Void, + failure: @escaping (Error) -> Void + ) { + Task { + do { + let roomId = try await getOrCreateDMRoomId(userId) + let req = try await verification.requestVerification( + userId: userId, + roomId: roomId, + methods: methods + ) + let request = MXKeyVerificationRequestV2(request: req) { [weak self] request, code in + self?.cancel(request: request, code: code) + } + requests.append(request) + await MainActor.run { + success(request) + } + } catch { + log.error("Cannot request verification", error: error) + await MainActor.run { + failure(error) + } + } + } + } + + override var pendingRequests: [MXKeyVerificationRequest] { + return requests + } + + override func beginKeyVerification( + withUserId userId: String, + andDeviceId deviceId: String, + method: String, + success: @escaping (MXKeyVerificationTransaction) -> Void, + failure: @escaping (Error) -> Void + ) { + log.debug("Not implemented") + success(MXDefaultKeyVerificationTransaction()) + } + + override func beginKeyVerification( + from request: MXKeyVerificationRequest, + method: String, + success: @escaping (MXKeyVerificationTransaction) -> Void, + failure: @escaping (Error) -> Void + ) { + Task { + do { + let sas = try await verification.beginSasVerification(userId: request.otherUser, flowId: request.requestId) + let transaction = MXSASTransactionV2( + sas: sas, + getEmojisAction: { [weak self] in + self?.getEmojis(sas: $0) ?? [] + }, + confirmMatchAction: { [weak self] in + self?.confirm(transaction: $0) + }, + cancelAction: { [weak self] in + self?.cancel(transaction: $0, code: $1) + } + ) + transactions.append(transaction) + + await MainActor.run { + success(transaction) + } + } catch { + MXLog.error("[MXKeyVerificationRequestV2] error \(error)") + await MainActor.run { + failure(error) + } + } + } + } + + override func transactions(_ complete: @escaping ([MXKeyVerificationTransaction]) -> Void) { + complete(transactions) + } + + override func keyVerification( + fromKeyVerificationEvent event: MXEvent, + success: @escaping (MXKeyVerification) -> Void, + failure: @escaping (Error) -> Void + ) -> MXHTTPOperation? { + log.debug("Not implemented") + success(MXKeyVerification()) + return MXHTTPOperation() + } + + override func keyVerificationId(fromDMEvent event: MXEvent) -> String? { + log.debug("Not implemented") + return nil + } + + override func qrCodeTransaction(withTransactionId transactionId: String) -> MXQRCodeTransaction? { + log.debug("Not implemented") + return nil + } + + override func removeQRCodeTransaction(withTransactionId transactionId: String) { + log.debug("Not implemented") + } + + override func notifyOthersOfAcceptance(withTransactionId transactionId: String, acceptedUserId: String, acceptedDeviceId: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) { + log.debug("Not implemented") + success() + } + + private func getEmojis(sas: Sas) -> [MXEmojiRepresentation] { + do { + let indices = try verification.emojiIndexes(sas: sas) + let emojis = MXDefaultSASTransaction.allEmojiRepresentations() + return indices.compactMap { idx in + idx < emojis.count ? emojis[idx] : nil + } + } catch { + log.error("Cannot get emoji indices", error: error) + return [] + } + } + + private func cancel(request: MXKeyVerificationRequest, code: MXTransactionCancelCode) { + Task { + do { + try await verification.cancelVerification(userId: request.otherUser, flowId: request.requestId, cancelCode: code.value) + } catch { + log.error("Cannot cancel request", error: error) + } + } + } + + private func confirm(transaction: MXSASTransaction) { + Task { + do { + try await verification.confirmVerification(userId: transaction.otherUserId, flowId: transaction.transactionId) + } catch { + log.error("Cannot confirm transaction", error: error) + } + } + } + + private func cancel(transaction: MXSASTransaction, code: MXTransactionCancelCode) { + Task { + do { + try await verification.cancelVerification(userId: transaction.otherUserId, flowId: transaction.transactionId, cancelCode: code.value) + } catch { + log.error("Cannot cancel request", error: error) + } + } + } +} + +#endif diff --git a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.h b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.h index ac96bc45e7..78445fe6a9 100644 --- a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.h +++ b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.h @@ -68,39 +68,28 @@ Accept an incoming key verification request. failure:(void(^ _Nullable)(NSError *error))failure; /** - The cancellation reason, if any. + Current state of the request */ -@property (nonatomic, nullable) MXTransactionCancelCode *reasonCancelCode; - -// Current state @property (nonatomic, readonly) MXKeyVerificationRequestState state; -// Original data for this request -@property (nonatomic, readonly) MXEvent *event; +/** + The cancellation reason, if state is cancelled + */ +@property (nonatomic, readonly, nullable) MXTransactionCancelCode *reasonCancelCode; // Is it a request made by our user? @property (nonatomic, readonly) BOOL isFromMyUser; @property (nonatomic, readonly) BOOL isFromMyDevice; - // Shortcuts to the original request @property (nonatomic, readonly) NSString *requestId; @property (nonatomic, readonly) MXKeyVerificationTransport transport; -@property (nonatomic, readonly) NSString *fromDevice; -@property (nonatomic, readonly) uint64_t timestamp; @property (nonatomic, readonly) NSArray *methods; // The other party @property (nonatomic, readonly) NSString *otherUser; @property (nonatomic, readonly, nullable) NSString *otherDevice; // This is unknown and nil while the request has not been accepted - -// Original data from the accepted (aka m.verification.ready) event -@property (nonatomic, readonly, nullable) MXKeyVerificationReady *acceptedData; - -// Shortcuts to the accepted event -@property (nonatomic, readonly, nullable) NSArray *acceptedMethods; - // Shortcuts of methods according to the point of view @property (nonatomic, readonly, nullable) NSArray *myMethods; @property (nonatomic, readonly, nullable) NSArray *otherMethods; @@ -112,6 +101,17 @@ Accept an incoming key verification request. */ @interface MXDefaultKeyVerificationRequest : NSObject +// Original data for this request +@property (nonatomic, readonly) MXEvent *event; + +// Shortcuts to the accepted event +@property (nonatomic, readonly) NSString *fromDevice; +@property (nonatomic, readonly) uint64_t timestamp; + +// Original data from the accepted (aka m.verification.ready) event +@property (nonatomic, readonly, nullable) MXKeyVerificationReady *acceptedData; +@property (nonatomic, readonly, nullable) NSArray *acceptedMethods; + @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.m b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.m index aeea57bf9d..09d7d84eec 100644 --- a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.m +++ b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest.m @@ -20,6 +20,7 @@ #import "MXCrypto_Private.h" +#warning File has not been annotated with nullability, see MX_ASSUME_MISSING_NULLABILITY_BEGIN #pragma mark - Constants NSString * const MXKeyVerificationRequestDidChangeNotification = @"MXKeyVerificationRequestDidChangeNotification"; diff --git a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift new file mode 100644 index 0000000000..644f7eb57d --- /dev/null +++ b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift @@ -0,0 +1,128 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +/// Verification request originating from `MatrixSDKCrypto` +class MXKeyVerificationRequestV2: NSObject, MXKeyVerificationRequest { + typealias CancelAction = (MXKeyVerificationRequest, MXTransactionCancelCode) -> Void + + var state: MXKeyVerificationRequestState { + // State as enum will be moved to MatrixSDKCrypto in the future + // to avoid the mapping of booleans into state + if request.isDone { + return MXKeyVerificationRequestStateAccepted + } else if request.isCancelled { + return MXKeyVerificationRequestStateCancelled + } else if request.isReady { + return MXKeyVerificationRequestStateReady + } else if request.isPassive { + return MXKeyVerificationRequestStatePending + } + return MXKeyVerificationRequestStatePending + } + + var reasonCancelCode: MXTransactionCancelCode? { + guard let info = request.cancelInfo else { + return nil + } + return .init( + value: info.cancelCode, + humanReadable: info.reason + ) + } + + var isFromMyUser: Bool { + return request.weStarted + } + + var isFromMyDevice: Bool { + // Not exposed on the underlying request, + // assuming that if request is from us, it is from our devide + log.debug("Not fully implemented") + return isFromMyUser + } + + var requestId: String { + return request.flowId + } + + var transport: MXKeyVerificationTransport { + log.debug("Not fully implemented") + return .directMessage + } + + var otherUser: String { + return request.otherUserId + } + + var otherDevice: String? { + return request.otherDeviceId + } + + var methods: [String] { + return (isFromMyUser ? myMethods : otherMethods) ?? [] + } + + var myMethods: [String]? { + return request.ourMethods + } + + var otherMethods: [String]? { + return request.theirMethods + } + + private var request: VerificationRequest + private let cancelAction: CancelAction + + private let log = MXNamedLog(name: "MXKeyVerificationRequestV2") + + init(request: VerificationRequest, cancelAction: @escaping CancelAction) { + self.request = request + self.cancelAction = cancelAction + } + + func update(request: VerificationRequest) { + guard self.request != request else { + return + } + self.request = request + NotificationCenter.default.post(name: .MXKeyVerificationRequestDidChange, object: self) + } + + func accept( + withMethods methods: [String], + success: @escaping () -> Void, + failure: @escaping (Error) -> Void + ) { + log.debug("Not implemented") + } + + func cancel( + with code: MXTransactionCancelCode, + success: (() -> Void)?, + failure: ((Error) -> Void)? = nil + ) { + cancelAction(self, code) + success?() + } +} + +#endif diff --git a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest_Private.h b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest_Private.h index c3462a138c..eb990ab878 100644 --- a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest_Private.h +++ b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequest_Private.h @@ -19,6 +19,8 @@ #import "MXKeyVerificationReady.h" #import "MXKeyVerificationCancel.h" +MX_ASSUME_MISSING_NULLABILITY_BEGIN + @class MXKeyVerificationManager, MXHTTPOperation; @@ -31,6 +33,7 @@ - (instancetype)initWithEvent:(MXEvent*)event andManager:(MXKeyVerificationManager*)manager; +@property (nonatomic, nullable) MXTransactionCancelCode *reasonCancelCode; @property (nonatomic) BOOL isFromMyUser; @property (nonatomic) BOOL isFromMyDevice; @@ -42,3 +45,5 @@ - (void)handleCancel:(MXKeyVerificationCancel*)cancelContent; @end + +MX_ASSUME_MISSING_NULLABILITY_END diff --git a/MatrixSDK/Crypto/Verification/Transactions/MXKeyVerificationTransaction.h b/MatrixSDK/Crypto/Verification/Transactions/MXKeyVerificationTransaction.h index bf928b0201..78375f2f93 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/MXKeyVerificationTransaction.h +++ b/MatrixSDK/Crypto/Verification/Transactions/MXKeyVerificationTransaction.h @@ -53,17 +53,7 @@ typedef NS_ENUM(NSInteger, MXKeyVerificationTransport) { /** YES for an incoming verification request. */ -@property (nonatomic) BOOL isIncoming; - -/** - The creation date. - */ -@property (nonatomic, strong) NSDate *creationDate; - -/** - The other user device. - */ -@property (nonatomic, readonly) MXDeviceInfo *otherDevice; +@property (nonatomic, readonly) BOOL isIncoming; /** The other user id. @@ -78,12 +68,17 @@ typedef NS_ENUM(NSInteger, MXKeyVerificationTransport) { /** The cancellation reason, if any. */ -@property (nonatomic, nullable) MXTransactionCancelCode *reasonCancelCode; +@property (nonatomic, readonly, nullable) MXTransactionCancelCode *reasonCancelCode; /** The occured error (like network error), if any. */ -@property (nonatomic, nullable) NSError *error; +@property (nonatomic, readonly, nullable) NSError *error; + +#pragma mark Direct message + +@property (nonatomic, nullable, readonly) NSString *dmRoomId; +@property (nonatomic, nullable, readonly) NSString *dmEventId; /** Cancel this transaction. @@ -105,10 +100,6 @@ typedef NS_ENUM(NSInteger, MXKeyVerificationTransport) { #pragma mark - Transport layer -#pragma mark Direct message - -@property (nonatomic, nullable, readonly) NSString *dmRoomId; -@property (nonatomic, nullable, readonly) NSString *dmEventId; @end @@ -117,6 +108,25 @@ typedef NS_ENUM(NSInteger, MXKeyVerificationTransport) { */ @interface MXDefaultKeyVerificationTransaction: NSObject +/** + The creation date. + */ +@property (nonatomic, strong) NSDate *creationDate; + +@property (nonatomic) BOOL isIncoming; + +/** + The other user device. + */ +@property (nonatomic, readonly) MXDeviceInfo *otherDevice; + +@property (nonatomic, nullable) MXTransactionCancelCode *reasonCancelCode; + +/** + The occured error (like network error), if any. + */ +@property (nonatomic, nullable) NSError *error; + @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.h b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.h index aa0f8e1a0e..96e187b4c3 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.h +++ b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.h @@ -50,23 +50,18 @@ typedef enum : NSUInteger */ @protocol MXSASTransaction -@property (nonatomic) MXSASTransactionState state; +@property (nonatomic, readonly) MXSASTransactionState state; /** - The Short Authentication Code bytes data. + `self.sasBytes` represented by a 7 emojis string. */ -@property (nonatomic, nullable) NSData *sasBytes; +@property (nonatomic, readonly, nullable) NSArray *sasEmoji; /** `self.sasBytes` represented by a three 4-digit numbers string. */ @property (nonatomic, readonly, nullable) NSString *sasDecimal; -/** - `self.sasBytes` represented by a 7 emojis string. - */ -@property (nonatomic, readonly, nullable) NSArray *sasEmoji; - /** To be called by the app when the user confirms that the SAS matches with the SAS displayed on the other user device. @@ -79,6 +74,14 @@ typedef enum : NSUInteger Default implementation of SAS transaction used by the SDK */ @interface MXDefaultSASTransaction : MXDefaultKeyVerificationTransaction + ++ (NSArray *)allEmojiRepresentations; + +/** + The Short Authentication Code bytes data. + */ +@property (nonatomic, nullable) NSData *sasBytes; + @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m index 7daefee12f..1367085bf4 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m +++ b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction.m @@ -567,6 +567,11 @@ + (void)initializeSasEmojis ]; } ++ (NSArray *)allEmojiRepresentations +{ + return kSasEmojis; +} + + (NSArray *)emojiRepresentationForSas:(NSData*)sas { UInt8 *sasBytes = (UInt8 *)sas.bytes; diff --git a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift new file mode 100644 index 0000000000..fea7b33e86 --- /dev/null +++ b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift @@ -0,0 +1,139 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +/// SAS transaction originating from `MatrixSDKCrypto` +class MXSASTransactionV2: NSObject, MXSASTransaction { + typealias GetEmojisAction = (Sas) -> [MXEmojiRepresentation] + typealias ConfirmMatchAction = (MXSASTransaction) -> Void + typealias CancelAction = (MXSASTransaction, MXTransactionCancelCode) -> Void + + var state: MXSASTransactionState { + // State as enum will be moved to MatrixSDKCrypto in the future + // to avoid the mapping of booleans into state + if sas.isDone { + return MXSASTransactionStateVerified + } else if sas.isCancelled { + return MXSASTransactionStateCancelled + } else if sas.canBePresented { + return MXSASTransactionStateShowSAS + } else if sas.hasBeenAccepted && !sas.haveWeConfirmed { + return MXSASTransactionStateIncomingShowAccept + } else if sas.haveWeConfirmed { + return MXSASTransactionStateOutgoingWaitForPartnerToAccept + } + return MXSASTransactionStateUnknown + } + + var sasEmoji: [MXEmojiRepresentation]? { + return getEmojisAction(sas) + } + + var sasDecimal: String? { + log.debug("Not implemented") + return nil + } + + var transactionId: String { + return sas.flowId + } + + var transport: MXKeyVerificationTransport { + log.debug("Not fully implemented") + return .directMessage + } + + var isIncoming: Bool { + return !sas.weStarted + } + + var otherUserId: String { + return sas.otherUserId + } + + var otherDeviceId: String { + return sas.otherDeviceId + } + + var reasonCancelCode: MXTransactionCancelCode? { + guard let info = sas.cancelInfo else { + return nil + } + return MXTransactionCancelCode( + value: info.cancelCode, + humanReadable: info.reason + ) + } + + var error: Error? { + return nil + } + + var dmRoomId: String? { + return sas.roomId + } + + var dmEventId: String? { + return transactionId + } + + private var sas: Sas + private let getEmojisAction: GetEmojisAction + private let confirmMatchAction: ConfirmMatchAction + private let cancelAction: CancelAction + + private let log = MXNamedLog(name: "MXSASTransactionV2") + + init( + sas: Sas, + getEmojisAction: @escaping GetEmojisAction, + confirmMatchAction: @escaping ConfirmMatchAction, + cancelAction: @escaping CancelAction + ) { + self.sas = sas + self.getEmojisAction = getEmojisAction + self.confirmMatchAction = confirmMatchAction + self.cancelAction = cancelAction + } + + func update(sas: Sas) { + guard self.sas != sas else { + return + } + self.sas = sas + NotificationCenter.default.post(name: .MXKeyVerificationTransactionDidChange, object: self) + } + + func confirmSASMatch() { + confirmMatchAction(self) + } + + func cancel(with code: MXTransactionCancelCode) { + cancelAction(self, code) + } + + func cancel(with code: MXTransactionCancelCode, success: @escaping () -> Void, failure: @escaping (Error) -> Void) { + cancelAction(self, code) + success() + } +} + +#endif diff --git a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction_Private.h b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction_Private.h index 39cc5f78e7..5da4fec914 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction_Private.h +++ b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransaction_Private.h @@ -39,6 +39,7 @@ FOUNDATION_EXPORT NSArray *kKnownShortCodes; */ @interface MXDefaultSASTransaction () +@property (nonatomic) MXSASTransactionState state; @property (nonatomic) OLMSAS *olmSAS; @property (nonatomic, nullable) MXSASKeyVerificationStart *startContent; @property (nonatomic) MXKeyVerificationAccept *accepted; diff --git a/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift new file mode 100644 index 0000000000..7e9a6d8003 --- /dev/null +++ b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift @@ -0,0 +1,140 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto +@testable import MatrixSDK + +class MXKeyVerificationRequestV2UnitTests: XCTestCase { + func test_usesCorrectProperties() { + let stub = VerificationRequest.stub( + otherUserId: "Bob", + otherDeviceId: "Device2", + flowId: "123", + weStarted: true, + theirMethods: ["sas", "qr"], + ourMethods: ["sas", "unknown"] + ) + + let request = MXKeyVerificationRequestV2( + request: stub, + cancelAction: { _, _ in } + ) + + XCTAssertTrue(request.isFromMyUser) + XCTAssertTrue(request.isFromMyDevice) + XCTAssertEqual(request.requestId, "123") + XCTAssertEqual(request.transport, MXKeyVerificationTransport.directMessage) + XCTAssertEqual(request.otherUser, "Bob") + XCTAssertEqual(request.otherDevice, "Device2") + XCTAssertEqual(request.methods, ["sas", "unknown"]) + XCTAssertEqual(request.myMethods, ["sas", "unknown"]) + XCTAssertEqual(request.otherMethods, ["sas", "qr"]) + } + + func test_state() { + let testCases: [(VerificationRequest, MXKeyVerificationRequestState)] = [ + (.stub( + isReady: false, + isPassive: false, + isDone: false, + isCancelled: false + ), MXKeyVerificationRequestStatePending), + (.stub( + isReady: false, + isPassive: false, + isDone: true, + isCancelled: false + ), MXKeyVerificationRequestStateAccepted), + (.stub( + isReady: true, + isPassive: false, + isDone: false, + isCancelled: false + ), MXKeyVerificationRequestStateReady), + (.stub( + isReady: false, + isPassive: false, + isDone: false, + isCancelled: true + ), MXKeyVerificationRequestStateCancelled), + (.stub( + isReady: false, + isPassive: true, + isDone: false, + isCancelled: false + ), MXKeyVerificationRequestStatePending), + (.stub( + isReady: true, + isPassive: true, + isDone: true, + isCancelled: true + ), MXKeyVerificationRequestStateAccepted), + (.stub( + isReady: true, + isPassive: true, + isDone: false, + isCancelled: true + ), MXKeyVerificationRequestStateCancelled), + ] + + for (stub, state) in testCases { + let request = MXKeyVerificationRequestV2( + request: stub, + cancelAction: { _, _ in } + ) + XCTAssertEqual(request.state, state) + } + } + + func test_reasonCancelCode() { + let cancelInfo = CancelInfo( + cancelCode: "123", + reason: "Changed mind", + cancelledByUs: true + ) + + let request = MXKeyVerificationRequestV2( + request: .stub(cancelInfo: cancelInfo), + cancelAction: { _, _ in } + ) + + XCTAssertEqual(request.reasonCancelCode?.value, "123") + XCTAssertEqual(request.reasonCancelCode?.humanReadable, "Changed mind") + } + + func test_update_postsNotification_ifChanged() { + let exp = expectation(description: "exp") + let request = MXKeyVerificationRequestV2( + request: .stub(isReady: false), + cancelAction: { _, _ in } + ) + NotificationCenter.default.addObserver(forName: .MXKeyVerificationRequestDidChange, object: request, queue: OperationQueue.main) { notif in + XCTAssertEqual(request.state, MXKeyVerificationRequestStateReady) + exp.fulfill() + } + + request.update(request: .stub(isReady: true)) + + waitForExpectations(timeout: 1) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/Verification/Requests/VerificationRequest+Stub.swift b/MatrixSDKTests/Crypto/Verification/Requests/VerificationRequest+Stub.swift new file mode 100644 index 0000000000..499c0c47d0 --- /dev/null +++ b/MatrixSDKTests/Crypto/Verification/Requests/VerificationRequest+Stub.swift @@ -0,0 +1,55 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +extension VerificationRequest { + static func stub( + otherUserId: String = "Bob", + otherDeviceId: String = "Device2", + flowId: String = "123", + roomId: String = "ABC", + weStarted: Bool = true, + isReady: Bool = false, + isPassive: Bool = false, + isDone: Bool = false, + isCancelled: Bool = false, + cancelInfo: CancelInfo? = nil, + theirMethods: [String] = ["sas"], + ourMethods: [String] = ["sas"] + ) -> VerificationRequest { + return .init( + otherUserId: otherUserId, + otherDeviceId: otherDeviceId, + flowId: flowId, + roomId: roomId, + weStarted: weStarted, + isReady: isReady, + isPassive: isPassive, + isDone: isDone, + isCancelled: isCancelled, + cancelInfo: cancelInfo, + theirMethods: theirMethods, + ourMethods: ourMethods + ) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift new file mode 100644 index 0000000000..16c1c76af8 --- /dev/null +++ b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift @@ -0,0 +1,180 @@ +// +// Copyright 2022 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 + +#if os(iOS) + +import MatrixSDKCrypto +@testable import MatrixSDK + +class MXSASTransactionV2UnitTests: XCTestCase { + func test_usesCorrectProperties() { + let stub = Sas.stub( + otherUserId: "Bob", + otherDeviceId: "Device2", + flowId: "123", + roomId: "ABC", + weStarted: true, + supportsEmoji: true + ) + + let transaction = MXSASTransactionV2( + sas: stub, + getEmojisAction: { _ in [] }, + confirmMatchAction: { _ in }, + cancelAction: { _, _ in } + ) + + XCTAssertEqual(transaction.transactionId, "123") + XCTAssertEqual(transaction.transport, MXKeyVerificationTransport.directMessage) + XCTAssertFalse(transaction.isIncoming) + XCTAssertEqual(transaction.otherUserId, "Bob") + XCTAssertEqual(transaction.otherDeviceId, "Device2") + XCTAssertEqual(transaction.dmRoomId, "ABC") + XCTAssertEqual(transaction.dmEventId, "123") + } + + func test_state() { + let testCases: [(Sas, MXSASTransactionState)] = [ + (.stub( + hasBeenAccepted: false, + canBePresented: false, + haveWeConfirmed: false, + isDone: false, + isCancelled: false + ), MXSASTransactionStateUnknown), + (.stub( + hasBeenAccepted: false, + canBePresented: false, + haveWeConfirmed: false, + isDone: true, + isCancelled: false + ), MXSASTransactionStateVerified), + (.stub( + hasBeenAccepted: false, + canBePresented: false, + haveWeConfirmed: false, + isDone: false, + isCancelled: true + ), MXSASTransactionStateCancelled), + (.stub( + hasBeenAccepted: false, + canBePresented: true, + haveWeConfirmed: false, + isDone: false, + isCancelled: false + ), MXSASTransactionStateShowSAS), + (.stub( + hasBeenAccepted: true, + canBePresented: false, + haveWeConfirmed: false, + isDone: false, + isCancelled: false + ), MXSASTransactionStateIncomingShowAccept), + (.stub( + hasBeenAccepted: false, + canBePresented: false, + haveWeConfirmed: true, + isDone: false, + isCancelled: false + ), MXSASTransactionStateOutgoingWaitForPartnerToAccept), + ] + + for (stub, state) in testCases { + let transaction = MXSASTransactionV2( + sas: stub, + getEmojisAction: { _ in [] }, + confirmMatchAction: { _ in }, + cancelAction: { _, _ in } + ) + XCTAssertEqual(transaction.state, state) + } + } + + func test_reasonCancelCode() { + let cancelInfo = CancelInfo( + cancelCode: "123", + reason: "Changed mind", + cancelledByUs: true + ) + + let transaction = MXSASTransactionV2( + sas: .stub(cancelInfo: cancelInfo), + getEmojisAction: { _ in [] }, + confirmMatchAction: { _ in }, + cancelAction: { _, _ in } + ) + + XCTAssertEqual(transaction.reasonCancelCode?.value, "123") + XCTAssertEqual(transaction.reasonCancelCode?.humanReadable, "Changed mind") + } + + func test_update_postsNotification_ifChanged() { + let exp = expectation(description: "exp") + let transaction = MXSASTransactionV2( + sas: .stub(isDone: false), + getEmojisAction: { _ in [] }, + confirmMatchAction: { _ in }, + cancelAction: { _, _ in } + ) + NotificationCenter.default.addObserver(forName: .MXKeyVerificationTransactionDidChange, object: transaction, queue: OperationQueue.main) { notif in + XCTAssertEqual(transaction.state, MXSASTransactionStateVerified) + exp.fulfill() + } + + transaction.update(sas: .stub(isDone: true)) + + waitForExpectations(timeout: 1) + } + + func test_sasEmoji_picksCorrectEmoji() { + let emoji = [ + MXEmojiRepresentation(emoji: "A", andName: "A"), + MXEmojiRepresentation(emoji: "B", andName: "B"), + MXEmojiRepresentation(emoji: "C", andName: "C"), + ] + + let transaction = MXSASTransactionV2( + sas: .stub(), + getEmojisAction: { _ in emoji }, + confirmMatchAction: { _ in }, + cancelAction: { _, _ in } + ) + + XCTAssertEqual(transaction.sasEmoji, emoji) + } + + func test_confirmSASMatch() { + let exp = expectation(description: "exp") + let transaction = MXSASTransactionV2( + sas: .stub(), + getEmojisAction: { _ in [] }, + confirmMatchAction: { _ in + XCTAssertTrue(true) + exp.fulfill() + }, + cancelAction: { _, _ in } + ) + + transaction.confirmSASMatch() + + waitForExpectations(timeout: 1) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/Sas+Stub.swift b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/Sas+Stub.swift new file mode 100644 index 0000000000..a9a10e034d --- /dev/null +++ b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/Sas+Stub.swift @@ -0,0 +1,55 @@ +// +// Copyright 2022 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 + +#if DEBUG && os(iOS) + +import MatrixSDKCrypto + +extension Sas { + static func stub( + otherUserId: String = "Bob", + otherDeviceId: String = "Device2", + flowId: String = "123", + roomId: String = "ABC", + weStarted: Bool = true, + hasBeenAccepted: Bool = false, + canBePresented: Bool = false, + supportsEmoji: Bool = true, + haveWeConfirmed: Bool = false, + isDone: Bool = false, + isCancelled: Bool = false, + cancelInfo: CancelInfo? = nil + ) -> Sas { + return .init( + otherUserId: otherUserId, + otherDeviceId: otherDeviceId, + flowId: flowId, + roomId: roomId, + weStarted: weStarted, + hasBeenAccepted: hasBeenAccepted, + canBePresented: canBePresented, + supportsEmoji: supportsEmoji, + haveWeConfirmed: haveWeConfirmed, + isDone: isDone, + isCancelled: isCancelled, + cancelInfo: cancelInfo + ) + } +} + +#endif diff --git a/changelog.d/6443.feature b/changelog.d/6443.feature new file mode 100644 index 0000000000..8bd8a86a23 --- /dev/null +++ b/changelog.d/6443.feature @@ -0,0 +1 @@ +CryptoSDK: Outgoing SAS User Verification Flow From 175d5a08afadaf9b9e7f13a246278c921e92f260 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 22 Aug 2022 11:17:53 +0100 Subject: [PATCH 40/65] Update README with correct Swift usage. --- README.rst | 6 ------ changelog.d/sdk-1552.doc | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) create mode 100644 changelog.d/sdk-1552.doc diff --git a/README.rst b/README.rst index 920e168fa1..750e012879 100644 --- a/README.rst +++ b/README.rst @@ -23,21 +23,15 @@ In order to set this up:: The best way to add the last release of the Matrix SDK to your application project is to add the MatrixSDK dependency to your Podfile:: - # Obj-C pod 'MatrixSDK' If you want to use the develop version of the SDK, use instead: - # Obj-C pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop' Options ======= -If you want also Swift support, add the following pod to your app Podfile:: - - pod 'MatrixSDK/SwiftSupport' - If you want to enable VoIP using the http://webrtc.org VoIP stack, add the following pod to your app Podfile:: pod 'MatrixSDK/JingleCallStack' diff --git a/changelog.d/sdk-1552.doc b/changelog.d/sdk-1552.doc new file mode 100644 index 0000000000..62f2912797 --- /dev/null +++ b/changelog.d/sdk-1552.doc @@ -0,0 +1 @@ +Update README for correct Swift usage. From 62ec1ecc39e7a63c03b2edeef23db3a8fa2859ad Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 22 Aug 2022 11:47:05 +0100 Subject: [PATCH 41/65] Fix setting a log level of .none. --- MatrixSDK/Utils/MXLog.swift | 1 + changelog.d/sdk-1550.build | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog.d/sdk-1550.build diff --git a/MatrixSDK/Utils/MXLog.swift b/MatrixSDK/Utils/MXLog.swift index 1c53f3c477..3a7755bfb4 100644 --- a/MatrixSDK/Utils/MXLog.swift +++ b/MatrixSDK/Utils/MXLog.swift @@ -155,6 +155,7 @@ private var logger: SwiftyBeaver.Type = { sizeLimit: configuration.logFilesSizeLimit) guard configuration.logLevel != .none else { + logger.removeAllDestinations() return } diff --git a/changelog.d/sdk-1550.build b/changelog.d/sdk-1550.build new file mode 100644 index 0000000000..b99823f7d3 --- /dev/null +++ b/changelog.d/sdk-1550.build @@ -0,0 +1 @@ +MXLog: Ensure MXLogLevel.none works if it is set after another log level has already been configured. From 40445ca11ece9f47d80aaeb0b7a9459ae1ec63bc Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 22 Aug 2022 10:20:36 +0100 Subject: [PATCH 42/65] Track all errors in Sentry --- .../MXBeaconAggregations.swift | 8 +- .../Realm/MXBeaconInfoSummaryRealmStore.swift | 12 +- .../MXAggregatedReactionsUpdater.m | 4 +- .../Background/MXBackgroundSyncService.swift | 5 +- .../CrossSigning/MXCrossSigningV2.swift | 4 +- .../CryptoMachine/MXCryptoMachine.swift | 10 +- .../MXRealmCryptoStore/MXRealmCryptoStore.m | 14 +- .../Crypto/Dehydration/MXDehydrationService.m | 20 ++- .../Data/Aes256/MXAes256KeyBackupAlgorithm.m | 4 +- .../MXCurve25519KeyBackupAlgorithm.m | 4 +- MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m | 9 +- MatrixSDK/Crypto/MXCrypto.m | 77 ++++++++--- MatrixSDK/Crypto/MXCryptoV2.swift | 14 +- .../Verification/MXKeyVerificationManager.m | 3 +- .../MXKeyVerificationManagerV2.swift | 12 +- .../EventTimeline/Room/MXRoomEventTimeline.m | 4 +- .../Thread/MXThreadEventTimeline.swift | 5 +- MatrixSDK/Data/MXRoom.m | 8 +- MatrixSDK/Data/MXRoomState.m | 6 +- MatrixSDK/Data/MXRoomSummary.m | 8 +- .../MXSuggestedRoomListDataFetcher.swift | 2 +- .../MXCoreDataRoomListDataFetcher.swift | 6 +- .../MXStore/MXStoreRoomListDataFetcher.swift | 4 +- .../CoreData/MXCoreDataRoomSummaryStore.swift | 16 +-- .../CoreData/Models/MXRoomSummaryMO.swift | 6 +- .../File/MXFileRoomSummaryStore.m | 6 +- .../Data/Store/MXFileStore/MXFileStore.m | 24 ++-- .../MXHomeServerCapabilitiesService.swift | 2 +- MatrixSDK/MXRestClient.m | 4 +- MatrixSDK/MXSession.m | 55 ++++++-- MatrixSDK/Space/MXSpaceFileStore.swift | 4 +- MatrixSDK/Space/MXSpaceGraphData.swift | 14 +- MatrixSDK/Threads/MXThreadingService.swift | 2 +- .../Utils/Categories/FileManager+Backup.swift | 6 +- MatrixSDK/Utils/{ => Logs}/MXLog.h | 18 +-- MatrixSDK/Utils/{ => Logs}/MXLog.swift | 127 ++++++++++-------- MatrixSDK/Utils/{ => Logs}/MXLogObjcWrapper.h | 4 +- MatrixSDK/Utils/{ => Logs}/MXLogObjcWrapper.m | 8 +- MatrixSDK/Utils/{ => Logs}/MXLogger.h | 0 MatrixSDK/Utils/{ => Logs}/MXLogger.m | 4 +- MatrixSDK/Utils/MXServerNotices.m | 6 +- MatrixSDK/VoIP/MXCall.m | 72 ++++++---- MatrixSDK/VoIP/MXiOSAudioOutputRouter.swift | 2 +- 43 files changed, 394 insertions(+), 229 deletions(-) rename MatrixSDK/Utils/{ => Logs}/MXLog.h (63%) rename MatrixSDK/Utils/{ => Logs}/MXLog.swift (68%) rename MatrixSDK/Utils/{ => Logs}/MXLogObjcWrapper.h (79%) rename MatrixSDK/Utils/{ => Logs}/MXLogObjcWrapper.m (74%) rename MatrixSDK/Utils/{ => Logs}/MXLogger.h (100%) rename MatrixSDK/Utils/{ => Logs}/MXLogger.m (99%) diff --git a/MatrixSDK/Aggregations/LocationSharing/MXBeaconAggregations.swift b/MatrixSDK/Aggregations/LocationSharing/MXBeaconAggregations.swift index 943370228f..10d4b8fa24 100644 --- a/MatrixSDK/Aggregations/LocationSharing/MXBeaconAggregations.swift +++ b/MatrixSDK/Aggregations/LocationSharing/MXBeaconAggregations.swift @@ -165,7 +165,7 @@ public class MXBeaconAggregations: NSObject { room.redactEvent(relationEvent.eventId, reason: nil) { response in if case .failure(let error) = response { - MXLog.error("[MXBeaconAggregations] Failed to redact m.beacon event with error: \(error)") + MXLog.error("[MXBeaconAggregations] Failed to redact m.beacon event", context: error) } } } @@ -182,7 +182,7 @@ public class MXBeaconAggregations: NSObject { // Redact stopped beacon info room.redactEvent(eventId, reason: nil) { response in if case .failure(let error) = response { - MXLog.error("[MXBeaconAggregations] Failed to redact stopped m.beacon_info event with error: \(error)") + MXLog.error("[MXBeaconAggregations] Failed to redact stopped m.beacon_info event", context: error) } } } @@ -258,7 +258,9 @@ public class MXBeaconAggregations: NSObject { existingBeaconInfoSummary.updateWithBeaconInfo(beaconInfo) beaconInfoSummary = existingBeaconInfoSummary } else { - MXLog.error("[MXBeaconAggregations] Fails to find beacon info summary associated to stopped beacon info event id: \(eventId)") + MXLog.error("[MXBeaconAggregations] Fails to find beacon info summary associated to stopped beacon info", context: [ + "event_id": eventId + ]) } } else if let existingBeaconInfoSummary = self.getBeaconInfoSummary(withIdentifier: eventId, inRoomWithId: roomId) { diff --git a/MatrixSDK/Aggregations/LocationSharing/Store/Realm/MXBeaconInfoSummaryRealmStore.swift b/MatrixSDK/Aggregations/LocationSharing/Store/Realm/MXBeaconInfoSummaryRealmStore.swift index 1c75c793fe..a67ca8d1d5 100644 --- a/MatrixSDK/Aggregations/LocationSharing/Store/Realm/MXBeaconInfoSummaryRealmStore.swift +++ b/MatrixSDK/Aggregations/LocationSharing/Store/Realm/MXBeaconInfoSummaryRealmStore.swift @@ -80,7 +80,7 @@ public class MXBeaconInfoSummaryRealmStore: NSObject { return realm } catch { - MXLog.error("[MXBeaconInfoSummaryRealmStore] failed to create Realm store with error: \(error)") + MXLog.error("[MXBeaconInfoSummaryRealmStore] failed to create Realm store", context: error) return nil } } @@ -132,7 +132,7 @@ public class MXBeaconInfoSummaryRealmStore: NSObject { do { try FileManager.default.createDirectory(at: realmFileFolderURL, withIntermediateDirectories: true, attributes: nil) } catch { - MXLog.error("[MXBeaconInfoSummaryRealmStore] Fail to create Realm folder \(realmFileFolderURL) with error: \(error)") + MXLog.error("[MXBeaconInfoSummaryRealmStore] Fail to create Realm folder", context: error) throw error } @@ -182,7 +182,7 @@ extension MXBeaconInfoSummaryRealmStore: MXBeaconInfoSummaryStoreProtocol { realm.addOrUpdate(realmBeaconInfoSummary) } } catch { - MXLog.error("[MXBeaconInfoSummaryRealmStore] addOrUpdateBeaconInfoSummary failed with error: \(error)") + MXLog.error("[MXBeaconInfoSummaryRealmStore] addOrUpdateBeaconInfoSummary failed", context: error) } } @@ -289,7 +289,7 @@ extension MXBeaconInfoSummaryRealmStore: MXBeaconInfoSummaryStoreProtocol { realm.deleteObjects(realmBeaconInfoSummaries) } } catch { - MXLog.error("[MXBeaconInfoSummaryRealmStore] deleteAllBeaconInfoSummaries failed with error: \(error)") + MXLog.error("[MXBeaconInfoSummaryRealmStore] deleteAllBeaconInfoSummaries failed", context: error) } } @@ -305,7 +305,7 @@ extension MXBeaconInfoSummaryRealmStore: MXBeaconInfoSummaryStoreProtocol { realm.deleteObjects(realmBeaconInfoSummaries) } } catch { - MXLog.error("[MXBeaconInfoSummaryRealmStore] deleteAllBeaconInfoSummaries failed with error: \(error)") + MXLog.error("[MXBeaconInfoSummaryRealmStore] deleteAllBeaconInfoSummaries failed", context: error) } } @@ -320,7 +320,7 @@ extension MXBeaconInfoSummaryRealmStore: MXBeaconInfoSummaryStoreProtocol { realm.deleteAllObjects() } } catch { - MXLog.error("[MXBeaconInfoSummaryRealmStore] Failed to delete all objects: \(error)") + MXLog.error("[MXBeaconInfoSummaryRealmStore] Failed to delete all objects", context: error) } } } diff --git a/MatrixSDK/Aggregations/MXAggregatedReactionsUpdater.m b/MatrixSDK/Aggregations/MXAggregatedReactionsUpdater.m index 447a6386fd..b07b9669a7 100644 --- a/MatrixSDK/Aggregations/MXAggregatedReactionsUpdater.m +++ b/MatrixSDK/Aggregations/MXAggregatedReactionsUpdater.m @@ -619,7 +619,9 @@ - (MXHTTPOperation*)sendReaction:(NSString*)reaction MXRoom *room = [self.mxSession roomWithRoomId:roomId]; if (!room) { - MXLogError(@"[MXAggregations] sendReaction Error: Unknown room: %@", roomId); + MXLogErrorDetails(@"[MXAggregations] sendReaction Error: Unknown room", @{ + @"room_id": roomId ?: @"unknown" + }); return nil; } diff --git a/MatrixSDK/Background/MXBackgroundSyncService.swift b/MatrixSDK/Background/MXBackgroundSyncService.swift index b1d4ab1899..6d37726144 100644 --- a/MatrixSDK/Background/MXBackgroundSyncService.swift +++ b/MatrixSDK/Background/MXBackgroundSyncService.swift @@ -551,7 +551,10 @@ public enum MXBackgroundSyncServiceError: Error { case .success: MXLog.debug("[MXBackgroundSyncService] handleSyncResponse: Joined room: \(roomId)") case .failure(let error): - MXLog.error("[MXBackgroundSyncService] handleSyncResponse: Failed to join room: \(roomId), error: \(error)") + MXLog.error("[MXBackgroundSyncService] handleSyncResponse: Failed to join room", context: [ + "error": error, + "room_id": roomId + ]) } } } diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift index 49a92f1451..9fafbe4983 100644 --- a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift @@ -72,7 +72,7 @@ class MXCrossSigningV2: MXCrossSigning { success() } } catch { - log.error("Cannot setup cross signing", error: error) + log.error("Cannot setup cross signing", context: error) await MainActor.run { failure(error) } @@ -92,7 +92,7 @@ class MXCrossSigningV2: MXCrossSigning { success() } } catch { - log.error("Cannot setup cross signing", error: error) + log.error("Cannot setup cross signing", context: error) await MainActor.run { failure(error) } diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index d35546d6be..daef68ccd8 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -235,7 +235,7 @@ extension MXCryptoMachine: MXCryptoDevicesSource { do { return try machine.getUserDevices(userId: userId, timeout: 0) } catch { - log.error("Cannot fetch devices", error: error) + log.error("Cannot fetch devices", context: error) return [] } } @@ -244,7 +244,7 @@ extension MXCryptoMachine: MXCryptoDevicesSource { do { return try machine.getDevice(userId: userId, deviceId: deviceId, timeout: 0) } catch { - log.error("Cannot fetch device", error: error) + log.error("Cannot fetch device", context: error) return nil } } @@ -256,7 +256,7 @@ extension MXCryptoMachine: MXCryptoUserIdentitySource { do { return try machine.isIdentityVerified(userId: userId) } catch { - log.error("Failed checking user verification status", error: error) + log.error("Failed checking user verification status", context: error) return false } } @@ -473,7 +473,9 @@ extension MXCryptoMachine: Logger { } func log(error: String) { - MXLog.error("[MXCryptoMachine] \(error)") + MXLog.error("[MXCryptoMachine] Error", context: [ + "error": error + ]) } } diff --git a/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m b/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m index 402ce6f21b..a302c2ea77 100644 --- a/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m +++ b/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m @@ -408,9 +408,7 @@ + (void)_deleteStoreWithCredentials:(MXCredentials*)credentials readOnly:(BOOL)r [RLMRealm deleteFilesForConfiguration:config error:&error]; if (error) { - MXLogErrorWithDetails(@"[MXRealmCryptoStore] deleteStore error", @{ - @"error": error - }); + MXLogErrorDetails(@"[MXRealmCryptoStore] deleteStore error", error); if (!readOnly) { @@ -427,9 +425,7 @@ + (void)_deleteStoreWithCredentials:(MXCredentials*)credentials readOnly:(BOOL)r } else { - MXLogErrorWithDetails(@"[MXRealmCryptoStore] deleteStore: Cannot open realm.", @{ - @"error": error - }); + MXLogErrorDetails(@"[MXRealmCryptoStore] deleteStore: Cannot open realm.", error); } } } @@ -892,7 +888,7 @@ - (void)performSessionOperationWithDevice:(NSString*)deviceKey andSessionId:(NSS } else { - MXLogErrorWithDetails(@"[MXRealmCryptoStore] performSessionOperationWithDevice. Error: olm session not found", @{ + MXLogErrorDetails(@"[MXRealmCryptoStore] performSessionOperationWithDevice. Error: olm session not found", @{ @"sessionId": sessionId }); block(nil); @@ -1011,7 +1007,7 @@ - (void)performSessionOperationWithGroupSessionWithId:(NSString*)sessionId sende } else { - MXLogErrorWithDetails(@"[MXRealmCryptoStore] performSessionOperationWithGroupSessionWithId. Error: Cannot build MXOlmInboundGroupSession for megolm session", @{ + MXLogErrorDetails(@"[MXRealmCryptoStore] performSessionOperationWithGroupSessionWithId. Error: Cannot build MXOlmInboundGroupSession for megolm session", @{ @"sessionId": sessionId }); block(nil); @@ -1019,7 +1015,7 @@ - (void)performSessionOperationWithGroupSessionWithId:(NSString*)sessionId sende } else { - MXLogErrorWithDetails(@"[MXRealmCryptoStore] performSessionOperationWithGroupSessionWithId. Error: megolm session not found", @{ + MXLogErrorDetails(@"[MXRealmCryptoStore] performSessionOperationWithGroupSessionWithId. Error: megolm session not found", @{ @"sessionId": sessionId }); block(nil); diff --git a/MatrixSDK/Crypto/Dehydration/MXDehydrationService.m b/MatrixSDK/Crypto/Dehydration/MXDehydrationService.m index 948e108f55..17a17bf4d3 100644 --- a/MatrixSDK/Crypto/Dehydration/MXDehydrationService.m +++ b/MatrixSDK/Crypto/Dehydration/MXDehydrationService.m @@ -74,7 +74,9 @@ - (void)dehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient if (error) { - MXLogError(@"[MXDehydrationService] dehydrateDevice: Account serialization failed: %@", error); + MXLogErrorDetails(@"[MXDehydrationService] dehydrateDevice: Account serialization failed", @{ + @"error": error ?: @"unknown" + }); [self stopProgress]; failure(error); return; @@ -114,7 +116,9 @@ - (void)dehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient }]; } failure:^(NSError *error) { [self stopProgress]; - MXLogError(@"[MXDehydrationService] dehydrateDevice: Failed pushing dehydrated device data: %@", error); + MXLogErrorDetails(@"[MXDehydrationService] dehydrateDevice: Failed pushing dehydrated device data", @{ + @"error": error ?: @"unknown" + }); failure(error); }]; } @@ -176,7 +180,9 @@ - (void)rehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient }); }]; } failure:^(NSError *error) { - MXLogError(@"[MXDehydrationService] rehydrateDevice: Claiming dehydrated device failed with error: %@", error); + MXLogErrorDetails(@"[MXDehydrationService] rehydrateDevice: Claiming dehydrated device failed", @{ + @"error": error ?: @"unknown" + }); failure(error); }]; } failure:^(NSError *error) { @@ -193,7 +199,9 @@ - (void)rehydrateDeviceWithMatrixRestClient:(MXRestClient*)restClient } else { - MXLogError(@"[MXDehydrationService] rehydrateDevice: DehydratedDeviceId failed with error: %@", error); + MXLogErrorDetails(@"[MXDehydrationService] rehydrateDevice: DehydratedDeviceId failed", @{ + @"error": error ?: @"unknown" + }); failure(error); } }]; @@ -229,7 +237,9 @@ - (void)uploadDeviceInfo:(MXDeviceInfo*)deviceInfo [self stopProgress]; success(deviceInfo.deviceId); } failure:^(NSError *error) { - MXLogError(@"[MXDehydrationService] uploadDeviceInfo: failed uploading device keys: %@", error); + MXLogErrorDetails(@"[MXDehydrationService] uploadDeviceInfo: failed uploading device keys", @{ + @"error": error ?: @"unknown" + }); MXStrongifyAndReturnIfNil(self); [self stopProgress]; failure(error); diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m index d53471fdb6..456295a178 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m @@ -80,7 +80,9 @@ + (MXKeyBackupPreparationInfo *)prepareWith:(NSString*)password error:(NSError * if (*error) { - MXLogError(@"[MXAes256KeyBackupAlgorithm] prepare: error: %@", *error); + MXLogErrorDetails(@"[MXAes256KeyBackupAlgorithm] prepare", @{ + @"error": *error ?: @"unknown" + }); return nil; } diff --git a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m index 3c49f01d89..a74a578613 100644 --- a/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m +++ b/MatrixSDK/Crypto/KeyBackup/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m @@ -88,7 +88,9 @@ + (MXKeyBackupPreparationInfo *)prepareWith:(NSString *)password error:(NSError if (*error) { - MXLogError(@"[MXCurve25519KeyBackupAlgorithm] prepare: error: %@", *error); + MXLogErrorDetails(@"[MXCurve25519KeyBackupAlgorithm] prepare", @{ + @"error": *error ?: @"unknown" + }); return nil; } return [[MXKeyBackupPreparationInfo alloc] initWithPrivateKey:decryption.privateKey authData:authData]; diff --git a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m index d48f196a2e..0206f7e3a0 100644 --- a/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m +++ b/MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m @@ -153,7 +153,8 @@ - (void)checkAndStartWithKeyBackupVersion:(nullable MXKeyBackupVersion*)keyBacku Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; if (algorithmClass == NULL) { - MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: unknown algorithm: %@", keyBackupVersion.algorithm); + NSString *message = [NSString stringWithFormat:@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: unknown algorithm: %@", keyBackupVersion.algorithm]; + MXLogError(message); return; } if (![algorithmClass checkBackupVersion:keyBackupVersion]) @@ -1419,7 +1420,8 @@ - (BOOL)canBeRefreshed Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; if (algorithmClass == NULL) { - MXLogError(@"[MXKeyBackup] getOrCreateKeyBackupAlgorithmFor: unknown algorithm: %@", keyBackupVersion.algorithm); + NSString *message = [NSString stringWithFormat:@"[MXKeyBackup] getOrCreateKeyBackupAlgorithmFor: unknown algorithm: %@", keyBackupVersion.algorithm]; + MXLogError(message); return nil; } if (![algorithmClass checkBackupVersion:keyBackupVersion]) @@ -1553,7 +1555,8 @@ - (nullable NSData*)privateKeyFromCryptoStore Class algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm]; if (algorithmClass == NULL) { - MXLogError(@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup for unknown algorithm: %@", keyBackupVersion.algorithm); + NSString *message = [NSString stringWithFormat:@"[MXKeyBackup] megolmBackupAuthDataFromKeyBackupVersion: Key backup for unknown algorithm: %@", keyBackupVersion.algorithm]; + MXLogError(message); *error = [NSError errorWithDomain:MXKeyBackupErrorDomain code:MXKeyBackupErrorUnknownAlgorithm diff --git a/MatrixSDK/Crypto/MXCrypto.m b/MatrixSDK/Crypto/MXCrypto.m index 8a9d3fd8e3..a75d1aebeb 100644 --- a/MatrixSDK/Crypto/MXCrypto.m +++ b/MatrixSDK/Crypto/MXCrypto.m @@ -250,7 +250,9 @@ + (void)rehydrateExportedOlmDevice:(MXExportedOlmDevice*)exportedOlmDevice dispatch_async(cryptoQueue, ^{ if ([MXCryptoStoreClass hasDataForCredentials:credentials]) { - MXLogError(@"the exported Olm device with ID %@ shouldn't exist locally", credentials.deviceId); + MXLogErrorDetails(@"the exported Olm device shouldn't exist locally", @{ + @"device_id": credentials.deviceId ?: @"unknown" + }); complete(false); return; } @@ -378,7 +380,9 @@ - (void)start:(void (^)(void))success } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCrypto] start. Error in maybeUploadOneTimeKeys: %@", error); + MXLogErrorDetails(@"[MXCrypto] start. Error in maybeUploadOneTimeKeys", @{ + @"error": error ?: @"unknown" + }); dispatch_async(dispatch_get_main_queue(), ^{ self->startOperation = nil; failure(error); @@ -388,7 +392,9 @@ - (void)start:(void (^)(void))success } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCrypto] start. Error in uploadDeviceKeys: %@", error); + MXLogErrorDetails(@"[MXCrypto] start. Error in uploadDeviceKeys", @{ + @"error": error ?: @"unknown" + }); dispatch_async(dispatch_get_main_queue(), ^{ self->startOperation = nil; failure(error); @@ -548,7 +554,9 @@ - (MXHTTPOperation *)encryptEventContent:(NSDictionary *)eventContent withType:( }); } failure:^(NSError *error) { - MXLogError(@"[MXCrypto] encryptEventContent: Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] encryptEventContent: Error", @{ + @"error": error ?: @"unknown" + }); dispatch_async(dispatch_get_main_queue(), ^{ failure(error); @@ -653,7 +661,12 @@ - (MXEventDecryptionResult *)decryptEvent2:(MXEvent *)event inTimeline:(NSString result = [alg decryptEvent:event inTimeline:timeline]; if (result.error) { - MXLogError(@"[MXCrypto] decryptEvent: Error for %@: %@\nEvent: %@", event.eventId, result.error, event.JSONDictionary); + NSDictionary *details = @{ + @"event_id": event.eventId ?: @"unknown", + @"error": result.error ?: @"unknown", + @"event": event.JSONDictionary ?: @"unknown" + }; + MXLogErrorDetails(@"[MXCrypto] decryptEvent", details); if ([result.error.domain isEqualToString:MXDecryptingErrorDomain] && result.error.code == MXDecryptingErrorBadEncryptedMessageCode) @@ -936,7 +949,9 @@ - (void)onSyncCompleted:(NSString *)oldSyncToken nextSyncToken:(NSString *)nextS } failure:^(NSError *error) { // If that failed, we fall back to invalidating everyone. - MXLogError(@"[MXCrypto] onSyncCompleted: Error fetching changed device list. Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] onSyncCompleted: Error fetching changed device list", @{ + @"error": error ?: @"unknown" + }); [self.deviceList invalidateAllDeviceLists]; }]; } @@ -1670,7 +1685,9 @@ - (void)importRoomKeys:(NSData *)keyFile withPassword:(NSString *)password succe dispatch_async(dispatch_get_main_queue(), ^{ - MXLogError(@"[MXCrypto] importRoomKeys:withPassword: Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] importRoomKeys:withPassword: Error", @{ + @"error": error ?: @"unknown" + }); if (failure) { @@ -1768,7 +1785,11 @@ - (void)acceptKeyRequestFromCryptoThread:(MXIncomingRoomKeyRequest *)keyRequest { dispatch_async(dispatch_get_main_queue(), ^{ - MXLogError(@"[MXCrypto] acceptPendingKeyRequests: ERROR: unknown alg %@ in room %@", alg, roomId); + NSDictionary *details = @{ + @"algorithm": alg ?: @"unknown", + @"room_id": roomId ?: @"unknown", + }; + MXLogErrorDetails(@"[MXCrypto] acceptPendingKeyRequests: ERROR: unknown alg in room", details); if (failure) { failure(nil); @@ -2110,7 +2131,8 @@ - (BOOL)setEncryptionInRoom:(NSString*)roomId withMembers:(NSArray*)m Class encryptionClass = [[MXCryptoAlgorithms sharedAlgorithms] encryptorClassForAlgorithm:algorithm]; if (!encryptionClass) { - MXLogError(@"[MXCrypto] setEncryptionInRoom: Unable to encrypt with %@", algorithm); + NSString *message = [NSString stringWithFormat:@"[MXCrypto] setEncryptionInRoom: Unable to encrypt with %@", algorithm]; + MXLogError(message); return NO; } @@ -2405,12 +2427,18 @@ - (NSString*)verifyKeyAndStartSession:(MXKey*)oneTimeKey userId:(NSString*)userI else { // Possibly a bad key - MXLogError(@"[MXCrypto] verifyKeyAndStartSession: Error starting olm session with device %@:%@", userId, deviceId); + MXLogErrorDetails(@"[MXCrypto] verifyKeyAndStartSession: Error starting olm session with device", @{ + @"device_id": deviceId ?: @"unknown" + }); } } else { - MXLogError(@"[MXCrypto] verifyKeyAndStartSession: Unable to verify signature on one-time key for device %@:%@. Error: %@", userId, deviceId, error.localizedFailureReason); + NSDictionary *details = @{ + @"device_id": deviceId ?: @"unknown", + @"error": error ?: @"unknown" + }; + MXLogErrorDetails(@"[MXCrypto] verifyKeyAndStartSession: Unable to verify signature on one-time key for device", details); } return sessionId; @@ -2695,7 +2723,8 @@ - (void)onRoomKeyEvent:(MXEvent*)event id alg = [self getRoomDecryptor:event.content[@"room_id"] algorithm:event.content[@"algorithm"]]; if (!alg) { - MXLogError(@"[MXCrypto] onRoomKeyEvent: ERROR: Unable to handle keys for %@", event.content[@"algorithm"]); + NSString *message = [NSString stringWithFormat:@"[MXCrypto] onRoomKeyEvent: ERROR: Unable to handle keys for %@", event.content[@"algorithm"]]; + MXLogError(message); return; } @@ -2860,7 +2889,9 @@ - (void)maybeUploadOneTimeKeys:(void (^)(void))success failure:(void (^)(NSError } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCrypto] maybeUploadOneTimeKeys: Failed to publish one-time keys. Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] maybeUploadOneTimeKeys: Failed to publish one-time keys", @{ + @"error": error ?: @"unknown" + }); self->uploadOneTimeKeysOperation = nil; if (failure) @@ -2906,7 +2937,9 @@ - (void)maybeUploadOneTimeKeys:(void (^)(void))success failure:(void (^)(NSError } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCrypto] maybeUploadOneTimeKeys: Failed to publish one-time keys. Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] maybeUploadOneTimeKeys: Failed to publish one-time keys", @{ + @"error": error ?: @"unknown" + }); self->uploadOneTimeKeysOperation = nil; if (failure) @@ -2931,7 +2964,9 @@ - (void)maybeUploadOneTimeKeys:(void (^)(void))success failure:(void (^)(NSError } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCrypto] maybeUploadOneTimeKeys: Get published one-time keys count failed. Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] maybeUploadOneTimeKeys: Get published one-time keys count failed", @{ + @"error": error ?: @"unknown" + }); self->uploadOneTimeKeysOperation = nil; if (failure) @@ -2953,7 +2988,9 @@ - (MXHTTPOperation *)generateAndUploadOneTimeKeys:(NSUInteger)keyCount retry:(BO operation = [self uploadOneTimeKeys:^(MXKeysUploadResponse *keysUploadResponse) { success(); } failure:^(NSError *error) { - MXLogError(@"[MXCrypto] generateAndUploadOneTimeKeys: Failed to publish one-time keys. Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] generateAndUploadOneTimeKeys: Failed to publish one-time keys", @{ + @"error": error ?: @"unknown" + }); if ([MXError isMXError:error] && retry) { @@ -3113,7 +3150,9 @@ - (MXHTTPOperation *)publishedOneTimeKeysCount:(void (^)(NSUInteger publishedKey success(publishedkeyCount); } failure:^(NSError *error) { - MXLogError(@"[MXCrypto] publishedOneTimeKeysCount failed. Error: %@", error); + MXLogErrorDetails(@"[MXCrypto] publishedOneTimeKeysCount failed", @{ + @"error": error ?: @"unknown" + }); failure(error); }]; } @@ -3189,7 +3228,9 @@ - (void)markOlmSessionForUnwedgingInEvent:(MXEvent*)event }]; } failure:^(NSError *error) { - MXLogError(@"[MXCrypto] markOlmSessionForUnwedgingInEvent: ERROR for ensureOlmSessionsForDevices: %@", error); + MXLogErrorDetails(@"[MXCrypto] markOlmSessionForUnwedgingInEvent: ERROR for ensureOlmSessionsForDevices", @{ + @"error": error ?: @"unknown" + }); }]; } diff --git a/MatrixSDK/Crypto/MXCryptoV2.swift b/MatrixSDK/Crypto/MXCryptoV2.swift index 693ac84885..e9f02f3ace 100644 --- a/MatrixSDK/Crypto/MXCryptoV2.swift +++ b/MatrixSDK/Crypto/MXCryptoV2.swift @@ -48,7 +48,7 @@ public extension MXCrypto { do { return try MXCryptoV2(userId: userId, deviceId: deviceId, session: session, restClient: restClient) } catch { - log.failure("Error creating crypto V2", error: error) + log.failure("Error creating crypto V2", context: error) return nil } #else @@ -234,7 +234,7 @@ private class MXCryptoV2: MXCrypto { success?(result, kMXEventTypeStringRoomEncrypted) } } catch { - log.error("Error encrypting content", error: error) + log.error("Error encrypting content", context: error) await MainActor.run { failure?(error) } @@ -258,7 +258,7 @@ private class MXCryptoV2: MXCrypto { return result } catch { - log.error("Error decrypting event", error: error) + log.error("Error decrypting event", context: error) let result = MXEventDecryptionResult() result.error = error return result @@ -294,7 +294,7 @@ private class MXCryptoV2: MXCrypto { success?() } } catch { - log.error("Error ensuring encryption", error: error) + log.error("Error ensuring encryption", context: error) await MainActor.run { failure?(error) } @@ -324,7 +324,7 @@ private class MXCryptoV2: MXCrypto { unusedFallbackKeys: syncResponse.unusedFallbackKeys ) } catch { - log.error("Cannot handle sync", error: error) + log.error("Cannot handle sync", context: error) } } @@ -349,7 +349,7 @@ private class MXCryptoV2: MXCrypto { do { try await machine.completeSync() } catch { - log.failure("Error processing outgoing requests", error: error) + log.failure("Error processing outgoing requests", context: error) } } keyVerification.updatePendingRequests() @@ -480,7 +480,7 @@ private class MXCryptoV2: MXCrypto { do { try machine.deleteAllData() } catch { - log.failure("Cannot delete crypto store", error: error) + log.failure("Cannot delete crypto store", context: error) } onComplete?() } diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m index e200b96ca2..f4b0bcd98f 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m @@ -777,7 +777,8 @@ - (void)cancelTransaction:(id)transaction } else { - MXLogFailure(@"[MXKeyVerification] cancelTransaction: Cannot set cancellation reason on unknown transaction type: %@", NSStringFromClass([transaction class])) + NSString *message = [NSString stringWithFormat:@"[MXKeyVerification] cancelTransaction: Cannot set cancellation reason on unknown transaction type: %@", NSStringFromClass([transaction class])]; + MXLogFailure(message) } if (success) diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift b/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift index 0f13d14365..263b69ee1b 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift @@ -100,7 +100,7 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { success(request) } } catch { - log.error("Cannot request verification", error: error) + log.error("Cannot request verification", context: error) await MainActor.run { failure(error) } @@ -150,7 +150,7 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { success(transaction) } } catch { - MXLog.error("[MXKeyVerificationRequestV2] error \(error)") + MXLog.error("[MXKeyVerificationRequestV2] error", context: error) await MainActor.run { failure(error) } @@ -199,7 +199,7 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { idx < emojis.count ? emojis[idx] : nil } } catch { - log.error("Cannot get emoji indices", error: error) + log.error("Cannot get emoji indices", context: error) return [] } } @@ -209,7 +209,7 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { do { try await verification.cancelVerification(userId: request.otherUser, flowId: request.requestId, cancelCode: code.value) } catch { - log.error("Cannot cancel request", error: error) + log.error("Cannot cancel request", context: error) } } } @@ -219,7 +219,7 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { do { try await verification.confirmVerification(userId: transaction.otherUserId, flowId: transaction.transactionId) } catch { - log.error("Cannot confirm transaction", error: error) + log.error("Cannot confirm transaction", context: error) } } } @@ -229,7 +229,7 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { do { try await verification.cancelVerification(userId: transaction.otherUserId, flowId: transaction.transactionId, cancelCode: code.value) } catch { - log.error("Cannot cancel request", error: error) + log.error("Cannot cancel request", context: error) } } } diff --git a/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m b/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m index 0e33eeeb50..03f3373da7 100644 --- a/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m +++ b/MatrixSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m @@ -823,7 +823,9 @@ - (void)handleRedaction:(MXEvent*)redactionEvent self->httpOperation = nil; - MXLogError(@"[MXRoomEventTimeline] handleRedaction: failed to retrieve the redacted event: %@", error); + MXLogErrorDetails(@"[MXRoomEventTimeline] handleRedaction: failed to retrieve the redacted event", @{ + @"error": error ?: @"unknown" + }); }]; } } diff --git a/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift b/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift index 00cece42d3..b5fada9a90 100644 --- a/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift +++ b/MatrixSDK/Data/EventTimeline/Thread/MXThreadEventTimeline.swift @@ -203,7 +203,10 @@ public class MXThreadEventTimeline: NSObject, MXEventTimeline { if eventFound { success() } else if let paginationError = paginationError { - MXLog.error("[MXThreadEventTimeline][\(self.timelineId)] resetPaginationAroundInitialEvent failed: \(paginationError)") + MXLog.error("[MXThreadEventTimeline] resetPaginationAroundInitialEvent failed", context: [ + "error": paginationError, + "timeline_id": self.timelineId + ]) failure(paginationError) } else { failure(MXThreadEventTimelineError.initialEventNotFound) diff --git a/MatrixSDK/Data/MXRoom.m b/MatrixSDK/Data/MXRoom.m index fa8ab83c76..718dea2166 100644 --- a/MatrixSDK/Data/MXRoom.m +++ b/MatrixSDK/Data/MXRoom.m @@ -2827,7 +2827,9 @@ - (void)removeAllOutgoingMessages [self.summary resetLastMessage:nil failure:nil commit:YES]; } } failure:^(NSError *error) { - MXLogError(@"[MXRoom] removeAllOutgoingMessages: event fetch failed: %@", error); + MXLogErrorDetails(@"[MXRoom] removeAllOutgoingMessages: event fetch failed", @{ + @"error": error ?: @"unknown" + }); }]; } @@ -3646,7 +3648,9 @@ - (void)validateEncryptionStateConsistency BOOL isEncryptedInStore = [crypto isRoomEncrypted:self.roomId]; if (isEncryptedInStore && !self.summary.isEncrypted) { - MXLogError(@"[MXRoom] checkEncryptionState: summary.isEncrypted is wrong for room %@. Fix it.", self.roomId); + MXLogErrorDetails(@"[MXRoom] checkEncryptionState: summary.isEncrypted is wrong for room Fix it.", @{ + @"room_id": self.roomId ?: @"unknown" + }); self.summary.isEncrypted = YES; [self.summary save:YES]; } diff --git a/MatrixSDK/Data/MXRoomState.m b/MatrixSDK/Data/MXRoomState.m index c33256d2e1..0147788f7c 100644 --- a/MatrixSDK/Data/MXRoomState.m +++ b/MatrixSDK/Data/MXRoomState.m @@ -129,7 +129,11 @@ + (void)loadRoomStateFromStore:(id)store [roomState handleStateEvents:events]; onComplete(roomState); } failure:^(NSError *error) { - MXLogError(@"[MXRoomState] loadRoomStateFromStore(%@): Failed to load any events from api with error %@", logId, error); + NSDictionary *details = @{ + @"log_id": logId ?: @"unknown", + @"error": error ?: @"unknown" + }; + MXLogErrorDetails(@"[MXRoomState] loadRoomStateFromStore: Failed to load any events from api", details); onComplete(roomState); }]; diff --git a/MatrixSDK/Data/MXRoomSummary.m b/MatrixSDK/Data/MXRoomSummary.m index d3155ea5ca..94ed030a4e 100644 --- a/MatrixSDK/Data/MXRoomSummary.m +++ b/MatrixSDK/Data/MXRoomSummary.m @@ -505,7 +505,9 @@ - (void)registerEventEditsListener MXEvent *editedEvent = [event editedEventFromReplacementEvent:replaceEvent]; [self handleEvent:editedEvent]; } failure:^(NSError *error) { - MXLogError(@"[MXRoomSummary] registerEventEditsListener: event fetch failed: %@", error); + MXLogErrorDetails(@"[MXRoomSummary] registerEventEditsListener: event fetch failed", @{ + @"error": error ?: @"unknown" + }); }]; } }]; @@ -552,7 +554,9 @@ - (void)setIsEncrypted:(BOOL)isEncrypted // This should never happen if (_isEncrypted && !isEncrypted) { - MXLogError(@"[MXRoomSummary] setIsEncrypted: Attempt to reset isEncrypted for room %@. Ignote it. Call stack: %@", self.roomId, [NSThread callStackSymbols]); + MXLogErrorDetails(@"[MXRoomSummary] setIsEncrypted: Attempt to reset isEncrypted for room. Ignote it", @{ + @"room_id": self.roomId ?: @"unknown" + }); return; } diff --git a/MatrixSDK/Data/RoomList/Common/MXSuggestedRoomListDataFetcher.swift b/MatrixSDK/Data/RoomList/Common/MXSuggestedRoomListDataFetcher.swift index 5eb125128b..3e27255c9a 100644 --- a/MatrixSDK/Data/RoomList/Common/MXSuggestedRoomListDataFetcher.swift +++ b/MatrixSDK/Data/RoomList/Common/MXSuggestedRoomListDataFetcher.swift @@ -206,7 +206,7 @@ internal class MXSuggestedRoomListDataFetcher: NSObject, MXRoomListDataFetcher { self.computeData(from: summary.childInfos) } case .failure(let error): - MXLog.error("[MXSuggestedRoomListDataFetcher] fetchSpaceChildren failed: \(error)") + MXLog.error("[MXSuggestedRoomListDataFetcher] fetchSpaceChildren failed", context: error) } } } diff --git a/MatrixSDK/Data/RoomList/CoreData/MXCoreDataRoomListDataFetcher.swift b/MatrixSDK/Data/RoomList/CoreData/MXCoreDataRoomListDataFetcher.swift index c5b0189e6c..0a3edf50ae 100644 --- a/MatrixSDK/Data/RoomList/CoreData/MXCoreDataRoomListDataFetcher.swift +++ b/MatrixSDK/Data/RoomList/CoreData/MXCoreDataRoomListDataFetcher.swift @@ -72,7 +72,7 @@ internal class MXCoreDataRoomListDataFetcher: NSObject, MXRoomListDataFetcher { do { return try store.mainManagedObjectContext.count(for: request) } catch let error { - MXLog.error("[MXCoreDataRoomListDataFetcher] failed to count rooms: \(error)") + MXLog.error("[MXCoreDataRoomListDataFetcher] failed to count rooms", context: error) return 0 } } @@ -108,7 +108,7 @@ internal class MXCoreDataRoomListDataFetcher: NSObject, MXRoomListDataFetcher { total: nil) } } catch let error { - MXLog.error("[MXCoreDataRoomListDataFetcher] failed to calculate total counts: \(error)") + MXLog.error("[MXCoreDataRoomListDataFetcher] failed to calculate total counts", context: error) } return result } @@ -197,7 +197,7 @@ internal class MXCoreDataRoomListDataFetcher: NSObject, MXRoomListDataFetcher { try fetchedResultsController.performFetch() computeData() } catch let error { - MXLog.error("[MXCoreDataRoomListDataFetcher] failed to perform fetch: \(error)") + MXLog.error("[MXCoreDataRoomListDataFetcher] failed to perform fetch", context: error) } } diff --git a/MatrixSDK/Data/RoomList/MXStore/MXStoreRoomListDataFetcher.swift b/MatrixSDK/Data/RoomList/MXStore/MXStoreRoomListDataFetcher.swift index b6df59ff4d..9cdefcfd87 100644 --- a/MatrixSDK/Data/RoomList/MXStore/MXStoreRoomListDataFetcher.swift +++ b/MatrixSDK/Data/RoomList/MXStore/MXStoreRoomListDataFetcher.swift @@ -222,7 +222,9 @@ internal class MXStoreRoomListDataFetcher: NSObject, MXRoomListDataFetcher { return } guard let summary = self.store.summary(ofRoom: roomId) else { - MXLog.error("[MXStoreRoomListDataManager] roomAdded: room with id: \(roomId) not found in the store") + MXLog.error("[MXStoreRoomListDataManager] roomAdded: room not found in the store", context: [ + "room_id": roomId + ]) return } self.roomSummaries[roomId] = summary diff --git a/MatrixSDK/Data/RoomSummaryStore/CoreData/MXCoreDataRoomSummaryStore.swift b/MatrixSDK/Data/RoomSummaryStore/CoreData/MXCoreDataRoomSummaryStore.swift index 04c88494fb..25a2c959e6 100644 --- a/MatrixSDK/Data/RoomSummaryStore/CoreData/MXCoreDataRoomSummaryStore.swift +++ b/MatrixSDK/Data/RoomSummaryStore/CoreData/MXCoreDataRoomSummaryStore.swift @@ -111,7 +111,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { do { result = try moc.count(for: request) } catch { - MXLog.error("[MXCoreDataRoomSummaryStore] countRooms failed: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] countRooms failed", context: error) } } return result @@ -137,7 +137,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { result = dictionaries.compactMap({ $0[propertyName] as? String }) } } catch { - MXLog.error("[MXCoreDataRoomSummaryStore] fetchRoomIds failed: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] fetchRoomIds failed", context: error) } } return result @@ -156,7 +156,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { result = MXRoomSummary(summaryModel: model) } } catch { - MXLog.error("[MXCoreDataRoomSummaryStore] fetchSummary failed: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] fetchSummary failed", context: error) } } return result @@ -172,7 +172,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { let results = try moc.fetch(request) return results.first } catch { - MXLog.error("[MXCoreDataRoomSummaryStore] fetchSummary failed: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] fetchSummary failed", context: error) } return nil } @@ -189,7 +189,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { do { try moc.obtainPermanentIDs(for: [model]) } catch { - MXLog.error("[MXCoreDataRoomSummaryStore] saveSummary couldn't obtain permanent id: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] saveSummary couldn't obtain permanent id", context: error) } } @@ -231,7 +231,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { self.saveIfNeeded(moc) } catch { - MXLog.error("[MXCoreDataRoomSummaryStore] deleteAllSummaries failed: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] deleteAllSummaries failed", context: error) } } } @@ -250,7 +250,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { completion(mapped) } } catch { - MXLog.error("[MXCoreDataRoomSummaryStore] fetchRoomIds failed: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] fetchRoomIds failed", context: error) } } } @@ -267,7 +267,7 @@ public class MXCoreDataRoomSummaryStore: NSObject { saved = true } catch { moc.rollback() - MXLog.error("[MXCoreDataRoomSummaryStore] saveIfNeeded failed: \(error)") + MXLog.error("[MXCoreDataRoomSummaryStore] saveIfNeeded failed", context: error) } if saved { diff --git a/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXRoomSummaryMO.swift b/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXRoomSummaryMO.swift index a12b759756..c886d433a9 100644 --- a/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXRoomSummaryMO.swift +++ b/MatrixSDK/Data/RoomSummaryStore/CoreData/Models/MXRoomSummaryMO.swift @@ -117,7 +117,7 @@ public class MXRoomSummaryMO: NSManagedObject { do { try moc.obtainPermanentIDs(for: [membersCountModel]) } catch { - MXLog.error("[MXRoomSummaryMO] update: couldn't obtain permanent id for membersCount: \(error)") + MXLog.error("[MXRoomSummaryMO] update: couldn't obtain permanent id for membersCount", context: error) } s_membersCount = membersCountModel @@ -127,7 +127,7 @@ public class MXRoomSummaryMO: NSManagedObject { do { try moc.obtainPermanentIDs(for: [trustModel]) } catch { - MXLog.error("[MXRoomSummaryMO] update: couldn't obtain permanent id for trust: \(error)") + MXLog.error("[MXRoomSummaryMO] update: couldn't obtain permanent id for trust", context: error) } s_trust = trustModel } else { @@ -143,7 +143,7 @@ public class MXRoomSummaryMO: NSManagedObject { do { try moc.obtainPermanentIDs(for: [lastMessageModel]) } catch { - MXLog.error("[MXRoomSummaryMO] update: couldn't obtain permanent id for lastMessage: \(error)") + MXLog.error("[MXRoomSummaryMO] update: couldn't obtain permanent id for lastMessage", context: error) } s_lastMessage = lastMessageModel } else { diff --git a/MatrixSDK/Data/RoomSummaryStore/File/MXFileRoomSummaryStore.m b/MatrixSDK/Data/RoomSummaryStore/File/MXFileRoomSummaryStore.m index 65cc07013e..36e6a2cd02 100644 --- a/MatrixSDK/Data/RoomSummaryStore/File/MXFileRoomSummaryStore.m +++ b/MatrixSDK/Data/RoomSummaryStore/File/MXFileRoomSummaryStore.m @@ -132,7 +132,11 @@ - (void)storeSummary:(id)summary } @catch(NSException *exception) { - MXLogError(@"[MXFileStore] Warning: room summary file for room %@ has been corrupted. Exception: %@", roomId, exception); + NSDictionary *details = @{ + @"room_id": roomId ?: @"unknown", + @"exception": exception ?: @"unknown" + }; + MXLogErrorDetails(@"[MXFileStore] Warning: room summary file for room has been corrupted", details); } } } diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m index 325e22bf6e..3137f0b6ed 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m @@ -903,10 +903,10 @@ - (MXMemoryRoomStore*)getOrCreateRoomStore:(NSString*)roomId @catch (NSException *exception) { NSDictionary *logDetails = @{ - @"roomId": roomId ?: @"", - @"exception": exception + @"roomId": roomId ?: @"unknown", + @"exception": exception ?: @"unknown" }; - MXLogErrorWithDetails(@"[MXFileStore] Warning: MXFileRoomStore file for room has been corrupted", logDetails); + MXLogErrorDetails(@"[MXFileStore] Warning: MXFileRoomStore file for room has been corrupted", logDetails); [self logFiles]; [self deleteAllData]; } @@ -946,10 +946,10 @@ - (MXMemoryRoomOutgoingMessagesStore *)getOrCreateRoomOutgoingMessagesStore:(NSS @catch (NSException *exception) { NSDictionary *logDetails = @{ - @"roomId": roomId ?: @"", - @"exception": exception + @"roomId": roomId ?: @"unknown", + @"exception": exception ?: @"unknown" }; - MXLogErrorWithDetails(@"[MXFileStore] Warning: MXFileRoomOutgoingMessagesStore file for room as been corrupted", logDetails); + MXLogErrorDetails(@"[MXFileStore] Warning: MXFileRoomOutgoingMessagesStore file for room as been corrupted", logDetails); [self logFiles]; [self deleteAllData]; } @@ -993,7 +993,7 @@ - (RoomReceiptsStore*)getOrCreateRoomReceiptsStore:(NSString *)roomId @"roomId": roomId ?: @"", @"exception": exception }; - MXLogErrorWithDetails(@"[MXFileStore] Warning: loadReceipts file for room as been corrupted", logDetails); +// MXLogErrorWithDetails(@"[MXFileStore] Warning: loadReceipts file for room as been corrupted", logDetails); // We used to reset the store and force a full initial sync but this makes the app // start very slowly. @@ -2233,7 +2233,7 @@ - (void)saveObject:(id)object toFile:(NSString *)file NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:NO error:&error]; if (error) { - MXLogFailure(@"[MXFileStore] Failed archiving root object with error: '%@'", error.debugDescription); + MXLogFailureDetails(@"[MXFileStore] Failed archiving root object", error); return; } @@ -2244,7 +2244,7 @@ - (void)saveObject:(id)object toFile:(NSString *)file } else { - MXLogFailure(@"[MXFileStore] Failed saving data with error: '%@'", error.debugDescription); + MXLogFailureDetails(@"[MXFileStore] Failed saving data", error); } } else @@ -2279,7 +2279,7 @@ - (id)loadObjectOfClasses:(NSSet *)classes fromFile:(NSString *)file } else { - MXLogFailure(@"[MXFileStore] Failed loading object from class with error: '%@'", error.debugDescription); + MXLogFailureDetails(@"[MXFileStore] Failed loading object from class", error); return nil; } } @@ -2311,7 +2311,7 @@ - (id)loadRootObjectWithoutSecureCodingFromFile:(NSString *)file NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&error]; if (error && !unarchiver) { - MXLogFailure(@"[MXFileStore] Cannot create unarchiver with error: '%@'", error.debugDescription); + MXLogFailureDetails(@"[MXFileStore] Cannot create unarchiver", error); return nil; } unarchiver.requiresSecureCoding = NO; @@ -2324,7 +2324,7 @@ - (id)loadRootObjectWithoutSecureCodingFromFile:(NSString *)file } else { - MXLogFailure(@"[MXFileStore] Failed loading object from class with error: '%@'", error.debugDescription); + MXLogFailureDetails(@"[MXFileStore] Failed loading object from class", error); return nil; } } diff --git a/MatrixSDK/HomeServer/MXHomeServerCapabilitiesService.swift b/MatrixSDK/HomeServer/MXHomeServerCapabilitiesService.swift index a12ca52681..51b7ebd638 100644 --- a/MatrixSDK/HomeServer/MXHomeServerCapabilitiesService.swift +++ b/MatrixSDK/HomeServer/MXHomeServerCapabilitiesService.swift @@ -71,7 +71,7 @@ public class MXHomeserverCapabilitiesService: NSObject { case .success(let capabilities): self.capabilities = capabilities case .failure(let error): - MXLog.error("[MXHomeServerCapabilitiesService] update: failed due to error: \(error)") + MXLog.error("[MXHomeServerCapabilitiesService] update: failed", context: error) } self.currentRequest = nil diff --git a/MatrixSDK/MXRestClient.m b/MatrixSDK/MXRestClient.m index 8cbdca00e6..d558770185 100644 --- a/MatrixSDK/MXRestClient.m +++ b/MatrixSDK/MXRestClient.m @@ -255,7 +255,9 @@ -(id)initWithCredentials:(MXCredentials*)inCredentials // If refreshDispatchGroup is unmatched(a request for a new access token is in-flight) wait. dispatch_group_wait([MXRestClient refreshDispatchGroup], DISPATCH_TIME_FOREVER); if(!weakself.completionQueue) { - MXLogError(@"[MXRestClient] tokenProviderHandler: %@ Client closed, exit tokenProviderHandler early", logId); + MXLogErrorDetails(@"[MXRestClient] tokenProviderHandler: Client closed, exit tokenProviderHandler early", @{ + @"log_id": logId ?: @"unknown" + }); return; } MXLogDebug(@"[MXRestClient] tokenProviderHandler: %@ Wait finished", logId); diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index 15b602e47e..550282d7d2 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -583,7 +583,9 @@ - (void)handleSyncResponse:(MXSyncResponse *)syncResponse dispatch_group_leave(dispatchGroup); } } failure:^(NSError *error) { - MXLogError(@"[MXSession] handleSyncResponse: event fetch failed: %@", error); + MXLogErrorDetails(@"[MXSession] handleSyncResponse: event fetch failed", @{ + @"error": error ?: @"unknown" + }); dispatch_group_leave(dispatchGroup); }]; } @@ -862,7 +864,9 @@ - (void)startWithSyncFilterId:(NSString *)syncFilterId onServerSyncDone:(void (^ } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXSession] startWithSyncFilterId: setStore failed with error: %@", error); + MXLogErrorDetails(@"[MXSession] startWithSyncFilterId: setStore failed", @{ + @"error": error ?: @"unknown" + }); [self setState:MXSessionStateInitialSyncFailed]; failure(error); @@ -951,7 +955,9 @@ - (void)_startWithSyncFilterId:(NSString *)syncFilterId onServerSyncDone:(void ( // Initial server sync [self serverSyncWithServerTimeout:0 success:onServerSyncDone failure:^(NSError *error) { - MXLogError(@"[MXSession] _startWithSyncFilterId: Failed with error %@", error); + MXLogErrorDetails(@"[MXSession] _startWithSyncFilterId: Failed", @{ + @"error": error ?: @"unknown" + }); [self setState:MXSessionStateInitialSyncFailed]; failure(error); @@ -960,7 +966,9 @@ - (void)_startWithSyncFilterId:(NSString *)syncFilterId onServerSyncDone:(void ( } failure:^(NSError *error) { - MXLogError(@"[MXSession] Crypto failed to start. Error: %@", error); + MXLogErrorDetails(@"[MXSession] Crypto failed to start", @{ + @"error": error ?: @"unknown" + }); [self setState:MXSessionStateInitialSyncFailed]; failure(error); @@ -969,7 +977,9 @@ - (void)_startWithSyncFilterId:(NSString *)syncFilterId onServerSyncDone:(void ( } failure:^(NSError *error) { - MXLogError(@"[MXSession] Get the user's profile information failed with error %@", error); + MXLogErrorDetails(@"[MXSession] Get the user's profile information failed", @{ + @"error": error ?: @"unknown" + }); [self setState:MXSessionStateInitialSyncFailed]; failure(error); @@ -1663,7 +1673,9 @@ - (void)handleServerSyncError:(NSError*)error forRequestWithServerTimeout:(NSUIn } else { - MXLogError(@"[MXSession] handleServerSyncError: %@", error); + MXLogErrorDetails(@"[MXSession] handleServerSyncError", @{ + @"error": error ?: @"unknown" + }); MXError *mxError = [[MXError alloc] initWithNSError:error]; if (mxError) @@ -1891,7 +1903,9 @@ - (void)validateAccountData NSInteger keysCount = self.crypto.secretStorage.numberOfValidKeys; if (keysCount > 1) { - MXLogError(@"[MXSession] validateAccountData: Detected %ld valid SSSS keys, should only have one at most", keysCount) + MXLogErrorDetails(@"[MXSession] validateAccountData: Detected multiple valid SSSS keys, should only have one at most", @{ + @"count": @(keysCount) + }); } } @@ -2006,7 +2020,8 @@ - (void)handleBackgroundSyncCacheIfRequiredWithCompletion:(void (^)(void))comple { BOOL isInValidState = _state == MXSessionStateStoreDataReady || _state == MXSessionStatePaused; if (!isInValidState) { - MXLogFailure(@"[MXSession] state %@ is not valid to handle background sync cache, investigate why the method was called", [MXTools readableSessionState:_state]); + NSString *message = [NSString stringWithFormat:@"[MXSession] state %@ is not valid to handle background sync cache, investigate why the method was called", [MXTools readableSessionState:_state]]; + MXLogFailure(message); if (completion) { completion(); @@ -2597,7 +2612,11 @@ - (void)joinPendingRoomInvites [self joinRoom:roomId viaServers:nil success:^(MXRoom *room) { MXLogDebug(@"[MXSession] joinPendingRoomInvites: Joined room: %@", roomId) } failure:^(NSError *error) { - MXLogError(@"[MXSession] joinPendingRoomInvites: Failed to join room: %@, error: %@", roomId, error) + NSDictionary *details = @{ + @"error": error ?: @"unknown", + @"room_id": roomId ?: @"unknown" + }; + MXLogErrorDetails(@"[MXSession] joinPendingRoomInvites: Failed to join room", details); if (error.code == kMXRoomAlreadyJoinedErrorCode) { @@ -3039,7 +3058,7 @@ - (MXHTTPOperation*)eventWithEventId:(NSString*)eventId { if (eventId == nil) { - MXLogError(@"[MXSession] eventWithEventId called with no eventId. Call stack: %@", [NSThread callStackSymbols]); + MXLogError(@"[MXSession] eventWithEventId called with no eventId"); if (failure) { MXError *error = [[MXError alloc] initWithErrorCode:kMXErrCodeStringNotFound @@ -3225,7 +3244,9 @@ - (void)fixRoomsSummariesLastMessageWithMaxServerPaginationCount:(NSUInteger)max } } failure:^(NSError *error) { - MXLogError(@"[MXSession] fixRoomsSummariesLastMessage: event fetch failed: %@", error); + MXLogErrorDetails(@"[MXSession] fixRoomsSummariesLastMessage: event fetch failed", @{ + @"error": error ?: @"unknown" + }); dispatch_group_leave(dispatchGroup); }]; } @@ -4456,12 +4477,16 @@ - (void)prepareIdentityServiceForTermsWithDefault:(NSString *)defaultIdentitySer } failure:^(NSError *error) { // Something went wrong setting the account data identity service - MXLogError(@"[MXSession] Error preparing identity server terms: %@", error); + MXLogErrorDetails(@"[MXSession] Error preparing identity server terms", @{ + @"error": error ?: @"unknown" + }); failure(error); }]; } failure:^(NSError * _Nonnull error) { // Something went wrong getting the identity service's access token. - MXLogError(@"[MXSession] Error preparing identity server terms: %@", error); + MXLogErrorDetails(@"[MXSession] Error preparing identity server terms", @{ + @"error": error ?: @"unknown" + }); failure(error); }]; } @@ -4846,7 +4871,9 @@ - (void)onDidDecryptEvent:(NSNotification *)notification [summary resetLastMessage:nil failure:nil commit:YES]; } } failure:^(NSError *error) { - MXLogError(@"[MXSession] onDidDecryptEvent: event fetch failed: %@", error); + MXLogErrorDetails(@"[MXSession] onDidDecryptEvent: event fetch failed", @{ + @"error": error ?: @"unknown" + }); }]; } } diff --git a/MatrixSDK/Space/MXSpaceFileStore.swift b/MatrixSDK/Space/MXSpaceFileStore.swift index b936371820..ef9c9c2470 100644 --- a/MatrixSDK/Space/MXSpaceFileStore.swift +++ b/MatrixSDK/Space/MXSpaceFileStore.swift @@ -61,7 +61,7 @@ class MXSpaceFileStore: MXSpaceStore { } try FileManager.default.moveItem(at: fileUrl, to: backupUrl) } catch { - MXLog.error("[MXSpaceFileStore] store: storeSpaceGraphData failed to move graph to backup: \(error)") + MXLog.error("[MXSpaceFileStore] store: storeSpaceGraphData failed to move graph to backup", context: error) } } @@ -111,7 +111,7 @@ class MXSpaceFileStore: MXSpaceStore { try FileManager.default.createDirectoryExcludedFromBackup(at: storeUrl) self.storeUrl = storeUrl } catch { - MXLog.error("[MXSpaceStore] setUpStoragePaths was unable to create space storage folder: \(error)") + MXLog.error("[MXSpaceStore] setUpStoragePaths was unable to create space storage folder", context: error) } } else { self.storeUrl = storeUrl diff --git a/MatrixSDK/Space/MXSpaceGraphData.swift b/MatrixSDK/Space/MXSpaceGraphData.swift index 8baa0079dd..f4a7c4ab0b 100644 --- a/MatrixSDK/Space/MXSpaceGraphData.swift +++ b/MatrixSDK/Space/MXSpaceGraphData.swift @@ -122,31 +122,31 @@ class MXSpaceGraphData: NSObject, NSCoding { class func model(fromJSON dictionary: [AnyHashable : Any]!) -> MXSpaceGraphData? { guard let spaceIdsJson = dictionary[Constants.spaceRoomIdsKey] as? [String] else { - MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing \(Constants.spaceRoomIdsKey)") + MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing spaceRoomIdsKey") return nil } guard let parentIdsPerRoomIdJson = dictionary[Constants.parentIdsPerRoomIdKey] as? [String : [String]] else { - MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing \(Constants.parentIdsPerRoomIdKey)") + MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing parentIdsPerRoomIdKey") return nil } guard let ancestorsPerRoomIdJson = dictionary[Constants.ancestorsPerRoomIdKey] as? [String : [String]] else { - MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing \(Constants.ancestorsPerRoomIdKey)") + MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing ancestorsPerRoomIdKey") return nil } guard let descendantsPerRoomIdJson = dictionary[Constants.descendantsPerRoomIdKey] as? [String : [String]] else { - MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing \(Constants.descendantsPerRoomIdKey)") + MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing descendantsPerRoomIdKey") return nil } guard let rootSpaceIdsJson = dictionary[Constants.rootSpaceIdsKey] as? [String] else { - MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing \(Constants.rootSpaceIdsKey)") + MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing rootSpaceIdsKey") return nil } guard let orphanedRoomIdsJson = dictionary[Constants.orphanedRoomIdsKey] as? [String] else { - MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing \(Constants.orphanedRoomIdsKey)") + MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing orphanedRoomIdsKey") return nil } guard let orphanedDirectRoomIdsJson = dictionary[Constants.orphanedDirectRoomIdsKey] as? [String] else { - MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing \(Constants.orphanedDirectRoomIdsKey)") + MXLog.error("[MXSpaceGraphData] model fromJSON aborted: missing orphanedDirectRoomIdsKey") return nil } diff --git a/MatrixSDK/Threads/MXThreadingService.swift b/MatrixSDK/Threads/MXThreadingService.swift index ff1d3b4c2b..f659614797 100644 --- a/MatrixSDK/Threads/MXThreadingService.swift +++ b/MatrixSDK/Threads/MXThreadingService.swift @@ -338,7 +338,7 @@ public class MXThreadingService: NSObject { case .success(let rootEvent): thread.addEvent(rootEvent, direction: direction) case .failure(let error): - MXLog.error("[MXThreadingService] handleInThreadEvent: root event not found: \(error)") + MXLog.error("[MXThreadingService] handleInThreadEvent: root event not found", context: error) } dispatchGroup.leave() } diff --git a/MatrixSDK/Utils/Categories/FileManager+Backup.swift b/MatrixSDK/Utils/Categories/FileManager+Backup.swift index 9c89f135b9..c006caaf63 100644 --- a/MatrixSDK/Utils/Categories/FileManager+Backup.swift +++ b/MatrixSDK/Utils/Categories/FileManager+Backup.swift @@ -66,7 +66,7 @@ public extension FileManager { do { try excludeItemFromBackup(at: url) } catch { - MXLog.error("[FileManager+Backup]: Cannot exclude url from backup: \(error.localizedDescription)") + MXLog.error("[FileManager+Backup]: Cannot exclude url from backup", context: error) } } } @@ -88,7 +88,7 @@ public extension FileManager { do { urls = try contentsOfDirectory(at: container, includingPropertiesForKeys: nil, options: []) } catch { - MXLog.error("[FileManager+Backup]: Cannot get contents of container: \(error.localizedDescription)") + MXLog.error("[FileManager+Backup]: Cannot get contents of container", context: error) return } @@ -96,7 +96,7 @@ public extension FileManager { do { try excludeItemFromBackup(at: url) } catch { - MXLog.error("[FileManager+Backup]: Cannot exclude url from backup: \(error.localizedDescription)") + MXLog.error("[FileManager+Backup]: Cannot exclude url from backup", context: error) } } } diff --git a/MatrixSDK/Utils/MXLog.h b/MatrixSDK/Utils/Logs/MXLog.h similarity index 63% rename from MatrixSDK/Utils/MXLog.h rename to MatrixSDK/Utils/Logs/MXLog.h index 0eef62b00b..b2a2f204f6 100644 --- a/MatrixSDK/Utils/MXLog.h +++ b/MatrixSDK/Utils/Logs/MXLog.h @@ -32,18 +32,20 @@ [MXLogObjcWrapper logWarning:[NSString stringWithFormat: message, ##__VA_ARGS__] file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__]; \ } -#define MXLogError(message, ...) { \ - [MXLogObjcWrapper logError:[NSString stringWithFormat: message, ##__VA_ARGS__] details:nil file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__]; \ +#define MXLogError(message) { \ + [MXLogObjcWrapper logError:message file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__ context:nil]; \ } -#define MXLogErrorWithDetails(message, dictionary) { \ - [MXLogObjcWrapper logError:message details:dictionary file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__]; \ +#define MXLogErrorDetails(message, details) { \ + [MXLogObjcWrapper logError:message file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__ context:details]; \ } -#define MXLogFailure(message, ...) { \ - [MXLogObjcWrapper logFailure:[NSString stringWithFormat: message, ##__VA_ARGS__] details:nil file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__]; \ +#define MXLogFailure(message) { \ + [MXLogObjcWrapper logFailure:message file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__ context:nil]; \ } -#define MXLogFailureWithDetails(message, dictionary) { \ - [MXLogObjcWrapper logFailure:message details:dictionary file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__]; \ +#define MXLogFailureDetails(message, details) { \ + [MXLogObjcWrapper logFailure:message file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__ context:details]; \ } + +// TODO: failure context diff --git a/MatrixSDK/Utils/MXLog.swift b/MatrixSDK/Utils/Logs/MXLog.swift similarity index 68% rename from MatrixSDK/Utils/MXLog.swift rename to MatrixSDK/Utils/Logs/MXLog.swift index 3a7755bfb4..93d90b7c46 100644 --- a/MatrixSDK/Utils/MXLog.swift +++ b/MatrixSDK/Utils/Logs/MXLog.swift @@ -108,39 +108,65 @@ private var logger: SwiftyBeaver.Type = { logger.warning(message, file, function, line: line) } - public static func error(_ message: @autoclosure () -> Any, - details: @autoclosure () -> [String: Any]? = nil, - _ file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) { - logger.error(formattedMessage(message(), details: details()), file, function, line: line, context: context) - - #if !DEBUG - if let details = details() { - // Tracking errors via analytics as an experiment (provided user consent), but only if details explicitly specified - MXSDKOptions.sharedInstance().analyticsDelegate?.trackNonFatalIssue("\(message())", details: details) - } - #endif + /// Log error with additional details + /// + /// - Parameters: + /// - message: Description of the error without any variables (this is to improve error aggregations by type) + /// - context: Additional context-dependent details about the issue + public static func error( + _ message: StaticString, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil + ) { + logger.error(message, file, function, line: line, context: context) } @available(swift, obsoleted: 5.4) - @objc public static func logError(_ message: String, details: [String: Any]? = nil, file: String, function: String, line: Int) { - error(message, details: details, context: nil) - } - - public static func failure(_ message: @autoclosure () -> Any, - details: @autoclosure () -> [String: Any]? = nil, - _ file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) { - logger.error(formattedMessage(message(), details: details()), file, function, line: line, context: context) - + @objc public static func logError( + _ message: String, + file: String, + function: String, + line: Int, + context: Any? = nil + ) { + logger.error(message, file, function, line: line, context: context) + } + + /// Log failure with additional details + /// + /// A failure is any type of programming error which should never occur in production. In `DEBUG` confuguration + /// any failure will raise `assertionFailure` + /// + /// - Parameters: + /// - message: Description of the error without any variables (this is to improve error aggregations by type) + /// - context: Additional context-dependent details about the issue + public static func failure( + _ message: StaticString, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil + ) { + logger.error(message, file, function, line: line, context: context) #if DEBUG - assertionFailure("\(message())") - #else - MXSDKOptions.sharedInstance().analyticsDelegate?.trackNonFatalIssue("\(message())", details: details()) + assertionFailure("\(message)") #endif } @available(swift, obsoleted: 5.4) - @objc public static func logFailure(_ message: String, details: [String: Any]? = nil, file: String, function: String, line: Int) { - failure(message, details: details, file, function, line: line, context: nil) + @objc public static func logFailure( + _ message: String, + file: String, + function: String, + line: Int, + context: Any? = nil + ) { + logger.error(message, file, function, line: line, context: context) + #if DEBUG + assertionFailure("\(message)") + #endif } // MARK: - Private @@ -159,10 +185,12 @@ private var logger: SwiftyBeaver.Type = { return } + logger.removeAllDestinations() + let consoleDestination = ConsoleDestination() consoleDestination.useNSLog = true consoleDestination.asynchronously = false - consoleDestination.format = "$C $M" + consoleDestination.format = "$C $M $X" // Format is `Color Message Context`, see https://docs.swiftybeaver.com/article/20-custom-format consoleDestination.levelColor.verbose = "" consoleDestination.levelColor.debug = "" consoleDestination.levelColor.info = "" @@ -183,52 +211,39 @@ private var logger: SwiftyBeaver.Type = { case .none: break } - - logger.removeAllDestinations() logger.addDestination(consoleDestination) - } - - fileprivate static func formattedMessage(_ message: Any, details: [String: Any]? = nil) -> String { - guard let details = details else { - return "\(message)" - } - return "\(message) - \(details)" + + let analytics = AnalyticsDestination() + logger.addDestination(analytics) } } /// Convenience wrapper around `MXLog` which formats all logs as "[Name] function: " +/// +/// Note: Ideallly the `format` of `ConsoleDestination` is set to track filename and function automatically +/// (e.g. as `consoleDestination.format = "[$N] $F $C $M $X")`, but this would require the removal of all +/// manually added filenames in logs. struct MXNamedLog { let name: String - func debug(_ message: String, function: String = #function) { - MXLog.debug(formattedMessage(message, function: function)) + func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) { + logger.debug(formattedMessage(message, function: function), file, function, line: line) } /// Logging errors requires a static message, all other details must be sent as additional parameters - func error(_ message: StaticString, error: Error? = nil, details: [String: Any]? = nil, function: String = #function) { - MXLog.error( - formattedMessage("\(message)", function: function), - details: formattedDetails(error, otherDetails: details) - ) + func error(_ message: StaticString, context: Any? = nil, file: String = #file, function: String = #function, line: Int = #line) { + logger.error(formattedMessage(message, function: function), file, function, line: line, context: context) } /// Logging failures requires a static message, all other details must be sent as additional parameters - func failure(_ message: StaticString, error: Error? = nil, details: [String: Any]? = nil, function: String = #function) { - MXLog.failure( - formattedMessage("\(message)", function: function), - details: formattedDetails(error, otherDetails: details) - ) + func failure(_ message: StaticString, context: Any? = nil, file: String = #file, function: String = #function, line: Int = #line) { + logger.error(formattedMessage(message, function: function), file, function, line: line, context: context) + #if DEBUG + assertionFailure("\(message)") + #endif } - private func formattedMessage(_ message: String, function: String) -> String { + private func formattedMessage(_ message: Any, function: String) -> String { return "[\(name)] \(function): \(message)" } - - private func formattedDetails(_ error: Error?, otherDetails: [String: Any]?) -> [String: Any]? { - var details = otherDetails ?? [:] - if let error = error { - details["error"] = error - } - return details.isEmpty ? nil : details - } } diff --git a/MatrixSDK/Utils/MXLogObjcWrapper.h b/MatrixSDK/Utils/Logs/MXLogObjcWrapper.h similarity index 79% rename from MatrixSDK/Utils/MXLogObjcWrapper.h rename to MatrixSDK/Utils/Logs/MXLogObjcWrapper.h index 11cbbc7e29..60dd29d114 100644 --- a/MatrixSDK/Utils/MXLogObjcWrapper.h +++ b/MatrixSDK/Utils/Logs/MXLogObjcWrapper.h @@ -31,9 +31,9 @@ NS_ASSUME_NONNULL_BEGIN + (void)logWarning:(NSString *)message file:(NSString *)file function:(NSString *)function line:(NSUInteger)line; -+ (void)logError:(NSString *)message details:(nullable NSDictionary *)details file:(NSString *)file function:(NSString *)function line:(NSUInteger)line; ++ (void)logError:(NSString *)message file:(NSString *)file function:(NSString *)function line:(NSUInteger)line context:(nullable id)context; -+ (void)logFailure:(NSString *)message details:(nullable NSDictionary *)details file:(NSString *)file function:(NSString *)function line:(NSUInteger)line; ++ (void)logFailure:(NSString *)message file:(NSString *)file function:(NSString *)function line:(NSUInteger)line context:(nullable id)context; @end diff --git a/MatrixSDK/Utils/MXLogObjcWrapper.m b/MatrixSDK/Utils/Logs/MXLogObjcWrapper.m similarity index 74% rename from MatrixSDK/Utils/MXLogObjcWrapper.m rename to MatrixSDK/Utils/Logs/MXLogObjcWrapper.m index e6d4ca4197..204fc6d3c1 100644 --- a/MatrixSDK/Utils/MXLogObjcWrapper.m +++ b/MatrixSDK/Utils/Logs/MXLogObjcWrapper.m @@ -39,14 +39,14 @@ + (void)logWarning:(NSString *)message file:(NSString *)file function:(NSString [MXLog logWarning:message file:file function:function line:line]; } -+ (void)logError:(NSString *)message details:(nullable NSDictionary *)details file:(NSString *)file function:(NSString *)function line:(NSUInteger)line ++ (void)logError:(NSString *)message file:(NSString *)file function:(NSString *)function line:(NSUInteger)line context:(id)context { - [MXLog logError:message details:details file:file function:function line:line]; + [MXLog logError:message file:file function:function line:line context:context]; } -+ (void)logFailure:(NSString *)message details:(nullable NSDictionary *)details file:(NSString *)file function:(NSString *)function line:(NSUInteger)line ++ (void)logFailure:(NSString *)message file:(NSString *)file function:(NSString *)function line:(NSUInteger)line context:(id)context { - [MXLog logFailure:message details:details file:file function:function line:line]; + [MXLog logFailure:message file:file function:function line:line context:context]; } @end diff --git a/MatrixSDK/Utils/MXLogger.h b/MatrixSDK/Utils/Logs/MXLogger.h similarity index 100% rename from MatrixSDK/Utils/MXLogger.h rename to MatrixSDK/Utils/Logs/MXLogger.h diff --git a/MatrixSDK/Utils/MXLogger.m b/MatrixSDK/Utils/Logs/MXLogger.m similarity index 99% rename from MatrixSDK/Utils/MXLogger.m rename to MatrixSDK/Utils/Logs/MXLogger.m index ae17feb2d4..8659a5179f 100644 --- a/MatrixSDK/Utils/MXLogger.m +++ b/MatrixSDK/Utils/Logs/MXLogger.m @@ -222,7 +222,9 @@ static void handleUncaughtException(NSException *exception) encoding:NSStringEncodingConversionAllowLossy error:nil]; - MXLogError(@"[MXLogger] handleUncaughtException:\n%@", description); + MXLogErrorDetails(@"[MXLogger] handleUncaughtException", @{ + @"description": description ?: @"unknown" + }); } // Signals emitted by the app are handled here diff --git a/MatrixSDK/Utils/MXServerNotices.m b/MatrixSDK/Utils/MXServerNotices.m index 60e7adfc57..29d82d3df3 100644 --- a/MatrixSDK/Utils/MXServerNotices.m +++ b/MatrixSDK/Utils/MXServerNotices.m @@ -181,7 +181,11 @@ - (void)serverNoticePinnedEvents:(nonnull void (^)(NSArray *pinnedEve } failure:^(NSError *error) { - MXLogError(@"[MXServerNotices] Failed to get pinned event %@ with error: %@. Continue anyway", pinnedEventId, error); + NSDictionary *details = @{ + @"event_id": pinnedEventId ?: @"unknown", + @"error": error ?: @"unknown" + }; + MXLogErrorDetails(@"[MXServerNotices] Failed to get pinned event. Continue anyway", details); dispatch_group_leave(group); }]; } diff --git a/MatrixSDK/VoIP/MXCall.m b/MatrixSDK/VoIP/MXCall.m index f1d946a675..86268d7865 100644 --- a/MatrixSDK/VoIP/MXCall.m +++ b/MatrixSDK/VoIP/MXCall.m @@ -152,7 +152,9 @@ - (instancetype)initWithRoomId:(NSString *)roomId callSignalingRoomId:(NSString callStackCall = [callManager.callStack createCall]; if (nil == callStackCall) { - MXLogError(@"[MXCall][%@] Error: Cannot create call. [MXCallStack createCall] returned nil.", _callId); + MXLogErrorDetails(@"[MXCall] Error: Cannot create call. [MXCallStack createCall] returned nil.", @{ + @"call_id": _callId ?: @"unknown" + }); [callManager.mxSession releasePreventPause]; return nil; } @@ -326,20 +328,22 @@ - (void)callWithVideo:(BOOL)video } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] callWithVideo: ERROR: Cannot send m.call.invite event.", self.callId); + MXLogErrorDetails(@"[MXCall] callWithVideo: ERROR: Cannot send m.call.invite event.", @{ + @"call_id": self.callId ?: @"unknown" + }); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] callWithVideo: ERROR: Cannot create offer. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] callWithVideo: ERROR: Cannot create offer", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonIceFailed]; }]; } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] callWithVideo: ERROR: Cannot start capturing media. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] callWithVideo: ERROR: Cannot start capturing media", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonUserMediaFailed]; }]; }]; @@ -409,14 +413,16 @@ - (void)answer } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] answer: ERROR: Cannot send m.call.answer event.", self.callId); + MXLogErrorDetails(@"[MXCall] answer: ERROR: Cannot send m.call.answer event.", @{ + @"call_id": self.callId ?: @"unknown" + }); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] answer: ERROR: Cannot create answer. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] answer: ERROR: Cannot create answer", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonIceFailed]; }]; }; @@ -433,7 +439,7 @@ - (void)answer [self->callManager.mxSession.crypto ensureEncryptionInRoom:self.callSignalingRoom.roomId success:answer failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] answer: ERROR: [MXCrypto ensureEncryptionInRoom] failed. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] answer: ERROR: [MXCrypto ensureEncryptionInRoom] failed", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; } @@ -508,7 +514,9 @@ - (void)hangupWithReason:(MXCallHangupReason)reason } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] hangup: ERROR: Cannot send m.call.reject event.", self.callId); + MXLogErrorDetails(@"[MXCall] hangup: ERROR: Cannot send m.call.reject event.", @{ + @"call_id": self.callId ?: @"unknown" + }); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; } @@ -553,7 +561,9 @@ - (void)hangupWithReason:(MXCallHangupReason)reason } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] hangupWithReason: ERROR: Cannot send m.call.hangup event.", self.callId); + MXLogErrorDetails(@"[MXCall] hangupWithReason: ERROR: Cannot send m.call.hangup event.", @{ + @"call_id": self.callId ?: @"unknown" + }); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; } @@ -645,14 +655,16 @@ - (void)hold:(BOOL)hold } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] hold: ERROR: Cannot send m.call.negotiate event.", self.callId); + MXLogErrorDetails(@"[MXCall] hold: ERROR: Cannot send m.call.negotiate event.", @{ + @"call_id": self.callId ?: @"unknown" + }); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; } failure:^(NSError * _Nonnull error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] hold: ERROR: Cannot create offer. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] hold: ERROR: Cannot create offer", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonIceFailed]; }]; }]; @@ -733,7 +745,9 @@ - (void)transferToRoom:(NSString * _Nullable)targetRoomId failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] transferToRoom: ERROR: Cannot send m.call.replaces event.", self.callId); + MXLogErrorDetails(@"[MXCall] transferToRoom: ERROR: Cannot send m.call.replaces event", @{ + @"call_id": self.callId ?: @"unknown" + }); if (failure) { failure(error); @@ -1029,7 +1043,9 @@ - (void)sendLocalIceCandidates [_callSignalingRoom sendEventOfType:kMXEventTypeStringCallCandidates content:content threadId:nil localEcho:nil success:nil failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] onICECandidate: Warning: Cannot send m.call.candidates event.", self.callId); + MXLogErrorDetails(@"[MXCall] onICECandidate: Warning: Cannot send m.call.candidates event", @{ + @"call_id": self.callId ?: @"unknown" + }); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; @@ -1049,7 +1065,7 @@ - (void)callStackCallDidRemotelyHold:(id)callStackCall - (void)callStackCall:(id)callStackCall onError:(NSError *)error { - MXLogError(@"[MXCall][%@] callStackCall didEncounterError: %@", _callId, error); + MXLogErrorDetails(@"[MXCall] callStackCall didEncounterError", [self detailsForError:error]); if (self.isEstablished) { @@ -1152,7 +1168,7 @@ - (void)handleCallInvite:(MXEvent *)event failure:^(NSError * _Nonnull error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallInvite: ERROR: Couldn't handle offer. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] handleCallInvite: ERROR: Couldn't handle offer", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; @@ -1160,7 +1176,7 @@ - (void)handleCallInvite:(MXEvent *)event } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallInvite: startCapturingMediaWithVideo : ERROR: Couldn't start capturing. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] handleCallInvite: startCapturingMediaWithVideo : ERROR: Couldn't start capturing", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonUserMediaFailed]; }]; @@ -1216,7 +1232,7 @@ - (void)handleCallAnswer:(MXEvent *)event failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallAnswer: ERROR: Cannot send handle answer. Error: %@\nEvent: %@", self.callId, error, event); + MXLogErrorDetails(@"[MXCall] handleCallAnswer: ERROR: Cannot send handle answer", [self detailsForError:error]); self.selectedAnswer = nil; [self didEncounterError:error reason:MXCallHangupReasonIceFailed]; }]; @@ -1244,7 +1260,7 @@ - (void)handleCallAnswer:(MXEvent *)event } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallAnswer: ERROR: Cannot send m.call.select_answer event. Error: %@\n", self.callId, error); + MXLogErrorDetails(@"[MXCall] handleCallAnswer: ERROR: Cannot send m.call.select_answer event", [self detailsForError:error]); self.selectedAnswer = nil; [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; @@ -1369,7 +1385,7 @@ - (void)handleCallReject:(MXEvent *)event } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallReject: ERROR: Cannot send m.call.select_answer event. Error: %@\n", self.callId, error); + MXLogErrorDetails(@"[MXCall] handleCallReject: ERROR: Cannot send m.call.select_answer event", [self detailsForError:error]); self.selectedAnswer = nil; [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; @@ -1433,20 +1449,22 @@ - (void)handleCallNegotiate:(MXEvent *)event [self.callSignalingRoom sendEventOfType:kMXEventTypeStringCallNegotiate content:content threadId:nil localEcho:nil success:nil failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallNegotiate: negotiate answer: ERROR: Cannot send m.call.negotiate event.", self.callId); + MXLogErrorDetails(@"[MXCall] handleCallNegotiate: negotiate answer: ERROR: Cannot send m.call.negotiate event.", @{ + @"call_id": self.callId ?: @"unknown" + }); [self didEncounterError:error reason:MXCallHangupReasonUnknownError]; }]; } failure:^(NSError * _Nonnull error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallNegotiate: negotiate answer: ERROR: Cannot create negotiate answer. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] handleCallNegotiate: negotiate answer: ERROR: Cannot create negotiate answer", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonIceFailed]; }]; } failure:^(NSError * _Nonnull error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallNegotiate: ERROR: Couldn't handle negotiate offer. Error: %@", self.callId, error); + MXLogErrorDetails(@"[MXCall] handleCallNegotiate: ERROR: Couldn't handle negotiate offer", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonIceFailed]; }]; } @@ -1458,7 +1476,7 @@ - (void)handleCallNegotiate:(MXEvent *)event failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - MXLogError(@"[MXCall][%@] handleCallNegotiate: ERROR: Cannot send handle negotiate answer. Error: %@\nEvent: %@", self.callId, error, event); + MXLogErrorDetails(@"[MXCall] handleCallNegotiate: ERROR: Cannot send handle negotiate answer", [self detailsForError:error]); [self didEncounterError:error reason:MXCallHangupReasonIceFailed]; }]; } @@ -1741,4 +1759,12 @@ - (void)onCallDeclinedElsewhere [callManager removeCall:self]; } +-(NSDictionary *)detailsForError:(NSError *)error +{ + return @{ + @"call_id": self.callId ?: @"unknown", + @"error": error ?: @"unknown" + }; +} + @end diff --git a/MatrixSDK/VoIP/MXiOSAudioOutputRouter.swift b/MatrixSDK/VoIP/MXiOSAudioOutputRouter.swift index fff3218660..4a7785f653 100644 --- a/MatrixSDK/VoIP/MXiOSAudioOutputRouter.swift +++ b/MatrixSDK/VoIP/MXiOSAudioOutputRouter.swift @@ -189,7 +189,7 @@ public class MXiOSAudioOutputRouter: NSObject { } currentRoute = route } catch { - MXLog.error("[MXiOSAudioOutputRouter] updateRoute: routing failed: \(error)") + MXLog.error("[MXiOSAudioOutputRouter] updateRoute: routing failed", context: error) } } From 6c55607ae887c89ae62b3b4f5cbeb07c93b484d8 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 22 Aug 2022 17:26:09 +0100 Subject: [PATCH 43/65] Changelog --- changelog.d/pr-1558.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-1558.misc diff --git a/changelog.d/pr-1558.misc b/changelog.d/pr-1558.misc new file mode 100644 index 0000000000..abc1f9031e --- /dev/null +++ b/changelog.d/pr-1558.misc @@ -0,0 +1 @@ +Analytics: Log all errors to analytics From df97e8a9140a226915fd6e6c087667a0eca3a749 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 22 Aug 2022 17:36:39 +0100 Subject: [PATCH 44/65] Missing files --- MatrixSDK.xcodeproj/project.pbxproj | 86 +++++++++++-------- .../Utils/Logs/AnalyticsDestination.swift | 56 ++++++++++++ 2 files changed, 106 insertions(+), 36 deletions(-) create mode 100644 MatrixSDK/Utils/Logs/AnalyticsDestination.swift diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 1f4342640f..50dac82049 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -29,10 +29,6 @@ 18121F7E273E837300B68ADF /* PollModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18121F7C273E835D00B68ADF /* PollModels.swift */; }; 18121F7F273E837300B68ADF /* PollModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18121F7C273E835D00B68ADF /* PollModels.swift */; }; 18121F80273E837400B68ADF /* PollModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18121F7C273E835D00B68ADF /* PollModels.swift */; }; - 181FD5D42660C791008EC084 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 181FD5D22660C791008EC084 /* MXLogObjcWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 181FD5D52660C791008EC084 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 181FD5D22660C791008EC084 /* MXLogObjcWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 181FD5D62660C791008EC084 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 181FD5D32660C791008EC084 /* MXLogObjcWrapper.m */; }; - 181FD5D72660C791008EC084 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 181FD5D32660C791008EC084 /* MXLogObjcWrapper.m */; }; 183892762702F553003F0C4F /* MXRoomNameDefaultStringLocalizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1838926F2702F552003F0C4F /* MXRoomNameDefaultStringLocalizer.h */; }; 183892772702F553003F0C4F /* MXRoomNameDefaultStringLocalizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1838926F2702F552003F0C4F /* MXRoomNameDefaultStringLocalizer.h */; }; 1838927A2702F553003F0C4F /* MXSendReplyEventDefaultStringLocalizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 183892712702F553003F0C4F /* MXSendReplyEventDefaultStringLocalizer.m */; }; @@ -47,10 +43,6 @@ 1838928927031D1D003F0C4F /* MXSendReplyEventStringLocalizerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 1838928527031D1D003F0C4F /* MXSendReplyEventStringLocalizerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18937E7C273A5AE500902626 /* MXPollRelationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 18937E79273A5AB000902626 /* MXPollRelationTests.m */; }; 18937E7D273A5AE500902626 /* MXPollRelationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 18937E79273A5AB000902626 /* MXPollRelationTests.m */; }; - 189CC081265E361C00BE1FD8 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 189CC07F265E361500BE1FD8 /* MXLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 189CC082265E361D00BE1FD8 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 189CC07F265E361500BE1FD8 /* MXLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 189CC083265E362600BE1FD8 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189CC080265E361500BE1FD8 /* MXLog.swift */; }; - 189CC084265E362700BE1FD8 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189CC080265E361500BE1FD8 /* MXLog.swift */; }; 18B22A7027707CDD00482170 /* MXEventContentLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 18B22A6E27707CDD00482170 /* MXEventContentLocation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18B22A7127707CDD00482170 /* MXEventContentLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 18B22A6E27707CDD00482170 /* MXEventContentLocation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18B22A7227707CDD00482170 /* MXEventContentLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 18B22A6F27707CDD00482170 /* MXEventContentLocation.m */; }; @@ -374,8 +366,6 @@ 327C3E4C23A39D91006183D1 /* MXAggregatedReferencesUpdater.h in Headers */ = {isa = PBXBuildFile; fileRef = 327C3E4923A39D91006183D1 /* MXAggregatedReferencesUpdater.h */; }; 327C3E4D23A39D91006183D1 /* MXAggregatedReferencesUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 327C3E4A23A39D91006183D1 /* MXAggregatedReferencesUpdater.m */; }; 327C3E4E23A39D91006183D1 /* MXAggregatedReferencesUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 327C3E4A23A39D91006183D1 /* MXAggregatedReferencesUpdater.m */; }; - 327E37B61A974F75007F026F /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 327E37B41A974F75007F026F /* MXLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 327E37B71A974F75007F026F /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 327E37B51A974F75007F026F /* MXLogger.m */; }; 327E37B91A977810007F026F /* MXLoggerUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 327E37B81A977810007F026F /* MXLoggerUnitTests.m */; }; 327E9ABC2284521C00A98BC1 /* MXEventUnsignedData.h in Headers */ = {isa = PBXBuildFile; fileRef = 327E9ABA2284521C00A98BC1 /* MXEventUnsignedData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 327E9ABD2284521C00A98BC1 /* MXEventUnsignedData.m in Sources */ = {isa = PBXBuildFile; fileRef = 327E9ABB2284521C00A98BC1 /* MXEventUnsignedData.m */; }; @@ -983,7 +973,6 @@ B14EF2532397E90400758AF0 /* MXPushRuleSenderNotificationPermissionConditionChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 3240969C1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.m */; }; B14EF2542397E90400758AF0 /* MXReceiptData.m in Sources */ = {isa = PBXBuildFile; fileRef = 71DE22DC1BC7C51200284153 /* MXReceiptData.m */; }; B14EF2552397E90400758AF0 /* MXWellKnownBaseConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 323547D72226D5D600F15F94 /* MXWellKnownBaseConfig.m */; }; - B14EF2562397E90400758AF0 /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 327E37B51A974F75007F026F /* MXLogger.m */; }; B14EF2572397E90400758AF0 /* MXMegolmExportEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = 324BE4671E3FADB1008D99D4 /* MXMegolmExportEncryption.m */; }; B14EF2582397E90400758AF0 /* MXFilterObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A31BBD20D3F2EC005916C7 /* MXFilterObject.m */; }; B14EF2592397E90400758AF0 /* MXHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 320DFDD819DD99B60068622A /* MXHTTPClient.m */; }; @@ -1230,7 +1219,6 @@ B14EF35A2397E90400758AF0 /* MXReplyEventFormattedBodyParts.h in Headers */ = {isa = PBXBuildFile; fileRef = B11BD45722CB58850064D8B0 /* MXReplyEventFormattedBodyParts.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF35B2397E90400758AF0 /* MXKeyBackupData.h in Headers */ = {isa = PBXBuildFile; fileRef = 32BBAE6A2178E99100D85F46 /* MXKeyBackupData.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF35C2397E90400758AF0 /* MXPusher.h in Headers */ = {isa = PBXBuildFile; fileRef = 32999DDD22DCD183004FF987 /* MXPusher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B14EF35D2397E90400758AF0 /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 327E37B41A974F75007F026F /* MXLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF35E2397E90400758AF0 /* MXMegolmBackupCreationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 320A883A217F4E35002EA952 /* MXMegolmBackupCreationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF35F2397E90400758AF0 /* MXCryptoConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 3256E37F1DCB91EB003C9718 /* MXCryptoConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; B14EF3602397E90400758AF0 /* MXHTTPClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 320DFDD719DD99B60068622A /* MXHTTPClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1842,6 +1830,20 @@ ED51943D284630090006EEC6 /* MXRestClientStub.m in Sources */ = {isa = PBXBuildFile; fileRef = ED51943B284630090006EEC6 /* MXRestClientStub.m */; }; ED5AE8C52816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = ED5AE8C22816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld */; }; ED5AE8C62816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = ED5AE8C22816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld */; }; + ED5C753C28B3E80300D24E85 /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753528B3E80300D24E85 /* MXLogger.h */; }; + ED5C753D28B3E80300D24E85 /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753528B3E80300D24E85 /* MXLogger.h */; }; + ED5C753E28B3E80300D24E85 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753628B3E80300D24E85 /* MXLog.h */; }; + ED5C753F28B3E80300D24E85 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753628B3E80300D24E85 /* MXLog.h */; }; + ED5C754028B3E80300D24E85 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753728B3E80300D24E85 /* MXLog.swift */; }; + ED5C754128B3E80300D24E85 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753728B3E80300D24E85 /* MXLog.swift */; }; + ED5C754228B3E80300D24E85 /* AnalyticsDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */; }; + ED5C754328B3E80300D24E85 /* AnalyticsDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */; }; + ED5C754428B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */; }; + ED5C754528B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */; }; + ED5C754628B3E80300D24E85 /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753A28B3E80300D24E85 /* MXLogger.m */; }; + ED5C754728B3E80300D24E85 /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753A28B3E80300D24E85 /* MXLogger.m */; }; + ED5C754828B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */; }; + ED5C754928B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */; }; ED5C95CE2833E85600843D82 /* MXOlmDeviceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */; }; ED5C95CF2833E85600843D82 /* MXOlmDeviceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */; }; ED7019DD2886C24100FC31B9 /* MXCrossSigningInfoSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D242885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift */; }; @@ -1982,8 +1984,6 @@ 18121F73273E6CED00B68ADF /* MXPollBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXPollBuilderTests.swift; sourceTree = ""; }; 18121F77273E6E1E00B68ADF /* PollBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollBuilder.swift; sourceTree = ""; }; 18121F7C273E835D00B68ADF /* PollModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollModels.swift; sourceTree = ""; }; - 181FD5D22660C791008EC084 /* MXLogObjcWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXLogObjcWrapper.h; sourceTree = ""; }; - 181FD5D32660C791008EC084 /* MXLogObjcWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXLogObjcWrapper.m; sourceTree = ""; }; 1838926F2702F552003F0C4F /* MXRoomNameDefaultStringLocalizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRoomNameDefaultStringLocalizer.h; sourceTree = ""; }; 183892712702F553003F0C4F /* MXSendReplyEventDefaultStringLocalizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXSendReplyEventDefaultStringLocalizer.m; sourceTree = ""; }; 183892732702F553003F0C4F /* MXSendReplyEventDefaultStringLocalizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXSendReplyEventDefaultStringLocalizer.h; sourceTree = ""; }; @@ -1991,8 +1991,6 @@ 1838928427031D1D003F0C4F /* MXRoomNameStringLocalizerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRoomNameStringLocalizerProtocol.h; sourceTree = ""; }; 1838928527031D1D003F0C4F /* MXSendReplyEventStringLocalizerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXSendReplyEventStringLocalizerProtocol.h; sourceTree = ""; }; 18937E79273A5AB000902626 /* MXPollRelationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXPollRelationTests.m; sourceTree = ""; }; - 189CC07F265E361500BE1FD8 /* MXLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXLog.h; sourceTree = ""; }; - 189CC080265E361500BE1FD8 /* MXLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = ""; }; 18B22A6E27707CDD00482170 /* MXEventContentLocation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXEventContentLocation.h; sourceTree = ""; }; 18B22A6F27707CDD00482170 /* MXEventContentLocation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXEventContentLocation.m; sourceTree = ""; }; 18C26C3C273C031900805154 /* PollAggregator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollAggregator.swift; sourceTree = ""; }; @@ -2242,8 +2240,6 @@ 327A5F46239805F600ED6329 /* MXKeyVerificationCancel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXKeyVerificationCancel.m; sourceTree = ""; }; 327C3E4923A39D91006183D1 /* MXAggregatedReferencesUpdater.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXAggregatedReferencesUpdater.h; sourceTree = ""; }; 327C3E4A23A39D91006183D1 /* MXAggregatedReferencesUpdater.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXAggregatedReferencesUpdater.m; sourceTree = ""; }; - 327E37B41A974F75007F026F /* MXLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXLogger.h; sourceTree = ""; }; - 327E37B51A974F75007F026F /* MXLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXLogger.m; sourceTree = ""; }; 327E37B81A977810007F026F /* MXLoggerUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXLoggerUnitTests.m; sourceTree = ""; }; 327E9ABA2284521C00A98BC1 /* MXEventUnsignedData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXEventUnsignedData.h; sourceTree = ""; }; 327E9ABB2284521C00A98BC1 /* MXEventUnsignedData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXEventUnsignedData.m; sourceTree = ""; }; @@ -2929,6 +2925,13 @@ ED51943E284630100006EEC6 /* MXRestClientStub.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXRestClientStub.h; sourceTree = ""; }; ED5AE8C32816C8CF00105072 /* MXRoomSummaryCoreDataStore2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MXRoomSummaryCoreDataStore2.xcdatamodel; sourceTree = ""; }; ED5AE8C42816C8CF00105072 /* MXRoomSummaryCoreDataStore.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MXRoomSummaryCoreDataStore.xcdatamodel; sourceTree = ""; }; + ED5C753528B3E80300D24E85 /* MXLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXLogger.h; sourceTree = ""; }; + ED5C753628B3E80300D24E85 /* MXLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXLog.h; sourceTree = ""; }; + ED5C753728B3E80300D24E85 /* MXLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = ""; }; + ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsDestination.swift; sourceTree = ""; }; + ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXLogObjcWrapper.m; sourceTree = ""; }; + ED5C753A28B3E80300D24E85 /* MXLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXLogger.m; sourceTree = ""; }; + ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXLogObjcWrapper.h; sourceTree = ""; }; ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXOlmDeviceUnitTests.swift; sourceTree = ""; }; ED7019E42886C32900FC31B9 /* MXSASTransactionV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXSASTransactionV2.swift; sourceTree = ""; }; ED7019E72886C33100FC31B9 /* MXKeyVerificationRequestV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationRequestV2.swift; sourceTree = ""; }; @@ -3187,6 +3190,7 @@ 323F87712554607A009E9E67 /* Profiling */, 3259D00E2603722A00C365DB /* Protocols */, B146D46E21A5939000D8C2C6 /* Realm */, + ED5C753428B3E80300D24E85 /* Logs */, 32322A491E575F65005DD155 /* MXAllowedCertificates.h */, 32322A4A1E575F65005DD155 /* MXAllowedCertificates.m */, C6FE1EEF1E65C4F7008587E4 /* MXAnalyticsDelegate.h */, @@ -3204,12 +3208,6 @@ 320DFDD819DD99B60068622A /* MXHTTPClient.m */, 32CAB1091A925B41008C5BB9 /* MXHTTPOperation.h */, 32CAB10A1A925B41008C5BB9 /* MXHTTPOperation.m */, - 327E37B41A974F75007F026F /* MXLogger.h */, - 327E37B51A974F75007F026F /* MXLogger.m */, - 189CC07F265E361500BE1FD8 /* MXLog.h */, - 189CC080265E361500BE1FD8 /* MXLog.swift */, - 181FD5D22660C791008EC084 /* MXLogObjcWrapper.h */, - 181FD5D32660C791008EC084 /* MXLogObjcWrapper.m */, F03EF5021DF01596009DF592 /* MXLRUCache.h */, F03EF5031DF01596009DF592 /* MXLRUCache.m */, 324676EB25C15F4600EA855B /* MXMemory.swift */, @@ -5191,6 +5189,20 @@ path = KeySharing; sourceTree = ""; }; + ED5C753428B3E80300D24E85 /* Logs */ = { + isa = PBXGroup; + children = ( + ED5C753528B3E80300D24E85 /* MXLogger.h */, + ED5C753628B3E80300D24E85 /* MXLog.h */, + ED5C753728B3E80300D24E85 /* MXLog.swift */, + ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */, + ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */, + ED5C753A28B3E80300D24E85 /* MXLogger.m */, + ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */, + ); + path = Logs; + sourceTree = ""; + }; ED7019ED2886CA6C00FC31B9 /* Verification */ = { isa = PBXGroup; children = ( @@ -5387,7 +5399,6 @@ B146D4E621A5AEF200D8C2C6 /* MXRealmMediaScan.h in Headers */, 32581DE823C8C0C900832EAA /* MXUserTrustLevel.h in Headers */, B146D4EF21A5AF7F00D8C2C6 /* MXRealmEventScan.h in Headers */, - 189CC081265E361C00BE1FD8 /* MXLog.h in Headers */, B146D49C21A5A04300D8C2C6 /* MXMediaScanStoreDelegate.h in Headers */, 32322A4B1E575F65005DD155 /* MXAllowedCertificates.h in Headers */, B14EECD72577DE7A00448735 /* MXLoginSSOIdentityProvider.h in Headers */, @@ -5414,6 +5425,7 @@ 323547D52226D3F500F15F94 /* MXWellKnown.h in Headers */, 32FFB4F0217E146A00C96002 /* MXRecoveryKey.h in Headers */, 32AF928A240EA3880008A0FD /* MXSecretShareSend.h in Headers */, + ED5C754828B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */, B14EECE52577F76100448735 /* MXLoginSSOFlow.h in Headers */, EC8A53E025B1BCC6004E0802 /* MXThirdPartyProtocolInstance.h in Headers */, 91F0685D2767CA420079F8FA /* MXTaskProfileName.h in Headers */, @@ -5449,7 +5461,6 @@ B19A309E240424BD00FB6F35 /* MXQRCodeTransaction_Private.h in Headers */, EC40384A289A7F260067D5B8 /* MXAes256KeyBackupAlgorithm.h in Headers */, 32BBAE742179CF4000D85F46 /* MXKeyBackup.h in Headers */, - 181FD5D42660C791008EC084 /* MXLogObjcWrapper.h in Headers */, 92634B821EF2E3C400DB9F60 /* MXCallKitConfiguration.h in Headers */, 32618E7120ED2DF500E1D2EA /* MXFilterJSONModel.h in Headers */, B146D47221A5939100D8C2C6 /* MXRealmHelper.h in Headers */, @@ -5487,6 +5498,7 @@ 325AD43F23BE3E7500FF5277 /* MXCrossSigningInfo.h in Headers */, 32AF928F24110ADD0008A0FD /* MXSecretShareManager_Private.h in Headers */, B176B25123EB03E4001879C6 /* MXAggregationPaginatedResponse_Private.h in Headers */, + ED5C753E28B3E80300D24E85 /* MXLog.h in Headers */, ECD289B426F9F00E00F268CF /* MXRoomSummarySentStatus.h in Headers */, 021AFBA62179E91900742B2C /* MXEncryptedContentKey.h in Headers */, 327187891DA7DCE50071C818 /* MXOlmEncryption.h in Headers */, @@ -5695,6 +5707,7 @@ 32F945F61FAB83D900622468 /* MXIncomingRoomKeyRequest.h in Headers */, 327137271A24D50A00DB6757 /* MXMyUser.h in Headers */, B146D47C21A5958400D8C2C6 /* MXAntivirusScanStatusFormatter.h in Headers */, + ED5C753C28B3E80300D24E85 /* MXLogger.h in Headers */, 3220093819EFA4C9008DE41D /* MXEventListener.h in Headers */, 327C3E4B23A39D91006183D1 /* MXAggregatedReferencesUpdater.h in Headers */, 324DD2B6246C21C700377005 /* MXSecretStorageKeyCreationInfo.h in Headers */, @@ -5721,7 +5734,6 @@ B11BD45922CB58850064D8B0 /* MXReplyEventFormattedBodyParts.h in Headers */, 32BBAE702178E99100D85F46 /* MXKeyBackupData.h in Headers */, 32999DDF22DCD183004FF987 /* MXPusher.h in Headers */, - 327E37B61A974F75007F026F /* MXLogger.h in Headers */, 320A883C217F4E35002EA952 /* MXMegolmBackupCreationInfo.h in Headers */, B19A30AA2404257700FB6F35 /* MXQRCodeKeyVerificationStart.h in Headers */, B105CDD6261F54C8006EB204 /* MXSpaceChildContent.h in Headers */, @@ -5856,7 +5868,6 @@ B14EF2CB2397E90400758AF0 /* MXCallAudioSessionConfigurator.h in Headers */, B14EF2CC2397E90400758AF0 /* MXMatrixVersions.h in Headers */, 324DD2A1246AE1EF00377005 /* MXEncryptedSecretContent.h in Headers */, - 181FD5D52660C791008EC084 /* MXLogObjcWrapper.h in Headers */, B14EF2CD2397E90400758AF0 /* MXRealmEventScanStore.h in Headers */, B14EF2CE2397E90400758AF0 /* MXFileRoomStore.h in Headers */, B14EF2D02397E90400758AF0 /* MXWellknownIntegrations.h in Headers */, @@ -5890,11 +5901,13 @@ B14EF2E12397E90400758AF0 /* MXContentScanEncryptedBody.h in Headers */, B14EF2E22397E90400758AF0 /* MX3PidAddManager.h in Headers */, B19A309D240424BD00FB6F35 /* MXQRCodeTransaction.h in Headers */, + ED5C753D28B3E80300D24E85 /* MXLogger.h in Headers */, ECD2899F26EB570C00F268CF /* MXRoomSummaryStore.h in Headers */, B14EF2E42397E90400758AF0 /* MXStore.h in Headers */, 32AF928B240EA3880008A0FD /* MXSecretShareSend.h in Headers */, B14EF2E62397E90400758AF0 /* MXMegolmEncryption.h in Headers */, EC8A53E125B1BCC6004E0802 /* MXThirdPartyProtocolInstance.h in Headers */, + ED5C753F28B3E80300D24E85 /* MXLog.h in Headers */, B14EF2E72397E90400758AF0 /* MXLRUCache.h in Headers */, B105CDD7261F54C8006EB204 /* MXSpaceChildContent.h in Headers */, 32AF929824115D8B0008A0FD /* MXPendingSecretShareRequest.h in Headers */, @@ -5960,6 +5973,7 @@ 32261B8B23C74A230018F1E2 /* MXDeviceTrustLevel.h in Headers */, 324DD2B7246C21C700377005 /* MXSecretStorageKeyCreationInfo.h in Headers */, B14EF3102397E90400758AF0 /* MXEmojiRepresentation.h in Headers */, + ED5C754928B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */, EC403857289B26400067D5B8 /* MXBaseKeyBackupAuthData.h in Headers */, EC116596270FBF090089FA56 /* MXApplicationProtocol.h in Headers */, ECF29BCD264194AE0053E6D6 /* MXCallAssertedIdentityEventContent.h in Headers */, @@ -6043,7 +6057,6 @@ B14EF33B2397E90400758AF0 /* MXInvite3PID.h in Headers */, ECD2899926EB3DCF00F268CF /* MXRoomSummaryProtocol.h in Headers */, B14EF33C2397E90400758AF0 /* MXFileStore.h in Headers */, - 189CC082265E361D00BE1FD8 /* MXLog.h in Headers */, B14EF33D2397E90400758AF0 /* MXRealmMediaScanStore.h in Headers */, B14EF3402397E90400758AF0 /* MXKeyBackupVersionTrust.h in Headers */, EC2EACFE266625170038B61F /* MXRoomLastMessage.h in Headers */, @@ -6090,7 +6103,6 @@ B14EF35A2397E90400758AF0 /* MXReplyEventFormattedBodyParts.h in Headers */, B14EF35B2397E90400758AF0 /* MXKeyBackupData.h in Headers */, B14EF35C2397E90400758AF0 /* MXPusher.h in Headers */, - B14EF35D2397E90400758AF0 /* MXLogger.h in Headers */, EC0B943E271DB68F00B4D440 /* MXVoidRoomSummaryStore.h in Headers */, B14EF35E2397E90400758AF0 /* MXMegolmBackupCreationInfo.h in Headers */, B14EF35F2397E90400758AF0 /* MXCryptoConstants.h in Headers */, @@ -6432,7 +6444,6 @@ 32B94E06228EE90300716A26 /* MXRealmReactionRelation.m in Sources */, 66836AB927CFA17200515780 /* MXLiveEventListener.swift in Sources */, 320BBF411D6C81550079890E /* MXEventsByTypesEnumeratorOnArray.m in Sources */, - 181FD5D62660C791008EC084 /* MXLogObjcWrapper.m in Sources */, EC60ED87265CFD0700B39A4E /* MXRoomsSyncResponse.m in Sources */, 3213301E228B190F0070BA9B /* MXRealmAggregationsMapper.m in Sources */, 8EC511062568216B00EC4E5B /* MXTaggedEventInfo.m in Sources */, @@ -6457,6 +6468,7 @@ B17982FC2119E4A2001FD722 /* MXRoomPowerLevels.m in Sources */, B146D4E421A5AEF200D8C2C6 /* MXRealmMediaScanMapper.m in Sources */, B146D4E321A5AEF200D8C2C6 /* MXRealmMediaScan.m in Sources */, + ED5C754628B3E80300D24E85 /* MXLogger.m in Sources */, 3291DC8523DF52E20009732F /* MXRoomCreationParameters.m in Sources */, 32C235731F827F3800E38FC5 /* MXRoomOperation.m in Sources */, 322A51C41D9AC8FE00C8536D /* MXCryptoAlgorithms.m in Sources */, @@ -6516,6 +6528,7 @@ B105CDD8261F54C8006EB204 /* MXSpaceChildContent.m in Sources */, 327E9ABD2284521C00A98BC1 /* MXEventUnsignedData.m in Sources */, 32AF9286240EA2430008A0FD /* MXSecretShareRequest.m in Sources */, + ED5C754428B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */, ED47CB6D28523995004FD755 /* MXCryptoV2.swift in Sources */, 32A1513A1DAD292400400192 /* MXMegolmEncryption.m in Sources */, EC60EDFE265CFFD200B39A4E /* MXInvitedGroupSync.m in Sources */, @@ -6688,6 +6701,7 @@ 324DD2C7246E638B00377005 /* MXAesHmacSha2.m in Sources */, 3A0AF06B2705A11400679D1A /* MXSpaceGraphData.swift in Sources */, 321CFDEF225264C4004D31DF /* NSArray+MatrixSDK.m in Sources */, + ED5C754228B3E80300D24E85 /* AnalyticsDestination.swift in Sources */, 918D30B7273951F400A16405 /* MXStoreService.swift in Sources */, 327A5F52239805F600ED6329 /* MXKeyVerificationStart.m in Sources */, 3294FD9D22F321B0007F1E60 /* MXServiceTermsRestClient.m in Sources */, @@ -6712,7 +6726,6 @@ 71DE22E01BC7C51200284153 /* MXReceiptData.m in Sources */, B14766B923D9D9420091F721 /* MXUsersTrustLevelSummary.m in Sources */, 323547D92226D5D600F15F94 /* MXWellKnownBaseConfig.m in Sources */, - 327E37B71A974F75007F026F /* MXLogger.m in Sources */, EC0B94272718E64500B4D440 /* CoreDataContextable.swift in Sources */, 324BE4691E3FADB1008D99D4 /* MXMegolmExportEncryption.m in Sources */, 32A31BBF20D3F2EC005916C7 /* MXFilterObject.m in Sources */, @@ -6724,7 +6737,6 @@ C602B58E1F22A8D700B67D87 /* MXImage.swift in Sources */, B105CD9D261E0B70006EB204 /* MXSpaceChildrenSummary.swift in Sources */, 32A9F8E0244720B10069C65B /* MXThrottler.m in Sources */, - 189CC083265E362600BE1FD8 /* MXLog.swift in Sources */, EC8A53E425B1BCC6004E0802 /* MXThirdPartyUsersResponse.m in Sources */, 3295401A216385F100E300FC /* MXServerNoticeContent.m in Sources */, B19A30A82404257700FB6F35 /* MXSASKeyVerificationStart.m in Sources */, @@ -6732,6 +6744,7 @@ 02CAD439217DD12F0074700B /* MXContentScanResult.m in Sources */, ED2DD116286C450600F06731 /* MXEventDecryptionResult+DecryptedEvent.swift in Sources */, EC60ED9C265CFE1700B39A4E /* MXRoomSyncState.m in Sources */, + ED5C754028B3E80300D24E85 /* MXLog.swift in Sources */, 32133016228AF4EF0070BA9B /* MXRealmAggregationsStore.m in Sources */, B19A30A62404257700FB6F35 /* MXQRCodeKeyVerificationStart.m in Sources */, B146D47B21A5958400D8C2C6 /* MXAntivirusScanStatusFormatter.m in Sources */, @@ -6983,7 +6996,6 @@ B14EF1CC2397E90400758AF0 /* MXEventAnnotationChunk.m in Sources */, B14EF1CD2397E90400758AF0 /* MXRealmEventScanStore.m in Sources */, ECE3DF9E270C660900FB4C96 /* MXMulticastDelegate.swift in Sources */, - 181FD5D72660C791008EC084 /* MXLogObjcWrapper.m in Sources */, EC1165B127107E330089FA56 /* MXRoomListDataManager.swift in Sources */, 324DD2C2246D658500377005 /* MXHkdfSha256.m in Sources */, B16C2450283AB05700F5D1FE /* MXRealmBeacon.swift in Sources */, @@ -7054,6 +7066,7 @@ EC8A53C625B1BC77004E0802 /* MXTurnServerResponse.m in Sources */, B14EF1F02397E90400758AF0 /* MXReplyEventParser.m in Sources */, B14EF1F12397E90400758AF0 /* MXFileStore.m in Sources */, + ED5C754728B3E80300D24E85 /* MXLogger.m in Sources */, B14EF1F22397E90400758AF0 /* MXIdentityService.swift in Sources */, B14EF1F32397E90400758AF0 /* MXServerNotices.m in Sources */, B14EF1F42397E90400758AF0 /* MXMemoryStore.m in Sources */, @@ -7113,6 +7126,7 @@ B14EF2062397E90400758AF0 /* MXGroup.m in Sources */, B14EF2072397E90400758AF0 /* MXAutoDiscovery.m in Sources */, 3297913123AA126500F7BB9B /* MXKeyVerificationStatusResolver.m in Sources */, + ED5C754528B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */, ED47CB6E28523995004FD755 /* MXCryptoV2.swift in Sources */, B14EF2082397E90400758AF0 /* MX3PidAddManager.m in Sources */, ECD2899026EB3B3400F268CF /* MXRoomListData.swift in Sources */, @@ -7281,10 +7295,10 @@ B1EE98C92804697400AB63F0 /* MXBeacon.m in Sources */, B105CD9E261E0B70006EB204 /* MXSpaceChildrenSummary.swift in Sources */, B14EF2552397E90400758AF0 /* MXWellKnownBaseConfig.m in Sources */, - B14EF2562397E90400758AF0 /* MXLogger.m in Sources */, EC383BB425406894002FBBE6 /* MXSyncResponseFileStore.swift in Sources */, B14EF2572397E90400758AF0 /* MXMegolmExportEncryption.m in Sources */, 3A0AF06C2705A11400679D1A /* MXSpaceGraphData.swift in Sources */, + ED5C754328B3E80300D24E85 /* AnalyticsDestination.swift in Sources */, 918D30B8273951F400A16405 /* MXStoreService.swift in Sources */, B14EF2582397E90400758AF0 /* MXFilterObject.m in Sources */, EC60EDEB265CFF3100B39A4E /* MXRoomInviteState.m in Sources */, @@ -7329,6 +7343,7 @@ ECCA02BC273485B200B6F34F /* MXThreadingService.swift in Sources */, ED2DD117286C450600F06731 /* MXEventDecryptionResult+DecryptedEvent.swift in Sources */, B14EF2692397E90400758AF0 /* MXMatrixVersions.m in Sources */, + ED5C754128B3E80300D24E85 /* MXLog.swift in Sources */, B14EF26A2397E90400758AF0 /* MXReactionCountChangeListener.m in Sources */, B14EF26B2397E90400758AF0 /* MXMegolmBackupCreationInfo.m in Sources */, B14EF26C2397E90400758AF0 /* MXRoom.m in Sources */, @@ -7400,7 +7415,6 @@ B14EF2872397E90400758AF0 /* MXPusherData.m in Sources */, 324DD2A3246AE1EF00377005 /* MXEncryptedSecretContent.m in Sources */, EC8A53B625B1BC77004E0802 /* MXCallHangupEventContent.m in Sources */, - 189CC084265E362700BE1FD8 /* MXLog.swift in Sources */, B14EF2882397E90400758AF0 /* MXOlmDevice.m in Sources */, B14766BA23D9D9420091F721 /* MXUsersTrustLevelSummary.m in Sources */, B14EF2892397E90400758AF0 /* MXKeyBackupPassword.m in Sources */, diff --git a/MatrixSDK/Utils/Logs/AnalyticsDestination.swift b/MatrixSDK/Utils/Logs/AnalyticsDestination.swift new file mode 100644 index 0000000000..0237b90f97 --- /dev/null +++ b/MatrixSDK/Utils/Logs/AnalyticsDestination.swift @@ -0,0 +1,56 @@ +// +// AnalyticsDestination.swift +// MatrixSDK +// +// Created by Element on 22/08/2022. +// + +import Foundation +import SwiftyBeaver + +/// SwiftyBeaver log destination that sends errors to analytics tracker +class AnalyticsDestination: BaseDestination { + override var asynchronously: Bool { + get { + return false + } + set { + assertionFailure("Cannot be used asynchronously to preserve strack trace") + } + } + + override var minLevel: SwiftyBeaver.Level { + get { + return .error + } + set { + assertionFailure("Analytics should not track anything less severe than errors") + } + } + + override func send(_ level: SwiftyBeaver.Level, msg: String, thread: String, file: String, function: String, line: Int, context: Any? = nil) -> String? { + let message = super.send(level, msg: msg, thread: thread, file: file, function: function, line: line, context: context) + #if !DEBUG + MXSDKOptions.sharedInstance().analyticsDelegate?.trackNonFatalIssue(msg, details: formattedDetails(from: context)) + #endif + return message + } + + private func formattedDetails(from context: Any?) -> [String: Any]? { + guard let context = context else { + return nil + } + + if let dictionary = context as? [String: Any] { + return dictionary + } else if let error = context as? Error { + return [ + "error": error.localizedDescription + ] + } else { + return [ + "context": String(describing: context) + ] + } + } +} From 5761b0f710111fd9a878e040063fc5beee2080e2 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Tue, 23 Aug 2022 08:12:27 +0100 Subject: [PATCH 45/65] Fix missing headers --- MatrixSDK.xcodeproj/project.pbxproj | 16 ++++++++-------- MatrixSDKTests/Utils/MXSessionTracker.swift | 7 +++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 50dac82049..9ffda8cbe4 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1830,10 +1830,10 @@ ED51943D284630090006EEC6 /* MXRestClientStub.m in Sources */ = {isa = PBXBuildFile; fileRef = ED51943B284630090006EEC6 /* MXRestClientStub.m */; }; ED5AE8C52816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = ED5AE8C22816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld */; }; ED5AE8C62816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = ED5AE8C22816C8CF00105072 /* MXCoreDataRoomSummaryStore.xcdatamodeld */; }; - ED5C753C28B3E80300D24E85 /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753528B3E80300D24E85 /* MXLogger.h */; }; - ED5C753D28B3E80300D24E85 /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753528B3E80300D24E85 /* MXLogger.h */; }; - ED5C753E28B3E80300D24E85 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753628B3E80300D24E85 /* MXLog.h */; }; - ED5C753F28B3E80300D24E85 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753628B3E80300D24E85 /* MXLog.h */; }; + ED5C753C28B3E80300D24E85 /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753528B3E80300D24E85 /* MXLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ED5C753D28B3E80300D24E85 /* MXLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753528B3E80300D24E85 /* MXLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ED5C753E28B3E80300D24E85 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753628B3E80300D24E85 /* MXLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ED5C753F28B3E80300D24E85 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753628B3E80300D24E85 /* MXLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; ED5C754028B3E80300D24E85 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753728B3E80300D24E85 /* MXLog.swift */; }; ED5C754128B3E80300D24E85 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753728B3E80300D24E85 /* MXLog.swift */; }; ED5C754228B3E80300D24E85 /* AnalyticsDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */; }; @@ -1842,8 +1842,8 @@ ED5C754528B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */; }; ED5C754628B3E80300D24E85 /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753A28B3E80300D24E85 /* MXLogger.m */; }; ED5C754728B3E80300D24E85 /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753A28B3E80300D24E85 /* MXLogger.m */; }; - ED5C754828B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */; }; - ED5C754928B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */; }; + ED5C754828B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ED5C754928B3E80300D24E85 /* MXLogObjcWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; ED5C95CE2833E85600843D82 /* MXOlmDeviceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */; }; ED5C95CF2833E85600843D82 /* MXOlmDeviceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C95CD2833E85600843D82 /* MXOlmDeviceUnitTests.swift */; }; ED7019DD2886C24100FC31B9 /* MXCrossSigningInfoSourceUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F1D242885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift */; }; @@ -5193,12 +5193,12 @@ isa = PBXGroup; children = ( ED5C753528B3E80300D24E85 /* MXLogger.h */, + ED5C753A28B3E80300D24E85 /* MXLogger.m */, ED5C753628B3E80300D24E85 /* MXLog.h */, ED5C753728B3E80300D24E85 /* MXLog.swift */, ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */, - ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */, - ED5C753A28B3E80300D24E85 /* MXLogger.m */, ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */, + ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */, ); path = Logs; sourceTree = ""; diff --git a/MatrixSDKTests/Utils/MXSessionTracker.swift b/MatrixSDKTests/Utils/MXSessionTracker.swift index 8ba3c9e282..8773370c06 100644 --- a/MatrixSDKTests/Utils/MXSessionTracker.swift +++ b/MatrixSDKTests/Utils/MXSessionTracker.swift @@ -50,9 +50,12 @@ class MXSessionTracker { func printOpenMXSessions() { for (trackId, trackedMXSession) in trackedMXSessions { - MXLog.error("MXSession(\(trackId)) for user \(trackedMXSession.userDeviceId) is not closed. It was created from:") + MXLog.error("MXSession for user is not closed. It was created from:", context: [ + "track_id": trackId, + "user_id": trackedMXSession.userDeviceId + ]) trackedMXSession.callStack.forEach { call in - MXLog.error(" - \(call)") + MXLog.error(" -", context: call) } } } From 5f4c8548cd891df596fae70ec098f7f26b0c4922 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Tue, 23 Aug 2022 14:33:27 +0100 Subject: [PATCH 46/65] Code review changes --- MatrixSDK.xcodeproj/project.pbxproj | 12 ++++++------ MatrixSDK/Data/Store/MXFileStore/MXFileStore.m | 2 +- ...estination.swift => MXAnalyticsDestination.swift} | 4 ++-- MatrixSDK/Utils/Logs/MXLog.h | 2 -- MatrixSDK/Utils/Logs/MXLog.swift | 6 +++--- 5 files changed, 12 insertions(+), 14 deletions(-) rename MatrixSDK/Utils/Logs/{AnalyticsDestination.swift => MXAnalyticsDestination.swift} (95%) diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 9ffda8cbe4..40cdc589fa 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1836,8 +1836,8 @@ ED5C753F28B3E80300D24E85 /* MXLog.h in Headers */ = {isa = PBXBuildFile; fileRef = ED5C753628B3E80300D24E85 /* MXLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; ED5C754028B3E80300D24E85 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753728B3E80300D24E85 /* MXLog.swift */; }; ED5C754128B3E80300D24E85 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753728B3E80300D24E85 /* MXLog.swift */; }; - ED5C754228B3E80300D24E85 /* AnalyticsDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */; }; - ED5C754328B3E80300D24E85 /* AnalyticsDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */; }; + ED5C754228B3E80300D24E85 /* MXAnalyticsDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753828B3E80300D24E85 /* MXAnalyticsDestination.swift */; }; + ED5C754328B3E80300D24E85 /* MXAnalyticsDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753828B3E80300D24E85 /* MXAnalyticsDestination.swift */; }; ED5C754428B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */; }; ED5C754528B3E80300D24E85 /* MXLogObjcWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */; }; ED5C754628B3E80300D24E85 /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = ED5C753A28B3E80300D24E85 /* MXLogger.m */; }; @@ -2928,7 +2928,7 @@ ED5C753528B3E80300D24E85 /* MXLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXLogger.h; sourceTree = ""; }; ED5C753628B3E80300D24E85 /* MXLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXLog.h; sourceTree = ""; }; ED5C753728B3E80300D24E85 /* MXLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = ""; }; - ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsDestination.swift; sourceTree = ""; }; + ED5C753828B3E80300D24E85 /* MXAnalyticsDestination.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXAnalyticsDestination.swift; sourceTree = ""; }; ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXLogObjcWrapper.m; sourceTree = ""; }; ED5C753A28B3E80300D24E85 /* MXLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXLogger.m; sourceTree = ""; }; ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXLogObjcWrapper.h; sourceTree = ""; }; @@ -5196,7 +5196,7 @@ ED5C753A28B3E80300D24E85 /* MXLogger.m */, ED5C753628B3E80300D24E85 /* MXLog.h */, ED5C753728B3E80300D24E85 /* MXLog.swift */, - ED5C753828B3E80300D24E85 /* AnalyticsDestination.swift */, + ED5C753828B3E80300D24E85 /* MXAnalyticsDestination.swift */, ED5C753B28B3E80300D24E85 /* MXLogObjcWrapper.h */, ED5C753928B3E80300D24E85 /* MXLogObjcWrapper.m */, ); @@ -6701,7 +6701,7 @@ 324DD2C7246E638B00377005 /* MXAesHmacSha2.m in Sources */, 3A0AF06B2705A11400679D1A /* MXSpaceGraphData.swift in Sources */, 321CFDEF225264C4004D31DF /* NSArray+MatrixSDK.m in Sources */, - ED5C754228B3E80300D24E85 /* AnalyticsDestination.swift in Sources */, + ED5C754228B3E80300D24E85 /* MXAnalyticsDestination.swift in Sources */, 918D30B7273951F400A16405 /* MXStoreService.swift in Sources */, 327A5F52239805F600ED6329 /* MXKeyVerificationStart.m in Sources */, 3294FD9D22F321B0007F1E60 /* MXServiceTermsRestClient.m in Sources */, @@ -7298,7 +7298,7 @@ EC383BB425406894002FBBE6 /* MXSyncResponseFileStore.swift in Sources */, B14EF2572397E90400758AF0 /* MXMegolmExportEncryption.m in Sources */, 3A0AF06C2705A11400679D1A /* MXSpaceGraphData.swift in Sources */, - ED5C754328B3E80300D24E85 /* AnalyticsDestination.swift in Sources */, + ED5C754328B3E80300D24E85 /* MXAnalyticsDestination.swift in Sources */, 918D30B8273951F400A16405 /* MXStoreService.swift in Sources */, B14EF2582397E90400758AF0 /* MXFilterObject.m in Sources */, EC60EDEB265CFF3100B39A4E /* MXRoomInviteState.m in Sources */, diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m index 3137f0b6ed..9140a89186 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m @@ -993,7 +993,7 @@ - (RoomReceiptsStore*)getOrCreateRoomReceiptsStore:(NSString *)roomId @"roomId": roomId ?: @"", @"exception": exception }; -// MXLogErrorWithDetails(@"[MXFileStore] Warning: loadReceipts file for room as been corrupted", logDetails); + MXLogErrorDetails(@"[MXFileStore] Warning: loadReceipts file for room as been corrupted", logDetails); // We used to reset the store and force a full initial sync but this makes the app // start very slowly. diff --git a/MatrixSDK/Utils/Logs/AnalyticsDestination.swift b/MatrixSDK/Utils/Logs/MXAnalyticsDestination.swift similarity index 95% rename from MatrixSDK/Utils/Logs/AnalyticsDestination.swift rename to MatrixSDK/Utils/Logs/MXAnalyticsDestination.swift index 0237b90f97..b3a82cb2bb 100644 --- a/MatrixSDK/Utils/Logs/AnalyticsDestination.swift +++ b/MatrixSDK/Utils/Logs/MXAnalyticsDestination.swift @@ -1,5 +1,5 @@ // -// AnalyticsDestination.swift +// MXAnalyticsDestination.swift // MatrixSDK // // Created by Element on 22/08/2022. @@ -9,7 +9,7 @@ import Foundation import SwiftyBeaver /// SwiftyBeaver log destination that sends errors to analytics tracker -class AnalyticsDestination: BaseDestination { +class MXAnalyticsDestination: BaseDestination { override var asynchronously: Bool { get { return false diff --git a/MatrixSDK/Utils/Logs/MXLog.h b/MatrixSDK/Utils/Logs/MXLog.h index b2a2f204f6..cfb92f6622 100644 --- a/MatrixSDK/Utils/Logs/MXLog.h +++ b/MatrixSDK/Utils/Logs/MXLog.h @@ -47,5 +47,3 @@ #define MXLogFailureDetails(message, details) { \ [MXLogObjcWrapper logFailure:message file:@__FILE__ function:[NSString stringWithFormat:@"%s", __FUNCTION__] line:__LINE__ context:details]; \ } - -// TODO: failure context diff --git a/MatrixSDK/Utils/Logs/MXLog.swift b/MatrixSDK/Utils/Logs/MXLog.swift index 93d90b7c46..50d4cceda1 100644 --- a/MatrixSDK/Utils/Logs/MXLog.swift +++ b/MatrixSDK/Utils/Logs/MXLog.swift @@ -136,7 +136,7 @@ private var logger: SwiftyBeaver.Type = { /// Log failure with additional details /// - /// A failure is any type of programming error which should never occur in production. In `DEBUG` confuguration + /// A failure is any type of programming error which should never occur in production. In `DEBUG` configuration /// any failure will raise `assertionFailure` /// /// - Parameters: @@ -213,14 +213,14 @@ private var logger: SwiftyBeaver.Type = { } logger.addDestination(consoleDestination) - let analytics = AnalyticsDestination() + let analytics = MXAnalyticsDestination() logger.addDestination(analytics) } } /// Convenience wrapper around `MXLog` which formats all logs as "[Name] function: " /// -/// Note: Ideallly the `format` of `ConsoleDestination` is set to track filename and function automatically +/// Note: Ideally the `format` of `ConsoleDestination` is set to track filename and function automatically /// (e.g. as `consoleDestination.format = "[$N] $F $C $M $X")`, but this would require the removal of all /// manually added filenames in logs. struct MXNamedLog { From 775e41f48b6acd391adcdcf814ede406495afb6b Mon Sep 17 00:00:00 2001 From: aringenbach Date: Tue, 23 Aug 2022 16:14:36 +0200 Subject: [PATCH 47/65] Allow setting room alias regardless of join rule --- MatrixSDK/Contrib/Swift/MXSession.swift | 2 +- changelog.d/pr-1559.change | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/pr-1559.change diff --git a/MatrixSDK/Contrib/Swift/MXSession.swift b/MatrixSDK/Contrib/Swift/MXSession.swift index 0116312e6f..11d7dd578d 100644 --- a/MatrixSDK/Contrib/Swift/MXSession.swift +++ b/MatrixSDK/Contrib/Swift/MXSession.swift @@ -163,6 +163,7 @@ public extension MXSession { let parameters = MXRoomCreationParameters() parameters.name = name parameters.topic = topic + parameters.roomAlias = aliasLocalPart let stateEventBuilder = MXRoomInitialStateEventBuilder() @@ -173,7 +174,6 @@ public extension MXSession { } parameters.preset = kMXRoomPresetPublicChat parameters.visibility = kMXRoomDirectoryVisibilityPublic - parameters.roomAlias = aliasLocalPart let guestAccessStateEvent = stateEventBuilder.buildGuestAccessEvent(withAccess: .canJoin) parameters.addOrUpdateInitialStateEvent(guestAccessStateEvent) let historyVisibilityStateEvent = stateEventBuilder.buildHistoryVisibilityEvent(withVisibility: .worldReadable) diff --git a/changelog.d/pr-1559.change b/changelog.d/pr-1559.change new file mode 100644 index 0000000000..f64830ad72 --- /dev/null +++ b/changelog.d/pr-1559.change @@ -0,0 +1 @@ +Allow setting room alias regardless of join rule From cb6c964a31a0d743410802050c0c59a88efe78a9 Mon Sep 17 00:00:00 2001 From: aringenbach Date: Tue, 23 Aug 2022 16:42:22 +0200 Subject: [PATCH 48/65] Fix incoming calls sometimes ringing after being answered on another client --- MatrixSDK/MXSession.m | 14 ++++++++++++++ changelog.d/6614.bugfix | 1 + 2 files changed, 15 insertions(+) create mode 100644 changelog.d/6614.bugfix diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index 15b602e47e..fdbdad2f7a 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -195,6 +195,10 @@ Queue of requested direct room change operations ([MXSession setRoom:directWithU */ @property (nonatomic) NSUInteger preventPauseCount; +#if TARGET_OS_IPHONE +@property (nonatomic, strong, readonly) MXUIKitApplicationStateService *applicationStateService; +#endif + @property (nonatomic, readwrite) MXScanManager *scanManager; /** @@ -233,6 +237,9 @@ - (id)initWithMatrixRestClient:(MXRestClient*)mxRestClient _accountData = [[MXAccountData alloc] init]; peekingRooms = [NSMutableArray array]; _preventPauseCount = 0; +#if TARGET_OS_IPHONE + _applicationStateService = [MXUIKitApplicationStateService new]; +#endif directRoomsOperationsQueue = [NSMutableArray array]; publicisedGroupsByUserId = [[NSMutableDictionary alloc] init]; nativeToVirtualRoomIds = [NSMutableDictionary dictionary]; @@ -1338,6 +1345,13 @@ - (void)releasePreventPause if (self.preventPauseCount > 0) { self.preventPauseCount--; +#if TARGET_OS_IPHONE + if (self.preventPauseCount == 0 + && self.applicationStateService.applicationState == UIApplicationStateBackground) + { + [self pause]; + } +#endif } } diff --git a/changelog.d/6614.bugfix b/changelog.d/6614.bugfix new file mode 100644 index 0000000000..32420d2ad8 --- /dev/null +++ b/changelog.d/6614.bugfix @@ -0,0 +1 @@ +Fix incoming calls sometimes ringing after being answered on another client From 689e0ec22d49b842a77f04580371f689df6d561a Mon Sep 17 00:00:00 2001 From: Gil Eluard Date: Tue, 23 Aug 2022 22:05:28 +0200 Subject: [PATCH 49/65] App Layout: force clear cache --- MatrixSDK/Data/Store/MXFileStore/MXFileStore.m | 2 +- changelog.d/6616.change | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/6616.change diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m index 325e22bf6e..e775e29298 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m @@ -29,7 +29,7 @@ #import "MatrixSDKSwiftHeader.h" #import "MXFileRoomSummaryStore.h" -static NSUInteger const kMXFileVersion = 80; +static NSUInteger const kMXFileVersion = 81; static NSString *const kMXFileStoreFolder = @"MXFileStore"; static NSString *const kMXFileStoreMedaDataFile = @"MXFileStore"; diff --git a/changelog.d/6616.change b/changelog.d/6616.change new file mode 100644 index 0000000000..4a483bcc97 --- /dev/null +++ b/changelog.d/6616.change @@ -0,0 +1 @@ +App Layout: Increased store version to force clear cache From 327eb5763e787a7d49a0d1f72a7e7af706940257 Mon Sep 17 00:00:00 2001 From: aringenbach Date: Wed, 24 Aug 2022 10:18:26 +0200 Subject: [PATCH 50/65] Move applicationState check to setPreventPauseCount setter and check vs `!UIApplicationStateActive` --- MatrixSDK/MXSession.m | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index fdbdad2f7a..838bd991dd 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -1345,13 +1345,6 @@ - (void)releasePreventPause if (self.preventPauseCount > 0) { self.preventPauseCount--; -#if TARGET_OS_IPHONE - if (self.preventPauseCount == 0 - && self.applicationStateService.applicationState == UIApplicationStateBackground) - { - [self pause]; - } -#endif } } @@ -1376,6 +1369,15 @@ - (void)setPreventPauseCount:(NSUInteger)preventPauseCount { MXLogDebug(@"[MXSession] setPreventPauseCount: Actually pause the session"); [self pause]; + } else { +#if TARGET_OS_IPHONE + // Pause the session if app is already in the background/inactive but pause wasn't requested + if (self.applicationStateService.applicationState != UIApplicationStateActive) + { + MXLogDebug(@"[MXSession] setPreventPauseCount: Pause session on already backgrounded/inactive app"); + [self pause]; + } +#endif } } } From 3cd6f0207e195d9a235c949b7e044c871b4948ea Mon Sep 17 00:00:00 2001 From: aringenbach Date: Wed, 24 Aug 2022 10:20:44 +0200 Subject: [PATCH 51/65] Fix coding style --- MatrixSDK/MXSession.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index 838bd991dd..86cc28cb16 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -1369,7 +1369,9 @@ - (void)setPreventPauseCount:(NSUInteger)preventPauseCount { MXLogDebug(@"[MXSession] setPreventPauseCount: Actually pause the session"); [self pause]; - } else { + } + else + { #if TARGET_OS_IPHONE // Pause the session if app is already in the background/inactive but pause wasn't requested if (self.applicationStateService.applicationState != UIApplicationStateActive) From 0d5057d95ceabf9d6c7ac285419679681af9733d Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 24 Aug 2022 12:46:59 +0300 Subject: [PATCH 52/65] Prepare for new sprint From e33c5f061754d5f6c801c1975ad6b6d7e5b59461 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Thu, 25 Aug 2022 09:42:50 +0100 Subject: [PATCH 53/65] Remove event from tracking --- .../Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m | 6 +++--- MatrixSDK/Crypto/MXCrypto.m | 4 ++-- MatrixSDKTests/Utils/MXSessionTracker.swift | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m b/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m index a302c2ea77..b7d75ce1c4 100644 --- a/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m +++ b/MatrixSDK/Crypto/Data/Store/MXRealmCryptoStore/MXRealmCryptoStore.m @@ -889,7 +889,7 @@ - (void)performSessionOperationWithDevice:(NSString*)deviceKey andSessionId:(NSS else { MXLogErrorDetails(@"[MXRealmCryptoStore] performSessionOperationWithDevice. Error: olm session not found", @{ - @"sessionId": sessionId + @"sessionId": sessionId ?: @"unknown" }); block(nil); } @@ -1008,7 +1008,7 @@ - (void)performSessionOperationWithGroupSessionWithId:(NSString*)sessionId sende else { MXLogErrorDetails(@"[MXRealmCryptoStore] performSessionOperationWithGroupSessionWithId. Error: Cannot build MXOlmInboundGroupSession for megolm session", @{ - @"sessionId": sessionId + @"sessionId": sessionId ?: @"unknown" }); block(nil); } @@ -1016,7 +1016,7 @@ - (void)performSessionOperationWithGroupSessionWithId:(NSString*)sessionId sende else { MXLogErrorDetails(@"[MXRealmCryptoStore] performSessionOperationWithGroupSessionWithId. Error: megolm session not found", @{ - @"sessionId": sessionId + @"sessionId": sessionId ?: @"unknown" }); block(nil); } diff --git a/MatrixSDK/Crypto/MXCrypto.m b/MatrixSDK/Crypto/MXCrypto.m index a75d1aebeb..3278af357a 100644 --- a/MatrixSDK/Crypto/MXCrypto.m +++ b/MatrixSDK/Crypto/MXCrypto.m @@ -663,10 +663,10 @@ - (MXEventDecryptionResult *)decryptEvent2:(MXEvent *)event inTimeline:(NSString { NSDictionary *details = @{ @"event_id": event.eventId ?: @"unknown", - @"error": result.error ?: @"unknown", - @"event": event.JSONDictionary ?: @"unknown" + @"error": result.error ?: @"unknown" }; MXLogErrorDetails(@"[MXCrypto] decryptEvent", details); + MXLogDebug(@"[MXCrypto] decryptEvent: Unable to decrypt event %@", event.JSONDictionary); if ([result.error.domain isEqualToString:MXDecryptingErrorDomain] && result.error.code == MXDecryptingErrorBadEncryptedMessageCode) diff --git a/MatrixSDKTests/Utils/MXSessionTracker.swift b/MatrixSDKTests/Utils/MXSessionTracker.swift index 8773370c06..18bb2d23f5 100644 --- a/MatrixSDKTests/Utils/MXSessionTracker.swift +++ b/MatrixSDKTests/Utils/MXSessionTracker.swift @@ -50,12 +50,12 @@ class MXSessionTracker { func printOpenMXSessions() { for (trackId, trackedMXSession) in trackedMXSessions { - MXLog.error("MXSession for user is not closed. It was created from:", context: [ + MXLog.error("MXSession for user is not closed", context: [ "track_id": trackId, - "user_id": trackedMXSession.userDeviceId ]) + MXLog.debug("MXSession was created from:") trackedMXSession.callStack.forEach { call in - MXLog.error(" -", context: call) + MXLog.debug(" - \(call)") } } } From be8f4de5609c06adc986b689a042d39b1bb2364d Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Thu, 25 Aug 2022 14:14:37 +0300 Subject: [PATCH 54/65] Improve MXLog file formatting and fix log message format --- MatrixSDK/Utils/Logs/MXLog.swift | 120 ++++++++++++++++--------------- changelog.d/pr-1564.misc | 1 + 2 files changed, 62 insertions(+), 59 deletions(-) create mode 100644 changelog.d/pr-1564.misc diff --git a/MatrixSDK/Utils/Logs/MXLog.swift b/MatrixSDK/Utils/Logs/MXLog.swift index 50d4cceda1..4a2d75478c 100644 --- a/MatrixSDK/Utils/Logs/MXLog.swift +++ b/MatrixSDK/Utils/Logs/MXLog.swift @@ -19,12 +19,11 @@ import SwiftyBeaver /// Various MXLog configuration options. Used in conjunction with `MXLog.configure()` @objc public class MXLogConfiguration: NSObject { - /// the desired log level. `.verbose` by default. - @objc public var logLevel: MXLogLevel = MXLogLevel.verbose + @objc public var logLevel = MXLogLevel.verbose /// whether logs should be written directly to files. `false` by default. - @objc public var redirectLogsToFiles: Bool = false + @objc public var redirectLogsToFiles = false /// the maximum total space to use for log files in bytes. `100MB` by default. @objc public var logFilesSizeLimit: UInt = 100 * 1024 * 1024 // 100MB @@ -33,7 +32,7 @@ import SwiftyBeaver @objc public var maxLogFilesCount: UInt = 50 /// the subname for log files. Files will be named as 'console-[subLogName].log'. `nil` by default - @objc public var subLogName: String? = nil + @objc public var subLogName: String? } /// MXLog logging levels. Use .none to disable logging entirely. @@ -48,7 +47,7 @@ import SwiftyBeaver private var logger: SwiftyBeaver.Type = { let logger = SwiftyBeaver.self - MXLog.configureLogger(logger, withConfiguration:MXLogConfiguration()) + MXLog.configureLogger(logger, withConfiguration: MXLogConfiguration()) return logger }() @@ -58,18 +57,20 @@ private var logger: SwiftyBeaver.Type = { Please see `MXLog.h` for Objective-C options. */ @objc public class MXLog: NSObject { - /// Method used to customize MXLog's behavior. /// Called automatically when first accessing the logger with the default values. /// Please see `MXLogConfiguration` for all available options. /// - Parameters: /// - configuration: the `MXLogConfiguration` instance to use - @objc static public func configure(_ configuration: MXLogConfiguration) { + @objc public static func configure(_ configuration: MXLogConfiguration) { configureLogger(logger, withConfiguration: configuration) } - public static func verbose(_ message: @autoclosure () -> Any, _ - file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) { + public static func verbose(_ message: @autoclosure () -> Any, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil) { logger.verbose(message(), file, function, line: line, context: context) } @@ -78,8 +79,11 @@ private var logger: SwiftyBeaver.Type = { logger.verbose(message, file, function, line: line) } - public static func debug(_ message: @autoclosure () -> Any, _ - file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) { + public static func debug(_ message: @autoclosure () -> Any, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil) { logger.debug(message(), file, function, line: line, context: context) } @@ -88,8 +92,11 @@ private var logger: SwiftyBeaver.Type = { logger.debug(message, file, function, line: line) } - public static func info(_ message: @autoclosure () -> Any, _ - file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) { + public static func info(_ message: @autoclosure () -> Any, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil) { logger.info(message(), file, function, line: line, context: context) } @@ -98,8 +105,11 @@ private var logger: SwiftyBeaver.Type = { logger.info(message, file, function, line: line) } - public static func warning(_ message: @autoclosure () -> Any, _ - file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) { + public static func warning(_ message: @autoclosure () -> Any, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil) { logger.warning(message(), file, function, line: line, context: context) } @@ -113,24 +123,20 @@ private var logger: SwiftyBeaver.Type = { /// - Parameters: /// - message: Description of the error without any variables (this is to improve error aggregations by type) /// - context: Additional context-dependent details about the issue - public static func error( - _ message: StaticString, - _ file: String = #file, - _ function: String = #function, - line: Int = #line, - context: Any? = nil - ) { + public static func error(_ message: StaticString, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil) { logger.error(message, file, function, line: line, context: context) } @available(swift, obsoleted: 5.4) - @objc public static func logError( - _ message: String, - file: String, - function: String, - line: Int, - context: Any? = nil - ) { + @objc public static func logError(_ message: String, + file: String, + function: String, + line: Int, + context: Any? = nil) { logger.error(message, file, function, line: line, context: context) } @@ -142,13 +148,11 @@ private var logger: SwiftyBeaver.Type = { /// - Parameters: /// - message: Description of the error without any variables (this is to improve error aggregations by type) /// - context: Additional context-dependent details about the issue - public static func failure( - _ message: StaticString, - _ file: String = #file, - _ function: String = #function, - line: Int = #line, - context: Any? = nil - ) { + public static func failure(_ message: StaticString, + _ file: String = #file, + _ function: String = #function, + line: Int = #line, + context: Any? = nil) { logger.error(message, file, function, line: line, context: context) #if DEBUG assertionFailure("\(message)") @@ -156,13 +160,11 @@ private var logger: SwiftyBeaver.Type = { } @available(swift, obsoleted: 5.4) - @objc public static func logFailure( - _ message: String, - file: String, - function: String, - line: Int, - context: Any? = nil - ) { + @objc public static func logFailure(_ message: String, + file: String, + function: String, + line: Int, + context: Any? = nil) { logger.error(message, file, function, line: line, context: context) #if DEBUG assertionFailure("\(message)") @@ -190,26 +192,26 @@ private var logger: SwiftyBeaver.Type = { let consoleDestination = ConsoleDestination() consoleDestination.useNSLog = true consoleDestination.asynchronously = false - consoleDestination.format = "$C $M $X" // Format is `Color Message Context`, see https://docs.swiftybeaver.com/article/20-custom-format + consoleDestination.format = "$C$M $X$c" // Format is `Color Message Context`, see https://docs.swiftybeaver.com/article/20-custom-format consoleDestination.levelColor.verbose = "" consoleDestination.levelColor.debug = "" consoleDestination.levelColor.info = "" - consoleDestination.levelColor.warning = "⚠️" - consoleDestination.levelColor.error = "🚨" + consoleDestination.levelColor.warning = "⚠️ " + consoleDestination.levelColor.error = "🚨 " switch configuration.logLevel { - case .verbose: - consoleDestination.minLevel = .verbose - case .debug: - consoleDestination.minLevel = .debug - case .info: - consoleDestination.minLevel = .info - case .warning: - consoleDestination.minLevel = .warning - case .error: - consoleDestination.minLevel = .error - case .none: - break + case .verbose: + consoleDestination.minLevel = .verbose + case .debug: + consoleDestination.minLevel = .debug + case .info: + consoleDestination.minLevel = .info + case .warning: + consoleDestination.minLevel = .warning + case .error: + consoleDestination.minLevel = .error + case .none: + break } logger.addDestination(consoleDestination) @@ -244,6 +246,6 @@ struct MXNamedLog { } private func formattedMessage(_ message: Any, function: String) -> String { - return "[\(name)] \(function): \(message)" + "[\(name)] \(function): \(message)" } } diff --git a/changelog.d/pr-1564.misc b/changelog.d/pr-1564.misc new file mode 100644 index 0000000000..14a139b66d --- /dev/null +++ b/changelog.d/pr-1564.misc @@ -0,0 +1 @@ +Improve MXLog file formatting and fix log message format \ No newline at end of file From 0575b3e9e79dfa0ba41c47c34c3d0e95f22b6fea Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Thu, 18 Aug 2022 15:33:59 +0100 Subject: [PATCH 55/65] Self-verification flow --- MatrixSDK.xcodeproj/project.pbxproj | 6 + .../CrossSigning/MXCrossSigningV2.swift | 46 +++- .../CryptoMachine/MXCryptoMachine.swift | 146 ++++++---- .../CryptoMachine/MXCryptoProtocols.swift | 52 +++- MatrixSDK/Crypto/MXCryptoV2.swift | 42 ++- MatrixSDK/Crypto/Recovery/MXRecoveryService.h | 2 +- .../Verification/MXKeyVerificationManager.h | 14 - .../Verification/MXKeyVerificationManager.m | 6 + .../MXKeyVerificationManagerV2.swift | 258 +++++++++++------- .../Requests/MXKeyVerificationRequestV2.swift | 69 +++-- .../Transactions/SAS/MXSASTransactionV2.swift | 89 ++++-- .../MXCrossSigningV2UnitTests.swift | 89 ++++++ .../CryptoMachine/MXCryptoProtocolStubs.swift | 103 ++++++- .../Devices/MXDeviceInfoSourceUnitTests.swift | 24 +- .../MXKeyVerificationRequestV2UnitTests.swift | 181 ++++++++++-- .../SAS/MXSASTransactionV2UnitTests.swift | 137 ++++++---- MatrixSDKTests/TestPlans/UnitTests.xctestplan | 1 + .../UnitTestsWithSanitizers.xctestplan | 3 +- changelog.d/6589.feature | 1 + 19 files changed, 928 insertions(+), 341 deletions(-) create mode 100644 MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift create mode 100644 changelog.d/6589.feature diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 40cdc589fa..188a5c8cdc 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1907,6 +1907,8 @@ EDD578EA2881C37C006739DD /* MXCryptoUserIdentityWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578E02881C37C006739DD /* MXCryptoUserIdentityWrapper.swift */; }; EDD578EC2881C38C006739DD /* MXCrossSigningV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578EB2881C38C006739DD /* MXCrossSigningV2.swift */; }; EDD578ED2881C38C006739DD /* MXCrossSigningV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDD578EB2881C38C006739DD /* MXCrossSigningV2.swift */; }; + EDE1B13B28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE1B13A28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift */; }; + EDE1B13C28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE1B13A28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift */; }; EDF1B6902876CD2C00BBBCEE /* MXTaskQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF1B68F2876CD2C00BBBCEE /* MXTaskQueue.swift */; }; EDF1B6912876CD2C00BBBCEE /* MXTaskQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF1B68F2876CD2C00BBBCEE /* MXTaskQueue.swift */; }; EDF1B6932876CD8600BBBCEE /* MXTaskQueueUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF1B6922876CD8600BBBCEE /* MXTaskQueueUnitTests.swift */; }; @@ -2963,6 +2965,7 @@ EDD578DF2881C37C006739DD /* MXCryptoDeviceWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoDeviceWrapper.swift; sourceTree = ""; }; EDD578E02881C37C006739DD /* MXCryptoUserIdentityWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCryptoUserIdentityWrapper.swift; sourceTree = ""; }; EDD578EB2881C38C006739DD /* MXCrossSigningV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXCrossSigningV2.swift; sourceTree = ""; }; + EDE1B13A28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCrossSigningV2UnitTests.swift; sourceTree = ""; }; 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 = ""; }; @@ -5259,6 +5262,7 @@ children = ( ED8F1D1528857FDA00F897E7 /* Data */, ED8F1D242885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift */, + EDE1B13A28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift */, ); path = CrossSigning; sourceTree = ""; @@ -6945,6 +6949,7 @@ 32792BE12296C64200F4FC9D /* MXAggregatedEditsTests.m in Sources */, 329571931B0240CE00ABB3BA /* MXVoIPTests.m in Sources */, ED8F1D322885AC5700F897E7 /* Device+Stub.swift in Sources */, + EDE1B13B28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift in Sources */, EC746C56274E5197002AD24C /* MXThreadingServiceUnitTests.swift in Sources */, ED8F1D252885A39800F897E7 /* MXCrossSigningInfoSourceUnitTests.swift in Sources */, 32A27D1F19EC335300BAFADE /* MXRoomTests.m in Sources */, @@ -7543,6 +7548,7 @@ B1E09A332397FD750057C069 /* MXRoomStateTests.m in Sources */, 18937E7D273A5AE500902626 /* MXPollRelationTests.m in Sources */, B1E09A352397FD7D0057C069 /* MXEventTests.m in Sources */, + EDE1B13C28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift in Sources */, A816248525F60D0300A46F05 /* MXDeviceListOperationsPoolUnitTests.swift in Sources */, EC746C57274E5197002AD24C /* MXThreadingServiceUnitTests.swift in Sources */, B1E09A312397FD750057C069 /* MXSessionTests.m in Sources */, diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift index 9fafbe4983..d4ab28c349 100644 --- a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift @@ -33,8 +33,17 @@ class MXCrossSigningV2: MXCrossSigning { } override var state: MXCrossSigningState { - log.debug("Only partial implementation") - return hasAllPrivateKeys ? .canCrossSign : .notBootstrapped + if hasAllPrivateKeys { + return .canCrossSign + } else if let info = info { + if info.trustLevel.isVerified { + return .trustCrossSigning + } else { + return .crossSigningExists + } + } else { + return .notBootstrapped + } } override var canTrustCrossSigning: Bool { @@ -46,16 +55,20 @@ class MXCrossSigningV2: MXCrossSigning { } override var hasAllPrivateKeys: Bool { - let status = machine.crossSigningStatus() + let status = crossSigning.crossSigningStatus() return status.hasMaster && status.hasSelfSigning && status.hasUserSigning } - private let machine: MXCryptoMachine + private let crossSigning: MXCryptoCrossSigning + private let infoSource: MXCrossSigningInfoSource + private var info: MXCrossSigningInfo? private let restClient: MXRestClient + private let log = MXNamedLog(name: "MXCrossSigningV2") - init(machine: MXCryptoMachine, restClient: MXRestClient) { - self.machine = machine + init(crossSigning: MXCryptoCrossSigning, restClient: MXRestClient) { + self.crossSigning = crossSigning + self.infoSource = MXCrossSigningInfoSource(source: crossSigning) self.restClient = restClient } @@ -67,7 +80,7 @@ class MXCrossSigningV2: MXCrossSigning { Task { do { let authParams = try await authParameters(password: password) - try await machine.bootstrapCrossSigning(authParams: authParams) + try await crossSigning.bootstrapCrossSigning(authParams: authParams) await MainActor.run { success() } @@ -87,7 +100,7 @@ class MXCrossSigningV2: MXCrossSigning { ) { Task { do { - try await machine.bootstrapCrossSigning(authParams: authParams) + try await crossSigning.bootstrapCrossSigning(authParams: authParams) await MainActor.run { success() } @@ -104,8 +117,21 @@ class MXCrossSigningV2: MXCrossSigning { success: ((Bool) -> Void)?, failure: ((Swift.Error) -> Void)? = nil ) { - log.debug("Not implemented") - success?(true) + Task { + do { + try await crossSigning.downloadKeys(users: [crossSigning.userId]) + info = infoSource.crossSigningInfo(userId: crossSigning.userId) + + await MainActor.run { + success?(true) + } + } catch { + log.error("Cannot refresh cross signing state", context: error) + await MainActor.run { + failure?(error) + } + } + } } override func crossSignDevice( diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index daef68ccd8..d038010eb2 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -98,6 +98,33 @@ class MXCryptoMachine { } } +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoIdentity { + var userId: String { + return machine.userId() + } + + var deviceId: String { + return machine.deviceId() + } + + var deviceCurve25519Key: String? { + guard let key = machine.identityKeys()["curve25519"] else { + log.error("Cannot get device curve25519 key") + return nil + } + return key + } + + var deviceEd25519Key: String? { + guard let key = machine.identityKeys()["ed25519"] else { + log.error("Cannot get device ed25519 key") + return nil + } + return key + } +} + @available(iOS 13.0.0, *) extension MXCryptoMachine: MXCryptoSyncing { func handleSyncResponse( @@ -105,7 +132,7 @@ extension MXCryptoMachine: MXCryptoSyncing { deviceLists: MXDeviceListResponse?, deviceOneTimeKeysCounts: [String: NSNumber], unusedFallbackKeys: [String]? - ) throws { + ) throws -> MXToDeviceSyncResponse { let events = toDevice?.jsonString() ?? "[]" let deviceChanges = DeviceLists( changed: deviceLists?.changed ?? [], @@ -120,9 +147,13 @@ extension MXCryptoMachine: MXCryptoSyncing { unusedFallbackKeys: unusedFallbackKeys ) - if let result = MXTools.deserialiseJSONString(result) as? [String: Any], !result.isEmpty { - log(error: "Result processing not implemented \(result)") + guard let json = MXTools.deserialiseJSONString(result) as? [AnyHashable: Any] else { + log.error("Result cannot be serialized", context: [ + "result": result + ]) + return MXToDeviceSyncResponse() } + return MXToDeviceSyncResponse(fromJSON: json) } func completeSync() async throws { @@ -215,22 +246,6 @@ extension MXCryptoMachine: MXCryptoSyncing { @available(iOS 13.0.0, *) extension MXCryptoMachine: MXCryptoDevicesSource { - var deviceCurve25519Key: String? { - guard let key = machine.identityKeys()["curve25519"] else { - log.error("Cannot get device curve25519 key") - return nil - } - return key - } - - var deviceEd25519Key: String? { - guard let key = machine.identityKeys()["ed25519"] else { - log.error("Cannot get device ed25519 key") - return nil - } - return key - } - func devices(userId: String) -> [Device] { do { return try machine.getUserDevices(userId: userId, timeout: 0) @@ -269,6 +284,12 @@ extension MXCryptoMachine: MXCryptoUserIdentitySource { return nil } } + + func downloadKeys(users: [String]) async throws { + try await handleRequest( + .keysQuery(requestId: UUID().uuidString, users: users) + ) + } } @available(iOS 13.0.0, *) @@ -371,7 +392,15 @@ extension MXCryptoMachine: MXCryptoCrossSigning { } @available(iOS 13.0.0, *) -extension MXCryptoMachine: MXCryptoVerification { +extension MXCryptoMachine: MXCryptoVerificationRequesting { + func requestSelfVerification(methods: [String]) async throws -> VerificationRequest { + guard let result = try machine.requestSelfVerification(methods: methods) else { + throw Error.missingVerification + } + try await handleOutgoingVerificationRequest(result.request) + return result.verification + } + func requestVerification(userId: String, roomId: String, methods: [String]) async throws -> VerificationRequest { guard let content = try machine.verificationRequestContent(userId: userId, methods: methods) else { throw Error.missingVerificationContent @@ -403,18 +432,47 @@ extension MXCryptoMachine: MXCryptoVerification { return machine.getVerificationRequest(userId: userId, flowId: flowId) } - func verification(userId: String, flowId: String) -> Verification? { - return machine.getVerification(userId: userId, flowId: flowId) + func acceptVerificationRequest(userId: String, flowId: String, methods: [String]) async throws { + guard let request = machine.acceptVerificationRequest(userId: userId, flowId: flowId, methods: methods) else { + throw Error.missingVerificationRequest + } + try await handleOutgoingVerificationRequest(request) } - - func beginSasVerification(userId: String, flowId: String) async throws -> Sas { - guard let result = try machine.startSasVerification(userId: userId, flowId: flowId) else { - throw Error.missingVerification + + func cancelVerification(userId: String, flowId: String, cancelCode: String) async throws { + guard let request = machine.cancelVerification(userId: userId, flowId: flowId, cancelCode: cancelCode) else { + throw Error.cannotCancelVerification + } + try await handleOutgoingVerificationRequest(request) + } + + // MARK: - Private + + private func handleOutgoingVerificationRequest(_ request: OutgoingVerificationRequest) async throws { + switch request { + case .toDevice(_, let eventType, let body): + try await requests.sendToDevice( + request: .init( + eventType: eventType, + body: body + ) + ) + case .inRoom(_, let roomId, let eventType, let content): + let _ = try await sendRoomMessage( + roomId: roomId, + eventType: eventType, + content: content + ) } - try await handleOutgoingVerificationRequest(result.request) - return result.sas } +} +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoVerifying { + func verification(userId: String, flowId: String) -> Verification? { + return machine.getVerification(userId: userId, flowId: flowId) + } + func confirmVerification(userId: String, flowId: String) async throws { let result = try machine.confirmVerification(userId: userId, flowId: flowId) guard let result = result else { @@ -435,10 +493,21 @@ extension MXCryptoMachine: MXCryptoVerification { try await group.waitForAll() } } +} + +@available(iOS 13.0.0, *) +extension MXCryptoMachine: MXCryptoSASVerifying { + func startSasVerification(userId: String, flowId: String) async throws -> Sas { + guard let result = try machine.startSasVerification(userId: userId, flowId: flowId) else { + throw Error.missingVerification + } + try await handleOutgoingVerificationRequest(result.request) + return result.sas + } - func cancelVerification(userId: String, flowId: String, cancelCode: String) async throws { - guard let request = machine.cancelVerification(userId: userId, flowId: flowId, cancelCode: cancelCode) else { - throw Error.cannotCancelVerification + func acceptSasVerification(userId: String, flowId: String) async throws { + guard let request = machine.acceptSasVerification(userId: userId, flowId: flowId) else { + throw Error.missingVerification } try await handleOutgoingVerificationRequest(request) } @@ -449,21 +518,6 @@ extension MXCryptoMachine: MXCryptoVerification { } return indexes.map(Int.init) } - - // MARK: - Private - - private func handleOutgoingVerificationRequest(_ request: OutgoingVerificationRequest) async throws { - guard case .inRoom(let requestId, let roomId, let eventType, let content) = request else { - assertionFailure("Not yet implemented") - return - } - - let _ = try await sendRoomMessage( - roomId: roomId, - eventType: eventType, - content: content - ) - } } @available(iOS 13.0.0, *) diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift index be6a14d7c2..b9e92c1c40 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoProtocols.swift @@ -22,53 +22,81 @@ import MatrixSDKCrypto /// A set of protocols defining the functionality in `MatrixSDKCrypto` and separating them into logical units +/// Cryptographic identity of the currently signed-in user @available(iOS 13.0.0, *) -protocol MXCryptoSyncing { +protocol MXCryptoIdentity { + var userId: String { get } + var deviceId: String { get } + var deviceCurve25519Key: String? { get } + var deviceEd25519Key: String? { get } +} + +/// Handler for cryptographic events in the sync loop +@available(iOS 13.0.0, *) +protocol MXCryptoSyncing: MXCryptoIdentity { func handleSyncResponse( toDevice: MXToDeviceSyncResponse?, deviceLists: MXDeviceListResponse?, deviceOneTimeKeysCounts: [String: NSNumber], unusedFallbackKeys: [String]? - ) throws + ) throws -> MXToDeviceSyncResponse func completeSync() async throws } -protocol MXCryptoDevicesSource { - var deviceCurve25519Key: String? { get } - var deviceEd25519Key: String? { get } +/// Source of user devices and their cryptographic trust status +@available(iOS 13.0.0, *) +protocol MXCryptoDevicesSource: MXCryptoIdentity { func device(userId: String, deviceId: String) -> Device? func devices(userId: String) -> [Device] } -protocol MXCryptoUserIdentitySource { +/// Source of user identities and their cryptographic trust status +@available(iOS 13.0.0, *) +protocol MXCryptoUserIdentitySource: MXCryptoIdentity { func userIdentity(userId: String) -> UserIdentity? func isUserVerified(userId: String) -> Bool + func downloadKeys(users: [String]) async throws } +/// Event encryption and decryption @available(iOS 13.0.0, *) -protocol MXCryptoEventEncrypting { +protocol MXCryptoEventEncrypting: MXCryptoIdentity { func shareRoomKeysIfNecessary(roomId: String, users: [String]) async throws func encrypt(_ content: [AnyHashable: Any], roomId: String, eventType: String, users: [String]) async throws -> [String: Any] func decryptEvent(_ event: MXEvent) throws -> MXEventDecryptionResult } +/// Cross-signing functionality @available(iOS 13.0.0, *) -protocol MXCryptoCrossSigning { +protocol MXCryptoCrossSigning: MXCryptoUserIdentitySource { func crossSigningStatus() -> CrossSigningStatus func bootstrapCrossSigning(authParams: [AnyHashable: Any]) async throws } +/// Lifecycle of verification request @available(iOS 13.0.0, *) -protocol MXCryptoVerification { +protocol MXCryptoVerificationRequesting: MXCryptoIdentity { + func requestSelfVerification(methods: [String]) async throws -> VerificationRequest func requestVerification(userId: String, roomId: String, methods: [String]) async throws -> VerificationRequest func verificationRequest(userId: String, flowId: String) -> VerificationRequest? - + func acceptVerificationRequest(userId: String, flowId: String, methods: [String]) async throws + func cancelVerification(userId: String, flowId: String, cancelCode: String) async throws +} + +/// Lifecycle of verification transaction +@available(iOS 13.0.0, *) +protocol MXCryptoVerifying: MXCryptoIdentity { func verification(userId: String, flowId: String) -> Verification? - func beginSasVerification(userId: String, flowId: String) async throws -> Sas func confirmVerification(userId: String, flowId: String) async throws func cancelVerification(userId: String, flowId: String, cancelCode: String) async throws - +} + +/// Lifecycle of SAS-specific verification transaction +@available(iOS 13.0.0, *) +protocol MXCryptoSASVerifying: MXCryptoVerifying { + func startSasVerification(userId: String, flowId: String) async throws -> Sas + func acceptSasVerification(userId: String, flowId: String) async throws func emojiIndexes(sas: Sas) throws -> [Int] } diff --git a/MatrixSDK/Crypto/MXCryptoV2.swift b/MatrixSDK/Crypto/MXCryptoV2.swift index e9f02f3ace..4ffe745136 100644 --- a/MatrixSDK/Crypto/MXCryptoV2.swift +++ b/MatrixSDK/Crypto/MXCryptoV2.swift @@ -92,7 +92,7 @@ private class MXCryptoV2: MXCrypto { public override var backup: MXKeyBackup! { log.debug("Not implemented") - return nil + return MXKeyBackup() } public override var keyVerificationManager: MXKeyVerificationManager! { @@ -151,7 +151,7 @@ private class MXCryptoV2: MXCrypto { ) crossSign = MXCrossSigningV2( - machine: machine, + crossSigning: machine, restClient: restClient ) @@ -317,12 +317,13 @@ private class MXCryptoV2: MXCrypto { } do { - try machine.handleSyncResponse( + let toDevice = try machine.handleSyncResponse( toDevice: syncResponse.toDevice, deviceLists: syncResponse.deviceLists, deviceOneTimeKeysCounts: syncResponse.deviceOneTimeKeysCount ?? [:], unusedFallbackKeys: syncResponse.unusedFallbackKeys ) + keyVerification.handleDeviceEvents(toDevice.events) } catch { log.error("Cannot handle sync", context: error) } @@ -352,7 +353,6 @@ private class MXCryptoV2: MXCrypto { log.failure("Error processing outgoing requests", context: error) } } - keyVerification.updatePendingRequests() } // MARK: - Trust level @@ -436,11 +436,35 @@ private class MXCryptoV2: MXCrypto { success: ((MXUsersDevicesMap?, [String: MXCrossSigningInfo]?) -> Void)!, failure: ((Swift.Error?) -> Void)! ) -> MXHTTPOperation! { - // Note: Download keys currently ignores the `forceDownload` flag and returns local data only - success?( - deviceInfoSource.devicesMap(userIds: userIds), - crossSigningInfoSource.crossSigningInfo(userIds: userIds) - ) + guard let userIds = userIds else { + log.failure("Missing user ids") + return nil + } + + guard forceDownload else { + success?( + deviceInfoSource.devicesMap(userIds: userIds), + crossSigningInfoSource.crossSigningInfo(userIds: userIds) + ) + return MXHTTPOperation() + } + + Task { + do { + try await machine.downloadKeys(users: userIds) + await MainActor.run { + success?( + deviceInfoSource.devicesMap(userIds: userIds), + crossSigningInfoSource.crossSigningInfo(userIds: userIds) + ) + } + } catch { + await MainActor.run { + failure?(error) + } + } + } + return MXHTTPOperation() } diff --git a/MatrixSDK/Crypto/Recovery/MXRecoveryService.h b/MatrixSDK/Crypto/Recovery/MXRecoveryService.h index 1e93f21f72..b0a8d7d9c3 100644 --- a/MatrixSDK/Crypto/Recovery/MXRecoveryService.h +++ b/MatrixSDK/Crypto/Recovery/MXRecoveryService.h @@ -37,7 +37,7 @@ typedef NS_ENUM(NSInteger, MXRecoveryServiceErrorCode) /** - `MXRecoveryService` manages the backup of secrets/keys used by `MXCrypto``. + `MXRecoveryService` manages the backup of secrets/keys used by `MXCrypto`. It stores secrets stored locally (`MXCryptoStore`) on the homeserver SSSS (`MXSecretStorage`) and vice versa. diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.h b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.h index 01fbd4107b..6f27cfa0ac 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.h +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.h @@ -85,12 +85,6 @@ FOUNDATION_EXPORT NSString *const MXKeyVerificationManagerNotificationTransactio #pragma mark - Requests -/** - The timeout for requests. - Default is 5 min. - */ -@property (nonatomic) NSTimeInterval requestTimeout; - /** Make a key verification request by to_device events. @@ -180,14 +174,6 @@ FOUNDATION_EXPORT NSString *const MXKeyVerificationManagerNotificationTransactio success:(void(^)(MXKeyVerification *keyVerification))success failure:(void(^)(NSError *error))failure; -/** - Extract the verification identifier from an event. - - @param event an event in the verification process. - @return the key verification id. Nil if the event is not a verification event. - */ -- (nullable NSString *)keyVerificationIdFromDMEvent:(MXEvent*)event; - /** Retrieve pending QR code transaction diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m index f4b0bcd98f..6034c6a93d 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m @@ -79,6 +79,12 @@ @interface MXKeyVerificationManager () @property (nonatomic, strong) MXQRCodeDataBuilder *qrCodeDataBuilder; +/** + The timeout for requests. + Default is 5 min. + */ +@property (nonatomic) NSTimeInterval requestTimeout; + @end @implementation MXKeyVerificationManager diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift b/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift index 263b69ee1b..d1afdd7873 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift @@ -11,25 +11,36 @@ import Foundation import MatrixSDKCrypto +/// Result of processing updates on verification object (request or transaction) +/// after each sync loop +enum MXKeyVerificationUpdateResult { + // The object has not changed since last sync + case noUpdates + // The object's state has changed + case updated + // The object is no longer available (e.g. it was cancelled) + case removed +} + +@available(iOS 13.0.0, *) +typealias MXCryptoVerification = MXCryptoVerificationRequesting & MXCryptoSASVerifying + @available(iOS 13.0.0, *) class MXKeyVerificationManagerV2: MXKeyVerificationManager { - typealias GetOrCreateDMRoomId = (_ userId: String) async throws -> String - - override var requestTimeout: TimeInterval { - set { - log.debug("Not implemented") - } - get { - log.debug("Not implemented") - return 1000 - } + enum Error: Swift.Error { + case notSupported } + typealias GetOrCreateDMRoomId = (_ userId: String) async throws -> String + private let verification: MXCryptoVerification private let getOrCreateDMRoomId: GetOrCreateDMRoomId - private var requests: [MXKeyVerificationRequestV2] - private var transactions: [MXSASTransactionV2] + // We need to keep track of request / transaction objects by reference + // because various flows / screens subscribe to updates via global notifications + // posted through them + private var activeRequests: [String: MXKeyVerificationRequestV2] + private var activeTransactions: [String: MXSASTransactionV2] private let log = MXNamedLog(name: "MXKeyVerificationManagerV2") @@ -37,32 +48,46 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { self.verification = verification self.getOrCreateDMRoomId = getOrCreateDMRoomId - self.requests = [] - self.transactions = [] + self.activeRequests = [:] + self.activeTransactions = [:] super.init() } - func updatePendingRequests() { - for request in requests { - guard let req = verification.verificationRequest(userId: request.otherUser, flowId: request.requestId) else { - log.debug("No request found for id \(request.requestId)") - continue - } - request.update(request: req) - } + func handleDeviceEvents(_ events: [MXEvent]) { + // We only have to manually handle request and start events, + // because they require creation of new objects observed by the UI. + // The other events (e.g. cancellation) are handled automatically + // by `MXCryptoVerification` + let eventTypes: Set = [ + kMXMessageTypeKeyVerificationRequest, + kMXEventTypeStringKeyVerificationStart + ] - for transaction in transactions { - guard let verification = verification.verification(userId: transaction.otherUserId, flowId: transaction.transactionId) else { - log.debug("No transaction found for id \(transaction.transactionId)") + for event in events { + guard eventTypes.contains(event.type) else { continue } - guard case .sasV1(let sas) = verification else { - assertionFailure("Not implemented") + + guard + let userId = event.sender, + let flowId = event.content["transaction_id"] as? String + else { + log.error("Missing userId or flowId in event") continue } - transaction.update(sas: sas) + + switch event.type { + case kMXMessageTypeKeyVerificationRequest: + incomingVerificationRequest(userId: userId, flowId: flowId) + case kMXEventTypeStringKeyVerificationStart: + incomingVerificationStart(userId: userId, flowId: flowId) + default: + log.failure("Event type should not be handled by key verification", context: event.type) + } } + + updatePendingVerification() } override func requestVerificationByToDevice( @@ -70,10 +95,29 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { deviceIds: [String]?, methods: [String], success: @escaping (MXKeyVerificationRequest) -> Void, - failure: @escaping (Error) -> Void + failure: @escaping (Swift.Error) -> Void ) { - log.debug("Not implemented") - success(MXDefaultKeyVerificationRequest()) + guard userId == verification.userId else { + log.failure("To-device verification with other users is not supported") + failure(Error.notSupported) + return + } + + Task { + do { + let req = try await verification.requestSelfVerification(methods: methods) + + let request = addRequest(for: req, transport: .toDevice) + await MainActor.run { + success(request) + } + } catch { + log.error("Cannot request verification", context: error) + await MainActor.run { + failure(error) + } + } + } } override func requestVerificationByDM( @@ -82,7 +126,7 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { fallbackText: String, methods: [String], success: @escaping (MXKeyVerificationRequest) -> Void, - failure: @escaping (Error) -> Void + failure: @escaping (Swift.Error) -> Void ) { Task { do { @@ -92,10 +136,8 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { roomId: roomId, methods: methods ) - let request = MXKeyVerificationRequestV2(request: req) { [weak self] request, code in - self?.cancel(request: request, code: code) - } - requests.append(request) + + let request = addRequest(for: req, transport: .directMessage) await MainActor.run { success(request) } @@ -108,16 +150,12 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { } } - override var pendingRequests: [MXKeyVerificationRequest] { - return requests - } - override func beginKeyVerification( withUserId userId: String, andDeviceId deviceId: String, method: String, success: @escaping (MXKeyVerificationTransaction) -> Void, - failure: @escaping (Error) -> Void + failure: @escaping (Swift.Error) -> Void ) { log.debug("Not implemented") success(MXDefaultKeyVerificationTransaction()) @@ -127,24 +165,12 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { from request: MXKeyVerificationRequest, method: String, success: @escaping (MXKeyVerificationTransaction) -> Void, - failure: @escaping (Error) -> Void + failure: @escaping (Swift.Error) -> Void ) { Task { do { - let sas = try await verification.beginSasVerification(userId: request.otherUser, flowId: request.requestId) - let transaction = MXSASTransactionV2( - sas: sas, - getEmojisAction: { [weak self] in - self?.getEmojis(sas: $0) ?? [] - }, - confirmMatchAction: { [weak self] in - self?.confirm(transaction: $0) - }, - cancelAction: { [weak self] in - self?.cancel(transaction: $0, code: $1) - } - ) - transactions.append(transaction) + let sas = try await verification.startSasVerification(userId: request.otherUser, flowId: request.requestId) + let transaction = addSasTransaction(for: sas, transport: request.transport) await MainActor.run { success(transaction) @@ -158,25 +184,24 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { } } + override var pendingRequests: [MXKeyVerificationRequest] { + return Array(activeRequests.values) + } + override func transactions(_ complete: @escaping ([MXKeyVerificationTransaction]) -> Void) { - complete(transactions) + complete(Array(activeTransactions.values)) } override func keyVerification( fromKeyVerificationEvent event: MXEvent, success: @escaping (MXKeyVerification) -> Void, - failure: @escaping (Error) -> Void + failure: @escaping (Swift.Error) -> Void ) -> MXHTTPOperation? { log.debug("Not implemented") success(MXKeyVerification()) return MXHTTPOperation() } - - override func keyVerificationId(fromDMEvent event: MXEvent) -> String? { - log.debug("Not implemented") - return nil - } - + override func qrCodeTransaction(withTransactionId transactionId: String) -> MXQRCodeTransaction? { log.debug("Not implemented") return nil @@ -186,52 +211,95 @@ class MXKeyVerificationManagerV2: MXKeyVerificationManager { log.debug("Not implemented") } - override func notifyOthersOfAcceptance(withTransactionId transactionId: String, acceptedUserId: String, acceptedDeviceId: String, success: @escaping () -> Void, failure: @escaping (Error) -> Void) { + override func notifyOthersOfAcceptance(withTransactionId transactionId: String, acceptedUserId: String, acceptedDeviceId: String, success: @escaping () -> Void, failure: @escaping (Swift.Error) -> Void) { log.debug("Not implemented") success() } - private func getEmojis(sas: Sas) -> [MXEmojiRepresentation] { - do { - let indices = try verification.emojiIndexes(sas: sas) - let emojis = MXDefaultSASTransaction.allEmojiRepresentations() - return indices.compactMap { idx in - idx < emojis.count ? emojis[idx] : nil - } - } catch { - log.error("Cannot get emoji indices", context: error) - return [] + // MARK: - Private + + func incomingVerificationRequest(userId: String, flowId: String) { + guard let request = verification.verificationRequest(userId: userId, flowId: flowId) else { + log.error("Verification request is not known", context: [ + "flow_id": flowId + ]) + return } + + _ = addRequest(for: request, transport: .toDevice, notify: true) } - private func cancel(request: MXKeyVerificationRequest, code: MXTransactionCancelCode) { - Task { - do { - try await verification.cancelVerification(userId: request.otherUser, flowId: request.requestId, cancelCode: code.value) - } catch { - log.error("Cannot cancel request", context: error) - } + func incomingVerificationStart(userId: String, flowId: String) { + guard let verif = verification.verification(userId: userId, flowId: flowId) else { + log.error("Verification is not known", context: [ + "flow_id": flowId + ]) + return + } + + switch verif { + case .sasV1(let sas): + let transaction = addSasTransaction(for: sas, transport: .toDevice) + transaction.accept() + + case .qrCodeV1: + assertionFailure("Not implemented") } } - private func confirm(transaction: MXSASTransaction) { - Task { - do { - try await verification.confirmVerification(userId: transaction.otherUserId, flowId: transaction.transactionId) - } catch { - log.error("Cannot confirm transaction", context: error) + func updatePendingVerification() { + for request in activeRequests.values { + switch request.processUpdates() { + case .noUpdates: + break + case .updated: + NotificationCenter.default.post(name: .MXKeyVerificationRequestDidChange, object: request) + case .removed: + activeRequests[request.requestId] = nil + } + } + + for transaction in activeTransactions.values { + switch transaction.processUpdates() { + case .noUpdates: + break + case .updated: + NotificationCenter.default.post(name: .MXKeyVerificationTransactionDidChange, object: transaction) + case .removed: + activeTransactions[transaction.transactionId] = nil } } } - private func cancel(transaction: MXSASTransaction, code: MXTransactionCancelCode) { - Task { - do { - try await verification.cancelVerification(userId: transaction.otherUserId, flowId: transaction.transactionId, cancelCode: code.value) - } catch { - log.error("Cannot cancel request", context: error) - } + private func addRequest( + for request: VerificationRequest, + transport: MXKeyVerificationTransport, + notify: Bool = false + ) -> MXKeyVerificationRequestV2 { + + let request = MXKeyVerificationRequestV2( + request: request, + transport: transport, + handler: verification + ) + activeRequests[request.requestId] = request + + if notify { + NotificationCenter.default.post( + name: .MXKeyVerificationManagerNewRequest, + object: self, + userInfo: [ + MXKeyVerificationManagerNotificationRequestKey: request + ] + ) } + return request + } + + private func addSasTransaction(for sas: Sas, transport: MXKeyVerificationTransport) -> MXSASTransactionV2 { + let transaction = MXSASTransactionV2(sas: sas, transport: transport, handler: verification) + activeTransactions[transaction.transactionId] = transaction + return transaction } } diff --git a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift index 644f7eb57d..d290b095c5 100644 --- a/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift +++ b/MatrixSDK/Crypto/Verification/Requests/MXKeyVerificationRequestV2.swift @@ -21,9 +21,8 @@ import Foundation import MatrixSDKCrypto /// Verification request originating from `MatrixSDKCrypto` +@available(iOS 13.0.0, *) class MXKeyVerificationRequestV2: NSObject, MXKeyVerificationRequest { - typealias CancelAction = (MXKeyVerificationRequest, MXTransactionCancelCode) -> Void - var state: MXKeyVerificationRequestState { // State as enum will be moved to MatrixSDKCrypto in the future // to avoid the mapping of booleans into state @@ -50,24 +49,18 @@ class MXKeyVerificationRequestV2: NSObject, MXKeyVerificationRequest { } var isFromMyUser: Bool { - return request.weStarted + return otherUser == handler.userId } var isFromMyDevice: Bool { - // Not exposed on the underlying request, - // assuming that if request is from us, it is from our devide - log.debug("Not fully implemented") - return isFromMyUser + return request.weStarted } var requestId: String { return request.flowId } - var transport: MXKeyVerificationTransport { - log.debug("Not fully implemented") - return .directMessage - } + let transport: MXKeyVerificationTransport var otherUser: String { return request.otherUserId @@ -78,7 +71,7 @@ class MXKeyVerificationRequestV2: NSObject, MXKeyVerificationRequest { } var methods: [String] { - return (isFromMyUser ? myMethods : otherMethods) ?? [] + return (isFromMyDevice ? myMethods : otherMethods) ?? [] } var myMethods: [String]? { @@ -90,21 +83,26 @@ class MXKeyVerificationRequestV2: NSObject, MXKeyVerificationRequest { } private var request: VerificationRequest - private let cancelAction: CancelAction + private let handler: MXCryptoVerificationRequesting private let log = MXNamedLog(name: "MXKeyVerificationRequestV2") - init(request: VerificationRequest, cancelAction: @escaping CancelAction) { + init(request: VerificationRequest, transport: MXKeyVerificationTransport, handler: MXCryptoVerificationRequesting) { self.request = request - self.cancelAction = cancelAction + self.transport = transport + self.handler = handler } - func update(request: VerificationRequest) { + func processUpdates() -> MXKeyVerificationUpdateResult { + guard let request = handler.verificationRequest(userId: otherUser, flowId: requestId) else { + return .removed + } + guard self.request != request else { - return + return .noUpdates } self.request = request - NotificationCenter.default.post(name: .MXKeyVerificationRequestDidChange, object: self) + return .updated } func accept( @@ -112,7 +110,22 @@ class MXKeyVerificationRequestV2: NSObject, MXKeyVerificationRequest { success: @escaping () -> Void, failure: @escaping (Error) -> Void ) { - log.debug("Not implemented") + Task { + do { + try await handler.acceptVerificationRequest( + userId: otherUser, + flowId: requestId, + methods: methods + ) + await MainActor.run { + success() + } + } catch { + await MainActor.run { + failure(error) + } + } + } } func cancel( @@ -120,8 +133,22 @@ class MXKeyVerificationRequestV2: NSObject, MXKeyVerificationRequest { success: (() -> Void)?, failure: ((Error) -> Void)? = nil ) { - cancelAction(self, code) - success?() + Task { + do { + try await handler.cancelVerification( + userId: otherUser, + flowId: requestId, + cancelCode: code.value + ) + await MainActor.run { + success?() + } + } catch { + await MainActor.run { + failure?(error) + } + } + } } } diff --git a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift index fea7b33e86..a0ffafd0c3 100644 --- a/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift +++ b/MatrixSDK/Crypto/Verification/Transactions/SAS/MXSASTransactionV2.swift @@ -21,10 +21,8 @@ import Foundation import MatrixSDKCrypto /// SAS transaction originating from `MatrixSDKCrypto` +@available(iOS 13.0.0, *) class MXSASTransactionV2: NSObject, MXSASTransaction { - typealias GetEmojisAction = (Sas) -> [MXEmojiRepresentation] - typealias ConfirmMatchAction = (MXSASTransaction) -> Void - typealias CancelAction = (MXSASTransaction, MXTransactionCancelCode) -> Void var state: MXSASTransactionState { // State as enum will be moved to MatrixSDKCrypto in the future @@ -44,7 +42,16 @@ class MXSASTransactionV2: NSObject, MXSASTransaction { } var sasEmoji: [MXEmojiRepresentation]? { - return getEmojisAction(sas) + do { + let indices = try handler.emojiIndexes(sas: sas) + let emojis = MXDefaultSASTransaction.allEmojiRepresentations() + return indices.compactMap { idx in + idx < emojis.count ? emojis[idx] : nil + } + } catch { + log.error("Cannot get emoji indices", context: error) + return nil + } } var sasDecimal: String? { @@ -56,10 +63,7 @@ class MXSASTransactionV2: NSObject, MXSASTransaction { return sas.flowId } - var transport: MXKeyVerificationTransport { - log.debug("Not fully implemented") - return .directMessage - } + let transport: MXKeyVerificationTransport var isIncoming: Bool { return !sas.weStarted @@ -96,43 +100,72 @@ class MXSASTransactionV2: NSObject, MXSASTransaction { } private var sas: Sas - private let getEmojisAction: GetEmojisAction - private let confirmMatchAction: ConfirmMatchAction - private let cancelAction: CancelAction - + private let handler: MXCryptoSASVerifying + private let log = MXNamedLog(name: "MXSASTransactionV2") - init( - sas: Sas, - getEmojisAction: @escaping GetEmojisAction, - confirmMatchAction: @escaping ConfirmMatchAction, - cancelAction: @escaping CancelAction - ) { + init(sas: Sas, transport: MXKeyVerificationTransport, handler: MXCryptoSASVerifying) { self.sas = sas - self.getEmojisAction = getEmojisAction - self.confirmMatchAction = confirmMatchAction - self.cancelAction = cancelAction + self.transport = transport + self.handler = handler } - func update(sas: Sas) { + func processUpdates() -> MXKeyVerificationUpdateResult { + guard + let verification = handler.verification(userId: otherUserId, flowId: transactionId), + case .sasV1(let sas) = verification + else { + return .removed + } + guard self.sas != sas else { - return + return .noUpdates } self.sas = sas - NotificationCenter.default.post(name: .MXKeyVerificationTransactionDidChange, object: self) + return .updated + } + + func accept() { + Task { + do { + try await handler.acceptSasVerification(userId: otherUserId, flowId: transactionId) + } catch { + log.error("Cannot accept transaction", context: error) + } + } } func confirmSASMatch() { - confirmMatchAction(self) + Task { + do { + try await handler.confirmVerification(userId: otherUserId, flowId: transactionId) + } catch { + log.error("Cannot confirm transaction", context: error) + } + } } func cancel(with code: MXTransactionCancelCode) { - cancelAction(self, code) + cancel(with: code) { + // No-op + } failure: { [weak self] in + self?.log.error("Cannot cancel transaction", context: $0) + } } func cancel(with code: MXTransactionCancelCode, success: @escaping () -> Void, failure: @escaping (Error) -> Void) { - cancelAction(self, code) - success() + Task { + do { + try await handler.cancelVerification(userId: otherUserId, flowId: transactionId, cancelCode: code.value) + await MainActor.run { + success() + } + } catch { + await MainActor.run { + failure(error) + } + } + } } } diff --git a/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift new file mode 100644 index 0000000000..94868f3fec --- /dev/null +++ b/MatrixSDKTests/Crypto/CrossSigning/MXCrossSigningV2UnitTests.swift @@ -0,0 +1,89 @@ +// +// Copyright 2022 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 + +#if os(iOS) + +import MatrixSDKCrypto + +@available(iOS 13.0.0, *) +class MXCrossSigningV2UnitTests: XCTestCase { + + var crypto: CryptoCrossSigningStub! + var crossSigning: MXCrossSigningV2! + var restClient: MXRestClientStub! + + override func setUp() { + crypto = CryptoCrossSigningStub() + restClient = MXRestClientStub() + crossSigning = MXCrossSigningV2( + crossSigning: crypto, + restClient: restClient + ) + } + + func test_state_notBootstrapped() { + XCTAssertEqual(crossSigning.state, .notBootstrapped) + } + + func test_state_canCrossSign() { + crypto.stubbedStatus = CrossSigningStatus(hasMaster: true, hasSelfSigning: true, hasUserSigning: true) + XCTAssertEqual(crossSigning.state, .canCrossSign) + } + + func test_state_crossSigningExists() { + let exp = expectation(description: "exp") + crypto.stubbedVerifiedUsers = [] + crypto.stubbedIdentities = [ + "Alice": .own( + userId: "Alice", + trustsOurOwnDevice: true, + masterKey: "", + selfSigningKey: "", + userSigningKey: "" + ) + ] + crossSigning.refreshState { _ in + XCTAssertEqual(self.crossSigning.state, .crossSigningExists) + exp.fulfill() + } + waitForExpectations(timeout: 1) + } + + func test_state_trustCrossSigning() { + let exp = expectation(description: "exp") + crypto.stubbedVerifiedUsers = ["Alice"] + crypto.stubbedIdentities = [ + "Alice": .own( + userId: "Alice", + trustsOurOwnDevice: true, + masterKey: "", + selfSigningKey: "", + userSigningKey: "" + ) + ] + crossSigning.refreshState { _ in + XCTAssertEqual(self.crossSigning.state, .trustCrossSigning) + exp.fulfill() + } + waitForExpectations(timeout: 1) + } +} + +#endif diff --git a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift index 1e90360acf..5414778e37 100644 --- a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift +++ b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoProtocolStubs.swift @@ -21,7 +21,10 @@ import Foundation import MatrixSDKCrypto -class DevicesSourceStub: MXCryptoDevicesSource { +class CryptoIdentityStub: MXCryptoIdentity { + var userId: String = "Alice" + var deviceId: String = "ABCD" + var deviceCurve25519Key: String? { return nil } @@ -29,7 +32,9 @@ class DevicesSourceStub: MXCryptoDevicesSource { var deviceEd25519Key: String? { return nil } - +} + +class DevicesSourceStub: CryptoIdentityStub, MXCryptoDevicesSource { var devices = [String: [String: Device]]() func device(userId: String, deviceId: String) -> Device? { @@ -41,7 +46,8 @@ class DevicesSourceStub: MXCryptoDevicesSource { } } -class UserIdentitySourceStub: MXCryptoUserIdentitySource { +@available(iOS 13.0.0, *) +class UserIdentitySourceStub: CryptoIdentityStub, MXCryptoUserIdentitySource { var identities = [String: UserIdentity]() func userIdentity(userId: String) -> UserIdentity? { return identities[userId] @@ -51,6 +57,97 @@ class UserIdentitySourceStub: MXCryptoUserIdentitySource { func isUserVerified(userId: String) -> Bool { return verification[userId] ?? false } + + func downloadKeys(users: [String]) async throws { + + } +} + +@available(iOS 13.0.0, *) +class CryptoCrossSigningStub: CryptoIdentityStub, MXCryptoCrossSigning { + var stubbedStatus = CrossSigningStatus( + hasMaster: false, + hasSelfSigning: false, + hasUserSigning: false + ) + func crossSigningStatus() -> CrossSigningStatus { + return stubbedStatus + } + + func bootstrapCrossSigning(authParams: [AnyHashable : Any]) async throws { + } + + var stubbedIdentities = [String: UserIdentity]() + func userIdentity(userId: String) -> UserIdentity? { + stubbedIdentities[userId] + } + + var stubbedVerifiedUsers = Set() + func isUserVerified(userId: String) -> Bool { + return stubbedVerifiedUsers.contains(userId) + } + + func downloadKeys(users: [String]) async throws { + } +} + +@available(iOS 13.0.0, *) +class CryptoVerificationStub: CryptoIdentityStub { + var stubbedRequests = [String: VerificationRequest]() + var stubbedTransactions = [String: Verification]() + var stubbedErrors = [String: Error]() + var stubbedEmojis = [String: [Int]]() +} + +@available(iOS 13.0.0, *) +extension CryptoVerificationStub: MXCryptoVerificationRequesting { + func requestSelfVerification(methods: [String]) async throws -> VerificationRequest { + .stub() + } + + func requestVerification(userId: String, roomId: String, methods: [String]) async throws -> VerificationRequest { + .stub() + } + + func verificationRequest(userId: String, flowId: String) -> VerificationRequest? { + return stubbedRequests[flowId] + } + + func acceptVerificationRequest(userId: String, flowId: String, methods: [String]) async throws { + if let error = stubbedErrors[flowId] { + throw error + } + } + + func cancelVerification(userId: String, flowId: String, cancelCode: String) async throws { + if let error = stubbedErrors[flowId] { + throw error + } + } +} + +@available(iOS 13.0.0, *) +extension CryptoVerificationStub: MXCryptoVerifying { + func verification(userId: String, flowId: String) -> Verification? { + return stubbedTransactions[flowId] + } + + func confirmVerification(userId: String, flowId: String) async throws { + } +} + +@available(iOS 13.0.0, *) +extension CryptoVerificationStub: MXCryptoSASVerifying { + func startSasVerification(userId: String, flowId: String) async throws -> Sas { + .stub() + } + + func acceptSasVerification(userId: String, flowId: String) async throws { + } + + func emojiIndexes(sas: Sas) throws -> [Int] { + stubbedEmojis[sas.flowId] ?? [] + } } #endif diff --git a/MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift b/MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift index 299bc03223..87eb924f91 100644 --- a/MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift +++ b/MatrixSDKTests/Crypto/Devices/MXDeviceInfoSourceUnitTests.swift @@ -24,31 +24,11 @@ import MatrixSDKCrypto @available(iOS 13.0.0, *) class MXDeviceInfoSourceUnitTests: XCTestCase { - class SourceStub: MXCryptoDevicesSource { - var deviceCurve25519Key: String? { - return nil - } - - var deviceEd25519Key: String? { - return nil - } - - var devices = [String: [String: Device]]() - - func device(userId: String, deviceId: String) -> Device? { - return devices[userId]?[deviceId] - } - - func devices(userId: String) -> [Device] { - return devices[userId]?.map { $0.value } ?? [] - } - } - - var cryptoSource: SourceStub! + var cryptoSource: DevicesSourceStub! var source: MXDeviceInfoSource! override func setUp() { - cryptoSource = SourceStub() + cryptoSource = DevicesSourceStub() source = MXDeviceInfoSource(source: cryptoSource) } diff --git a/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift index 7e9a6d8003..e82a3bed82 100644 --- a/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift @@ -22,10 +22,31 @@ import XCTest import MatrixSDKCrypto @testable import MatrixSDK +@available(iOS 13.0.0, *) class MXKeyVerificationRequestV2UnitTests: XCTestCase { + enum Error: Swift.Error, Equatable { + case dummy + } + + var verification: CryptoVerificationStub! + + override func setUp() { + verification = CryptoVerificationStub() + } + + func makeRequest(for request: VerificationRequest = .stub()) -> MXKeyVerificationRequestV2 { + .init( + request: request, + transport: .directMessage, + handler: verification + ) + } + + // MARK: - Test Properties + func test_usesCorrectProperties() { let stub = VerificationRequest.stub( - otherUserId: "Bob", + otherUserId: "Alice", otherDeviceId: "Device2", flowId: "123", weStarted: true, @@ -33,22 +54,51 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { ourMethods: ["sas", "unknown"] ) - let request = MXKeyVerificationRequestV2( - request: stub, - cancelAction: { _, _ in } - ) + let request = makeRequest(for: stub) XCTAssertTrue(request.isFromMyUser) XCTAssertTrue(request.isFromMyDevice) XCTAssertEqual(request.requestId, "123") XCTAssertEqual(request.transport, MXKeyVerificationTransport.directMessage) - XCTAssertEqual(request.otherUser, "Bob") + XCTAssertEqual(request.otherUser, "Alice") XCTAssertEqual(request.otherDevice, "Device2") XCTAssertEqual(request.methods, ["sas", "unknown"]) XCTAssertEqual(request.myMethods, ["sas", "unknown"]) XCTAssertEqual(request.otherMethods, ["sas", "qr"]) } + func test_isFromMyUser_ifUsersMatch() { + verification.userId = "Alice" + let request1 = makeRequest(for: .stub( + otherUserId: "Alice" + )) + XCTAssertTrue(request1.isFromMyUser) + + let request2 = makeRequest(for: .stub( + otherUserId: "Bob" + )) + XCTAssertFalse(request2.isFromMyUser) + } + + func test_methodsForWhoStarted() { + let ourMethods = ["A", "B"] + let theirMethods = ["C", "D"] + + let request1 = makeRequest(for: .stub( + weStarted: true, + theirMethods: theirMethods, + ourMethods: ourMethods + )) + XCTAssertEqual(request1.methods, ourMethods) + + let request2 = makeRequest(for: .stub( + weStarted: false, + theirMethods: theirMethods, + ourMethods: ourMethods + )) + XCTAssertEqual(request2.methods, theirMethods) + } + func test_state() { let testCases: [(VerificationRequest, MXKeyVerificationRequestState)] = [ (.stub( @@ -96,14 +146,11 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { ] for (stub, state) in testCases { - let request = MXKeyVerificationRequestV2( - request: stub, - cancelAction: { _, _ in } - ) + let request = makeRequest(for: stub) XCTAssertEqual(request.state, state) } } - + func test_reasonCancelCode() { let cancelInfo = CancelInfo( cancelCode: "123", @@ -111,27 +158,113 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { cancelledByUs: true ) - let request = MXKeyVerificationRequestV2( - request: .stub(cancelInfo: cancelInfo), - cancelAction: { _, _ in } - ) - + let request = makeRequest(for: .stub(cancelInfo: cancelInfo)) + XCTAssertEqual(request.reasonCancelCode?.value, "123") XCTAssertEqual(request.reasonCancelCode?.humanReadable, "Changed mind") } - func test_update_postsNotification_ifChanged() { - let exp = expectation(description: "exp") - let request = MXKeyVerificationRequestV2( - request: .stub(isReady: false), - cancelAction: { _, _ in } + // MARK: - Test Updates + + func test_processUpdated_removedIfNoMatchingRequest() { + verification.stubbedRequests = [:] + let request = makeRequest() + + let result = request.processUpdates() + + XCTAssertEqual(result, VerificationUpdateResult.removed) + } + + func test_processUpdated_noUpdatesIfRequestUnchanged() { + let stub = VerificationRequest.stub( + flowId: "ABC", + isReady: false ) - NotificationCenter.default.addObserver(forName: .MXKeyVerificationRequestDidChange, object: request, queue: OperationQueue.main) { notif in - XCTAssertEqual(request.state, MXKeyVerificationRequestStateReady) + verification.stubbedRequests = [stub.flowId: stub] + let request = makeRequest(for: stub) + + let result = request.processUpdates() + + XCTAssertEqual(result, VerificationUpdateResult.noUpdates) + } + + func test_processUpdated_updatedIfRequestChanged() { + let stub = VerificationRequest.stub( + flowId: "ABC", + isReady: false + ) + verification.stubbedRequests = [stub.flowId: stub] + let request = makeRequest(for: stub) + verification.stubbedRequests = [stub.flowId: .stub( + flowId: "ABC", + isReady: true + )] + + let result = request.processUpdates() + + XCTAssertEqual(result, VerificationUpdateResult.updated) + XCTAssertEqual(request.state, MXKeyVerificationRequestStateReady) + } + + // MARK: - Test Interactions + + func test_acceptSucceeds() { + let exp = expectation(description: "exp") + verification.stubbedErrors = [:] + let request = makeRequest(for: .stub(flowId: "ABC")) + + request.accept(withMethods: []) { + exp.fulfill() + XCTAssert(true) + } failure: { _ in + XCTFail("Accepting should not fail") + } + + waitForExpectations(timeout: 1) + } + + func test_acceptFails() { + let exp = expectation(description: "exp") + verification.stubbedErrors = ["ABC": Error.dummy] + let request = makeRequest(for: .stub(flowId: "ABC")) + + request.accept(withMethods: []) { + XCTFail("Accepting should not succeed") + } failure: { error in exp.fulfill() + XCTAssertEqual(error as? Error, Error.dummy) } - request.update(request: .stub(isReady: true)) + waitForExpectations(timeout: 1) + } + + func test_cancelSucceeds() { + let exp = expectation(description: "exp") + verification.stubbedErrors = [:] + let request = makeRequest(for: .stub(flowId: "ABC")) + + request.cancel(with: MXTransactionCancelCode()) { + exp.fulfill() + XCTAssert(true) + } failure: { _ in + XCTFail("Cancelling should not fail") + } + + waitForExpectations(timeout: 1) + } + + func test_cancelFails() { + let exp = expectation(description: "exp") + verification.stubbedErrors = ["ABC": Error.dummy] + let request = makeRequest(for: .stub(flowId: "ABC")) + + + request.cancel(with: MXTransactionCancelCode()) { + XCTFail("Cancelling should not succeed") + } failure: { error in + exp.fulfill() + XCTAssertEqual(error as? Error, Error.dummy) + } waitForExpectations(timeout: 1) } diff --git a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift index 16c1c76af8..8e5df1e4ab 100644 --- a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift @@ -22,7 +22,23 @@ import XCTest import MatrixSDKCrypto @testable import MatrixSDK +@available(iOS 13.0.0, *) class MXSASTransactionV2UnitTests: XCTestCase { + var verification: CryptoVerificationStub! + override func setUp() { + verification = CryptoVerificationStub() + } + + func makeTransaction(for sas: Sas = .stub()) -> MXSASTransactionV2 { + .init( + sas: sas, + transport: .directMessage, + handler: verification + ) + } + + // MARK: - Test Properties + func test_usesCorrectProperties() { let stub = Sas.stub( otherUserId: "Bob", @@ -33,12 +49,7 @@ class MXSASTransactionV2UnitTests: XCTestCase { supportsEmoji: true ) - let transaction = MXSASTransactionV2( - sas: stub, - getEmojisAction: { _ in [] }, - confirmMatchAction: { _ in }, - cancelAction: { _, _ in } - ) + let transaction = makeTransaction(for: stub) XCTAssertEqual(transaction.transactionId, "123") XCTAssertEqual(transaction.transport, MXKeyVerificationTransport.directMessage) @@ -49,6 +60,22 @@ class MXSASTransactionV2UnitTests: XCTestCase { XCTAssertEqual(transaction.dmEventId, "123") } + func test_sasEmoji() { + // Index-to-emoji mapping specified in + // https://spec.matrix.org/v1.3/client-server-api/#sas-method-emoji + verification.stubbedEmojis = [ + "123": [1, 3, 10, 20] + ] + let expectedEmojis = ["🐱", "🐎", "🐧", "🌙"] + + let transaction = makeTransaction(for: .stub( + flowId: "123" + )) + + let emoji = transaction.sasEmoji?.map { $0.emoji } + XCTAssertEqual(emoji, expectedEmojis) + } + func test_state() { let testCases: [(Sas, MXSASTransactionState)] = [ (.stub( @@ -98,13 +125,24 @@ class MXSASTransactionV2UnitTests: XCTestCase { for (stub, state) in testCases { let transaction = MXSASTransactionV2( sas: stub, - getEmojisAction: { _ in [] }, - confirmMatchAction: { _ in }, - cancelAction: { _, _ in } + transport: .directMessage, + handler: verification ) XCTAssertEqual(transaction.state, state) } } + + func test_isIncomingIfWeStarted() { + let transaction1 = makeTransaction(for: .stub( + weStarted: true + )) + XCTAssertFalse(transaction1.isIncoming) + + let transaction2 = makeTransaction(for: .stub( + weStarted: true + )) + XCTAssertFalse(transaction2.isIncoming) + } func test_reasonCancelCode() { let cancelInfo = CancelInfo( @@ -115,65 +153,54 @@ class MXSASTransactionV2UnitTests: XCTestCase { let transaction = MXSASTransactionV2( sas: .stub(cancelInfo: cancelInfo), - getEmojisAction: { _ in [] }, - confirmMatchAction: { _ in }, - cancelAction: { _, _ in } + transport: .directMessage, + handler: verification ) XCTAssertEqual(transaction.reasonCancelCode?.value, "123") XCTAssertEqual(transaction.reasonCancelCode?.humanReadable, "Changed mind") } - - func test_update_postsNotification_ifChanged() { - let exp = expectation(description: "exp") - let transaction = MXSASTransactionV2( - sas: .stub(isDone: false), - getEmojisAction: { _ in [] }, - confirmMatchAction: { _ in }, - cancelAction: { _, _ in } - ) - NotificationCenter.default.addObserver(forName: .MXKeyVerificationTransactionDidChange, object: transaction, queue: OperationQueue.main) { notif in - XCTAssertEqual(transaction.state, MXSASTransactionStateVerified) - exp.fulfill() - } - - transaction.update(sas: .stub(isDone: true)) - - waitForExpectations(timeout: 1) - } - func test_sasEmoji_picksCorrectEmoji() { - let emoji = [ - MXEmojiRepresentation(emoji: "A", andName: "A"), - MXEmojiRepresentation(emoji: "B", andName: "B"), - MXEmojiRepresentation(emoji: "C", andName: "C"), - ] + // MARK: - Test Updates + + func test_processUpdated_removedIfNoMatchingRequest() { + verification.stubbedTransactions = [:] + let transaction = makeTransaction() - let transaction = MXSASTransactionV2( - sas: .stub(), - getEmojisAction: { _ in emoji }, - confirmMatchAction: { _ in }, - cancelAction: { _, _ in } - ) + let result = transaction.processUpdates() - XCTAssertEqual(transaction.sasEmoji, emoji) + XCTAssertEqual(result, VerificationUpdateResult.removed) } - func test_confirmSASMatch() { - let exp = expectation(description: "exp") - let transaction = MXSASTransactionV2( - sas: .stub(), - getEmojisAction: { _ in [] }, - confirmMatchAction: { _ in - XCTAssertTrue(true) - exp.fulfill() - }, - cancelAction: { _, _ in } + func test_processUpdated_noUpdatesIfRequestUnchanged() { + let stub = Sas.stub( + flowId: "ABC", + isDone: false ) + verification.stubbedTransactions = [stub.flowId: .sasV1(sas: stub)] + let transaction = makeTransaction(for: stub) - transaction.confirmSASMatch() + let result = transaction.processUpdates() + + XCTAssertEqual(result, VerificationUpdateResult.noUpdates) + } + + func test_processUpdated_updatedIfRequestChanged() { + let stub = Sas.stub( + flowId: "ABC", + isDone: false + ) + verification.stubbedTransactions = [stub.flowId: .sasV1(sas: stub)] + let transaction = makeTransaction(for: stub) + verification.stubbedTransactions = [stub.flowId: .sasV1(sas: .stub( + flowId: "ABC", + isDone: true + ))] - waitForExpectations(timeout: 1) + let result = transaction.processUpdates() + + XCTAssertEqual(result, VerificationUpdateResult.updated) + XCTAssertEqual(transaction.state, MXSASTransactionStateVerified) } } diff --git a/MatrixSDKTests/TestPlans/UnitTests.xctestplan b/MatrixSDKTests/TestPlans/UnitTests.xctestplan index 962842e076..a85e21f057 100644 --- a/MatrixSDKTests/TestPlans/UnitTests.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTests.xctestplan @@ -40,6 +40,7 @@ "MXCredentialsUnitTests", "MXCrossSigningInfoSourceUnitTests", "MXCrossSigningInfoUnitTests", + "MXCrossSigningV2UnitTests", "MXCryptoRequestsUnitTests", "MXDeviceInfoSourceUnitTests", "MXDeviceInfoUnitTests", diff --git a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan index 54fe76fe10..846fc94957 100644 --- a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan @@ -50,6 +50,7 @@ "MXCredentialsUnitTests", "MXCrossSigningInfoSourceUnitTests", "MXCrossSigningInfoUnitTests", + "MXCrossSigningV2UnitTests", "MXCryptoRequestsUnitTests", "MXDeviceInfoSourceUnitTests", "MXDeviceInfoUnitTests", @@ -82,7 +83,7 @@ "MXThreadEventTimelineUnitTests", "MXThreadingServiceUnitTests", "MXToolsUnitTests", - "MXTrustLevelSourceUnitTests", + "MXTrustLevelSourceUnitTests" ], "target" : { "containerPath" : "container:MatrixSDK.xcodeproj", diff --git a/changelog.d/6589.feature b/changelog.d/6589.feature new file mode 100644 index 0000000000..e1ae486917 --- /dev/null +++ b/changelog.d/6589.feature @@ -0,0 +1 @@ +CryptoV2: Self-verification flow From ee12ce3cdff28aa1c3bacef32923be146bb50572 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Fri, 26 Aug 2022 15:00:21 +0100 Subject: [PATCH 56/65] Cache inbound group sessions when decrypting --- MatrixSDK/Crypto/MXOlmDevice.m | 64 +++++++++++++++++++++++++-- MatrixSDK/MXSDKOptions.h | 8 ++++ MatrixSDK/MXSDKOptions.m | 4 ++ MatrixSDK/MXSession.m | 11 +++++ MatrixSDK/Utils/MXAnalyticsDelegate.h | 21 +++++++++ 5 files changed, 104 insertions(+), 4 deletions(-) diff --git a/MatrixSDK/Crypto/MXOlmDevice.m b/MatrixSDK/Crypto/MXOlmDevice.m index a3b9aa0383..a8f0efdc62 100644 --- a/MatrixSDK/Crypto/MXOlmDevice.m +++ b/MatrixSDK/Crypto/MXOlmDevice.m @@ -29,6 +29,8 @@ #import "MXKeyProvider.h" #import "MXRawDataKey.h" +NSInteger const kMXInboundGroupSessionCacheSize = 100; + @interface MXOlmDevice () { // The OLMKit utility instance. @@ -53,8 +55,10 @@ @interface MXOlmDevice () // The store where crypto data is saved. @property (nonatomic, readonly) id store; -@end +// Cache to avoid refetching unchanged sessions from the crypto store +@property (nonatomic, strong) MXLRUCache *inboundGroupSessionCache; +@end @implementation MXOlmDevice @synthesize store; @@ -98,6 +102,8 @@ - (instancetype)initWithStore:(id)theStore _deviceCurve25519Key = olmAccount.identityKeys[@"curve25519"]; _deviceEd25519Key = olmAccount.identityKeys[@"ed25519"]; + + _inboundGroupSessionCache = [[MXLRUCache alloc] initWithCapacity:kMXInboundGroupSessionCacheSize]; } return self; } @@ -394,7 +400,7 @@ - (BOOL)addInboundGroupSession:(NSString*)sessionId session.sharedHistory = sharedHistory; } - [store storeInboundGroupSessions:@[session]]; + [self storeInboundGroupSessions:@[session]]; return YES; } @@ -441,7 +447,7 @@ - (BOOL)addInboundGroupSession:(NSString*)sessionId [sessions addObject:session]; } - [store storeInboundGroupSessions:sessions]; + [self storeInboundGroupSessions:sessions]; return sessions; } @@ -462,7 +468,7 @@ - (MXDecryptionResult *)decryptGroupMessage:(NSString *)body MXDecryptionResult *result; - [store performSessionOperationWithGroupSessionWithId:sessionId senderKey:senderKey block:^(MXOlmInboundGroupSession *session) { + [self performGroupSessionOperationWithSessionId:sessionId senderKey:senderKey block:^(MXOlmInboundGroupSession *session) { *error = [self checkInboundGroupSession:session roomId:roomId]; if (*error) @@ -521,6 +527,41 @@ - (MXDecryptionResult *)decryptGroupMessage:(NSString *)body return result; } +- (void)performGroupSessionOperationWithSessionId:(NSString*)sessionId senderKey:(NSString*)senderKey block:(void (^)(MXOlmInboundGroupSession *inboundGroupSession))block +{ + // Based on a feature flag megolm decryption will either fetch a group session from the store on every decryption, + // or (if the flag is enabled) it will use LRU cache to avoid refetching unchanged sessions. + // + // Additionally the duration of each variant is tracked in analytics (if configured and enabled by the user) + // to allow performance comparison + // + // LRU cache variant will eventually become the default implementation if proved stable. + + BOOL enableCache = MXSDKOptions.sharedInstance.enableGroupSessionCache; + NSString *operation = enableCache ? @"megolm.decrypt.cache" : @"megolm.decrypt.store"; + StopDurationTracking stopTracking = [MXSDKOptions.sharedInstance.analyticsDelegate startDurationTrackingForName:@"MXOlmDevice" operation:operation]; + + if (enableCache) + { + __block MXOlmInboundGroupSession *session; + @synchronized (self.inboundGroupSessionCache) + { + session = (MXOlmInboundGroupSession *)[self.inboundGroupSessionCache get:sessionId]; + if (!session) + { + session = [store inboundGroupSessionWithId:sessionId andSenderKey:senderKey]; + [self.inboundGroupSessionCache put:sessionId object:session]; + } + } + block(session); + } + else + { + [store performSessionOperationWithGroupSessionWithId:sessionId senderKey:senderKey block:block]; + } + stopTracking(); +} + - (void)resetReplayAttackCheckInTimeline:(NSString*)timeline { [inboundGroupSessionMessageIndexes removeObjectForKey:timeline]; @@ -622,6 +663,21 @@ - (NSDictionary*)getInboundGroupSessionKey:(NSString*)roomId senderKey:(NSString return inboundGroupSessionKey; } +- (void)storeInboundGroupSessions:(NSArray *)sessions +{ + [store storeInboundGroupSessions:sessions]; + if (MXSDKOptions.sharedInstance.enableGroupSessionCache) + { + @synchronized (self.inboundGroupSessionCache) + { + for (MXOlmInboundGroupSession *session in sessions) + { + [self.inboundGroupSessionCache put:session.session.sessionIdentifier object:session]; + } + } + } +} + #pragma mark - OLMKitPickleKeyDelegate diff --git a/MatrixSDK/MXSDKOptions.h b/MatrixSDK/MXSDKOptions.h index 9de9ca59bb..3d7f29072f 100644 --- a/MatrixSDK/MXSDKOptions.h +++ b/MatrixSDK/MXSDKOptions.h @@ -214,6 +214,14 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic) BOOL enableCryptoV2; +/** + Enable performance optimization where inbound group sessions are cached between decryption of events + rather than fetched from the store every time. + + @remark The value is set randomly between YES / NO to perform a very basic A/B test + */ +@property (nonatomic) BOOL enableGroupSessionCache; + #endif @end diff --git a/MatrixSDK/MXSDKOptions.m b/MatrixSDK/MXSDKOptions.m index 9526f33233..9243741ca3 100644 --- a/MatrixSDK/MXSDKOptions.m +++ b/MatrixSDK/MXSDKOptions.m @@ -58,6 +58,10 @@ - (instancetype)init #if DEBUG _enableCryptoV2 = NO; #endif + + // The value is set randomly between YES / NO to perform a very basic A/B test + // measured by `analytics` (if set and enabled) + _enableGroupSessionCache = arc4random_uniform(2) == 1; } return self; diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index f79d04de66..0d447a5b08 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -1406,6 +1406,7 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout dispatch_group_t initialSyncDispatchGroup = dispatch_group_create(); __block MXTaskProfile *syncTaskProfile; + __block StopDurationTracking stopDurationTracking; __block MXSyncResponse *syncResponse; __block BOOL useLiveResponse = YES; @@ -1437,6 +1438,13 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout BOOL isInitialSync = !self.isEventStreamInitialised; MXTaskProfileName taskName = isInitialSync ? MXTaskProfileNameStartupInitialSync : MXTaskProfileNameStartupIncrementalSync; syncTaskProfile = [MXSDKOptions.sharedInstance.profiler startMeasuringTaskWithName:taskName]; + if (isInitialSync) { + // Temporarily tracking performance both by `MXSDKOptions.sharedInstance.profiler` (manually measuring time) + // and `MXSDKOptions.sharedInstance.analyticsDelegate` (delegating to performance monitoring tool). + // This ambiguity will be resolved in the future + NSString *operation = MXSDKOptions.sharedInstance.enableGroupSessionCache ? @"initialSync.enableGroupSessionCache" : @"initialSync.diableGroupSessionCache"; + stopDurationTracking = [MXSDKOptions.sharedInstance.analyticsDelegate startDurationTrackingForName:@"MXSession" operation:operation]; + } } NSString * streamToken = self.store.eventStreamToken; @@ -1479,6 +1487,9 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout syncTaskProfile.units = syncResponse.rooms.join.count; [MXSDKOptions.sharedInstance.profiler stopMeasuringTaskWithProfile:syncTaskProfile]; + if (stopDurationTracking) { + stopDurationTracking(); + } } BOOL isInitialSync = !self.isEventStreamInitialised; diff --git a/MatrixSDK/Utils/MXAnalyticsDelegate.h b/MatrixSDK/Utils/MXAnalyticsDelegate.h index d63b92135a..7e32481025 100644 --- a/MatrixSDK/Utils/MXAnalyticsDelegate.h +++ b/MatrixSDK/Utils/MXAnalyticsDelegate.h @@ -20,6 +20,12 @@ #import "MXCallHangupEventContent.h" #import "MXTaskProfile.h" +/** + Callback function to cancel ongoing duration tracking + started by `[MXAnalyticsDelegate startDurationTracking]` + */ +typedef void (^StopDurationTracking)(void); + NS_ASSUME_NONNULL_BEGIN /** @@ -46,6 +52,21 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)trackDuration:(NSInteger)milliseconds name:(MXTaskProfileName)name units:(NSUInteger)units; +/** + Start tracking the duration of a task and manually cancel when finished using the return handle + + @note This method is similar to `trackDuration`, but instead of passing the measured duraction + as a parameter, it relies on the implementation of `MXAnalyticsDelegate` to perform the + measurements. + + @param name Name of the entity being measured (e.g. `RoomsViewController` or `Crypto`) + @param operation Short code identifying the type of operation measured (e.g. `viewDidLoad` or `decrypt`) + + + @return Handle that can be used to stop the performance tracking + */ +- (StopDurationTracking)startDurationTrackingForName:(NSString *)name operation:(NSString *)operation; + /** Report that a call has started. From 8a3e73ebc93e25a5eea0e8607b46fb448aa5b31b Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Fri, 26 Aug 2022 16:31:13 +0100 Subject: [PATCH 57/65] Changelog --- changelog.d/pr-1566.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-1566.change diff --git a/changelog.d/pr-1566.change b/changelog.d/pr-1566.change new file mode 100644 index 0000000000..6a2a541261 --- /dev/null +++ b/changelog.d/pr-1566.change @@ -0,0 +1 @@ +Crypto: Cache inbound group sessions when decrypting From 2441b66409666a0ac97bfecd8f9cf57bd7669e3d Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Fri, 26 Aug 2022 16:52:39 +0100 Subject: [PATCH 58/65] Use key constants --- .../Crypto/CrossSigning/JSONModels/MXCrossSigningKey.m | 1 + MatrixSDK/Crypto/CrossSigning/MXCrossSigningTools.m | 1 + MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift | 4 ++-- MatrixSDK/Crypto/Data/MXCryptoConstants.h | 7 +++++++ MatrixSDK/Crypto/Data/MXCryptoConstants.m | 4 ++++ MatrixSDK/Crypto/Data/MXKey.h | 7 ------- MatrixSDK/Crypto/Data/MXKey.m | 4 ---- MatrixSDK/Crypto/MXOlmDevice.m | 5 +++-- MatrixSDK/MatrixSDK.h | 2 ++ .../Requests/MXKeyVerificationRequestV2UnitTests.swift | 6 +++--- .../Transactions/SAS/MXSASTransactionV2UnitTests.swift | 6 +++--- 11 files changed, 26 insertions(+), 21 deletions(-) diff --git a/MatrixSDK/Crypto/CrossSigning/JSONModels/MXCrossSigningKey.m b/MatrixSDK/Crypto/CrossSigning/JSONModels/MXCrossSigningKey.m index ac2ea52693..c648633deb 100644 --- a/MatrixSDK/Crypto/CrossSigning/JSONModels/MXCrossSigningKey.m +++ b/MatrixSDK/Crypto/CrossSigning/JSONModels/MXCrossSigningKey.m @@ -17,6 +17,7 @@ #import "MXCrossSigningKey.h" #import "MXKey.h" +#import "MXCryptoConstants.h" #pragma mark - Constants diff --git a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningTools.m b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningTools.m index 21003ba876..a80479b169 100644 --- a/MatrixSDK/Crypto/CrossSigning/MXCrossSigningTools.m +++ b/MatrixSDK/Crypto/CrossSigning/MXCrossSigningTools.m @@ -18,6 +18,7 @@ #import "MXCryptoTools.h" #import "MXKey.h" +#import "MXCryptoConstants.h" #pragma mark - Constants diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index d038010eb2..1f1d73021a 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -109,7 +109,7 @@ extension MXCryptoMachine: MXCryptoIdentity { } var deviceCurve25519Key: String? { - guard let key = machine.identityKeys()["curve25519"] else { + guard let key = machine.identityKeys()[kMXKeyCurve25519Type] else { log.error("Cannot get device curve25519 key") return nil } @@ -117,7 +117,7 @@ extension MXCryptoMachine: MXCryptoIdentity { } var deviceEd25519Key: String? { - guard let key = machine.identityKeys()["ed25519"] else { + guard let key = machine.identityKeys()[kMXKeyEd25519Type] else { log.error("Cannot get device ed25519 key") return nil } diff --git a/MatrixSDK/Crypto/Data/MXCryptoConstants.h b/MatrixSDK/Crypto/Data/MXCryptoConstants.h index ef9b004674..5d16b8f26d 100644 --- a/MatrixSDK/Crypto/Data/MXCryptoConstants.h +++ b/MatrixSDK/Crypto/Data/MXCryptoConstants.h @@ -18,6 +18,13 @@ #import +/** + Key types + */ +FOUNDATION_EXPORT NSString *const kMXKeyCurve25519Type; +FOUNDATION_EXPORT NSString *const kMXKeySignedCurve25519Type; +FOUNDATION_EXPORT NSString *const kMXKeyEd25519Type; + /** Matrix algorithm tag for olm. */ diff --git a/MatrixSDK/Crypto/Data/MXCryptoConstants.m b/MatrixSDK/Crypto/Data/MXCryptoConstants.m index a804a41479..ed0a9d618f 100644 --- a/MatrixSDK/Crypto/Data/MXCryptoConstants.m +++ b/MatrixSDK/Crypto/Data/MXCryptoConstants.m @@ -17,6 +17,10 @@ #import "MXCryptoConstants.h" +NSString *const kMXKeyCurve25519Type = @"curve25519"; +NSString *const kMXKeySignedCurve25519Type = @"signed_curve25519"; +NSString *const kMXKeyEd25519Type = @"ed25519"; + NSString *const kMXCryptoOlmAlgorithm = @"m.olm.v1.curve25519-aes-sha2"; NSString *const kMXCryptoMegolmAlgorithm = @"m.megolm.v1.aes-sha2"; NSString *const kMXCryptoCurve25519KeyBackupAlgorithm = @"m.megolm_backup.v1.curve25519-aes-sha2"; diff --git a/MatrixSDK/Crypto/Data/MXKey.h b/MatrixSDK/Crypto/Data/MXKey.h index ed10952233..4ae65cb719 100644 --- a/MatrixSDK/Crypto/Data/MXKey.h +++ b/MatrixSDK/Crypto/Data/MXKey.h @@ -18,13 +18,6 @@ #import "MXUsersDevicesMap.h" -/** - Key types. - */ -FOUNDATION_EXPORT NSString *const kMXKeyCurve25519Type; -FOUNDATION_EXPORT NSString *const kMXKeySignedCurve25519Type; -FOUNDATION_EXPORT NSString *const kMXKeyEd25519Type; - /** A `MXKey` instance stores a key data shared for Matrix cryptography. */ diff --git a/MatrixSDK/Crypto/Data/MXKey.m b/MatrixSDK/Crypto/Data/MXKey.m index 703f64c482..3c41e8dda8 100644 --- a/MatrixSDK/Crypto/Data/MXKey.m +++ b/MatrixSDK/Crypto/Data/MXKey.m @@ -16,10 +16,6 @@ #import "MXKey.h" -NSString *const kMXKeyCurve25519Type = @"curve25519"; -NSString *const kMXKeySignedCurve25519Type = @"signed_curve25519"; -NSString *const kMXKeyEd25519Type = @"ed25519"; - @interface MXKey() /** diff --git a/MatrixSDK/Crypto/MXOlmDevice.m b/MatrixSDK/Crypto/MXOlmDevice.m index a3b9aa0383..7f7081f88a 100644 --- a/MatrixSDK/Crypto/MXOlmDevice.m +++ b/MatrixSDK/Crypto/MXOlmDevice.m @@ -28,6 +28,7 @@ #import "MXKeyProvider.h" #import "MXRawDataKey.h" +#import "MXCryptoConstants.h" @interface MXOlmDevice () { @@ -96,8 +97,8 @@ - (instancetype)initWithStore:(id)theStore inboundGroupSessionMessageIndexes = [NSMutableDictionary dictionary]; - _deviceCurve25519Key = olmAccount.identityKeys[@"curve25519"]; - _deviceEd25519Key = olmAccount.identityKeys[@"ed25519"]; + _deviceCurve25519Key = olmAccount.identityKeys[kMXKeyCurve25519Type]; + _deviceEd25519Key = olmAccount.identityKeys[kMXKeyEd25519Type]; } return self; } diff --git a/MatrixSDK/MatrixSDK.h b/MatrixSDK/MatrixSDK.h index b2308292df..c39fa05d3a 100644 --- a/MatrixSDK/MatrixSDK.h +++ b/MatrixSDK/MatrixSDK.h @@ -156,6 +156,7 @@ FOUNDATION_EXPORT NSString *MatrixSDKVersion; #import "MXLoginSSOIdentityProviderBrand.h" // Bridging to Swift +#import "MXCryptoConstants.h" #import "MXCryptoStore.h" #import "MXRealmCryptoStore.h" #import "MXCryptoAlgorithms.h" @@ -193,3 +194,4 @@ FOUNDATION_EXPORT NSString *MatrixSDKVersion; #import "MXBeaconInfo.h" #import "MXBeacon.h" #import "MXEventAssetType.h" + diff --git a/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift index e82a3bed82..bb1d9ffc9b 100644 --- a/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/Verification/Requests/MXKeyVerificationRequestV2UnitTests.swift @@ -172,7 +172,7 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { let result = request.processUpdates() - XCTAssertEqual(result, VerificationUpdateResult.removed) + XCTAssertEqual(result, MXKeyVerificationUpdateResult.removed) } func test_processUpdated_noUpdatesIfRequestUnchanged() { @@ -185,7 +185,7 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { let result = request.processUpdates() - XCTAssertEqual(result, VerificationUpdateResult.noUpdates) + XCTAssertEqual(result, MXKeyVerificationUpdateResult.noUpdates) } func test_processUpdated_updatedIfRequestChanged() { @@ -202,7 +202,7 @@ class MXKeyVerificationRequestV2UnitTests: XCTestCase { let result = request.processUpdates() - XCTAssertEqual(result, VerificationUpdateResult.updated) + XCTAssertEqual(result, MXKeyVerificationUpdateResult.updated) XCTAssertEqual(request.state, MXKeyVerificationRequestStateReady) } diff --git a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift index 8e5df1e4ab..8fb770f565 100644 --- a/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift +++ b/MatrixSDKTests/Crypto/Verification/Transactions/SAS/MXSASTransactionV2UnitTests.swift @@ -169,7 +169,7 @@ class MXSASTransactionV2UnitTests: XCTestCase { let result = transaction.processUpdates() - XCTAssertEqual(result, VerificationUpdateResult.removed) + XCTAssertEqual(result, MXKeyVerificationUpdateResult.removed) } func test_processUpdated_noUpdatesIfRequestUnchanged() { @@ -182,7 +182,7 @@ class MXSASTransactionV2UnitTests: XCTestCase { let result = transaction.processUpdates() - XCTAssertEqual(result, VerificationUpdateResult.noUpdates) + XCTAssertEqual(result, MXKeyVerificationUpdateResult.noUpdates) } func test_processUpdated_updatedIfRequestChanged() { @@ -199,7 +199,7 @@ class MXSASTransactionV2UnitTests: XCTestCase { let result = transaction.processUpdates() - XCTAssertEqual(result, VerificationUpdateResult.updated) + XCTAssertEqual(result, MXKeyVerificationUpdateResult.updated) XCTAssertEqual(transaction.state, MXSASTransactionStateVerified) } } From b3b481e7ff507e5dbd7026afae17f16108ada3fa Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Tue, 30 Aug 2022 11:56:42 +0100 Subject: [PATCH 59/65] PR review --- MatrixSDK/Crypto/MXOlmDevice.m | 5 ++++- MatrixSDK/MXSDKOptions.h | 6 +++--- MatrixSDK/Utils/MXAnalyticsDelegate.h | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/MatrixSDK/Crypto/MXOlmDevice.m b/MatrixSDK/Crypto/MXOlmDevice.m index a8f0efdc62..bc05124ed4 100644 --- a/MatrixSDK/Crypto/MXOlmDevice.m +++ b/MatrixSDK/Crypto/MXOlmDevice.m @@ -559,7 +559,10 @@ - (void)performGroupSessionOperationWithSessionId:(NSString*)sessionId senderKey { [store performSessionOperationWithGroupSessionWithId:sessionId senderKey:senderKey block:block]; } - stopTracking(); + if (stopTracking) + { + stopTracking(); + } } - (void)resetReplayAttackCheckInTimeline:(NSString*)timeline diff --git a/MatrixSDK/MXSDKOptions.h b/MatrixSDK/MXSDKOptions.h index 3d7f29072f..56f2005ab5 100644 --- a/MatrixSDK/MXSDKOptions.h +++ b/MatrixSDK/MXSDKOptions.h @@ -214,16 +214,16 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic) BOOL enableCryptoV2; +#endif + /** Enable performance optimization where inbound group sessions are cached between decryption of events rather than fetched from the store every time. - @remark The value is set randomly between YES / NO to perform a very basic A/B test + @remark By default, the value is set randomly between YES / NO to perform a very basic A/B test */ @property (nonatomic) BOOL enableGroupSessionCache; -#endif - @end NS_ASSUME_NONNULL_END diff --git a/MatrixSDK/Utils/MXAnalyticsDelegate.h b/MatrixSDK/Utils/MXAnalyticsDelegate.h index 7e32481025..ddc73d8fe7 100644 --- a/MatrixSDK/Utils/MXAnalyticsDelegate.h +++ b/MatrixSDK/Utils/MXAnalyticsDelegate.h @@ -21,7 +21,7 @@ #import "MXTaskProfile.h" /** - Callback function to cancel ongoing duration tracking + Callback function to stop ongoing duration tracking started by `[MXAnalyticsDelegate startDurationTracking]` */ typedef void (^StopDurationTracking)(void); @@ -53,7 +53,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)trackDuration:(NSInteger)milliseconds name:(MXTaskProfileName)name units:(NSUInteger)units; /** - Start tracking the duration of a task and manually cancel when finished using the return handle + Start tracking the duration of a task and manually stop when finished using the return handle @note This method is similar to `trackDuration`, but instead of passing the measured duraction as a parameter, it relies on the implementation of `MXAnalyticsDelegate` to perform the From 02b3541278fb22e2bd94f2fbb8cb3225b466cc31 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Tue, 30 Aug 2022 14:11:45 +0100 Subject: [PATCH 60/65] Include decryption block inside synchronisation block --- MatrixSDK/Crypto/MXOlmDevice.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MatrixSDK/Crypto/MXOlmDevice.m b/MatrixSDK/Crypto/MXOlmDevice.m index 2a5ddbc015..e52a6f0749 100644 --- a/MatrixSDK/Crypto/MXOlmDevice.m +++ b/MatrixSDK/Crypto/MXOlmDevice.m @@ -544,17 +544,16 @@ - (void)performGroupSessionOperationWithSessionId:(NSString*)sessionId senderKey if (enableCache) { - __block MXOlmInboundGroupSession *session; @synchronized (self.inboundGroupSessionCache) { - session = (MXOlmInboundGroupSession *)[self.inboundGroupSessionCache get:sessionId]; + MXOlmInboundGroupSession *session = (MXOlmInboundGroupSession *)[self.inboundGroupSessionCache get:sessionId]; if (!session) { session = [store inboundGroupSessionWithId:sessionId andSenderKey:senderKey]; [self.inboundGroupSessionCache put:sessionId object:session]; } + block(session); } - block(session); } else { From c8396262fadb72a03785f0e3607369f80b049148 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 31 Aug 2022 14:36:01 +0200 Subject: [PATCH 61/65] README: Update the badge header More importantly, fix the coverage one to make it open the codevoc.io URL correctly --- README.rst | 11 ++++++++++- changelog.d/pr-1569.doc | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 changelog.d/pr-1569.doc diff --git a/README.rst b/README.rst index 750e012879..74dff902cb 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,13 @@ -.. image:: https://codecov.io/gh/matrix-org/matrix-ios-sdk/branch/develop/graph/badge.svg?token=2c9mzJoVpu:target: https://codecov.io/gh/matrix-org/matrix-ios-sdk +.. image:: https://img.shields.io/cocoapods/v/MatrixSDK?style=flat-square + :target: https://github.com/matrix-org/matrix-ios-sdk/releases +.. image:: https://img.shields.io/cocoapods/p/MatrixSDK?style=flat-square + :target: README.rst +.. image:: https://img.shields.io/github/workflow/status/matrix-org/matrix-ios-sdk/Lint%20CI/develop?style=flat-square + :target: https://github.com/matrix-org/matrix-ios-sdk/actions?query=branch%3Adevelop +.. image:: https://codecov.io/gh/matrix-org/matrix-ios-sdk/branch/develop/graph/badge.svg?token=2c9mzJoVpu + :target: https://codecov.io/gh/matrix-org/matrix-ios-sdk +.. image:: https://img.shields.io/badge/License-Apache%202.0-yellowgreen.svg?style=flat-square + :target: https://opensource.org/licenses/Apache-2.0 Matrix iOS SDK ============== diff --git a/changelog.d/pr-1569.doc b/changelog.d/pr-1569.doc new file mode 100644 index 0000000000..7e4112ab09 --- /dev/null +++ b/changelog.d/pr-1569.doc @@ -0,0 +1 @@ +README: Update the badge header \ No newline at end of file From 64daa812cae85ccfe159c95422a7802bfede489f Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 5 Sep 2022 09:26:26 +0100 Subject: [PATCH 62/65] Create lazy in-memory room encryptors --- MatrixSDK/Crypto/MXCrypto.m | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/MatrixSDK/Crypto/MXCrypto.m b/MatrixSDK/Crypto/MXCrypto.m index 3278af357a..14fbb4eb91 100644 --- a/MatrixSDK/Crypto/MXCrypto.m +++ b/MatrixSDK/Crypto/MXCrypto.m @@ -2527,9 +2527,39 @@ - (NSDictionary*)encryptMessage:(NSDictionary*)payloadFields forDevices:(NSArray { if (![algorithm isEqualToString:kMXCryptoMegolmAlgorithm]) { + MXLogErrorDetails(@"[MXCrypto] getRoomEncryptor: algorithm is not supported", @{ + @"algorithm": algorithm ?: @"unknown" + }); + return nil; + } + + id alg = roomEncryptors[roomId]; + if (alg) + { + return alg; + } + + NSString *existingAlgorithm = [self.store algorithmForRoom:roomId]; + if ([algorithm isEqualToString:existingAlgorithm]) + { + MXLogErrorDetails(@"[MXCrypto] getRoomEncryptor: algorithm does not match the room", @{ + @"algorithm": algorithm ?: @"unknown" + }); return nil; } - return roomEncryptors[roomId]; + + Class algClass = [[MXCryptoAlgorithms sharedAlgorithms] encryptorClassForAlgorithm:algorithm]; + if (!algClass) + { + MXLogErrorDetails(@"[MXCrypto] getRoomEncryptor: cannot get encryptor for algorithm", @{ + @"algorithm": algorithm ?: @"unknown" + }); + return nil; + } + + alg = [[algClass alloc] initWithCrypto:self andRoom:roomId]; + roomEncryptors[roomId] = alg; + return alg; } - (NSDictionary*)signObject:(NSDictionary*)object From 0ff11b57d4963981805cf65743faa98871d1c811 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 5 Sep 2022 09:33:09 +0100 Subject: [PATCH 63/65] Changelog --- changelog.d/pr-1570.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-1570.change diff --git a/changelog.d/pr-1570.change b/changelog.d/pr-1570.change new file mode 100644 index 0000000000..30373384ec --- /dev/null +++ b/changelog.d/pr-1570.change @@ -0,0 +1 @@ +Crypto: Create lazy in-memory room encryptors From 387bf2c4d07d9d85886ba9a87babc176f8d16c3f Mon Sep 17 00:00:00 2001 From: gulekismail Date: Wed, 7 Sep 2022 13:07:33 +0300 Subject: [PATCH 64/65] version++ --- CHANGES.md | 36 ++++++++++++++++++++++++++++++++++++ MatrixSDK.podspec | 2 +- MatrixSDK/MatrixSDKVersion.m | 2 +- changelog.d/6443.feature | 1 - changelog.d/6589.feature | 1 - changelog.d/6614.bugfix | 1 - changelog.d/6616.change | 1 - changelog.d/pr-1531.misc | 1 - changelog.d/pr-1542.feature | 1 - changelog.d/pr-1543.build | 1 - changelog.d/pr-1558.misc | 1 - changelog.d/pr-1559.change | 1 - changelog.d/pr-1564.misc | 1 - changelog.d/pr-1566.change | 1 - changelog.d/pr-1569.doc | 1 - changelog.d/pr-1570.change | 1 - changelog.d/sdk-1550.build | 1 - changelog.d/sdk-1552.doc | 1 - 18 files changed, 38 insertions(+), 17 deletions(-) delete mode 100644 changelog.d/6443.feature delete mode 100644 changelog.d/6589.feature delete mode 100644 changelog.d/6614.bugfix delete mode 100644 changelog.d/6616.change delete mode 100644 changelog.d/pr-1531.misc delete mode 100644 changelog.d/pr-1542.feature delete mode 100644 changelog.d/pr-1543.build delete mode 100644 changelog.d/pr-1558.misc delete mode 100644 changelog.d/pr-1559.change delete mode 100644 changelog.d/pr-1564.misc delete mode 100644 changelog.d/pr-1566.change delete mode 100644 changelog.d/pr-1569.doc delete mode 100644 changelog.d/pr-1570.change delete mode 100644 changelog.d/sdk-1550.build delete mode 100644 changelog.d/sdk-1552.doc diff --git a/CHANGES.md b/CHANGES.md index 55e9161efb..4c9385e317 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,39 @@ +## Changes in 0.23.18 (2022-09-07) + +✨ Features + +- MXKeyBackup: Add support for symmetric key backups. ([#1542](https://github.com/matrix-org/matrix-ios-sdk/pull/1542)) +- CryptoSDK: Outgoing SAS User Verification Flow ([#6443](https://github.com/vector-im/element-ios/issues/6443)) +- CryptoV2: Self-verification flow ([#6589](https://github.com/vector-im/element-ios/issues/6589)) + +🙌 Improvements + +- Allow setting room alias regardless of join rule ([#1559](https://github.com/matrix-org/matrix-ios-sdk/pull/1559)) +- Crypto: Cache inbound group sessions when decrypting ([#1566](https://github.com/matrix-org/matrix-ios-sdk/pull/1566)) +- Crypto: Create lazy in-memory room encryptors ([#1570](https://github.com/matrix-org/matrix-ios-sdk/pull/1570)) +- App Layout: Increased store version to force clear cache ([#6616](https://github.com/vector-im/element-ios/issues/6616)) + +🐛 Bugfixes + +- Fix incoming calls sometimes ringing after being answered on another client ([#6614](https://github.com/vector-im/element-ios/issues/6614)) + +🧱 Build + +- Xcode project(s) updated via Xcode recommended setting ([#1543](https://github.com/matrix-org/matrix-ios-sdk/pull/1543)) +- MXLog: Ensure MXLogLevel.none works if it is set after another log level has already been configured. ([#1550](https://github.com/matrix-org/matrix-ios-sdk/issues/1550)) + +📄 Documentation + +- README: Update the badge header ([#1569](https://github.com/matrix-org/matrix-ios-sdk/pull/1569)) +- Update README for correct Swift usage. ([#1552](https://github.com/matrix-org/matrix-ios-sdk/issues/1552)) + +Others + +- Crypto: User and device identity objects ([#1531](https://github.com/matrix-org/matrix-ios-sdk/pull/1531)) +- Analytics: Log all errors to analytics ([#1558](https://github.com/matrix-org/matrix-ios-sdk/pull/1558)) +- Improve MXLog file formatting and fix log message format ([#1564](https://github.com/matrix-org/matrix-ios-sdk/pull/1564)) + + ## Changes in 0.23.17 (2022-08-31) 🙌 Improvements diff --git a/MatrixSDK.podspec b/MatrixSDK.podspec index bf32708555..cffb2f7207 100644 --- a/MatrixSDK.podspec +++ b/MatrixSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MatrixSDK" - s.version = "0.23.17" + s.version = "0.23.18" s.summary = "The iOS SDK to build apps compatible with Matrix (https://www.matrix.org)" s.description = <<-DESC diff --git a/MatrixSDK/MatrixSDKVersion.m b/MatrixSDK/MatrixSDKVersion.m index 6f5561e6df..1acda7f4a7 100644 --- a/MatrixSDK/MatrixSDKVersion.m +++ b/MatrixSDK/MatrixSDKVersion.m @@ -16,4 +16,4 @@ #import -NSString *const MatrixSDKVersion = @"0.23.17"; +NSString *const MatrixSDKVersion = @"0.23.18"; diff --git a/changelog.d/6443.feature b/changelog.d/6443.feature deleted file mode 100644 index 8bd8a86a23..0000000000 --- a/changelog.d/6443.feature +++ /dev/null @@ -1 +0,0 @@ -CryptoSDK: Outgoing SAS User Verification Flow diff --git a/changelog.d/6589.feature b/changelog.d/6589.feature deleted file mode 100644 index e1ae486917..0000000000 --- a/changelog.d/6589.feature +++ /dev/null @@ -1 +0,0 @@ -CryptoV2: Self-verification flow diff --git a/changelog.d/6614.bugfix b/changelog.d/6614.bugfix deleted file mode 100644 index 32420d2ad8..0000000000 --- a/changelog.d/6614.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix incoming calls sometimes ringing after being answered on another client diff --git a/changelog.d/6616.change b/changelog.d/6616.change deleted file mode 100644 index 4a483bcc97..0000000000 --- a/changelog.d/6616.change +++ /dev/null @@ -1 +0,0 @@ -App Layout: Increased store version to force clear cache diff --git a/changelog.d/pr-1531.misc b/changelog.d/pr-1531.misc deleted file mode 100644 index 3ff9133769..0000000000 --- a/changelog.d/pr-1531.misc +++ /dev/null @@ -1 +0,0 @@ -Crypto: User and device identity objects diff --git a/changelog.d/pr-1542.feature b/changelog.d/pr-1542.feature deleted file mode 100644 index 36ba0c237e..0000000000 --- a/changelog.d/pr-1542.feature +++ /dev/null @@ -1 +0,0 @@ -MXKeyBackup: Add support for symmetric key backups. diff --git a/changelog.d/pr-1543.build b/changelog.d/pr-1543.build deleted file mode 100644 index d4937593bc..0000000000 --- a/changelog.d/pr-1543.build +++ /dev/null @@ -1 +0,0 @@ -Xcode project(s) updated via Xcode recommended setting \ No newline at end of file diff --git a/changelog.d/pr-1558.misc b/changelog.d/pr-1558.misc deleted file mode 100644 index abc1f9031e..0000000000 --- a/changelog.d/pr-1558.misc +++ /dev/null @@ -1 +0,0 @@ -Analytics: Log all errors to analytics diff --git a/changelog.d/pr-1559.change b/changelog.d/pr-1559.change deleted file mode 100644 index f64830ad72..0000000000 --- a/changelog.d/pr-1559.change +++ /dev/null @@ -1 +0,0 @@ -Allow setting room alias regardless of join rule diff --git a/changelog.d/pr-1564.misc b/changelog.d/pr-1564.misc deleted file mode 100644 index 14a139b66d..0000000000 --- a/changelog.d/pr-1564.misc +++ /dev/null @@ -1 +0,0 @@ -Improve MXLog file formatting and fix log message format \ No newline at end of file diff --git a/changelog.d/pr-1566.change b/changelog.d/pr-1566.change deleted file mode 100644 index 6a2a541261..0000000000 --- a/changelog.d/pr-1566.change +++ /dev/null @@ -1 +0,0 @@ -Crypto: Cache inbound group sessions when decrypting diff --git a/changelog.d/pr-1569.doc b/changelog.d/pr-1569.doc deleted file mode 100644 index 7e4112ab09..0000000000 --- a/changelog.d/pr-1569.doc +++ /dev/null @@ -1 +0,0 @@ -README: Update the badge header \ No newline at end of file diff --git a/changelog.d/pr-1570.change b/changelog.d/pr-1570.change deleted file mode 100644 index 30373384ec..0000000000 --- a/changelog.d/pr-1570.change +++ /dev/null @@ -1 +0,0 @@ -Crypto: Create lazy in-memory room encryptors diff --git a/changelog.d/sdk-1550.build b/changelog.d/sdk-1550.build deleted file mode 100644 index b99823f7d3..0000000000 --- a/changelog.d/sdk-1550.build +++ /dev/null @@ -1 +0,0 @@ -MXLog: Ensure MXLogLevel.none works if it is set after another log level has already been configured. diff --git a/changelog.d/sdk-1552.doc b/changelog.d/sdk-1552.doc deleted file mode 100644 index 62f2912797..0000000000 --- a/changelog.d/sdk-1552.doc +++ /dev/null @@ -1 +0,0 @@ -Update README for correct Swift usage. From 6755cf866a83586522570f203bc14b537c8c1a59 Mon Sep 17 00:00:00 2001 From: gulekismail Date: Wed, 7 Sep 2022 13:43:10 +0300 Subject: [PATCH 65/65] finish version++ --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index d76ec07018..d55e183ca8 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -73,4 +73,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 8a21d32ad6a381e80ea32b6104daee39323c306c -COCOAPODS: 1.11.3 +COCOAPODS: 1.11.2