Bladeren bron

Bugfix. Create device based on prekey message for `from` JID

Otherwise for sent carbons we created it for the wrong user.
JC Brand 6 jaren geleden
bovenliggende
commit
21ca33ec29
4 gewijzigde bestanden met toevoegingen van 120 en 17 verwijderingen
  1. 12 7
      dist/converse.js
  2. 93 1
      spec/omemo.js
  3. 13 7
      src/converse-omemo.js
  4. 2 2
      src/headless/converse-disco.js

+ 12 - 7
dist/converse.js

@@ -56274,8 +56274,9 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
         _converse.log(`${e.name} ${e.message}`, Strophe.LogLevel.ERROR);
         _converse.log(`${e.name} ${e.message}`, Strophe.LogLevel.ERROR);
       },
       },
 
 
-      async handleDecryptedWhisperMessage(encrypted, key_and_tag) {
+      async handleDecryptedWhisperMessage(attrs, key_and_tag) {
         const _converse = this.__super__._converse,
         const _converse = this.__super__._converse,
+              encrypted = attrs.encrypted,
               devicelist = _converse.devicelists.getDeviceList(this.get('jid'));
               devicelist = _converse.devicelists.getDeviceList(this.get('jid'));
 
 
         this.save('omemo_supported', true);
         this.save('omemo_supported', true);
@@ -56284,7 +56285,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
         if (!device) {
         if (!device) {
           device = devicelist.devices.create({
           device = devicelist.devices.create({
             'id': encrypted.device_id,
             'id': encrypted.device_id,
-            'jid': this.get('jid')
+            'jid': attrs.from
           });
           });
         }
         }
 
 
@@ -56306,7 +56307,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
 
 
         if (attrs.encrypted.prekey === true) {
         if (attrs.encrypted.prekey === true) {
           let plaintext;
           let plaintext;
-          return session_cipher.decryptPreKeyWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary').then(key_and_tag => this.handleDecryptedWhisperMessage(attrs.encrypted, key_and_tag)).then(pt => {
+          return session_cipher.decryptPreKeyWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary').then(key_and_tag => this.handleDecryptedWhisperMessage(attrs, key_and_tag)).then(pt => {
             plaintext = pt;
             plaintext = pt;
             return _converse.omemo_store.generateMissingPreKeys();
             return _converse.omemo_store.generateMissingPreKeys();
           }).then(() => _converse.omemo_store.publishBundle()).then(() => {
           }).then(() => _converse.omemo_store.publishBundle()).then(() => {
@@ -56324,7 +56325,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
             return attrs;
             return attrs;
           });
           });
         } else {
         } else {
-          return session_cipher.decryptWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary').then(key_and_tag => this.handleDecryptedWhisperMessage(attrs.encrypted, key_and_tag)).then(plaintext => _.extend(attrs, {
+          return session_cipher.decryptWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary').then(key_and_tag => this.handleDecryptedWhisperMessage(attrs, key_and_tag)).then(plaintext => _.extend(attrs, {
             'plaintext': plaintext
             'plaintext': plaintext
           })).catch(e => {
           })).catch(e => {
             this.reportDecryptionError(e);
             this.reportDecryptionError(e);
@@ -57006,7 +57007,11 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
                   resolve();
                   resolve();
                 }
                 }
               },
               },
-              'error': () => {
+              'error': (model, resp) => {
+                _converse.log("Could not fetch OMEMO session from cache, we'll generate a new one.", Strophe.LogLevel.WARN);
+
+                _converse.log(resp, Strophe.LogLevel.WARN);
+
                 this.generateBundle().then(resolve).catch(reject);
                 this.generateBundle().then(resolve).catch(reject);
               }
               }
             });
             });
@@ -65275,9 +65280,9 @@ _converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins.add('converse-dis
           const stanza = await _converse.api.disco.info(this.get('jid'), null);
           const stanza = await _converse.api.disco.info(this.get('jid'), null);
           this.onInfo(stanza);
           this.onInfo(stanza);
         } catch (iq) {
         } catch (iq) {
-          this.waitUntilFeaturesDiscovered.resolve(this);
-
           _converse.log(iq, Strophe.LogLevel.ERROR);
           _converse.log(iq, Strophe.LogLevel.ERROR);
+
+          this.waitUntilFeaturesDiscovered.resolve(this);
         }
         }
       },
       },
 
 

+ 93 - 1
spec/omemo.js

@@ -31,7 +31,7 @@
     function bundleFetched (_converse, jid, device_id) {
     function bundleFetched (_converse, jid, device_id) {
         return _.filter(
         return _.filter(
             _converse.connection.IQ_stanzas,
             _converse.connection.IQ_stanzas,
-            (iq) => iq.nodeTree.querySelector(`iq[to="${jid}"] items[node="eu.siacs.conversations.axolotl.bundles:${device_id}"]`)
+            iq => iq.nodeTree.querySelector(`iq[to="${jid}"] items[node="eu.siacs.conversations.axolotl.bundles:${device_id}"]`)
         ).pop();
         ).pop();
     }
     }
 
 
@@ -381,6 +381,98 @@
             done();
             done();
         }));
         }));
 
 
+        it("will create a new device based on a received carbon message",
+            mock.initConverse(
+                null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+                async function (done, _converse) {
+
+            await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
+
+            let sent_stanza;
+            test_utils.createContacts(_converse, 'current', 1);
+            _converse.api.trigger('rosterContactsFetched');
+            const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+            await test_utils.waitUntil(() => initializedOMEMO(_converse));
+            await test_utils.openChatBoxFor(_converse, contact_jid);
+            let iq_stanza = await test_utils.waitUntil(() => deviceListFetched(_converse, contact_jid));
+            const stanza = $iq({
+                    'from': contact_jid,
+                    'id': iq_stanza.nodeTree.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(test_utils.createRequest(stanza));
+            await test_utils.waitUntil(() => _converse.omemo_store);
+            const devicelist = _converse.devicelists.get({'jid': contact_jid});
+            await test_utils.waitUntil(() => devicelist.devices.length === 1);
+
+            const view = _converse.chatboxviews.get(contact_jid);
+            view.model.set('omemo_active', true);
+
+            // Test reception of an encrypted carbon message
+            const obj = await view.model.encryptMessage('This is an encrypted carbon message from another device of mine')
+            const carbon = u.toStanza(`
+                <message xmlns="jabber:client" to="dummy@localhost/resource" from="dummy@localhost" type="chat">
+                    <sent xmlns="urn:xmpp:carbons:2">
+                        <forwarded xmlns="urn:xmpp:forward:0">
+                        <message xmlns="jabber:client"
+                                 from="dummy@localhost/gajim.HE02SW1L"
+                                 xml:lang="en"
+                                 to="${contact_jid}/gajim.0LATM5V2"
+                                 type="chat" id="87141781-61d6-4eb3-9a31-429935a61b76">
+
+                            <archived xmlns="urn:xmpp:mam:tmp" by="dummy@localhost" id="1554033877043470"/>
+                            <stanza-id xmlns="urn:xmpp:sid:0" by="dummy@localhost" id="1554033877043470"/>
+                            <request xmlns="urn:xmpp:receipts"/>
+                            <active xmlns="http://jabber.org/protocol/chatstates"/>
+                            <origin-id xmlns="urn:xmpp:sid:0" id="87141781-61d6-4eb3-9a31-429935a61b76"/>
+                            <encrypted xmlns="eu.siacs.conversations.axolotl">
+                                <header sid="988349631">
+                                    <key rid="${_converse.omemo_store.get('device_id')}"
+                                         prekey="true">${u.arrayBufferToBase64(obj.key_and_tag)}</key>
+                                    <iv>${obj.iv}</iv>
+                                </header>
+                                <payload>${obj.payload}</payload>
+                            </encrypted>
+                            <encryption xmlns="urn:xmpp:eme:0" namespace="eu.siacs.conversations.axolotl" name="OMEMO"/>
+                            <store xmlns="urn:xmpp:hints"/>
+                        </message>
+                        </forwarded>
+                    </sent>
+                </message>
+            `);
+            _converse.connection._dataRecv(test_utils.createRequest(carbon));
+            await new Promise(resolve => view.once('messageInserted', resolve));
+            expect(view.model.messages.length).toBe(1);
+            expect(view.el.querySelector('.chat-msg__body').textContent.trim())
+                .toBe('This is an encrypted carbon message from another device of mine');
+
+            expect(devicelist.devices.length).toBe(2);
+            expect(devicelist.devices.at(0).get('id')).toBe('555');
+            expect(devicelist.devices.at(1).get('id')).toBe('988349631');
+            expect(devicelist.devices.get('988349631').get('active')).toBe(true);
+
+            const textarea = view.el.querySelector('.chat-textarea');
+            textarea.value = 'This is an encrypted message from this device';
+            view.keyPressed({
+                target: textarea,
+                preventDefault: _.noop,
+                keyCode: 13 // Enter
+            });
+            iq_stanza = await test_utils.waitUntil(() => bundleFetched(_converse, _converse.bare_jid, '988349631'));
+            expect(iq_stanza.toLocaleString()).toBe(
+                `<iq from="dummy@localhost" id="${iq_stanza.nodeTree.getAttribute("id")}" to="${_converse.bare_jid}" type="get" xmlns="jabber:client">`+
+                    `<pubsub xmlns="http://jabber.org/protocol/pubsub">`+
+                        `<items node="eu.siacs.conversations.axolotl.bundles:988349631"/>`+
+                    `</pubsub>`+
+                `</iq>`);
+            done();
+        }));
+
         it("gracefully handles auth errors when trying to send encrypted groupchat messages",
         it("gracefully handles auth errors when trying to send encrypted groupchat messages",
             mock.initConverse(
             mock.initConverse(
                 null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                 null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},

+ 13 - 7
src/converse-omemo.js

@@ -229,14 +229,15 @@ converse.plugins.add('converse-omemo', {
                 _converse.log(`${e.name} ${e.message}`, Strophe.LogLevel.ERROR);
                 _converse.log(`${e.name} ${e.message}`, Strophe.LogLevel.ERROR);
             },
             },
 
 
-            async handleDecryptedWhisperMessage (encrypted, key_and_tag) {
+            async handleDecryptedWhisperMessage (attrs, key_and_tag) {
                 const { _converse } = this.__super__,
                 const { _converse } = this.__super__,
+                      encrypted = attrs.encrypted,
                       devicelist = _converse.devicelists.getDeviceList(this.get('jid'));
                       devicelist = _converse.devicelists.getDeviceList(this.get('jid'));
 
 
                 this.save('omemo_supported', true);
                 this.save('omemo_supported', true);
                 let device = devicelist.get(encrypted.device_id);
                 let device = devicelist.get(encrypted.device_id);
                 if (!device) {
                 if (!device) {
-                    device = devicelist.devices.create({'id': encrypted.device_id, 'jid': this.get('jid')});
+                    device = devicelist.devices.create({'id': encrypted.device_id, 'jid': attrs.from});
                 }
                 }
                 if (encrypted.payload) {
                 if (encrypted.payload) {
                     const key = key_and_tag.slice(0, 16),
                     const key = key_and_tag.slice(0, 16),
@@ -255,7 +256,7 @@ converse.plugins.add('converse-omemo', {
                 if (attrs.encrypted.prekey === true) {
                 if (attrs.encrypted.prekey === true) {
                     let plaintext;
                     let plaintext;
                     return session_cipher.decryptPreKeyWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary')
                     return session_cipher.decryptPreKeyWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary')
-                        .then(key_and_tag => this.handleDecryptedWhisperMessage(attrs.encrypted, key_and_tag))
+                        .then(key_and_tag => this.handleDecryptedWhisperMessage(attrs, key_and_tag))
                         .then(pt => {
                         .then(pt => {
                             plaintext = pt;
                             plaintext = pt;
                             return _converse.omemo_store.generateMissingPreKeys();
                             return _converse.omemo_store.generateMissingPreKeys();
@@ -272,7 +273,7 @@ converse.plugins.add('converse-omemo', {
                         });
                         });
                 } else {
                 } else {
                     return session_cipher.decryptWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary')
                     return session_cipher.decryptWhisperMessage(u.base64ToArrayBuffer(attrs.encrypted.key), 'binary')
-                        .then(key_and_tag => this.handleDecryptedWhisperMessage(attrs.encrypted, key_and_tag))
+                        .then(key_and_tag => this.handleDecryptedWhisperMessage(attrs, key_and_tag))
                         .then(plaintext => _.extend(attrs, {'plaintext': plaintext}))
                         .then(plaintext => _.extend(attrs, {'plaintext': plaintext}))
                         .catch(e => {
                         .catch(e => {
                             this.reportDecryptionError(e);
                             this.reportDecryptionError(e);
@@ -886,7 +887,12 @@ converse.plugins.add('converse-omemo', {
                                     resolve();
                                     resolve();
                                 }
                                 }
                             },
                             },
-                            'error': () => {
+                            'error': (model, resp) => {
+                                _converse.log(
+                                    "Could not fetch OMEMO session from cache, we'll generate a new one.",
+                                    Strophe.LogLevel.WARN
+                                );
+                                _converse.log(resp, Strophe.LogLevel.WARN);
                                 this.generateBundle().then(resolve).catch(reject);
                                 this.generateBundle().then(resolve).catch(reject);
                             }
                             }
                         });
                         });
@@ -926,8 +932,8 @@ converse.plugins.add('converse-omemo', {
                     throw new IQError("Could not fetch bundle", iq);
                     throw new IQError("Could not fetch bundle", iq);
                 }
                 }
                 const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, iq).pop(),
                 const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, iq).pop(),
-                        bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop(),
-                        bundle = parseBundle(bundle_el);
+                      bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop(),
+                      bundle = parseBundle(bundle_el);
                 this.save('bundle', bundle);
                 this.save('bundle', bundle);
                 return bundle;
                 return bundle;
             },
             },

+ 2 - 2
src/headless/converse-disco.js

@@ -141,9 +141,9 @@ converse.plugins.add('converse-disco', {
                 try {
                 try {
                     const stanza = await _converse.api.disco.info(this.get('jid'), null);
                     const stanza = await _converse.api.disco.info(this.get('jid'), null);
                     this.onInfo(stanza);
                     this.onInfo(stanza);
-                } catch(iq) {
-                    this.waitUntilFeaturesDiscovered.resolve(this);
+                } catch (iq) {
                     _converse.log(iq, Strophe.LogLevel.ERROR);
                     _converse.log(iq, Strophe.LogLevel.ERROR);
+                    this.waitUntilFeaturesDiscovered.resolve(this);
                 }
                 }
             },
             },