diff --git a/spec/chatbox.js b/spec/chatbox.js index 273c15778..e4a1b24b3 100644 --- a/spec/chatbox.js +++ b/spec/chatbox.js @@ -911,7 +911,7 @@ describe("Chatboxes", function () { describe("Special Messages", function () { - fit("'/clear' can be used to clear messages in a conversation", + it("'/clear' can be used to clear messages in a conversation", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { await mock.waitForRoster(_converse, 'current'); diff --git a/spec/unfurls.js b/spec/unfurls.js index 512169cd4..8d4b7741e 100644 --- a/spec/unfurls.js +++ b/spec/unfurls.js @@ -89,7 +89,7 @@ describe("A Groupchat Message", function () { metadata_stanza = u.toStanza(` - + @@ -101,4 +101,96 @@ describe("A Groupchat Message", function () { await u.waitUntil(() => view.querySelectorAll('converse-message-unfurl').length === 2); done(); })); + + it("will not render an unfurl based on a URL not in the original message", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { + const nick = 'romeo'; + const muc_jid = 'lounge@montague.lit'; + await mock.openAndEnterChatRoom(_converse, muc_jid, nick); + const view = _converse.api.chatviews.get(muc_jid); + + const message_stanza = u.toStanza(` + + https://www.youtube.com/watch?v=dQw4w9WgXcQ + + + + + `); + _converse.connection._dataRecv(mock.createRequest(message_stanza)); + const el = await u.waitUntil(() => view.querySelector('.chat-msg__text')); + expect(el.textContent).toBe('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); + + spyOn(view.model, 'handleMetadataFastening').and.callThrough(); + + const metadata_stanza = u.toStanza(` + + + + + + + + + + + + + + + + + `); + _converse.connection._dataRecv(mock.createRequest(metadata_stanza)); + + await u.waitUntil(() => view.model.handleMetadataFastening.calls.count()); + expect(view.model.handleMetadataFastening.calls.first().returnValue).toBe(false); + expect(view.querySelector('converse-message-unfurl')).toBe(null); + done(); + })); + + it("will not render an unfurl received from a MUC participant", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { + const nick = 'romeo'; + const muc_jid = 'lounge@montague.lit'; + await mock.openAndEnterChatRoom(_converse, muc_jid, nick); + const view = _converse.api.chatviews.get(muc_jid); + + const message_stanza = u.toStanza(` + + https://www.youtube.com/watch?v=dQw4w9WgXcQ + + + + + `); + _converse.connection._dataRecv(mock.createRequest(message_stanza)); + const el = await u.waitUntil(() => view.querySelector('.chat-msg__text')); + expect(el.textContent).toBe('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); + + spyOn(view.model, 'handleMetadataFastening').and.callThrough(); + + const metadata_stanza = u.toStanza(` + + + + + + + + + + + + + + + + + `); + _converse.connection._dataRecv(mock.createRequest(metadata_stanza)); + + await u.waitUntil(() => view.model.handleMetadataFastening.calls.count()); + expect(view.model.handleMetadataFastening.calls.first().returnValue).toBe(false); + expect(view.querySelector('converse-message-unfurl')).toBe(null); + done(); + })); }); diff --git a/src/headless/plugins/chat/model.js b/src/headless/plugins/chat/model.js index 92b32e648..bfbcc05d2 100644 --- a/src/headless/plugins/chat/model.js +++ b/src/headless/plugins/chat/model.js @@ -13,24 +13,6 @@ const { Strophe, $msg } = converse.env; const u = converse.env.utils; -const METADATA_ATTRIBUTES = [ - "og:description", - "og:image", - "og:image:height", - "og:image:width", - "og:site_name", - "og:title", - "og:type", - "og:url", - "og:video:height", - "og:video:secure_url", - "og:video:tag", - "og:video:type", - "og:video:url", - "og:video:width" -]; - - /** * Represents an open/ongoing chat conversation. * @@ -488,20 +470,6 @@ const ChatBox = ModelWithContact.extend({ return false; }, - handleMetadataFastening (attrs) { - if (attrs.ogp_for_id) { - const message = this.messages.findWhere({'origin_id': attrs.ogp_for_id}); - if (message) { - const list = [...(message.get('ogp_metadata') || []), pick(attrs, METADATA_ATTRIBUTES)]; - message.save('ogp_metadata', list); - return true; - } else { - return false; - } - } - return false; - }, - /** * Determines whether the passed in message attributes represent a * message which corrects a previously received message, or an diff --git a/src/headless/plugins/muc/muc.js b/src/headless/plugins/muc/muc.js index 3b2f972e5..7a2d54ced 100644 --- a/src/headless/plugins/muc/muc.js +++ b/src/headless/plugins/muc/muc.js @@ -16,6 +16,23 @@ const ADMIN_COMMANDS = ['admin', 'ban', 'deop', 'destroy', 'member', 'op', 'revo const MODERATOR_COMMANDS = ['kick', 'mute', 'voice', 'modtools']; const VISITOR_COMMANDS = ['nick']; +const METADATA_ATTRIBUTES = [ + "og:description", + "og:image", + "og:image:height", + "og:image:width", + "og:site_name", + "og:title", + "og:type", + "og:url", + "og:video:height", + "og:video:secure_url", + "og:video:tag", + "og:video:type", + "og:video:url", + "og:video:width" +]; + const ACTION_INFO_CODES = ['301', '303', '333', '307', '321', '322']; const MUCSession = Model.extend({ @@ -2104,6 +2121,29 @@ const ChatRoomMixin = { window.setTimeout(() => this.removeNotification(actor, state), 10000); }, + handleMetadataFastening (attrs) { + if (attrs.ogp_for_id) { + if (attrs.from !== this.get('jid')) { + // For now we only allow metadata from the MUC itself and not + // from individual users who are deemed less trustworthy. + return false; + } + const message = this.messages.findWhere({'origin_id': attrs.ogp_for_id}); + if (message) { + if (!attrs['og:url'] || !message.get('body').includes(attrs['og:url'])) { + // For security purposes, we don't show metadata for a URL not actually + // included in the original message + log.warn("Not showing OGP data because we can't find the relevant URL in the original message"); + return false; + } + const list = [...(message.get('ogp_metadata') || []), pick(attrs, METADATA_ATTRIBUTES)]; + message.save('ogp_metadata', list); + return true; + } + } + return false; + }, + /** * Handler for all MUC messages sent to this groupchat. This method * shouldn't be called directly, instead {@link _converse.ChatRoom#queueMessage}