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