|
1 | 1 | {% extends 'base.html' %}
|
2 | 2 | {% load i18n %}
|
3 | 3 | {% load socialaccount %}
|
| 4 | +{% block head %} |
| 5 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js" integrity="sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> |
| 6 | +{% endblock %} |
4 | 7 | {% block subtitle %}{{ auth|title }}{% endblock %}
|
5 | 8 | {% block container %}
|
6 | 9 | <div class="row justify-content-md-center" style="margin: 0">
|
|
10 | 13 | {% endif %}
|
11 | 14 | <div class="bg-{{ theme }} text-{% if theme == 'dark' %}white{% else %}black{% endif %}">
|
12 | 15 | {% if not blocked_message %}
|
13 |
| - <form method="post"> |
| 16 | + <form method="post" id="auth-form"> |
14 | 17 | {% csrf_token %}
|
15 | 18 | <div class="content p-4">
|
16 | 19 | {% if auth != 'register' %}
|
|
55 | 58 | </div>
|
56 | 59 | </div>
|
57 | 60 | </div>
|
| 61 | + <script> |
| 62 | + $(document).ready(() => { |
| 63 | + {% if auth == 'register' %} |
| 64 | + let min_chars = {{ auth_password_validators.min_characters|default:8 }}; |
| 65 | + let min_digits = {{ auth_password_validators.min_length_digit|default:0 }}; |
| 66 | + let min_special = {{ auth_password_validators.min_length_special|default:0 }}; |
| 67 | + let special = '{{ auth_password_validators.special_characters|default:'' }}'; |
| 68 | + let min_lower = {{ auth_password_validators.min_length_lower|default:0 }}; |
| 69 | + let min_upper = {{ auth_password_validators.min_length_upper|default:0 }}; |
| 70 | + function check_password_requirements(password_input, password_text) { |
| 71 | + let password = password_input.val() |
| 72 | + if (password.length < min_chars || |
| 73 | + (password.match('[0-9]')?.length ?? 0) < min_digits || |
| 74 | + (password.match({{ auth_password_validators.special_characters|default:'' }})?.length ?? 0) < min_special || |
| 75 | + (password.match('[a-z]')?.length ?? 0) < min_lower || |
| 76 | + (password.match('[A-Z]')?.length ?? 0) < min_upper) { |
| 77 | + password_input.addClass('is-invalid') |
| 78 | + password_text.removeClass('text-success list-check') |
| 79 | + password_text.addClass('text-danger list-cross') |
| 80 | + return false |
| 81 | + } |
| 82 | + password_input.removeClass('is-invalid') |
| 83 | + password_text.addClass('text-success list-check') |
| 84 | + password_text.removeClass('text-danger list-cross') |
| 85 | + return true |
| 86 | + } |
| 87 | + let special_to_see = special.slice(special.indexOf('[') + 1, special.lastIndexOf(']')) |
| 88 | + let help_text = $(`<ul><li>This password be ${min_chars} must contain at least ${min_digits} digit, ${min_lower} lower case letter, ${min_upper} upper case letter, ${min_special} special character, such as ${special_to_see}.</li><ul>`) |
| 89 | + $('.form-text > ul').css('margin', '0') |
| 90 | + $('.form-text').append(help_text) |
| 91 | + let password_input = $('#id_password1') |
| 92 | + let password_input_repeat = $('#id_password2') |
| 93 | + password_input.keyup(() => { |
| 94 | + check_password_requirements(password_input, help_text) |
| 95 | + if (password_input.val() !== password_input_repeat.val()) { |
| 96 | + password_input_repeat.addClass('is-invalid') |
| 97 | + } else { |
| 98 | + password_input_repeat.removeClass('is-invalid') |
| 99 | + } |
| 100 | + }) |
| 101 | + password_input_repeat.keyup(() => { |
| 102 | + if (password_input.val() !== password_input_repeat.val()) { |
| 103 | + password_input_repeat.addClass('is-invalid') |
| 104 | + } else { |
| 105 | + password_input_repeat.removeClass('is-invalid') |
| 106 | + } |
| 107 | + }) |
| 108 | + {% endif %} |
| 109 | + async function digestMessage(message) { |
| 110 | + const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array |
| 111 | + const hashBuffer = await crypto.subtle.digest("SHA-512", msgUint8); // hash the message |
| 112 | + const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array |
| 113 | + const hashHex = hashArray |
| 114 | + .map((b) => b.toString(16).padStart(2, "0")) |
| 115 | + .join(""); // convert bytes to hex string |
| 116 | + return hashHex; |
| 117 | + } |
| 118 | + async function hash_password_inputs(password_inputs_id) { |
| 119 | + for (const password_input_id of password_inputs_id) { |
| 120 | + let password_input = $('#' + password_input_id) |
| 121 | + if (password_input.length > 0) { |
| 122 | + let text = window.location.hostname + ':' + password_input.val() |
| 123 | + let hash = await digestMessage(text) |
| 124 | + password_input.val(hash) |
| 125 | + } |
| 126 | + } |
| 127 | + } |
| 128 | + let hashed = false |
| 129 | + $('#auth-form').submit((event) => { |
| 130 | + {% if auth == 'register' %} |
| 131 | + if (!check_password_requirements(password_input, help_text) || password_input.val() !== password_input_repeat.val()) { |
| 132 | + event.preventDefault() |
| 133 | + return |
| 134 | + } |
| 135 | + {% endif %} |
| 136 | + if (hashed) { |
| 137 | + hashed = false |
| 138 | + return |
| 139 | + } |
| 140 | + event.preventDefault() |
| 141 | + hash_password_inputs(['id_password', 'id_password2', 'id_password1']).then(() => { |
| 142 | + hashed = true |
| 143 | + event.target.submit() |
| 144 | + }) |
| 145 | + }) |
| 146 | + }) |
| 147 | + </script> |
58 | 148 | {% endblock %}
|
0 commit comments