feat(sanitization): integrate DOMPurify for HTML sanitization across components
- Added DOMPurify library to sanitize HTML content in toast notifications and other components to prevent XSS vulnerabilities. - Updated relevant components to use the new `sanitizeHTML` function for safe rendering of HTML content. - Ensured that only allowed tags and attributes are permitted in sanitized output.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
popToast(custom) {
|
||||
let html = '';
|
||||
if (typeof custom != 'undefined') {
|
||||
html = custom;
|
||||
html = window.sanitizeHTML(custom);
|
||||
}
|
||||
toast(this.title, { description: this.description, type: this.type, position: this.position, html: html })
|
||||
}
|
||||
@@ -96,27 +96,27 @@
|
||||
topToast.style.top = '0px';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let bottomPositionOfFirstToast = this.getBottomPositionOfElement(topToast);
|
||||
|
||||
|
||||
if (this.toasts.length == 1) return;
|
||||
let middleToast = document.getElementById(this.toasts[1].id);
|
||||
middleToast.style.zIndex = 90;
|
||||
|
||||
|
||||
if (this.expanded) {
|
||||
middleToastPosition = topToast.getBoundingClientRect().height +
|
||||
this.paddingBetweenToasts + 'px';
|
||||
|
||||
|
||||
if (this.position.includes('bottom')) {
|
||||
middleToast.style.top = 'auto';
|
||||
middleToast.style.bottom = middleToastPosition;
|
||||
} else {
|
||||
middleToast.style.top = middleToastPosition;
|
||||
}
|
||||
|
||||
|
||||
middleToast.style.scale = '100%';
|
||||
middleToast.style.transform = 'translateY(0px)';
|
||||
|
||||
|
||||
} else {
|
||||
middleToast.style.scale = '94%';
|
||||
if (this.position.includes('bottom')) {
|
||||
@@ -126,8 +126,8 @@
|
||||
middleToast.style.transform = 'translateY(16px)';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (this.toasts.length == 2) return;
|
||||
let bottomToast = document.getElementById(this.toasts[2].id);
|
||||
bottomToast.style.zIndex = 80;
|
||||
@@ -136,14 +136,14 @@
|
||||
this.paddingBetweenToasts +
|
||||
middleToast.getBoundingClientRect().height +
|
||||
this.paddingBetweenToasts + 'px';
|
||||
|
||||
|
||||
if (this.position.includes('bottom')) {
|
||||
bottomToast.style.top = 'auto';
|
||||
bottomToast.style.bottom = bottomToastPosition;
|
||||
} else {
|
||||
bottomToast.style.top = bottomToastPosition;
|
||||
}
|
||||
|
||||
|
||||
bottomToast.style.scale = '100%';
|
||||
bottomToast.style.transform = 'translateY(0px)';
|
||||
} else {
|
||||
@@ -155,9 +155,9 @@
|
||||
bottomToast.style.transform = 'translateY(32px)';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (this.toasts.length == 3) return;
|
||||
let burnToast = document.getElementById(this.toasts[3].id);
|
||||
burnToast.style.zIndex = 70;
|
||||
@@ -168,14 +168,14 @@
|
||||
this.paddingBetweenToasts +
|
||||
bottomToast.getBoundingClientRect().height +
|
||||
this.paddingBetweenToasts + 'px';
|
||||
|
||||
|
||||
if (this.position.includes('bottom')) {
|
||||
burnToast.style.top = 'auto';
|
||||
burnToast.style.bottom = burnToastPosition;
|
||||
} else {
|
||||
burnToast.style.top = burnToastPosition;
|
||||
}
|
||||
|
||||
|
||||
burnToast.style.scale = '100%';
|
||||
burnToast.style.transform = 'translateY(0px)';
|
||||
} else {
|
||||
@@ -183,40 +183,40 @@
|
||||
this.alignBottom(topToast, burnToast);
|
||||
burnToast.style.transform = 'translateY(48px)';
|
||||
}
|
||||
|
||||
|
||||
burnToast.firstElementChild.classList.remove('opacity-100');
|
||||
burnToast.firstElementChild.classList.add('opacity-0');
|
||||
|
||||
|
||||
let that = this;
|
||||
// Burn 🔥 (remove) last toast
|
||||
setTimeout(function() {
|
||||
that.toasts.pop();
|
||||
}, 300);
|
||||
|
||||
|
||||
if (this.position.includes('bottom')) {
|
||||
middleToast.style.top = 'auto';
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
},
|
||||
alignBottom(element1, element2) {
|
||||
// Get the top position and height of the first element
|
||||
let top1 = element1.offsetTop;
|
||||
let height1 = element1.offsetHeight;
|
||||
|
||||
|
||||
// Get the height of the second element
|
||||
let height2 = element2.offsetHeight;
|
||||
|
||||
|
||||
// Calculate the top position for the second element
|
||||
let top2 = top1 + (height1 - height2);
|
||||
|
||||
|
||||
// Apply the calculated top position to the second element
|
||||
element2.style.top = top2 + 'px';
|
||||
},
|
||||
alignTop(element1, element2) {
|
||||
// Get the top position of the first element
|
||||
let top1 = element1.offsetTop;
|
||||
|
||||
|
||||
// Apply the same top position to the second element
|
||||
element2.style.top = top1 + 'px';
|
||||
},
|
||||
@@ -244,13 +244,13 @@
|
||||
$el.style.height = '0px';
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
lastToast = this.toasts[this.toasts.length - 1];
|
||||
lastToastRectangle = document.getElementById(lastToast.id).getBoundingClientRect();
|
||||
|
||||
|
||||
firstToast = this.toasts[0];
|
||||
firstToastRectangle = document.getElementById(firstToast.id).getBoundingClientRect();
|
||||
|
||||
|
||||
if (this.toastsHovered) {
|
||||
if (this.position.includes('bottom')) {
|
||||
$el.style.height = ((firstToastRectangle.top + firstToastRectangle.height) - lastToastRectangle.top) + 'px';
|
||||
@@ -276,13 +276,16 @@
|
||||
if(event.detail.position){
|
||||
position = event.detail.position;
|
||||
}
|
||||
// Sanitize HTML content to prevent XSS
|
||||
let sanitizedHtml = event.detail.html ? window.sanitizeHTML(event.detail.html) : '';
|
||||
|
||||
toasts.unshift({
|
||||
id: 'toast-' + Math.random().toString(16).slice(2),
|
||||
show: false,
|
||||
message: event.detail.message,
|
||||
description: event.detail.description,
|
||||
type: event.detail.type,
|
||||
html: event.detail.html
|
||||
html: sanitizedHtml
|
||||
});
|
||||
"
|
||||
@mouseenter="toastsHovered=true;" @mouseleave="toastsHovered=false" x-init="if (layout == 'expanded') {
|
||||
@@ -356,9 +359,9 @@
|
||||
}, 2000)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
if (position.includes('bottom')) {
|
||||
$el.firstElementChild.classList.remove('opacity-0', 'translate-y-full');
|
||||
@@ -366,13 +369,13 @@
|
||||
$el.firstElementChild.classList.remove('opacity-0', '-translate-y-full');
|
||||
}
|
||||
$el.firstElementChild.classList.add('opacity-100', 'translate-y-0');
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
stackToasts();
|
||||
}, 10);
|
||||
}, 5);
|
||||
}, 50);
|
||||
|
||||
|
||||
this.timeout = setTimeout(function() {
|
||||
setTimeout(function() {
|
||||
$el.firstElementChild.classList.remove('opacity-100');
|
||||
@@ -421,16 +424,16 @@
|
||||
d="M2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12ZM11.9996 7C12.5519 7 12.9996 7.44772 12.9996 8V12C12.9996 12.5523 12.5519 13 11.9996 13C11.4474 13 10.9996 12.5523 10.9996 12V8C10.9996 7.44772 11.4474 7 11.9996 7ZM12.001 14.99C11.4488 14.9892 11.0004 15.4363 10.9997 15.9886L10.9996 15.9986C10.9989 16.5509 11.446 16.9992 11.9982 17C12.5505 17.0008 12.9989 16.5537 12.9996 16.0014L12.9996 15.9914C13.0004 15.4391 12.5533 14.9908 12.001 14.99Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
<p class="text-black leading-2 dark:text-neutral-200" x-html="toast.message">
|
||||
<p class="text-black leading-2 dark:text-neutral-200" x-text="toast.message">
|
||||
</p>
|
||||
</div>
|
||||
<div x-show="toast.description" :class="{ 'pl-5': toast.type!='default' }"
|
||||
class="mt-1.5 text-xs px-2 opacity-90 whitespace-pre-wrap w-full break-words"
|
||||
x-html="toast.description"></div>
|
||||
x-html="window.sanitizeHTML(toast.description)"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="toast.html">
|
||||
<div x-html="toast.html"></div>
|
||||
<div x-html="window.sanitizeHTML(toast.html)"></div>
|
||||
</template>
|
||||
<span class="absolute mt-1 text-xs right-[4.4rem] text-success font-bold"
|
||||
x-show="copyNotification"
|
||||
|
||||
Reference in New Issue
Block a user