From 009309908a524eef4d07280dc29002724e37a211 Mon Sep 17 00:00:00 2001 From: Luca Date: Thu, 21 Dec 2023 23:07:51 +0100 Subject: [PATCH] Add 'ip' app --- ljg/ip/__init__.py | 0 ljg/ip/urls.py | 7 +++++++ ljg/ip/views.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++ ljg/settings.py | 1 + ljg/urls.py | 1 + 5 files changed, 61 insertions(+) create mode 100644 ljg/ip/__init__.py create mode 100644 ljg/ip/urls.py create mode 100644 ljg/ip/views.py diff --git a/ljg/ip/__init__.py b/ljg/ip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ljg/ip/urls.py b/ljg/ip/urls.py new file mode 100644 index 0000000..55bc4e5 --- /dev/null +++ b/ljg/ip/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path("ip/", views.remote_ip, name="remote_ip"), +] diff --git a/ljg/ip/views.py b/ljg/ip/views.py new file mode 100644 index 0000000..5211ded --- /dev/null +++ b/ljg/ip/views.py @@ -0,0 +1,52 @@ +import re + +from django.conf import settings +from django.core.exceptions import SuspiciousOperation +from django.http import HttpResponse +from django.shortcuts import redirect + + +def hosts_pattern(): + hosts = [] + for host in settings.ALLOWED_HOSTS: + if host == "*": + return ".*" + + if host.startswith("."): + host = host.removeprefix(".") + hosts.append(f"(?:.+\.)?{re.escape(host)}") + + hosts.append(re.escape(host)) + + if hosts == []: + hosts = ["(?:.+\.)?localhost(?::\d+)?", "127.0.0.1(?::\d+)?", "[::1](?::\d+)?"] + + return "|".join(hosts) + + +match_next_url = re.compile(f"^http(s?)://(?:{hosts_pattern()})(?:/|$)", re.IGNORECASE) + + +def remote_ip(request): + if "x-forwarded-for" in request.headers: + remote_addr = request.headers["x-forwarded-for"].split(",")[0] + else: + remote_addr = request.META["REMOTE_ADDR"] + + q = request.GET.copy() + q.appendlist("addr", remote_addr) + + if "next" in q: + next = q.pop("next") + if len(next) > 1: + q.setlist("next", next[1:]) + next = next[0] + + if (m := match_next_url.match(next)) is None or m[1] != {False: "", True: "s"}[ + request.is_secure() + ]: + raise SuspiciousOperation(f"invalid redirect url {next}") + + return redirect(next + f"?{q.urlencode()}") + + return HttpResponse(",".join(q.getlist("addr")), "text/plain") diff --git a/ljg/settings.py b/ljg/settings.py index 3ad8696..dfd788f 100644 --- a/ljg/settings.py +++ b/ljg/settings.py @@ -45,6 +45,7 @@ INSTALLED_APPS = [ "django.contrib.staticfiles", "mozilla_django_oidc", "ljg.core", + "ljg.ip", "ljg.redirect", ] diff --git a/ljg/urls.py b/ljg/urls.py index 179ede3..e7c2db2 100644 --- a/ljg/urls.py +++ b/ljg/urls.py @@ -19,6 +19,7 @@ from django.urls import include, path urlpatterns = [ path("", include("ljg.core.urls")), + path("", include("ljg.ip.urls")), path("", include("ljg.redirect.urls")), path("admin/", admin.site.urls), path("oidc/", include("mozilla_django_oidc.urls")),