Remove regexes from is_local()

This commit is contained in:
Joakim Hellsén 2024-01-31 00:03:17 +01:00
commit c9878b51c8
3 changed files with 74 additions and 25 deletions

View file

@ -7,6 +7,7 @@
"feedburner", "feedburner",
"feedparser", "feedparser",
"feedvault", "feedvault",
"gaierror",
"leftright", "leftright",
"levelname", "levelname",
"PGHOST", "PGHOST",

View file

@ -1 +1,51 @@
"""https://docs.djangoproject.com/en/5.0/topics/testing/.""" """https://docs.djangoproject.com/en/5.0/topics/testing/."""
from __future__ import annotations
import random
from typing import TYPE_CHECKING
from django.test import Client, TestCase
from feeds.validator import is_ip, validate_scheme
if TYPE_CHECKING:
from django.http import HttpResponse
class TestHomePage(TestCase):
"""Test case for the home page view."""
def setUp(self: TestHomePage) -> None:
"""Set up the test client for the test case."""
self.client = Client()
def test_home_page(self: TestHomePage) -> None:
"""Test that a GET request to the home page returns a 200 status code."""
response: HttpResponse = self.client.get("/")
assert response.status_code == 200
class TestValidator(TestCase):
"""Test case for the validator."""
def setUp(self: TestValidator) -> None:
"""Set up the test client for the test case."""
self.client = Client()
def test_is_ip(self: TestValidator) -> None:
"""Test that is_ip() returns True for a valid IP address."""
# Test random IP address
random_ip: str = ".".join(str(random.randint(0, 255)) for _ in range(4)) # noqa: S311
assert is_ip(feed_url=random_ip)
# Test domain name
assert not is_ip(feed_url="https://example.com")
def test_validate_scheme(self: TestValidator) -> None:
"""Test that validate_scheme() returns True for a valid scheme."""
assert validate_scheme(feed_url="https://example.com")
assert validate_scheme(feed_url="http://example.com")
assert not validate_scheme(feed_url="ftp://example.com")
assert not validate_scheme(feed_url="example.com")
assert not validate_scheme(feed_url="127.0.0.1")

View file

@ -4,7 +4,7 @@ from __future__ import annotations
import ipaddress import ipaddress
import logging import logging
import re import socket
from urllib.parse import urlparse from urllib.parse import urlparse
import requests import requests
@ -45,7 +45,7 @@ def is_ip(feed_url: str) -> bool:
try: try:
ipaddress.ip_address(feed_url) ipaddress.ip_address(feed_url)
except ValueError: except ValueError:
logger.info(f"{feed_url} is not an IP address") # noqa: G004 logger.info(f"{feed_url} passed isn't either a v4 or a v6 address") # noqa: G004
return False return False
else: else:
logger.info(f"{feed_url} is an IP address") # noqa: G004 logger.info(f"{feed_url} is an IP address") # noqa: G004
@ -97,30 +97,28 @@ def update_blocklist() -> str:
def is_local(feed_url: str) -> bool: def is_local(feed_url: str) -> bool:
"""Check if feed is a local address.""" """Check if feed is a local address."""
# Regexes from https://github.com/gwarser/filter-lists network_location: str = urlparse(url=feed_url).netloc
regexes: list[str] = [
# 10.0.0.0 - 10.255.255.255
r"^\w+:\/\/10\.(?:(?:[1-9]?\d|1\d\d|2(?:[0-4]\d|5[0-5]))\.){2}(?:[1-9]?\d|1\d\d|2(?:[0-4]\d|5[0-5]))[:/]",
# 172.16.0.0 - 172.31.255.255
r"^\w+:\/\/172\.(?:1[6-9]|2\d|3[01])(?:\.(?:[1-9]?\d|1\d\d|2(?:[0-4]\d|5[0-5]))){2}[:/]",
# 192.168.0.0 - 192.168.255.255
r"^\w+:\/\/192\.168(?:\.(?:[1-9]?\d|1\d\d|2(?:[0-4]\d|5[0-5]))){2}[:/]",
# https://en.wikipedia.org/wiki/Private_network#Link-local_addresses
r"^\w+:\/\/169\.254\.(?:[1-9]\d?|1\d{2}|2(?:[0-4]\d|5[0-4]))\.(?:[1-9]?\d|1\d{2}|2(?:[0-4]\d|5[0-5]))[:/]",
# https://en.wikipedia.org/wiki/IPv6_address#Transition_from_IPv4
r"^\w+:\/\/\[::ffff:(?:7f[0-9a-f]{2}|a[0-9a-f]{2}|ac1[0-9a-f]|c0a8|a9fe):[0-9a-f]{1,4}\][:/]",
# localhost
r"^\w+:\/\/127\.(?:(?:[1-9]?\d|1\d\d|2(?:[0-4]\d|5[0-5]))\.){2}(?:[1-9]?\d|1\d\d|2(?:[0-4]\d|5[0-5]))[:/]",
]
domain: str | None = urlparse(feed_url).hostname # Check if network location is an IP address
if not domain: if is_ip(feed_url=network_location):
return False try:
ip: ipaddress.IPv4Address | ipaddress.IPv6Address = ipaddress.ip_address(address=network_location)
except ValueError:
return False
else:
return ip.is_private
if domain in {"localhost", "127.0.0.1", "::1", "0.0.0.0", "::", "local", "[::1]"}: # noqa: S104 try:
ip_address: str = socket.gethostbyname(network_location)
is_private: bool = ipaddress.ip_address(address=ip_address).is_private
except socket.gaierror as e:
logger.info(f"{feed_url} failed to resolve: {e}") # noqa: G004
return True
except ValueError as e:
logger.info(f"{feed_url} failed to resolve: {e}") # noqa: G004
return True return True
if domain.endswith((".local", ".home.arpa")): msg: str = f"{feed_url} is a local URL" if is_private else f"{feed_url} is not a local URL"
return True logger.info(msg)
return any(re.match(regex, feed_url) for regex in regexes) return is_private