from functools import wraps import secrets from django.core.signing import TimestampSigner, SignatureExpired from django.shortcuts import redirect, render from hc.api.models import TokenBucket from hc.lib import emails def _session_unsign(request, key, max_age): if key not in request.session: return None try: return TimestampSigner().unsign(request.session[key], max_age=max_age) except SignatureExpired: pass def require_sudo_mode(f): @wraps(f) def wrapper(request, *args, **kwds): assert request.user.is_authenticated # is sudo mode active and has not expired yet? if _session_unsign(request, "sudo", 1800) == "active": return f(request, *args, **kwds) if not TokenBucket.authorize_sudo_code(request.user): return render(request, "try_later.html") # has the user submitted a code to enter sudo mode? if "sudo_code" in request.POST: ours = _session_unsign(request, "sudo_code", 900) if ours and ours == request.POST["sudo_code"]: request.session.pop("sudo_code") request.session["sudo"] = TimestampSigner().sign("active") return redirect(request.path) if not _session_unsign(request, "sudo_code", 900): code = "%06d" % secrets.randbelow(1000000) request.session["sudo_code"] = TimestampSigner().sign(code) emails.sudo_code(request.user.email, {"sudo_code": code}) ctx = {} if "sudo_code" in request.POST: ctx["wrong_code"] = True return render(request, "accounts/sudo.html", ctx) return wrapper