ljg.sh/ljg/ip/views.py

53 lines
1.4 KiB
Python

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")