from django.contrib.auth.views import LoginView as DjangoLoginView from django.contrib.auth import login from django.utils.decorators import method_decorator from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.csrf import csrf_protect from django.views.decorators.cache import never_cache from django.core.exceptions import PermissionDenied from django.http.response import HttpResponseRedirect from django.urls import reverse from ..models.auth import OTPSession from ..forms.auth import OTPForm class LoginView(DjangoLoginView): template_name = "core/auth/login.html" @method_decorator(sensitive_post_parameters()) @method_decorator(csrf_protect) @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): if self.request.session.get("OTPSession"): return HttpResponseRedirect(self.get_otp_url()) return super().dispatch(request, *args, **kwargs) def get_otp_url(self): return reverse("checkotp", kwargs={self.redirect_field_name: self.get_redirect_url()}) def form_valid(self, form): if not (user := form.get_user()).totp: login(self.request, user) return HttpResponseRedirect(self.get_success_url()) session = OTPSession.objects.create(user=user) self.request.session["OTPSession"] = session.uuid return HttpResponseRedirect(self.get_otp_url()) class OTPView(DjangoLoginView): authentication_form = OTPForm @method_decorator(sensitive_post_parameters()) @method_decorator(csrf_protect) @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): if not self.get_otpsession().is_alive(): del request.session["OTPSession"] raise PermissionDenied("Your session has expired. Please try again.") return super().dispatch(request, *args, **kwargs) def get_otpsession(self): return OTPSession.objects.get(uuid=self.request.session.get("OTPSession")) def form_valid(self, form): login(self.request, self.get_otpsession().user) del request.session["OTPSession"] return HttpResponseRedirect(self.get_success_url())