From b41c7b1bc627ab8ff2eb7fbe0a75df9bd00f27c2 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Tue, 21 Sep 2021 09:58:11 +0200 Subject: [PATCH] fix: Don't re-play m.dummy to_device events If both ends had m.dummy events queued as last messages an an olm session corrupted, then the clients landed in an infinite game of ping-pong. It was so stable, that the clients could have won the ping-pong world championships! --- lib/encryption/olm_manager.dart | 11 ++++++++--- test/encryption/olm_manager_test.dart | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/encryption/olm_manager.dart b/lib/encryption/olm_manager.dart index 62290380..1e73559f 100644 --- a/lib/encryption/olm_manager.dart +++ b/lib/encryption/olm_manager.dart @@ -667,9 +667,14 @@ class OlmManager { return; } final lastSentMessage = json.decode(lastSentMessageRes.first); - // okay, time to send the message! - await client.sendToDeviceEncrypted( - [device], lastSentMessage['type'], lastSentMessage['content']); + // We do *not* want to re-play m.dummy events, as they hold no value except of saying + // what olm session is the most recent one. In fact, if we *do* replay them, then + // we can easily land in an infinite ping-pong trap! + if (lastSentMessage['type'] != EventTypes.Dummy) { + // okay, time to send the message! + await client.sendToDeviceEncrypted( + [device], lastSentMessage['type'], lastSentMessage['content']); + } } } diff --git a/test/encryption/olm_manager_test.dart b/test/encryption/olm_manager_test.dart index 858f5914..3b063bd8 100644 --- a/test/encryption/olm_manager_test.dart +++ b/test/encryption/olm_manager_test.dart @@ -234,6 +234,30 @@ void main() { FakeMatrixApi.calledEndpoints.keys.any( (k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')), false); + + // don't replay if the last event is m.dummy itself + FakeMatrixApi.calledEndpoints.clear(); + await client.database.setLastSentMessageUserDeviceKey( + json.encode({ + 'type': 'm.dummy', + 'content': {}, + }), + client.id, + userId, + deviceId); + event = ToDeviceEvent( + sender: userId, + type: 'm.dummy', + content: {}, + encryptedContent: { + 'sender_key': senderKey, + }, + ); + await client.encryption.olmManager.handleToDeviceEvent(event); + expect( + FakeMatrixApi.calledEndpoints.keys.any( + (k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')), + false); }); test('dispose client', () async {