PR#2756: Show VCS and DistURL tags as links when appropriate

Merges #2756
https://pagure.io/koji/pull-request/2756

Fixes: #2748
https://pagure.io/koji/issue/2748
VCS and DistURL could be displayed as links
This commit is contained in:
Tomas Kopecek 2021-04-19 15:09:43 +02:00
commit 8d13743e1b
4 changed files with 54 additions and 13 deletions

View file

@ -1,6 +1,6 @@
import unittest
from kojiweb.util import formatMode
from kojiweb.util import formatMode, formatLink, escapeHTML
class TestFormatMode(unittest.TestCase):
def test_format_mode(self):
@ -16,3 +16,34 @@ class TestFormatMode(unittest.TestCase):
for s, mode in formats:
self.assertEqual(formatMode(mode), s)
def test_format_link(self):
formats = (
('test me', 'test me'),
(' test ', 'test'),
('<script>hack</script>', '&lt;script&gt;hack&lt;/script&gt;'),
('not://valid', 'not://valid'),
('https://foo.com', '<a href="https://foo.com">https://foo.com</a>'),
('http://bar.com/', '<a href="http://bar.com/">http://bar.com/</a>'),
('HTtP://BaR.CoM/', '<a href="HTtP://BaR.CoM/">HTtP://BaR.CoM/</a>'),
('https://baz.com/baz&t=1', '<a href="https://baz.com/baz&amp;t=1">https://baz.com/baz&amp;t=1</a>'),
('ssh://git@pagure.io/foo', '<a href="ssh://git@pagure.io/foo">ssh://git@pagure.io/foo</a>'),
('git://git@pagure.io/foo', '<a href="git://git@pagure.io/foo">git://git@pagure.io/foo</a>'),
('obs://build.opensuse.org/foo', '<a href="obs://build.opensuse.org/foo">obs://build.opensuse.org/foo</a>'),
)
for input, output in formats:
self.assertEqual(formatLink(input), output)
def test_escape_html(self):
tests = (
('test me', 'test me'),
('test <danger>', 'test &lt;danger&gt;'),
('test <danger="true">', 'test &lt;danger=&quot;true&quot;&gt;'),
("test <danger='true'>", 'test &lt;danger=&#x27;true&#x27;&gt;'),
('test&test', 'test&amp;test'),
('test&amp;test', 'test&amp;test'),
)
for input, output in tests:
self.assertEqual(escapeHTML(input), output)

View file

@ -52,12 +52,12 @@
#end if
#if $vcs
<tr>
<th><label title="Package source code VCS location">VCS</label></th><td>$util.escapeHTML($vcs)</td>
<th><label title="Package source code VCS location">VCS</label></th><td>$util.formatLink($vcs)</td>
</tr>
#end if
#if $disturl
<tr>
<th>DistURL</th><td>$util.escapeHTML($disturl)</td>
<th>DistURL</th><td>$util.formatLink($disturl)</td>
</tr>
#end if
<tr>

View file

@ -70,12 +70,12 @@
</tr>
#if $vcs
<tr>
<th><label title="Package source code VCS location">VCS</label></th><td>$util.escapeHTML($vcs)</td>
<th><label title="Package source code VCS location">VCS</label></th><td>$util.formatLink($vcs)</td>
</tr>
#end if
#if $disturl
<tr>
<th>DistURL</th><td>$util.escapeHTML($disturl)</td>
<th>DistURL</th><td>$util.formatLink($disturl)</td>
</tr>
#end if
#end if

View file

@ -106,12 +106,7 @@ class DecodeUTF8(Cheetah.Filters.Filter):
class XHTMLFilter(DecodeUTF8):
def filter(self, *args, **kw):
result = super(XHTMLFilter, self).filter(*args, **kw)
result = result.replace('&', '&amp;')
result = result.replace('&amp;amp;', '&amp;')
result = result.replace('&amp;nbsp;', '&nbsp;')
result = result.replace('&amp;lt;', '&lt;')
result = result.replace('&amp;gt;', '&gt;')
return result
return re.sub(r'&(?![a-zA-Z0-9#]+;)', '&amp;', result)
TEMPLATES = {}
@ -523,6 +518,17 @@ def formatThousands(value):
return '{:,}'.format(value)
def formatLink(url):
"""Turn a string into an HTML link if it looks vaguely like a URL.
If it doesn't, just return it properly escaped."""
url = escapeHTML(url.strip())
m = re.match(r'(https?|ssh|git|obs)://.*', url, flags=re.IGNORECASE)
if m:
return '<a href="{}">{}</a>'.format(url, url)
return url
def rowToggle(template):
"""If the value of template._rowNum is even, return 'row-even';
if it is odd, return 'row-odd'. Increment the value before checking it.
@ -583,14 +589,18 @@ def escapeHTML(value):
< : &lt;
> : &gt;
& : &amp;
" : &quot;
' : &#x27;
"""
if not value:
return value
value = koji.fixEncoding(value)
return value.replace('&', '&amp;').\
return re.sub(r'&(?![a-zA-Z0-9#]+;)', '&amp;', value).\
replace('<', '&lt;').\
replace('>', '&gt;')
replace('>', '&gt;').\
replace('"', '&quot;').\
replace("'", '&#x27;')
def authToken(template, first=False, form=False):