Ensure the type of URL attributes is always str when matching against preview blacklist (#12333)

This commit is contained in:
Brendan Abolivier 2022-03-31 11:49:49 +02:00 committed by GitHub
parent c31c1091d4
commit f96b85eca8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 4 deletions

1
changelog.d/12333.bugfix Normal file
View file

@ -0,0 +1 @@
Fix a long-standing bug affecting URL previews that would generate a 500 response instead of a 403 if the previewed URL includes a port that isn't allowed by the relevant blacklist.

View file

@ -200,12 +200,17 @@ class PreviewUrlResource(DirectServeJsonResource):
match = False match = False
continue continue
# Some attributes might not be parsed as strings by urlsplit (such as the
# port, which is parsed as an int). Because we use match functions that
# expect strings, we want to make sure that's what we give them.
value_str = str(value)
if pattern.startswith("^"): if pattern.startswith("^"):
if not re.match(pattern, getattr(url_tuple, attrib)): if not re.match(pattern, value_str):
match = False match = False
continue continue
else: else:
if not fnmatch.fnmatch(getattr(url_tuple, attrib), pattern): if not fnmatch.fnmatch(value_str, pattern):
match = False match = False
continue continue
if match: if match:

View file

@ -17,7 +17,7 @@ import json
import os import os
import re import re
from typing import Any, Dict, Optional, Sequence, Tuple, Type from typing import Any, Dict, Optional, Sequence, Tuple, Type
from urllib.parse import urlencode from urllib.parse import quote, urlencode
from twisted.internet._resolver import HostResolution from twisted.internet._resolver import HostResolution
from twisted.internet.address import IPv4Address, IPv6Address from twisted.internet.address import IPv4Address, IPv6Address
@ -69,7 +69,6 @@ class URLPreviewTests(unittest.HomeserverTestCase):
"2001:800::/21", "2001:800::/21",
) )
config["url_preview_ip_range_whitelist"] = ("1.1.1.1",) config["url_preview_ip_range_whitelist"] = ("1.1.1.1",)
config["url_preview_url_blacklist"] = []
config["url_preview_accept_language"] = [ config["url_preview_accept_language"] = [
"en-UK", "en-UK",
"en-US;q=0.9", "en-US;q=0.9",
@ -1123,3 +1122,43 @@ class URLPreviewTests(unittest.HomeserverTestCase):
os.path.exists(path), os.path.exists(path),
f"{os.path.relpath(path, self.media_store_path)} was not deleted", f"{os.path.relpath(path, self.media_store_path)} was not deleted",
) )
@unittest.override_config({"url_preview_url_blacklist": [{"port": "*"}]})
def test_blacklist_port(self) -> None:
"""Tests that blacklisting URLs with a port makes previewing such URLs
fail with a 403 error and doesn't impact other previews.
"""
self.lookups["matrix.org"] = [(IPv4Address, "10.1.2.3")]
bad_url = quote("http://matrix.org:8888/foo")
good_url = quote("http://matrix.org/foo")
channel = self.make_request(
"GET",
"preview_url?url=" + bad_url,
shorthand=False,
await_result=False,
)
self.pump()
self.assertEqual(channel.code, 403, channel.result)
channel = self.make_request(
"GET",
"preview_url?url=" + good_url,
shorthand=False,
await_result=False,
)
self.pump()
client = self.reactor.tcpClients[0][2].buildProtocol(None)
server = AccumulatingProtocol()
server.makeConnection(FakeTransport(client, self.reactor))
client.makeConnection(FakeTransport(server, self.reactor))
client.dataReceived(
b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n"
% (len(self.end_content),)
+ self.end_content
)
self.pump()
self.assertEqual(channel.code, 200)