Mercurial > p > roundup > code
diff test/test_templating.py @ 6282:d30501bafdfb
issue2551098: markdown links missing rel="noreferer nofollow"
Links generated by all markdown backends are missing the noopener and
nofollow relation that roundup's normal text -> html core adds to
prevent security issues and link spam.
Now rel="nofollow" is added to links generated by markdown2 backends
and rel="nofollow noopener" for mistune and markdown backends.
Markdown2 isn't as programable as the other two backends so I used the
built-in nofollow support. This means that a user that generates a
link that opens in a new window can manpulate the parent window.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sat, 31 Oct 2020 14:51:16 -0400 |
| parents | 6ed5152a92d0 |
| children | 3f7538316724 |
line wrap: on
line diff
--- a/test/test_templating.py Thu Oct 29 23:43:05 2020 -0400 +++ b/test/test_templating.py Sat Oct 31 14:51:16 2020 -0400 @@ -420,6 +420,45 @@ # common markdown test cases class MarkdownTests: + def mangleMarkdown2(self, s): + ''' markdown2's rel=nofollow support on 'a' tags isn't programmable. + So we are using it's builtin nofollow support. Mangle the string + so that it matches the test case. + + turn: <a rel="nofollow" href="foo"> into + <a href="foo" rel="nofollow noopener"> + + Also if it is a mailto url, we don't expect rel="nofollow", + so delete it. + + turn: <a rel="nofollow" href="mailto:foo"> into + <a href="mailto:foo"> + + Also when a title is present it is put in a different place + from markdown, so fix it to normalize. + + turn: + + <a rel="nofollow" href="http://example.com/" title="a title"> + into + <a href="http://example.com/" rel="nofollow noopener" title="a title"> + ''' + if type(self) == Markdown2TestCase and s.find('a rel="nofollow"') != -1: + if s.find('href="mailto:') == -1: + # not a mailto url + if 'rel="nofollow"' in s: + if 'title="' in s: + s = s.replace(' rel="nofollow" ', ' ').replace(' title=', ' rel="nofollow noopener" title=') + else: + s = s.replace(' rel="nofollow" ', ' ').replace('">', '" rel="nofollow noopener">') + + return s + else: + # a mailto url + return s.replace(' rel="nofollow" ', ' ') + return s + + def test_string_markdown(self): p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with <br> *embedded* \u00df')) self.assertEqual(p.markdown().strip(), u2s(u'<p>A string with <br> <em>embedded</em> \u00df</p>')) @@ -437,7 +476,10 @@ html_unescape = HTMLParser().unescape p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A link <cmeerw@example.com>')) - self.assertEqual(html_unescape(p.markdown().strip()), u2s(u'<p>A link <a href="mailto:cmeerw@example.com">cmeerw@example.com</a></p>')) + m = html_unescape(p.markdown().strip()) + m = self.mangleMarkdown2(m) + + self.assertEqual(m, u2s(u'<p>A link <a href="mailto:cmeerw@example.com">cmeerw@example.com</a></p>')) def test_string_markdown_javascript_link(self): # make sure we don't get a "javascript:" link @@ -457,6 +499,7 @@ # Rather than using a different result for each # renderer, look for '<br' and require three of them. m = p.markdown() + print(m) self.assertEqual(3, m.count('<br')) def test_string_markdown_code_block(self): @@ -498,14 +541,23 @@ # so rstrip \n. p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'http://example.com/')) m = p.markdown(hyperlink=1) - self.assertEqual(m.rstrip('\n'), '<p><a href="http://example.com/">http://example.com/</a></p>') + m = self.mangleMarkdown2(m) + print(m) + self.assertEqual(m.rstrip('\n'), '<p><a href="http://example.com/" rel="nofollow noopener">http://example.com/</a></p>') p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'<http://example.com/>')) m = p.markdown(hyperlink=1) - self.assertEqual(m.rstrip('\n'), '<p><a href="http://example.com/">http://example.com/</a></p>') + m = self.mangleMarkdown2(m) + self.assertEqual(m.rstrip('\n'), '<p><a href="http://example.com/" rel="nofollow noopener">http://example.com/</a></p>') + + p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'[label](http://example.com/ "a title")')) + m = p.markdown(hyperlink=1) + m = self.mangleMarkdown2(m) + self.assertEqual(m.rstrip('\n'), '<p><a href="http://example.com/" rel="nofollow noopener" title="a title">label</a></p>') p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'')) m = p.markdown(hyperlink=1) + m = self.mangleMarkdown2(m) self.assertIn(m, [ '<p><img src="http://example.com/" alt=""/></p>\n', '<p><img src="http://example.com/" alt="" /></p>\n', @@ -515,11 +567,13 @@ p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'An URL http://example.com/ with text')) m = p.markdown(hyperlink=1) - self.assertEqual(m.rstrip('\n'), '<p>An URL <a href="http://example.com/">http://example.com/</a> with text</p>') + m = self.mangleMarkdown2(m) + self.assertEqual(m.rstrip('\n'), '<p>An URL <a href="http://example.com/" rel="nofollow noopener">http://example.com/</a> with text</p>') p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'An URL https://example.com/path with text')) m = p.markdown(hyperlink=1) - self.assertEqual(m.rstrip('\n'), '<p>An URL <a href="https://example.com/path">https://example.com/path</a> with text</p>') + m = self.mangleMarkdown2(m) + self.assertEqual(m.rstrip('\n'), '<p>An URL <a href="https://example.com/path" rel="nofollow noopener">https://example.com/path</a> with text</p>') @skip_mistune class MistuneTestCase(TemplatingTestCase, MarkdownTests) :
