Add js-xss and use it to sanitize message HTML

This commit is contained in:
JC Brand 2017-07-15 17:33:25 +02:00
parent b85b29bb20
commit 284e884766
9 changed files with 60 additions and 37 deletions

View File

@ -1582,6 +1582,7 @@
font-style: italic; }
#converse-embedded-chat .chatbox .chat-body .chat-message,
#conversejs .chatbox .chat-body .chat-message {
overflow: auto;
margin: 0.3em; }
#converse-embedded-chat .chatbox .chat-body .chat-message span.chat-msg-author,
#conversejs .chatbox .chat-body .chat-message span.chat-msg-author {

View File

@ -1628,6 +1628,7 @@ body {
font-style: italic; }
#converse-embedded-chat .chatbox .chat-body .chat-message,
#conversejs .chatbox .chat-body .chat-message {
overflow: auto;
margin: 0.3em; }
#converse-embedded-chat .chatbox .chat-body .chat-message span.chat-msg-author,
#conversejs .chatbox .chat-body .chat-message span.chat-msg-author {

12
package-lock.json generated
View File

@ -1118,6 +1118,12 @@
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
"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": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@ -6908,6 +6914,12 @@
"integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=",
"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": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",

View File

@ -78,7 +78,8 @@
"strophejs-plugin-vcard": "0.0.1",
"text": "requirejs/text#2.0.15",
"uglify-es": "^3.0.24",
"wait-until-promise": "^1.0.0"
"wait-until-promise": "^1.0.0",
"xss": "^0.3.3"
},
"dependencies": {}
}

View File

@ -156,6 +156,7 @@
font-style: italic;
}
.chat-message {
overflow: auto; // Ensures that content stays inside
margin: 0.3em;
span {
&.chat-msg-author {

View File

@ -19,15 +19,18 @@ require.config({
"awesomplete": "node_modules/awesomplete-avoid-xss/awesomplete",
"babel": "node_modules/requirejs-babel/babel-5.8.34.min",
"backbone": "node_modules/backbone/backbone",
"backbone.noconflict": "src/backbone.noconflict",
"backbone.browserStorage": "node_modules/backbone.browserStorage/backbone.browserStorage",
"backbone.noconflict": "src/backbone.noconflict",
"backbone.overview": "node_modules/backbone.overview/backbone.overview",
"emojione": "node_modules/emojione/lib/js/emojione",
"eventemitter": "node_modules/otr/build/dep/eventemitter",
"es6-promise": "node_modules/es6-promise/dist/es6-promise.auto",
"eventemitter": "node_modules/otr/build/dep/eventemitter",
"jquery": "node_modules/jquery/dist/jquery",
"jquery.noconflict": "src/jquery.noconflict",
"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",
"polyfill": "src/polyfill",
"sizzle": "node_modules/jquery/sizzle/dist/sizzle",
@ -39,11 +42,10 @@ require.config({
"text": "node_modules/text/text",
"tpl": "node_modules/lodash-template-loader/loader",
"typeahead": "components/typeahead.js/index",
"lodash": "node_modules/lodash/lodash",
"lodash.converter": "3rdparty/lodash.fp",
"lodash.noconflict": "src/lodash.noconflict",
"underscore": "src/underscore-shim",
"utils": "src/utils",
"xss.noconflict": "src/xss.noconflict",
"xss": "node_modules/xss/dist/xss",
// Converse
"converse": "src/converse",
@ -139,5 +141,13 @@ require.config({
shim: {
'awesomplete': { exports: 'Awesomplete'},
'emojione': { exports: 'emojione'},
'xss': {
init: function (xss_noconflict) {
return {
filterXSS: window.filterXSS,
filterCSS: window.filterCSS
}
}
}
}
});

View File

@ -11,6 +11,7 @@
"jquery.noconflict",
"converse-core",
"emojione",
"xss",
"tpl!chatbox",
"tpl!new_day",
"tpl!action",
@ -25,6 +26,7 @@
$,
converse,
emojione,
xss,
tpl_chatbox,
tpl_new_day,
tpl_action,
@ -427,7 +429,9 @@
if (_converse.visible_toolbar_buttons.emoji) {
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;
},

View File

@ -136,7 +136,7 @@
logger.warn(`WARNING: ${txt}`);
} else if (level === Strophe.LogLevel.FATAL) {
if (_converse.debug) {
logger.trace(`FATAL: ${txt}`);
logger.error(`FATAL: ${txt}`);
} else {
logger.error(`FATAL: ${txt}`);
}

View File

@ -101,34 +101,6 @@
el.innerHTML = html;
}, 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) {
if (height > 100) {
return 10;
@ -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) {
return Promise.all(
_.map(