Browse Source

Updates #2849

Add test case for incoming OMEMO message corrections.

The correction was being ignored because the parsed `msgid` of an
incoming correction was set to the `msgid` of the message being
replaced.
JC Brand 3 years ago
parent
commit
7355c2c5fe

+ 6 - 4
src/headless/plugins/chat/model.js

@@ -637,7 +637,8 @@ const ChatBox = ModelWithContact.extend({
             } else {
             } else {
                 older_versions[message.get('time')] = message.getMessageText();
                 older_versions[message.get('time')] = message.getMessageText();
             }
             }
-            attrs = Object.assign(attrs, {'older_versions': older_versions});
+            attrs = Object.assign(attrs, { older_versions });
+            delete attrs['msgid']; // We want to keep the msgid of the original message
             delete attrs['id']; // Delete id, otherwise a new cache entry gets created
             delete attrs['id']; // Delete id, otherwise a new cache entry gets created
             attrs['time'] = message.get('time');
             attrs['time'] = message.get('time');
             message.save(attrs);
             message.save(attrs);
@@ -679,15 +680,16 @@ const ChatBox = ModelWithContact.extend({
     },
     },
 
 
     getMessageBodyQueryAttrs (attrs) {
     getMessageBodyQueryAttrs (attrs) {
-        if (attrs.message && attrs.msgid) {
+        if (attrs.msgid) {
             const query = {
             const query = {
                 'from': attrs.from,
                 'from': attrs.from,
                 'msgid': attrs.msgid
                 'msgid': attrs.msgid
             }
             }
-            if (!attrs.is_encrypted) {
+            // XXX: Need to take XEP-428 <fallback> into consideration
+            if (!attrs.is_encrypted && attrs.body) {
                 // We can't match the message if it's a reflected
                 // We can't match the message if it's a reflected
                 // encrypted message (e.g. via MAM or in a MUC)
                 // encrypted message (e.g. via MAM or in a MUC)
-                query['message'] =  attrs.message;
+                query['body'] =  attrs.body;
             }
             }
             return query;
             return query;
         }
         }

+ 2 - 1
src/headless/plugins/chat/utils.js

@@ -125,7 +125,8 @@ export async function handleMessageStanza (stanza) {
         attrs.stanza && log.error(attrs.stanza);
         attrs.stanza && log.error(attrs.stanza);
         return log.error(attrs.message);
         return log.error(attrs.message);
     }
     }
-    const has_body = !!sizzle(`body, encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).length;
+    // XXX: Need to take XEP-428 <fallback> into consideration
+    const has_body = !!(attrs.body || attrs.plaintext)
     const chatbox = await api.chats.get(attrs.contact_jid, { 'nickname': attrs.nick }, has_body);
     const chatbox = await api.chats.get(attrs.contact_jid, { 'nickname': attrs.nick }, has_body);
     await chatbox?.queueMessage(attrs);
     await chatbox?.queueMessage(attrs);
     /**
     /**

+ 0 - 2
src/headless/shared/parsers.js

@@ -108,12 +108,10 @@ export function getCorrectionAttributes (stanza, original_stanza) {
     const el = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop();
     const el = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop();
     if (el) {
     if (el) {
         const replace_id = el.getAttribute('id');
         const replace_id = el.getAttribute('id');
-        const msgid = replace_id;
         if (replace_id) {
         if (replace_id) {
             const delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop();
             const delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop();
             const time = delay ? dayjs(delay.getAttribute('stamp')).toISOString() : new Date().toISOString();
             const time = delay ? dayjs(delay.getAttribute('stamp')).toISOString() : new Date().toISOString();
             return {
             return {
-                msgid,
                 replace_id,
                 replace_id,
                 'edited': time
                 'edited': time
             };
             };

+ 54 - 2
src/plugins/omemo/tests/corrections.js

@@ -1,6 +1,6 @@
 /*global mock, converse */
 /*global mock, converse */
 
 
-const { Strophe, $iq, $pres, u } = converse.env;
+const { Strophe, $iq, $msg, $pres, u, omemo } = converse.env;
 
 
 describe("An OMEMO encrypted message", function() {
 describe("An OMEMO encrypted message", function() {
 
 
@@ -126,7 +126,7 @@ describe("An OMEMO encrypted message", function() {
                     `<encryption namespace="eu.siacs.conversations.axolotl" xmlns="urn:xmpp:eme:0"/>`+
                     `<encryption namespace="eu.siacs.conversations.axolotl" xmlns="urn:xmpp:eme:0"/>`+
             `</message>`);
             `</message>`);
 
 
-        const older_versions = first_msg.get('older_versions');
+        let older_versions = first_msg.get('older_versions');
         let keys = Object.keys(older_versions);
         let keys = Object.keys(older_versions);
         expect(keys.length).toBe(1);
         expect(keys.length).toBe(1);
         expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
         expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
@@ -154,6 +154,58 @@ describe("An OMEMO encrypted message", function() {
         expect(keys.length).toBe(2);
         expect(keys.length).toBe(2);
         expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
         expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
         expect(older_versions[keys[1]]).toBe('But soft, what light through yonder door breaks?');
         expect(older_versions[keys[1]]).toBe('But soft, what light through yonder door breaks?');
+
+        const first_rcvd_msg_id = u.getUniqueId();
+        let obj = await omemo.encryptMessage('This is an encrypted message from the contact')
+        _converse.connection._dataRecv(mock.createRequest($msg({
+                'from': contact_jid,
+                'to': _converse.connection.jid,
+                'type': 'chat',
+                'id': first_rcvd_msg_id
+            }).c('body').t(fallback_text).up()
+                .c('origin-id', {'id': first_rcvd_msg_id, 'xmlns': 'urn:xmpp:sid:0'}).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)));
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        expect(view.model.messages.length).toBe(2);
+        expect(view.querySelectorAll('.chat-msg__body')[1].textContent.trim())
+            .toBe('This is an encrypted message from the contact');
+
+        const msg_id = u.getUniqueId();
+        obj = await omemo.encryptMessage('This is an edited encrypted message from the contact')
+        _converse.connection._dataRecv(mock.createRequest($msg({
+                'from': contact_jid,
+                'to': _converse.connection.jid,
+                'type': 'chat',
+                'id': msg_id
+            }).c('body').t(fallback_text).up()
+                .c('replace', {'id': first_rcvd_msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).up()
+                .c('origin-id', {'id': msg_id, 'xmlns': 'urn:xmpp:sid:0'}).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)));
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        expect(view.model.messages.length).toBe(2);
+        expect(view.querySelectorAll('.chat-msg__body')[1].textContent.trim())
+            .toBe('This is an edited encrypted message from the contact');
+
+        const message = view.model.messages.at(1);
+        older_versions = message.get('older_versions');
+        keys = Object.keys(older_versions);
+        expect(keys.length).toBe(1);
+        expect(older_versions[keys[0]]).toBe('This is an encrypted message from the contact');
+        expect(message.get('plaintext')).toBe('This is an edited encrypted message from the contact');
+        expect(message.get('is_encrypted')).toBe(true);
+        expect(message.get('body')).toBe(fallback_text);
+        expect(message.get('message')).toBe(fallback_text);
+        expect(message.get('msgid')).toBe(first_rcvd_msg_id);
     }));
     }));
 });
 });