OMEMO: ensure reflected encrypted MUC messages are identified

This commit is contained in:
JC Brand 2020-09-16 13:28:59 +02:00
parent 9fe7bfcd64
commit 0a82a177c4
6 changed files with 36 additions and 22 deletions

View File

@ -18,7 +18,7 @@ const tpl_message = (o) => html`
?editable=${o.editable} ?editable=${o.editable}
?has_mentions=${o.has_mentions} ?has_mentions=${o.has_mentions}
?is_delayed=${o.is_delayed} ?is_delayed=${o.is_delayed}
?is_encrypted=${o.is_encrypted} ?is_encrypted=${!!o.is_encrypted}
?is_first_unread=${o.is_first_unread} ?is_first_unread=${o.is_first_unread}
?is_me_message=${o.is_me_message} ?is_me_message=${o.is_me_message}
?is_only_emojis=${o.is_only_emojis} ?is_only_emojis=${o.is_only_emojis}

View File

@ -161,7 +161,7 @@ export default class Message extends CustomElement {
this.message_type !== 'info' && this.message_type !== 'info' &&
prev_model.get('type') !== 'info' && prev_model.get('type') !== 'info' &&
date.isBefore(dayjs(prev_model.get('time')).add(10, 'minutes')) && date.isBefore(dayjs(prev_model.get('time')).add(10, 'minutes')) &&
this.is_encrypted === prev_model.get('is_encrypted'); !!this.is_encrypted === !!prev_model.get('is_encrypted');
} }
getExtraMessageClasses () { getExtraMessageClasses () {

View File

@ -187,9 +187,9 @@ async function decryptWhisperMessage (attrs) {
function addKeysToMessageStanza (stanza, dicts, iv) { function addKeysToMessageStanza (stanza, dicts, iv) {
for (const i in dicts) { for (const i in dicts) {
if (Object.prototype.hasOwnProperty.call(dicts, i)) { if (Object.prototype.hasOwnProperty.call(dicts, i)) {
const payload = dicts[i].payload, const payload = dicts[i].payload;
device = dicts[i].device, const device = dicts[i].device;
prekey = 3 == parseInt(payload.type, 10); const prekey = 3 == parseInt(payload.type, 10);
stanza.c('key', {'rid': device.get('id') }).t(btoa(payload.body)); stanza.c('key', {'rid': device.get('id') }).t(btoa(payload.body));
if (prekey) { if (prekey) {
@ -1206,7 +1206,7 @@ converse.plugins.add('converse-omemo', {
}); });
function parseEncryptedMessage (stanza, attrs) { function parseEncryptedMessage (stanza, attrs) {
if (attrs.is_encrypted) { if (attrs.is_encrypted && attrs.encrypted.key) {
// https://xmpp.org/extensions/xep-0384.html#usecases-receiving // https://xmpp.org/extensions/xep-0384.html#usecases-receiving
if (attrs.encrypted.prekey === true) { if (attrs.encrypted.prekey === true) {
return decryptPrekeyWhisperMessage(attrs); return decryptPrekeyWhisperMessage(attrs);

View File

@ -466,7 +466,7 @@ export const api = _converse.api = {
* @method _converse.api.hook * @method _converse.api.hook
* @param {string} name - The hook name * @param {string} name - The hook name
* @param {...any} context - The context to which the hook applies (could be for example, a {@link _converse.ChatBox)). * @param {...any} context - The context to which the hook applies (could be for example, a {@link _converse.ChatBox)).
* @param {...any} data - The data structure to be intercepted and * modified by the hook listeners. * @param {...any} data - The data structure to be intercepted and modified by the hook listeners.
*/ */
hook (name, context, data) { hook (name, context, data) {
const events = _converse._events[name] || []; const events = _converse._events[name] || [];

View File

@ -1930,6 +1930,21 @@ converse.plugins.add('converse-muc', {
return false; return false;
}, },
getMessageBodyQueryAttrs (attrs) {
if (attrs.message && attrs.msgid) {
const query = {
'from': attrs.from,
'msgid': attrs.msgid
}
if (!attrs.is_encrypted) {
// We can't match the message if it's a reflected
// encrypted MUC message
query['message'] = attrs.message;
}
return query;
}
},
/** /**
* Queue an incoming message stanza meant for this {@link _converse.Chatroom} for processing. * Queue an incoming message stanza meant for this {@link _converse.Chatroom} for processing.
* @async * @async

View File

@ -50,25 +50,24 @@ function getCorrectionAttributes (stanza, original_stanza) {
function getEncryptionAttributes (stanza, _converse) { function getEncryptionAttributes (stanza, _converse) {
const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).pop(); const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).pop();
const attrs = { 'is_encrypted': !!encrypted };
if (!encrypted || !_converse.config.get('trusted')) { if (!encrypted || !_converse.config.get('trusted')) {
return {}; return attrs;
} }
const header = encrypted.querySelector('header');
attrs['encrypted'] = {'device_id': header.getAttribute('sid')};
const device_id = _converse.omemo_store?.get('device_id'); const device_id = _converse.omemo_store?.get('device_id');
const key = device_id && sizzle(`key[rid="${device_id}"]`, encrypted).pop(); const key = device_id && sizzle(`key[rid="${device_id}"]`, encrypted).pop();
if (key) { if (key) {
const header = encrypted.querySelector('header'); Object.assign(attrs.encrypted, {
return { 'iv': header.querySelector('iv').textContent,
'is_encrypted': true, 'key': key.textContent,
'encrypted': { 'payload': encrypted.querySelector('payload')?.textContent || null,
'device_id': header.getAttribute('sid'), 'prekey': ['true', '1'].includes(key.getAttribute('prekey'))
'iv': header.querySelector('iv').textContent, });
'key': key.textContent,
'payload': encrypted.querySelector('payload')?.textContent || null,
'prekey': ['true', '1'].includes(key.getAttribute('prekey'))
}
}
} }
return {}; return attrs;
} }
@ -537,7 +536,7 @@ const st = {
* *Hook* which allows plugins to add additional parsing * *Hook* which allows plugins to add additional parsing
* @event _converse#parseMessage * @event _converse#parseMessage
*/ */
return api.hook('parseMessage', _converse, attrs); return api.hook('parseMessage', stanza, attrs);
}, },
/** /**
@ -685,7 +684,7 @@ const st = {
* *Hook* which allows plugins to add additional parsing * *Hook* which allows plugins to add additional parsing
* @event _converse#parseMUCMessage * @event _converse#parseMUCMessage
*/ */
return api.hook('parseMUCMessage', chatbox, attrs); return api.hook('parseMUCMessage', stanza, attrs);
}, },
/** /**