fixing rolodex and search
This commit is contained in:
91
static/js/sanitizer.js
Normal file
91
static/js/sanitizer.js
Normal file
@@ -0,0 +1,91 @@
|
||||
(function () {
|
||||
const DOMPURIFY_CDN = 'https://cdn.jsdelivr.net/npm/dompurify@3.0.4/dist/purify.min.js';
|
||||
let _domPurifyPromise = null;
|
||||
|
||||
function ensureDOMPurifyLoaded() {
|
||||
if (typeof window === 'undefined') {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (window.DOMPurify && typeof window.DOMPurify.sanitize === 'function') {
|
||||
return Promise.resolve(window.DOMPurify);
|
||||
}
|
||||
if (_domPurifyPromise) return _domPurifyPromise;
|
||||
|
||||
_domPurifyPromise = new Promise((resolve, reject) => {
|
||||
try {
|
||||
const script = document.createElement('script');
|
||||
script.src = DOMPURIFY_CDN;
|
||||
script.async = true;
|
||||
script.onload = () => {
|
||||
if (window.DOMPurify && window.DOMPurify.sanitize) {
|
||||
resolve(window.DOMPurify);
|
||||
} else {
|
||||
reject(new Error('DOMPurify failed to load'));
|
||||
}
|
||||
};
|
||||
script.onerror = () => reject(new Error('Failed to load DOMPurify'));
|
||||
document.head.appendChild(script);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
return _domPurifyPromise;
|
||||
}
|
||||
|
||||
// Basic fallback sanitizer when DOMPurify is not available yet.
|
||||
function fallbackSanitize(dirty) {
|
||||
const temp = document.createElement('div');
|
||||
temp.innerHTML = dirty;
|
||||
|
||||
// Remove script and style tags
|
||||
temp.querySelectorAll('script, style').forEach((el) => el.remove());
|
||||
|
||||
// Remove dangerous attributes
|
||||
temp.querySelectorAll('*').forEach((el) => {
|
||||
Array.from(el.attributes).forEach((attr) => {
|
||||
const name = attr.name;
|
||||
const value = attr.value;
|
||||
if (/^on/i.test(name)) {
|
||||
el.removeAttribute(name);
|
||||
return;
|
||||
}
|
||||
if ((name === 'href' || name === 'src') && value && value.trim().toLowerCase().startsWith('javascript:')) {
|
||||
el.removeAttribute(name);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return temp.innerHTML;
|
||||
}
|
||||
|
||||
function sanitizeHTML(dirty) {
|
||||
if (typeof window !== 'undefined' && window.DOMPurify && window.DOMPurify.sanitize) {
|
||||
return window.DOMPurify.sanitize(dirty);
|
||||
}
|
||||
// Trigger async load so the next call benefits
|
||||
ensureDOMPurifyLoaded().catch(() => {});
|
||||
return fallbackSanitize(dirty);
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
const span = document.createElement('span');
|
||||
span.textContent = String(text == null ? '' : text);
|
||||
return span.innerHTML;
|
||||
}
|
||||
|
||||
function setSafeHTML(element, html) {
|
||||
if (!element) return;
|
||||
const sanitized = sanitizeHTML(String(html == null ? '' : html));
|
||||
element.innerHTML = sanitized;
|
||||
}
|
||||
|
||||
// Expose globally
|
||||
window.htmlSanitizer = {
|
||||
sanitize: sanitizeHTML,
|
||||
ensureDOMPurifyLoaded,
|
||||
escape: escapeHtml,
|
||||
setHTML: setSafeHTML
|
||||
};
|
||||
window.setSafeHTML = setSafeHTML;
|
||||
})();
|
||||
Reference in New Issue
Block a user