Add a password strength check on the signup page

(imported from commit a44101485e49fd7a7951bda05ba10a021b6d3ee0)
This commit is contained in:
Keegan McAllister 2013-04-03 16:30:36 -04:00
parent 7eb0bf4fc1
commit 07bb220194
5 changed files with 59 additions and 2 deletions

View File

@ -7,6 +7,11 @@ their email address.
Form is validated both client-side using jquery-validate (see signup.js) and server-side. Form is validated both client-side using jquery-validate (see signup.js) and server-side.
{% endcomment %} {% endcomment %}
{% block customhead %}
{{ block.super }}
<script type="text/javascript" src="/static/third/zxcvbn/zxcvbn.js"></script>
{% endblock %}
{% block for_you %}for {% if company_name %} {{company_name}} {% else %} __________ {% endif %} {% endblock %} {% block for_you %}for {% if company_name %} {{company_name}} {% else %} __________ {% endif %} {% endblock %}
{% block portico_content %} {% block portico_content %}
@ -53,6 +58,14 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div class="control-group">
<label class="control-label">Password strength</label>
<div class="controls">
<div class="progress" id="pw_strength_outer">
<div class="bar" id="pw_strength" style="width: 10%;"></div>
</div>
</div>
</div>
<div class="control-group"> <div class="control-group">
<div class="controls"> <div class="controls">

View File

@ -3,13 +3,13 @@
// Global variables, categorized by place of definition. // Global variables, categorized by place of definition.
var globals = var globals =
// Third-party libraries // Third-party libraries
' $ jQuery Spinner Handlebars XDate' ' $ jQuery Spinner Handlebars XDate zxcvbn'
// index.html // index.html
+ ' page_params' + ' page_params'
// common.js // common.js
+ ' status_classes' + ' status_classes password_quality'
// setup.js // setup.js
+ ' csrf_token' + ' csrf_token'

View File

@ -5,3 +5,24 @@ function autofocus(selector) {
$(selector)[0].focus(); $(selector)[0].focus();
}); });
} }
// Return a list of
//
// - A width setting for a graphical password quality indicator.
// - A boolean indicating whether the password is acceptable.
//
// Assumes that zxcvbn.js has been loaded.
//
// This is in common.js because we want to use it from the signup page
// and also from the in-app password change interface.
function password_quality(password) {
var result = zxcvbn(password);
var quality = Math.min(1, Math.log(1 + result.crack_time) / 22);
// Display the password quality score on a progress bar
// which bottoms out at 10% so there's always something
// for the user to see.
var width = ((90 * quality) + 10) + '%';
return [width, result.crack_time >= 1e5];
}

View File

@ -1,4 +1,13 @@
$(function () { $(function () {
// NB: this file is included on multiple pages. In each context,
// some of the jQuery selectors below will return empty lists.
$.validator.addMethod('password', function (value, element) {
var result = password_quality(value);
$('#pw_strength').width(result[0]);
return result[1];
}, 'Password is weak.');
function highlight(class_to_add) { function highlight(class_to_add) {
// Set a class on the enclosing control group. // Set a class on the enclosing control group.
return function (element) { return function (element) {
@ -9,6 +18,9 @@ $(function () {
} }
$('#registration').validate({ $('#registration').validate({
rules: {
id_password: 'password'
},
errorElement: "p", errorElement: "p",
errorPlacement: function (error, element) { errorPlacement: function (error, element) {
// NB: this is called at most once, when the error element // NB: this is called at most once, when the error element
@ -19,6 +31,12 @@ $(function () {
unhighlight: highlight('success') unhighlight: highlight('success')
}); });
$('#id_password').keyup(function () {
// Start validating the password field as soon as the user
// starts typing, not waiting for the first blur.
$('#registration').validate().element('#id_password');
});
$("#send_confirm").validate({ $("#send_confirm").validate({
errorElement: "p", errorElement: "p",
errorPlacement: function (error, element) { errorPlacement: function (error, element) {

View File

@ -108,3 +108,8 @@ img.screenshot{
.integration p { .integration p {
margin-top: 2em; margin-top: 2em;
} }
#pw_strength_outer {
/* Same width as a Bootstrap default text <input> with padding */
width: 220px;
}