You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

51 lines
1.6 KiB

  1. from functools import wraps
  2. import secrets
  3. from django.core.signing import TimestampSigner, SignatureExpired
  4. from django.shortcuts import redirect, render
  5. from hc.api.models import TokenBucket
  6. from hc.lib import emails
  7. def _session_unsign(request, key, max_age):
  8. if key not in request.session:
  9. return None
  10. try:
  11. return TimestampSigner().unsign(request.session[key], max_age=max_age)
  12. except SignatureExpired:
  13. pass
  14. def require_sudo_mode(f):
  15. @wraps(f)
  16. def wrapper(request, *args, **kwds):
  17. assert request.user.is_authenticated
  18. # is sudo mode active and has not expired yet?
  19. if _session_unsign(request, "sudo", 1800) == "active":
  20. return f(request, *args, **kwds)
  21. if not TokenBucket.authorize_sudo_code(request.user):
  22. return render(request, "try_later.html")
  23. # has the user submitted a code to enter sudo mode?
  24. if "sudo_code" in request.POST:
  25. ours = _session_unsign(request, "sudo_code", 900)
  26. if ours and ours == request.POST["sudo_code"]:
  27. request.session.pop("sudo_code")
  28. request.session["sudo"] = TimestampSigner().sign("active")
  29. return redirect(request.path)
  30. if not _session_unsign(request, "sudo_code", 900):
  31. code = "%06d" % secrets.randbelow(1000000)
  32. request.session["sudo_code"] = TimestampSigner().sign(code)
  33. emails.sudo_code(request.user.email, {"sudo_code": code})
  34. ctx = {}
  35. if "sudo_code" in request.POST:
  36. ctx["wrong_code"] = True
  37. return render(request, "accounts/sudo.html", ctx)
  38. return wrapper