mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-11 15:51:19 +00:00
Password strength meter and length check in the "Set Password" form
This commit is contained in:
parent
afaa8767cd
commit
23b197526c
8 changed files with 149 additions and 13 deletions
|
@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Can configure the email integration to only report the "down" events (#231)
|
||||
- Add "Test!" function in the Integrations page (#207)
|
||||
- Rate limiting for the log in attempts
|
||||
- Password strength meter and length check in the "Set Password" form
|
||||
|
||||
## 1.6.0 - 2019-04-01
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ class ReportSettingsForm(forms.Form):
|
|||
|
||||
|
||||
class SetPasswordForm(forms.Form):
|
||||
password = forms.CharField()
|
||||
password = forms.CharField(min_length=8)
|
||||
|
||||
|
||||
class ChangeEmailForm(forms.Form):
|
||||
|
|
49
hc/accounts/tests/test_set_password.py
Normal file
49
hc/accounts/tests/test_set_password.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
from hc.test import BaseTestCase
|
||||
|
||||
|
||||
class SetPasswordTestCase(BaseTestCase):
|
||||
|
||||
def test_it_shows_form(self):
|
||||
token = self.profile.prepare_token("set-password")
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/accounts/set_password/%s/" % token)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.assertContains(r, "Please pick a password")
|
||||
|
||||
def test_it_checks_token(self):
|
||||
self.profile.prepare_token("set-password")
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
# GET
|
||||
r = self.client.get("/accounts/set_password/invalid-token/")
|
||||
self.assertEqual(r.status_code, 400)
|
||||
|
||||
# POST
|
||||
r = self.client.post("/accounts/set_password/invalid-token/")
|
||||
self.assertEqual(r.status_code, 400)
|
||||
|
||||
def test_it_sets_password(self):
|
||||
token = self.profile.prepare_token("set-password")
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
payload = {"password": "correct horse battery staple"}
|
||||
r = self.client.post("/accounts/set_password/%s/" % token, payload)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
old_password = self.alice.password
|
||||
self.alice.refresh_from_db()
|
||||
self.assertNotEqual(self.alice.password, old_password)
|
||||
|
||||
def test_post_checks_length(self):
|
||||
token = self.profile.prepare_token("set-password")
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
payload = {"password": "abc"}
|
||||
r = self.client.post("/accounts/set_password/%s/" % token, payload)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
old_password = self.alice.password
|
||||
self.alice.refresh_from_db()
|
||||
self.assertEqual(self.alice.password, old_password)
|
37
static/css/set_password.css
Normal file
37
static/css/set_password.css
Normal file
|
@ -0,0 +1,37 @@
|
|||
#set-password-group #password {
|
||||
border-color: #ddd;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#meter {
|
||||
margin: 3px 0 20px 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#meter div {
|
||||
background: #ddd;
|
||||
height: 5px;
|
||||
flex: 1;
|
||||
border-radius: 2px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
#meter div:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#meter.score-1 .s1 {
|
||||
background: #FF5252;
|
||||
}
|
||||
|
||||
#meter.score-2 .s2 {
|
||||
background: #FFAB40;
|
||||
}
|
||||
|
||||
#meter.score-3 .s3 {
|
||||
background: #9CCC65;
|
||||
}
|
||||
|
||||
#meter.score-4 .s4 {
|
||||
background: #22bc66;;
|
||||
}
|
8
static/js/set-password.js
Normal file
8
static/js/set-password.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
$(function () {
|
||||
$pw = $("#password");
|
||||
$meter = $("#meter");
|
||||
$pw.on("input", function() {
|
||||
var result = zxcvbn($pw.val());
|
||||
$meter.attr("class", "score-" + result.score);
|
||||
});
|
||||
});
|
28
static/js/zxcvbn.js
Normal file
28
static/js/zxcvbn.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% load hc_extras %}
|
||||
{% load compress hc_extras static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
|
@ -15,17 +15,20 @@
|
|||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-group">
|
||||
<div class="input-group input-group-lg">
|
||||
<div class="input-group-addon">
|
||||
<span class="icon-dots"></span>
|
||||
</div>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
name="password"
|
||||
placeholder="pick a password">
|
||||
</div>
|
||||
<div id="set-password-group" class="form-group">
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
minlength="8"
|
||||
class="form-control input-lg"
|
||||
name="password"
|
||||
placeholder="pick a password (at least 8 characters)">
|
||||
<div id="meter">
|
||||
<div class="s1 s2 s3 s4"></div>
|
||||
<div class="s2 s3 s4"></div>
|
||||
<div class="s3 s4"></div>
|
||||
<div class="s4"></div>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="clearfix">
|
||||
|
@ -38,3 +41,12 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{% compress js %}
|
||||
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||
<script src="{% static 'js/zxcvbn.js' %}"></script>
|
||||
<script src="{% static 'js/set-password.js' %}"></script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<link rel="stylesheet" href="{% static 'css/snippet-copy.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/syntax.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/welcome.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/set_password.css' %}" type="text/css">
|
||||
{% endcompress %}
|
||||
</head>
|
||||
<body class="page-{{ page }}">
|
||||
|
|
Loading…
Add table
Reference in a new issue