Commit 21ca33ec authored by JC Brand's avatar JC Brand

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

Otherwise for sent carbons we created it for the wrong user.
parent 97400ed5
...@@ -56274,8 +56274,9 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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);
} }
}, },
...@@ -31,7 +31,7 @@ ...@@ -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 @@ ...@@ -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'], {},
......
...@@ -229,14 +229,15 @@ converse.plugins.add('converse-omemo', { ...@@ -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', { ...@@ -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', { ...@@ -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', { ...@@ -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', { ...@@ -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_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop(),
bundle = parseBundle(bundle_el); bundle = parseBundle(bundle_el);
this.save('bundle', bundle); this.save('bundle', bundle);
return bundle; return bundle;
}, },
......
...@@ -141,9 +141,9 @@ converse.plugins.add('converse-disco', { ...@@ -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) { } catch (iq) {
this.waitUntilFeaturesDiscovered.resolve(this);
_converse.log(iq, Strophe.LogLevel.ERROR); _converse.log(iq, Strophe.LogLevel.ERROR);
this.waitUntilFeaturesDiscovered.resolve(this);
} }
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment