fix(security): remove innerHTML XSS sink in showAlert
This commit is contained in:
+23
-4
@@ -160,7 +160,26 @@
|
|||||||
* @param {string} type - Bootstrap alert type (success, danger, warning, info)
|
* @param {string} type - Bootstrap alert type (success, danger, warning, info)
|
||||||
*/
|
*/
|
||||||
showAlert(element, message, type = 'info') {
|
showAlert(element, message, type = 'info') {
|
||||||
element.innerHTML = `<div class="alert alert-${type}" role="alert">${message}</div>`;
|
element.replaceChildren();
|
||||||
|
const alert = document.createElement('div');
|
||||||
|
alert.className = `alert alert-${type}`;
|
||||||
|
alert.setAttribute('role', 'alert');
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
alert.textContent = message;
|
||||||
|
} else if (message && typeof message === 'object') {
|
||||||
|
if (message.title) {
|
||||||
|
const strong = document.createElement('strong');
|
||||||
|
strong.textContent = message.title;
|
||||||
|
alert.appendChild(strong);
|
||||||
|
}
|
||||||
|
if (message.body) {
|
||||||
|
if (message.title) {
|
||||||
|
alert.appendChild(document.createTextNode(' '));
|
||||||
|
}
|
||||||
|
alert.appendChild(document.createTextNode(message.body));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element.appendChild(alert);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -465,7 +484,7 @@
|
|||||||
ui.showUserInfo(user);
|
ui.showUserInfo(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.showAlert(elements.secretResult, `<strong>Secret Phrase:</strong> ${cachedSecret}`, 'success');
|
utils.showAlert(elements.secretResult, { title: 'Secret Phrase:', body: cachedSecret }, 'success');
|
||||||
} else {
|
} else {
|
||||||
// Fetch fresh secret phrase and user info
|
// Fetch fresh secret phrase and user info
|
||||||
setTimeout(ui.getSecretPhrase, 500);
|
setTimeout(ui.getSecretPhrase, 500);
|
||||||
@@ -581,7 +600,7 @@
|
|||||||
localStorage.setItem('secret_phrase', data.secret_phrase);
|
localStorage.setItem('secret_phrase', data.secret_phrase);
|
||||||
localStorage.setItem('secret_last_fetch', Date.now().toString());
|
localStorage.setItem('secret_last_fetch', Date.now().toString());
|
||||||
|
|
||||||
utils.showAlert(elements.secretResult, `<strong>Secret Phrase:</strong> ${data.secret_phrase}`, 'success');
|
utils.showAlert(elements.secretResult, { title: 'Secret Phrase:', body: data.secret_phrase }, 'success');
|
||||||
} else {
|
} else {
|
||||||
// Clear cached secret if user is no longer authorized
|
// Clear cached secret if user is no longer authorized
|
||||||
localStorage.removeItem('secret_phrase');
|
localStorage.removeItem('secret_phrase');
|
||||||
@@ -618,7 +637,7 @@
|
|||||||
const price = data.bitcoin.chf;
|
const price = data.bitcoin.chf;
|
||||||
utils.showAlert(
|
utils.showAlert(
|
||||||
elements.btcPriceResult,
|
elements.btcPriceResult,
|
||||||
`<strong>1 Bitcoin (BTC) = CHF ${price.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</strong>`,
|
{ title: `1 Bitcoin (BTC) = CHF ${price.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}` },
|
||||||
'success'
|
'success'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user