diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index a148d19fcf..50d84e8f87 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -1939,6 +1939,8 @@ ED751DAF28EDEC7E003748C3 /* MXKeyVerificationStateResolverUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED751DAD28EDEC7E003748C3 /* MXKeyVerificationStateResolverUnitTests.swift */; }; ED76A4AD28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED76A4AC28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift */; }; ED76A4AE28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED76A4AC28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift */; }; + ED79B9852940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */; }; + ED79B9862940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */; }; ED825F8F29014EDA006A614E /* MXSession+LegacyCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */; }; ED825F9029014EDA006A614E /* MXSession+LegacyCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */; }; ED88999127F2065D00718486 /* MXRoomAliasResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -2003,6 +2005,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 */; }; + EDDBA7F0293F353900AD1480 /* MXToDevicePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDDBA7EF293F353900AD1480 /* MXToDevicePayload.swift */; }; + EDDBA7F1293F353900AD1480 /* MXToDevicePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDDBA7EF293F353900AD1480 /* MXToDevicePayload.swift */; }; EDDD90C82901611600B760E0 /* MXLegacyCrypto+LegacyCrossSigning.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDDD90C72901611600B760E0 /* MXLegacyCrypto+LegacyCrossSigning.swift */; }; EDDD90C92901611600B760E0 /* MXLegacyCrypto+LegacyCrossSigning.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDDD90C72901611600B760E0 /* MXLegacyCrypto+LegacyCrossSigning.swift */; }; EDE1B13B28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE1B13A28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift */; }; @@ -3079,6 +3083,7 @@ ED751DA928EDE4F4003748C3 /* MXKeyVerificationManagerV2UnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationManagerV2UnitTests.swift; sourceTree = ""; }; ED751DAD28EDEC7E003748C3 /* MXKeyVerificationStateResolverUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationStateResolverUnitTests.swift; sourceTree = ""; }; ED76A4AC28EDA2CE00036FF0 /* MXKeyVerificationStateResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKeyVerificationStateResolver.swift; sourceTree = ""; }; + ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXToDevicePayloadUnitTests.swift; sourceTree = ""; }; ED825F8E29014EDA006A614E /* MXSession+LegacyCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXSession+LegacyCrypto.swift"; sourceTree = ""; }; ED88998F27F2065C00718486 /* MXRoomAliasResolution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRoomAliasResolution.h; sourceTree = ""; }; ED88999027F2065D00718486 /* MXRoomAliasResolution.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXRoomAliasResolution.m; sourceTree = ""; }; @@ -3112,6 +3117,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 = ""; }; + EDDBA7EF293F353900AD1480 /* MXToDevicePayload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXToDevicePayload.swift; sourceTree = ""; }; EDDD90C72901611600B760E0 /* MXLegacyCrypto+LegacyCrossSigning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXLegacyCrypto+LegacyCrossSigning.swift"; sourceTree = ""; }; EDE1B13A28B7BEAB000DEEE8 /* MXCrossSigningV2UnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXCrossSigningV2UnitTests.swift; sourceTree = ""; }; EDE70DC728DA22F800099736 /* MXKeyBackupEngine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXKeyBackupEngine.h; sourceTree = ""; }; @@ -3379,6 +3385,7 @@ EDF1B68F2876CD2C00BBBCEE /* MXTaskQueue.swift */, ED1AE9292881AC7100D3432A /* MXWarnings.h */, ED6DAC2028C7A4F000ECDCB6 /* MXDateProvider.swift */, + EDDBA7EF293F353900AD1480 /* MXToDevicePayload.swift */, ); path = Utils; sourceTree = ""; @@ -4357,6 +4364,7 @@ 3A96CD482901512C00F9A5AB /* MXReceiptDataIntegrationTests.swift */, 3A2A3237291031A7005EF477 /* MXThreadsNotificationCountTests.swift */, 3A4BB661291D93EA006F7585 /* MXRoomEventFilterUnitTests.swift */, + ED79B9842940BB45008952F6 /* MXToDevicePayloadUnitTests.swift */, ); path = MatrixSDKTests; sourceTree = ""; @@ -7122,6 +7130,7 @@ B11556EE230C45C600B2A2CF /* MXIdentityServerRestClient.swift in Sources */, EDAAC41F28E30F4C00DD89B5 /* (null) in Sources */, 321CFDE722525A49004D31DF /* MXSASTransaction.m in Sources */, + EDDBA7F0293F353900AD1480 /* MXToDevicePayload.swift in Sources */, 32720D9D222EAA6F0086FFF5 /* MXDiscoveredClientConfig.m in Sources */, EC5C560C2798CEA00014CBE9 /* NSDictionary+MutableDeepCopy.m in Sources */, ECD2897926E8EE9300F268CF /* MXRoomListDataSortOptions.swift in Sources */, @@ -7230,6 +7239,7 @@ EDB4209927DF842F0036AF39 /* MXEventFixtures.swift in Sources */, ECDBE69328E5E16F000C83AF /* MXClientInformationServiceUnitTests.swift in Sources */, 32114A7F1A24E15500FF2EC4 /* MXMyUserTests.m in Sources */, + ED79B9852940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */, 32832B5E1BCC048300241108 /* MXStoreNoStoreTests.m in Sources */, A816247C25F60C7700A46F05 /* MXDeviceListOperationsPoolUnitTests.swift in Sources */, B1660F1C260A20B900C3AA12 /* MXSpaceServiceTest.swift in Sources */, @@ -7765,6 +7775,7 @@ B14EF2782397E90400758AF0 /* MXTransactionCancelCode.m in Sources */, EDAAC42028E30F4C00DD89B5 /* (null) in Sources */, B14EF2792397E90400758AF0 /* MXEventListener.m in Sources */, + EDDBA7F1293F353900AD1480 /* MXToDevicePayload.swift in Sources */, B1710B202613D01400A9B429 /* MXSpaceChildrenRequestParameters.swift in Sources */, B14EF27A2397E90400758AF0 /* MXSessionEventListener.swift in Sources */, B14EF27B2397E90400758AF0 /* MXOlmSessionResult.m in Sources */, @@ -7873,6 +7884,7 @@ EDB4209A27DF842F0036AF39 /* MXEventFixtures.swift in Sources */, ECDBE69428E5E16F000C83AF /* MXClientInformationServiceUnitTests.swift in Sources */, B1E09A2E2397FD750057C069 /* MXRestClientTests.m in Sources */, + ED79B9862940BB45008952F6 /* MXToDevicePayloadUnitTests.swift in Sources */, 32C9B71923E81A1C00C6F30A /* MXCrossSigningVerificationTests.m in Sources */, B1E09A1D2397FCE90057C069 /* MXCryptoKeyVerificationTests.m in Sources */, B1E09A472397FD990057C069 /* MXEventScanStoreUnitTests.m in Sources */, diff --git a/MatrixSDK/Contrib/Swift/MXRestClient.swift b/MatrixSDK/Contrib/Swift/MXRestClient.swift index f6fc351ac2..cac922cdd7 100644 --- a/MatrixSDK/Contrib/Swift/MXRestClient.swift +++ b/MatrixSDK/Contrib/Swift/MXRestClient.swift @@ -1833,15 +1833,14 @@ public extension MXRestClient { Send an event to a specific list of devices - paramaeters: - - eventType: the type of event to send - - contentMap: content to send. Map from user_id to device_id to content dictionary. + - payload: Payload with `eventType` and `contentMap` to be sent - completion: A block object called when the operation completes. - response: Indicates whether the operation was successful. - returns: a `MXHTTPOperation` instance. */ - @nonobjc @discardableResult func sendDirectToDevice(eventType: String, contentMap: MXUsersDevicesMap, txnId: String?, completion: @escaping (_ response: MXResponse) -> Void) -> MXHTTPOperation { - return __send(toDevice: eventType, contentMap: contentMap, txnId: txnId, success: currySuccess(completion), failure: curryFailure(completion)) + @nonobjc @discardableResult func sendDirectToDevice(payload: MXToDevicePayload, completion: @escaping (_ response: MXResponse) -> Void) -> MXHTTPOperation { + return __send(toDevice: payload, success: currySuccess(completion), failure: curryFailure(completion)) } diff --git a/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m b/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m index ac6c9ffdb4..9f8180a22c 100644 --- a/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m +++ b/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m @@ -366,10 +366,10 @@ - (MXHTTPOperation *)shareKeysWitUserId:(NSString *)userId } MXLogDebug(@"[MXMegolmDecryption] shareKeysWithDevices: sharing keys for session %@|%@ with devices of user %@", senderKey, sessionId, userId); - - MXHTTPOperation *operation2 = [self->crypto.matrixRestClient sendToDevice:kMXEventTypeStringRoomEncrypted - contentMap:contentMap - txnId:nil + + MXToDevicePayload *toDevicePayload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomEncrypted + contentMap:contentMap]; + MXHTTPOperation *operation2 = [self->crypto.matrixRestClient sendToDevice:toDevicePayload success:success failure:failure]; [operation mutateTo:operation2]; diff --git a/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmEncryption.m b/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmEncryption.m index 03b3e80f24..103994d5c9 100644 --- a/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmEncryption.m +++ b/MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmEncryption.m @@ -29,6 +29,7 @@ #import "MXOutboundSessionInfo.h" #import #import "MXSharedHistoryKeyService.h" +#import "MatrixSDKSwiftHeader.h" @interface MXMegolmEncryption () @@ -422,7 +423,9 @@ - (MXHTTPOperation*)shareKey:(MXOutboundSessionInfo*)session //MXLogDebug(@"[MXMegolmEncryption] shareKey. Actually share with %tu users and %tu devices: %@", contentMap.userIds.count, contentMap.count, contentMap); MXLogDebug(@"[MXMegolmEncryption] shareKey: Actually share with %tu users and %tu devices", contentMap.userIds.count, contentMap.count); - MXHTTPOperation *operation2 = [self->crypto.matrixRestClient sendToDevice:kMXEventTypeStringRoomEncrypted contentMap:contentMap txnId:nil success:^{ + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomEncrypted + contentMap:contentMap]; + MXHTTPOperation *operation2 = [self->crypto.matrixRestClient sendToDevice:payload success:^{ MXLogDebug(@"[MXMegolmEncryption] shareKey: request succeeded"); @@ -541,7 +544,9 @@ - (MXHTTPOperation*)reshareKey:(NSString*)sessionId [contentMap setObject:[self->crypto encryptMessage:payload forDevices:@[deviceInfo]] forUser:userId andDevice:deviceId]; - MXHTTPOperation *operation2 = [self->crypto.matrixRestClient sendToDevice:kMXEventTypeStringRoomEncrypted contentMap:contentMap txnId:nil success:success failure:failure]; + MXToDevicePayload *toDevicePayload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomEncrypted + contentMap:contentMap]; + MXHTTPOperation *operation2 = [self->crypto.matrixRestClient sendToDevice:toDevicePayload success:success failure:failure]; [operation mutateTo:operation2]; } failure:failure]; diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift index 38a92dbc78..ec0f02d0e1 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift @@ -223,7 +223,7 @@ extension MXCryptoMachine: MXCryptoSyncing { switch request { case .toDevice(let requestId, let eventType, let body): try await requests.sendToDevice( - request: .init(eventType: eventType, body: body) + request: .init(eventType: eventType, body: body, addMessageId: true) ) try markRequestAsSent(requestId: requestId, requestType: .toDevice) @@ -595,7 +595,9 @@ extension MXCryptoMachine: MXCryptoVerificationRequesting { try await requests.sendToDevice( request: .init( eventType: eventType, - body: body + body: body, + // Should not add anything for verification events as it would break their signatures + addMessageId: false ) ) case .inRoom(_, let roomId, let eventType, let content): diff --git a/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift b/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift index 8a39de02b6..9724da6cae 100644 --- a/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift +++ b/MatrixSDK/Crypto/CryptoMachine/MXCryptoRequests.swift @@ -31,9 +31,12 @@ struct MXCryptoRequests { func sendToDevice(request: ToDeviceRequest) async throws { return try await performCallbackRequest { restClient.sendDirectToDevice( - eventType: request.eventType, - contentMap: request.contentMap, - txnId: nil, + payload: .init( + eventType: request.eventType, + contentMap: request.contentMap, + transactionId: nil, + addMessageId: request.addMessageId + ), completion: $0 ) } @@ -131,8 +134,9 @@ extension MXCryptoRequests { struct ToDeviceRequest { let eventType: String let contentMap: MXUsersDevicesMap + let addMessageId: Bool - init(eventType: String, body: String) throws { + init(eventType: String, body: String, addMessageId: Bool) throws { guard let json = MXTools.deserialiseJSONString(body) as? [String: [String: NSDictionary]], let contentMap = MXUsersDevicesMap(map: json) @@ -142,6 +146,7 @@ extension MXCryptoRequests { self.eventType = eventType self.contentMap = contentMap + self.addMessageId = addMessageId } } diff --git a/MatrixSDK/Crypto/KeySharing/MXOutgoingRoomKeyRequestManager.m b/MatrixSDK/Crypto/KeySharing/MXOutgoingRoomKeyRequestManager.m index e5c774c86c..61832eddfe 100644 --- a/MatrixSDK/Crypto/KeySharing/MXOutgoingRoomKeyRequestManager.m +++ b/MatrixSDK/Crypto/KeySharing/MXOutgoingRoomKeyRequestManager.m @@ -18,6 +18,7 @@ #import "MXTools.h" #import "MXOutgoingRoomKeyRequest.h" +#import "MatrixSDKSwiftHeader.h" #ifdef MX_CRYPTO @@ -359,7 +360,11 @@ - (void)sendMessageToDevices:(NSDictionary*)message [contentMap setObject:message forUser:recipient[@"userId"] andDevice:recipient[@"deviceId"]]; } - [matrixRestClient sendToDevice:kMXEventTypeStringRoomKeyRequest contentMap:contentMap txnId:txnId success:success failure:failure]; + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomKeyRequest + contentMap:contentMap + transactionId:txnId + addMessageId:YES]; + [matrixRestClient sendToDevice:payload success:success failure:failure]; } /** diff --git a/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m b/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m index 4e839bd4d4..e17b319c8d 100644 --- a/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m +++ b/MatrixSDK/Crypto/KeySharing/Secret/MXSecretShareManager.m @@ -21,6 +21,7 @@ #import "MXPendingSecretShareRequest.h" #import "MXSecretShareSend.h" #import "MXTools.h" +#import "MatrixSDKSwiftHeader.h" #pragma mark - Constants @@ -210,7 +211,9 @@ - (MXHTTPOperation*)sendMessage:(NSDictionary*)message [contentMap setObject:message forUser:myUser.userId andDevice:@"*"]; } - return [_crypto.matrixRestClient sendToDevice:kMXEventTypeStringSecretRequest contentMap:contentMap txnId:nil success:success failure:failure]; + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringSecretRequest + contentMap:contentMap]; + return [_crypto.matrixRestClient sendToDevice:payload success:success failure:failure]; } - (BOOL)isSecretShareEvent:(MXEventTypeString)type @@ -390,7 +393,9 @@ - (void)shareSecret:(NSString*)secret toRequest:(MXSecretShareRequest*)request MXUsersDevicesMap *contentMap = [MXUsersDevicesMap new]; [contentMap setObject:encryptedContent forUser:myUser.userId andDevice:device.deviceId]; - [self.crypto.matrixRestClient sendToDevice:kMXEventTypeStringRoomEncrypted contentMap:contentMap txnId:nil success:nil failure:^(NSError *error) { + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomEncrypted + contentMap:contentMap]; + [self.crypto.matrixRestClient sendToDevice:payload success:nil failure:^(NSError *error) { MXLogDebug(@"[MXSecretShareManager] shareSecret: ERROR for sendToDevice: %@", error); }]; diff --git a/MatrixSDK/Crypto/MXCrypto.m b/MatrixSDK/Crypto/MXCrypto.m index a14a6a0133..d014cc9039 100644 --- a/MatrixSDK/Crypto/MXCrypto.m +++ b/MatrixSDK/Crypto/MXCrypto.m @@ -3239,7 +3239,9 @@ - (void)markOlmSessionForUnwedgingInEvent:(MXEvent*)event MXUsersDevicesMap *contentMap = [MXUsersDevicesMap new]; [contentMap setObject:encryptedContent forUser:sender andDevice:device.deviceId]; - [self.matrixRestClient sendToDevice:kMXEventTypeStringRoomEncrypted contentMap:contentMap txnId:nil success:nil failure:^(NSError *error) { + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomEncrypted + contentMap:contentMap]; + [self.matrixRestClient sendToDevice:payload success:nil failure:^(NSError *error) { MXLogDebug(@"[MXCrypto] markOlmSessionForUnwedgingInEvent: ERROR for sendToDevice: %@", error); }]; diff --git a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m index ca1fa6a9c8..734dc8fd07 100644 --- a/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m +++ b/MatrixSDK/Crypto/Verification/MXKeyVerificationManager.m @@ -40,6 +40,8 @@ #import "MXQRCodeDataBuilder.h" +#import "MatrixSDKSwiftHeader.h" + #pragma mark - Constants NSString *const MXKeyVerificationErrorDomain = @"org.matrix.sdk.verification"; @@ -164,7 +166,12 @@ - (void)requestVerificationByToDeviceWithUserId2:(NSString*)userId [contentMap setObject:requestJSONModel.JSONDictionary forUser:userId andDevice:deviceId]; } - [self.crypto.matrixRestClient sendToDevice:kMXMessageTypeKeyVerificationRequest contentMap:contentMap txnId:nil success:^{ + MXToDevicePayload *payload = [[MXToDevicePayload alloc] + initWithEventType:kMXMessageTypeKeyVerificationRequest + contentMap:contentMap + transactionId:nil + addMessageId:NO]; // Should not add anything for verification events as it would break their signatures + [self.crypto.matrixRestClient sendToDevice:payload success:^{ MXEvent *event = [MXEvent modelFromJSON:@{ @"sender": self.crypto.mxSession.myUserId, @@ -1338,7 +1345,11 @@ - (MXHTTPOperation*)sendToDevices:(NSString*)userId [contentMap setObject:content forUser:userId andDevice:deviceId]; } - return [self.crypto.matrixRestClient sendToDevice:eventType contentMap:contentMap txnId:nil success:success failure:failure]; + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:eventType + contentMap:contentMap + transactionId:nil + addMessageId:NO]; // // Should not add anything for verification events as it would break their signatures + return [self.crypto.matrixRestClient sendToDevice:payload success:success failure:failure]; } diff --git a/MatrixSDK/JSONModels/MXEvent.h b/MatrixSDK/JSONModels/MXEvent.h index 3694226e1a..edbd3ed085 100644 --- a/MatrixSDK/JSONModels/MXEvent.h +++ b/MatrixSDK/JSONModels/MXEvent.h @@ -230,6 +230,11 @@ FOUNDATION_EXPORT NSString *const MXEventRelationTypeReplace; // Edition FOUNDATION_EXPORT NSString *const kMXMessageContentKeyNewContent; // Edited content key FOUNDATION_EXPORT NSString *const MXEventRelationTypeThread; // Thread +/** + To-device messages + */ +FOUNDATION_EXPORT NSString *const kMXToDeviceMessageId; + /** Prefix used for id of temporary local event. */ diff --git a/MatrixSDK/JSONModels/MXEvent.m b/MatrixSDK/JSONModels/MXEvent.m index 6332557fb8..35060eb9f6 100644 --- a/MatrixSDK/JSONModels/MXEvent.m +++ b/MatrixSDK/JSONModels/MXEvent.m @@ -129,6 +129,8 @@ // https://github.com/matrix-org/matrix-doc/pull/3440 NSString *const MXEventRelationTypeThread = @"m.thread"; +NSString *const kMXToDeviceMessageId = @"org.matrix.msgid"; + NSString *const kMXEventLocalEventIdPrefix = @"kMXEventLocalId_"; uint64_t const kMXUndefinedTimestamp = (uint64_t)-1; diff --git a/MatrixSDK/MXRestClient.h b/MatrixSDK/MXRestClient.h index 0731dd0b23..aa1dfcb941 100644 --- a/MatrixSDK/MXRestClient.h +++ b/MatrixSDK/MXRestClient.h @@ -53,6 +53,7 @@ @class MXSpaceChildrenRequestParameters; @class MXCapabilities; @class MXDevice; +@class MXToDevicePayload; MX_ASSUME_MISSING_NULLABILITY_BEGIN @@ -2707,17 +2708,14 @@ Note: Clients should consider avoiding this endpoint for URLs posted in encrypte /** Send an event to a specific list of devices - @param eventType the type of event to send - @param contentMap content to send. Map from user_id to device_id to content dictionary. - @param txnId the transaction id to use. If nil, one will be generated. + @param payload Payload with `eventType` and `contentMap` to be sent @param success A block object called when the operation succeeds. @param failure A block object called when the operation fails. @return a MXHTTPOperation instance. */ -- (MXHTTPOperation*)sendToDevice:(NSString*)eventType contentMap:(MXUsersDevicesMap*)contentMap - txnId:(NSString*)txnId +- (MXHTTPOperation*)sendToDevice:(MXToDevicePayload*)payload success:(void (^)(void))success failure:(void (^)(NSError *error))failure NS_REFINED_FOR_SWIFT; diff --git a/MatrixSDK/MXRestClient.m b/MatrixSDK/MXRestClient.m index 89d090ec6a..0921406497 100644 --- a/MatrixSDK/MXRestClient.m +++ b/MatrixSDK/MXRestClient.m @@ -5394,21 +5394,16 @@ - (NSString*)keyBackupPath:(NSString*)roomId session:(NSString*)sessionId versio #pragma mark - Direct-to-device messaging -- (MXHTTPOperation*)sendToDevice:(NSString*)eventType contentMap:(MXUsersDevicesMap*)contentMap - txnId:(NSString*)txnId +- (MXHTTPOperation*)sendToDevice:(MXToDevicePayload *)payload success:(void (^)(void))success failure:(void (^)(NSError *error))failure { - if (!txnId) - { - txnId = [MXTools generateTransactionId]; - } // Prepare the path by adding a random transaction id (This id is used to prevent duplicated event). - NSString *path = [NSString stringWithFormat:@"%@/sendToDevice/%@/%@", kMXAPIPrefixPathR0, eventType, txnId]; + NSString *path = [NSString stringWithFormat:@"%@/sendToDevice/%@/%@", kMXAPIPrefixPathR0, payload.eventType, payload.transactionId]; NSDictionary *content = @{ - @"messages": contentMap.map + @"messages": payload.messages }; MXWeakify(self); diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index d4a4993e61..7c4c8cee77 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -2047,6 +2047,7 @@ - (void)handleToDeviceEvents:(NSArray *)events onComplete:(void (^)(v { if ([MXTools isSupportedToDeviceEvent:event]) { + MXLogDebug(@"[MXSession] handleToDeviceEvents: Processing new to-device event msgid: %@", event.content[kMXToDeviceMessageId]) [supportedEvents addObject:event]; } } @@ -2064,6 +2065,7 @@ - (void)handleToDeviceEvents:(NSArray *)events onComplete:(void (^)(v { if (!event.decryptionError) { + MXLogDebug(@"[MXSession] handleToDeviceEvents: Received new to-device event `%@` from `%@` msgid: %@", event.type, event.sender, event.wireContent[kMXToDeviceMessageId]) dispatch_group_enter(dispatchGroup); [self handleToDeviceEvent:event onComplete:^{ dispatch_group_leave(dispatchGroup); diff --git a/MatrixSDK/Utils/MXToDevicePayload.swift b/MatrixSDK/Utils/MXToDevicePayload.swift new file mode 100644 index 0000000000..8504ec46e2 --- /dev/null +++ b/MatrixSDK/Utils/MXToDevicePayload.swift @@ -0,0 +1,77 @@ +// +// 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 + +/// Payload sent via `PUT /sendToDevice` endpoint +@objcMembers public class MXToDevicePayload: NSObject { + + public let eventType: String + public let transactionId: String + public let messages: [String: [String: NSDictionary]] + public let messageIds: [String] + + /// Initialize new to-device payload + /// + /// - Parameters: + /// - eventType: The type of event to send + /// - contentMap: Content to send. Map from user_id to device_id to content dictionary. + /// - transactionId: The transaction id to use. If nil, one will be generated. + /// - addMessageId: Whether to automatically generate new message id for each user/device. + /// This is used for tracing messages across different systems + public init( + eventType: String, + contentMap: MXUsersDevicesMap, + transactionId: String?, + addMessageId: Bool + ) { + self.eventType = eventType + self.transactionId = transactionId ?? MXTools.generateTransactionId() + + var ids = [String]() + if addMessageId { + for (userId, devices) in contentMap.map { + for (deviceId, content) in devices { + + let messageId = UUID().uuidString + let dict = NSMutableDictionary(dictionary: content) + dict[kMXToDeviceMessageId] = messageId + contentMap.setObject( + NSDictionary(dictionary: dict), + forUser: userId, + andDevice: deviceId + ) + + ids.append("\(userId)/\(deviceId) \(messageId)") + } + } + } + + self.messages = contentMap.map + self.messageIds = ids + + super.init() + + MXLog.debug("[MXToDevicePayload] Created to-device payload with txnId \(self.transactionId), message ids: [\(self.messageIds.joined(separator: ", "))]") + } + + convenience public init( + eventType: String, + contentMap: MXUsersDevicesMap + ) { + self.init(eventType: eventType, contentMap: contentMap, transactionId: nil, addMessageId: true) + } +} diff --git a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoRequestsUnitTests.swift b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoRequestsUnitTests.swift index 2a2b0874c3..37332519a9 100644 --- a/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoRequestsUnitTests.swift +++ b/MatrixSDKTests/Crypto/CryptoMachine/MXCryptoRequestsUnitTests.swift @@ -34,9 +34,10 @@ class MXCryptoRequestsUnitTests: XCTestCase { ] do { - let request = try MXCryptoRequests.ToDeviceRequest(eventType: "A", body: MXTools.serialiseJSONObject(body)) + let request = try MXCryptoRequests.ToDeviceRequest(eventType: "A", body: MXTools.serialiseJSONObject(body), addMessageId: true) XCTAssertEqual(request.eventType, "A") XCTAssertEqual(request.contentMap.map, body) + XCTAssertTrue(request.addMessageId) } catch { XCTFail("Failed creating to device request with error - \(error)") } diff --git a/MatrixSDKTests/MXCryptoTests.m b/MatrixSDKTests/MXCryptoTests.m index 5cd3dc27d6..77ee6dba09 100644 --- a/MatrixSDKTests/MXCryptoTests.m +++ b/MatrixSDKTests/MXCryptoTests.m @@ -2865,7 +2865,11 @@ - (void)testIncomingRoomKeyRequest MXUsersDevicesMap *contentMap = [[MXUsersDevicesMap alloc] init]; [contentMap setObject:requestMessage forUser:alice1Credentials.userId andDevice:@"*"]; - [alice1MatrixRestClient sendToDevice:kMXEventTypeStringRoomKeyRequest contentMap:contentMap txnId:requestMessage[@"request_id"] success:nil failure:^(NSError *error) { + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomKeyRequest + contentMap:contentMap + transactionId:requestMessage[@"request_id"] + addMessageId:YES]; + [alice1MatrixRestClient sendToDevice:payload success:nil failure:^(NSError *error) { XCTFail(@"The operation should not fail - NSError: %@", error); [expectation fulfill]; }]; diff --git a/MatrixSDKTests/MXSessionTests.m b/MatrixSDKTests/MXSessionTests.m index 47991b1394..ba27af405a 100644 --- a/MatrixSDKTests/MXSessionTests.m +++ b/MatrixSDKTests/MXSessionTests.m @@ -1454,7 +1454,9 @@ - (void)testToDeviceEvents } } forUser:mxSession.myUserId]; - [aliceRestClient sendToDevice:kMXEventTypeStringRoomKeyRequest contentMap:contentMap txnId:nil success:^{ + MXToDevicePayload *payload = [[MXToDevicePayload alloc] initWithEventType:kMXEventTypeStringRoomKeyRequest + contentMap:contentMap]; + [aliceRestClient sendToDevice:payload success:^{ } failure:^(NSError *error) { XCTFail(@"Cannot set up intial test conditions - error: %@", error); diff --git a/MatrixSDKTests/MXToDevicePayloadUnitTests.swift b/MatrixSDKTests/MXToDevicePayloadUnitTests.swift new file mode 100644 index 0000000000..66b009c9c7 --- /dev/null +++ b/MatrixSDKTests/MXToDevicePayloadUnitTests.swift @@ -0,0 +1,87 @@ +// +// 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 + +class MXToDevicePayloadUnitTests: XCTestCase { + func makePayload( + eventType: String = "", + contentMap: MXUsersDevicesMap = .init(), + transactionId: String? = nil, + addMessageId: Bool = false + ) -> MXToDevicePayload { + .init(eventType: eventType, contentMap: contentMap, transactionId: transactionId, addMessageId: addMessageId) + } + + func test_cratesTransactionId_ifNotProvided() { + let payload1 = makePayload(transactionId: nil) + XCTAssertFalse(payload1.transactionId.isEmpty) + + let payload2 = makePayload(transactionId: "abc") + XCTAssertEqual(payload2.transactionId, "abc") + } + + func test_containsContentMapMessages() { + let content: NSDictionary = [ + "cipher": "blabla", + "mac": "123" + ] + let dict = [ + "alice": [ + "deviceA": content, + "deviceB": content + ], + "bob": [ + "deviceC": content, + ] + ] + + let payload = makePayload(contentMap: .init(map: dict), addMessageId: false) + + XCTAssertEqual(payload.messageIds.count, 0) + XCTAssertEqual(payload.messages, dict) + } + + func test_addsMessageIdsToContent() { + let content: NSDictionary = [ + "cipher": "blabla", + "mac": "123" + ] + let dict = [ + "alice": [ + "deviceA": content, + "deviceB": content + ], + "bob": [ + "deviceC": content, + ] + ] + + let payload = makePayload(contentMap: .init(map: dict), addMessageId: true) + + XCTAssertEqual(payload.messageIds.count, 3) + for (userId, devices) in payload.messages { + for (deviceId, content) in devices { + if let messageId = content[kMXToDeviceMessageId] as? String { + let messageFormat = "\(userId)/\(deviceId) \(messageId)" + XCTAssertTrue(payload.messageIds.contains(messageFormat)) + } else { + XCTFail("Missing to-device message id") + } + } + } + } +} diff --git a/MatrixSDKTests/TestPlans/UnitTests.xctestplan b/MatrixSDKTests/TestPlans/UnitTests.xctestplan index 06cb38ee04..1ced71cd75 100644 --- a/MatrixSDKTests/TestPlans/UnitTests.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTests.xctestplan @@ -64,7 +64,6 @@ "MXKeyVerificationManagerV2UnitTests", "MXKeyVerificationRequestV2UnitTests", "MXKeyVerificationStateResolverUnitTests", - "MXLoggerUnitTests", "MXMediaScanStoreUnitTests", "MXMegolmDecryptionUnitTests", "MXMegolmExportEncryptionUnitTests", @@ -90,6 +89,7 @@ "MXTaskQueueUnitTests", "MXThreadEventTimelineUnitTests", "MXThreadingServiceUnitTests", + "MXToDevicePayloadUnitTests", "MXToolsUnitTests", "MXTrustLevelSourceUnitTests", "MXUnrequestedForwardedRoomKeyManagerUnitTests" diff --git a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan index 109d09394d..fd7bc413b4 100644 --- a/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan +++ b/MatrixSDKTests/TestPlans/UnitTestsWithSanitizers.xctestplan @@ -72,7 +72,6 @@ "MXKeyVerificationManagerV2UnitTests", "MXKeyVerificationRequestV2UnitTests", "MXKeyVerificationStateResolverUnitTests", - "MXLoggerUnitTests", "MXMediaScanStoreUnitTests", "MXMegolmDecryptionUnitTests", "MXMegolmExportEncryptionUnitTests", @@ -98,6 +97,7 @@ "MXTaskQueueUnitTests", "MXThreadEventTimelineUnitTests", "MXThreadingServiceUnitTests", + "MXToDevicePayloadUnitTests", "MXToolsUnitTests", "MXTrustLevelSourceUnitTests", "MXUnrequestedForwardedRoomKeyManagerUnitTests" diff --git a/changelog.d/pr-1652.change b/changelog.d/pr-1652.change new file mode 100644 index 0000000000..1ffa18ef5f --- /dev/null +++ b/changelog.d/pr-1652.change @@ -0,0 +1 @@ +Add message id for to-device events