Commit a1d55639 authored by JC Brand's avatar JC Brand

Move OMEMO-related message parsing to utils/stanza.js

parent ce1f7e09
......@@ -381,7 +381,6 @@
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
await test_utils.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => initializedOMEMO(_converse));
......
......@@ -169,18 +169,6 @@ converse.plugins.add('converse-omemo', {
},
ChatBox: {
async parseMessage (stanza, original_stanza) {
const { _converse } = this.__super__;
const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, original_stanza).pop(),
attrs = await this.__super__.parseMessage.apply(this, arguments);
if (!encrypted || !_converse.config.get('trusted')) {
return attrs;
} else {
return this.getEncryptionAttributesfromStanza(stanza, original_stanza, attrs);
}
},
async sendMessage (text, spoiler_hint) {
if (this.get('omemo_active') && text) {
const { _converse } = this.__super__;
......@@ -368,25 +356,6 @@ converse.plugins.add('converse-omemo', {
}
},
getEncryptionAttributesfromStanza (stanza, original_stanza, attrs) {
const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, original_stanza).pop(),
header = encrypted.querySelector('header'),
key = sizzle(`key[rid="${_converse.omemo_store.get('device_id')}"]`, encrypted).pop();
if (key) {
attrs['is_encrypted'] = true;
attrs['encrypted'] = {
'device_id': header.getAttribute('sid'),
'iv': header.querySelector('iv').textContent,
'key': key.textContent,
'payload': encrypted.querySelector('payload')?.textContent || null,
'prekey': ['true', '1'].includes(key.getAttribute('prekey'))
}
return this.decrypt(attrs);
} else {
return Promise.resolve(attrs);
}
},
getSessionCipher (jid, id) {
const address = new libsignal.SignalProtocolAddress(jid, id);
this.session_cipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
......
......@@ -411,7 +411,7 @@ converse.plugins.add('converse-chat', {
},
async onMessage (stanza, original_stanza, from_jid) {
const attrs = await this.parseMessage(stanza, original_stanza);
const attrs = await st.parseMessage(stanza, original_stanza, this, _converse);
const message = this.getDuplicateMessage(attrs);
if (message) {
this.updateMessage(message, original_stanza);
......@@ -1081,22 +1081,6 @@ converse.plugins.add('converse-chat', {
});
},
/**
* Parses a passed in message stanza and returns an object of attributes.
* @private
* @method _converse.ChatBox#parseMessage
* @param { XMLElement } stanza - The message stanza
* @param { XMLElement } original_stanza - The original stanza, that contains the
* message stanza, if it was contained, otherwise it's the message stanza itself.
* @returns { Object }
*/
parseMessage (stanza, original_stanza) {
// XXX: Eventually we want to get rid of this pass-through
// method but currently we still need it because converse-omemo
// overrides it.
return st.parseMessage(stanza, original_stanza, this, _converse);
},
maybeShow () {
return this.trigger("show");
},
......@@ -1169,7 +1153,7 @@ converse.plugins.add('converse-chat', {
if (!should_show) {
return;
}
const attrs = await chatbox.parseMessage(stanza, stanza);
const attrs = await st.parseMessage(stanza, stanza, chatbox, _converse);
await chatbox.createMessage(attrs);
}
......
......@@ -3,8 +3,9 @@
* @copyright 2020, the Converse.js contributors
* @description XEP-0045 Multi-User Chat Views
*/
import converse from "@converse/headless/converse-core";
import { isString } from "lodash";
import converse from "@converse/headless/converse-core";
import st from "./utils/stanza";
const u = converse.env.utils;
......@@ -80,16 +81,16 @@ converse.plugins.add('converse-headlines', {
}
});
async function onHeadlineMessage (message) {
async function onHeadlineMessage (stanza) {
// Handler method for all incoming messages of type "headline".
if (u.isHeadlineMessage(_converse, message)) {
const from_jid = message.getAttribute('from');
if (u.isHeadlineMessage(_converse, stanza)) {
const from_jid = stanza.getAttribute('from');
if (from_jid.includes('@') &&
!_converse.roster.get(from_jid) &&
!api.settings.get("allow_non_roster_messaging")) {
return;
}
if (message.querySelector('body') === null) {
if (stanza.querySelector('body') === null) {
// Avoid creating a chat box if we have nothing to show inside it.
return;
}
......@@ -99,9 +100,9 @@ converse.plugins.add('converse-headlines', {
'type': _converse.HEADLINES_TYPE,
'from': from_jid
});
const attrs = await chatbox.parseMessage(message, message);
const attrs = await st.parseMessage(stanza, stanza, chatbox, _converse);
await chatbox.createMessage(attrs);
api.trigger('message', {'chatbox': chatbox, 'stanza': message});
api.trigger('message', {'chatbox': chatbox, 'stanza': stanza});
}
}
......
......@@ -2026,7 +2026,7 @@ converse.plugins.add('converse-muc', {
await this.createInfoMessages(stanza);
this.fetchFeaturesIfConfigurationChanged(stanza);
const attrs = await this.parseMessage(stanza, original_stanza);
const attrs = await st.parseMessage(stanza, original_stanza, this, _converse);
const message = this.getDuplicateMessage(attrs);
if (message) {
this.updateMessage(message, original_stanza);
......
......@@ -7,6 +7,97 @@ import u from '@converse/headless/utils/core';
const Strophe = strophe.default.Strophe;
function getSenderAttributes (stanza, chatbox, _converse) {
if (u.isChatRoom(chatbox)) {
const from = stanza.getAttribute('from');
const nick = Strophe.unescapeNode(Strophe.getResourceFromJid(from));
return {
'from': from,
'from_muc': Strophe.getBareJidFromJid(from),
'nick': nick,
'sender': nick === chatbox.get('nick') ? 'me': 'them',
'received': (new Date()).toISOString(),
}
} else {
const from = Strophe.getBareJidFromJid(stanza.getAttribute('from'));
if (from === _converse.bare_jid) {
return {
from,
'sender': 'me',
'fullname': _converse.xmppstatus.get('fullname')
}
} else {
return {
from,
'sender': 'them',
'fullname': chatbox.get('fullname')
}
}
}
}
function getSpoilerAttributes (stanza) {
const spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, stanza).pop();
return {
'is_spoiler': !!spoiler,
'spoiler_hint': spoiler?.textContent
}
}
function getOutOfBandAttributes (stanza) {
const xform = sizzle(`x[xmlns="${Strophe.NS.OUTOFBAND}"]`, stanza).pop();
if (xform) {
return {
'oob_url': xform.querySelector('url')?.textContent,
'oob_desc': xform.querySelector('desc')?.textContent
}
}
return {};
}
function getCorrectionAttributes (stanza, original_stanza) {
const el = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop();
if (el) {
const replaced_id = el.getAttribute('id');
const msgid = replaced_id;
if (replaced_id) {
const delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop();
const time = delay ? dayjs(delay.getAttribute('stamp')).toISOString() : (new Date()).toISOString();
return {
msgid,
replaced_id,
'edited': time
}
}
}
return {};
}
function getEncryptionAttributes (stanza, original_stanza, attrs, chatbox, _converse) {
const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, original_stanza).pop();
if (!encrypted || !_converse.config.get('trusted')) {
return attrs;
}
const key = sizzle(`key[rid="${_converse.omemo_store.get('device_id')}"]`, encrypted).pop();
if (key) {
const header = encrypted.querySelector('header');
attrs['is_encrypted'] = true;
attrs['encrypted'] = {
'device_id': header.getAttribute('sid'),
'iv': header.querySelector('iv').textContent,
'key': key.textContent,
'payload': encrypted.querySelector('payload')?.textContent || null,
'prekey': ['true', '1'].includes(key.getAttribute('prekey'))
}
// Returns a promise
return chatbox.decrypt(attrs);
} else {
return attrs;
}
}
/**
* The stanza utils object. Contains utility functions related to stanza
* processing.
......@@ -168,73 +259,6 @@ const stanza_utils = {
});
},
getSenderAttributes (stanza, chatbox, _converse) {
if (u.isChatRoom(chatbox)) {
const from = stanza.getAttribute('from');
const nick = Strophe.unescapeNode(Strophe.getResourceFromJid(from));
return {
'from': from,
'from_muc': Strophe.getBareJidFromJid(from),
'nick': nick,
'sender': nick === chatbox.get('nick') ? 'me': 'them',
'received': (new Date()).toISOString(),
}
} else {
const from = Strophe.getBareJidFromJid(stanza.getAttribute('from'));
if (from === _converse.bare_jid) {
return {
from,
'sender': 'me',
'fullname': _converse.xmppstatus.get('fullname')
}
} else {
return {
from,
'sender': 'them',
'fullname': chatbox.get('fullname')
}
}
}
},
getSpoilerAttributes (stanza) {
const spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, stanza).pop();
return {
'is_spoiler': !!spoiler,
'spoiler_hint': spoiler?.textContent
}
},
getOutOfBandAttributes (stanza) {
const xform = sizzle(`x[xmlns="${Strophe.NS.OUTOFBAND}"]`, stanza).pop();
if (xform) {
return {
'oob_url': xform.querySelector('url')?.textContent,
'oob_desc': xform.querySelector('desc')?.textContent
}
}
return {};
},
getCorrectionAttributes (stanza, original_stanza) {
const el = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop();
if (el) {
const replaced_id = el.getAttribute('id');
const msgid = replaced_id;
if (replaced_id) {
const delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop();
const time = delay ? dayjs(delay.getAttribute('stamp')).toISOString() : (new Date()).toISOString();
return {
msgid,
replaced_id,
'edited': time
}
}
}
return {};
},
getErrorMessage (stanza, is_muc, _converse) {
const { __ } = _converse;
if (is_muc) {
......@@ -292,7 +316,7 @@ const stanza_utils = {
* @param { _converse } _converse
* @returns { Object }
*/
parseMessage (stanza, original_stanza, chatbox, _converse) {
async parseMessage (stanza, original_stanza, chatbox, _converse) {
const is_muc = u.isChatRoom(chatbox);
let attrs = Object.assign(
stanza_utils.getStanzaIDs(stanza, original_stanza),
......@@ -316,11 +340,12 @@ const stanza_utils = {
'type': stanza.getAttribute('type')
},
attrs,
stanza_utils.getSenderAttributes(stanza, chatbox, _converse),
stanza_utils.getOutOfBandAttributes(stanza),
stanza_utils.getSpoilerAttributes(stanza),
stanza_utils.getCorrectionAttributes(stanza, original_stanza)
getSenderAttributes(stanza, chatbox, _converse),
getOutOfBandAttributes(stanza),
getSpoilerAttributes(stanza),
getCorrectionAttributes(stanza, original_stanza),
)
attrs = await getEncryptionAttributes(stanza, original_stanza, attrs, chatbox, _converse)
// We prefer to use one of the XEP-0359 unique and stable stanza IDs
// as the Model id, to avoid duplicates.
attrs['id'] = attrs['origin_id'] || attrs[`stanza_id ${(attrs.from_muc || attrs.from)}`] || u.getUniqueId();
......
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