Commit 35e97c23 authored by JC Brand's avatar JC Brand

Ignore MAM `chat` messages not sent from yourself

parent 0af9bc8f
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
different path, you'll need to set `publicPath` in `webpack.config.js` to different path, you'll need to set `publicPath` in `webpack.config.js` to
your preferred path and then rebuild all assets (e.g. `make dist`). your preferred path and then rebuild all assets (e.g. `make dist`).
- Use `listenTo` to avoid memory leaks when views get removed. - Use `listenTo` to avoid memory leaks when views get removed.
- SECURITY FIX: Ignore MAM `chat` messages not sent from yourself
- #1692 Bugfix: `TypeError: oldest_message is undefined` - #1692 Bugfix: `TypeError: oldest_message is undefined`
- #1704 SECURITY FIX: Impersonation by misusage of groupchat carbons - #1704 SECURITY FIX: Impersonation by misusage of groupchat carbons
- #1705 Bugfix: `this.roomspanel` is `undefined` after hibernating - #1705 Bugfix: `this.roomspanel` is `undefined` after hibernating
## 5.0.1 (2019-08-14) ## 5.0.1 (2019-08-14)
- Add a new GUI for moderator actions. You can trigger it by entering `/modtools` in a MUC. - Add a new GUI for moderator actions. You can trigger it by entering `/modtools` in a MUC.
......
...@@ -210,6 +210,62 @@ ...@@ -210,6 +210,62 @@
describe("when recieved", function () { describe("when recieved", function () {
it("is discarded if it doesn't come from the right sender",
mock.initConverse(
null, ['discoInitialized'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
const sent_IQs = _converse.connection.IQ_stanzas;
const stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.MAM}"]`)).pop());
const queryid = stanza.querySelector('query').getAttribute('queryid');
let msg = $msg({'id': _converse.connection.getUniqueId(), 'from': 'impersonator@capulet.lit', 'to': _converse.bare_jid})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id': _converse.connection.getUniqueId()})
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
.c('message', {
'xmlns':'jabber:client',
'to': _converse.bare_jid,
'id': _converse.connection.getUniqueId(),
'from': contact_jid,
'type':'chat'
}).c('body').t("Meet me at the dance");
spyOn(_converse, 'log');
_converse.connection._dataRecv(test_utils.createRequest(msg));
expect(_converse.log).toHaveBeenCalledWith(`Ignoring alleged MAM message from ${msg.nodeTree.getAttribute('from')}`, Strophe.LogLevel.WARN);
msg = $msg({'id': _converse.connection.getUniqueId(), 'to': _converse.bare_jid})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id': _converse.connection.getUniqueId()})
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
.c('message', {
'xmlns':'jabber:client',
'to': _converse.bare_jid,
'id': _converse.connection.getUniqueId(),
'from': contact_jid,
'type':'chat'
}).c('body').t("Thrice the brinded cat hath mew'd.");
_converse.connection._dataRecv(test_utils.createRequest(msg));
const iq_result = $iq({'type': 'result', 'id': stanza.getAttribute('id')})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('first', {'index': '0'}).t('23452-4534-1').up()
.c('last').t('09af3-cc343-b409f').up()
.c('count').t('16');
_converse.connection._dataRecv(test_utils.createRequest(iq_result));
const view = _converse.chatboxviews.get(contact_jid);
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('message')).toBe("Thrice the brinded cat hath mew'd.");
done();
}));
it("updates the is_archived value of an already cached version", it("updates the is_archived value of an already cached version",
mock.initConverse( mock.initConverse(
null, ['discoInitialized'], {}, null, ['discoInitialized'], {},
......
...@@ -310,7 +310,6 @@ ...@@ -310,7 +310,6 @@
let message, msg; let message, msg;
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length) await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
spyOn(_converse, 'log');
spyOn(_converse.chatboxes, 'getChatBox').and.callThrough(); spyOn(_converse.chatboxes, 'getChatBox').and.callThrough();
_converse.filter_by_resource = true; _converse.filter_by_resource = true;
...@@ -531,7 +530,6 @@ ...@@ -531,7 +530,6 @@
test_utils.openControlBox(); test_utils.openControlBox();
// Send a message from a different resource // Send a message from a different resource
spyOn(_converse, 'log');
const msgtext = 'This is a carbon message'; const msgtext = 'This is a carbon message';
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msg = $msg({ const msg = $msg({
...@@ -584,7 +582,6 @@ ...@@ -584,7 +582,6 @@
test_utils.openControlBox(); test_utils.openControlBox();
// Send a message from a different resource // Send a message from a different resource
spyOn(_converse, 'log');
const msgtext = 'This is a sent carbon message'; const msgtext = 'This is a sent carbon message';
const recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msg = $msg({ const msg = $msg({
...@@ -622,9 +619,9 @@ ...@@ -622,9 +619,9 @@
})); }));
it("will be discarded if it's a malicious message meant to look like a carbon copy", it("will be discarded if it's a malicious message meant to look like a carbon copy",
mock.initConverse( mock.initConverse(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
async function (done, _converse) { async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current'); await test_utils.waitForRoster(_converse, 'current');
test_utils.openControlBox(); test_utils.openControlBox();
...@@ -638,7 +635,6 @@ ...@@ -638,7 +635,6 @@
* </received> * </received>
* </message> * </message>
*/ */
spyOn(_converse, 'log');
const msgtext = 'Please come to Creepy Valley tonight, alone!'; const msgtext = 'Please come to Creepy Valley tonight, alone!';
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const impersonated_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const impersonated_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
......
...@@ -1062,6 +1062,13 @@ converse.plugins.add('converse-chatboxes', { ...@@ -1062,6 +1062,13 @@ converse.plugins.add('converse-chatboxes', {
registerMessageHandler () { registerMessageHandler () {
_converse.connection.addHandler(stanza => { _converse.connection.addHandler(stanza => {
if (sizzle(`message > result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop()) {
// MAM messages are handled in converse-mam.
// We shouldn't get MAM messages here because
// they shouldn't have a `type` attribute.
_converse.log(`Received a MAM message with type "chat".`, Strophe.LogLevel.WARN);
return true;
}
this.onMessage(stanza); this.onMessage(stanza);
return true; return true;
}, null, 'message', 'chat'); }, null, 'message', 'chat');
......
...@@ -500,14 +500,22 @@ converse.plugins.add('converse-mam', { ...@@ -500,14 +500,22 @@ converse.plugins.add('converse-mam', {
} }
const messages = []; const messages = [];
const message_handler = _converse.connection.addHandler(message => { const message_handler = _converse.connection.addHandler(stanza => {
if (options.groupchat && message.getAttribute('from') !== options['with']) { const result = sizzle(`message > result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
if (result === undefined || result.getAttribute('queryid') !== queryid) {
return true; return true;
} }
const result = message.querySelector('result'); const from = stanza.getAttribute('from') || _converse.bare_jid;
if (result !== null && result.getAttribute('queryid') === queryid) { if (options.groupchat) {
messages.push(message); if (from !== options['with']) {
_converse.log(`Ignoring alleged groupchat MAM message from ${stanza.getAttribute('from')}`, Strophe.LogLevel.WARN);
return true;
}
} else if (from !== _converse.bare_jid) {
_converse.log(`Ignoring alleged MAM message from ${stanza.getAttribute('from')}`, Strophe.LogLevel.WARN);
return true;
} }
messages.push(stanza);
return true; return true;
}, Strophe.NS.MAM); }, Strophe.NS.MAM);
......
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