diff --git a/dist/converse.js b/dist/converse.js
index b875fff85..daccda218 100644
--- a/dist/converse.js
+++ b/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);
},
- async handleDecryptedWhisperMessage(encrypted, key_and_tag) {
+ async handleDecryptedWhisperMessage(attrs, key_and_tag) {
const _converse = this.__super__._converse,
+ encrypted = attrs.encrypted,
devicelist = _converse.devicelists.getDeviceList(this.get('jid'));
this.save('omemo_supported', true);
@@ -56284,7 +56285,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
if (!device) {
device = devicelist.devices.create({
'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) {
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;
return _converse.omemo_store.generateMissingPreKeys();
}).then(() => _converse.omemo_store.publishBundle()).then(() => {
@@ -56324,7 +56325,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
return attrs;
});
} 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
})).catch(e => {
this.reportDecryptionError(e);
@@ -57006,7 +57007,11 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
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);
}
});
@@ -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);
this.onInfo(stanza);
} catch (iq) {
- this.waitUntilFeaturesDiscovered.resolve(this);
-
_converse.log(iq, Strophe.LogLevel.ERROR);
+
+ this.waitUntilFeaturesDiscovered.resolve(this);
}
},
diff --git a/spec/omemo.js b/spec/omemo.js
index 908b86abb..e1347534f 100644
--- a/spec/omemo.js
+++ b/spec/omemo.js
@@ -31,7 +31,7 @@
function bundleFetched (_converse, jid, device_id) {
return _.filter(
_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();
}
@@ -381,6 +381,98 @@
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(`
+
+
+
+
+
+
+
+
+
+
+
+
+ ${u.arrayBufferToBase64(obj.key_and_tag)}
+ ${obj.iv}
+
+ ${obj.payload}
+
+
+
+
+
+
+
+ `);
+ _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(
+ ``+
+ ``+
+ ``+
+ ``+
+ ``);
+ done();
+ }));
+
it("gracefully handles auth errors when trying to send encrypted groupchat messages",
mock.initConverse(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
diff --git a/src/converse-omemo.js b/src/converse-omemo.js
index ff80f088c..a7c33cb69 100644
--- a/src/converse-omemo.js
+++ b/src/converse-omemo.js
@@ -229,14 +229,15 @@ converse.plugins.add('converse-omemo', {
_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__,
+ encrypted = attrs.encrypted,
devicelist = _converse.devicelists.getDeviceList(this.get('jid'));
this.save('omemo_supported', true);
let device = devicelist.get(encrypted.device_id);
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) {
const key = key_and_tag.slice(0, 16),
@@ -255,7 +256,7 @@ converse.plugins.add('converse-omemo', {
if (attrs.encrypted.prekey === true) {
let plaintext;
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 => {
plaintext = pt;
return _converse.omemo_store.generateMissingPreKeys();
@@ -272,7 +273,7 @@ converse.plugins.add('converse-omemo', {
});
} else {
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}))
.catch(e => {
this.reportDecryptionError(e);
@@ -886,7 +887,12 @@ converse.plugins.add('converse-omemo', {
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);
}
});
@@ -926,8 +932,8 @@ converse.plugins.add('converse-omemo', {
throw new IQError("Could not fetch bundle", iq);
}
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);
return bundle;
},
diff --git a/src/headless/converse-disco.js b/src/headless/converse-disco.js
index 3eaaf869f..07610a7ef 100644
--- a/src/headless/converse-disco.js
+++ b/src/headless/converse-disco.js
@@ -141,9 +141,9 @@ converse.plugins.add('converse-disco', {
try {
const stanza = await _converse.api.disco.info(this.get('jid'), null);
this.onInfo(stanza);
- } catch(iq) {
- this.waitUntilFeaturesDiscovered.resolve(this);
+ } catch (iq) {
_converse.log(iq, Strophe.LogLevel.ERROR);
+ this.waitUntilFeaturesDiscovered.resolve(this);
}
},