Skip to content

Commit 8977dbe

Browse files
committed
safety: fix safeify_url() exception on python 3.11
1 parent da05822 commit 8977dbe

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

sopel/builtins/safety.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,15 @@ def setup(bot: Sopel) -> None:
126126

127127
def safeify_url(url: str) -> str:
128128
"""Replace bits of a URL to make it hard to browse to."""
129-
parts = urlparse(url)
130-
scheme = "hxx" + parts.scheme[3:] # hxxp
131-
netloc = parts.netloc.replace(".", "[.]") # google[.]com and IPv4
132-
netloc = netloc.replace(":", "[:]") # IPv6 addresses (bad lazy method)
133-
return urlunparse((scheme, netloc) + parts[2:])
129+
try:
130+
parts = urlparse(url)
131+
scheme = parts.scheme.replace("t", "x") # hxxp
132+
netloc = parts.netloc.replace(".", "[.]") # google[.]com and IPv4
133+
netloc = netloc.replace(":", "[:]") # IPv6 addresses (bad lazy method)
134+
return urlunparse((scheme, netloc) + parts[2:])
135+
except ValueError:
136+
# Still try to defang URLs that fail parsing
137+
return url.replace(":", "[:]").replace(".", "[.]")
134138

135139

136140
def download_domain_list(bot: Sopel, path: str) -> bool:
@@ -224,7 +228,6 @@ def url_handler(bot: SopelWrapper, trigger: Trigger) -> None:
224228
strict = "strict" in mode
225229

226230
for url in tools.web.search_urls(trigger):
227-
safe_url = safeify_url(url)
228231

229232
positives = 0 # Number of engines saying it's malicious
230233
total = 0 # Number of total engines
@@ -249,6 +252,7 @@ def url_handler(bot: SopelWrapper, trigger: Trigger) -> None:
249252

250253
if positives >= 1:
251254
# Possibly malicious URL detected!
255+
safe_url = safeify_url(url)
252256
LOGGER.info(
253257
"Possibly malicious link (%s/%s) posted in %s by %s: %r",
254258
positives,
@@ -258,11 +262,10 @@ def url_handler(bot: SopelWrapper, trigger: Trigger) -> None:
258262
safe_url,
259263
)
260264
bot.say(
261-
"{} {} of {} engine{} flagged a link {} posted as malicious".format(
265+
"{} {} of {} engines flagged a link {} posted as malicious".format(
262266
bold(color("WARNING:", colors.RED)),
263267
positives,
264268
total,
265-
"" if total == 1 else "s",
266269
bold(trigger.nick),
267270
)
268271
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Tests for Sopel's ``safety`` plugin"""
2+
3+
from __future__ import annotations
4+
5+
import pytest
6+
7+
from sopel.builtins.safety import safeify_url
8+
9+
URL_TESTS = (
10+
# Valid URLs
11+
("http://example.com", ("hxxp://example[.]com")),
12+
("http://1.2.3.4/mgr.cgi", ("hxxp://1[.]2[.]3[.]4/mgr.cgi")),
13+
("http://[fd00:1234::4321]/", ("hxxp://[fd00[:]1234[:][:]4321]/")),
14+
("ftp://1.2.3.4/", ("fxp://1[.]2[.]3[.]4/")),
15+
# Invalid, but parsed anyway
16+
("http://<placeholder>/", ("hxxp://<placeholder>/")),
17+
("http://1.2.3.4.5/", ("hxxp://1[.]2[.]3[.]4[.]5/")),
18+
("http://555.555.555.555/", ("hxxp://555[.]555[.]555[.]555/")),
19+
# urllib.urlparse() works on these in python <=3.10 but fails in 3.11
20+
("http://[fd00:::]/", ("hxxp://[fd00[:][:][:]]/", "http[:]//[fd00[:][:][:]]/")),
21+
("http://[placeholder]/", ("hxxp://[placeholder]/", "http[:]//[placeholder]/")),
22+
)
23+
24+
25+
@pytest.mark.parametrize("original, safed_options", URL_TESTS)
26+
def test_safeify_url(original, safed_options):
27+
assert safeify_url(original) in safed_options

0 commit comments

Comments
 (0)