datatracker/ietf/static/js/password_strength.js
Lars Eggert 9d5d9d5172
fix: replace deprecated bootstrap things (#5858)
* text-muted -> text-body-secondary

* navbar-dark is deprecated

* Remove FIXME block, not an issue anymore

* Remove `navbar-light`
2023-07-18 12:22:28 -05:00

189 lines
7.8 KiB
JavaScript

// Taken from django-password-strength, with changes to use the bower-managed zxcvbn.js The
// bower-managed zxcvbn.js is kept up-to-date to a larger extent than the copy packaged with
// the django-password-strength component.
(function ($, window, document, undefined) {
window.djangoPasswordStrength = {
config: {
passwordClass: 'password_strength',
confirmationClass: 'password_confirmation'
},
init: function (config) {
var self = this;
// Setup configuration
if ($.isPlainObject(config)) {
$.extend(self.config, config);
}
// Fix the initial widget for bootstrap 5
var widget = $("." + self.config.passwordClass)
.closest("form");
widget
.find(".hidden")
.addClass("d-none")
.removeClass("hidden");
widget
.find(".label")
.addClass("badge rounded-pill")
.removeClass("label");
widget
.find(".label-danger")
.addClass("bg-danger")
.removeClass("label-danger");
widget
.find(".text-body-secondary")
.addClass("form-text")
.removeClass("text-body-secondary");
self.initListeners();
},
initListeners: function () {
var self = this;
$('.' + self.config.passwordClass)
.on('keyup', function () {
var password_strength_bar = $(this)
.parent()
.find('.password_strength_bar');
var password_strength_info = $(this)
.parent()
.find('.password_strength_info');
var password_strength_offline_info = $(this)
.parent()
.parent()
.parent()
.find('.password_strength_offline_info');
if ($(this)
.val()) {
var result = zxcvbn($(this)
.val());
if (result.score < 3) {
password_strength_bar.removeClass('bg-success')
.addClass('bg-warning');
password_strength_info.find('.badge')
.removeClass('d-none');
} else {
password_strength_bar.removeClass('bg-warning')
.addClass('bg-success');
password_strength_info.find('.badge')
.addClass('d-none');
}
password_strength_bar.width(((result.score + 1) / 5) * 100 + '%')
.attr('aria-valuenow', result.score + 1);
// henrik@levkowetz.com -- this is the only changed line:
password_strength_info.find('.password_strength_time')
.html(result.crack_times_display.online_no_throttling_10_per_second);
password_strength_info.removeClass('d-none');
password_strength_offline_info.find('.password_strength_time')
.html(result.crack_times_display.offline_slow_hashing_1e4_per_second);
password_strength_offline_info.removeClass('d-none');
} else {
password_strength_bar.removeClass('bg-success')
.addClass('bg-warning');
password_strength_bar.width('0%')
.attr('aria-valuenow', 0);
password_strength_info.addClass('d-none');
}
self.match_passwords($(this));
});
var timer = null;
$('.' + self.config.confirmationClass)
.on('keyup', function () {
var password_field;
var confirm_with = $(this)
.data('confirm-with');
if (confirm_with) {
password_field = $('#' + confirm_with);
} else {
password_field = $('.' + self.config.passwordClass);
}
if (timer !== null) clearTimeout(timer);
timer = setTimeout(function () {
self.match_passwords(password_field);
}, 400);
});
},
display_time: function (seconds) {
var minute = 60;
var hour = minute * 60;
var day = hour * 24;
var month = day * 31;
var year = month * 12;
var century = year * 100;
// Provide fake gettext for when it is not available
if (typeof gettext !== 'function') { gettext = function (text) { return text; }; }
if (seconds < minute) return gettext('only an instant');
if (seconds < hour) return (1 + Math.ceil(seconds / minute)) + ' ' + gettext('minutes');
if (seconds < day) return (1 + Math.ceil(seconds / hour)) + ' ' + gettext('hours');
if (seconds < month) return (1 + Math.ceil(seconds / day)) + ' ' + gettext('days');
if (seconds < year) return (1 + Math.ceil(seconds / month)) + ' ' + gettext('months');
if (seconds < century) return (1 + Math.ceil(seconds / year)) + ' ' + gettext('years');
return gettext('centuries');
},
match_passwords: function (password_field, confirmation_fields) {
var self = this;
// Optional parameter: if no specific confirmation field is given, check all
if (confirmation_fields === undefined) { confirmation_fields = $('.' + self.config.confirmationClass); }
if (confirmation_fields === undefined) { return; }
var password = password_field.val();
confirmation_fields.each(function (index, confirm_field) {
var confirm_value = $(confirm_field)
.val();
var confirm_with = $(confirm_field)
.data('confirm-with');
if (confirm_with && confirm_with == password_field.attr('id')) {
if (confirm_value && password) {
if (confirm_value === password) {
$(confirm_field)
.parent()
.find('.password_strength_info')
.addClass('d-none');
} else {
$(confirm_field)
.parent()
.find('.password_strength_info')
.removeClass('d-none');
}
} else {
$(confirm_field)
.parent()
.find('.password_strength_info')
.addClass('d-none');
}
}
});
// If a password field other than our own has been used, add the listener here
if (!password_field.hasClass(self.config.passwordClass) && !password_field.data('password-listener')) {
password_field.on('keyup', function () {
self.match_passwords($(this));
});
password_field.data('password-listener', true);
}
}
};
// Call the init for backwards compatibility
djangoPasswordStrength.init();
})(jQuery, window, document);