diff --git a/MatrixSDK/Crypto/MXCrypto.m b/MatrixSDK/Crypto/MXCrypto.m index fa2b594267..c3e29947f9 100644 --- a/MatrixSDK/Crypto/MXCrypto.m +++ b/MatrixSDK/Crypto/MXCrypto.m @@ -41,6 +41,9 @@ #ifdef MX_CRYPTO +// Frequency with which to check & upload one-time keys +NSTimeInterval kMXCryptoUploadOneTimeKeysPeriod = 60.0; // one minute + @interface MXCrypto () { // The Matrix session. @@ -63,8 +66,11 @@ @interface MXCrypto () // @TODO: could be removed NSDictionary *lastPublishedOneTimeKeys; - // Timer to periodically upload keys - NSTimer *uploadKeysTimer; + // Last time we check available one-time keys on the homeserver + NSDate *lastOneTimeKeyCheck; + + // The current one-time key operation, if any + MXHTTPOperation *uploadOneTimeKeysOperation; // The operation used for crypto starting requests MXHTTPOperation *startOperation; @@ -198,7 +204,7 @@ - (void)start:(void (^)())success NSMutableDictionary *roomsByUser = [self usersToMakeAnnouncement]; // Start uploading user device keys - startOperation = [self uploadKeys:5 success:^{ + startOperation = [self uploadDeviceKeys:^(MXKeysUploadResponse *keysUploadResponse) { if (!startOperation) { @@ -206,7 +212,7 @@ - (void)start:(void (^)())success } NSLog(@"[MXCrypto] start ###########################################################"); - NSLog(@" uploadKeys done for %@: ", mxSession.myUser.userId); + NSLog(@" uploadDeviceKeys done for %@: ", mxSession.myUser.userId); NSLog(@" - device id : %@", _store.deviceId); NSLog(@" - ed25519 : %@", _olmDevice.deviceEd25519Key); @@ -216,37 +222,54 @@ - (void)start:(void (^)())success NSLog(@"Store: %@", _store); NSLog(@""); - // Once keys are uploaded, make sure we announce ourselves - MXHTTPOperation *operation2 = [self makeAnnoucement:roomsByUser success:^{ + // Anounce ourselves if not already done + if (roomsByUser) + { + // But upload our one-time keys before. + // Thus, other devices can download them once they receive our to-device annoucement event + [self maybeUploadOneTimeKeys:^{ - // Start periodic timer for uploading keys - uploadKeysTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:10 * 60] - interval:10 * 60 // 10 min - target:self - selector:@selector(uploadKeys) - userInfo:nil - repeats:YES]; - [[NSRunLoop mainRunLoop] addTimer:uploadKeysTimer forMode:NSDefaultRunLoopMode]; + // Once keys are uploaded, announce ourselves + MXHTTPOperation *operation2 = [self makeAnnoucement:roomsByUser success:^{ - dispatch_async(dispatch_get_main_queue(), ^{ - startOperation = nil; - success(); - }); + // Make sure we are refreshing devices lists right instead + // of waiting for the next /sync that may occur in 30s. + [_deviceList refreshOutdatedDeviceLists]; - } failure:^(NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + startOperation = nil; + success(); + }); + + } failure:^(NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + startOperation = nil; + failure(error); + }); + }]; + + if (operation2) + { + [startOperation mutateTo:operation2]; + } + } failure:^(NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + startOperation = nil; + failure(error); + }); + }]; + } + else + { + // No annoucement require dispatch_async(dispatch_get_main_queue(), ^{ startOperation = nil; - failure(error); + success(); }); - }]; - - if (operation2) - { - [startOperation mutateTo:operation2]; } } failure:^(NSError *error) { - NSLog(@"[MXCrypto] start. Error in uploadKeys"); + NSLog(@"[MXCrypto] start. Error in uploadDeviceKeys"); dispatch_async(dispatch_get_main_queue(), ^{ startOperation = nil; failure(error); @@ -269,9 +292,9 @@ - (void)close dispatch_async(_cryptoQueue, ^{ - // Stop timer - [uploadKeysTimer invalidate]; - uploadKeysTimer = nil; + // Cancel pending one-time keys upload + [uploadOneTimeKeysOperation cancel]; + uploadOneTimeKeysOperation = nil; _olmDevice = nil; _cryptoQueue = nil; @@ -425,6 +448,8 @@ - (void)handleDeviceListsChanged:(NSArray*)userIds oldSyncToken:(NSS NSLog(@"[MXCrypto] handleDeviceListsChanged: %@", userIds); + BOOL isCatchingUp = mxSession.catchingUp; + dispatch_async(_cryptoQueue, ^{ // Flag users to refresh @@ -482,14 +507,16 @@ - (void)handleDeviceListsChanged:(NSArray*)userIds oldSyncToken:(NSS [_deviceList refreshOutdatedDeviceLists]; } - // @TODO - // we don't start uploading one-time keys until we've caught up with + // We don't start uploading one-time keys until we've caught up with // to-device messages, to help us avoid throwing away one-time-keys that we // are about to receive messages for // (https://github.com/vector-im/riot-web/issues/2782). -// if (!syncData.catchingUp) { -// _maybeUploadOneTimeKeys(this); -// } + // Also, do not upload them if we have not announced our device yet. + // They will be uploaded just before the announcement in [self start]. + if (!isCatchingUp && _store.deviceAnnounced) + { + [self maybeUploadOneTimeKeys:nil failure:nil]; + } }); #endif @@ -989,86 +1016,6 @@ - (instancetype)initWithMatrixSession:(MXSession*)matrixSession cryptoQueue:(dis return self; } -- (MXHTTPOperation *)uploadKeys:(NSUInteger)maxKeys - success:(void (^)())success - failure:(void (^)(NSError *))failure -{ - MXHTTPOperation *operation; - operation = [self uploadDeviceKeys:^(MXKeysUploadResponse *keysUploadResponse) { - - // We need to keep a pool of one time public keys on the server so that - // other devices can start conversations with us. But we can only store - // a finite number of private keys in the olm Account object. - // To complicate things further then can be a delay between a device - // claiming a public one time key from the server and it sending us a - // message. We need to keep the corresponding private key locally until - // we receive the message. - // But that message might never arrive leaving us stuck with duff - // private keys clogging up our local storage. - // So we need some kind of enginering compromise to balance all of - // these factors. - - // We first find how many keys the server has for us. - NSUInteger keyCount = [keysUploadResponse oneTimeKeyCountsForAlgorithm:@"signed_curve25519"]; - - // We then check how many keys we can store in the Account object. - CGFloat maxOneTimeKeys = _olmDevice.maxNumberOfOneTimeKeys; - - // Try to keep at most half that number on the server. This leaves the - // rest of the slots free to hold keys that have been claimed from the - // server but we haven't recevied a message for. - // If we run out of slots when generating new keys then olm will - // discard the oldest private keys first. This will eventually clean - // out stale private keys that won't receive a message. - NSUInteger keyLimit = floor(maxOneTimeKeys / 2); - - // We work out how many new keys we need to create to top up the server - // If there are too many keys on the server then we don't need to - // create any more keys. - NSUInteger numberToGenerate = MAX(keyLimit - keyCount, 0); - - if (maxKeys) - { - // Creating keys can be an expensive operation so we limit the - // number we generate in one go to avoid blocking the application - // for too long. - numberToGenerate = MIN(numberToGenerate, maxKeys); - - // Ask olm to generate new one time keys, then upload them to synapse. - [_olmDevice generateOneTimeKeys:numberToGenerate]; - MXHTTPOperation *operation2 = [self uploadOneTimeKeys:success failure:failure]; - - // Mutate MXHTTPOperation so that the user can cancel this new operation - [operation mutateTo:operation2]; - } - else - { - // If we don't need to generate any keys then we are done. - success(); - } - - if (numberToGenerate <= 0) { - return; - } - - } failure:^(NSError *error) { - NSLog(@"[MXCrypto] uploadDeviceKeys fails."); - failure(error); - }]; - - return operation; -} - -- (void)uploadKeys -{ - NSLog(@"[MXCrypto] Periodic uploadKeys"); - - [self uploadKeys:5 success:^{ - } failure:^(NSError *error) { - NSLog(@"[MXCrypto] Periodic uploadKeys failed."); - }]; -} - - (MXDeviceInfo *)eventSenderDeviceOfEvent:(MXEvent *)event { NSString *senderKey = event.senderKey; @@ -1776,6 +1723,106 @@ - (MXHTTPOperation *)uploadDeviceKeys:(void (^)(MXKeysUploadResponse *keysUpload return [_matrixRestClient uploadKeys:myDevice.JSONDictionary oneTimeKeys:nil forDevice:myDevice.deviceId success:success failure:failure]; } +/** + Check if it's time to upload one-time keys, and do so if so. + */ +- (void)maybeUploadOneTimeKeys:(void (^)())success failure:(void (^)(NSError *))failure +{ + if (uploadOneTimeKeysOperation) + { + return; + } + + NSDate *now = [NSDate date]; + if (lastOneTimeKeyCheck && [now timeIntervalSinceDate:lastOneTimeKeyCheck] < kMXCryptoUploadOneTimeKeysPeriod) + { + // We've done a key upload recently. + return; + } + + lastOneTimeKeyCheck = now; + + NSLog(@"[MXCrypto] maybeUploadOneTimeKeys: Checking available one-time keys on the homeserver"); + + uploadOneTimeKeysOperation = [_matrixRestClient uploadKeys:myDevice.JSONDictionary oneTimeKeys:nil forDevice:myDevice.deviceId success:^(MXKeysUploadResponse *keysUploadResponse) { + + if (!uploadOneTimeKeysOperation) + { + return; + } + + // We need to keep a pool of one time public keys on the server so that + // other devices can start conversations with us. But we can only store + // a finite number of private keys in the olm Account object. + // To complicate things further then can be a delay between a device + // claiming a public one time key from the server and it sending us a + // message. We need to keep the corresponding private key locally until + // we receive the message. + // But that message might never arrive leaving us stuck with duff + // private keys clogging up our local storage. + // So we need some kind of enginering compromise to balance all of + // these factors. + + // We first find how many keys the server has for us. + NSUInteger keyCount = [keysUploadResponse oneTimeKeyCountsForAlgorithm:@"signed_curve25519"]; + + NSLog(@"[MXCrypto] maybeUploadOneTimeKeys: one-time keys on the homeserver: %tu", keyCount); + + // We then check how many keys we can store in the Account object. + CGFloat maxOneTimeKeys = _olmDevice.maxNumberOfOneTimeKeys; + + // Try to keep at most half that number on the server. This leaves the + // rest of the slots free to hold keys that have been claimed from the + // server but we haven't recevied a message for. + // If we run out of slots when generating new keys then olm will + // discard the oldest private keys first. This will eventually clean + // out stale private keys that won't receive a message. + NSUInteger keyLimit = floor(maxOneTimeKeys / 2); + + // We work out how many new keys we need to create to top up the server + // If there are too many keys on the server then we don't need to + // create any more keys. + NSUInteger numberToGenerate = MAX(keyLimit - keyCount, 0); + if (numberToGenerate) + { + // Ask olm to generate new one time keys, then upload them to synapse. + [_olmDevice generateOneTimeKeys:numberToGenerate]; + MXHTTPOperation *operation2 = [self uploadOneTimeKeys:^(MXKeysUploadResponse *keysUploadResponse) { + + if (success) + { + success(); + } + else + { + uploadOneTimeKeysOperation = nil; + } + + } failure:^(NSError *error) { + NSLog(@"[MXCrypto] maybeUploadOneTimeKeys: Failed to publish one-time keys. Error: %@", error); + uploadOneTimeKeysOperation = nil; + + if (failure) + { + failure(error); + } + }]; + + // Mutate MXHTTPOperation so that the user can cancel this new operation + [uploadOneTimeKeysOperation mutateTo:operation2]; + } + else + { + // If we don't need to generate any keys then we are done. + uploadOneTimeKeysOperation = nil; + } + + } failure:^(NSError *error) { + NSLog(@"[MXCrypto] maybeUploadOneTimeKeys: Get published one-time keys count failed. Error: %@", error); + uploadOneTimeKeysOperation = nil; + }]; +} + /** Upload my user's one time keys. */ diff --git a/MatrixSDK/Crypto/MXCrypto_Private.h b/MatrixSDK/Crypto/MXCrypto_Private.h index 2ac002da59..36b8a80a18 100644 --- a/MatrixSDK/Crypto/MXCrypto_Private.h +++ b/MatrixSDK/Crypto/MXCrypto_Private.h @@ -76,20 +76,6 @@ */ @property (nonatomic, readonly) dispatch_queue_t decryptionQueue; -/** - Upload the device keys to the homeserver and ensure that the - homeserver has enough one-time keys. - - @param maxKeys The maximum number of keys to generate. - - @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*)uploadKeys:(NSUInteger)maxKeys - success:(void (^)())success - failure:(void (^)(NSError *))failure; /** Get the device which sent an event. diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index 13b9ed3357..87b1f20672 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -696,7 +696,11 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout setPresence:(NSString*)setPresence { NSDate *startDate = [NSDate date]; - NSLog(@"[MXSession] Do a server sync"); + + // Determine if we are catching up + _catchingUp = (0 == serverTimeout); + + NSLog(@"[MXSession] Do a server sync%@", _catchingUp ? @" (catching up)" : @""); NSString *inlineFilter; if (-1 != syncMessagesLimit) @@ -705,9 +709,6 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout inlineFilter = [NSString stringWithFormat:@"{\"room\":{\"timeline\":{\"limit\":%tu}}}", syncMessagesLimit]; } - // Determine if we are catching up - _catchingUp = (0 == serverTimeout); - eventStreamRequest = [matrixRestClient syncFromToken:_store.eventStreamToken serverTimeout:serverTimeout clientTimeout:clientTimeout setPresence:setPresence filter:inlineFilter success:^(MXSyncResponse *syncResponse) { // Make sure [MXSession close] or [MXSession pause] has not been called before the server response @@ -894,6 +895,12 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout { [_store commit]; } + + // Do a loop of /syncs until catching up is done + if (nextServerTimeout == 0) + { + [self serverSyncWithServerTimeout:nextServerTimeout success:success failure:failure clientTimeout:CLIENT_TIMEOUT_MS setPresence:nil]; + } // there is a pending backgroundSync if (onBackgroundSyncDone) diff --git a/MatrixSDKTests/MXCryptoTests.m b/MatrixSDKTests/MXCryptoTests.m index e80223e928..f055c725be 100644 --- a/MatrixSDKTests/MXCryptoTests.m +++ b/MatrixSDKTests/MXCryptoTests.m @@ -258,7 +258,7 @@ - (NSUInteger)checkEncryptedEvent:(MXEvent*)event roomId:(NSString*)roomId clear XCTAssert(event.eventId); XCTAssertEqualObjects(event.roomId, roomId); XCTAssertEqual(event.eventType, MXEventTypeRoomMessage); - XCTAssertLessThan(event.age, 2000); + XCTAssertLessThan(event.age, 10000); XCTAssertEqualObjects(event.content[@"body"], clearMessage); XCTAssertEqualObjects(event.sender, senderSession.myUser.userId); XCTAssertNil(event.decryptionError); @@ -402,92 +402,6 @@ - (void)testCryptoPersistenceInStore XCTFail(@"The request should not fail - NSError: %@", error); [expectation fulfill]; }]; - }]; -} - -- (void)testKeysUploadAndDownload -{ - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - - [matrixSDKTestsData doMXSessionTestWithAlice:self readyToTest:^(MXSession *aliceSession, XCTestExpectation *expectation) { - - [aliceSession.crypto uploadKeys:10 success:^{ - - [matrixSDKTestsData doMXSessionTestWithBob:nil readyToTest:^(MXSession *mxSession, XCTestExpectation *expectation2) { - - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; - - [mxSession.crypto.deviceList downloadKeys:@[mxSession.myUser.userId, aliceSession.myUser.userId] forceDownload:NO success:^(MXUsersDevicesMap *usersDevicesInfoMap) { - - XCTAssertEqual(usersDevicesInfoMap.userIds.count, 2, @"BobDevice must be obtain from the cache and AliceDevice from the hs"); - - XCTAssertEqual([usersDevicesInfoMap deviceIdsForUser:aliceSession.myUser.userId].count, 1); - - __block MXDeviceInfo *aliceDeviceFromBobPOV = [usersDevicesInfoMap objectForDevice:aliceSession.matrixRestClient.credentials.deviceId forUser:aliceSession.myUser.userId]; - XCTAssert(aliceDeviceFromBobPOV); - XCTAssertEqualObjects(aliceDeviceFromBobPOV.fingerprint, aliceSession.crypto.olmDevice.deviceEd25519Key); - - // Continue testing other methods - XCTAssertEqualObjects([mxSession.crypto.deviceList deviceWithIdentityKey:aliceSession.crypto.olmDevice.deviceCurve25519Key forUser:aliceSession.myUser.userId andAlgorithm:kMXCryptoOlmAlgorithm].description, aliceDeviceFromBobPOV.description); - - XCTAssertEqual(aliceDeviceFromBobPOV.verified, MXDeviceUnknown, @"This is the first time Alice sees this device"); - - [mxSession.crypto setDeviceVerification:MXDeviceBlocked forDevice:aliceDeviceFromBobPOV.deviceId ofUser:aliceSession.myUser.userId success:^{ - - aliceDeviceFromBobPOV = [mxSession.crypto.store deviceWithDeviceId:aliceDeviceFromBobPOV.deviceId forUser:aliceSession.myUser.userId]; - XCTAssertEqual(aliceDeviceFromBobPOV.verified, MXDeviceBlocked); - - MXRestClient *bobRestClient = mxSession.matrixRestClient; - [mxSession close]; - - - // Test storage: Reopen the session - MXFileStore *store = [[MXFileStore alloc] init]; - - MXSession *mxSession2 = [[MXSession alloc] initWithMatrixRestClient:bobRestClient]; - [mxSession2 setStore:store success:^{ - - MXDeviceInfo *aliceDeviceFromBobPOV2 = [mxSession2.crypto.deviceList deviceWithIdentityKey:aliceSession.crypto.olmDevice.deviceCurve25519Key forUser:aliceSession.myUser.userId andAlgorithm:kMXCryptoOlmAlgorithm]; - - XCTAssert(aliceDeviceFromBobPOV2); - XCTAssertEqualObjects(aliceDeviceFromBobPOV2.fingerprint, aliceSession.crypto.olmDevice.deviceEd25519Key); - XCTAssertEqual(aliceDeviceFromBobPOV2.verified, MXDeviceBlocked, @"AliceDevice must still be blocked"); - - // Download again alice device - [mxSession2.crypto.deviceList downloadKeys:@[aliceSession.myUser.userId] forceDownload:YES success:^(MXUsersDevicesMap *usersDevicesInfoMap2) { - - MXDeviceInfo *aliceDeviceFromBobPOV3 = [mxSession2.crypto.deviceList deviceWithIdentityKey:aliceSession.crypto.olmDevice.deviceCurve25519Key forUser:aliceSession.myUser.userId andAlgorithm:kMXCryptoOlmAlgorithm]; - - XCTAssert(aliceDeviceFromBobPOV3); - XCTAssertEqualObjects(aliceDeviceFromBobPOV3.fingerprint, aliceSession.crypto.olmDevice.deviceEd25519Key); - XCTAssertEqual(aliceDeviceFromBobPOV3.verified, MXDeviceBlocked, @"AliceDevice must still be blocked."); - - [expectation fulfill]; - - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - - }]; - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; }]; } @@ -595,81 +509,6 @@ - (void)testDownloadKeysWithUnreachableHS }]; } -- (void)testEnsureOlmSessionsForUsers -{ - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES; - - [matrixSDKTestsData doMXSessionTestWithAlice:self readyToTest:^(MXSession *aliceSession, XCTestExpectation *expectation) { - - [aliceSession.crypto uploadKeys:10 success:^{ - - [matrixSDKTestsData doMXSessionTestWithBob:nil readyToTest:^(MXSession *mxSession, XCTestExpectation *expectation2) { - - [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = NO; - - [mxSession.crypto.deviceList downloadKeys:@[mxSession.myUser.userId, aliceSession.myUser.userId] forceDownload:NO success:^(MXUsersDevicesMap *usersDevicesInfoMap) { - - - // Start the test - MXHTTPOperation *httpOperation = [mxSession.crypto ensureOlmSessionsForUsers:@[mxSession.myUser.userId, aliceSession.myUser.userId] success:^(MXUsersDevicesMap *results) { - - XCTAssertEqual(results.userIds.count, 1, @"Only a session with Alice must be created. No mean to create on with oneself(Bob)"); - - MXOlmSessionResult *sessionWithAliceDevice = [results objectForDevice:aliceSession.matrixRestClient.credentials.deviceId forUser:aliceSession.myUser.userId]; - XCTAssert(sessionWithAliceDevice); - XCTAssert(sessionWithAliceDevice.sessionId); - XCTAssertEqualObjects(sessionWithAliceDevice.device.deviceId, aliceSession.matrixRestClient.credentials.deviceId); - - - // Test persistence - MXRestClient *bobRestClient = mxSession.matrixRestClient; - [mxSession close]; - - MXSession *mxSession2 = [[MXSession alloc] initWithMatrixRestClient:bobRestClient]; - [mxSession2 setStore:[[MXFileStore alloc] init] success:^{ - - MXHTTPOperation *httpOperation2 = [mxSession2.crypto ensureOlmSessionsForUsers:@[mxSession2.myUser.userId, aliceSession.myUser.userId] success:^(MXUsersDevicesMap *results) { - - XCTAssertEqual(results.userIds.count, 1, @"Only a session with Alice must be created. No mean to create on with oneself(Bob)"); - - MXOlmSessionResult *sessionWithAliceDevice = [results objectForDevice:aliceSession.matrixRestClient.credentials.deviceId forUser:aliceSession.myUser.userId]; - XCTAssert(sessionWithAliceDevice); - XCTAssert(sessionWithAliceDevice.sessionId); - XCTAssertEqualObjects(sessionWithAliceDevice.device.deviceId, aliceSession.matrixRestClient.credentials.deviceId); - - [expectation fulfill]; - - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - - XCTAssertNil(httpOperation2, @"The session must be in cache. No need to make a request"); - - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - - } failure:^(NSError *error) { - XCTFail(@"The request should not fail - NSError: %@", error); - [expectation fulfill]; - }]; - - XCTAssert(httpOperation); - - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - }]; - } failure:^(NSError *error) { - XCTFail(@"Cannot set up intial test conditions - error: %@", error); - [expectation fulfill]; - }]; - }]; -} - #pragma mark - MXRoom - (void)testRoomIsEncrypted @@ -1175,7 +1014,6 @@ - (void)testAliceDecryptOldMessageWithANewDeviceInACryptedRoom - (void)testAliceWithNewDeviceAndBob { [self doE2ETestWithAliceAndBobInARoomWithCryptedMessages:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { -// [self doE2ETestWithAliceAndBobInARoom:self cryptedBob:YES readyToTest:^(MXSession *aliceSession, MXSession *bobSession, NSString *roomId, XCTestExpectation *expectation) { // Relog alice to simulate a new device [MXSDKOptions sharedInstance].enableCryptoWhenStartingMXSession = YES;