Удалять пользовательские сообщения чата, но визуализировать ссылки
Пользователь вводит сообщения чата, которые отображаются непосредственно на странице с помощью шаблонов Mustache. Очевидно, что HTML должен быть экранирован для предотвращения вставки HTML, но затем ссылки должны отображаться как <a href='...'>
.
Существуют разные подходы, которые я пытался использовать {{{ ... }}}
, чтобы вернуть неэкранированный HTML-контент, что означает, что ссылка будет визуализирована, и мне нужно позаботиться о том, чтобы HTML сбежал. Есть ли безопасный способ сделать это, не полагаясь на наполовину испеченное решение, которое я пишу себе?
jQuery.text()
было бы здорово, но я думаю, он снова отобразит <a>
как текст.
Что еще я могу сделать здесь?
Ответы
Ответ 1
Если вы не хотите писать собственное решение для экранирования или разбора, есть плагин jQuery для обработки ссылок под названием Linkify. Вы могли бы просто избегать сообщений, а затем анализировать их на стороне клиента.
Пример того, как это работает:
var text = "<div>Test<br>Test<br>Test http://stackoverflow.com</div>";
$('div').text(text);
// Before: <div>Test<br>Test<br>Test http://stackoverflow.com</div>
$('div').linkify();
// After: lt;div>Test<br>Test<br>Test <a href="http://stackoverflow.com" class="linkified" target="_blank">http://stackoverflow.com</a></div>
Ответ 2
Просто идея: вы можете создать свою собственную функцию экранирования
escape : function () {
return function(val, render) {
var $s = $(val);
var $elements = $s.find("*").not("a"); //add other white-listed elements seperated by comma
for (var i = $elements.length - 1; i >= 0; i--) {
var e = $elements[i];
$(e).replaceWith(e.innerHTML);
}
return $s.html();
}
}
Вы можете вызвать функцию
{{#escape}}{{{YOUR_TEXT}}}{{/escape}}
Я не тестировал это. Для этого решения требуется jQuery. Приведенный выше код основан на этом решении: fooobar.com/questions/57733/...
Ответ 3
попробуйте вставить сначала в .text(), а затем используйте regexp для визуализации ссылки с .html(). Здесь вы можете увидеть пример ванили:
var a="see formula a<b>c in http://test.com or https://x.com?p=3";
var hold=document.createElement('div');
hold.textContent=a;
hold.innerHTML=hold.innerHTML.replace(
/(https?:\/\/[-$A-Za-z0-9%_?&.~+\/=]+)/g,
'<a href="$1">$1</a>'
);
window.addEventListener('load',function(){
document.body.appendChild(hold);
});
Для более явного regexp вы можете увидеть здесь
Ответ 4
Если вы закончите трафик регулярного выражения, следующий фильтр и регулярное выражение были наиболее агрессивными, которые я нашел для поиска всех типов URL-адресов, которые будут пытаться ввести ваши пользователи.
Здесь существует регулярное выражение: http://regexr.com/3bjk9
(function () {
'use strict';
angular
.module('core.filters')
.filter('urlToA', urlToA);
// --------------------
function urlToA () {
return function (string, noClick) {
var urlPattern = /((?:(http|https|Http|Https|rtsp|Rtsp):\/\/(?:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,64}(?:\:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,25})?\@)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\:\d{1,5})?)(\/(?:(?:[a-zA-Z0-9\;\/\?\:\@\&\=\#\~\-\.\+\!\*\'\(\)\,\_])|(?:\%[a-fA-F0-9]{2}))*)?(?:\b|$)/gi; // jshint ignore:line
return string ? string.replace(urlPattern, replace) : string;
function replace (url) {
var httpUrl = url.indexOf('http') === -1 ? 'http://' + url : url;
if (noClick) {
return '<a>' + url + '</a>';
} else {
return '<a href="' + httpUrl + '">' + url + '</a>';
}
}
};
}
})();