Commit 284e8847 authored by JC Brand's avatar JC Brand

Add `js-xss` and use it to sanitize message HTML

parent b85b29bb
...@@ -1582,6 +1582,7 @@ ...@@ -1582,6 +1582,7 @@
font-style: italic; } font-style: italic; }
#converse-embedded-chat .chatbox .chat-body .chat-message, #converse-embedded-chat .chatbox .chat-body .chat-message,
#conversejs .chatbox .chat-body .chat-message { #conversejs .chatbox .chat-body .chat-message {
overflow: auto;
margin: 0.3em; } margin: 0.3em; }
#converse-embedded-chat .chatbox .chat-body .chat-message span.chat-msg-author, #converse-embedded-chat .chatbox .chat-body .chat-message span.chat-msg-author,
#conversejs .chatbox .chat-body .chat-message span.chat-msg-author { #conversejs .chatbox .chat-body .chat-message span.chat-msg-author {
......
...@@ -1628,6 +1628,7 @@ body { ...@@ -1628,6 +1628,7 @@ body {
font-style: italic; } font-style: italic; }
#converse-embedded-chat .chatbox .chat-body .chat-message, #converse-embedded-chat .chatbox .chat-body .chat-message,
#conversejs .chatbox .chat-body .chat-message { #conversejs .chatbox .chat-body .chat-message {
overflow: auto;
margin: 0.3em; } margin: 0.3em; }
#converse-embedded-chat .chatbox .chat-body .chat-message span.chat-msg-author, #converse-embedded-chat .chatbox .chat-body .chat-message span.chat-msg-author,
#conversejs .chatbox .chat-body .chat-message span.chat-msg-author { #conversejs .chatbox .chat-body .chat-message span.chat-msg-author {
......
...@@ -1118,6 +1118,12 @@ ...@@ -1118,6 +1118,12 @@
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
"dev": true "dev": true
}, },
"cssfilter": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.9.tgz",
"integrity": "sha1-j1zrOqvXaNtTnaRYKyFS1j73cV4=",
"dev": true
},
"currently-unhandled": { "currently-unhandled": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
...@@ -6908,6 +6914,12 @@ ...@@ -6908,6 +6914,12 @@
"integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=", "integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=",
"dev": true "dev": true
}, },
"xss": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/xss/-/xss-0.3.3.tgz",
"integrity": "sha1-oBQ2De4QMXMx+edCWBQfftA/x4Q=",
"dev": true
},
"xtend": { "xtend": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
......
...@@ -78,7 +78,8 @@ ...@@ -78,7 +78,8 @@
"strophejs-plugin-vcard": "0.0.1", "strophejs-plugin-vcard": "0.0.1",
"text": "requirejs/text#2.0.15", "text": "requirejs/text#2.0.15",
"uglify-es": "^3.0.24", "uglify-es": "^3.0.24",
"wait-until-promise": "^1.0.0" "wait-until-promise": "^1.0.0",
"xss": "^0.3.3"
}, },
"dependencies": {} "dependencies": {}
} }
...@@ -156,6 +156,7 @@ ...@@ -156,6 +156,7 @@
font-style: italic; font-style: italic;
} }
.chat-message { .chat-message {
overflow: auto; // Ensures that content stays inside
margin: 0.3em; margin: 0.3em;
span { span {
&.chat-msg-author { &.chat-msg-author {
......
...@@ -19,15 +19,18 @@ require.config({ ...@@ -19,15 +19,18 @@ require.config({
"awesomplete": "node_modules/awesomplete-avoid-xss/awesomplete", "awesomplete": "node_modules/awesomplete-avoid-xss/awesomplete",
"babel": "node_modules/requirejs-babel/babel-5.8.34.min", "babel": "node_modules/requirejs-babel/babel-5.8.34.min",
"backbone": "node_modules/backbone/backbone", "backbone": "node_modules/backbone/backbone",
"backbone.noconflict": "src/backbone.noconflict",
"backbone.browserStorage": "node_modules/backbone.browserStorage/backbone.browserStorage", "backbone.browserStorage": "node_modules/backbone.browserStorage/backbone.browserStorage",
"backbone.noconflict": "src/backbone.noconflict",
"backbone.overview": "node_modules/backbone.overview/backbone.overview", "backbone.overview": "node_modules/backbone.overview/backbone.overview",
"emojione": "node_modules/emojione/lib/js/emojione", "emojione": "node_modules/emojione/lib/js/emojione",
"eventemitter": "node_modules/otr/build/dep/eventemitter",
"es6-promise": "node_modules/es6-promise/dist/es6-promise.auto", "es6-promise": "node_modules/es6-promise/dist/es6-promise.auto",
"eventemitter": "node_modules/otr/build/dep/eventemitter",
"jquery": "node_modules/jquery/dist/jquery", "jquery": "node_modules/jquery/dist/jquery",
"jquery.noconflict": "src/jquery.noconflict",
"jquery.browser": "node_modules/jquery.browser/dist/jquery.browser", "jquery.browser": "node_modules/jquery.browser/dist/jquery.browser",
"jquery.noconflict": "src/jquery.noconflict",
"lodash": "node_modules/lodash/lodash",
"lodash.converter": "3rdparty/lodash.fp",
"lodash.noconflict": "src/lodash.noconflict",
"pluggable": "node_modules/pluggable.js/dist/pluggable", "pluggable": "node_modules/pluggable.js/dist/pluggable",
"polyfill": "src/polyfill", "polyfill": "src/polyfill",
"sizzle": "node_modules/jquery/sizzle/dist/sizzle", "sizzle": "node_modules/jquery/sizzle/dist/sizzle",
...@@ -39,11 +42,10 @@ require.config({ ...@@ -39,11 +42,10 @@ require.config({
"text": "node_modules/text/text", "text": "node_modules/text/text",
"tpl": "node_modules/lodash-template-loader/loader", "tpl": "node_modules/lodash-template-loader/loader",
"typeahead": "components/typeahead.js/index", "typeahead": "components/typeahead.js/index",
"lodash": "node_modules/lodash/lodash",
"lodash.converter": "3rdparty/lodash.fp",
"lodash.noconflict": "src/lodash.noconflict",
"underscore": "src/underscore-shim", "underscore": "src/underscore-shim",
"utils": "src/utils", "utils": "src/utils",
"xss.noconflict": "src/xss.noconflict",
"xss": "node_modules/xss/dist/xss",
// Converse // Converse
"converse": "src/converse", "converse": "src/converse",
...@@ -139,5 +141,13 @@ require.config({ ...@@ -139,5 +141,13 @@ require.config({
shim: { shim: {
'awesomplete': { exports: 'Awesomplete'}, 'awesomplete': { exports: 'Awesomplete'},
'emojione': { exports: 'emojione'}, 'emojione': { exports: 'emojione'},
'xss': {
init: function (xss_noconflict) {
return {
filterXSS: window.filterXSS,
filterCSS: window.filterCSS
}
}
}
} }
}); });
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"jquery.noconflict", "jquery.noconflict",
"converse-core", "converse-core",
"emojione", "emojione",
"xss",
"tpl!chatbox", "tpl!chatbox",
"tpl!new_day", "tpl!new_day",
"tpl!action", "tpl!action",
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
$, $,
converse, converse,
emojione, emojione,
xss,
tpl_chatbox, tpl_chatbox,
tpl_new_day, tpl_new_day,
tpl_action, tpl_action,
...@@ -427,7 +429,9 @@ ...@@ -427,7 +429,9 @@
if (_converse.visible_toolbar_buttons.emoji) { if (_converse.visible_toolbar_buttons.emoji) {
text = utils.addEmoji(_converse, emojione, text); text = utils.addEmoji(_converse, emojione, text);
} }
$msg.find('.chat-msg-content').first().text(text).addHyperlinks(); const msg_content = $msg[0].querySelector('.chat-msg-content');
msg_content.innerHTML = xss.filterXSS(text, {'whiteList': {}});
utils.addHyperlinks(msg_content);
return $msg; return $msg;
}, },
......
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
logger.warn(`WARNING: ${txt}`); logger.warn(`WARNING: ${txt}`);
} else if (level === Strophe.LogLevel.FATAL) { } else if (level === Strophe.LogLevel.FATAL) {
if (_converse.debug) { if (_converse.debug) {
logger.trace(`FATAL: ${txt}`); logger.error(`FATAL: ${txt}`);
} else { } else {
logger.error(`FATAL: ${txt}`); logger.error(`FATAL: ${txt}`);
} }
......
...@@ -101,34 +101,6 @@ ...@@ -101,34 +101,6 @@
el.innerHTML = html; el.innerHTML = html;
}, 500); }, 500);
$.fn.addHyperlinks = function () {
if (this.length > 0) {
this.each(function (i, obj) {
var prot, escaped_url;
var x = obj.innerHTML;
var list = x.match(/\b(https?:\/\/|www\.|https?:\/\/www\.)[^\s<]{2,200}\b/g );
if (list) {
for (i=0; i<list.length; i++) {
prot = list[i].indexOf('http://') === 0 || list[i].indexOf('https://') === 0 ? '' : 'http://';
escaped_url = encodeURI(decodeURI(list[i])).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
x = x.replace(list[i], '<a target="_blank" rel="noopener" href="' + prot + escaped_url + '">'+ list[i] + '</a>' );
}
}
obj.innerHTML = x;
_.forEach(list, function (url) {
isImage(unescapeHTML(url)).then(function (img) {
img.className = 'chat-image';
var a = obj.querySelector('a');
if (!_.isNull(a)) {
throttledHTML(a, img.outerHTML);
}
});
});
});
}
return this;
};
function calculateSlideStep (height) { function calculateSlideStep (height) {
if (height > 100) { if (height > 100) {
return 10; return 10;
...@@ -185,6 +157,27 @@ ...@@ -185,6 +157,27 @@
} }
}; };
utils.addHyperlinks = function (obj) {
var x = obj.innerHTML;
var list = x.match(/\b(https?:\/\/|www\.|https?:\/\/www\.)[^\s<]{2,200}\b/g ) || [];
_.each(list, (match) => {
const prot = match.indexOf('http://') === 0 || match.indexOf('https://') === 0 ? '' : 'http://';
const url = prot + encodeURI(decodeURI(match)).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
x = x.replace(match, '<a target="_blank" rel="noopener" href="' + url + '">'+ match + '</a>' );
});
obj.innerHTML = x;
_.forEach(list, function (url) {
isImage(unescapeHTML(url)).then(function (img) {
img.className = 'chat-image';
var a = obj.querySelector('a');
if (!_.isNull(a)) {
throttledHTML(a, img.outerHTML);
}
});
});
return obj;
};
utils.slideInAllElements = function (elements) { utils.slideInAllElements = function (elements) {
return Promise.all( return Promise.all(
_.map( _.map(
......
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