From c0686e13054fefbe7aad28b630dfd029ddd320ec Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Tue, 2 Mar 2021 18:02:03 +0100 Subject: [PATCH] misc: send password reset email even if no account (#47469) --- src/authentic2/forms/passwords.py | 11 ++++++----- .../password_reset_no_account_body.html | 14 ++++++++++++++ .../password_reset_no_account_body.txt | 9 +++++++++ .../password_reset_no_account_subject.txt | 4 ++++ src/authentic2/templates/emails/body_base.html | 15 +++++++++++++++ src/authentic2/templates/emails/body_base.txt | 1 + .../templates/emails/button-link.html | 1 + src/authentic2/templates/emails/subject.txt | 1 + tests/test_password_reset.py | 17 +++++++++++++++-- 9 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 src/authentic2/templates/authentic2/password_reset_no_account_body.html create mode 100644 src/authentic2/templates/authentic2/password_reset_no_account_body.txt create mode 100644 src/authentic2/templates/authentic2/password_reset_no_account_subject.txt create mode 100644 src/authentic2/templates/emails/body_base.html create mode 100644 src/authentic2/templates/emails/body_base.txt create mode 100644 src/authentic2/templates/emails/button-link.html create mode 100644 src/authentic2/templates/emails/subject.txt diff --git a/src/authentic2/forms/passwords.py b/src/authentic2/forms/passwords.py index f158c63f..7e26d767 100644 --- a/src/authentic2/forms/passwords.py +++ b/src/authentic2/forms/passwords.py @@ -22,6 +22,7 @@ from django.core.exceptions import ValidationError from django.db.models import Q from django.forms import Form from django import forms +from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from .. import models, hooks, app_settings, utils @@ -45,10 +46,8 @@ class PasswordResetForm(forms.Form): user. """ email = self.cleaned_data["email"].strip() - users = get_user_queryset() - active_users = users.filter( - Q(email__iexact=email) | Q(username__iexact=email), - is_active=True) + users = get_user_queryset().filter(Q(email__iexact=email) | Q(username__iexact=email)) + active_users = users.filter(is_active=True) for user in active_users: # we don't set the password to a random string, as some users should not have # a password @@ -58,8 +57,10 @@ class PasswordResetForm(forms.Form): user, set_random_password=set_random_password, next_url=self.cleaned_data.get('next_url')) - if not active_users: + if not users.exists(): logger.info(u'password reset request for "%s", no user found', email) + ctx = {'registration_url': utils.make_url('registration_register', absolute=True)} + utils.send_templated_mail(email, ['authentic2/password_reset_no_account'], context=ctx) hooks.call_hooks('event', name='password-reset', email=email, users=active_users) diff --git a/src/authentic2/templates/authentic2/password_reset_no_account_body.html b/src/authentic2/templates/authentic2/password_reset_no_account_body.html new file mode 100644 index 00000000..b676535c --- /dev/null +++ b/src/authentic2/templates/authentic2/password_reset_no_account_body.html @@ -0,0 +1,14 @@ +{% extends "emails/body_base.html" %} +{% load i18n %} + +{% block content %} +

{% trans "Hi," %}

+ +

{% blocktrans trimmed with hostname=request.get_host %} +You requested reset of your password on {{ hostname }}, but no account was found associated with this address. +{% endblocktrans %}

+ +{% with _("Create an account") as button_label %} +{% include "emails/button-link.html" with url=registration_url label=button_label %} +{% endwith %} +{% endblock %} diff --git a/src/authentic2/templates/authentic2/password_reset_no_account_body.txt b/src/authentic2/templates/authentic2/password_reset_no_account_body.txt new file mode 100644 index 00000000..65de333e --- /dev/null +++ b/src/authentic2/templates/authentic2/password_reset_no_account_body.txt @@ -0,0 +1,9 @@ +{% extends "emails/body_base.txt" %} +{% load i18n %} + +{% block content %}{% trans "Hi," %} +{% blocktrans trimmed with hostname=request.get_host %} +You requested reset of your password on {{ hostname }}, but no account was found associated with this address. +{% endblocktrans %} +{% trans "You can create an account here:" %} {{ registration_url }}. +{% endblock %} diff --git a/src/authentic2/templates/authentic2/password_reset_no_account_subject.txt b/src/authentic2/templates/authentic2/password_reset_no_account_subject.txt new file mode 100644 index 00000000..b4988b2a --- /dev/null +++ b/src/authentic2/templates/authentic2/password_reset_no_account_subject.txt @@ -0,0 +1,4 @@ +{% extends "emails/subject.txt" %} +{% load i18n %} + +{% block email-subject %}{% blocktrans with hostname=request.get_host %}Password reset on {{ hostname }}{% endblocktrans %}{% endblock %} diff --git a/src/authentic2/templates/emails/body_base.html b/src/authentic2/templates/emails/body_base.html new file mode 100644 index 00000000..9705c361 --- /dev/null +++ b/src/authentic2/templates/emails/body_base.html @@ -0,0 +1,15 @@ + + + + + + +
+
+ {% block content %} + {{ content }} + {% endblock %} +
+
+ + diff --git a/src/authentic2/templates/emails/body_base.txt b/src/authentic2/templates/emails/body_base.txt new file mode 100644 index 00000000..15e8e85d --- /dev/null +++ b/src/authentic2/templates/emails/body_base.txt @@ -0,0 +1 @@ +{% block content %}{{ content }}{% endblock %} diff --git a/src/authentic2/templates/emails/button-link.html b/src/authentic2/templates/emails/button-link.html new file mode 100644 index 00000000..7cb7d474 --- /dev/null +++ b/src/authentic2/templates/emails/button-link.html @@ -0,0 +1 @@ +{{label}} diff --git a/src/authentic2/templates/emails/subject.txt b/src/authentic2/templates/emails/subject.txt new file mode 100644 index 00000000..2764059b --- /dev/null +++ b/src/authentic2/templates/emails/subject.txt @@ -0,0 +1 @@ +{% block email-subject %}{% endblock %} diff --git a/tests/test_password_reset.py b/tests/test_password_reset.py index df80eed4..350a1d84 100644 --- a/tests/test_password_reset.py +++ b/tests/test_password_reset.py @@ -103,7 +103,7 @@ def test_user_filter(app, simple_user, mailoutbox, settings): resp.form.set('email', simple_user.email) assert len(mailoutbox) == 0 resp = resp.form.submit() - assert len(mailoutbox) == 0 + assert 'no account was found associated with this address' in mailoutbox[0].body def test_user_exclude(app, simple_user, mailoutbox, settings): @@ -114,7 +114,7 @@ def test_user_exclude(app, simple_user, mailoutbox, settings): resp.form.set('email', simple_user.email) assert len(mailoutbox) == 0 resp = resp.form.submit() - assert len(mailoutbox) == 0 + assert 'no account was found associated with this address' in mailoutbox[0].body def test_old_url_redirect(app): @@ -122,3 +122,16 @@ def test_old_url_redirect(app): assert response.location == '/accounts/password/reset/' response = response.follow() assert 'please reset your password again' in response + + +def test_send_password_reset_email_no_account(app, db, mailoutbox): + url = reverse('password_reset') + resp = app.get(url, status=200) + resp.form.set('email', 'test@entrouvert.com') + resp = resp.form.submit() + + mail = mailoutbox[0] + assert mail.subject == 'Password reset on testserver' + for body in (mail.body, mail.alternatives[0][0]): + assert 'no account was found associated with this address' in body + assert 'http://testserver/accounts/register/' in body -- 2.20.1