| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 | import DOMPurify from 'dompurify';// Centralized secure DOMPurify configuration to prevent XSS and CSS injection attacksexport function getSecureDOMPurifyConfig() {  return {    // Block dangerous elements that can cause XSS and CSS injection    FORBID_TAGS: [      'svg', 'defs', 'use', 'g', 'symbol', 'marker', 'pattern', 'mask', 'clipPath',      'linearGradient', 'radialGradient', 'stop', 'animate', 'animateTransform',      'animateMotion', 'set', 'switch', 'foreignObject', 'script', 'style', 'link',      'meta', 'iframe', 'object', 'embed', 'applet', 'form', 'input', 'textarea',      'select', 'option', 'button', 'label', 'fieldset', 'legend', 'frameset',      'frame', 'noframes', 'base', 'basefont', 'isindex', 'dir', 'menu', 'menuitem'    ],    // Block dangerous attributes that can cause XSS and CSS injection    FORBID_ATTR: [      'xlink:href', 'href', 'onload', 'onerror', 'onclick', 'onmouseover',      'onfocus', 'onblur', 'onchange', 'onsubmit', 'onreset', 'onselect',      'onunload', 'onresize', 'onscroll', 'onkeydown', 'onkeyup', 'onkeypress',      'onmousedown', 'onmouseup', 'onmouseover', 'onmouseout', 'onmousemove',      'ondblclick', 'oncontextmenu', 'onwheel', 'ontouchstart', 'ontouchend',      'ontouchmove', 'ontouchcancel', 'onabort', 'oncanplay', 'oncanplaythrough',      'ondurationchange', 'onemptied', 'onended', 'onerror', 'onloadeddata',      'onloadedmetadata', 'onloadstart', 'onpause', 'onplay', 'onplaying',      'onprogress', 'onratechange', 'onseeked', 'onseeking', 'onstalled',      'onsuspend', 'ontimeupdate', 'onvolumechange', 'onwaiting', 'onbeforeunload',      'onhashchange', 'onpagehide', 'onpageshow', 'onpopstate', 'onstorage',      'onunload', 'style', 'class', 'id', 'data-*', 'aria-*'    ],    // Allow only safe image formats and protocols    ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,    // Remove dangerous protocols    ALLOW_UNKNOWN_PROTOCOLS: false,    // Sanitize URLs to prevent malicious content loading    SANITIZE_DOM: true,    // Remove dangerous elements completely    KEEP_CONTENT: false,    // Additional security measures    ADD_ATTR: [],    // Block data URIs that could contain malicious content    ALLOW_DATA_ATTR: false,    // Custom hook to further sanitize content    HOOKS: {      uponSanitizeElement: function(node, data) {        // Block any remaining dangerous elements        const dangerousTags = ['svg', 'style', 'script', 'link', 'meta', 'iframe', 'object', 'embed', 'applet'];        if (node.tagName && dangerousTags.includes(node.tagName.toLowerCase())) {          if (process.env.DEBUG === 'true') {            console.warn('Blocked potentially dangerous element:', node.tagName);          }          return false;        }        // Block img tags with SVG data URIs        if (node.tagName && node.tagName.toLowerCase() === 'img') {          const src = node.getAttribute('src');          if (src && (src.startsWith('data:image/svg') || src.endsWith('.svg'))) {            if (process.env.DEBUG === 'true') {              console.warn('Blocked potentially malicious SVG image:', src);            }            return false;          }        }        // Block elements with dangerous attributes        const dangerousAttrs = ['style', 'onload', 'onerror', 'onclick', 'onmouseover', 'onfocus', 'onblur'];        for (const attr of dangerousAttrs) {          if (node.hasAttribute && node.hasAttribute(attr)) {            if (process.env.DEBUG === 'true') {              console.warn('Blocked element with dangerous attribute:', node.tagName, attr);            }            return false;          }        }        return true;      },      uponSanitizeAttribute: function(node, data) {        // Block style attributes completely        if (data.attrName === 'style') {          if (process.env.DEBUG === 'true') {            console.warn('Blocked style attribute');          }          return false;        }        // Block class and id attributes that might be used for CSS injection        if (data.attrName === 'class' || data.attrName === 'id') {          if (process.env.DEBUG === 'true') {            console.warn('Blocked class/id attribute:', data.attrName, data.attrValue);          }          return false;        }        // Block data attributes        if (data.attrName && data.attrName.startsWith('data-')) {          if (process.env.DEBUG === 'true') {            console.warn('Blocked data attribute:', data.attrName);          }          return false;        }        return true;      }    }  };}// Convenience function for secure sanitizationexport function sanitizeHTML(html) {  return DOMPurify.sanitize(html, getSecureDOMPurifyConfig());}// Convenience function for sanitizing text (no HTML)export function sanitizeText(text) {  return DOMPurify.sanitize(text, {    ALLOWED_TAGS: [],    ALLOWED_ATTR: [],    KEEP_CONTENT: true  });}
 |