aboutsummaryrefslogtreecommitdiff
path: root/webmentions_ssg/tasks/receiver.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--webmentions_ssg/tasks/receiver.py18
1 files changed, 18 insertions, 0 deletions
diff --git a/webmentions_ssg/tasks/receiver.py b/webmentions_ssg/tasks/receiver.py
index ea48299..9475866 100644
--- a/webmentions_ssg/tasks/receiver.py
+++ b/webmentions_ssg/tasks/receiver.py
@@ -10,6 +10,11 @@ from .. import APP_NAME, VERSION
from .. import DATABASE as db
from .. import HUEY as huey
from ..models import ReceivedWebmention
+from ..url_security import (
+ AddressResolutionError,
+ NonPublicAddressError,
+ ensure_public_url,
+)
class VerificationError(Exception):
@@ -103,6 +108,16 @@ def text_mentions_target(body: str, target_url: str) -> bool:
return any(match.group() == target_url for match in IRI_PATTERN.finditer(body))
+def ensure_public_request(request: httpx.Request) -> None:
+ """Prevent requests to non-public network addresses."""
+ try:
+ ensure_public_url(str(request.url))
+ except NonPublicAddressError as exc:
+ raise VerificationError("Source resolves to a non-public address") from exc
+ except AddressResolutionError as exc:
+ raise TemporaryFetchError("Source hostname could not be resolved") from exc
+
+
def fetch_source(source_url: str) -> tuple[httpx.Response, bytes]:
"""Fetch a source with limits on redirects, time, and response size."""
@@ -117,6 +132,9 @@ def fetch_source(source_url: str) -> tuple[httpx.Response, bytes]:
follow_redirects=True,
max_redirects=current_app.config.get("WEBMENTIONS_SSG_MAX_REDIRECTS", 20),
trust_env=False,
+ event_hooks={
+ "request": [ensure_public_request],
+ },
) as client:
with client.stream("GET", source_url) as response:
match response.status_code: