diff --git a/.env.example b/.env.example index 429e03b..ce2cf3a 100644 --- a/.env.example +++ b/.env.example @@ -15,3 +15,7 @@ OIDC_RP_CLIENT_SECRET= # defaults to RS256 OIDC_RP_SIGN_ALGO= + +IP_REDIRECT_HOST_BOTH= +IP_REDIRECT_HOST_IPV4= +IP_REDIRECT_HOST_IPV6= diff --git a/ljg/ip/middleware.py b/ljg/ip/middleware.py new file mode 100644 index 0000000..0890458 --- /dev/null +++ b/ljg/ip/middleware.py @@ -0,0 +1,56 @@ +from django.conf import settings +from django.http import HttpResponseNotFound, HttpResponseRedirect, QueryDict +from django.urls import reverse + + +class RedirectMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + self.redirect_ipv4 = settings.IP_REDIRECT_HOST["ipv4"] + self.redirect_ipv6 = settings.IP_REDIRECT_HOST["ipv6"] + self.redirect_both = ( + settings.IP_REDIRECT_HOST["both"] + if self.redirect_ipv4 and self.redirect_ipv6 + else "" + ) + + self.disallowed_paths = set(["/favicon.ico", "/robots.txt"]) + + def __call__(self, request): + host = request.get_host() + + if self.redirect_both and host == self.redirect_both: + if request.path in self.disallowed_paths: + return HttpResponseNotFound() + + q = QueryDict(mutable=True) + q.appendlist("next", self.build_url(request, self.redirect_ipv6)) + return HttpResponseRedirect( + f"{self.build_url(request, self.redirect_ipv4)}?{q.urlencode()}" + ) + + if ( + self.redirect_ipv4 + and host == self.redirect_ipv4 + and request.path != reverse("remote_ip") + ): + if request.path in self.disallowed_paths: + return HttpResponseNotFound() + + return HttpResponseRedirect(self.build_url(request, self.redirect_ipv4)) + + if ( + self.redirect_ipv6 + and host == self.redirect_ipv6 + and request.path != reverse("remote_ip") + ): + if request.path in self.disallowed_paths: + return HttpResponseNotFound() + + return HttpResponseRedirect(self.build_url(request, self.redirect_ipv6)) + + return self.get_response(request) + + def build_url(self, request, redirect_host): + return f"http{'s' if request.is_secure() else ''}://{redirect_host}{reverse('remote_ip')}" diff --git a/ljg/settings.py b/ljg/settings.py index dfd788f..142e910 100644 --- a/ljg/settings.py +++ b/ljg/settings.py @@ -51,6 +51,7 @@ INSTALLED_APPS = [ MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", + "ljg.ip.middleware.RedirectMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", @@ -155,3 +156,9 @@ OIDC_OP_USER_ENDPOINT = env.str("OIDC_OP_USER_ENDPOINT", "") OIDC_RP_CLIENT_ID = env.str("OIDC_RP_CLIENT_ID", "") OIDC_RP_CLIENT_SECRET = env.str("OIDC_RP_CLIENT_SECRET", "") OIDC_RP_SIGN_ALGO = env.str("OIDC_RP_SIGN_ALGO", "RS256") + +IP_REDIRECT_HOST = { + "both": env.str("IP_REDIRECT_HOST_BOTH", ""), + "ipv4": env.str("IP_REDIRECT_HOST_IPV4", ""), + "ipv6": env.str("IP_REDIRECT_HOST_IPV6", ""), +}