blob: 277b4efbaf0bbc466f98fff62217ee597e37be7b [file] [log] [blame]
Marc Kupietz484ec8e2023-02-25 11:23:07 +01001// Example starter JavaScript for disabling form submissions if there are invalid fields
2(function () {
3 'use strict';
4 window.addEventListener('load', function () {
Marc Kupietz87a14312023-03-09 20:39:31 +01005 update_total_due();
Marc Kupietz484ec8e2023-02-25 11:23:07 +01006 // Fetch all the forms we want to apply custom Bootstrap validation styles to
7 var forms = document.getElementsByClassName('needs-validation');
8 // Loop over them and prevent submission
9 var validation = Array.prototype.filter.call(forms, function (form) {
10 form.addEventListener('submit', function (event) {
11 if (form.checkValidity() === false) {
12 event.preventDefault();
13 event.stopPropagation();
14 }
15 form.classList.add('was-validated');
16 }, false);
17 });
18 }, false);
19})();
20
Marc Kupietz87a14312023-03-09 20:39:31 +010021function update_total_due() {
Marc Kupietz79c2b922023-03-08 09:29:11 +010022 var costs = 0;
23
24
25 if ($('#participate').is(":checked")) {
26 costs += parseInt($("#conference_fee").text(),10);
27 if ($('#student').is(":checked")) {
28 costs -= parseInt($("#student_discount").text(), 10);
29 }
30 if ($('#conference_dinner').is(":checked")) {
31 costs += parseInt($("#conference_dinner_price").text(), 10);
32 }
33 }
Marc Kupietz87a14312023-03-09 20:39:31 +010034 $("#total_due").val(costs.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2}));
Marc Kupietz79c2b922023-03-08 09:29:11 +010035}
36
37function update_paper_id_field() {
38 var paper_id = $("#paper_id");
39 if ($('#author').is(":checked")) {
40 paper_id.removeAttr('disabled');
41 paper_id.attr('placeholder', '0000');
42 paper_id.attr('pattern', '\\d{4}');
43 paper_id.attr('required', 'required');
44 } else {
45 paper_id.val('');
46 paper_id.attr('disabled', 'disabled');
47 paper_id.removeAttr('placeholder');
48 paper_id.removeAttr('pattern');
49 paper_id.removeAttr('required');
50 }
51}
Marc Kupietz484ec8e2023-02-25 11:23:07 +010052
53function check_password_match() {
54 pass = $("#pw1").val();
55 pass2 = $("#pw2").val();
56
57 if (pass2.length > 0) {
58 $("#pwconfirm")[0].classList.add('was-validated')
59 if (pass != pass2) {
60 $("#pw2")[0].setCustomValidity("Passwords do not match");
61 } else {
62 $("#pw2")[0].setCustomValidity(""); // is valid
63 }
64 } else {
65 $("#pwconfirm")[0].classList.remove('was-validated')
66 }
67 passUpdated();
68}
69
70TOO_SHORT = 'Password too short, still %% characters needed';
71TOO_LONG = 'Password too long, please remove %% characters';
72INVALID_CHARS = 'Password contains invalid characters';
73QUAL_NONE = 'Password is very weak'
74QUAL_LOW = 'Password is weak';
75QUAL_MEDIUM = 'Password is average'
76QUAL_GOOD = 'Password is good';
77QUAL_STRONG = 'Password is strong';
78REP_OK = 'Repetition ok';
79REP_NE = 'Passwords not identical';
80PWNED = 'Password found in public password list';
81
82String.prototype.strReverse = function () {
83 var newstring = '';
84 for (var s = 0; s < this.length; s++)
85 newstring = this.charAt(s) + newstring;
86 return newstring;
87};
88
89function isPasswordPwned(pass, callback) {
90 const sha1Hash = CryptoJS.enc.Hex.stringify(CryptoJS.SHA1(pass)).toUpperCase();
91 const passwordChunk1 = sha1Hash.substring(0, 5);
92 const passwordChunk2 = sha1Hash.substring(5);
93 $.get('https://api.pwnedpasswords.com/range/' + passwordChunk1).done(function (data, status) {
94 var isPwned = false;
95 if (status == "success") {
96 if (data && data.length) {
97 const chunks = data.split('\r\n');
98 const matches = chunks.filter(s => s.includes(passwordChunk2));
99
100 if (matches.length) {
101 isPwned = true
102 }
103 }
104 callback(isPwned)
105 }
106 });
107}
108
109//var checkTimer;
110
111function passUpdated() {
112 var nScore = 0;
113 var message = '';
114
115 var pass = $('#pw1').val();
116 var pass2 = $('#pw2').val();
117
118 //clearTimeout(checkTimer);
119
120 try {
121 if (!pass)
122 throw '';
123
124 if (pass.match(/[^a-zA-Z0-9!@#$%()_+=:;",.?/-]/))
125 throw INVALID_CHARS;
126
127 var nLength = pass.length;
128 if (nLength < 8)
129 throw TOO_SHORT.replace('%%', 8 - nLength);
130 if (nLength > 20)
131 throw TOO_LONG.replace('%%', nLength - 20);
132
133 nScore = 4 * nLength;
134
135 // check for upper-/lowercase, numeric and special chars pattern matches
136 var nAlphaUC = 0, nAlphaLC = 0, nNumber = 0, nSpecial = 0;
137 var nMidChar = 0, nRepChar = 0, nRepInc = 0;
138 var nConsecAlphaUC = 0, nConsecAlphaLC = 0, nConsecNumber = 0;
139 var nTmpAlphaUC = '', nTmpAlphaLC = '', nTmpNumber = '';
140 for (var i = 0; i < nLength; i++) {
141 if (pass[i].match(/[A-Z]/g)) { // uppercase characters
142 if (nTmpAlphaUC !== '' && (nTmpAlphaUC + 1) == i) {
143 nConsecAlphaUC++;
144 }
145 nTmpAlphaUC = i;
146 nAlphaUC++;
147 } else if (pass[i].match(/[a-z]/g)) { // lowercase characters
148 if (nTmpAlphaLC !== '' && (nTmpAlphaLC + 1) == i) {
149 nConsecAlphaLC++;
150 }
151 nTmpAlphaLC = i;
152 nAlphaLC++;
153 } else if (pass[i].match(/[0-9]/g)) { // numbers
154 if (i > 0 && i < (nLength - 1)) {
155 nMidChar++;
156 }
157 if (nTmpNumber !== '' && (nTmpNumber + 1) == i) {
158 nConsecNumber++;
159 }
160 nTmpNumber = i;
161 nNumber++;
162 } else { // special characters
163 if (i > 0 && i < (nLength - 1)) {
164 nMidChar++;
165 }
166 nSpecial++;
167 }
168
169 // check for repeated characters
170 var bCharExists = false;
171 for (var j = 0; j < nLength; j++) {
172 if (pass[i] == pass[j] && i != j) {
173 bCharExists = true;
174 nRepInc += Math.abs(nLength / (j - i));
175 }
176 }
177 if (bCharExists) {
178 nRepChar++;
179 var nUnqChar = nLength - nRepChar;
180 nRepInc = (nUnqChar) ? Math.ceil(nRepInc / nUnqChar) : Math.ceil(nRepInc);
181 }
182 }
183
184 // check for sequential alpha string patterns (forward and reverse)
185 var sAlphas = "abcdefghijklmnopqrstuvwxyz";
186 var nSeqAlpha = 0;
187 for (var i = 0; i < 23; i++) {
188 var sFwd = sAlphas.substring(i, i + 3);
189 var sRev = sFwd.strReverse();
190 if (pass.toLowerCase().indexOf(sFwd) != -1
191 || pass.toLowerCase().indexOf(sRev) != -1)
192 nSeqAlpha++;
193 }
194
195 // check for sequential numeric string patterns (forward and reverse)
196 var sNumerics = "01234567890";
197 var nSeqNumber = 0;
198 for (var i = 0; i < 8; i++) {
199 var sFwd = sNumerics.substring(i, i + 3);
200 var sRev = sFwd.strReverse();
201 if (pass.toLowerCase().indexOf(sFwd) != -1
202 || pass.toLowerCase().indexOf(sRev) != -1)
203 nSeqNumber++;
204 }
205
206 // general point assignment
207 if (nAlphaUC > 0 && nAlphaUC < nLength) // uppercase characters
208 nScore += 2 * (nLength - nAlphaUC);
209 if (nAlphaLC > 0 && nAlphaLC < nLength) // lowercase characters
210 nScore += 2 * (nLength - nAlphaLC);
211 if (nNumber > 0 && nNumber < nLength) // numbers
212 nScore += 2 * nNumber;
213 if (nSpecial > 0) // special characters
214 nScore += 4 * nSpecial;
215 if (nMidChar > 0) // mid numbers/special characters
216 nScore += 2 * nMidChar;
217
218 // point deductions for poor practices
219 if ((nAlphaLC > 0 || nAlphaUC > 0)
220 && nSpecial === 0 && nNumber === 0) // characters only
221 nScore -= nLength;
222 if (nAlphaLC === 0 && nAlphaUC === 0
223 && nSpecial === 0 && nNumber > 0) // numbers only
224 nScore -= nLength;
225 if (nRepChar > 0) // same character exists more than once
226 nScore -= nRepInc;
227 if (nConsecAlphaUC > 0) // consecutive uppercase letters exist
228 nScore -= 2 * nConsecAlphaUC;
229 if (nConsecAlphaLC > 0) // consecutive lowercase letters exist
230 nScore -= 2 * nConsecAlphaLC;
231 if (nConsecNumber > 0) // consecutive numbers exist
232 nScore -= 2 * nConsecNumber;
233 if (nSeqAlpha > 0) // sequential alpha strings exist (3 chars or more)
234 nScore -= 3 * nSeqAlpha;
235 if (nSeqNumber > 0) // sequential numeric strings exist (3 chars or more)
236 nScore -= 3 * nSeqNumber;
237
238 // determine if mandatory requirements have been met
239 var arrChars = [nAlphaUC, nAlphaLC, nNumber, nSpecial];
240 var nReqChar = 0;
241 for (var i = 0; i < arrChars.length; i++) {
242 if (arrChars[i]) {
243 nReqChar++;
244 }
245 }
246 if (nReqChar >= arrChars.length)
247 nScore += 2 * nReqChar;
248 else if (nReqChar < arrChars.length - 1)
249 nScore -= 2 * nReqChar;
250
251 // limit points to 3..100
252 nScore = Math.max(3, Math.min(nScore, 100));
253
254 // set message according to points
255 if (nScore >= 80)
256 message = QUAL_STRONG;
257 else if (nScore >= 60)
258 message = QUAL_GOOD;
259 else if (nScore >= 40)
260 message = QUAL_MEDIUM;
261 else if (nScore >= 10)
262 message = QUAL_LOW;
263 else
264 message = QUAL_NONE;
265 } catch (error) {
266 nScore = 3;
267 message = error;
268 }
269 /*
270 if (pass.length > 0 && pass2.length > 0) {
271 message+=' / ';
272 message+=(pass == pass2) ? REP_OK : REP_NE;
273 }
274 */
275 $('#pwqinfo').val(message);
276
277 var progress = $('#pwqbar');
278 progress.width(nScore + '%');
279 progress.attr('aria-valuenow', nScore);
280 if (nScore >= 60)
281 progress.removeClass('bg-danger bg-warning').addClass('bg-success');
282 else if (nScore >= 40)
283 progress.removeClass('bg-danger bg-success').addClass('bg-warning');
284 else
285 progress.removeClass('bg-warning bg-success').addClass('bg-danger');
286
287 if (nScore >= 40) {
288 $("#password-div")[0].classList.add('was-validated');
289 $('#btn_change').prop('disabled', pass !== pass2);
290 $("#pw1")[0].setCustomValidity("");
291 isPasswordPwned(pass, function (isPwned) {
292 if (isPwned) {
293 $('#pwqinfo').val(PWNED);
294 progress.removeClass().addClass('low');
295 progress.val(3);
296 $("#pw1")[0].setCustomValidity("Password is pwned");
297 }
298 });
299 } else {
300 $("#password-div")[0].classList.add('was-validated');
301 $('#btn_change').prop('disabled', 1);
302 $("#pw1")[0].setCustomValidity("Password is to week");
303 }
304
305}