diff --git a/evennia/utils/tests/test_tagparsing.py b/evennia/utils/tests/test_tagparsing.py index c684ab9e3b..76cc9dd801 100644 --- a/evennia/utils/tests/test_tagparsing.py +++ b/evennia/utils/tests/test_tagparsing.py @@ -250,13 +250,13 @@ class TestTextToHTMLparser(TestCase): def test_url_scheme_ftp(self): self.assertEqual( self.parser.convert_urls("ftp.example.com"), - 'ftp.example.com', + 'ftp.example.com', ) def test_url_scheme_www(self): self.assertEqual( self.parser.convert_urls("www.example.com"), - 'www.example.com', + 'www.example.com', ) def test_url_scheme_ftpproto(self): @@ -280,7 +280,7 @@ class TestTextToHTMLparser(TestCase): def test_url_chars_slash(self): self.assertEqual( self.parser.convert_urls("www.example.com/homedir"), - 'www.example.com/homedir', + 'www.example.com/homedir', ) def test_url_chars_colon(self): @@ -313,22 +313,16 @@ class TestTextToHTMLparser(TestCase): ' target="_blank">https://groups.google.com/forum/?fromgroups#!categories/evennia/ainneve', ) - def test_url_edge_leadingw(self): - self.assertEqual( - self.parser.convert_urls("wwww.example.com"), - 'wwww.example.com', - ) - def test_url_edge_following_period_eol(self): self.assertEqual( self.parser.convert_urls("www.example.com."), - 'www.example.com.', + 'www.example.com.', ) def test_url_edge_following_period(self): self.assertEqual( self.parser.convert_urls("see www.example.com. "), - 'see www.example.com. ', + 'see www.example.com. ', ) def test_url_edge_brackets(self): @@ -356,3 +350,15 @@ class TestTextToHTMLparser(TestCase): '' 'http://example.com/', ) + + def test_non_url_with_www(self): + self.assertEqual( + self.parser.convert_urls('Awwww.this should not be highlighted'), + 'Awwww.this should not be highlighted' + ) + + def test_invalid_www_url(self): + self.assertEqual( + self.parser.convert_urls('www.t'), + 'www.t' + ) diff --git a/evennia/utils/text2html.py b/evennia/utils/text2html.py index 1a0b2bf6cc..9ea74bf269 100644 --- a/evennia/utils/text2html.py +++ b/evennia/utils/text2html.py @@ -88,8 +88,10 @@ class TextToHTMLparser(object): re.S | re.M | re.I, ) re_url = re.compile( - r'(?\[\]\s])+)(\.(?:\s|$)|&\w+;|)' + r'(?\[\]\s])+)(\.(?:\s|$)|&\w+;|)' ) + re_protocol = re.compile(r'^(?:ftp|https?)://') + re_valid_no_protocol = re.compile(r'^(?:www|ftp)\.[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b[-a-zA-Z0-9@:%_\+.~#?&//=]*') re_mxplink = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) re_mxpurl = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL) @@ -147,9 +149,22 @@ class TextToHTMLparser(object): text (str): Processed text. """ - # -> added target to output prevent the web browser from attempting to - # change pages (and losing our webclient session). - return self.re_url.sub(r'\1\2', text) + m = self.re_url.search(text) + if m: + href = m.group(1) + label = href + # if there is no protocol (i.e. starts with www or ftp) + # prefix with http:// so the link isn't treated as relative + if not self.re_protocol.match(href): + if not self.re_valid_no_protocol.match(href): + return text + href = "http://" + href + rest = m.group(2) + # -> added target to output prevent the web browser from attempting to + # change pages (and losing our webclient session). + return text[:m.start()] + f'{label}{rest}' + text[m.end():] + else: + return text def sub_mxp_links(self, match): """