Przeglądaj źródła

Test that own devices (from other clients) get included

when sending out encrypted messages.

updates #497
JC Brand 7 lat temu
rodzic
commit
e774e9d1af
3 zmienionych plików z 86 dodań i 23 usunięć
  1. 50 4
      spec/omemo.js
  2. 33 18
      src/converse-omemo.js
  3. 3 1
      tests/mock.js

+ 50 - 4
spec/omemo.js

@@ -10,7 +10,7 @@
 
 
     describe("The OMEMO module", function() {
     describe("The OMEMO module", function() {
 
 
-        it("enables encrypted messages to be sent",
+        it("enables encrypted messages to be sent and received",
             mock.initConverseWithPromises(
             mock.initConverseWithPromises(
                 null, ['rosterGroupsFetched'], {},
                 null, ['rosterGroupsFetched'], {},
                 function (done, _converse) {
                 function (done, _converse) {
@@ -83,7 +83,9 @@
                     return _.filter(
                     return _.filter(
                         _converse.connection.IQ_stanzas,
                         _converse.connection.IQ_stanzas,
                         (iq) => {
                         (iq) => {
-                            const node = iq.nodeTree.querySelector('iq[to="'+contact_jid+'"] items[node="eu.siacs.conversations.axolotl.bundles:555"]');
+                            const node = iq.nodeTree.querySelector(
+                                'iq[to="'+contact_jid+'"] items[node="eu.siacs.conversations.axolotl.bundles:555"]'
+                            );
                             if (node) { iq_stanza = iq.nodeTree; }
                             if (node) { iq_stanza = iq.nodeTree; }
                             return node;
                             return node;
                         }).length;
                         }).length;
@@ -106,6 +108,36 @@
                                     .c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
                                     .c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
                                     .c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
                                     .c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
                                     .c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
                                     .c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
+                _converse.connection._dataRecv(test_utils.createRequest(stanza));
+                return test_utils.waitUntil(() => {
+                    return _.filter(
+                        _converse.connection.IQ_stanzas,
+                        (iq) => {
+                            const node = iq.nodeTree.querySelector(
+                                'iq[to="'+_converse.bare_jid+'"] items[node="eu.siacs.conversations.axolotl.bundles:482886413b977930064a5888b92134fe"]'
+                            );
+                            if (node) { iq_stanza = iq.nodeTree; }
+                            return node;
+                        }).length;
+                });
+            }).then(() => {
+                const stanza = $iq({
+                    'from': _converse.bare_jid,
+                    'id': iq_stanza.getAttribute('id'),
+                    'to': _converse.bare_jid,
+                    'type': 'result',
+                }).c('pubsub', {
+                    'xmlns': 'http://jabber.org/protocol/pubsub'
+                    }).c('items', {'node': "eu.siacs.conversations.axolotl.bundles:482886413b977930064a5888b92134fe"})
+                        .c('item')
+                            .c('bundle', {'xmlns': 'eu.siacs.conversations.axolotl'})
+                                .c('signedPreKeyPublic', {'signedPreKeyId': '4223'}).t(btoa('100000')).up()
+                                .c('signedPreKeySignature').t(btoa('200000')).up()
+                                .c('identityKey').t(btoa('300000')).up()
+                                .c('prekeys')
+                                    .c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1991')).up()
+                                    .c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1992')).up()
+                                    .c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1993'));
 
 
                 spyOn(_converse.connection, 'send').and.callFake(stanza => { sent_stanza = stanza });
                 spyOn(_converse.connection, 'send').and.callFake(stanza => { sent_stanza = stanza });
                 _converse.connection._dataRecv(test_utils.createRequest(stanza));
                 _converse.connection._dataRecv(test_utils.createRequest(stanza));
@@ -117,11 +149,25 @@
                         `<body>This is an OMEMO encrypted message which your client doesn’t seem to support. Find more information on https://conversations.im/omemo</body>`+
                         `<body>This is an OMEMO encrypted message which your client doesn’t seem to support. Find more information on https://conversations.im/omemo</body>`+
                         `<encrypted xmlns='eu.siacs.conversations.axolotl'>`+
                         `<encrypted xmlns='eu.siacs.conversations.axolotl'>`+
                             `<header sid='123456789'>`+
                             `<header sid='123456789'>`+
-                                `<key>eyJpdiI6IjEyMzQ1In0=</key>`+
-                                `<iv>12345</iv>`+
+                                `<key rid='482886413b977930064a5888b92134fe'>eyJ0eXBlIjoxLCJib2R5IjoiYzFwaDNSNzNYNyIsInJlZ2lzdHJhdGlvbklkIjoiMTMzNyJ9</key>`+
+                                `<key rid='555'>eyJ0eXBlIjoxLCJib2R5IjoiYzFwaDNSNzNYNyIsInJlZ2lzdHJhdGlvbklkIjoiMTMzNyJ9</key>`+
+                                `<iv>${sent_stanza.nodeTree.querySelector('iv').textContent}</iv>`+
                             `</header>`+
                             `</header>`+
                         `</encrypted>`+
                         `</encrypted>`+
                     `</message>`);
                     `</message>`);
+
+                // Test reception of an encrypted message
+                const stanza = $msg({
+                        'from': contact_jid,
+                        'to': _converse.connection.jid,
+                        'type': 'chat',
+                        'id': 'qwerty' 
+                    }).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('c1ph3R73X7').up()
+                                .c('iv').t('1234');
+                _converse.connection._dataRecv(test_utils.createRequest(stanza));
                 done();
                 done();
             });
             });
         }));
         }));

+ 33 - 18
src/converse-omemo.js

@@ -92,8 +92,13 @@
                     const { _converse } = this.__super__;
                     const { _converse } = this.__super__;
                     return new Promise((resolve, reject) => {
                     return new Promise((resolve, reject) => {
                         _converse.getDevicesForContact(this.get('jid'))
                         _converse.getDevicesForContact(this.get('jid'))
-                            .then((devices) => {
-                                Promise.all(devices.map((device) => device.getBundle()))
+                            .then((their_devices) => {
+                                const device_id = _converse.omemo_store.get('device_id'),
+                                      devicelist = _converse.devicelists.get(_converse.bare_jid),
+                                      own_devices = devicelist.devices.filter(device => device.get('id') !== device_id),
+                                      devices = _.concat(own_devices, their_devices.models);
+
+                                Promise.all(devices.map(device => device.getBundle()))
                                     .then(() => this.buildSessions(devices))
                                     .then(() => this.buildSessions(devices))
                                     .then(() => resolve(devices))
                                     .then(() => resolve(devices))
                                     .catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
                                     .catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
@@ -165,22 +170,27 @@
                           address = new libsignal.SignalProtocolAddress(this.get('jid'), device.get('id')),
                           address = new libsignal.SignalProtocolAddress(this.get('jid'), device.get('id')),
                           sessionCipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
                           sessionCipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
 
 
-                    return sessionCipher.encrypt(plaintext);
+                    return new Promise((resolve, reject) => {
+                        sessionCipher.encrypt(plaintext)
+                            .then(payload => resolve({'payload': payload, 'device': device}))
+                            .catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
+                        });
                 },
                 },
 
 
-                addKeysToMessageStanza (stanza, devices, payloads) {
-                    for (var i in payloads) {
-                        if (Object.prototype.hasOwnProperty.call(payloads, i)) {
-                            const payload = btoa(JSON.stringify(payloads[i]))
-                            const prekey = 3 == parseInt(payloads[i].type, 10)
-                            if (i == payloads.length-1) {
-                                stanza.c('key', {'rid': devices.get('id') }).t(payload)
-                                if (prekey) {
-                                    stanza.attrs({'prekey': prekey});
-                                }
-                                stanza.up().c('iv').t(payloads[0].iv).up().up()
-                            } else {
-                                stanza.c('key', {prekey: prekey, rid: devices.get('id') }).t(payload).up()
+                addKeysToMessageStanza (stanza, dicts, iv) {
+                    for (var i in dicts) {
+                        if (Object.prototype.hasOwnProperty.call(dicts, i)) {
+                            const payload = dicts[i].payload,
+                                  device = dicts[i].device,
+                                  prekey = 3 == parseInt(payload.type, 10);
+
+                            stanza.c('key', {'rid': device.get('id') }).t(btoa(JSON.stringify(dicts[i].payload)));
+                            if (prekey) {
+                                stanza.attrs({'prekey': prekey});
+                            }
+                            stanza.up();
+                            if (i == dicts.length-1) {
+                                stanza.c('iv').t(iv).up().up()
                             }
                             }
                         }
                         }
                     }
                     }
@@ -213,8 +223,13 @@
                         // long-standing SignalProtocol session.
                         // long-standing SignalProtocol session.
 
 
                         // TODO: need to include own devices here as well (and filter out distrusted devices)
                         // TODO: need to include own devices here as well (and filter out distrusted devices)
-                        const promises = devices.map(device => this.encryptKey(payload.key_str+payload.tag, device));
-                        return Promise.all(promises).then((payloads) => this.addKeysToMessageStanza(stanza, devices, payloads));
+                        const promises = devices
+                            .filter(device => device.get('trusted') != UNTRUSTED)
+                            .map(device => this.encryptKey(payload.key_str+payload.tag, device));
+
+                        return Promise.all(promises)
+                            .then((dicts) => this.addKeysToMessageStanza(stanza, dicts, payload.iv))
+                            .catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
                     });
                     });
                 },
                 },
 
 

+ 3 - 1
tests/mock.js

@@ -16,7 +16,9 @@
             this.remoteAddress = remote_address;
             this.remoteAddress = remote_address;
             this.storage = storage;
             this.storage = storage;
             this.encrypt = () => Promise.resolve({
             this.encrypt = () => Promise.resolve({
-                'iv': '12345'
+                'type': 1,
+                'body': 'c1ph3R73X7',
+                'registrationId': '1337' 
             });
             });
         },
         },
         'SessionBuilder': function (storage, remote_address) {
         'SessionBuilder': function (storage, remote_address) {