aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/conftest.py24
-rw-r--r--tests/test_forms.py2
-rw-r--r--tests/test_url_security.py42
-rw-r--r--tests/test_views.py3
4 files changed, 71 insertions, 0 deletions
diff --git a/tests/conftest.py b/tests/conftest.py
index 94ba650..f1ef4b5 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -18,6 +18,14 @@ HTTPHandler = Callable[
]
+class FakeHostAnswers:
+ def __init__(self, *addresses: str):
+ self._addresses = addresses
+
+ def addresses(self):
+ return iter(self._addresses)
+
+
@pytest.fixture
def app() -> Iterator[Flask]:
"""
@@ -101,6 +109,12 @@ def install_httpx_mock(
Replace the HTTPX transport without replacing HTTPX itself.
"""
+ monkeypatch.setattr(
+ receiver_module,
+ "ensure_public_url",
+ lambda url: None,
+ )
+
real_client = httpx.Client
def install(handler: HTTPHandler) -> None:
@@ -123,3 +137,13 @@ def install_httpx_mock(
)
return install
+
+
+@pytest.fixture
+def public_dns(
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ monkeypatch.setattr(
+ "webmentions_ssg.url_security.dns.resolver.resolve_name",
+ lambda hostname: FakeHostAnswers("93.184.216.34"),
+ )
diff --git a/tests/test_forms.py b/tests/test_forms.py
index 9be6ca8..2d5fc01 100644
--- a/tests/test_forms.py
+++ b/tests/test_forms.py
@@ -89,6 +89,7 @@ VALID_TARGET = "https://dennisfink.me/blog/example/"
)
def test_endpoint_form_rejects_invalid_data(
app: Flask,
+ public_dns: None,
form_data: dict[str, str],
invalid_field: str,
expected_error: str | None,
@@ -111,6 +112,7 @@ def test_endpoint_form_rejects_invalid_data(
def test_endpoint_form_accepts_valid_data(
app: Flask,
+ public_dns: None,
) -> None:
with app.test_request_context(
"/endpoint",
diff --git a/tests/test_url_security.py b/tests/test_url_security.py
new file mode 100644
index 0000000..fba6d7d
--- /dev/null
+++ b/tests/test_url_security.py
@@ -0,0 +1,42 @@
+import pytest
+
+from webmentions_ssg.url_security import (
+ NonPublicAddressError,
+ ensure_public_url,
+)
+
+
+class FakeAnswers:
+ def __init__(self, *addresses: str):
+ self._addresses = addresses
+
+ def addresses(self):
+ return iter(self._addresses)
+
+
+@pytest.mark.parametrize(
+ ("url", "resolved_addresses"),
+ [
+ ("http://127.0.0.1/", ["127.0.0.1"]),
+ ("http://127.0.0.1:8080/test", ["127.0.0.1"]),
+ ("http://[::1]/", ["::1"]),
+ ("http://10.0.0.1/", ["10.0.0.1"]),
+ ("http://172.16.0.1/", ["172.16.0.1"]),
+ ("http://192.168.1.1/", ["192.168.1.1"]),
+ ("http://169.254.169.254/", ["169.254.169.254"]),
+ ("http://localhost/", ["127.0.0.1", "::1"]),
+ ("http://internal.example/", ["192.168.1.10"]),
+ ],
+)
+def test_ensure_public_url_rejects_non_public_addresses(
+ monkeypatch: pytest.MonkeyPatch,
+ url: str,
+ resolved_addresses: list[str],
+) -> None:
+ monkeypatch.setattr(
+ "webmentions_ssg.url_security.dns.resolver.resolve_name",
+ lambda hostname: FakeAnswers(*resolved_addresses),
+ )
+
+ with pytest.raises(NonPublicAddressError):
+ ensure_public_url(url)
diff --git a/tests/test_views.py b/tests/test_views.py
index d7fd798..70ed732 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -42,6 +42,7 @@ def test_endpoint_creates_webmention(
client: FlaskClient,
views_module: ModuleType,
monkeypatch: pytest.MonkeyPatch,
+ public_dns: None,
) -> None:
queued: list[uuid.UUID] = []
@@ -85,6 +86,7 @@ def test_endpoint_is_idempotent(
client: FlaskClient,
views_module: ModuleType,
monkeypatch: pytest.MonkeyPatch,
+ public_dns: None,
) -> None:
queued: list[uuid.UUID] = []
@@ -138,6 +140,7 @@ def test_resending_resets_failure_state(
client: FlaskClient,
views_module: ModuleType,
monkeypatch: pytest.MonkeyPatch,
+ public_dns: None,
) -> None:
monkeypatch.setattr(
views_module,