Browse Source

Update the "Change Email" function to use confirmation codes

pull/456/head
Pēteris Caune 4 years ago
parent
commit
fb79948759
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
13 changed files with 65 additions and 140 deletions
  1. +0
    -6
      hc/accounts/models.py
  2. +18
    -15
      hc/accounts/tests/test_change_email.py
  3. +0
    -17
      hc/accounts/tests/test_profile.py
  4. +1
    -1
      hc/accounts/tests/test_set_password.py
  5. +1
    -2
      hc/accounts/urls.py
  6. +11
    -21
      hc/accounts/views.py
  7. +0
    -4
      hc/lib/emails.py
  8. +31
    -26
      templates/accounts/change_email.html
  9. +0
    -18
      templates/accounts/link_sent.html
  10. +3
    -4
      templates/accounts/profile.html
  11. +0
    -13
      templates/emails/change-email-body-html.html
  12. +0
    -11
      templates/emails/change-email-body-text.html
  13. +0
    -2
      templates/emails/change-email-subject.html

+ 0
- 6
hc/accounts/models.py View File

@ -118,12 +118,6 @@ class Profile(models.Model):
}
emails.transfer_request(self.user.email, ctx)
def send_change_email_link(self):
token = self.prepare_token("change-email")
path = reverse("hc-change-email", args=[token])
ctx = {"button_text": "Change Email", "button_url": settings.SITE_ROOT + path}
emails.change_email(self.user.email, ctx)
def send_sms_limit_notice(self, transport):
ctx = {"transport": transport, "limit": self.sms_limit}
if self.sms_limit != 500 and settings.USE_PAYMENTS:


+ 18
- 15
hc/accounts/tests/test_change_email.py View File

@ -1,39 +1,42 @@
from django.contrib.auth.hashers import make_password
from hc.test import BaseTestCase
class ChangeEmailTestCase(BaseTestCase):
def test_it_shows_form(self):
self.profile.token = make_password("foo", "change-email")
self.profile.save()
def test_it_requires_sudo_mode(self):
self.client.login(username="[email protected]", password="password")
r = self.client.get("/accounts/change_email/")
self.assertContains(r, "We have sent a confirmation code")
def test_it_shows_form(self):
self.client.login(username="[email protected]", password="password")
self.set_sudo_flag()
r = self.client.get("/accounts/change_email/foo/")
r = self.client.get("/accounts/change_email/")
self.assertContains(r, "Change Account's Email Address")
def test_it_changes_password(self):
self.profile.token = make_password("foo", "change-email")
self.profile.save()
def test_it_updates_email(self):
self.client.login(username="[email protected]", password="password")
self.set_sudo_flag()
payload = {"email": "[email protected]"}
self.client.post("/accounts/change_email/foo/", payload)
r = self.client.post("/accounts/change_email/", payload, follow=True)
self.assertRedirects(r, "/accounts/change_email/done/")
self.assertContains(r, "Email Address Updated")
self.alice.refresh_from_db()
self.assertEqual(self.alice.email, "[email protected]")
self.assertFalse(self.alice.has_usable_password())
def test_it_requires_unique_email(self):
self.profile.token = make_password("foo", "change-email")
self.profile.save()
# The user should have been logged out:
self.assertNotIn("_auth_user_id", self.client.session)
def test_it_requires_unique_email(self):
self.client.login(username="[email protected]", password="password")
self.set_sudo_flag()
payload = {"email": "[email protected]"}
r = self.client.post("/accounts/change_email/foo/", payload)
r = self.client.post("/accounts/change_email/", payload)
self.assertContains(r, "[email protected] is already registered")
self.alice.refresh_from_db()


+ 0
- 17
hc/accounts/tests/test_profile.py View File

@ -75,23 +75,6 @@ class ProfileTestCase(BaseTestCase):
self.assertEqual(len(mail.outbox), 0)
def test_it_sends_change_email_link(self):
self.client.login(username="[email protected]", password="password")
form = {"change_email": "1"}
r = self.client.post("/accounts/profile/", form)
assert r.status_code == 302
# profile.token should be set now
self.profile.refresh_from_db()
token = self.profile.token
self.assertTrue(len(token) > 10)
# And an email should have been sent
self.assertEqual(len(mail.outbox), 1)
expected_subject = "Change email address on %s" % settings.SITE_NAME
self.assertEqual(mail.outbox[0].subject, expected_subject)
def test_leaving_works(self):
self.client.login(username="[email protected]", password="password")


+ 1
- 1
hc/accounts/tests/test_set_password.py View File

@ -2,7 +2,7 @@ from hc.test import BaseTestCase
class SetPasswordTestCase(BaseTestCase):
def test_it_requires_sudo_mod(self):
def test_it_requires_sudo_mode(self):
self.client.login(username="[email protected]", password="password")
r = self.client.get("/accounts/set_password/")


+ 1
- 2
hc/accounts/urls.py View File

@ -7,7 +7,6 @@ urlpatterns = [
path("logout/", views.logout, name="hc-logout"),
path("signup/", views.signup, name="hc-signup"),
path("login_link_sent/", views.login_link_sent, name="hc-login-link-sent"),
path("link_sent/", views.link_sent, name="hc-link-sent"),
path(
"check_token/<slug:username>/<slug:token>/",
views.check_token,
@ -23,7 +22,7 @@ urlpatterns = [
),
path("set_password/", views.set_password, name="hc-set-password"),
path("change_email/done/", views.change_email_done, name="hc-change-email-done"),
path("change_email/<slug:token>/", views.change_email, name="hc-change-email"),
path("change_email/", views.change_email, name="hc-change-email"),
path("two_factor/add/", views.add_credential, name="hc-add-credential"),
path(
"two_factor/<uuid:code>/remove/",


+ 11
- 21
hc/accounts/views.py View File

@ -186,10 +186,6 @@ def login_link_sent(request):
return render(request, "accounts/login_link_sent.html")
def link_sent(request):
return render(request, "accounts/link_sent.html")
def check_token(request, username, token):
if request.user.is_authenticated and request.user.username == username:
# User is already logged in
@ -235,21 +231,17 @@ def profile(request):
if ctx["removed_credential_name"]:
ctx["2fa_status"] = "info"
if request.method == "POST":
if "change_email" in request.POST:
profile.send_change_email_link()
return redirect("hc-link-sent")
elif "leave_project" in request.POST:
code = request.POST["code"]
try:
project = Project.objects.get(code=code, member__user=request.user)
except Project.DoesNotExist:
return HttpResponseBadRequest()
if request.method == "POST" and "leave_project" in request.POST:
code = request.POST["code"]
try:
project = Project.objects.get(code=code, member__user=request.user)
except Project.DoesNotExist:
return HttpResponseBadRequest()
Member.objects.filter(project=project, user=request.user).delete()
Member.objects.filter(project=project, user=request.user).delete()
ctx["left_project"] = project
ctx["my_projects_status"] = "info"
ctx["left_project"] = project
ctx["my_projects_status"] = "info"
return render(request, "accounts/profile.html", ctx)
@ -486,10 +478,8 @@ def set_password(request):
@login_required
def change_email(request, token):
if not request.profile.check_token(token, "change-email"):
return HttpResponseBadRequest()
@require_sudo_mode
def change_email(request):
if request.method == "POST":
form = forms.ChangeEmailForm(request.POST)
if form.is_valid():


+ 0
- 4
hc/lib/emails.py View File

@ -62,10 +62,6 @@ def transfer_request(to, ctx):
send("transfer-request", to, ctx)
def change_email(to, ctx):
send("change-email", to, ctx)
def alert(to, ctx, headers={}):
send("alert", to, ctx, headers)


+ 31
- 26
templates/accounts/change_email.html View File

@ -20,44 +20,49 @@
</p>
{% if request.user.has_usable_password %}
<p>
Note: Changing the email address will also
<strong>reset your current password</strong>
<p class="alert alert-warning">
<strong>Your password will be reset.</strong>
For security purposes, after updating your email address,
{% site_name %} will also reset your current password
and log you out.
</p>
{% endif %}
{% if request.user.credentials.exists %}
<p class="alert alert-warning">
<strong>Two-factor authentication is active.</strong>
If you are handing this account over to somebody else,
consider disabling two-factor authentication first.
</p>
{% endif %}
</div>
<form class="form-horizontal" method="post">
<form method="post">
{% csrf_token %}
<div class="form-group">
<label class="col-sm-3 control-label">Current Email</label>
<div class="col-sm-9">
<input
type="text"
class="form-control"
disabled
value="{{ request.user.email }}">
</div>
<label class="control-label">Current Email</label>
<input
type="text"
class="form-control input-lg"
disabled
value="{{ request.user.email }}">
</div>
<div class="form-group {{ form.email.css_classes }}">
<label for="ce-email" class="col-sm-3 control-label">New Email</label>
<div class="col-sm-9">
<input
type="email"
class="form-control"
id="ce-email"
name="email"
placeholder="[email protected]">
{% if form.email.errors %}
<div class="help-block">
{{ form.email.errors|join:"" }}
</div>
{% endif %}
<label for="ce-email" class="control-label">New Email</label>
<input
type="email"
class="form-control input-lg"
id="ce-email"
name="email"
placeholder="[email protected]">
{% if form.email.errors %}
<div class="help-block">
{{ form.email.errors|join:"" }}
</div>
{% endif %}
</div>
</div>
<div class="clearfix">


+ 0
- 18
templates/accounts/link_sent.html View File

@ -1,18 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<div class="hc-dialog">
<h1>Email with Instructions Sent!</h1>
<br />
<p>
We've sent you an email with further instructions.
Please check your inbox!
</p>
</div>
</div>
</div>
{% endblock %}

+ 3
- 4
templates/accounts/profile.html View File

@ -42,10 +42,9 @@
Your account's email address is
<code>{{ request.user.email }}</code>
<button
type="submit"
name="change_email"
class="btn btn-default pull-right">Change Email</button>
<a
href="{% url 'hc-change-email' %}"
class="btn btn-default pull-right">Change Email</a>
</p>
<p class="clearfix"></p>
<p>


+ 0
- 13
templates/emails/change-email-body-html.html View File

@ -1,13 +0,0 @@
{% extends "emails/base.html" %}
{% load hc_extras %}
{% block content %}
Hello,<br />
To change the email address for your account on {% site_name %}, please press
the button below:</p>
{% endblock %}
{% block content_more %}
Regards,<br />
The {% site_name %} Team
{% endblock %}

+ 0
- 11
templates/emails/change-email-body-text.html View File

@ -1,11 +0,0 @@
{% load hc_extras %}
Hello,
Here's a link to change the email address for your account on {% site_name %}:
{{ button_url }}
--
Regards,
{% site_name %}

+ 0
- 2
templates/emails/change-email-subject.html View File

@ -1,2 +0,0 @@
{% load hc_extras %}
Change email address on {% site_name %}

Loading…
Cancel
Save