omemo: better error handling when some bundles can't be fetched

This commit is contained in:
JC Brand 2020-09-18 13:27:51 +02:00
parent 3af1ffc357
commit 7330530d13
2 changed files with 25 additions and 10 deletions

View File

@ -298,6 +298,10 @@ async function buildSession (device) {
} }
async function getSession (device) { async function getSession (device) {
if (!device.get('bundle')) {
log.error(`Could not build an OMEMO session for device ${device.get('id')} because we don't have its bundle`);
return null;
}
const address = new libsignal.SignalProtocolAddress(device.get('jid'), device.get('id')); const address = new libsignal.SignalProtocolAddress(device.get('jid'), device.get('id'));
const session = await _converse.omemo_store.loadSession(address.toString()); const session = await _converse.omemo_store.loadSession(address.toString());
if (session) { if (session) {
@ -716,9 +720,11 @@ converse.plugins.add('converse-omemo', {
// Filter out our own device // Filter out our own device
const id = _converse.omemo_store.get('device_id'); const id = _converse.omemo_store.get('device_id');
devices = devices.filter(d => d.get('id') !== id); devices = devices.filter(d => d.get('id') !== id);
// Fetch bundles if necessary
await Promise.all(devices.map(d => d.getBundle())); await Promise.all(devices.map(d => d.getBundle()));
const sessions = await Promise.all(devices.map(d => getSession(d)));
const sessions = devices.filter(d => d).map(d => getSession(d));
await Promise.all(sessions);
if (sessions.includes(null)) { if (sessions.includes(null)) {
// We couldn't build a session for certain devices. // We couldn't build a session for certain devices.
devices = devices.filter(d => sessions[devices.indexOf(d)]); devices = devices.filter(d => sessions[devices.indexOf(d)]);
@ -1025,6 +1031,11 @@ converse.plugins.add('converse-omemo', {
} }
}); });
/**
* @class
* @namespace _converse.Device
* @memberOf _converse
*/
_converse.Device = Model.extend({ _converse.Device = Model.extend({
defaults: { defaults: {
'trusted': UNDECIDED, 'trusted': UNDECIDED,
@ -1049,22 +1060,26 @@ converse.plugins.add('converse-omemo', {
try { try {
iq = await api.sendIQ(stanza) iq = await api.sendIQ(stanza)
} catch (iq) { } catch (iq) {
throw new IQError("Could not fetch bundle", iq); log.error(`Could not fetch bundle for device ${this.get('id')} from ${this.get('jid')}`);
log.error(iq);
return null;
} }
if (iq.querySelector('error')) { if (iq.querySelector('error')) {
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(), const bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop();
bundle = parseBundle(bundle_el); const bundle = parseBundle(bundle_el);
this.save('bundle', bundle); this.save('bundle', bundle);
return bundle; return bundle;
}, },
/**
* Fetch and save the bundle information associated with
* this device, if the information is not cached already.
* @method _converse.Device#getBundle
*/
getBundle () { getBundle () {
/* Fetch and save the bundle information associated with
* this device, if the information is not at hand already.
*/
if (this.get('bundle')) { if (this.get('bundle')) {
return Promise.resolve(this.get('bundle'), this); return Promise.resolve(this.get('bundle'), this);
} else { } else {

View File

@ -912,7 +912,7 @@ export const api = _converse.api = {
* @param { Boolean } reject - Whether an error IQ should cause the promise * @param { Boolean } reject - Whether an error IQ should cause the promise
* to be rejected. If `false`, the promise will resolve instead of being rejected. * to be rejected. If `false`, the promise will resolve instead of being rejected.
* @returns {Promise} A promise which resolves when we receive a `result` stanza * @returns {Promise} A promise which resolves when we receive a `result` stanza
* or is rejected when we receive an `error` stanza. * or is rejected when we receive an `error` stanza.
*/ */
sendIQ (stanza, timeout, reject=true) { sendIQ (stanza, timeout, reject=true) {
timeout = timeout || _converse.STANZA_TIMEOUT; timeout = timeout || _converse.STANZA_TIMEOUT;