|
1 | | -/* global owaspPasswordStrengthTest, TextEncoder, crypto */ |
| 1 | +/* global owaspPasswordStrengthTest, TextEncoder, crypto, fetch */ |
2 | 2 | (function () { |
3 | 3 | 'use strict' |
4 | 4 |
|
5 | | - var PasswordValidator = function (passwordField, repeatedPasswordField) { |
| 5 | + const PasswordValidator = function (passwordField, repeatedPasswordField) { |
6 | 6 | if ( |
7 | 7 | passwordField === null || passwordField === undefined || |
8 | 8 | repeatedPasswordField === null || repeatedPasswordField === undefined |
|
20 | 20 | this.errors = [] |
21 | 21 | } |
22 | 22 |
|
23 | | - PasswordValidator.prototype.FEEDBACK_SUCCESS = 'success' |
24 | | - PasswordValidator.prototype.FEEDBACK_WARNING = 'warning' |
25 | | - PasswordValidator.prototype.FEEDBACK_ERROR = 'error' |
| 23 | + const FEEDBACK_SUCCESS = 'success' |
| 24 | + const FEEDBACK_WARNING = 'warning' |
| 25 | + const FEEDBACK_ERROR = 'error' |
26 | 26 |
|
27 | | - PasswordValidator.prototype.ICON_SUCCESS = 'glyphicon-ok' |
28 | | - PasswordValidator.prototype.ICON_WARNING = 'glyphicon-warning-sign' |
29 | | - PasswordValidator.prototype.ICON_ERROR = 'glyphicon-remove' |
| 27 | + const ICON_SUCCESS = 'glyphicon-ok' |
| 28 | + const ICON_WARNING = 'glyphicon-warning-sign' |
| 29 | + const ICON_ERROR = 'glyphicon-remove' |
30 | 30 |
|
31 | | - PasswordValidator.prototype.VALIDATION_SUCCESS = 'has-success' |
32 | | - PasswordValidator.prototype.VALIDATION_WARNING = 'has-warning' |
33 | | - PasswordValidator.prototype.VALIDATION_ERROR = 'has-error' |
| 31 | + const VALIDATION_SUCCESS = 'has-success' |
| 32 | + const VALIDATION_WARNING = 'has-warning' |
| 33 | + const VALIDATION_ERROR = 'has-error' |
34 | 34 |
|
35 | | - PasswordValidator.prototype.STRENGTH_PROGRESS_0 = 'progress-bar-danger level-0' |
36 | | - PasswordValidator.prototype.STRENGTH_PROGRESS_1 = 'progress-bar-danger level-1' |
37 | | - PasswordValidator.prototype.STRENGTH_PROGRESS_2 = 'progress-bar-warning level-2' |
38 | | - PasswordValidator.prototype.STRENGTH_PROGRESS_3 = 'progress-bar-success level-3' |
39 | | - PasswordValidator.prototype.STRENGTH_PROGRESS_4 = 'progress-bar-success level-4' |
| 35 | + const STRENGTH_PROGRESS_0 = 'progress-bar-danger level-0' |
| 36 | + const STRENGTH_PROGRESS_1 = 'progress-bar-danger level-1' |
| 37 | + const STRENGTH_PROGRESS_2 = 'progress-bar-warning level-2' |
| 38 | + const STRENGTH_PROGRESS_3 = 'progress-bar-success level-3' |
| 39 | + const STRENGTH_PROGRESS_4 = 'progress-bar-success level-4' |
40 | 40 |
|
41 | 41 | /** |
42 | 42 | * Prefetch all dom nodes at initialisation in order to gain time at execution since DOM manipulations |
|
77 | 77 | * Validate password on the fly to provide the user a visual strength meter |
78 | 78 | */ |
79 | 79 | PasswordValidator.prototype.instantFeedbackForPassword = function () { |
80 | | - var passwordStrength = this.getPasswordStrength(this.passwordField.value) |
81 | | - var strengthLevel = this.getStrengthLevel(passwordStrength) |
| 80 | + const passwordStrength = this.getPasswordStrength(this.passwordField.value) |
| 81 | + const strengthLevel = this.getStrengthLevel(passwordStrength) |
82 | 82 |
|
83 | 83 | if (this.currentStrengthLevel === strengthLevel) { |
84 | 84 | return |
|
98 | 98 | */ |
99 | 99 | PasswordValidator.prototype.validatePassword = function () { |
100 | 100 | this.errors = [] |
101 | | - var password = this.passwordField.value |
102 | | - var passwordStrength = this.getPasswordStrength(password) |
| 101 | + const password = this.passwordField.value |
| 102 | + const passwordStrength = this.getPasswordStrength(password) |
103 | 103 | this.currentStrengthLevel = this.getStrengthLevel(passwordStrength) |
104 | 104 |
|
105 | 105 | if (passwordStrength.errors) { |
|
135 | 135 | } |
136 | 136 |
|
137 | 137 | PasswordValidator.prototype.setPasswordFeedback = function () { |
138 | | - var feedback = this.getFeedbackFromLevel() |
| 138 | + const feedback = this.getFeedbackFromLevel() |
139 | 139 | this.updateStrengthMeter() |
140 | 140 | this.displayPasswordErrors() |
141 | 141 | this.setFeedbackForField(feedback, this.passwordField) |
|
145 | 145 | * Update the repeated password feedback icon and color |
146 | 146 | */ |
147 | 147 | PasswordValidator.prototype.updateRepeatedPasswordFeedback = function () { |
148 | | - var feedback = this.checkPasswordFieldsEquality() ? this.FEEDBACK_SUCCESS : this.FEEDBACK_ERROR |
| 148 | + const feedback = this.checkPasswordFieldsEquality() ? FEEDBACK_SUCCESS : FEEDBACK_ERROR |
149 | 149 | this.setFeedbackForField(feedback, this.repeatedPasswordField) |
150 | 150 | } |
151 | 151 |
|
|
155 | 155 | * @param {HTMLElement} field |
156 | 156 | */ |
157 | 157 | PasswordValidator.prototype.setFeedbackForField = function (feedback, field) { |
158 | | - var formGroup = this.getFormGroupElementForField(field) |
159 | | - var visualFeedback = this.getFeedbackElementForField(field) |
| 158 | + const formGroup = this.getFormGroupElementForField(field) |
| 159 | + const visualFeedback = this.getFeedbackElementForField(field) |
160 | 160 |
|
161 | 161 | this.resetValidation(formGroup) |
162 | 162 | this.resetFeedbackIcon(visualFeedback) |
|
218 | 218 | return 4 |
219 | 219 | } |
220 | 220 |
|
221 | | - PasswordValidator.prototype.LEVEL_TO_FEEDBACK_MAP = [] |
222 | | - PasswordValidator.prototype.LEVEL_TO_FEEDBACK_MAP[0] = PasswordValidator.prototype.LEVEL_TO_FEEDBACK_MAP[1] = PasswordValidator.prototype.FEEDBACK_ERROR |
223 | | - PasswordValidator.prototype.LEVEL_TO_FEEDBACK_MAP[2] = PasswordValidator.prototype.FEEDBACK_WARNING |
224 | | - PasswordValidator.prototype.LEVEL_TO_FEEDBACK_MAP[3] = PasswordValidator.prototype.LEVEL_TO_FEEDBACK_MAP[4] = PasswordValidator.prototype.FEEDBACK_SUCCESS |
| 221 | + PasswordValidator.prototype.LEVEL_TO_FEEDBACK_MAP = [ |
| 222 | + FEEDBACK_ERROR, |
| 223 | + FEEDBACK_ERROR, |
| 224 | + FEEDBACK_WARNING, |
| 225 | + FEEDBACK_SUCCESS, |
| 226 | + FEEDBACK_SUCCESS |
| 227 | + ] |
225 | 228 |
|
226 | 229 | /** |
227 | 230 | * @returns {string} |
|
230 | 233 | return this.LEVEL_TO_FEEDBACK_MAP[this.currentStrengthLevel] |
231 | 234 | } |
232 | 235 |
|
233 | | - PasswordValidator.prototype.LEVEL_TO_PROGRESS_MAP = [] |
234 | | - PasswordValidator.prototype.LEVEL_TO_PROGRESS_MAP[0] = PasswordValidator.prototype.STRENGTH_PROGRESS_0 |
235 | | - PasswordValidator.prototype.LEVEL_TO_PROGRESS_MAP[1] = PasswordValidator.prototype.STRENGTH_PROGRESS_1 |
236 | | - PasswordValidator.prototype.LEVEL_TO_PROGRESS_MAP[2] = PasswordValidator.prototype.STRENGTH_PROGRESS_2 |
237 | | - PasswordValidator.prototype.LEVEL_TO_PROGRESS_MAP[3] = PasswordValidator.prototype.STRENGTH_PROGRESS_3 |
238 | | - PasswordValidator.prototype.LEVEL_TO_PROGRESS_MAP[4] = PasswordValidator.prototype.STRENGTH_PROGRESS_4 |
| 236 | + PasswordValidator.prototype.LEVEL_TO_PROGRESS_MAP = [ |
| 237 | + STRENGTH_PROGRESS_0, |
| 238 | + STRENGTH_PROGRESS_1, |
| 239 | + STRENGTH_PROGRESS_2, |
| 240 | + STRENGTH_PROGRESS_3, |
| 241 | + STRENGTH_PROGRESS_4 |
| 242 | + ] |
239 | 243 |
|
240 | 244 | /** |
241 | 245 | * Get the CSS class for the meter based on the current level |
|
245 | 249 | } |
246 | 250 |
|
247 | 251 | PasswordValidator.prototype.addPasswordError = function (error) { |
248 | | - if (Array.isArray(error)) { |
249 | | - for (var i = 0, ln = error.length; i < ln; i++) { |
250 | | - this.addPasswordError(error[i]) |
251 | | - } |
252 | | - return |
253 | | - } |
254 | | - |
255 | | - this.errors.push(error) |
| 252 | + this.errors.push(...(Array.isArray(error) ? error : [error])) |
256 | 253 | } |
257 | 254 |
|
258 | 255 | PasswordValidator.prototype.displayPasswordErrors = function () { |
259 | | - this.passwordHelpText.innerHTML = '<p>' + this.errors.join('</p><p>') + '</p>' |
| 256 | + // Erase the error list content |
| 257 | + while (this.passwordHelpText.firstChild) { |
| 258 | + this.passwordHelpText.removeChild(this.passwordHelpText.firstChild) |
| 259 | + } |
| 260 | + |
| 261 | + // Add the errors in the stack to the DOM |
| 262 | + this.errors.map((error) => { |
| 263 | + let text = document.createTextNode(error) |
| 264 | + let paragraph = document.createElement('p') |
| 265 | + paragraph.appendChild(text) |
| 266 | + this.passwordHelpText.appendChild(paragraph) |
| 267 | + }) |
260 | 268 | } |
261 | 269 |
|
262 | 270 | PasswordValidator.prototype.FEEDBACK_TO_ICON_MAP = [] |
263 | | - PasswordValidator.prototype.FEEDBACK_TO_ICON_MAP[PasswordValidator.prototype.FEEDBACK_SUCCESS] = PasswordValidator.prototype.ICON_SUCCESS |
264 | | - PasswordValidator.prototype.FEEDBACK_TO_ICON_MAP[PasswordValidator.prototype.FEEDBACK_WARNING] = PasswordValidator.prototype.ICON_WARNING |
265 | | - PasswordValidator.prototype.FEEDBACK_TO_ICON_MAP[PasswordValidator.prototype.FEEDBACK_ERROR] = PasswordValidator.prototype.ICON_ERROR |
| 271 | + PasswordValidator.prototype.FEEDBACK_TO_ICON_MAP[FEEDBACK_SUCCESS] = ICON_SUCCESS |
| 272 | + PasswordValidator.prototype.FEEDBACK_TO_ICON_MAP[FEEDBACK_WARNING] = ICON_WARNING |
| 273 | + PasswordValidator.prototype.FEEDBACK_TO_ICON_MAP[FEEDBACK_ERROR] = ICON_ERROR |
266 | 274 |
|
267 | 275 | /** |
268 | 276 | * @param success|error|warning feedback |
|
272 | 280 | } |
273 | 281 |
|
274 | 282 | PasswordValidator.prototype.FEEDBACK_TO_VALIDATION_MAP = [] |
275 | | - PasswordValidator.prototype.FEEDBACK_TO_VALIDATION_MAP[PasswordValidator.prototype.FEEDBACK_SUCCESS] = PasswordValidator.prototype.VALIDATION_SUCCESS |
276 | | - PasswordValidator.prototype.FEEDBACK_TO_VALIDATION_MAP[PasswordValidator.prototype.FEEDBACK_WARNING] = PasswordValidator.prototype.VALIDATION_WARNING |
277 | | - PasswordValidator.prototype.FEEDBACK_TO_VALIDATION_MAP[PasswordValidator.prototype.FEEDBACK_ERROR] = PasswordValidator.prototype.VALIDATION_ERROR |
| 283 | + PasswordValidator.prototype.FEEDBACK_TO_VALIDATION_MAP[FEEDBACK_SUCCESS] = VALIDATION_SUCCESS |
| 284 | + PasswordValidator.prototype.FEEDBACK_TO_VALIDATION_MAP[FEEDBACK_WARNING] = VALIDATION_WARNING |
| 285 | + PasswordValidator.prototype.FEEDBACK_TO_VALIDATION_MAP[FEEDBACK_ERROR] = VALIDATION_ERROR |
278 | 286 |
|
279 | 287 | /** |
280 | 288 | * @param success|error|warning feedback |
|
300 | 308 | * @param password |
301 | 309 | */ |
302 | 310 | PasswordValidator.prototype.checkLeakedPassword = function (password) { |
303 | | - var url = 'https://api.pwnedpasswords.com/range/' |
| 311 | + const url = 'https://api.pwnedpasswords.com/range/' |
304 | 312 |
|
305 | 313 | return new Promise(function (resolve, reject) { |
306 | 314 | this.sha1(password).then((digest) => { |
307 | | - var preFix = digest.slice(0, 5) |
308 | | - var suffix = digest.slice(5, digest.length) |
| 315 | + const preFix = digest.slice(0, 5) |
| 316 | + let suffix = digest.slice(5, digest.length) |
309 | 317 | suffix = suffix.toUpperCase() |
310 | 318 |
|
311 | 319 | return fetch(url + preFix) |
|
335 | 343 | * CSS Classes reseters |
336 | 344 | */ |
337 | 345 |
|
338 | | - |
339 | 346 | PasswordValidator.prototype.resetValidation = function (el) { |
340 | | - var tokenizedClasses = this.tokenize( |
341 | | - this.VALIDATION_ERROR, |
342 | | - this.VALIDATION_WARNING, |
343 | | - this.VALIDATION_SUCCESS |
| 347 | + const tokenizedClasses = this.tokenize( |
| 348 | + VALIDATION_ERROR, |
| 349 | + VALIDATION_WARNING, |
| 350 | + VALIDATION_SUCCESS |
344 | 351 | ) |
345 | 352 |
|
346 | 353 | el.classList.remove.apply( |
|
350 | 357 | } |
351 | 358 |
|
352 | 359 | PasswordValidator.prototype.resetFeedbackIcon = function (el) { |
353 | | - var tokenizedClasses = this.tokenize( |
354 | | - this.ICON_ERROR, |
355 | | - this.ICON_WARNING, |
356 | | - this.ICON_SUCCESS |
| 360 | + const tokenizedClasses = this.tokenize( |
| 361 | + ICON_ERROR, |
| 362 | + ICON_WARNING, |
| 363 | + ICON_SUCCESS |
357 | 364 | ) |
358 | 365 |
|
359 | 366 | el.classList.remove.apply( |
|
363 | 370 | } |
364 | 371 |
|
365 | 372 | PasswordValidator.prototype.resetStrengthMeter = function () { |
366 | | - var tokenizedClasses = this.tokenize( |
367 | | - this.STRENGTH_PROGRESS_1, |
368 | | - this.STRENGTH_PROGRESS_2, |
369 | | - this.STRENGTH_PROGRESS_3, |
370 | | - this.STRENGTH_PROGRESS_4 |
| 373 | + const tokenizedClasses = this.tokenize( |
| 374 | + STRENGTH_PROGRESS_1, |
| 375 | + STRENGTH_PROGRESS_2, |
| 376 | + STRENGTH_PROGRESS_3, |
| 377 | + STRENGTH_PROGRESS_4 |
371 | 378 | ) |
372 | 379 |
|
373 | 380 | this.passwordStrengthMeter.classList.remove.apply( |
|
405 | 412 | * @returns {string[]} |
406 | 413 | */ |
407 | 414 | PasswordValidator.prototype.tokenize = function () { |
408 | | - var tokenArray = [] |
409 | | - for (var i in arguments) { |
| 415 | + let tokenArray = [] |
| 416 | + for (let i in arguments) { |
410 | 417 | tokenArray.push(arguments[i]) |
411 | 418 | } |
412 | 419 | return tokenArray.join(' ').split(' ') |
|
415 | 422 | PasswordValidator.prototype.sha1 = function (str) { |
416 | 423 | let buffer = new TextEncoder('utf-8').encode(str) |
417 | 424 |
|
418 | | - return crypto.subtle.digest('SHA-1', buffer).then(function (hash) { |
| 425 | + return crypto.subtle.digest('SHA-1', buffer).then((hash) => { |
419 | 426 | return this.hex(hash) |
420 | | - }.bind(this)) |
| 427 | + }) |
421 | 428 | } |
422 | 429 |
|
423 | 430 | PasswordValidator.prototype.hex = function (buffer) { |
|
0 commit comments