aboutsummaryrefslogtreecommitdiff
path: root/webmentions_ssg/url_security.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--webmentions_ssg/url_security.py37
1 files changed, 37 insertions, 0 deletions
diff --git a/webmentions_ssg/url_security.py b/webmentions_ssg/url_security.py
new file mode 100644
index 0000000..ce5d700
--- /dev/null
+++ b/webmentions_ssg/url_security.py
@@ -0,0 +1,37 @@
+import ipaddress
+from urllib.parse import urlsplit
+
+import dns.exception
+import dns.resolver
+
+
+class AddressResolutionError(Exception):
+ pass
+
+
+class NonPublicAddressError(Exception):
+ pass
+
+
+def ensure_public_url(url: str) -> None:
+ hostname = urlsplit(url).hostname
+
+ if hostname is None:
+ raise NonPublicAddressError("URL has no hostname")
+
+ try:
+ answers = dns.resolver.resolve_name(hostname)
+ except dns.exception.DNSException as exc:
+ raise AddressResolutionError(
+ f"Could not resolve hostname {hostname!r}"
+ ) from exc
+
+ addresses = {ipaddress.ip_address(address) for address in answers.addresses()}
+
+ if not addresses:
+ raise AddressResolutionError(f"Hostname {hostname!r} did not resolve")
+
+ if any(not address.is_global for address in addresses):
+ raise NonPublicAddressError(
+ f"Hostname {hostname!r} resolves to a non-public address"
+ )