From cdff79b142e4aa4c3b699ef5db246bc847035185 Mon Sep 17 00:00:00 2001 From: emickiewicz Date: Mon, 15 Apr 2024 13:11:53 +0200 Subject: [PATCH 1/3] Fix the reset_password_token_created signal to be fired even when no token have been created. --- django_rest_passwordreset/views.py | 26 ++++++++++++++++---------- tests/test/test_auth_test_case.py | 4 +++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/django_rest_passwordreset/views.py b/django_rest_passwordreset/views.py index b17752c..683db99 100644 --- a/django_rest_passwordreset/views.py +++ b/django_rest_passwordreset/views.py @@ -60,7 +60,7 @@ def clear_expired_tokens(): clear_expired(now_minus_expiry_time) -def generate_token_for_email(email, user_agent='', ip_address=''): +def generate_token_for_email(email, user_agent='', ip_address='') -> ResetPasswordToken | None: # find a user by email address (case-insensitive search) users = User.objects.filter(**{'{}__iexact'.format(get_password_reset_lookup_field()): email}) @@ -75,12 +75,14 @@ def generate_token_for_email(email, user_agent='', ip_address=''): break # No active user found, raise a ValidationError - # but not if DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE == True - if not active_user_found and not getattr(settings, 'DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE', False): - raise exceptions.ValidationError({ - 'email': [_( - "We couldn't find an account associated with that email. Please try a different e-mail address.")], - }) + # but not if DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE == True, in that case we return None + if not active_user_found: + if not getattr(settings, 'DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE', False): + raise exceptions.ValidationError({ + 'email': [_( + "We couldn't find an account associated with that email. Please try a different e-mail address.")], + }) + return None # last but not least: iterate over all users that are active and can change their password # and create a Reset Password Token and send a signal with the created token @@ -199,9 +201,13 @@ def post(self, request, *args, **kwargs): ip_address=request.META.get(HTTP_IP_ADDRESS_HEADER, ''), ) - # send a signal that the password token was created - # let whoever receives this signal handle sending the email for the password reset - reset_password_token_created.send(sender=self.__class__, instance=self, reset_password_token=token) + if token: + # send a signal that the password token was created + # let whoever receives this signal handle sending the email for the password reset + reset_password_token_created.send( + sender=self.__class__, + instance=self, reset_password_token=token + ) return Response({'status': 'OK'}) diff --git a/tests/test/test_auth_test_case.py b/tests/test/test_auth_test_case.py index 2ad5f40..68b6c97 100644 --- a/tests/test/test_auth_test_case.py +++ b/tests/test/test_auth_test_case.py @@ -360,13 +360,15 @@ def test_signals(self, self.assertEqual(mock_pre_password_reset.call_args[1]['reset_password_token'], token1) @override_settings(DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE=True) - def test_try_reset_password_email_does_not_exist_no_leakage_enabled(self): + @patch('django_rest_passwordreset.signals.reset_password_token_created.send') + def test_try_reset_password_email_does_not_exist_no_leakage_enabled(self, mock_reset_signal): """ Tests requesting a token for an email that does not exist when DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE == True """ response = self.rest_do_request_reset_token(email="foobar@doesnotexist.com") self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertFalse(mock_reset_signal.called) def test_user_without_password(self): """ Tests requesting a token for an email without a password doesn't work""" From 10423fd036c15b6097afe9ed3589d2e81df604e9 Mon Sep 17 00:00:00 2001 From: emickiewicz Date: Mon, 15 Apr 2024 22:50:34 +0200 Subject: [PATCH 2/3] Updated CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afd942c..0184a86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ PyPi: [https://pypi.org/project/django-rest-passwordreset/](https://pypi.org/pro ## [Unreleased] +### Fixed +- Fix the reset_password_token_created signal to be fired even when no token have been created. (#188) + ## [1.4.0] ### Added From 861611bb2fc2660de89949c92fb2c844eb02c90c Mon Sep 17 00:00:00 2001 From: emickiewicz Date: Mon, 15 Apr 2024 23:46:11 +0200 Subject: [PATCH 3/3] Removed Typing not available in Py3.9 --- django_rest_passwordreset/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_rest_passwordreset/views.py b/django_rest_passwordreset/views.py index 683db99..1af7590 100644 --- a/django_rest_passwordreset/views.py +++ b/django_rest_passwordreset/views.py @@ -60,7 +60,7 @@ def clear_expired_tokens(): clear_expired(now_minus_expiry_time) -def generate_token_for_email(email, user_agent='', ip_address='') -> ResetPasswordToken | None: +def generate_token_for_email(email, user_agent='', ip_address=''): # find a user by email address (case-insensitive search) users = User.objects.filter(**{'{}__iexact'.format(get_password_reset_lookup_field()): email})