From dcf970d0c6f10fb7c3d217927cd8ea5ac01ffba5 Mon Sep 17 00:00:00 2001 From: Georg Krause Date: Tue, 29 Aug 2023 11:58:11 +0200 Subject: [PATCH] fix(api): Fix password reset via email The original serializes assumes if allauth is installed, its also used for the token generation. Thats not the case for us, so we need to overwrite this behavior --- api/config/settings/common.py | 3 ++- api/funkwhale_api/users/serializers.py | 31 ++++++++++++++++++++++++++ changes/changelog.d/2209.bugfix | 2 ++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 changes/changelog.d/2209.bugfix diff --git a/api/config/settings/common.py b/api/config/settings/common.py index ffbe4c4fb..290cc5337 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -1181,7 +1181,8 @@ if BROWSABLE_API_ENABLED: ) REST_AUTH_SERIALIZERS = { - "PASSWORD_RESET_SERIALIZER": "funkwhale_api.users.serializers.PasswordResetSerializer" # noqa + "PASSWORD_RESET_SERIALIZER": "funkwhale_api.users.serializers.PasswordResetSerializer", # noqa + "PASSWORD_RESET_CONFIRM_SERIALIZER": "funkwhale_api.users.serializers.PasswordResetConfirmSerializer", # noqa } REST_SESSION_LOGIN = False diff --git a/api/funkwhale_api/users/serializers.py b/api/funkwhale_api/users/serializers.py index 67908f6b9..4a8747620 100644 --- a/api/funkwhale_api/users/serializers.py +++ b/api/funkwhale_api/users/serializers.py @@ -3,15 +3,18 @@ import re from allauth.account import models as allauth_models from dj_rest_auth.registration.serializers import RegisterSerializer as RS from dj_rest_auth.registration.serializers import get_adapter +from dj_rest_auth.serializers import PasswordResetConfirmSerializer as PRCS from dj_rest_auth.serializers import PasswordResetSerializer as PRS from django.contrib import auth from django.contrib.auth.forms import PasswordResetForm from django.core import validators from django.utils.deconstruct import deconstructible +from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import extend_schema_field from rest_framework import serializers +from rest_framework.exceptions import ValidationError from funkwhale_api.activity import serializers as activity_serializers from funkwhale_api.common import models as common_models @@ -252,6 +255,34 @@ class PasswordResetSerializer(PRS): return {"extra_email_context": adapters.get_email_context()} +class PasswordResetConfirmSerializer(PRCS): + def validate(self, attrs): + from allauth.account.forms import default_token_generator + from django.utils.http import urlsafe_base64_decode as uid_decoder + + UserModel = auth.get_user_model() + # Decode the uidb64 (allauth use base36) to uid to get User object + try: + uid = force_str(uid_decoder(attrs["uid"])) + self.user = UserModel._default_manager.get(pk=uid) + except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist): + raise ValidationError({"uid": [_("Invalid value")]}) + + if not default_token_generator.check_token(self.user, attrs["token"]): + raise ValidationError({"token": [_("Invalid value")]}) + + self.custom_validation(attrs) + # Construct SetPasswordForm instance + self.set_password_form = self.set_password_form_class( + user=self.user, + data=attrs, + ) + if not self.set_password_form.is_valid(): + raise serializers.ValidationError(self.set_password_form.errors) + + return attrs + + class UserDeleteSerializer(serializers.Serializer): password = serializers.CharField() confirm = serializers.BooleanField() diff --git a/changes/changelog.d/2209.bugfix b/changes/changelog.d/2209.bugfix new file mode 100644 index 000000000..18d29f1a8 --- /dev/null +++ b/changes/changelog.d/2209.bugfix @@ -0,0 +1,2 @@ + +Fix password reset via email