Skip to content

Commit 63e0b21

Browse files
committed
Fix HTML injection issue
1 parent 1e5f1cd commit 63e0b21

File tree

1 file changed

+77
-70
lines changed

1 file changed

+77
-70
lines changed

common/js/solid.js

Lines changed: 77 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/* global owaspPasswordStrengthTest, TextEncoder, crypto */
1+
/* global owaspPasswordStrengthTest, TextEncoder, crypto, fetch */
22
(function () {
33
'use strict'
44

5-
var PasswordValidator = function (passwordField, repeatedPasswordField) {
5+
const PasswordValidator = function (passwordField, repeatedPasswordField) {
66
if (
77
passwordField === null || passwordField === undefined ||
88
repeatedPasswordField === null || repeatedPasswordField === undefined
@@ -20,23 +20,23 @@
2020
this.errors = []
2121
}
2222

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'
2626

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'
3030

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'
3434

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'
4040

4141
/**
4242
* Prefetch all dom nodes at initialisation in order to gain time at execution since DOM manipulations
@@ -77,8 +77,8 @@
7777
* Validate password on the fly to provide the user a visual strength meter
7878
*/
7979
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)
8282

8383
if (this.currentStrengthLevel === strengthLevel) {
8484
return
@@ -98,8 +98,8 @@
9898
*/
9999
PasswordValidator.prototype.validatePassword = function () {
100100
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)
103103
this.currentStrengthLevel = this.getStrengthLevel(passwordStrength)
104104

105105
if (passwordStrength.errors) {
@@ -135,7 +135,7 @@
135135
}
136136

137137
PasswordValidator.prototype.setPasswordFeedback = function () {
138-
var feedback = this.getFeedbackFromLevel()
138+
const feedback = this.getFeedbackFromLevel()
139139
this.updateStrengthMeter()
140140
this.displayPasswordErrors()
141141
this.setFeedbackForField(feedback, this.passwordField)
@@ -145,7 +145,7 @@
145145
* Update the repeated password feedback icon and color
146146
*/
147147
PasswordValidator.prototype.updateRepeatedPasswordFeedback = function () {
148-
var feedback = this.checkPasswordFieldsEquality() ? this.FEEDBACK_SUCCESS : this.FEEDBACK_ERROR
148+
const feedback = this.checkPasswordFieldsEquality() ? FEEDBACK_SUCCESS : FEEDBACK_ERROR
149149
this.setFeedbackForField(feedback, this.repeatedPasswordField)
150150
}
151151

@@ -155,8 +155,8 @@
155155
* @param {HTMLElement} field
156156
*/
157157
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)
160160

161161
this.resetValidation(formGroup)
162162
this.resetFeedbackIcon(visualFeedback)
@@ -218,10 +218,13 @@
218218
return 4
219219
}
220220

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+
]
225228

226229
/**
227230
* @returns {string}
@@ -230,12 +233,13 @@
230233
return this.LEVEL_TO_FEEDBACK_MAP[this.currentStrengthLevel]
231234
}
232235

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+
]
239243

240244
/**
241245
* Get the CSS class for the meter based on the current level
@@ -245,24 +249,28 @@
245249
}
246250

247251
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]))
256253
}
257254

258255
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+
})
260268
}
261269

262270
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
266274

267275
/**
268276
* @param success|error|warning feedback
@@ -272,9 +280,9 @@
272280
}
273281

274282
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
278286

279287
/**
280288
* @param success|error|warning feedback
@@ -300,12 +308,12 @@
300308
* @param password
301309
*/
302310
PasswordValidator.prototype.checkLeakedPassword = function (password) {
303-
var url = 'https://api.pwnedpasswords.com/range/'
311+
const url = 'https://api.pwnedpasswords.com/range/'
304312

305313
return new Promise(function (resolve, reject) {
306314
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)
309317
suffix = suffix.toUpperCase()
310318

311319
return fetch(url + preFix)
@@ -335,12 +343,11 @@
335343
* CSS Classes reseters
336344
*/
337345

338-
339346
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
344351
)
345352

346353
el.classList.remove.apply(
@@ -350,10 +357,10 @@
350357
}
351358

352359
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
357364
)
358365

359366
el.classList.remove.apply(
@@ -363,11 +370,11 @@
363370
}
364371

365372
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
371378
)
372379

373380
this.passwordStrengthMeter.classList.remove.apply(
@@ -405,8 +412,8 @@
405412
* @returns {string[]}
406413
*/
407414
PasswordValidator.prototype.tokenize = function () {
408-
var tokenArray = []
409-
for (var i in arguments) {
415+
let tokenArray = []
416+
for (let i in arguments) {
410417
tokenArray.push(arguments[i])
411418
}
412419
return tokenArray.join(' ').split(' ')
@@ -415,9 +422,9 @@
415422
PasswordValidator.prototype.sha1 = function (str) {
416423
let buffer = new TextEncoder('utf-8').encode(str)
417424

418-
return crypto.subtle.digest('SHA-1', buffer).then(function (hash) {
425+
return crypto.subtle.digest('SHA-1', buffer).then((hash) => {
419426
return this.hex(hash)
420-
}.bind(this))
427+
})
421428
}
422429

423430
PasswordValidator.prototype.hex = function (buffer) {

0 commit comments

Comments
 (0)