1//#region node_modules/dompurify/dist/purify.es.mjs 2/*! @license DOMPurify 3.4.15 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.15/LICENSE */ 3function _arrayLikeToArray(r, a) { 4 (null == a || a > r.length) && (a = r.length); 5 for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; 6 return n; 7} 8function _arrayWithHoles(r) { 9 if (Array.isArray(r)) return r; 10} 11function _iterableToArrayLimit(r, l) { 12 var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; 13 if (null != t) { 14 var e, n, i, u, a = [], f = true, o = false; 15 try { 16 if (i = (t = t.call(r)).next, 0 === l); 17 else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); 18 } catch (r) { 19 o = true, n = r; 20 } finally { 21 try { 22 if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; 23 } finally { 24 if (o) throw n; 25 } 26 } 27 return a; 28 } 29} 30function _nonIterableRest() { 31 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 32} 33function _slicedToArray(r, e) { 34 return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); 35} 36function _unsupportedIterableToArray(r, a) { 37 if (r) { 38 if ("string" == typeof r) return _arrayLikeToArray(r, a); 39 var t = {}.toString.call(r).slice(8, -1); 40 return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; 41 } 42} 43var entries = Object.entries; 44var setPrototypeOf = Object.setPrototypeOf; 45var isFrozen = Object.isFrozen; 46var getPrototypeOf = Object.getPrototypeOf; 47var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 48var freeze = Object.freeze; 49var seal = Object.seal; 50var create = Object.create; 51var _ref = typeof Reflect !== "undefined" && Reflect; 52var apply = _ref.apply; 53var construct = _ref.construct; 54if (!freeze) freeze = function freeze(x) { 55 return x; 56}; 57if (!seal) seal = function seal(x) { 58 return x; 59}; 60if (!apply) apply = function apply(func, thisArg) { 61 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key]; 62 return func.apply(thisArg, args); 63}; 64if (!construct) construct = function construct(Func) { 65 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) args[_key2 - 1] = arguments[_key2]; 66 return new Func(...args); 67}; 68var arrayForEach = unapply(Array.prototype.forEach); 69var arrayLastIndexOf = unapply(Array.prototype.lastIndexOf); 70var arrayPop = unapply(Array.prototype.pop); 71var arrayPush = unapply(Array.prototype.push); 72var arraySplice = unapply(Array.prototype.splice); 73var arrayIsArray = Array.isArray; 74var stringToLowerCase = unapply(String.prototype.toLowerCase); 75var stringToString = unapply(String.prototype.toString); 76var stringMatch = unapply(String.prototype.match); 77var stringReplace = unapply(String.prototype.replace); 78var stringIndexOf = unapply(String.prototype.indexOf); 79var stringTrim = unapply(String.prototype.trim); 80var numberToString = unapply(Number.prototype.toString); 81var booleanToString = unapply(Boolean.prototype.toString); 82var bigintToString = typeof BigInt === "undefined" ? null : unapply(BigInt.prototype.toString); 83var symbolToString = typeof Symbol === "undefined" ? null : unapply(Symbol.prototype.toString); 84var objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty); 85var objectToString = unapply(Object.prototype.toString); 86var regExpTest = unapply(RegExp.prototype.test); 87var typeErrorCreate = unconstruct(TypeError); 88/** 89* Creates a new function that calls the given function with a specified thisArg and arguments. 90* 91* @param func - The function to be wrapped and called. 92* @returns A new function that calls the given function with a specified thisArg and arguments. 93*/ 94function unapply(func) { 95 return function(thisArg) { 96 if (thisArg instanceof RegExp) thisArg.lastIndex = 0; 97 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) args[_key3 - 1] = arguments[_key3]; 98 return apply(func, thisArg, args); 99 }; 100} 101/** 102* Creates a new function that constructs an instance of the given constructor function with the provided arguments. 103* 104* @param func - The constructor function to be wrapped and called. 105* @returns A new function that constructs an instance of the given constructor function with the provided arguments. 106*/ 107function unconstruct(Func) { 108 return function() { 109 for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4;
vendor: 4,278 bytes, lines 109-282
109 _key4++) args[_key4] = arguments[_key4]; 110 return construct(Func, args); 111 }; 112} 113/** 114* Add properties to a lookup table 115* 116* @param set - The set to which elements will be added. 117* @param array - The array containing elements to be added to the set. 118* @param transformCaseFunc - An optional function to transform the case of each element before adding to the set. 119* @returns The modified set with added elements. 120*/ 121function addToSet(set, array) { 122 let transformCaseFunc = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : stringToLowerCase; 123 if (setPrototypeOf) setPrototypeOf(set, null); 124 if (!arrayIsArray(array)) return set; 125 let l = array.length; 126 while (l--) { 127 let element = array[l]; 128 if (typeof element === "string") { 129 const lcElement = transformCaseFunc(element); 130 if (lcElement !== element) { 131 if (!isFrozen(array)) array[l] = lcElement; 132 element = lcElement; 133 } 134 } 135 set[element] = true; 136 } 137 return set; 138} 139/** 140* Clean up an array to harden against CSPP 141* 142* @param array - The array to be cleaned. 143* @returns The cleaned version of the array 144*/ 145function cleanArray(array) { 146 for (let index = 0; index < array.length; index++) if (!objectHasOwnProperty(array, index)) array[index] = null; 147 return array; 148} 149/** 150* Shallow clone an object 151* 152* @param object - The object to be cloned. 153* @returns A new object that copies the original. 154*/ 155function clone(object) { 156 const newObject = create(null); 157 for (const _ref2 of entries(object)) { 158 var _ref3 = _slicedToArray(_ref2, 2); 159 const property = _ref3[0]; 160 const value = _ref3[1]; 161 if (objectHasOwnProperty(object, property)) { 162 if (arrayIsArray(value)) newObject[property] = cleanArray(value); 163 else if (value && typeof value === "object" && value.constructor === Object) newObject[property] = clone(value); 164 else newObject[property] = value; 165 } 166 } 167 return newObject; 168} 169/** 170* Convert non-node values into strings without depending on direct property access. 171* 172* @param value - The value to stringify. 173* @returns A string representation of the provided value. 174*/ 175function stringifyValue(value) { 176 switch (typeof value) { 177 case "string": return value; 178 case "number": return numberToString(value); 179 case "boolean": return booleanToString(value); 180 case "bigint": return bigintToString ? bigintToString(value) : "0"; 181 case "symbol": return symbolToString ? symbolToString(value) : "Symbol()"; 182 case "undefined": return objectToString(value); 183 case "function": 184 case "object": { 185 if (value === null) return objectToString(value); 186 const valueAsRecord = value; 187 const valueToString = lookupGetter(valueAsRecord, "toString"); 188 if (typeof valueToString === "function") { 189 const stringified = valueToString(valueAsRecord); 190 return typeof stringified === "string" ? stringified : objectToString(stringified); 191 } 192 return objectToString(value); 193 } 194 default: return objectToString(value); 195 } 196} 197/** 198* This method automatically checks if the prop is function or getter and behaves accordingly. 199* 200* @param object - The object to look up the getter function in its prototype chain. 201* @param prop - The property name for which to find the getter function. 202* @returns The getter function found in the prototype chain or a fallback function. 203*/ 204function lookupGetter(object, prop) { 205 while (object !== null) { 206 const desc = getOwnPropertyDescriptor(object, prop); 207 if (desc) { 208 if (desc.get) return unapply(desc.get); 209 if (typeof desc.value === "function") return unapply(desc.value); 210 } 211 object = getPrototypeOf(object); 212 } 213 function fallbackValue() { 214 return null; 215 } 216 return fallbackValue; 217} 218function isRegex(value) { 219 try { 220 regExpTest(value, ""); 221 return true; 222 } catch (_unused) { 223 return false; 224 } 225} 226var html$1 = freeze([ 227 "a", 228 "abbr", 229 "acronym", 230 "address", 231 "area", 232 "article", 233 "aside", 234 "audio", 235 "b", 236 "bdi", 237 "bdo", 238 "big", 239 "blink", 240 "blockquote", 241 "body", 242 "br", 243 "button", 244 "canvas", 245 "caption", 246 "center", 247 "cite", 248 "code", 249 "col", 250 "colgroup", 251 "content", 252 "data", 253 "datalist", 254 "dd", 255 "decorator", 256 "del", 257 "details", 258 "dfn", 259 "dialog", 260 "dir", 261 "div", 262 "dl", 263 "dt", 264 "element", 265 "em", 266 "fieldset", 267 "figcaption", 268 "figure", 269 "font", 270 "footer", 271 "form", 272 "h1", 273 "h2", 274 "h3", 275 "h4", 276 "h5", 277 "h6", 278 "head", 279 "header", 280 "hgroup", 281 "hr", 282 "html",
283 "i", 284 "img", 285 "input", 286 "ins", 287 "kbd", 288 "label", 289 "legend", 290 "li", 291 "main", 292 "map", 293 "mark", 294 "marquee", 295 "menu", 296 "menuitem", 297 "meter", 298 "nav", 299 "nobr", 300 "ol", 301 "optgroup", 302 "option", 303 "output", 304 "p", 305 "picture", 306 "pre", 307 "progress", 308 "q", 309 "rp", 310 "rt", 311 "ruby", 312 "s", 313 "samp", 314 "search", 315 "section", 316 "select", 317 "shadow", 318 "slot", 319 "small", 320 "source", 321 "spacer", 322 "span", 323 "strike", 324 "strong", 325 "style", 326 "sub", 327 "summary", 328 "sup", 329 "table", 330 "tbody", 331 "td", 332 "template", 333 "textarea", 334 "tfoot", 335 "th", 336 "thead", 337 "time", 338 "tr", 339 "track", 340 "tt", 341 "u", 342 "ul", 343 "var", 344 "video", 345 "wbr" 346]); 347var svg$1 = freeze([ 348 "svg", 349 "a", 350 "altglyph", 351 "altglyphdef", 352 "altglyphitem", 353 "animatecolor", 354 "animatemotion", 355 "animatetransform", 356 "circle", 357 "clippath", 358 "defs", 359 "desc", 360 "ellipse", 361 "enterkeyhint", 362 "exportparts", 363 "filter", 364 "font", 365 "g", 366 "glyph", 367 "glyphref", 368 "hkern", 369 "image", 370 "inputmode", 371 "line", 372 "lineargradient", 373 "marker", 374 "mask", 375 "metadata", 376 "mpath", 377 "part", 378 "path", 379 "pattern", 380 "polygon", 381 "polyline", 382 "radialgradient", 383 "rect", 384 "stop", 385 "style", 386 "switch", 387 "symbol", 388 "text", 389 "textpath", 390 "title", 391 "tref", 392 "tspan", 393 "view", 394 "vkern" 395]); 396var svgFilters = freeze([ 397 "feBlend", 398 "feColorMatrix", 399 "feComponentTransfer", 400 "feComposite", 401 "feConvolveMatrix", 402 "feDiffuseLighting", 403 "feDisplacementMap", 404 "feDistantLight", 405 "feDropShadow", 406 "feFlood", 407 "feFuncA", 408 "feFuncB", 409 "feFuncG", 410 "feFuncR", 411 "feGaussianBlur", 412 "feImage", 413 "feMerge", 414 "feMergeNode", 415 "feMorphology", 416 "feOffset", 417 "fePointLight", 418 "feSpecularLighting", 419 "feSpotLight", 420 "feTile", 421 "feTurbulence" 422]); 423var svgDisallowed = freeze([ 424 "animate", 425 "color-profile", 426 "cursor", 427 "discard", 428 "font-face", 429 "font-face-format", 430 "font-face-name", 431 "font-face-src", 432 "font-face-uri", 433 "foreignobject", 434 "hatch", 435 "hatchpath", 436 "mesh", 437 "meshgradient", 438 "meshpatch", 439 "meshrow", 440 "missing-glyph", 441 "script", 442 "set", 443 "solidcolor", 444 "unknown", 445 "use" 446]); 447var mathMl$1 = freeze([ 448 "math", 449 "menclose", 450 "merror", 451 "mfenced", 452 "mfrac", 453 "mglyph", 454 "mi", 455 "mlabeledtr", 456 "mmultiscripts", 457 "mn", 458 "mo", 459 "mover", 460 "mpadded", 461 "mphantom", 462 "mroot", 463 "mrow", 464 "ms", 465 "mspace", 466 "msqrt", 467 "mstyle", 468 "msub", 469 "msup", 470 "msubsup", 471 "mtable", 472 "mtd", 473 "mtext", 474 "mtr", 475 "munder", 476 "munderover", 477 "mprescripts" 478]); 479var mathMlDisallowed = freeze([ 480 "maction", 481 "maligngroup", 482 "malignmark", 483 "mlongdiv", 484 "mscarries", 485 "mscarry", 486 "msgroup", 487 "mstack", 488 "msline", 489 "msrow", 490 "semantics", 491 "annotation", 492 "annotation-xml", 493 "mprescripts", 494 "none" 495]); 496var text = freeze(["#text"]); 497var html = freeze([ 498 "accept", 499 "action", 500 "align", 501 "alt", 502 "autocapitalize", 503 "autocomplete", 504 "autopictureinpicture", 505 "autoplay", 506 "background", 507 "bgcolor", 508 "border", 509 "capture", 510 "cellpadding", 511 "cellspacing", 512 "checked", 513 "cite", 514 "class", 515 "clear", 516 "color", 517 "cols", 518 "colspan", 519 "command", 520 "commandfor", 521 "controls", 522 "controlslist", 523 "coords", 524 "crossorigin", 525 "datetime", 526 "decoding", 527 "default", 528 "dir", 529 "disabled", 530 "disablepictureinpicture", 531 "disableremoteplayback", 532 "download", 533 "draggable", 534 "enctype", 535 "enterkeyhint", 536 "exportparts", 537 "face", 538 "for", 539 "headers", 540 "height", 541 "hidden", 542 "high", 543 "href", 544 "hreflang", 545 "id", 546 "inert", 547 "inputmode", 548 "integrity", 549 "ismap", 550 "kind", 551 "label", 552 "lang", 553 "list", 554 "loading", 555 "loop", 556 "low", 557 "max", 558 "maxlength", 559 "media", 560 "method", 561 "min", 562 "minlength", 563 "multiple", 564 "muted", 565 "name", 566 "nonce", 567 "noshade", 568 "novalidate", 569 "nowrap", 570 "open", 571 "optimum", 572 "part", 573 "pattern", 574 "placeholder", 575 "playsinline", 576 "popover", 577 "popovertarget", 578 "popovertargetaction", 579 "poster", 580 "preload", 581 "pubdate", 582 "radiogroup", 583 "readonly", 584 "rel", 585 "required", 586 "rev", 587 "reversed", 588 "role", 589 "rows", 590 "rowspan", 591 "spellcheck", 592 "scope", 593 "selected", 594 "shape", 595 "size", 596 "sizes", 597 "slot", 598 "span", 599 "srclang", 600 "start", 601 "src", 602 "srcset", 603 "step", 604 "style", 605 "summary", 606 "tabindex", 607 "title", 608 "translate", 609 "type", 610 "usemap", 611 "valign", 612 "value", 613 "width", 614 "wrap", 615 "xmlns" 616]); 617var
vendor: 2,664 bytes, lines 617-810
617 svg = freeze([ 618 "accent-height", 619 "accumulate", 620 "additive", 621 "alignment-baseline", 622 "amplitude", 623 "ascent", 624 "attributename", 625 "attributetype", 626 "azimuth", 627 "basefrequency", 628 "baseline-shift", 629 "begin", 630 "bias", 631 "by", 632 "class", 633 "clip", 634 "clippathunits", 635 "clip-path", 636 "clip-rule", 637 "color", 638 "color-interpolation", 639 "color-interpolation-filters", 640 "color-profile", 641 "color-rendering", 642 "cx", 643 "cy", 644 "d", 645 "dx", 646 "dy", 647 "diffuseconstant", 648 "direction", 649 "display", 650 "divisor", 651 "dominant-baseline", 652 "dur", 653 "edgemode", 654 "elevation", 655 "end", 656 "exponent", 657 "fill", 658 "fill-opacity", 659 "fill-rule", 660 "filter", 661 "filterunits", 662 "flood-color", 663 "flood-opacity", 664 "font-family", 665 "font-size", 666 "font-size-adjust", 667 "font-stretch", 668 "font-style", 669 "font-variant", 670 "font-weight", 671 "fx", 672 "fy", 673 "g1", 674 "g2", 675 "glyph-name", 676 "glyphref", 677 "gradientunits", 678 "gradienttransform", 679 "height", 680 "href", 681 "id", 682 "image-rendering", 683 "in", 684 "in2", 685 "intercept", 686 "k", 687 "k1", 688 "k2", 689 "k3", 690 "k4", 691 "kerning", 692 "keypoints", 693 "keysplines", 694 "keytimes", 695 "lang", 696 "lengthadjust", 697 "letter-spacing", 698 "kernelmatrix", 699 "kernelunitlength", 700 "lighting-color", 701 "local", 702 "marker-end", 703 "marker-mid", 704 "marker-start", 705 "markerheight", 706 "markerunits", 707 "markerwidth", 708 "maskcontentunits", 709 "maskunits", 710 "max", 711 "mask", 712 "mask-type", 713 "media", 714 "method", 715 "mode", 716 "min", 717 "name", 718 "numoctaves", 719 "offset", 720 "operator", 721 "opacity", 722 "order", 723 "orient", 724 "orientation", 725 "origin", 726 "overflow", 727 "paint-order", 728 "path", 729 "pathlength", 730 "patterncontentunits", 731 "patterntransform", 732 "patternunits", 733 "pointer-events", 734 "points", 735 "preservealpha", 736 "preserveaspectratio", 737 "primitiveunits", 738 "r", 739 "rx", 740 "ry", 741 "radius", 742 "refx", 743 "refy", 744 "repeatcount", 745 "repeatdur", 746 "restart", 747 "result", 748 "rotate", 749 "scale", 750 "seed", 751 "shape-rendering", 752 "slope", 753 "specularconstant", 754 "specularexponent", 755 "spreadmethod", 756 "startoffset", 757 "stddeviation", 758 "stitchtiles", 759 "stop-color", 760 "stop-opacity", 761 "stroke-dasharray", 762 "stroke-dashoffset", 763 "stroke-linecap", 764 "stroke-linejoin", 765 "stroke-miterlimit", 766 "stroke-opacity", 767 "stroke", 768 "stroke-width", 769 "style", 770 "surfacescale", 771 "systemlanguage", 772 "tabindex", 773 "tablevalues", 774 "targetx", 775 "targety", 776 "transform", 777 "transform-origin", 778 "text-anchor", 779 "text-decoration", 780 "text-orientation", 781 "text-rendering", 782 "textlength", 783 "type", 784 "u1", 785 "u2", 786 "unicode", 787 "values", 788 "vector-effect", 789 "viewbox", 790 "visibility", 791 "version", 792 "vert-adv-y", 793 "vert-origin-x", 794 "vert-origin-y", 795 "width", 796 "word-spacing", 797 "wrap", 798 "writing-mode", 799 "xchannelselector", 800 "ychannelselector", 801 "x", 802 "x1", 803 "x2", 804 "xmlns", 805 "y", 806 "y1", 807 "y2", 808 "z", 809 "zoomandpan" 810]);
811var mathMl = freeze([ 812 "accent", 813 "accentunder", 814 "align", 815 "bevelled", 816 "close", 817 "columnalign", 818 "columnlines", 819 "columnspacing", 820 "columnspan", 821 "denomalign", 822 "depth", 823 "dir", 824 "display", 825 "displaystyle", 826 "encoding", 827 "fence", 828 "frame", 829 "height", 830 "href", 831 "id", 832 "largeop", 833 "length", 834 "linethickness", 835 "lquote", 836 "lspace", 837 "mathbackground", 838 "mathcolor", 839 "mathsize", 840 "mathvariant", 841 "maxsize", 842 "minsize", 843 "movablelimits", 844 "notation", 845 "numalign", 846 "open", 847 "rowalign", 848 "rowlines", 849 "rowspacing", 850 "rowspan", 851 "rspace", 852 "rquote", 853 "scriptlevel", 854 "scriptminsize", 855 "scriptsizemultiplier", 856 "selection", 857 "separator", 858 "separators", 859 "stretchy", 860 "subscriptshift", 861 "supscriptshift", 862 "symmetric", 863 "voffset", 864 "width", 865 "xmlns" 866]); 867var xml = freeze([ 868 "xlink:href", 869 "xml:id", 870 "xlink:title", 871 "xml:space", 872 "xmlns:xlink" 873]); 874var MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g); 875var ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g); 876var TMPLIT_EXPR = seal(/\${[\w\W]*/g); 877var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); 878var ARIA_ATTR = seal(/^aria-[\-\w]+$/); 879var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i); 880var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); 881var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g); 882var DOCTYPE_NAME = seal(/^html$/i); 883var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); 884var ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g); 885var COMMENT_MARKUP_PROBE = seal(/<[/\w]/g); 886var FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i); 887var SELF_CLOSING_TAG = seal(/\/>/i); 888var NODE_TYPE = { 889 element: 1, 890 attribute: 2, 891 text: 3, 892 cdataSection: 4, 893 entityReference: 5, 894 entityNode: 6, 895 processingInstruction: 7, 896 comment: 8, 897 document: 9, 898 documentType: 10, 899 documentFragment: 11, 900 notation: 12 901}; 902var LITERAL_TEXT_ELEMENT_NAMES = [ 903 "style", 904 "script", 905 "xmp", 906 "iframe", 907 "noembed", 908 "noframes", 909 "plaintext", 910 "noscript" 911]; 912var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, LITERAL_TEXT_ELEMENT_NAMES)); 913var LITERAL_TEXT_CLOSE = function() { 914 const map = {}; 915 arrayForEach(LITERAL_TEXT_ELEMENT_NAMES, (name) => { 916 map[name] = seal(new RegExp("</" + name + "(?=[\\t\\n\\f\\r />])", "i")); 917 }); 918 return freeze(map); 919}(); 920var getGlobal = function getGlobal() { 921 return typeof window === "undefined" ? null : window; 922}; 923/** 924* Creates a no-op policy for internal use only. 925* Don't export this function outside this module! 926* @param trustedTypes The policy factory. 927* @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix). 928* @return The policy created (or null, if Trusted Types 929* are not supported or creating the policy failed). 930*/ 931var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) { 932 if (typeof trustedTypes !== "object" || typeof trustedTypes.createPolicy !== "function") return null; 933 let suffix = null; 934 const ATTR_NAME = "data-tt-policy-suffix"; 935 if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) suffix = purifyHostElement.getAttribute(ATTR_NAME); 936 const policyName = "dompurify" + (suffix ? "#" + suffix : ""); 937 try { 938 return trustedTypes.createPolicy(policyName, { 939 createHTML(html) { 940 return html; 941 }, 942 createScriptURL(scriptUrl) { 943 return scriptUrl; 944 } 945 }); 946 } catch (_) { 947 console.warn("TrustedTypes policy " + policyName + " could not be created."); 948 return null; 949 } 950}; 951var _createHooksMap = function _createHooksMap() { 952 return { 953 afterSanitizeAttributes: [], 954 afterSanitizeElements: [], 955 afterSanitizeShadowDOM: [], 956 beforeSanitizeAttributes: [], 957 beforeSanitizeElements: [], 958 beforeSanitizeShadowDOM: [], 959 uponSanitizeAttribute: [], 960 uponSanitizeElement: [], 961 uponSanitizeShadowNode: [] 962 }; 963}; 964/** 965* Resolve a set-valued configuration option: a fresh set built from 966* cfg[key] when it is an own array property (seeded with a clone of 967* options.base when given, case-normalized via options.transform), 968* the fallback set otherwise. 969* 970* @param cfg the cloned, prototype-free configuration object 971* @param key the configuration property to read 972* @param fallback the set to use when the option is absent or not an array 973* @param options transform and optional base set to merge into 974* @returns the resolved set 975*/ 976var _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) { 977 return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback; 978}; 979/** 980* Resolve an object-valued configuration option: a prototype-free clone 981* of cfg[key] when it is an own, truthy object property, else a fresh 982* fallback built by makeFallback (fresh on every parse, so a previous 983* parse can never leak state into the next one). 984* 985* @param cfg the cloned, prototype-free configuration object 986* @param key the configuration property to read 987* @param makeFallback builds the fallback value when the option is absent 988* @returns the resolved object 989*/ 990var _resolveObjectOption = function _resolveObjectOption(cfg, key, makeFallback) { 991 const value = objectHasOwnProperty(cfg, key) ? cfg[key] : void 0; 992 return value && typeof value === "object" ? clone(value) : makeFallback(); 993}; 994function createDOMPurify() { 995 let window = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal(); 996 const DOMPurify = (root) => createDOMPurify(root); 997 DOMPurify.version = "3.4.15
vendor: 44,004 bytes, lines 997-1987
997"; 998 DOMPurify.removed = []; 999 if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { 1000 DOMPurify.isSupported = false; 1001 return DOMPurify; 1002 } 1003 let document = window.document; 1004 const originalDocument = document; 1005 const currentScript = originalDocument.currentScript; 1006 window.DocumentFragment; 1007 const HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter; 1008 window.NamedNodeMap === void 0 && (window.NamedNodeMap || window.MozNamedAttrMap); 1009 window.HTMLFormElement; 1010 const DOMParser = window.DOMParser, trustedTypes = window.trustedTypes; 1011 const ElementPrototype = Element.prototype; 1012 const cloneNode = lookupGetter(ElementPrototype, "cloneNode"); 1013 const remove = lookupGetter(ElementPrototype, "remove"); 1014 const removeAttributeNode = lookupGetter(ElementPrototype, "removeAttributeNode"); 1015 const getNextSibling = lookupGetter(ElementPrototype, "nextSibling"); 1016 const getChildNodes = lookupGetter(ElementPrototype, "childNodes"); 1017 const getParentNode = lookupGetter(ElementPrototype, "parentNode"); 1018 const getShadowRoot = lookupGetter(ElementPrototype, "shadowRoot"); 1019 const getAttributes = lookupGetter(ElementPrototype, "attributes"); 1020 const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeType") : null; 1021 const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeName") : null; 1022 const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, "ownerDocument") : null; 1023 const _readNodeType = function _readNodeType(node) { 1024 return getNodeType ? getNodeType(node) : node.nodeType; 1025 }; 1026 const _readNodeName = function _readNodeName(node) { 1027 return getNodeName ? getNodeName(node) : node.nodeName; 1028 }; 1029 if (typeof HTMLTemplateElement === "function") { 1030 const template = document.createElement("template"); 1031 if (template.content && template.content.ownerDocument) document = template.content.ownerDocument; 1032 } 1033 let trustedTypesPolicy; 1034 let emptyHTML = ""; 1035 let defaultTrustedTypesPolicy; 1036 let defaultTrustedTypesPolicyResolved = false; 1037 let IN_TRUSTED_TYPES_POLICY = 0; 1038 const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() { 1039 if (IN_TRUSTED_TYPES_POLICY > 0) throw typeErrorCreate("A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the \"DOMPurify and Trusted Types\" section of the README."); 1040 }; 1041 const _createTrustedHTML = function _createTrustedHTML(html) { 1042 _assertNotInTrustedTypesPolicy(); 1043 IN_TRUSTED_TYPES_POLICY++; 1044 try { 1045 return trustedTypesPolicy.createHTML(html); 1046 } finally { 1047 IN_TRUSTED_TYPES_POLICY--; 1048 } 1049 }; 1050 const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) { 1051 _assertNotInTrustedTypesPolicy(); 1052 IN_TRUSTED_TYPES_POLICY++; 1053 try { 1054 return trustedTypesPolicy.createScriptURL(scriptUrl); 1055 } finally { 1056 IN_TRUSTED_TYPES_POLICY--; 1057 } 1058 }; 1059 const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() { 1060 if (!defaultTrustedTypesPolicyResolved) { 1061 defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); 1062 defaultTrustedTypesPolicyResolved = true; 1063 } 1064 return defaultTrustedTypesPolicy; 1065 }; 1066 const _document = document, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName; 1067 const importNode = originalDocument.importNode; 1068 let hooks = _createHooksMap(); 1069 /** 1070 * Expose whether this browser supports running the full DOMPurify. 1071 */ 1072 DOMPurify.isSupported = typeof entries === "function" && typeof getParentNode === "function" && implementation && implementation.createHTMLDocument !== void 0; 1073 const MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, TMPLIT_EXPR$1 = TMPLIT_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE, CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT; 1074 let IS_ALLOWED_URI$1 = IS_ALLOWED_URI; 1075 /** 1076 * We consider the elements and attributes below to be safe. Ideally 1077 * don't add any new ones but feel free to remove unwanted ones. 1078 */ 1079 let ALLOWED_TAGS = null; 1080 const DEFAULT_ALLOWED_TAGS = addToSet({}, [ 1081 ...html$1, 1082 ...svg$1, 1083 ...svgFilters, 1084 ...mathMl$1, 1085 ...text 1086 ]); 1087 let ALLOWED_ATTR = null; 1088 const DEFAULT_ALLOWED_ATTR = addToSet({}, [ 1089 ...html, 1090 ...svg, 1091 ...mathMl, 1092 ...xml 1093 ]); 1094 let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, { 1095 tagNameCheck: { 1096 writable: true, 1097 configurable: false, 1098 enumerable: true, 1099 value: null 1100 }, 1101 attributeNameCheck: { 1102 writable: true, 1103 configurable: false, 1104 enumerable: true, 1105 value: null 1106 }, 1107 allowCustomizedBuiltInElements: { 1108 writable: true, 1109 configurable: false, 1110 enumerable: true, 1111 value: false 1112 } 1113 })); 1114 let FORBID_TAGS = null; 1115 let FORBID_ATTR = null; 1116 const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, { 1117 tagCheck: { 1118 writable: true, 1119 configurable: false, 1120 enumerable: true, 1121 value: null 1122 }, 1123 attributeCheck: { 1124 writable: true, 1125 configurable: false, 1126 enumerable: true, 1127 value: null 1128 } 1129 })); 1130 let ALLOW_ARIA_ATTR = true; 1131 let ALLOW_DATA_ATTR = true; 1132 let ALLOW_UNKNOWN_PROTOCOLS = false; 1133 let ALLOW_SELF_CLOSE_IN_ATTR = true; 1134 let SAFE_FOR_TEMPLATES = false; 1135 let SAFE_FOR_XML = true; 1136 let WHOLE_DOCUMENT = false; 1137 let SET_CONFIG = false; 1138 let SET_CONFIG_ALLOWED_TAGS = null; 1139 let SET_CONFIG_ALLOWED_ATTR = null; 1140 let FORCE_BODY = false; 1141 let RETURN_DOM = false; 1142 let RETURN_DOM_FRAGMENT = false; 1143 let RETURN_TRUSTED_TYPE = false; 1144 let SANITIZE_DOM = true; 1145 let SANITIZE_NAMED_PROPS = false; 1146 const SANITIZE_NAMED_PROPS_PREFIX = "user-content-"; 1147 let KEEP_CONTENT = true; 1148 let IN_PLACE = false; 1149 let USE_PROFILES = {}; 1150 let FORBID_CONTENTS = null; 1151 const DEFAULT_FORBID_CONTENTS = addToSet({}, [ 1152 "annotation-xml", 1153 "audio", 1154 "colgroup", 1155 "desc", 1156 "foreignobject", 1157 "head", 1158 "iframe", 1159 "math", 1160 "mi", 1161 "mn", 1162 "mo", 1163 "ms", 1164 "mtext", 1165 "noembed", 1166 "noframes", 1167 "noscript", 1168 "plaintext", 1169 "script", 1170 "selectedcontent", 1171 "style", 1172 "svg", 1173 "template", 1174 "thead", 1175 "title", 1176 "video", 1177 "xmp" 1178 ]); 1179 let DATA_URI_TAGS = null; 1180 const DEFAULT_DATA_URI_TAGS = addToSet({}, [ 1181 "audio", 1182 "video", 1183 "img", 1184 "source", 1185 "image", 1186 "track" 1187 ]); 1188 let URI_SAFE_ATTRIBUTES = null; 1189 const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [ 1190 "alt", 1191 "class", 1192 "for", 1193 "id", 1194 "label", 1195 "name", 1196 "pattern", 1197 "placeholder", 1198 "role", 1199 "summary", 1200 "title", 1201 "value", 1202 "style", 1203 "xmlns" 1204 ]); 1205 const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML"; 1206 const SVG_NAMESPACE = "http://www.w3.org/2000/svg"; 1207 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; 1208 let NAMESPACE = HTML_NAMESPACE; 1209 let IS_EMPTY_INPUT = false; 1210 let ALLOWED_NAMESPACES = null; 1211 const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [ 1212 MATHML_NAMESPACE, 1213 SVG_NAMESPACE, 1214 HTML_NAMESPACE 1215 ], stringToString); 1216 const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze([ 1217 "mi", 1218 "mo", 1219 "mn", 1220 "ms", 1221 "mtext" 1222 ]); 1223 let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); 1224 const DEFAULT_HTML_INTEGRATION_POINTS = freeze(["annotation-xml"]); 1225 let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); 1226 const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [ 1227 "title", 1228 "style", 1229 "font", 1230 "a", 1231 "script" 1232 ]); 1233 let PARSER_MEDIA_TYPE = null; 1234 const SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"]; 1235 const DEFAULT_PARSER_MEDIA_TYPE = "text/html"; 1236 let transformCaseFunc = null; 1237 let CONFIG = null; 1238 const formElement = document.createElement("form"); 1239 const isRegexOrFunction = function isRegexOrFunction(testValue) { 1240 return testValue instanceof RegExp || testValue instanceof Function; 1241 }; 1242 /** 1243 * _parseConfig 1244 * 1245 * @param cfg optional config literal 1246 */ 1247 const _parseConfig = function _parseConfig() { 1248 let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 1249 if (CONFIG && CONFIG === cfg) return; 1250 if (!cfg || typeof cfg !== "object") cfg = {}; 1251 cfg = clone(cfg); 1252 PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE; 1253 transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? stringToString : stringToLowerCase; 1254 ALLOWED_TAGS = _resolveSetOption(cfg, "ALLOWED_TAGS", DEFAULT_ALLOWED_TAGS, { transform: transformCaseFunc }); 1255 ALLOWED_ATTR = _resolveSetOption(cfg, "ALLOWED_ATTR", DEFAULT_ALLOWED_ATTR, { transform: transformCaseFunc }); 1256 ALLOWED_NAMESPACES = _resolveSetOption(cfg, "ALLOWED_NAMESPACES", DEFAULT_ALLOWED_NAMESPACES, { transform: stringToString }); 1257 URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, "ADD_URI_SAFE_ATTR", DEFAULT_URI_SAFE_ATTRIBUTES, { 1258 transform: transformCaseFunc, 1259 base: DEFAULT_URI_SAFE_ATTRIBUTES 1260 }); 1261 DATA_URI_TAGS = _resolveSetOption(cfg, "ADD_DATA_URI_TAGS", DEFAULT_DATA_URI_TAGS, { 1262 transform: transformCaseFunc, 1263 base: DEFAULT_DATA_URI_TAGS 1264 }); 1265 FORBID_CONTENTS = _resolveSetOption(cfg, "FORBID_CONTENTS", DEFAULT_FORBID_CONTENTS, { transform: transformCaseFunc }); 1266 FORBID_TAGS = _resolveSetOption(cfg, "FORBID_TAGS", clone({}), { transform: transformCaseFunc }); 1267 FORBID_ATTR = _resolveSetOption(cfg, "FORBID_ATTR", clone({}), { transform: transformCaseFunc }); 1268 USE_PROFILES = objectHasOwnProperty(cfg, "USE_PROFILES") ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === "object" ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false; 1269 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; 1270 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; 1271 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; 1272 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; 1273 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; 1274 SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; 1275 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; 1276 RETURN_DOM = cfg.RETURN_DOM || false; 1277 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; 1278 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; 1279 FORCE_BODY = cfg.FORCE_BODY || false; 1280 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; 1281 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; 1282 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; 1283 IN_PLACE = cfg.IN_PLACE || false; 1284 IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; 1285 NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE; 1286 MATHML_TEXT_INTEGRATION_POINTS = _resolveObjectOption(cfg, "MATHML_TEXT_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS)); 1287 HTML_INTEGRATION_POINTS = _resolveObjectOption(cfg, "HTML_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS)); 1288 const customElementHandling = _resolveObjectOption(cfg, "CUSTOM_ELEMENT_HANDLING", () => create(null)); 1289 CUSTOM_ELEMENT_HANDLING = create(null); 1290 if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; 1291 if (objectHasOwnProperty(customElementHandling, "attributeNameCheck") && isRegexOrFunction(customElementHandling.attributeNameCheck)) CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; 1292 if (objectHasOwnProperty(customElementHandling, "allowCustomizedBuiltInElements") && typeof customElementHandling.allowCustomizedBuiltInElements === "boolean") CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; 1293 seal(CUSTOM_ELEMENT_HANDLING); 1294 if (SAFE_FOR_TEMPLATES) ALLOW_DATA_ATTR = false; 1295 if (RETURN_DOM_FRAGMENT) RETURN_DOM = true; 1296 if (USE_PROFILES) { 1297 ALLOWED_TAGS = addToSet({}, text); 1298 ALLOWED_ATTR = create(null); 1299 if (USE_PROFILES.html === true) { 1300 addToSet(ALLOWED_TAGS, html$1); 1301 addToSet(ALLOWED_ATTR, html); 1302 } 1303 if (USE_PROFILES.svg === true) { 1304 addToSet(ALLOWED_TAGS, svg$1); 1305 addToSet(ALLOWED_ATTR, svg); 1306 addToSet(ALLOWED_ATTR, xml); 1307 } 1308 if (USE_PROFILES.svgFilters === true) { 1309 addToSet(ALLOWED_TAGS, svgFilters); 1310 addToSet(ALLOWED_ATTR, svg); 1311 addToSet(ALLOWED_ATTR, xml); 1312 } 1313 if (USE_PROFILES.mathMl === true) { 1314 addToSet(ALLOWED_TAGS, mathMl$1); 1315 addToSet(ALLOWED_ATTR, mathMl); 1316 addToSet(ALLOWED_ATTR, xml); 1317 } 1318 } 1319 EXTRA_ELEMENT_HANDLING.tagCheck = null; 1320 EXTRA_ELEMENT_HANDLING.attributeCheck = null; 1321 if (objectHasOwnProperty(cfg, "ADD_TAGS")) { 1322 if (typeof cfg.ADD_TAGS === "function") EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS; 1323 else if (arrayIsArray(cfg.ADD_TAGS)) { 1324 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) ALLOWED_TAGS = clone(ALLOWED_TAGS); 1325 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); 1326 } 1327 } 1328 if (objectHasOwnProperty(cfg, "ADD_ATTR")) { 1329 if (typeof cfg.ADD_ATTR === "function") EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR; 1330 else if (arrayIsArray(cfg.ADD_ATTR)) { 1331 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) ALLOWED_ATTR = clone(ALLOWED_ATTR); 1332 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); 1333 } 1334 } 1335 if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) { 1336 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS); 1337 addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc); 1338 } 1339 if (KEEP_CONTENT) ALLOWED_TAGS["#text"] = true; 1340 if (WHOLE_DOCUMENT) addToSet(ALLOWED_TAGS, [ 1341 "html", 1342 "head", 1343 "body" 1344 ]); 1345 if (ALLOWED_TAGS.table) { 1346 addToSet(ALLOWED_TAGS, ["tbody"]); 1347 delete FORBID_TAGS.tbody; 1348 } 1349 if (cfg.TRUSTED_TYPES_POLICY) { 1350 if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook."); 1351 if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook."); 1352 const previousTrustedTypesPolicy = trustedTypesPolicy; 1353 trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; 1354 try { 1355 emptyHTML = _createTrustedHTML(""); 1356 } catch (error) { 1357 trustedTypesPolicy = previousTrustedTypesPolicy; 1358 throw error; 1359 } 1360 } else if (cfg.TRUSTED_TYPES_POLICY === null) { 1361 trustedTypesPolicy = void 0; 1362 emptyHTML = ""; 1363 } else { 1364 if (trustedTypesPolicy === void 0) trustedTypesPolicy = _getDefaultTrustedTypesPolicy(); 1365 if (trustedTypesPolicy && typeof emptyHTML === "string") emptyHTML = _createTrustedHTML(""); 1366 } 1367 if (freeze) freeze(cfg); 1368 CONFIG = cfg; 1369 }; 1370 const ALL_SVG_TAGS = addToSet({}, [ 1371 ...svg$1, 1372 ...svgFilters, 1373 ...svgDisallowed 1374 ]); 1375 const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]); 1376 /** 1377 * Namespace rules for an element in the SVG namespace. 1378 * 1379 * @param tagName the element's lowercase tag name 1380 * @param parent the (possibly simulated) parent node 1381 * @param parentTagName the parent's lowercase tag name 1382 * @returns true if a spec-compliant parser could produce this element 1383 */ 1384 const _checkSvgNamespace = function _checkSvgNamespace(tagName, parent, parentTagName) { 1385 if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "svg"; 1386 if (parent.namespaceURI === MATHML_NAMESPACE) return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); 1387 return Boolean(ALL_SVG_TAGS[tagName]); 1388 }; 1389 /** 1390 * Namespace rules for an element in the MathML namespace. 1391 * 1392 * @param tagName the element's lowercase tag name 1393 * @param parent the (possibly simulated) parent node 1394 * @param parentTagName the parent's lowercase tag name 1395 * @returns true if a spec-compliant parser could produce this element 1396 */ 1397 const _checkMathMlNamespace = function _checkMathMlNamespace(tagName, parent, parentTagName) { 1398 if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "math"; 1399 if (parent.namespaceURI === SVG_NAMESPACE) return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName]; 1400 return Boolean(ALL_MATHML_TAGS[tagName]); 1401 }; 1402 /** 1403 * Namespace rules for an element in the HTML namespace. 1404 * 1405 * @param tagName the element's lowercase tag name 1406 * @param parent the (possibly simulated) parent node 1407 * @param parentTagName the parent's lowercase tag name 1408 * @returns true if a spec-compliant parser could produce this element 1409 */ 1410 const _checkHtmlNamespace = function _checkHtmlNamespace(tagName, parent, parentTagName) { 1411 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) return false; 1412 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) return false; 1413 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); 1414 }; 1415 /** 1416 * @param element a DOM element whose namespace is being checked 1417 * @returns Return false if the element has a 1418 * namespace that a spec-compliant parser would never 1419 * return. Return true otherwise. 1420 */ 1421 const _checkValidNamespace = function _checkValidNamespace(element) { 1422 let parent = getParentNode(element); 1423 if (!parent || !parent.tagName) parent = { 1424 namespaceURI: NAMESPACE, 1425 tagName: "template" 1426 }; 1427 const tagName = stringToLowerCase(element.tagName); 1428 const parentTagName = stringToLowerCase(parent.tagName); 1429 if (!ALLOWED_NAMESPACES[element.namespaceURI]) return false; 1430 if (element.namespaceURI === SVG_NAMESPACE) return _checkSvgNamespace(tagName, parent, parentTagName); 1431 if (element.namespaceURI === MATHML_NAMESPACE) return _checkMathMlNamespace(tagName, parent, parentTagName); 1432 if (element.namespaceURI === HTML_NAMESPACE) return _checkHtmlNamespace(tagName, parent, parentTagName); 1433 if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[element.namespaceURI]) return true; 1434 return false; 1435 }; 1436 /** 1437 * _forceRemove 1438 * 1439 * @param node a DOM node 1440 */ 1441 const _forceRemove = function _forceRemove(node) { 1442 arrayPush(DOMPurify.removed, { element: node }); 1443 try { 1444 getParentNode(node).removeChild(node); 1445 } catch (_) { 1446 remove(node); 1447 if (!getParentNode(node)) throw typeErrorCreate("a node selected for removal could not be detached from its tree and cannot be safely returned; refusing to sanitize in place"); 1448 } 1449 }; 1450 /** 1451 * _stripAttributeNode 1452 * 1453 * Remove a single Attr node case/namespace-exactly on an attribute-teardown 1454 * path. Name-based removeAttribute() ASCII-lowercases its lookup key for an 1455 * HTML element in an HTML document and so silently misses a case-preserved 1456 * handler (e.g. `ONERROR` off an XML/XHTML import) - the same defect 1457 * _removeAttribute() was fixed for, which a name-based call would reintroduce 1458 * on these IN_PLACE teardown paths. Unlike _removeAttribute this does not 1459 * record into DOMPurify.removed: the neutralize passes intentionally do not 1460 * book-keep. A clobbered/detached node falls back to best-effort name-based 1461 * removal. 1462 * 1463 * @param element the element to strip the attribute from 1464 * @param attribute the Attr node to remove 1465 * @param name the attribute's name, for the fallback path 1466 */ 1467 const _stripAttributeNode = function _stripAttributeNode(element, attribute, name) { 1468 try { 1469 removeAttributeNode(element, attribute); 1470 } catch (_) { 1471 try { 1472 element.removeAttribute(name); 1473 } catch (_) {} 1474 } 1475 }; 1476 /** 1477 * _neutralizeRoot 1478 * 1479 * Fail-closed teardown of an in-place root after the sanitize walk aborts 1480 * (campaign-3 F2). An internal throw mid-walk â e.g. a page-registered 1481 * custom element's reaction detaches a node so `_forceRemove`'s deliberate 1482 * parentless guard throws, or any other re-entrant engine mutation â would 1483 * otherwise leave the caller's *live* tree half-sanitized, with everything 1484 * after the abort point still carrying its handlers. There is no safe way 1485 * to resume the walk (the tree mutated under us), so we strip the root bare: 1486 * remove every child and every attribute, then let the caller's catch see 1487 * the original error. Clobber-safe (cached `remove`/`childNodes`/`attributes` 1488 * getters; the root was already clobber-pre-flighted at the IN_PLACE entry). 1489 * 1490 * @param root the in-place root to empty 1491 */ 1492 const _neutralizeRoot = function _neutralizeRoot(root) { 1493 _neutralizeSubtree(root); 1494 const childNodes = getChildNodes(root); 1495 if (childNodes) { 1496 const snapshot = []; 1497 arrayForEach(childNodes, (child) => { 1498 arrayPush(snapshot, child); 1499 }); 1500 arrayForEach(snapshot, (child) => { 1501 try { 1502 remove(child); 1503 } catch (_) {} 1504 }); 1505 } 1506 const attributes = getAttributes(root); 1507 if (attributes) for (let i = attributes.length - 1; i >= 0; --i) { 1508 const attribute = attributes[i]; 1509 const name = attribute && attribute.name; 1510 if (typeof name === "string") _stripAttributeNode(root, attribute, name); 1511 } 1512 }; 1513 /** 1514 * _removeAttribute 1515 * 1516 * Name-based getAttributeNode()/removeAttribute() ASCII-lowercase their 1517 * lookup key for HTML elements in an HTML document, so they silently miss an 1518 * attribute whose stored qualified name still contains uppercase ASCII 1519 * letters. That happens when the node came from a case-preserving source 1520 * (an XML/XHTML document imported via importNode(), or createAttributeNS()), 1521 * where e.g. `ONERROR` survives the walk: the policy check lowercases to 1522 * `onerror` and rejects it, but `removeAttribute('ONERROR')` looks up 1523 * `onerror` and finds nothing. Remove the exact Attr node instead, which is 1524 * case- and namespace-exact, and fall back to name-based removal only when 1525 * the caller could not supply the node. 1526 * 1527 * @param name an Attribute name 1528 * @param element a DOM node 1529 * @param attr the exact Attr node to remove, when the caller has it 1530 */ 1531 const _removeAttribute = function _removeAttribute(name, element, attr) { 1532 if (!attr) try { 1533 attr = element.getAttributeNode(name); 1534 } catch (_) { 1535 attr = null; 1536 } 1537 arrayPush(DOMPurify.removed, { 1538 attribute: attr || null, 1539 from: element 1540 }); 1541 try { 1542 if (attr) removeAttributeNode(element, attr); 1543 else element.removeAttribute(name); 1544 } catch (_) { 1545 try { 1546 element.removeAttribute(name); 1547 } catch (_) {} 1548 } 1549 if (name === "is") { 1550 if (RETURN_DOM || RETURN_DOM_FRAGMENT) try { 1551 _forceRemove(element); 1552 } catch (_) {} 1553 else try { 1554 element.setAttribute(name, ""); 1555 } catch (_) {} 1556 } 1557 }; 1558 /** 1559 * _stripDisallowedAttributes 1560 * 1561 * Removes every attribute the active configuration does not allow from a 1562 * single element, using the same allowlist as the main attribute pass (so 1563 * `on*` handlers go, but no `/^on/` blocklist is introduced). Used only to 1564 * neutralise nodes that are being discarded from an in-place tree. 1565 * 1566 * @param element the element to strip 1567 */ 1568 const _stripDisallowedAttributes = function _stripDisallowedAttributes(element) { 1569 const attributes = getAttributes(element); 1570 if (!attributes) return; 1571 for (let i = attributes.length - 1; i >= 0; --i) { 1572 const attribute = attributes[i]; 1573 const name = attribute && attribute.name; 1574 if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) continue; 1575 _stripAttributeNode(element, attribute, name); 1576 } 1577 }; 1578 /** 1579 * _neutralizeSubtree 1580 * 1581 * Completes the audit-5 F1 fix across every removal path. The KEEP_CONTENT 1582 * move-hoist neutralises only disallowed-tag removals; clobber, mXSS-canary, 1583 * namespace, comment, processing-instruction and KEEP_CONTENT:false removals 1584 * all drop their subtree wholesale via `_forceRemove`. On the IN_PLACE path 1585 * those dropped nodes are detached from the caller's LIVE tree but a 1586 * handler-bearing original among them (an `<img onerror>`/`<video>` that was 1587 * loading) keeps its queued resource event, which fires in page scope after 1588 * sanitize returns. This walks a removed subtree and strips every attribute 1589 * the active configuration does not allow â so `on*` handlers are cancelled 1590 * through the SAME allowlist that governs kept nodes, not a separate `/^on/` 1591 * blocklist. Run synchronously before sanitize returns, i.e. before any 1592 * queued event can fire. Hook-free by design: these nodes leave the output, 1593 * so firing attribute hooks for them would be surprising. Clobber-safe reads; 1594 * a doomed clobbered node may shadow `removeAttribute` (its own attributes are 1595 * irrelevant â it is discarded â while its non-clobbered descendants, e.g. 1596 * the `<img>`, are reached and scrubbed). 1597 * 1598 * @param root the root of a removed subtree to neutralise 1599 */ 1600 const _neutralizeSubtree = function _neutralizeSubtree(root) { 1601 const stack = [root]; 1602 while (stack.length > 0) { 1603 const node = stack.pop(); 1604 if (_readNodeType(node) === NODE_TYPE.element) _stripDisallowedAttributes(node); 1605 const childNodes = getChildNodes(node); 1606 if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]); 1607 } 1608 }; 1609 /** 1610 * _neutralizePatchLinkage 1611 * 1612 * IN_PLACE entry pre-pass (declarative-partial-updates / streaming 1613 * hardening, https://github.com/WICG/declarative-partial-updates). 1614 * 1615 * The main walk strips patch linkage (`for`/`patchsrc`) and removes range 1616 * markers (PIs / markup comments) node-by-node, in document order, AS it 1617 * reaches each node. On a live in-place root that leaves a window: from the 1618 * moment the root is connected until the walk arrives at a given node, that 1619 * node's linkage is live. A patch applied on connection/stream can fire as 1620 * a microtask during the walk and inject or teleport an unsanitized DOM 1621 * range into a region the iterator has already passed and will not revisit, 1622 * so the post-return "tree is sanitized" contract is violated. Sweep the 1623 * whole tree once up front and sever every linkage before the walk begins, 1624 * closing that window. 1625 * 1626 * This CANNOT undo a patch that already fired before sanitize ran â that is 1627 * the irreducible "do not IN_PLACE a live-connected attacker tree" caveat â 1628 * but it closes everything from sanitize-start onward. Gated on SAFE_FOR_XML 1629 * to group with the rest of the declarative-partial-updates handling and 1630 * stay overridable, consistent with the codebase. 1631 * 1632 * Clobber-safe traversal (cached childNodes getter); per-node try/catch so a 1633 * clobbered root cannot defeat the sweep of its non-clobbered descendants. 1634 * 1635 * NOTE (pending real-Chrome confirmation, see test/declarative-patch-probe 1636 * .html Q1): this mirrors the existing policy of keeping `for` on 1637 * <label>/<output>. If the shipping feature can drive a patch through a 1638 * surviving `for`-on-label/output + `id` pair, this pre-pass and the 1639 * attribute check at _isBasicCustomElement's caller must additionally drop 1640 * that pair on the IN_PLACE path. Left as-is until the taxonomy is verified. 1641 * 1642 * @param root the in-place root to sweep 1643 */ 1644 /** 1645 * Central policy for declarative-partial-updates patch-linkage attributes, 1646 * shared by the _neutralizePatchLinkage pre-pass and _isValidAttribute so 1647 * the two sites cannot drift: `patchsrc` always links, `for` links 1648 * everywhere except on <label>/<output>, and the whole policy is gated on 1649 * SAFE_FOR_XML (see the rationale block in _isValidAttribute). 1650 * 1651 * @param lcName the transformCaseFunc'd attribute name 1652 * @param lcTag the transformCaseFunc'd tag name of the carrying element 1653 * @return true if the attribute is patch linkage and must be dropped 1654 */ 1655 const _isPatchLinkageAttribute = function _isPatchLinkageAttribute(lcName, lcTag) { 1656 if (!SAFE_FOR_XML) return false; 1657 if (lcName === "patchsrc") return true; 1658 return lcName === "for" && lcTag !== "label" && lcTag !== "output"; 1659 }; 1660 const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) { 1661 if (!SAFE_FOR_XML) return; 1662 const stack = [root]; 1663 while (stack.length > 0) { 1664 const node = stack.pop(); 1665 const nodeType = _readNodeType(node); 1666 if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) { 1667 try { 1668 remove(node); 1669 } catch (_) {} 1670 continue; 1671 } 1672 if (nodeType === NODE_TYPE.element) { 1673 const element = node; 1674 const lcTag = transformCaseFunc(_readNodeName(node)); 1675 try { 1676 if (element.hasAttribute && element.hasAttribute("patchsrc")) element.removeAttribute("patchsrc"); 1677 if (element.hasAttribute && element.hasAttribute("for") && _isPatchLinkageAttribute("for", lcTag)) element.removeAttribute("for"); 1678 } catch (_) {} 1679 } 1680 const childNodes = getChildNodes(node); 1681 if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]); 1682 } 1683 }; 1684 /** 1685 * _initDocument 1686 * 1687 * @param dirty - a string of dirty markup 1688 * @return a DOM, filled with the dirty markup 1689 */ 1690 const _initDocument = function _initDocument(dirty) { 1691 let doc = null; 1692 let leadingWhitespace = null; 1693 if (FORCE_BODY) dirty = "<remove></remove>" + dirty; 1694 else { 1695 const matches = stringMatch(dirty, /^[\r\n\t ]+/); 1696 leadingWhitespace = matches && matches[0]; 1697 } 1698 if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && NAMESPACE === HTML_NAMESPACE) dirty = "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>" + dirty + "</body></html>"; 1699 const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty; 1700 if (NAMESPACE === HTML_NAMESPACE) try { 1701 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); 1702 } catch (_) {} 1703 if (!doc || !doc.documentElement) { 1704 doc = implementation.createDocument(NAMESPACE, "template", null); 1705 try { 1706 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload; 1707 } catch (_) {} 1708 } 1709 const body = doc.body || doc.documentElement; 1710 if (dirty && leadingWhitespace) body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null); 1711 if (NAMESPACE === HTML_NAMESPACE) return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0]; 1712 return WHOLE_DOCUMENT ? doc.documentElement : body; 1713 }; 1714 /** 1715 * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. 1716 * 1717 * @param root The root element or node to start traversing on. 1718 * @return The created NodeIterator 1719 */ 1720 const _createNodeIterator = function _createNodeIterator(root) { 1721 const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument; 1722 return createNodeIterator.call(doc || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null); 1723 }; 1724 /** 1725 * Replace template expression syntax (mustache, ERB, template 1726 * literal) with a space; shared by all SAFE_FOR_TEMPLATES scrub 1727 * sites. Order matters: mustache, then ERB, then template literal. 1728 * 1729 * @param value the string to scrub 1730 * @returns the scrubbed string 1731 */ 1732 const _stripTemplateExpressions = function _stripTemplateExpressions(value) { 1733 value = stringReplace(value, MUSTACHE_EXPR$1, " "); 1734 value = stringReplace(value, ERB_EXPR$1, " "); 1735 value = stringReplace(value, TMPLIT_EXPR$1, " "); 1736 return value; 1737 }; 1738 /** 1739 * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the 1740 * character data of an element subtree. Used as the final safety net for 1741 * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions 1742 * which only form after text-node normalization (e.g. fragments split across 1743 * stripped elements) cannot survive into a template-evaluating framework. 1744 * 1745 * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data` 1746 * in place rather than round-tripping through innerHTML. This preserves 1747 * descendant node references (important for IN_PLACE callers), avoids a 1748 * serialize/reparse cycle, and reads literal character data â which means 1749 * `<%...%>` in text content matches the ERB regex against its real bytes 1750 * instead of the HTML-entity-escaped form innerHTML would produce. 1751 * 1752 * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for 1753 * attributes is performed during the per-node `_sanitizeAttributes` pass. 1754 * 1755 * @param node The root element whose character data should be scrubbed. 1756 */ 1757 const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) { 1758 var _node$querySelectorAl; 1759 node.normalize(); 1760 const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument; 1761 const walker = createNodeIterator.call(doc || node, node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null); 1762 let currentNode = walker.nextNode(); 1763 while (currentNode) { 1764 currentNode.data = _stripTemplateExpressions(currentNode.data); 1765 currentNode = walker.nextNode(); 1766 } 1767 const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template"); 1768 if (templates) arrayForEach(templates, (tmpl) => { 1769 if (_isDocumentFragment(tmpl.content)) _scrubTemplateExpressions2(tmpl.content); 1770 }); 1771 }; 1772 /** 1773 * _isClobbered 1774 * 1775 * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML 1776 * interface with [LegacyOverrideBuiltIns]; a descendant element with a 1777 * `name` attribute matching a prototype property shadows that property 1778 * on direct reads. We use this check at the IN_PLACE entry-point and 1779 * during attribute sanitization to refuse clobbered forms. 1780 * 1781 * @param element element to check for clobbering attacks 1782 * @return true if clobbered, false if safe 1783 */ 1784 const _isClobbered = function _isClobbered(element) { 1785 const realTagName = getNodeName ? getNodeName(element) : null; 1786 if (typeof realTagName !== "string") return false; 1787 if (transformCaseFunc(realTagName) !== "form") return false; 1788 return typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || element.attributes !== getAttributes(element) || typeof element.removeAttribute !== "function" || typeof element.removeAttributeNode !== "function" || typeof element.getAttributeNode !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function" || element.nodeType !== getNodeType(element) || element.childNodes !== getChildNodes(element); 1789 }; 1790 /** 1791 * Checks whether the given value is a DocumentFragment from any realm. 1792 * 1793 * The realm-independent replacement reads `nodeType` through the cached 1794 * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE 1795 * constant (11). nodeType is a numeric value resolved from the node's 1796 * internal slot, identical across realms for the same kind of node. 1797 * 1798 * @param value object to check 1799 * @return true if value is a DocumentFragment-shaped node from any realm 1800 */ 1801 const _isDocumentFragment = function _isDocumentFragment(value) { 1802 if (!getNodeType || typeof value !== "object" || value === null) return false; 1803 try { 1804 return getNodeType(value) === NODE_TYPE.documentFragment; 1805 } catch (_) { 1806 return false; 1807 } 1808 }; 1809 /** 1810 * Checks whether the given object is a DOM node, including nodes that 1811 * originate from a different window/realm (e.g. an iframe's 1812 * contentDocument). The previous `value instanceof Node` check was 1813 * realm-bound: nodes from a different window failed it, causing 1814 * sanitize() to silently stringify them and reset IN_PLACE to false, 1815 * returning the original node unsanitized. See GHSA-4w3q-35jp-p934. 1816 * 1817 * @param value object to check whether it's a DOM node 1818 * @return true if value is a DOM node from any realm 1819 */ 1820 const _isNode = function _isNode(value) { 1821 if (!getNodeType || typeof value !== "object" || value === null) return false; 1822 try { 1823 return typeof getNodeType(value) === "number"; 1824 } catch (_) { 1825 return false; 1826 } 1827 }; 1828 function _executeHooks(hooks, currentNode, data) { 1829 if (hooks.length === 0) return; 1830 arrayForEach(hooks, (hook) => { 1831 hook.call(DOMPurify, currentNode, data, CONFIG); 1832 }); 1833 } 1834 /** 1835 * Structural-threat checks that condemn a node regardless of the 1836 * allowlists: mXSS via namespace confusion, risky CSS construction, 1837 * processing instructions, markup-bearing comments. Pure predicate; 1838 * the caller removes. Check order is load-bearing. 1839 * 1840 * @param currentNode the node to inspect 1841 * @param tagName the node's transformCaseFunc'd tag name 1842 * @return true if the node must be removed 1843 */ 1844 const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) { 1845 if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) return true; 1846 if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && LITERAL_TEXT_ELEMENTS[tagName] && (_isNode(currentNode.firstElementChild) || typeof currentNode.textContent === "string" && regExpTest(LITERAL_TEXT_CLOSE[tagName], currentNode.textContent))) return true; 1847 if (currentNode.nodeType === NODE_TYPE.processingInstruction) return true; 1848 if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) return true; 1849 return false; 1850 }; 1851 /** 1852 * Evaluate a CUSTOM_ELEMENT_HANDLING check (a RegExp or a predicate 1853 * function, per the validation in _parseConfig) against a name. 1854 * Additional arguments are forwarded to predicate functions - the 1855 * attributeNameCheck predicate receives the tag name as its second 1856 * argument. A null/absent check never matches. 1857 * 1858 * @param check the configured tagNameCheck / attributeNameCheck value 1859 * @param name the name to test 1860 * @param args extra arguments forwarded to a predicate function 1861 * @return true if the check matches the name 1862 */ 1863 const _matchesNameCheck = function _matchesNameCheck(check, name) { 1864 if (check instanceof RegExp) return regExpTest(check, name); 1865 if (check instanceof Function) { 1866 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key]; 1867 return Boolean(check(name, ...args)); 1868 } 1869 return false; 1870 }; 1871 /** 1872 * Handle a node whose tag is forbidden or not allowlisted: keep 1873 * allowed custom elements (false return exits _sanitizeElements 1874 * early - the namespace and fallback-tag removal checks are 1875 * intentionally skipped for kept custom elements), else hoist 1876 * content per KEEP_CONTENT and remove. 1877 * 1878 * A kept custom element is the ONLY case in which this function 1879 * returns false, so the caller uses that return value to run the 1880 * afterSanitizeElements hook on the kept element and keep the 1881 * element-hook lifecycle consistent with normal allowlisted 1882 * elements (GHSA-c2j3-45gr-mqc4). 1883 * 1884 * @param currentNode the disallowed node 1885 * @param tagName the node's transformCaseFunc'd tag name 1886 * @return true if the node was removed, false if kept 1887 */ 1888 const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) { 1889 if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false; 1890 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) { 1891 const parentNode = getParentNode(currentNode); 1892 const childNodes = getChildNodes(currentNode); 1893 if (childNodes && parentNode) { 1894 const childCount = childNodes.length; 1895 for (let i = childCount - 1; i >= 0; --i) { 1896 const hoisted = currentNode === root ? cloneNode(childNodes[i], true) : childNodes[i]; 1897 parentNode.insertBefore(hoisted, getNextSibling(currentNode)); 1898 } 1899 } 1900 } 1901 _forceRemove(currentNode); 1902 return true; 1903 }; 1904 /** 1905 * Fork a hook-mutable allowlist off its shared binding the first time a 1906 * (possibly lazily-installed) uponSanitize* hook is about to see it, so the 1907 * hook cannot widen the per-instance default or the setConfig binding by 1908 * reference and leak past the call. Returns the set unchanged once it is 1909 * already call-local, so repeated calls across elements are idempotent. 1910 * 1911 * @param hookList the uponSanitize* hook array for this event 1912 * @param set the current ALLOWED_TAGS / ALLOWED_ATTR binding 1913 * @param defaultSet the per-instance DEFAULT_ALLOWED_* constant 1914 * @param setConfigSet the captured setConfig() binding, or null 1915 * @return a call-local clone if a hook is present and set is still shared, 1916 * else set unchanged 1917 */ 1918 const _forkSharedAllowlist = function _forkSharedAllowlist(hookList, set, defaultSet, setConfigSet) { 1919 if (hookList.length === 0) return set; 1920 return set === defaultSet || set === setConfigSet ? clone(set) : set; 1921 }; 1922 /** 1923 * Shared guard for a node that a hook has detached from the walk tree, 1924 * used after each element-hook site in _sanitizeElements. Detaching is a 1925 * long-standing user pattern (issue #469; draw.io-style foreignObject 1926 * filtering). Per the cached, unclobberable parentNode getter the node is 1927 * genuinely out of the tree, so it can reach neither the serialized 1928 * output nor an IN_PLACE live tree; treat it as removed and stop 1929 * processing it. Without this guard, the unsafe-node / namespace checks 1930 * would call _forceRemove on a parentless node and hit the REPORT-3 1931 * fail-closed throw â which exists for nodes DOMPurify wants gone but 1932 * *cannot* detach (clobbered / parentless roots), the opposite of a node 1933 * that is already safely gone. The walk root is exempt: a detached 1934 * IN_PLACE root is legitimate input and must still be fully sanitized, 1935 * and a kill-decision on it must keep hitting the REPORT-3 throw. 1936 * 1937 * Nodes detached by hooks stay the hook's responsibility for placement: 1938 * they are not recorded in DOMPurify.removed, so the post-walk IN_PLACE 1939 * pass (which iterates DOMPurify.removed) does not reach them. But a 1940 * hook-detached subtree can still hold a queued resource-event handler - 1941 * e.g. an <img onload> that began loading when the caller built the live 1942 * tree - which fires in page scope after sanitize returns even though the 1943 * handler never reached the returned tree. That is the audit-5 F1 hazard, 1944 * and the documented node.remove() hook pattern walks straight into it. 1945 * So on the IN_PLACE path we neutralize the detached subtree inline, 1946 * stripping its non-allow-listed attributes before returning, exactly as 1947 * the post-walk pass does for _forceRemove'd subtrees. 1948 * 1949 * @param currentNode the node a hook may have detached 1950 * @param root the current walk root 1951 * @return true if the node is detached and now handled, false otherwise 1952 */ 1953 const _handleHookDetachedNode = function _handleHookDetachedNode(currentNode, root) { 1954 if (currentNode === root || getParentNode(currentNode) !== null) return false; 1955 if (IN_PLACE) _neutralizeSubtree(currentNode); 1956 return true; 1957 }; 1958 /** 1959 * _sanitizeElements 1960 * 1961 * @protect nodeName 1962 * @protect textContent 1963 * @protect removeChild 1964 * @param currentNode to check for permission to exist 1965 * @return true if node was killed, false if left alive 1966 */ 1967 const _sanitizeElements = function _sanitizeElements(currentNode, root) { 1968 _executeHooks(hooks.beforeSanitizeElements, currentNode, null); 1969 if (_handleHookDetachedNode(currentNode, root)) return true; 1970 if (_isClobbered(currentNode)) { 1971 _forceRemove(currentNode); 1972 return true; 1973 } 1974 const tagName = transformCaseFunc(_readNodeName(currentNode)); 1975 ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS); 1976 _executeHooks(hooks.uponSanitizeElement, currentNode, { 1977 tagName, 1978 allowedTags: ALLOWED_TAGS 1979 }); 1980 if (_handleHookDetachedNode(currentNode, root)) return true; 1981 if (_isUnsafeNode(currentNode, tagName)) { 1982 _forceRemove(currentNode); 1983 return true; 1984 } 1985 if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) { 1986 const removed = _sanitizeDisallowedNode(currentNode, tagName, root); 1987 if (removed === false)
vendor: 9,910 bytes, lines 1987-2211
1987_executeHooks(hooks.afterSanitizeElements, currentNode, null); 1988 return removed; 1989 } 1990 if (_readNodeType(currentNode) === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { 1991 _forceRemove(currentNode); 1992 return true; 1993 } 1994 if ((tagName === "noscript" || tagName === "noembed" || tagName === "noframes") && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) { 1995 _forceRemove(currentNode); 1996 return true; 1997 } 1998 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) { 1999 const content = _stripTemplateExpressions(currentNode.textContent); 2000 if (currentNode.textContent !== content) { 2001 arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() }); 2002 currentNode.textContent = content; 2003 } 2004 } 2005 _executeHooks(hooks.afterSanitizeElements, currentNode, null); 2006 return false; 2007 }; 2008 /** 2009 * _isValidAttribute 2010 * 2011 * @param lcTag Lowercase tag name of containing element. 2012 * @param lcName Lowercase attribute name. 2013 * @param value Attribute value. 2014 * @return Returns true if `value` is valid, otherwise false. 2015 */ 2016 const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) { 2017 if (FORBID_ATTR[lcName]) return false; 2018 if (_isPatchLinkageAttribute(lcName, lcTag)) return false; 2019 if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document || value in formElement)) return false; 2020 const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag); 2021 if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) return true; 2022 if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) return true; 2023 if (!nameIsPermitted) return _isBasicCustomElement(lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName, lcTag) || lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value); 2024 if (URI_SAFE_ATTRIBUTES[lcName]) return true; 2025 if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true; 2026 if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]) return true; 2027 if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true; 2028 return !value; 2029 }; 2030 const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, [ 2031 "annotation-xml", 2032 "color-profile", 2033 "font-face", 2034 "font-face-format", 2035 "font-face-name", 2036 "font-face-src", 2037 "font-face-uri", 2038 "missing-glyph" 2039 ]); 2040 /** 2041 * _isBasicCustomElement 2042 * checks if at least one dash is included in tagName, and it's not the first char 2043 * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name 2044 * 2045 * @param tagName name of the tag of the node to sanitize 2046 * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false. 2047 */ 2048 const _isBasicCustomElement = function _isBasicCustomElement(tagName) { 2049 return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName); 2050 }; 2051 /** 2052 * Wrap an attribute value in the matching Trusted Types object when 2053 * the active policy requires it. Namespaced attributes pass through 2054 * unchanged (no TT support yet, see 2055 * https://bugs.chromium.org/p/chromium/issues/detail?id=1305293). 2056 * 2057 * @param lcTag lowercase tag name of the containing element 2058 * @param lcName lowercase attribute name 2059 * @param namespaceURI the attribute's namespace, if any 2060 * @param value the attribute value to wrap 2061 * @return the value, wrapped when Trusted Types demand it 2062 */ 2063 const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value) { 2064 if (trustedTypesPolicy && typeof trustedTypes === "object" && typeof trustedTypes.getAttributeType === "function" && !namespaceURI) switch (trustedTypes.getAttributeType(lcTag, lcName)) { 2065 case "TrustedHTML": return _createTrustedHTML(value); 2066 case "TrustedScriptURL": return _createTrustedScriptURL(value); 2067 } 2068 return value; 2069 }; 2070 /** 2071 * Write a modified attribute value back onto the element. On 2072 * success, re-probe for clobbering introduced by the new value and 2073 * remove the element when found; otherwise, when this writeback is the 2074 * recreate half of the SANITIZE_NAMED_PROPS remove-and-recreate, pop the 2075 * removal entry that path recorded so it does not show as removed. On 2076 * failure, remove the attribute instead. 2077 * 2078 * Returns true only on a clean write (the value was set and the new value 2079 * introduced no clobbering). The caller uses that, together with its own 2080 * knowledge of whether this attribute pushed a DOMPurify.removed record, to 2081 * decide whether to pop that record. The pop must happen ONLY for the 2082 * named-prop remove-and-recreate; popping on any other value change (trim, 2083 * template scrubbing, Trusted Types) would consume an unrelated _forceRemove 2084 * subtree-cleanup record and let that detached subtree keep a live event 2085 * handler through the IN_PLACE neutralization pass (SO-001). 2086 * 2087 * @param currentNode the element carrying the attribute 2088 * @param name the attribute name as present on the element 2089 * @param namespaceURI the attribute's namespace, if any 2090 * @param value the new attribute value 2091 * @return true if the value was written without introducing clobbering 2092 */ 2093 const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) { 2094 try { 2095 if (namespaceURI) currentNode.setAttributeNS(namespaceURI, name, value); 2096 else currentNode.setAttribute(name, value); 2097 if (_isClobbered(currentNode)) { 2098 _forceRemove(currentNode); 2099 return false; 2100 } 2101 return true; 2102 } catch (_) { 2103 _removeAttribute(name, currentNode); 2104 return false; 2105 } 2106 }; 2107 /** 2108 * _sanitizeAttributes 2109 * 2110 * @protect attributes 2111 * @protect nodeName 2112 * @protect removeAttribute 2113 * @protect setAttribute 2114 * 2115 * @param currentNode to sanitize 2116 */ 2117 const _sanitizeAttributes = function _sanitizeAttributes(currentNode) { 2118 _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null); 2119 const attributes = currentNode.attributes; 2120 if (!attributes || _isClobbered(currentNode)) return; 2121 ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR); 2122 const hookEvent = { 2123 attrName: "", 2124 attrValue: "", 2125 keepAttr: true, 2126 allowedAttributes: ALLOWED_ATTR, 2127 forceKeepAttr: void 0 2128 }; 2129 let l = attributes.length; 2130 const lcTag = transformCaseFunc(currentNode.nodeName); 2131 while (l--) { 2132 const attr = attributes[l]; 2133 const name = attr.name, namespaceURI = attr.namespaceURI, attrValue = attr.value; 2134 const lcName = transformCaseFunc(name); 2135 const initValue = attrValue; 2136 let value = name === "value" ? initValue : stringTrim(initValue); 2137 let recreatedNamedProp = false; 2138 hookEvent.attrName = lcName; 2139 hookEvent.attrValue = value; 2140 hookEvent.keepAttr = true; 2141 hookEvent.forceKeepAttr = void 0; 2142 _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent); 2143 value = hookEvent.attrValue; 2144 if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) { 2145 _removeAttribute(name, currentNode, attr); 2146 value = SANITIZE_NAMED_PROPS_PREFIX + value; 2147 recreatedNamedProp = true; 2148 } 2149 if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) { 2150 _removeAttribute(name, currentNode, attr); 2151 continue; 2152 } 2153 if (lcName === "attributename" && stringMatch(value, "href")) { 2154 _removeAttribute(name, currentNode, attr); 2155 continue; 2156 } 2157 if (hookEvent.forceKeepAttr) continue; 2158 if (!hookEvent.keepAttr) { 2159 _removeAttribute(name, currentNode, attr); 2160 continue; 2161 } 2162 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) { 2163 _removeAttribute(name, currentNode, attr); 2164 continue; 2165 } 2166 if (SAFE_FOR_TEMPLATES) value = _stripTemplateExpressions(value); 2167 if (!_isValidAttribute(lcTag, lcName, value)) { 2168 _removeAttribute(name, currentNode, attr); 2169 continue; 2170 } 2171 value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value); 2172 if (value !== initValue) { 2173 if (_setAttributeValue(currentNode, name, namespaceURI, value) && recreatedNamedProp) arrayPop(DOMPurify.removed); 2174 } 2175 } 2176 _executeHooks(hooks.afterSanitizeAttributes, currentNode, null); 2177 }; 2178 /** 2179 * _sanitizeShadowDOM 2180 * 2181 * @param fragment to iterate over recursively 2182 */ 2183 const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) { 2184 let shadowNode = null; 2185 const shadowIterator = _createNodeIterator(fragment); 2186 _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null); 2187 while (shadowNode = shadowIterator.nextNode()) { 2188 _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null); 2189 _sanitizeElements(shadowNode, fragment); 2190 _sanitizeAttributes(shadowNode); 2191 if (_isDocumentFragment(shadowNode.content)) _sanitizeShadowDOM2(shadowNode.content); 2192 if (_readNodeType(shadowNode) === NODE_TYPE.element) { 2193 const innerSr = getShadowRoot(shadowNode); 2194 if (_isDocumentFragment(innerSr)) { 2195 _sanitizeAttachedShadowRoots(innerSr); 2196 _sanitizeShadowDOM2(innerSr); 2197 } 2198 } 2199 } 2200 _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null); 2201 }; 2202 /** 2203 * _sanitizeAttachedShadowRoots 2204 * 2205 * Walks `root` and feeds every attached shadow root we encounter into 2206 * the existing _sanitizeShadowDOM pipeline. The default node iterator 2207 * does not descend into shadow trees, so nodes inside an attached 2208 * shadow root would otherwise be skipped entirely. 2209 * 2210 * Two real input paths put attached shadow roots in front of us: 2211 * 1. IN_PLACE on a DOM node that already has shadow roots attached.
vendor: 4,441 bytes, lines 2212-2335
2212 * 2. DOM-node input where importNode(dirty, true) deep-clones the 2213 * shadow root because it was created with `clonable: true`. 2214 * 2215 * This pass runs once, up front, so the main iteration loop (and the 2216 * existing _sanitizeShadowDOM template-content recursion) stay 2217 * untouched â string-input paths are not affected. 2218 * 2219 * @param root the subtree root to walk for attached shadow roots 2220 */ 2221 const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots(root) { 2222 const stack = [{ 2223 node: root, 2224 shadow: null 2225 }]; 2226 while (stack.length > 0) { 2227 const item = stack.pop(); 2228 if (item.shadow) { 2229 _sanitizeShadowDOM2(item.shadow); 2230 continue; 2231 } 2232 const node = item.node; 2233 const isElement = _readNodeType(node) === NODE_TYPE.element; 2234 const childNodes = getChildNodes(node); 2235 if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push({ 2236 node: childNodes[i], 2237 shadow: null 2238 }); 2239 if (isElement) { 2240 const rootName = getNodeName ? getNodeName(node) : null; 2241 if (typeof rootName === "string" && transformCaseFunc(rootName) === "template") { 2242 const content = node.content; 2243 if (_isDocumentFragment(content)) stack.push({ 2244 node: content, 2245 shadow: null 2246 }); 2247 } 2248 } 2249 if (isElement) { 2250 const sr = getShadowRoot(node); 2251 if (_isDocumentFragment(sr)) stack.push({ 2252 node: null, 2253 shadow: sr 2254 }, { 2255 node: sr, 2256 shadow: null 2257 }); 2258 } 2259 } 2260 }; 2261 DOMPurify.sanitize = function(dirty) { 2262 let cfg = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; 2263 let body = null; 2264 let importedNode = null; 2265 let currentNode = null; 2266 let returnNode = null; 2267 IS_EMPTY_INPUT = !dirty; 2268 if (IS_EMPTY_INPUT) dirty = "<!-->"; 2269 if (typeof dirty !== "string" && !_isNode(dirty)) { 2270 dirty = stringifyValue(dirty); 2271 if (typeof dirty !== "string") throw typeErrorCreate("dirty is not a string, aborting"); 2272 } 2273 if (!DOMPurify.isSupported) return dirty; 2274 if (SET_CONFIG) { 2275 ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS; 2276 ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR; 2277 } else _parseConfig(cfg); 2278 if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) ALLOWED_TAGS = clone(ALLOWED_TAGS); 2279 if (hooks.uponSanitizeAttribute.length > 0) ALLOWED_ATTR = clone(ALLOWED_ATTR); 2280 DOMPurify.removed = []; 2281 const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty); 2282 if (inPlace) { 2283 _neutralizePatchLinkage(dirty); 2284 const nn = _readNodeName(dirty); 2285 if (typeof nn === "string") { 2286 const tagName = transformCaseFunc(nn); 2287 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { 2288 _neutralizeRoot(dirty); 2289 throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place"); 2290 } 2291 } 2292 if (_isClobbered(dirty)) { 2293 _neutralizeRoot(dirty); 2294 throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place"); 2295 } 2296 try { 2297 _sanitizeAttachedShadowRoots(dirty); 2298 } catch (error) { 2299 _neutralizeRoot(dirty); 2300 throw error; 2301 } 2302 } else if (_isNode(dirty)) { 2303 body = _initDocument("<!---->"); 2304 importedNode = body.ownerDocument.importNode(dirty, true); 2305 if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === "BODY") body = importedNode; 2306 else if (importedNode.nodeName === "HTML") body = importedNode; 2307 else body.appendChild(importedNode); 2308 _sanitizeAttachedShadowRoots(body); 2309 } else { 2310 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf("<") === -1) return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty; 2311 body = _initDocument(dirty); 2312 if (!body) return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : ""; 2313 } 2314 if (body && FORCE_BODY) _forceRemove(body.firstChild); 2315 const walkRoot = inPlace ? dirty : body; 2316 try { 2317 const nodeIterator = _createNodeIterator(walkRoot); 2318 while (currentNode = nodeIterator.nextNode()) { 2319 _sanitizeElements(currentNode, walkRoot); 2320 _sanitizeAttributes(currentNode); 2321 if (_isDocumentFragment(currentNode.content)) _sanitizeShadowDOM2(currentNode.content); 2322 } 2323 } catch (error) { 2324 if (inPlace) { 2325 _neutralizeRoot(dirty); 2326 arrayForEach(DOMPurify.removed, (entry) => { 2327 if (entry.element) _neutralizeSubtree(entry.element); 2328 }); 2329 } 2330 throw error; 2331 } 2332 if (inPlace) { 2333 arrayForEach(DOMPurify.removed, (entry) => { 2334 if (entry.element) _neutralizeSubtree(entry.element); 2335 });
vendor: 2,623 bytes, lines 2336-2398
2336 if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(dirty); 2337 return dirty; 2338 } 2339 if (RETURN_DOM) { 2340 if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(body); 2341 if (RETURN_DOM_FRAGMENT) { 2342 returnNode = createDocumentFragment.call(body.ownerDocument); 2343 while (body.firstChild) returnNode.appendChild(body.firstChild); 2344 } else returnNode = body; 2345 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) returnNode = importNode.call(originalDocument, returnNode, true); 2346 return returnNode; 2347 } 2348 let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; 2349 if (WHOLE_DOCUMENT && ALLOWED_TAGS["!doctype"] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) serializedHTML = "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML; 2350 if (SAFE_FOR_TEMPLATES) serializedHTML = _stripTemplateExpressions(serializedHTML); 2351 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML; 2352 }; 2353 DOMPurify.setConfig = function() { 2354 let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 2355 _parseConfig(cfg); 2356 SET_CONFIG = true; 2357 SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS; 2358 SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR; 2359 }; 2360 DOMPurify.clearConfig = function() { 2361 CONFIG = null; 2362 SET_CONFIG = false; 2363 SET_CONFIG_ALLOWED_TAGS = null; 2364 SET_CONFIG_ALLOWED_ATTR = null; 2365 trustedTypesPolicy = defaultTrustedTypesPolicy; 2366 emptyHTML = ""; 2367 }; 2368 DOMPurify.isValidAttribute = function(tag, attr, value) { 2369 if (!CONFIG) _parseConfig({}); 2370 const lcTag = transformCaseFunc(tag); 2371 const lcName = transformCaseFunc(attr); 2372 return _isValidAttribute(lcTag, lcName, value); 2373 }; 2374 DOMPurify.addHook = function(entryPoint, hookFunction) { 2375 if (typeof hookFunction !== "function") return; 2376 if (!objectHasOwnProperty(hooks, entryPoint)) return; 2377 arrayPush(hooks[entryPoint], hookFunction); 2378 }; 2379 DOMPurify.removeHook = function(entryPoint, hookFunction) { 2380 if (!objectHasOwnProperty(hooks, entryPoint)) return; 2381 if (hookFunction !== void 0) { 2382 const index = arrayLastIndexOf(hooks[entryPoint], hookFunction); 2383 return index === -1 ? void 0 : arraySplice(hooks[entryPoint], index, 1)[0]; 2384 } 2385 return arrayPop(hooks[entryPoint]); 2386 }; 2387 DOMPurify.removeHooks = function(entryPoint) { 2388 if (!objectHasOwnProperty(hooks, entryPoint)) return; 2389 hooks[entryPoint] = []; 2390 }; 2391 DOMPurify.removeAllHooks = function() { 2392 hooks = _createHooksMap(); 2393 }; 2394 return DOMPurify; 2395} 2396var purify = createDOMPurify(); 2397//#endregion 2398export { purify as default };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.