From d1176a5b2bb781e4c7bddd6878c413d134d2e04a Mon Sep 17 00:00:00 2001 From: Hannu Hartikainen Date: Fri, 27 Nov 2015 17:58:07 +0200 Subject: [PATCH] disallow nested links in DOMfilter (fixes #680) --- js/filters.js | 12 +++++++++++- test/unit/filters.js | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/js/filters.js b/js/filters.js index 71ecee9..70f9341 100644 --- a/js/filters.js +++ b/js/filters.js @@ -61,10 +61,15 @@ weechat.filter('inlinecolour', function() { // apply a filter to an HTML string's text nodes, and do so with not exceedingly terrible performance weechat.filter('DOMfilter', ['$filter', '$sce', function($filter, $sce) { + // To prevent nested anchors, we need to know if a filter is going to create them. + // Here's a list of names. See #681 for more information. + var filtersThatCreateAnchors = ['irclinky']; + return function(text, filter) { if (!text || !filter) { return text; } + var createsAnchor = filtersThatCreateAnchors.indexOf(filter) > -1; var escape_html = function(text) { // First, escape entities to prevent escaping issues because it's a bad idea @@ -92,6 +97,7 @@ weechat.filter('DOMfilter', ['$filter', '$sce', function($filter, $sce) { // 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 could also only add its children but that would probably incur @@ -114,7 +120,11 @@ weechat.filter('DOMfilter', ['$filter', '$sce', function($filter, $sce) { if (node === undefined || node === null) return; node = node.firstChild; while (node) { - var nextNode = process(node); + var nextNode; + // do not recurse inside links if the filter would create a nested link + if (!(createsAnchor && node.tagName === 'A')) { + nextNode = process(node); + } node = (nextNode ? nextNode : node).nextSibling; } }; diff --git a/test/unit/filters.js b/test/unit/filters.js index ca1228e..b1eedec 100644 --- a/test/unit/filters.js +++ b/test/unit/filters.js @@ -22,6 +22,13 @@ describe('Filters', function() { it('should not mess up IRC channels surrounded by HTML entities', inject(function(irclinkyFilter) { expect(irclinkyFilter('<"#foo">')).toEqual('<"\');">#foo">'); })); + + it('should not touch links created by `linky`', inject(function(linkyFilter, DOMfilterFilter) { + var url = 'http://foo.bar/#baz', + link = linkyFilter(url, '_blank'), + result = DOMfilterFilter(link, 'irclinky').$$unwrapTrustedValue(); + expect(result).toEqual(link); + })); }); describe('inlinecolour', function() { @@ -62,4 +69,19 @@ describe('Filters', function() { })); }); + describe('DOMfilter', function() { + it('should run a filter on all text nodes', inject(function(DOMfilterFilter) { + var dom = 'a

bcdefgh

i', + expected = 'A

BCDEFGH

I', + result = DOMfilterFilter(dom, 'uppercase').$$unwrapTrustedValue(); + expect(result).toEqual(expected); + })); + + it('should pass additional arguments to the filter', inject(function(DOMfilterFilter) { + var dom = '1

2

3.14159265', + expected = '1.00

2.00

3.14', + result = DOMfilterFilter(dom, 'number', 2).$$unwrapTrustedValue(); + expect(result).toEqual(expected); + })); + }); });