Merge pull request #623 from glowing-bear/fix-escaping
Properly fix #622 by escaping input into DOMfilter
This commit is contained in:
commit
5df0ce21a2
3 changed files with 18 additions and 24 deletions
|
@ -21,7 +21,7 @@
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-sanitize.min.js"></script>
|
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-sanitize.min.js"></script>
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-touch.min.js"></script>
|
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-touch.min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/emojione/1.3.0/lib/js/emojione.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/emojione/1.4.0/lib/js/emojione.min.js"></script>
|
||||||
<script type="text/javascript" src="3rdparty/inflate.min.js"></script>
|
<script type="text/javascript" src="3rdparty/inflate.min.js"></script>
|
||||||
<script type="text/javascript" src="js/localstorage.js"></script>
|
<script type="text/javascript" src="js/localstorage.js"></script>
|
||||||
<script type="text/javascript" src="js/weechat.js"></script>
|
<script type="text/javascript" src="js/weechat.js"></script>
|
||||||
|
@ -284,7 +284,7 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
|
||||||
<td class="prefix"><a ng-click="addMention(bufferline.prefix)"><span class="hidden-bracket"><</span><span ng-repeat="part in ::bufferline.prefix" ng-class="::part.classes" ng-bind="::part.text|prefixlimit:25"></span><span class="hidden-bracket">></span></a></td><!--
|
<td class="prefix"><a ng-click="addMention(bufferline.prefix)"><span class="hidden-bracket"><</span><span ng-repeat="part in ::bufferline.prefix" ng-class="::part.classes" ng-bind="::part.text|prefixlimit:25"></span><span class="hidden-bracket">></span></a></td><!--
|
||||||
--><td class="message"><!--
|
--><td class="message"><!--
|
||||||
--><div ng-repeat="metadata in ::bufferline.metadata" plugin data="::metadata"></div><!--
|
--><div ng-repeat="metadata in ::bufferline.metadata" plugin data="::metadata"></div><!--
|
||||||
--><span ng-repeat="part in ::bufferline.content" class="text" ng-class="::part.classes.concat(['line-' + part.$$hashKey.replace(':','_')])" ng-bind-html="::part.text | escape | linky:'_blank' | DOMfilter:'irclinky' | DOMfilter:'emojify':settings.enableJSEmoji | DOMfilter:'inlinecolour' | DOMfilter:'mathjax':('.line-' + part.$$hashKey.replace(':','_')):settings.enableMathjax"></span>
|
--><span ng-repeat="part in ::bufferline.content" class="text" ng-class="::part.classes.concat(['line-' + part.$$hashKey.replace(':','_')])" ng-bind-html="::part.text | linky:'_blank' | DOMfilter:'irclinky' | DOMfilter:'emojify':settings.enableJSEmoji | DOMfilter:'inlinecolour' | DOMfilter:'mathjax':('.line-' + part.$$hashKey.replace(':','_')):settings.enableMathjax"></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="readmarker" ng-if="activeBuffer().lastSeen==$index">
|
<tr class="readmarker" ng-if="activeBuffer().lastSeen==$index">
|
||||||
|
|
|
@ -30,13 +30,6 @@ weechat.filter('irclinky', ['$filter', function($filter) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, escape entities to prevent escaping issues because it's a bad idea
|
|
||||||
// to parse/modify HTML with regexes, which we do a couple of lines down...
|
|
||||||
var entities = {"<": "<", ">": ">", '"': '"', "'": ''', "&": "&", "/": '/'};
|
|
||||||
text = text.replace(/[<>"'&\/]/g, function (char) {
|
|
||||||
return entities[char];
|
|
||||||
});
|
|
||||||
|
|
||||||
// This regex in no way matches all IRC channel names (they could also begin with &, + or an
|
// This regex in no way matches all IRC channel names (they could also begin with &, + or an
|
||||||
// exclamation mark followed by 5 alphanumeric characters, and are bounded in length by 50).
|
// exclamation mark followed by 5 alphanumeric characters, and are bounded in length by 50).
|
||||||
// However, it matches all *common* IRC channels while trying to minimise false positives.
|
// However, it matches all *common* IRC channels while trying to minimise false positives.
|
||||||
|
@ -73,6 +66,15 @@ weechat.filter('DOMfilter', ['$filter', '$sce', function($filter, $sce) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var escape_html = function(text) {
|
||||||
|
// First, escape entities to prevent escaping issues because it's a bad idea
|
||||||
|
// to parse/modify HTML with regexes, which we do a couple of lines down...
|
||||||
|
var entities = {"<": "<", ">": ">", '"': '"', "'": ''', "&": "&", "/": '/'};
|
||||||
|
return text.replace(/[<>"'&\/]/g, function (char) {
|
||||||
|
return entities[char];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// hacky way to pass extra arguments without using .apply, which
|
// hacky way to pass extra arguments without using .apply, which
|
||||||
// would require assembling an argument array. PERFORMANCE!!!
|
// would require assembling an argument array. PERFORMANCE!!!
|
||||||
var extraArgument = (arguments.length > 2) ? arguments[2] : null;
|
var extraArgument = (arguments.length > 2) ? arguments[2] : null;
|
||||||
|
@ -85,8 +87,12 @@ weechat.filter('DOMfilter', ['$filter', '$sce', function($filter, $sce) {
|
||||||
// Recursive DOM-walking function applying the filter to the text nodes
|
// Recursive DOM-walking function applying the filter to the text nodes
|
||||||
var process = function(node) {
|
var process = function(node) {
|
||||||
if (node.nodeType === 3) { // text node
|
if (node.nodeType === 3) { // text node
|
||||||
var value = filterFunction(node.nodeValue, extraArgument, thirdArgument);
|
// apply the filter to *escaped* HTML, and only commit changes if
|
||||||
if (value !== node.nodeValue) {
|
// it changed the escaped value. This is because setting the result
|
||||||
|
// as innerHTML causes it to be unescaped.
|
||||||
|
var input = escape_html(node.nodeValue);
|
||||||
|
var value = filterFunction(input, extraArgument, thirdArgument);
|
||||||
|
if (value !== input) {
|
||||||
// we changed something. create a new node to replace the current one
|
// we changed something. create a new node to replace the current one
|
||||||
// we could also only add its children but that would probably incur
|
// we could also only add its children but that would probably incur
|
||||||
// more overhead than it would gain us
|
// more overhead than it would gain us
|
||||||
|
@ -141,18 +147,6 @@ weechat.filter('getBufferQuickKeys', function () {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
weechat.filter('escape', ['$sanitize', function($sanitize) {
|
|
||||||
return function(text) {
|
|
||||||
// manual escaping because ng-sanitize is shit
|
|
||||||
return text
|
|
||||||
.replace(/&/g, "&")
|
|
||||||
.replace(/</g, "<")
|
|
||||||
.replace(/>/g, ">")
|
|
||||||
.replace(/"/g, """)
|
|
||||||
.replace(/'/g, "'");
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
|
|
||||||
// Emojifis the string using https://github.com/Ranks/emojione
|
// Emojifis the string using https://github.com/Ranks/emojione
|
||||||
weechat.filter('emojify', function() {
|
weechat.filter('emojify', function() {
|
||||||
return function(text, enable_JS_Emoji) {
|
return function(text, enable_JS_Emoji) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe('Filters', function() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not mess up IRC channels surrounded by HTML entities', inject(function(irclinkyFilter) {
|
it('should not mess up IRC channels surrounded by HTML entities', inject(function(irclinkyFilter) {
|
||||||
expect(irclinkyFilter('<"#foo">')).toEqual('<"<a href="#" onclick="var $scope = angular.element(event.target).scope(); $scope.openBuffer(\'#foo">\'); $scope.$apply();">#foo"></a>');
|
expect(irclinkyFilter('<"#foo">')).toEqual('<"<a href="#" onclick="var $scope = angular.element(event.target).scope(); $scope.openBuffer(\'#foo">\'); $scope.$apply();">#foo"></a>');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue