Browse Source

Updates #2733

Properly handle the same OMEMO message being recieved twice, with the
2nd one failing to decrypt.
JC Brand 3 năm trước cách đây
mục cha
commit
38519a6261
3 tập tin đã thay đổi với 85 bổ sung3 xóa
  1. 1 1
      CHANGES.md
  2. 15 2
      src/headless/plugins/chat/model.js
  3. 69 0
      src/plugins/omemo/tests/omemo.js

+ 1 - 1
CHANGES.md

@@ -2,7 +2,7 @@
 
 ## 9.0.1 (Unreleased)
 
-- Updated translations: lt
+- Updated translations: af, ar, es, eu, fr, gl, he, lt
 - Increased stanza timeout from 10 to 20 seconds
 - Replace various font icons with SVG icons
 - #1761: Add a new dark theme based on the [Dracula](https://draculatheme.com/) theme

+ 15 - 2
src/headless/plugins/chat/model.js

@@ -449,8 +449,21 @@ const ChatBox = ModelWithContact.extend({
     },
 
     getUpdatedMessageAttributes (message, attrs) {
-        // Filter the attrs object, restricting it to only the `is_archived` key.
-        return (({ is_archived }) => ({ is_archived }))(attrs)
+        if (!attrs.error_type && message.get('error_type') === 'Decryption') {
+            // Looks like we have a failed decrypted message stored, and now
+            // we have a properly decrypted version of the same message.
+            // See issue: https://github.com/conversejs/converse.js/issues/2733#issuecomment-1035493594
+            return Object.assign({}, attrs, {
+                error_condition: undefined,
+                error_message: undefined,
+                error_text: undefined,
+                error_type: undefined,
+                is_archived: attrs.is_archived,
+                is_ephemeral: false,
+            });
+        } else {
+            return { is_archived: attrs.is_archived };
+        }
     },
 
     updateMessage (message, attrs) {

+ 69 - 0
src/plugins/omemo/tests/omemo.js

@@ -152,6 +152,75 @@ describe("The OMEMO module", function() {
             .toBe('Another received encrypted message without fallback');
     }));
 
+    it("properly handles an already decrypted message being received again",
+            mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
+
+        await mock.waitForRoster(_converse, 'current', 1);
+        const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+        await mock.initializedOMEMO(_converse);
+        await mock.openChatBoxFor(_converse, contact_jid);
+        const iq_stanza = await u.waitUntil(() => mock.deviceListFetched(_converse, contact_jid));
+        let stanza = $iq({
+                'from': contact_jid,
+                'id': iq_stanza.getAttribute('id'),
+                'to': _converse.connection.jid,
+                'type': 'result',
+            }).c('pubsub', {'xmlns': "http://jabber.org/protocol/pubsub"})
+                .c('items', {'node': "eu.siacs.conversations.axolotl.devicelist"})
+                    .c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
+                        .c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
+                            .c('device', {'id': '555'});
+        _converse.connection._dataRecv(mock.createRequest(stanza));
+
+        await u.waitUntil(() => _converse.omemo_store);
+
+        const view = _converse.chatboxviews.get(contact_jid);
+        view.model.set('omemo_active', true);
+
+        // Test reception of an encrypted message
+        const msg_txt = 'This is an encrypted message from the contact';
+        const obj = await omemo.encryptMessage(msg_txt)
+        const id = _converse.connection.getUniqueId();
+        stanza = $msg({
+                'from': contact_jid,
+                'to': _converse.connection.jid,
+                'type': 'chat',
+                id
+            }).c('body').t('This is a fallback message').up()
+                .c('encrypted', {'xmlns': Strophe.NS.OMEMO})
+                    .c('header', {'sid':  '555'})
+                        .c('key', {'rid':  _converse.omemo_store.get('device_id')})
+                            .t(u.arrayBufferToBase64(obj.key_and_tag)).up()
+                        .c('iv').t(obj.iv)
+                        .up().up()
+                    .c('payload').t(obj.payload);
+        _converse.connection._dataRecv(mock.createRequest(stanza));
+
+        // Test reception of the same message, but the decryption fails.
+        // The properly decrypted message should still show to the user.
+        // See issue: https://github.com/conversejs/converse.js/issues/2733#issuecomment-1035493594
+        stanza = $msg({
+                'from': contact_jid,
+                'to': _converse.connection.jid,
+                'type': 'chat',
+                id
+            }).c('body').t('This is a fallback message').up()
+                .c('encrypted', {'xmlns': Strophe.NS.OMEMO})
+                    .c('header', {'sid':  '555'})
+                        .c('key', {'rid':  _converse.omemo_store.get('device_id')})
+                            .t(u.arrayBufferToBase64(obj.key_and_tag)).up()
+                        .c('iv').t(obj.iv)
+                        .up().up()
+                    .c('payload').t(obj.payload+'x'); // Hack to break decryption.
+        _converse.connection._dataRecv(mock.createRequest(stanza));
+
+        await u.waitUntil(() => view.querySelector('.chat-msg__text')?.textContent.trim() === msg_txt);
+
+        expect(view.model.messages.length).toBe(1);
+        const msg = view.model.messages.at(0);
+        expect(msg.get('is_ephemeral')).toBe(false)
+    }));
+
     it("will create a new device based on a received carbon message",
             mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {