Source code for jwt_allauth.password_reset.views

from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.http import HttpResponseRedirect, HttpResponseNotFound
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.http import urlsafe_base64_decode
from django.utils.translation import gettext_lazy as _
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
from rest_framework_simplejwt.exceptions import InvalidToken

from jwt_allauth.app_settings import PasswordResetSerializer
from jwt_allauth.constants import PASS_RESET, PASSWORD_RESET_REDIRECT, PASS_RESET_ACCESS, PASS_RESET_COOKIE, FOR_USER, \
    ONE_TIME_PERMISSION
from jwt_allauth.password_reset.permissions import ResetPasswordPermission
from jwt_allauth.password_reset.serializers import SetPasswordSerializer
from jwt_allauth.tokens.app_settings import RefreshToken
from jwt_allauth.tokens.models import GenericTokenModel, RefreshTokenWhitelistModel
from jwt_allauth.tokens.serializers import GenericTokenModelSerializer
from jwt_allauth.tokens.tokens import GenericToken
from jwt_allauth.utils import get_user_agent, sensitive_post_parameters_m


[docs] class PasswordResetView(GenericAPIView): """ Calls Django Auth PasswordResetForm save method. Accepts the following POST parameters: email Returns the success/fail message. """ serializer_class = PasswordResetSerializer permission_classes = (AllowAny,) throttle_classes = [AnonRateThrottle] @get_user_agent def post(self, request): # Create a serializer with request.data serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() # Return the success message with OK HTTP status return Response( {"detail": _("Password reset e-mail has been sent.")}, status=status.HTTP_200_OK )
[docs] class DefaultPasswordResetView(GenericAPIView): """ Default view for password reset form. """ permission_classes = (AllowAny,) template_name = 'password/reset.html'
[docs] def get(self, request): return render(request, self.template_name, { 'validlink': PASS_RESET_COOKIE in request.COOKIES, 'form': None })
[docs] class PasswordResetConfirmView(GenericAPIView): form_url = getattr(settings, PASSWORD_RESET_REDIRECT, None) @get_user_agent def get(self, *_, **kwargs): if "uidb64" not in kwargs or "token" not in kwargs: raise ImproperlyConfigured( "The URL path must contain 'uidb64' and 'token' parameters." ) user = self.get_user(kwargs["uidb64"]) if user is not None: if GenericToken(request=self.request, purpose=PASS_RESET).check_token(user, kwargs["token"]): refresh_token = RefreshToken() refresh_token[FOR_USER] = user.id refresh_token[ONE_TIME_PERMISSION] = PASS_RESET_ACCESS access_token = refresh_token.access_token response = HttpResponseRedirect( self.form_url if self.form_url else reverse_lazy('default_password_reset') ) response.set_cookie( key=PASS_RESET_COOKIE, value=str(access_token), httponly=getattr(settings, 'PASSWORD_RESET_COOKIE_HTTP_ONLY', True), secure=getattr(settings, 'PASSWORD_RESET_COOKIE_SECURE', not settings.DEBUG), samesite=getattr(settings, 'PASSWORD_RESET_COOKIE_SAME_SITE', 'Lax'), max_age=getattr(settings, 'PASSWORD_RESET_COOKIE_MAX_AGE', 3600) ) token_serializer = GenericTokenModelSerializer(data={ 'token': access_token['jti'], 'user': user.id, 'purpose': PASS_RESET_ACCESS }) token_serializer.is_valid(raise_exception=True) token_serializer.save() return response return render(self.request, 'password/reset.html', { 'validlink': False, 'form': None })
[docs] @staticmethod def get_user(uidb64): try: # urlsafe_base64_decode() decodes to bytestring uid = urlsafe_base64_decode(uidb64).decode() user = get_user_model()._default_manager.get(pk=uid) except ( TypeError, ValueError, OverflowError, get_user_model().DoesNotExist, ValidationError, ): user = None return user
[docs] class ResetPasswordView(GenericAPIView): """ Calls Django Auth SetPasswordForm save method. Accepts the following POST parameters: new_password1, new_password2 Returns the success/fail message. """ serializer_class = SetPasswordSerializer permission_classes = (ResetPasswordPermission,) throttle_classes = [UserRateThrottle]
[docs] @sensitive_post_parameters_m def dispatch(self, *args, **kwargs): return super(ResetPasswordView, self).dispatch(*args, **kwargs)
[docs] def post(self, request): # check the token has not been used query_set = GenericTokenModel.objects.filter(token=request.auth['jti'], purpose=PASS_RESET_ACCESS) if len(query_set) != 1: raise InvalidToken() query_set.delete() # single use # Load the user in the request request.user = get_user_model().objects.get(id=self.request.user.id) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() # Revoke old sessions if getattr(settings, 'LOGOUT_ON_PASSWORD_CHANGE', True): RefreshTokenWhitelistModel.objects.filter(user=self.request.user.id).delete() refresh_token = RefreshToken.for_user(request.user) return Response({ "refresh": str(refresh_token), "access": str(refresh_token.access_token), "detail": _("Password reset.") })