purify.js

From disqus.com, 1 Week ago, written in JavaScript, viewed 3 times. This paste is a reply to ediaCollection.js from disqus.com - view diff
URL https://pastebin.freepbx.org/view/d8c64a3b Embed
Download Paste or View Raw
  1. (function (global, factory) {
  2.         typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3.         typeof define === 'function' && define.amd ? define('dompurify',factory) :
  4.         (global.DOMPurify = factory());
  5. }(this, (function () { 'use strict';
  6.  
  7. var freeze$1 = Object.freeze || function (x) {
  8.   return x;
  9. };
  10.  
  11. var html = freeze$1(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
  12.  
  13. // SVG
  14. var svg = freeze$1(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'audio', 'canvas', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'video', 'view', 'vkern']);
  15.  
  16. var svgFilters = freeze$1(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
  17.  
  18. var mathMl = freeze$1(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']);
  19.  
  20. var text = freeze$1(['#text']);
  21.  
  22. var freeze$2 = Object.freeze || function (x) {
  23.   return x;
  24. };
  25.  
  26. var html$1 = freeze$2(['accept', 'action', 'align', 'alt', 'autocomplete', 'background', 'bgcolor', 'border', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'coords', 'crossorigin', 'datetime', 'default', 'dir', 'disabled', 'download', 'enctype', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'integrity', 'ismap', 'label', 'lang', 'list', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']);
  27.  
  28. var svg$1 = freeze$2(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
  29.  
  30. var mathMl$1 = freeze$2(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
  31.  
  32. var xml = freeze$2(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
  33.  
  34. var hasOwnProperty = Object.hasOwnProperty;
  35. var setPrototypeOf = Object.setPrototypeOf;
  36.  
  37. var _ref$1 = typeof Reflect !== 'undefined' && Reflect;
  38. var apply$1 = _ref$1.apply;
  39.  
  40. if (!apply$1) {
  41.   apply$1 = function apply(fun, thisValue, args) {
  42.     return fun.apply(thisValue, args);
  43.   };
  44. }
  45.  
  46. /* Add properties to a lookup table */
  47. function addToSet(set, array) {
  48.   if (setPrototypeOf) {
  49.     // Make 'in' and truthy checks like Boolean(set.constructor)
  50.     // independent of any properties defined on Object.prototype.
  51.     // Prevent prototype setters from intercepting set as a this value.
  52.     setPrototypeOf(set, null);
  53.   }
  54.  
  55.   var l = array.length;
  56.   while (l--) {
  57.     var element = array[l];
  58.     if (typeof element === 'string') {
  59.       var lcElement = element.toLowerCase();
  60.       if (lcElement !== element) {
  61.         // Config presets (e.g. tags.js, attrs.js) are immutable.
  62.         if (!Object.isFrozen(array)) {
  63.           array[l] = lcElement;
  64.         }
  65.  
  66.         element = lcElement;
  67.       }
  68.     }
  69.  
  70.     set[element] = true;
  71.   }
  72.  
  73.   return set;
  74. }
  75.  
  76. /* Shallow clone an object */
  77. function clone(object) {
  78.   var newObject = {};
  79.  
  80.   var property = void 0;
  81.   for (property in object) {
  82.     if (apply$1(hasOwnProperty, object, [property])) {
  83.       newObject[property] = object[property];
  84.     }
  85.   }
  86.  
  87.   return newObject;
  88. }
  89.  
  90. var seal = Object.seal || function (x) {
  91.   return x;
  92. };
  93.  
  94. var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
  95. var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm);
  96. var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
  97. var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
  98. var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
  99. );
  100. var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
  101. var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g // eslint-disable-line no-control-regex
  102. );
  103.  
  104. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  105.  
  106. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  107.  
  108. var _ref = typeof Reflect !== 'undefined' && Reflect;
  109. var apply = _ref.apply;
  110.  
  111. var arraySlice = Array.prototype.slice;
  112. var freeze = Object.freeze;
  113.  
  114. var getGlobal = function getGlobal() {
  115.   return typeof window === 'undefined' ? null : window;
  116. };
  117.  
  118. if (!apply) {
  119.   apply = function apply(fun, thisValue, args) {
  120.     return fun.apply(thisValue, args);
  121.   };
  122. }
  123.  
  124. /**
  125.  * Creates a no-op policy for internal use only.
  126.  * Don't export this function outside this module!
  127.  * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
  128.  * @param {Document} document The document object (to determine policy name suffix)
  129.  * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
  130.  * are not supported).
  131.  */
  132. var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
  133.   if ((typeof trustedTypes === 'undefined' ? 'undefined' : _typeof(trustedTypes)) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
  134.     return null;
  135.   }
  136.  
  137.   // Allow the callers to control the unique policy name
  138.   // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
  139.   // Policy creation with duplicate names throws in Trusted Types.
  140.   var suffix = null;
  141.   var ATTR_NAME = 'data-tt-policy-suffix';
  142.   if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
  143.     suffix = document.currentScript.getAttribute(ATTR_NAME);
  144.   }
  145.  
  146.   var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
  147.  
  148.   try {
  149.     return trustedTypes.createPolicy(policyName, {
  150.       createHTML: function createHTML(html$$1) {
  151.         return html$$1;
  152.       }
  153.     });
  154.   } catch (error) {
  155.     // Policy creation failed (most likely another DOMPurify script has
  156.     // already run). Skip creating the policy, as this will only cause errors
  157.     // if TT are enforced.
  158.     console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
  159.     return null;
  160.   }
  161. };
  162.  
  163. function createDOMPurify() {
  164.   var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
  165.  
  166.   var DOMPurify = function DOMPurify(root) {
  167.     return createDOMPurify(root);
  168.   };
  169.  
  170.   /**
  171.    * Version label, exposed for easier checks
  172.    * if DOMPurify is up to date or not
  173.    */
  174.   DOMPurify.version = '2.0.7';
  175.  
  176.   /**
  177.    * Array of elements that DOMPurify removed during sanitation.
  178.    * Empty if nothing was removed.
  179.    */
  180.   DOMPurify.removed = [];
  181.  
  182.   if (!window || !window.document || window.document.nodeType !== 9) {
  183.     // Not running in a browser, provide a factory function
  184.     // so that you can pass your own Window
  185.     DOMPurify.isSupported = false;
  186.  
  187.     return DOMPurify;
  188.   }
  189.  
  190.   var originalDocument = window.document;
  191.   var useDOMParser = false;
  192.   var removeTitle = false;
  193.  
  194.   var document = window.document;
  195.   var DocumentFragment = window.DocumentFragment,
  196.       HTMLTemplateElement = window.HTMLTemplateElement,
  197.       Node = window.Node,
  198.       NodeFilter = window.NodeFilter,
  199.       _window$NamedNodeMap = window.NamedNodeMap,
  200.       NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
  201.       Text = window.Text,
  202.       Comment = window.Comment,
  203.       DOMParser = window.DOMParser,
  204.       TrustedTypes = window.TrustedTypes;
  205.  
  206.   // As per issue #47, the web-components registry is inherited by a
  207.   // new document created via createHTMLDocument. As per the spec
  208.   // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
  209.   // a new empty registry is used when creating a template contents owner
  210.   // document, so we use that as our parent document to ensure nothing
  211.   // is inherited.
  212.  
  213.   if (typeof HTMLTemplateElement === 'function') {
  214.     var template = document.createElement('template');
  215.     if (template.content && template.content.ownerDocument) {
  216.       document = template.content.ownerDocument;
  217.     }
  218.   }
  219.  
  220.   var trustedTypesPolicy = _createTrustedTypesPolicy(TrustedTypes, originalDocument);
  221.   var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
  222.  
  223.   var _document = document,
  224.       implementation = _document.implementation,
  225.       createNodeIterator = _document.createNodeIterator,
  226.       getElementsByTagName = _document.getElementsByTagName,
  227.       createDocumentFragment = _document.createDocumentFragment;
  228.   var importNode = originalDocument.importNode;
  229.  
  230.  
  231.   var hooks = {};
  232.  
  233.   /**
  234.    * Expose whether this browser supports running the full DOMPurify.
  235.    */
  236.   DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && document.documentMode !== 9;
  237.  
  238.   var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
  239.       ERB_EXPR$$1 = ERB_EXPR,
  240.       DATA_ATTR$$1 = DATA_ATTR,
  241.       ARIA_ATTR$$1 = ARIA_ATTR,
  242.       IS_SCRIPT_OR_DATA$$1 = IS_SCRIPT_OR_DATA,
  243.       ATTR_WHITESPACE$$1 = ATTR_WHITESPACE;
  244.   var IS_ALLOWED_URI$$1 = IS_ALLOWED_URI;
  245.  
  246.   /**
  247.    * We consider the elements and attributes below to be safe. Ideally
  248.    * don't add any new ones but feel free to remove unwanted ones.
  249.    */
  250.  
  251.   /* allowed element names */
  252.  
  253.   var ALLOWED_TAGS = null;
  254.   var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(svgFilters), _toConsumableArray(mathMl), _toConsumableArray(text)));
  255.  
  256.   /* Allowed attribute names */
  257.   var ALLOWED_ATTR = null;
  258.   var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(mathMl$1), _toConsumableArray(xml)));
  259.  
  260.   /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
  261.   var FORBID_TAGS = null;
  262.  
  263.   /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
  264.   var FORBID_ATTR = null;
  265.  
  266.   /* Decide if ARIA attributes are okay */
  267.   var ALLOW_ARIA_ATTR = true;
  268.  
  269.   /* Decide if custom data attributes are okay */
  270.   var ALLOW_DATA_ATTR = true;
  271.  
  272.   /* Decide if unknown protocols are okay */
  273.   var ALLOW_UNKNOWN_PROTOCOLS = false;
  274.  
  275.   /* Output should be safe for jQuery's $() factory? */
  276.   var SAFE_FOR_JQUERY = false;
  277.  
  278.   /* Output should be safe for common template engines.
  279.    * This means, DOMPurify removes data attributes, mustaches and ERB
  280.    */
  281.   var SAFE_FOR_TEMPLATES = false;
  282.  
  283.   /* Decide if document with <html>... should be returned */
  284.   var WHOLE_DOCUMENT = false;
  285.  
  286.   /* Track whether config is already set on this instance of DOMPurify. */
  287.   var SET_CONFIG = false;
  288.  
  289.   /* Decide if all elements (e.g. style, script) must be children of
  290.    * document.body. By default, browsers might move them to document.head */
  291.   var FORCE_BODY = false;
  292.  
  293.   /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
  294.    * string (or a TrustedHTML object if Trusted Types are supported).
  295.    * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
  296.    */
  297.   var RETURN_DOM = false;
  298.  
  299.   /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
  300.    * string  (or a TrustedHTML object if Trusted Types are supported) */
  301.   var RETURN_DOM_FRAGMENT = false;
  302.  
  303.   /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM
  304.    * `Node` is imported into the current `Document`. If this flag is not enabled the
  305.    * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by
  306.    * DOMPurify. */
  307.   var RETURN_DOM_IMPORT = false;
  308.  
  309.   /* Try to return a Trusted Type object instead of a string, retrun a string in
  310.    * case Trusted Types are not supported  */
  311.   var RETURN_TRUSTED_TYPE = false;
  312.  
  313.   /* Output should be free from DOM clobbering attacks? */
  314.   var SANITIZE_DOM = true;
  315.  
  316.   /* Keep element content when removing element? */
  317.   var KEEP_CONTENT = true;
  318.  
  319.   /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
  320.    * of importing it into a new Document and returning a sanitized copy */
  321.   var IN_PLACE = false;
  322.  
  323.   /* Allow usage of profiles like html, svg and mathMl */
  324.   var USE_PROFILES = {};
  325.  
  326.   /* Tags to ignore content of when KEEP_CONTENT is true */
  327.   var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
  328.  
  329.   /* Tags that are safe for data: URIs */
  330.   var DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image']);
  331.  
  332.   /* Attributes safe for values like "javascript:" */
  333.   var URI_SAFE_ATTRIBUTES = null;
  334.   var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
  335.  
  336.   /* Keep a reference to config to pass to hooks */
  337.   var CONFIG = null;
  338.  
  339.   /* Ideally, do not touch anything below this line */
  340.   /* ______________________________________________ */
  341.  
  342.   var formElement = document.createElement('form');
  343.  
  344.   /**
  345.    * _parseConfig
  346.    *
  347.    * @param  {Object} cfg optional config literal
  348.    */
  349.   // eslint-disable-next-line complexity
  350.   var _parseConfig = function _parseConfig(cfg) {
  351.     if (CONFIG && CONFIG === cfg) {
  352.       return;
  353.     }
  354.  
  355.     /* Shield configuration object from tampering */
  356.     if (!cfg || (typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {
  357.       cfg = {};
  358.     }
  359.  
  360.     /* Set configuration parameters */
  361.     ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
  362.     ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
  363.     URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
  364.     FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
  365.     FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
  366.     USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
  367.     ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
  368.     ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
  369.     ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
  370.     SAFE_FOR_JQUERY = cfg.SAFE_FOR_JQUERY || false; // Default false
  371.     SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
  372.     WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
  373.     RETURN_DOM = cfg.RETURN_DOM || false; // Default false
  374.     RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
  375.     RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT || false; // Default false
  376.     RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
  377.     FORCE_BODY = cfg.FORCE_BODY || false; // Default false
  378.     SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
  379.     KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
  380.     IN_PLACE = cfg.IN_PLACE || false; // Default false
  381.  
  382.     IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
  383.  
  384.     if (SAFE_FOR_TEMPLATES) {
  385.       ALLOW_DATA_ATTR = false;
  386.     }
  387.  
  388.     if (RETURN_DOM_FRAGMENT) {
  389.       RETURN_DOM = true;
  390.     }
  391.  
  392.     /* Parse profile info */
  393.     if (USE_PROFILES) {
  394.       ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(text)));
  395.       ALLOWED_ATTR = [];
  396.       if (USE_PROFILES.html === true) {
  397.         addToSet(ALLOWED_TAGS, html);
  398.         addToSet(ALLOWED_ATTR, html$1);
  399.       }
  400.  
  401.       if (USE_PROFILES.svg === true) {
  402.         addToSet(ALLOWED_TAGS, svg);
  403.         addToSet(ALLOWED_ATTR, svg$1);
  404.         addToSet(ALLOWED_ATTR, xml);
  405.       }
  406.  
  407.       if (USE_PROFILES.svgFilters === true) {
  408.         addToSet(ALLOWED_TAGS, svgFilters);
  409.         addToSet(ALLOWED_ATTR, svg$1);
  410.         addToSet(ALLOWED_ATTR, xml);
  411.       }
  412.  
  413.       if (USE_PROFILES.mathMl === true) {
  414.         addToSet(ALLOWED_TAGS, mathMl);
  415.         addToSet(ALLOWED_ATTR, mathMl$1);
  416.         addToSet(ALLOWED_ATTR, xml);
  417.       }
  418.     }
  419.  
  420.     /* Merge configuration parameters */
  421.     if (cfg.ADD_TAGS) {
  422.       if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
  423.         ALLOWED_TAGS = clone(ALLOWED_TAGS);
  424.       }
  425.  
  426.       addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
  427.     }
  428.  
  429.     if (cfg.ADD_ATTR) {
  430.       if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
  431.         ALLOWED_ATTR = clone(ALLOWED_ATTR);
  432.       }
  433.  
  434.       addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
  435.     }
  436.  
  437.     if (cfg.ADD_URI_SAFE_ATTR) {
  438.       addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
  439.     }
  440.  
  441.     /* Add #text in case KEEP_CONTENT is set to true */
  442.     if (KEEP_CONTENT) {
  443.       ALLOWED_TAGS['#text'] = true;
  444.     }
  445.  
  446.     /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
  447.     if (WHOLE_DOCUMENT) {
  448.       addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
  449.     }
  450.  
  451.     /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
  452.     if (ALLOWED_TAGS.table) {
  453.       addToSet(ALLOWED_TAGS, ['tbody']);
  454.       delete FORBID_TAGS.tbody;
  455.     }
  456.  
  457.     // Prevent further manipulation of configuration.
  458.     // Not available in IE8, Safari 5, etc.
  459.     if (freeze) {
  460.       freeze(cfg);
  461.     }
  462.  
  463.     CONFIG = cfg;
  464.   };
  465.  
  466.   /**
  467.    * _forceRemove
  468.    *
  469.    * @param  {Node} node a DOM node
  470.    */
  471.   var _forceRemove = function _forceRemove(node) {
  472.     DOMPurify.removed.push({ element: node });
  473.     try {
  474.       node.parentNode.removeChild(node);
  475.     } catch (error) {
  476.       node.outerHTML = emptyHTML;
  477.     }
  478.   };
  479.  
  480.   /**
  481.    * _removeAttribute
  482.    *
  483.    * @param  {String} name an Attribute name
  484.    * @param  {Node} node a DOM node
  485.    */
  486.   var _removeAttribute = function _removeAttribute(name, node) {
  487.     try {
  488.       DOMPurify.removed.push({
  489.         attribute: node.getAttributeNode(name),
  490.         from: node
  491.       });
  492.     } catch (error) {
  493.       DOMPurify.removed.push({
  494.         attribute: null,
  495.         from: node
  496.       });
  497.     }
  498.  
  499.     node.removeAttribute(name);
  500.   };
  501.  
  502.   /**
  503.    * _initDocument
  504.    *
  505.    * @param  {String} dirty a string of dirty markup
  506.    * @return {Document} a DOM, filled with the dirty markup
  507.    */
  508.   var _initDocument = function _initDocument(dirty) {
  509.     /* Create a HTML document */
  510.     var doc = void 0;
  511.     var leadingWhitespace = void 0;
  512.  
  513.     if (FORCE_BODY) {
  514.       dirty = '<remove></remove>' + dirty;
  515.     } else {
  516.       /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
  517.       var matches = dirty.match(/^[\s]+/);
  518.       leadingWhitespace = matches && matches[0];
  519.       if (leadingWhitespace) {
  520.         dirty = dirty.slice(leadingWhitespace.length);
  521.       }
  522.     }
  523.  
  524.     /* Use DOMParser to workaround Firefox bug (see comment below) */
  525.     if (useDOMParser) {
  526.       try {
  527.         doc = new DOMParser().parseFromString(dirty, 'text/html');
  528.       } catch (error) {}
  529.     }
  530.  
  531.     /* Remove title to fix a mXSS bug in older MS Edge */
  532.     if (removeTitle) {
  533.       addToSet(FORBID_TAGS, ['title']);
  534.     }
  535.  
  536.     /* Otherwise use createHTMLDocument, because DOMParser is unsafe in
  537.     Safari (see comment below) */
  538.     if (!doc || !doc.documentElement) {
  539.       doc = implementation.createHTMLDocument('');
  540.       var _doc = doc,
  541.           body = _doc.body;
  542.  
  543.       body.parentNode.removeChild(body.parentNode.firstElementChild);
  544.       body.outerHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
  545.     }
  546.  
  547.     if (dirty && leadingWhitespace) {
  548.       doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
  549.     }
  550.  
  551.     /* Work on whole document or just its body */
  552.     return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
  553.   };
  554.  
  555.   // Firefox uses a different parser for innerHTML rather than
  556.   // DOMParser (see https://bugzilla.mozilla.org/show_bug.cgi?id=1205631)
  557.   // which means that you *must* use DOMParser, otherwise the output may
  558.   // not be safe if used in a document.write context later.
  559.   //
  560.   // So we feature detect the Firefox bug and use the DOMParser if necessary.
  561.   //
  562.   // Chrome 77 and other versions ship an mXSS bug that caused a bypass to
  563.   // happen. We now check for the mXSS trigger and react accordingly.
  564.   if (DOMPurify.isSupported) {
  565.     (function () {
  566.       try {
  567.         var doc = _initDocument('<svg><p><textarea><img src="</textarea><img src=x abc=1//">');
  568.         if (doc.querySelector('svg img')) {
  569.           useDOMParser = true;
  570.         }
  571.       } catch (error) {}
  572.     })();
  573.  
  574.     (function () {
  575.       try {
  576.         var doc = _initDocument('<x/><title>&lt;/title&gt;&lt;img&gt;');
  577.         if (/<\/title/.test(doc.querySelector('title').innerHTML)) {
  578.           removeTitle = true;
  579.         }
  580.       } catch (error) {}
  581.     })();
  582.   }
  583.  
  584.   /**
  585.    * _createIterator
  586.    *
  587.    * @param  {Document} root document/fragment to create iterator for
  588.    * @return {Iterator} iterator instance
  589.    */
  590.   var _createIterator = function _createIterator(root) {
  591.     return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () {
  592.       return NodeFilter.FILTER_ACCEPT;
  593.     }, false);
  594.   };
  595.  
  596.   /**
  597.    * _isClobbered
  598.    *
  599.    * @param  {Node} elm element to check for clobbering attacks
  600.    * @return {Boolean} true if clobbered, false if safe
  601.    */
  602.   var _isClobbered = function _isClobbered(elm) {
  603.     if (elm instanceof Text || elm instanceof Comment) {
  604.       return false;
  605.     }
  606.  
  607.     if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string') {
  608.       return true;
  609.     }
  610.  
  611.     return false;
  612.   };
  613.  
  614.   /**
  615.    * _isNode
  616.    *
  617.    * @param  {Node} obj object to check whether it's a DOM node
  618.    * @return {Boolean} true is object is a DOM node
  619.    */
  620.   var _isNode = function _isNode(obj) {
  621.     return (typeof Node === 'undefined' ? 'undefined' : _typeof(Node)) === 'object' ? obj instanceof Node : obj && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && typeof obj.nodeType === 'number' && typeof obj.nodeName === 'string';
  622.   };
  623.  
  624.   /**
  625.    * _executeHook
  626.    * Execute user configurable hooks
  627.    *
  628.    * @param  {String} entryPoint  Name of the hook's entry point
  629.    * @param  {Node} currentNode node to work on with the hook
  630.    * @param  {Object} data additional hook parameters
  631.    */
  632.   var _executeHook = function _executeHook(entryPoint, currentNode, data) {
  633.     if (!hooks[entryPoint]) {
  634.       return;
  635.     }
  636.  
  637.     hooks[entryPoint].forEach(function (hook) {
  638.       hook.call(DOMPurify, currentNode, data, CONFIG);
  639.     });
  640.   };
  641.  
  642.   /**
  643.    * _sanitizeElements
  644.    *
  645.    * @protect nodeName
  646.    * @protect textContent
  647.    * @protect removeChild
  648.    *
  649.    * @param   {Node} currentNode to check for permission to exist
  650.    * @return  {Boolean} true if node was killed, false if left alive
  651.    */
  652.   // eslint-disable-next-line complexity
  653.   var _sanitizeElements = function _sanitizeElements(currentNode) {
  654.     var content = void 0;
  655.  
  656.     /* Execute a hook if present */
  657.     _executeHook('beforeSanitizeElements', currentNode, null);
  658.  
  659.     /* Check if element is clobbered or can clobber */
  660.     if (_isClobbered(currentNode)) {
  661.       _forceRemove(currentNode);
  662.       return true;
  663.     }
  664.  
  665.     /* Now let's check the element's type and name */
  666.     var tagName = currentNode.nodeName.toLowerCase();
  667.  
  668.     /* Execute a hook if present */
  669.     _executeHook('uponSanitizeElement', currentNode, {
  670.       tagName: tagName,
  671.       allowedTags: ALLOWED_TAGS
  672.     });
  673.  
  674.     /* Take care of an mXSS pattern using p, br inside svg, math */
  675.     if ((tagName === 'svg' || tagName === 'math') && currentNode.querySelectorAll('p, br').length !== 0) {
  676.       _forceRemove(currentNode);
  677.       return true;
  678.     }
  679.  
  680.     /* Remove element if anything forbids its presence */
  681.     if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
  682.       /* Keep content except for black-listed elements */
  683.       if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] && typeof currentNode.insertAdjacentHTML === 'function') {
  684.         try {
  685.           var htmlToInsert = currentNode.innerHTML;
  686.           currentNode.insertAdjacentHTML('AfterEnd', trustedTypesPolicy ? trustedTypesPolicy.createHTML(htmlToInsert) : htmlToInsert);
  687.         } catch (error) {}
  688.       }
  689.  
  690.       _forceRemove(currentNode);
  691.       return true;
  692.     }
  693.  
  694.     /* Remove in case a noscript/noembed XSS is suspected */
  695.     if (tagName === 'noscript' && /<\/noscript/i.test(currentNode.innerHTML)) {
  696.       _forceRemove(currentNode);
  697.       return true;
  698.     }
  699.  
  700.     if (tagName === 'noembed' && /<\/noembed/i.test(currentNode.innerHTML)) {
  701.       _forceRemove(currentNode);
  702.       return true;
  703.     }
  704.  
  705.     /* Convert markup to cover jQuery behavior */
  706.     if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && (!currentNode.content || !currentNode.content.firstElementChild) && /</g.test(currentNode.textContent)) {
  707.       DOMPurify.removed.push({ element: currentNode.cloneNode() });
  708.       if (currentNode.innerHTML) {
  709.         currentNode.innerHTML = currentNode.innerHTML.replace(/</g, '&lt;');
  710.       } else {
  711.         currentNode.innerHTML = currentNode.textContent.replace(/</g, '&lt;');
  712.       }
  713.     }
  714.  
  715.     /* Sanitize element content to be template-safe */
  716.     if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
  717.       /* Get the element's text content */
  718.       content = currentNode.textContent;
  719.       content = content.replace(MUSTACHE_EXPR$$1, ' ');
  720.       content = content.replace(ERB_EXPR$$1, ' ');
  721.       if (currentNode.textContent !== content) {
  722.         DOMPurify.removed.push({ element: currentNode.cloneNode() });
  723.         currentNode.textContent = content;
  724.       }
  725.     }
  726.  
  727.     /* Execute a hook if present */
  728.     _executeHook('afterSanitizeElements', currentNode, null);
  729.  
  730.     return false;
  731.   };
  732.  
  733.   /**
  734.    * _isValidAttribute
  735.    *
  736.    * @param  {string} lcTag Lowercase tag name of containing element.
  737.    * @param  {string} lcName Lowercase attribute name.
  738.    * @param  {string} value Attribute value.
  739.    * @return {Boolean} Returns true if `value` is valid, otherwise false.
  740.    */
  741.   // eslint-disable-next-line complexity
  742.   var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
  743.     /* Make sure attribute cannot clobber */
  744.     if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
  745.       return false;
  746.     }
  747.  
  748.     /* Allow valid data-* attributes: At least one character after "-"
  749.         (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
  750.         XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
  751.         We don't need to check the value; it's always URI safe. */
  752.     if (ALLOW_DATA_ATTR && DATA_ATTR$$1.test(lcName)) {
  753.       // This attribute is safe
  754.     } else if (ALLOW_ARIA_ATTR && ARIA_ATTR$$1.test(lcName)) {
  755.       // This attribute is safe
  756.       /* Otherwise, check the name is permitted */
  757.     } else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
  758.       return false;
  759.  
  760.       /* Check value is safe. First, is attr inert? If so, is safe */
  761.     } else if (URI_SAFE_ATTRIBUTES[lcName]) {
  762.       // This attribute is safe
  763.       /* Check no script, data or unknown possibly unsafe URI
  764.         unless we know URI values are safe for that attribute */
  765.     } else if (IS_ALLOWED_URI$$1.test(value.replace(ATTR_WHITESPACE$$1, ''))) {
  766.       // This attribute is safe
  767.       /* Keep image data URIs alive if src/xlink:href is allowed */
  768.       /* Further prevent gadget XSS for dynamically built script tags */
  769.     } else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && value.indexOf('data:') === 0 && DATA_URI_TAGS[lcTag]) {
  770.       // This attribute is safe
  771.       /* Allow unknown protocols: This provides support for links that
  772.         are handled by protocol handlers which may be unknown ahead of
  773.         time, e.g. fb:, spotify: */
  774.     } else if (ALLOW_UNKNOWN_PROTOCOLS && !IS_SCRIPT_OR_DATA$$1.test(value.replace(ATTR_WHITESPACE$$1, ''))) {
  775.       // This attribute is safe
  776.       /* Check for binary attributes */
  777.       // eslint-disable-next-line no-negated-condition
  778.     } else if (!value) {
  779.       // Binary attributes are safe at this point
  780.       /* Anything else, presume unsafe, do not add it back */
  781.     } else {
  782.       return false;
  783.     }
  784.  
  785.     return true;
  786.   };
  787.  
  788.   /**
  789.    * _sanitizeAttributes
  790.    *
  791.    * @protect attributes
  792.    * @protect nodeName
  793.    * @protect removeAttribute
  794.    * @protect setAttribute
  795.    *
  796.    * @param  {Node} currentNode to sanitize
  797.    */
  798.   // eslint-disable-next-line complexity
  799.   var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
  800.     var attr = void 0;
  801.     var value = void 0;
  802.     var lcName = void 0;
  803.     var idAttr = void 0;
  804.     var l = void 0;
  805.     /* Execute a hook if present */
  806.     _executeHook('beforeSanitizeAttributes', currentNode, null);
  807.  
  808.     var attributes = currentNode.attributes;
  809.  
  810.     /* Check if we have attributes; if not we might have a text node */
  811.  
  812.     if (!attributes) {
  813.       return;
  814.     }
  815.  
  816.     var hookEvent = {
  817.       attrName: '',
  818.       attrValue: '',
  819.       keepAttr: true,
  820.       allowedAttributes: ALLOWED_ATTR
  821.     };
  822.     l = attributes.length;
  823.  
  824.     /* Go backwards over all attributes; safely remove bad ones */
  825.     while (l--) {
  826.       attr = attributes[l];
  827.       var _attr = attr,
  828.           name = _attr.name,
  829.           namespaceURI = _attr.namespaceURI;
  830.  
  831.       value = attr.value.trim();
  832.       lcName = name.toLowerCase();
  833.  
  834.       /* Execute a hook if present */
  835.       hookEvent.attrName = lcName;
  836.       hookEvent.attrValue = value;
  837.       hookEvent.keepAttr = true;
  838.       _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
  839.       value = hookEvent.attrValue;
  840.  
  841.       /* Remove attribute */
  842.       // Safari (iOS + Mac), last tested v8.0.5, crashes if you try to
  843.       // remove a "name" attribute from an <img> tag that has an "id"
  844.       // attribute at the time.
  845.       if (lcName === 'name' && currentNode.nodeName === 'IMG' && attributes.id) {
  846.         idAttr = attributes.id;
  847.         attributes = apply(arraySlice, attributes, []);
  848.         _removeAttribute('id', currentNode);
  849.         _removeAttribute(name, currentNode);
  850.         if (attributes.indexOf(idAttr) > l) {
  851.           currentNode.setAttribute('id', idAttr.value);
  852.         }
  853.       } else if (
  854.       // This works around a bug in Safari, where input[type=file]
  855.       // cannot be dynamically set after type has been removed
  856.       currentNode.nodeName === 'INPUT' && lcName === 'type' && value === 'file' && hookEvent.keepAttr && (ALLOWED_ATTR[lcName] || !FORBID_ATTR[lcName])) {
  857.         continue;
  858.       } else {
  859.         // This avoids a crash in Safari v9.0 with double-ids.
  860.         // The trick is to first set the id to be empty and then to
  861.         // remove the attribute
  862.         if (name === 'id') {
  863.           currentNode.setAttribute(name, '');
  864.         }
  865.  
  866.         _removeAttribute(name, currentNode);
  867.       }
  868.  
  869.       /* Did the hooks approve of the attribute? */
  870.       if (!hookEvent.keepAttr) {
  871.         continue;
  872.       }
  873.  
  874.       /* Take care of an mXSS pattern using namespace switches */
  875.       if (/svg|math/i.test(currentNode.namespaceURI) && new RegExp('</(' + Object.keys(FORBID_CONTENTS).join('|') + ')', 'i').test(value)) {
  876.         _removeAttribute(name, currentNode);
  877.         continue;
  878.       }
  879.  
  880.       /* Sanitize attribute content to be template-safe */
  881.       if (SAFE_FOR_TEMPLATES) {
  882.         value = value.replace(MUSTACHE_EXPR$$1, ' ');
  883.         value = value.replace(ERB_EXPR$$1, ' ');
  884.       }
  885.  
  886.       /* Is `value` valid for this attribute? */
  887.       var lcTag = currentNode.nodeName.toLowerCase();
  888.       if (!_isValidAttribute(lcTag, lcName, value)) {
  889.         continue;
  890.       }
  891.  
  892.       /* Handle invalid data-* attribute set by try-catching it */
  893.       try {
  894.         if (namespaceURI) {
  895.           currentNode.setAttributeNS(namespaceURI, name, value);
  896.         } else {
  897.           /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
  898.           currentNode.setAttribute(name, value);
  899.         }
  900.  
  901.         DOMPurify.removed.pop();
  902.       } catch (error) {}
  903.     }
  904.  
  905.     /* Execute a hook if present */
  906.     _executeHook('afterSanitizeAttributes', currentNode, null);
  907.   };
  908.  
  909.   /**
  910.    * _sanitizeShadowDOM
  911.    *
  912.    * @param  {DocumentFragment} fragment to iterate over recursively
  913.    */
  914.   var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
  915.     var shadowNode = void 0;
  916.     var shadowIterator = _createIterator(fragment);
  917.  
  918.     /* Execute a hook if present */
  919.     _executeHook('beforeSanitizeShadowDOM', fragment, null);
  920.  
  921.     while (shadowNode = shadowIterator.nextNode()) {
  922.       /* Execute a hook if present */
  923.       _executeHook('uponSanitizeShadowNode', shadowNode, null);
  924.  
  925.       /* Sanitize tags and elements */
  926.       if (_sanitizeElements(shadowNode)) {
  927.         continue;
  928.       }
  929.  
  930.       /* Deep shadow DOM detected */
  931.       if (shadowNode.content instanceof DocumentFragment) {
  932.         _sanitizeShadowDOM(shadowNode.content);
  933.       }
  934.  
  935.       /* Check attributes, sanitize if necessary */
  936.       _sanitizeAttributes(shadowNode);
  937.     }
  938.  
  939.     /* Execute a hook if present */
  940.     _executeHook('afterSanitizeShadowDOM', fragment, null);
  941.   };
  942.  
  943.   /**
  944.    * Sanitize
  945.    * Public method providing core sanitation functionality
  946.    *
  947.    * @param {String|Node} dirty string or DOM node
  948.    * @param {Object} configuration object
  949.    */
  950.   // eslint-disable-next-line complexity
  951.   DOMPurify.sanitize = function (dirty, cfg) {
  952.     var body = void 0;
  953.     var importedNode = void 0;
  954.     var currentNode = void 0;
  955.     var oldNode = void 0;
  956.     var returnNode = void 0;
  957.     /* Make sure we have a string to sanitize.
  958.       DO NOT return early, as this will return the wrong type if
  959.       the user has requested a DOM object rather than a string */
  960.     if (!dirty) {
  961.       dirty = '<!-->';
  962.     }
  963.  
  964.     /* Stringify, in case dirty is an object */
  965.     if (typeof dirty !== 'string' && !_isNode(dirty)) {
  966.       // eslint-disable-next-line no-negated-condition
  967.       if (typeof dirty.toString !== 'function') {
  968.         throw new TypeError('toString is not a function');
  969.       } else {
  970.         dirty = dirty.toString();
  971.         if (typeof dirty !== 'string') {
  972.           throw new TypeError('dirty is not a string, aborting');
  973.         }
  974.       }
  975.     }
  976.  
  977.     /* Check we can run. Otherwise fall back or ignore */
  978.     if (!DOMPurify.isSupported) {
  979.       if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
  980.         if (typeof dirty === 'string') {
  981.           return window.toStaticHTML(dirty);
  982.         }
  983.  
  984.         if (_isNode(dirty)) {
  985.           return window.toStaticHTML(dirty.outerHTML);
  986.         }
  987.       }
  988.  
  989.       return dirty;
  990.     }
  991.  
  992.     /* Assign config vars */
  993.     if (!SET_CONFIG) {
  994.       _parseConfig(cfg);
  995.     }
  996.  
  997.     /* Clean up removed elements */
  998.     DOMPurify.removed = [];
  999.  
  1000.     if (IN_PLACE) {
  1001.       /* No special handling necessary for in-place sanitization */
  1002.     } else if (dirty instanceof Node) {
  1003.       /* If dirty is a DOM element, append to an empty document to avoid
  1004.          elements being stripped by the parser */
  1005.       body = _initDocument('<!-->');
  1006.       importedNode = body.ownerDocument.importNode(dirty, true);
  1007.       if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
  1008.         /* Node is already a body, use as is */
  1009.         body = importedNode;
  1010.       } else if (importedNode.nodeName === 'HTML') {
  1011.         body = importedNode;
  1012.       } else {
  1013.         // eslint-disable-next-line unicorn/prefer-node-append
  1014.         body.appendChild(importedNode);
  1015.       }
  1016.     } else {
  1017.       /* Exit directly if we have nothing to do */
  1018.       if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && RETURN_TRUSTED_TYPE && dirty.indexOf('<') === -1) {
  1019.         return trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
  1020.       }
  1021.  
  1022.       /* Initialize the document to work on */
  1023.       body = _initDocument(dirty);
  1024.  
  1025.       /* Check we have a DOM node from the data */
  1026.       if (!body) {
  1027.         return RETURN_DOM ? null : emptyHTML;
  1028.       }
  1029.     }
  1030.  
  1031.     /* Remove first element node (ours) if FORCE_BODY is set */
  1032.     if (body && FORCE_BODY) {
  1033.       _forceRemove(body.firstChild);
  1034.     }
  1035.  
  1036.     /* Get node iterator */
  1037.     var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
  1038.  
  1039.     /* Now start iterating over the created document */
  1040.     while (currentNode = nodeIterator.nextNode()) {
  1041.       /* Fix IE's strange behavior with manipulated textNodes #89 */
  1042.       if (currentNode.nodeType === 3 && currentNode === oldNode) {
  1043.         continue;
  1044.       }
  1045.  
  1046.       /* Sanitize tags and elements */
  1047.       if (_sanitizeElements(currentNode)) {
  1048.         continue;
  1049.       }
  1050.  
  1051.       /* Shadow DOM detected, sanitize it */
  1052.       if (currentNode.content instanceof DocumentFragment) {
  1053.         _sanitizeShadowDOM(currentNode.content);
  1054.       }
  1055.  
  1056.       /* Check attributes, sanitize if necessary */
  1057.       _sanitizeAttributes(currentNode);
  1058.  
  1059.       oldNode = currentNode;
  1060.     }
  1061.  
  1062.     oldNode = null;
  1063.  
  1064.     /* If we sanitized `dirty` in-place, return it. */
  1065.     if (IN_PLACE) {
  1066.       return dirty;
  1067.     }
  1068.  
  1069.     /* Return sanitized string or DOM */
  1070.     if (RETURN_DOM) {
  1071.       if (RETURN_DOM_FRAGMENT) {
  1072.         returnNode = createDocumentFragment.call(body.ownerDocument);
  1073.  
  1074.         while (body.firstChild) {
  1075.           // eslint-disable-next-line unicorn/prefer-node-append
  1076.           returnNode.appendChild(body.firstChild);
  1077.         }
  1078.       } else {
  1079.         returnNode = body;
  1080.       }
  1081.  
  1082.       if (RETURN_DOM_IMPORT) {
  1083.         /* AdoptNode() is not used because internal state is not reset
  1084.                (e.g. the past names map of a HTMLFormElement), this is safe
  1085.                in theory but we would rather not risk another attack vector.
  1086.                The state that is cloned by importNode() is explicitly defined
  1087.                by the specs. */
  1088.         returnNode = importNode.call(originalDocument, returnNode, true);
  1089.       }
  1090.  
  1091.       return returnNode;
  1092.     }
  1093.  
  1094.     var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
  1095.  
  1096.     /* Sanitize final string template-safe */
  1097.     if (SAFE_FOR_TEMPLATES) {
  1098.       serializedHTML = serializedHTML.replace(MUSTACHE_EXPR$$1, ' ');
  1099.       serializedHTML = serializedHTML.replace(ERB_EXPR$$1, ' ');
  1100.     }
  1101.  
  1102.     return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
  1103.   };
  1104.  
  1105.   /**
  1106.    * Public method to set the configuration once
  1107.    * setConfig
  1108.    *
  1109.    * @param {Object} cfg configuration object
  1110.    */
  1111.   DOMPurify.setConfig = function (cfg) {
  1112.     _parseConfig(cfg);
  1113.     SET_CONFIG = true;
  1114.   };
  1115.  
  1116.   /**
  1117.    * Public method to remove the configuration
  1118.    * clearConfig
  1119.    *
  1120.    */
  1121.   DOMPurify.clearConfig = function () {
  1122.     CONFIG = null;
  1123.     SET_CONFIG = false;
  1124.   };
  1125.  
  1126.   /**
  1127.    * Public method to check if an attribute value is valid.
  1128.    * Uses last set config, if any. Otherwise, uses config defaults.
  1129.    * isValidAttribute
  1130.    *
  1131.    * @param  {string} tag Tag name of containing element.
  1132.    * @param  {string} attr Attribute name.
  1133.    * @param  {string} value Attribute value.
  1134.    * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
  1135.    */
  1136.   DOMPurify.isValidAttribute = function (tag, attr, value) {
  1137.     /* Initialize shared config vars if necessary. */
  1138.     if (!CONFIG) {
  1139.       _parseConfig({});
  1140.     }
  1141.  
  1142.     var lcTag = tag.toLowerCase();
  1143.     var lcName = attr.toLowerCase();
  1144.     return _isValidAttribute(lcTag, lcName, value);
  1145.   };
  1146.  
  1147.   /**
  1148.    * AddHook
  1149.    * Public method to add DOMPurify hooks
  1150.    *
  1151.    * @param {String} entryPoint entry point for the hook to add
  1152.    * @param {Function} hookFunction function to execute
  1153.    */
  1154.   DOMPurify.addHook = function (entryPoint, hookFunction) {
  1155.     if (typeof hookFunction !== 'function') {
  1156.       return;
  1157.     }
  1158.  
  1159.     hooks[entryPoint] = hooks[entryPoint] || [];
  1160.     hooks[entryPoint].push(hookFunction);
  1161.   };
  1162.  
  1163.   /**
  1164.    * RemoveHook
  1165.    * Public method to remove a DOMPurify hook at a given entryPoint
  1166.    * (pops it from the stack of hooks if more are present)
  1167.    *
  1168.    * @param {String} entryPoint entry point for the hook to remove
  1169.    */
  1170.   DOMPurify.removeHook = function (entryPoint) {
  1171.     if (hooks[entryPoint]) {
  1172.       hooks[entryPoint].pop();
  1173.     }
  1174.   };
  1175.  
  1176.   /**
  1177.    * RemoveHooks
  1178.    * Public method to remove all DOMPurify hooks at a given entryPoint
  1179.    *
  1180.    * @param  {String} entryPoint entry point for the hooks to remove
  1181.    */
  1182.   DOMPurify.removeHooks = function (entryPoint) {
  1183.     if (hooks[entryPoint]) {
  1184.       hooks[entryPoint] = [];
  1185.     }
  1186.   };
  1187.  
  1188.   /**
  1189.    * RemoveAllHooks
  1190.    * Public method to remove all DOMPurify hooks
  1191.    *
  1192.    */
  1193.   DOMPurify.removeAllHooks = function () {
  1194.     hooks = {};
  1195.   };
  1196.  
  1197.   return DOMPurify;
  1198. }
  1199.  
  1200. var purify = createDOMPurify();
  1201.  
  1202. return purify;
  1203.  
  1204. })));
  1205. //# sourceMappingURL=https://c.disquscdn.com/next/node_modules/dompurify/dist/purify.js.map
  1206. ;
  1207. // https://c.disquscdn.com/next/node_modules/dompurify/dist/purify.js

Replies to purify.js rss

Title Name Language When
backbone.js disqus.com javascript 1 Week ago.

Reply to "purify.js"

Here you can reply to the paste above