diff --git a/bookwyrm/templates/preferences/change_password.html b/bookwyrm/templates/preferences/change_password.html index 563bdee4dd..ad34aca1ac 100644 --- a/bookwyrm/templates/preferences/change_password.html +++ b/bookwyrm/templates/preferences/change_password.html @@ -8,15 +8,46 @@ {% endblock %} {% block panel %} +{% if success %} +
+ + + {% trans "Successfully changed password" %} + +
+{% endif %}
{% csrf_token %} +
+ + + {% include 'snippets/form_errors.html' with errors_list=errors.current_password id="desc_current_password" %} +
+
- + + {% include 'snippets/form_errors.html' with errors_list=errors.confirm_password id="desc_confirm_password" %}
diff --git a/bookwyrm/tests/views/preferences/test_change_password.py b/bookwyrm/tests/views/preferences/test_change_password.py index 61837c4e1f..b6d2f48ef1 100644 --- a/bookwyrm/tests/views/preferences/test_change_password.py +++ b/bookwyrm/tests/views/preferences/test_change_password.py @@ -42,17 +42,50 @@ def test_password_change(self): """change password""" view = views.ChangePassword.as_view() password_hash = self.local_user.password - request = self.factory.post("", {"password": "hi", "confirm-password": "hi"}) + request = self.factory.post( + "", + { + "current_password": "password", + "password": "hi", + "confirm-password": "hi", + }, + ) request.user = self.local_user with patch("bookwyrm.views.preferences.change_password.login"): - view(request) + result = view(request) + validate_html(result.render()) self.assertNotEqual(self.local_user.password, password_hash) + def test_password_change_wrong_current(self): + """change password""" + view = views.ChangePassword.as_view() + password_hash = self.local_user.password + request = self.factory.post( + "", + { + "current_password": "not my password", + "password": "hi", + "confirm-password": "hihi", + }, + ) + request.user = self.local_user + result = view(request) + validate_html(result.render()) + self.assertEqual(self.local_user.password, password_hash) + def test_password_change_mismatch(self): """change password""" view = views.ChangePassword.as_view() password_hash = self.local_user.password - request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"}) + request = self.factory.post( + "", + { + "current_password": "password", + "password": "hi", + "confirm-password": "hihi", + }, + ) request.user = self.local_user - view(request) + result = view(request) + validate_html(result.render()) self.assertEqual(self.local_user.password, password_hash) diff --git a/bookwyrm/views/preferences/change_password.py b/bookwyrm/views/preferences/change_password.py index cdfc9d3335..eaca2d8fa1 100644 --- a/bookwyrm/views/preferences/change_password.py +++ b/bookwyrm/views/preferences/change_password.py @@ -1,10 +1,13 @@ """ class views for password management """ from django.contrib.auth import login from django.contrib.auth.decorators import login_required -from django.shortcuts import redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ from django.views import View +from django.views.decorators.debug import sensitive_variables, sensitive_post_parameters + +from bookwyrm import models # pylint: disable= no-self-use @@ -17,15 +20,30 @@ def get(self, request): data = {"user": request.user} return TemplateResponse(request, "preferences/change_password.html", data) + @sensitive_variables("new_password") + @sensitive_variables("confirm_password") + @method_decorator(sensitive_post_parameters("current_password")) + @method_decorator(sensitive_post_parameters("password")) + @method_decorator(sensitive_post_parameters("confirm__password")) def post(self, request): """allow a user to change their password""" + data = {"user": request.user} + + # check current password + user = models.User.objects.get(id=request.user.id) + if not user.check_password(request.POST.get("current_password")): + data["errors"] = {"current_password": [_("Incorrect password")]} + return TemplateResponse(request, "preferences/change_password.html", data) + new_password = request.POST.get("password") confirm_password = request.POST.get("confirm-password") if new_password != confirm_password: - return redirect("prefs-password") + data["errors"] = {"confirm_password": [_("Password does not match")]} + return TemplateResponse(request, "preferences/change_password.html", data) request.user.set_password(new_password) request.user.save(broadcast=False, update_fields=["password"]) login(request, request.user) - return redirect("user-feed", request.user.localname) + data["success"] = True + return TemplateResponse(request, "preferences/change_password.html", data)