dompurify 1.0.7 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -7
- package/dist/purify.cjs.js +235 -60
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +235 -60
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +235 -60
- package/dist/purify.js.map +1 -1
- package/dist/purify.min.js +1 -1
- package/dist/purify.min.js.map +1 -1
- package/package.json +17 -20
- package/package-lock.json +0 -10785
- package/yarn.lock +0 -5776
package/dist/purify.cjs.js
CHANGED
|
@@ -1,64 +1,161 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var freeze$1 = Object.freeze || function (x) {
|
|
4
|
+
return x;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
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']);
|
|
4
8
|
|
|
5
9
|
// SVG
|
|
6
|
-
var svg = ['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'];
|
|
10
|
+
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']);
|
|
11
|
+
|
|
12
|
+
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']);
|
|
7
13
|
|
|
8
|
-
var
|
|
14
|
+
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']);
|
|
15
|
+
|
|
16
|
+
var text = freeze$1(['#text']);
|
|
17
|
+
|
|
18
|
+
var freeze$2 = Object.freeze || function (x) {
|
|
19
|
+
return x;
|
|
20
|
+
};
|
|
9
21
|
|
|
10
|
-
var
|
|
22
|
+
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', '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']);
|
|
11
23
|
|
|
12
|
-
var
|
|
24
|
+
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']);
|
|
13
25
|
|
|
14
|
-
var
|
|
26
|
+
var mathMl$1 = freeze$2(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', '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']);
|
|
15
27
|
|
|
16
|
-
var
|
|
28
|
+
var xml = freeze$2(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
17
29
|
|
|
18
|
-
var
|
|
30
|
+
var hasOwnProperty = Object.hasOwnProperty;
|
|
31
|
+
var setPrototypeOf = Object.setPrototypeOf;
|
|
19
32
|
|
|
20
|
-
var
|
|
33
|
+
var _ref$1 = typeof Reflect !== 'undefined' && Reflect;
|
|
34
|
+
var apply$1 = _ref$1.apply;
|
|
35
|
+
|
|
36
|
+
if (!apply$1) {
|
|
37
|
+
apply$1 = function apply(fun, thisValue, args) {
|
|
38
|
+
return fun.apply(thisValue, args);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
21
41
|
|
|
22
42
|
/* Add properties to a lookup table */
|
|
23
43
|
function addToSet(set, array) {
|
|
44
|
+
if (setPrototypeOf) {
|
|
45
|
+
// Make 'in' and truthy checks like Boolean(set.constructor)
|
|
46
|
+
// independent of any properties defined on Object.prototype.
|
|
47
|
+
// Prevent prototype setters from intercepting set as a this value.
|
|
48
|
+
setPrototypeOf(set, null);
|
|
49
|
+
}
|
|
50
|
+
|
|
24
51
|
var l = array.length;
|
|
25
52
|
while (l--) {
|
|
26
|
-
|
|
27
|
-
|
|
53
|
+
var element = array[l];
|
|
54
|
+
if (typeof element === 'string') {
|
|
55
|
+
var lcElement = element.toLowerCase();
|
|
56
|
+
if (lcElement !== element) {
|
|
57
|
+
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
58
|
+
if (!Object.isFrozen(array)) {
|
|
59
|
+
array[l] = lcElement;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
element = lcElement;
|
|
63
|
+
}
|
|
28
64
|
}
|
|
29
|
-
|
|
65
|
+
|
|
66
|
+
set[element] = true;
|
|
30
67
|
}
|
|
68
|
+
|
|
31
69
|
return set;
|
|
32
70
|
}
|
|
33
71
|
|
|
34
72
|
/* Shallow clone an object */
|
|
35
73
|
function clone(object) {
|
|
36
74
|
var newObject = {};
|
|
75
|
+
|
|
37
76
|
var property = void 0;
|
|
38
77
|
for (property in object) {
|
|
39
|
-
if (
|
|
78
|
+
if (apply$1(hasOwnProperty, object, [property])) {
|
|
40
79
|
newObject[property] = object[property];
|
|
41
80
|
}
|
|
42
81
|
}
|
|
82
|
+
|
|
43
83
|
return newObject;
|
|
44
84
|
}
|
|
45
85
|
|
|
46
|
-
var
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
var
|
|
51
|
-
var
|
|
52
|
-
var
|
|
86
|
+
var seal = Object.seal || function (x) {
|
|
87
|
+
return x;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
91
|
+
var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm);
|
|
92
|
+
var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
|
|
93
|
+
var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
94
|
+
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
|
|
95
|
+
);
|
|
96
|
+
var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
97
|
+
var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g // eslint-disable-line no-control-regex
|
|
98
|
+
);
|
|
53
99
|
|
|
54
100
|
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; };
|
|
55
101
|
|
|
56
102
|
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); } }
|
|
57
103
|
|
|
104
|
+
var _ref = typeof Reflect !== 'undefined' && Reflect;
|
|
105
|
+
var apply = _ref.apply;
|
|
106
|
+
|
|
107
|
+
var arraySlice = Array.prototype.slice;
|
|
108
|
+
var freeze = Object.freeze;
|
|
109
|
+
|
|
58
110
|
var getGlobal = function getGlobal() {
|
|
59
111
|
return typeof window === 'undefined' ? null : window;
|
|
60
112
|
};
|
|
61
113
|
|
|
114
|
+
if (!apply) {
|
|
115
|
+
apply = function apply(fun, thisValue, args) {
|
|
116
|
+
return fun.apply(thisValue, args);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Creates a no-op policy for internal use only.
|
|
122
|
+
* Don't export this function outside this module!
|
|
123
|
+
* @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
|
|
124
|
+
* @param {Document} document The document object (to determine policy name suffix)
|
|
125
|
+
* @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
|
|
126
|
+
* are not supported).
|
|
127
|
+
*/
|
|
128
|
+
var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
|
|
129
|
+
if ((typeof trustedTypes === 'undefined' ? 'undefined' : _typeof(trustedTypes)) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Allow the callers to control the unique policy name
|
|
134
|
+
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
135
|
+
// Policy creation with duplicate names throws in Trusted Types.
|
|
136
|
+
var suffix = null;
|
|
137
|
+
var ATTR_NAME = 'data-tt-policy-suffix';
|
|
138
|
+
if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
|
|
139
|
+
suffix = document.currentScript.getAttribute(ATTR_NAME);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
return trustedTypes.createPolicy(policyName, {
|
|
146
|
+
createHTML: function createHTML(html$$1) {
|
|
147
|
+
return html$$1;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
} catch (error) {
|
|
151
|
+
// Policy creation failed (most likely another DOMPurify script has
|
|
152
|
+
// already run). Skip creating the policy, as this will only cause errors
|
|
153
|
+
// if TT are enforced.
|
|
154
|
+
console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
62
159
|
function createDOMPurify() {
|
|
63
160
|
var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
64
161
|
|
|
@@ -70,7 +167,7 @@ function createDOMPurify() {
|
|
|
70
167
|
* Version label, exposed for easier checks
|
|
71
168
|
* if DOMPurify is up to date or not
|
|
72
169
|
*/
|
|
73
|
-
DOMPurify.version = '1.0.
|
|
170
|
+
DOMPurify.version = '1.0.11';
|
|
74
171
|
|
|
75
172
|
/**
|
|
76
173
|
* Array of elements that DOMPurify removed during sanitation.
|
|
@@ -87,8 +184,8 @@ function createDOMPurify() {
|
|
|
87
184
|
}
|
|
88
185
|
|
|
89
186
|
var originalDocument = window.document;
|
|
90
|
-
var useDOMParser = false;
|
|
91
|
-
var removeTitle = false;
|
|
187
|
+
var useDOMParser = false;
|
|
188
|
+
var removeTitle = false;
|
|
92
189
|
|
|
93
190
|
var document = window.document;
|
|
94
191
|
var DocumentFragment = window.DocumentFragment,
|
|
@@ -99,7 +196,8 @@ function createDOMPurify() {
|
|
|
99
196
|
NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
|
|
100
197
|
Text = window.Text,
|
|
101
198
|
Comment = window.Comment,
|
|
102
|
-
DOMParser = window.DOMParser
|
|
199
|
+
DOMParser = window.DOMParser,
|
|
200
|
+
TrustedTypes = window.TrustedTypes;
|
|
103
201
|
|
|
104
202
|
// As per issue #47, the web-components registry is inherited by a
|
|
105
203
|
// new document created via createHTMLDocument. As per the spec
|
|
@@ -115,6 +213,9 @@ function createDOMPurify() {
|
|
|
115
213
|
}
|
|
116
214
|
}
|
|
117
215
|
|
|
216
|
+
var trustedTypesPolicy = _createTrustedTypesPolicy(TrustedTypes, originalDocument);
|
|
217
|
+
var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
|
|
218
|
+
|
|
118
219
|
var _document = document,
|
|
119
220
|
implementation = _document.implementation,
|
|
120
221
|
createNodeIterator = _document.createNodeIterator,
|
|
@@ -184,12 +285,14 @@ function createDOMPurify() {
|
|
|
184
285
|
* document.body. By default, browsers might move them to document.head */
|
|
185
286
|
var FORCE_BODY = false;
|
|
186
287
|
|
|
187
|
-
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
288
|
+
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
289
|
+
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
188
290
|
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
189
291
|
*/
|
|
190
292
|
var RETURN_DOM = false;
|
|
191
293
|
|
|
192
|
-
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
294
|
+
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
295
|
+
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
193
296
|
var RETURN_DOM_FRAGMENT = false;
|
|
194
297
|
|
|
195
298
|
/* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM
|
|
@@ -218,7 +321,8 @@ function createDOMPurify() {
|
|
|
218
321
|
var DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image']);
|
|
219
322
|
|
|
220
323
|
/* Attributes safe for values like "javascript:" */
|
|
221
|
-
var URI_SAFE_ATTRIBUTES =
|
|
324
|
+
var URI_SAFE_ATTRIBUTES = null;
|
|
325
|
+
var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
222
326
|
|
|
223
327
|
/* Keep a reference to config to pass to hooks */
|
|
224
328
|
var CONFIG = null;
|
|
@@ -235,13 +339,19 @@ function createDOMPurify() {
|
|
|
235
339
|
*/
|
|
236
340
|
// eslint-disable-next-line complexity
|
|
237
341
|
var _parseConfig = function _parseConfig(cfg) {
|
|
342
|
+
if (CONFIG && CONFIG === cfg) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
238
346
|
/* Shield configuration object from tampering */
|
|
239
|
-
if ((typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {
|
|
347
|
+
if (!cfg || (typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {
|
|
240
348
|
cfg = {};
|
|
241
349
|
}
|
|
350
|
+
|
|
242
351
|
/* Set configuration parameters */
|
|
243
352
|
ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
|
|
244
353
|
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
|
|
354
|
+
URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet({}, cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
245
355
|
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
|
|
246
356
|
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
|
|
247
357
|
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
|
|
@@ -277,16 +387,19 @@ function createDOMPurify() {
|
|
|
277
387
|
addToSet(ALLOWED_TAGS, html);
|
|
278
388
|
addToSet(ALLOWED_ATTR, html$1);
|
|
279
389
|
}
|
|
390
|
+
|
|
280
391
|
if (USE_PROFILES.svg === true) {
|
|
281
392
|
addToSet(ALLOWED_TAGS, svg);
|
|
282
393
|
addToSet(ALLOWED_ATTR, svg$1);
|
|
283
394
|
addToSet(ALLOWED_ATTR, xml);
|
|
284
395
|
}
|
|
396
|
+
|
|
285
397
|
if (USE_PROFILES.svgFilters === true) {
|
|
286
398
|
addToSet(ALLOWED_TAGS, svgFilters);
|
|
287
399
|
addToSet(ALLOWED_ATTR, svg$1);
|
|
288
400
|
addToSet(ALLOWED_ATTR, xml);
|
|
289
401
|
}
|
|
402
|
+
|
|
290
403
|
if (USE_PROFILES.mathMl === true) {
|
|
291
404
|
addToSet(ALLOWED_TAGS, mathMl);
|
|
292
405
|
addToSet(ALLOWED_ATTR, mathMl$1);
|
|
@@ -299,14 +412,18 @@ function createDOMPurify() {
|
|
|
299
412
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
300
413
|
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
301
414
|
}
|
|
415
|
+
|
|
302
416
|
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
|
|
303
417
|
}
|
|
418
|
+
|
|
304
419
|
if (cfg.ADD_ATTR) {
|
|
305
420
|
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
306
421
|
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
307
422
|
}
|
|
423
|
+
|
|
308
424
|
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
|
|
309
425
|
}
|
|
426
|
+
|
|
310
427
|
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
311
428
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
|
|
312
429
|
}
|
|
@@ -328,8 +445,8 @@ function createDOMPurify() {
|
|
|
328
445
|
|
|
329
446
|
// Prevent further manipulation of configuration.
|
|
330
447
|
// Not available in IE8, Safari 5, etc.
|
|
331
|
-
if (
|
|
332
|
-
|
|
448
|
+
if (freeze) {
|
|
449
|
+
freeze(cfg);
|
|
333
450
|
}
|
|
334
451
|
|
|
335
452
|
CONFIG = cfg;
|
|
@@ -344,8 +461,8 @@ function createDOMPurify() {
|
|
|
344
461
|
DOMPurify.removed.push({ element: node });
|
|
345
462
|
try {
|
|
346
463
|
node.parentNode.removeChild(node);
|
|
347
|
-
} catch (
|
|
348
|
-
node.outerHTML =
|
|
464
|
+
} catch (error) {
|
|
465
|
+
node.outerHTML = emptyHTML;
|
|
349
466
|
}
|
|
350
467
|
};
|
|
351
468
|
|
|
@@ -361,12 +478,13 @@ function createDOMPurify() {
|
|
|
361
478
|
attribute: node.getAttributeNode(name),
|
|
362
479
|
from: node
|
|
363
480
|
});
|
|
364
|
-
} catch (
|
|
481
|
+
} catch (error) {
|
|
365
482
|
DOMPurify.removed.push({
|
|
366
483
|
attribute: null,
|
|
367
484
|
from: node
|
|
368
485
|
});
|
|
369
486
|
}
|
|
487
|
+
|
|
370
488
|
node.removeAttribute(name);
|
|
371
489
|
};
|
|
372
490
|
|
|
@@ -379,19 +497,27 @@ function createDOMPurify() {
|
|
|
379
497
|
var _initDocument = function _initDocument(dirty) {
|
|
380
498
|
/* Create a HTML document */
|
|
381
499
|
var doc = void 0;
|
|
500
|
+
var leadingWhitespace = void 0;
|
|
382
501
|
|
|
383
502
|
if (FORCE_BODY) {
|
|
384
503
|
dirty = '<remove></remove>' + dirty;
|
|
504
|
+
} else {
|
|
505
|
+
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
|
506
|
+
var matches = dirty.match(/^[\s]+/);
|
|
507
|
+
leadingWhitespace = matches && matches[0];
|
|
508
|
+
if (leadingWhitespace) {
|
|
509
|
+
dirty = dirty.slice(leadingWhitespace.length);
|
|
510
|
+
}
|
|
385
511
|
}
|
|
386
512
|
|
|
387
513
|
/* Use DOMParser to workaround Firefox bug (see comment below) */
|
|
388
514
|
if (useDOMParser) {
|
|
389
515
|
try {
|
|
390
516
|
doc = new DOMParser().parseFromString(dirty, 'text/html');
|
|
391
|
-
} catch (
|
|
517
|
+
} catch (error) {}
|
|
392
518
|
}
|
|
393
519
|
|
|
394
|
-
/* Remove title to fix
|
|
520
|
+
/* Remove title to fix a mXSS bug in older MS Edge */
|
|
395
521
|
if (removeTitle) {
|
|
396
522
|
addToSet(FORBID_TAGS, ['title']);
|
|
397
523
|
}
|
|
@@ -404,7 +530,11 @@ function createDOMPurify() {
|
|
|
404
530
|
body = _doc.body;
|
|
405
531
|
|
|
406
532
|
body.parentNode.removeChild(body.parentNode.firstElementChild);
|
|
407
|
-
body.outerHTML = dirty;
|
|
533
|
+
body.outerHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (leadingWhitespace) {
|
|
537
|
+
doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
|
|
408
538
|
}
|
|
409
539
|
|
|
410
540
|
/* Work on whole document or just its body */
|
|
@@ -423,19 +553,20 @@ function createDOMPurify() {
|
|
|
423
553
|
if (DOMPurify.isSupported) {
|
|
424
554
|
(function () {
|
|
425
555
|
try {
|
|
426
|
-
var doc = _initDocument('<svg><p><style><img src="</style><img src=x onerror=
|
|
556
|
+
var doc = _initDocument('<svg><p><style><img src="</style><img src=x onerror=1//">');
|
|
427
557
|
if (doc.querySelector('svg img')) {
|
|
428
558
|
useDOMParser = true;
|
|
429
559
|
}
|
|
430
|
-
} catch (
|
|
560
|
+
} catch (error) {}
|
|
431
561
|
})();
|
|
562
|
+
|
|
432
563
|
(function () {
|
|
433
564
|
try {
|
|
434
565
|
var doc = _initDocument('<x/><title></title><img>');
|
|
435
|
-
if (doc.querySelector('title').
|
|
566
|
+
if (doc.querySelector('title').innerHTML.match(/<\/title/)) {
|
|
436
567
|
removeTitle = true;
|
|
437
568
|
}
|
|
438
|
-
} catch (
|
|
569
|
+
} catch (error) {}
|
|
439
570
|
})();
|
|
440
571
|
}
|
|
441
572
|
|
|
@@ -461,9 +592,11 @@ function createDOMPurify() {
|
|
|
461
592
|
if (elm instanceof Text || elm instanceof Comment) {
|
|
462
593
|
return false;
|
|
463
594
|
}
|
|
595
|
+
|
|
464
596
|
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') {
|
|
465
597
|
return true;
|
|
466
598
|
}
|
|
599
|
+
|
|
467
600
|
return false;
|
|
468
601
|
};
|
|
469
602
|
|
|
@@ -505,6 +638,7 @@ function createDOMPurify() {
|
|
|
505
638
|
* @param {Node} currentNode to check for permission to exist
|
|
506
639
|
* @return {Boolean} true if node was killed, false if left alive
|
|
507
640
|
*/
|
|
641
|
+
// eslint-disable-next-line complexity
|
|
508
642
|
var _sanitizeElements = function _sanitizeElements(currentNode) {
|
|
509
643
|
var content = void 0;
|
|
510
644
|
|
|
@@ -531,9 +665,22 @@ function createDOMPurify() {
|
|
|
531
665
|
/* Keep content except for black-listed elements */
|
|
532
666
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] && typeof currentNode.insertAdjacentHTML === 'function') {
|
|
533
667
|
try {
|
|
534
|
-
|
|
535
|
-
|
|
668
|
+
var htmlToInsert = currentNode.innerHTML;
|
|
669
|
+
currentNode.insertAdjacentHTML('AfterEnd', trustedTypesPolicy ? trustedTypesPolicy.createHTML(htmlToInsert) : htmlToInsert);
|
|
670
|
+
} catch (error) {}
|
|
536
671
|
}
|
|
672
|
+
|
|
673
|
+
_forceRemove(currentNode);
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/* Remove in case a noscript/noembed XSS is suspected */
|
|
678
|
+
if (tagName === 'noscript' && currentNode.innerHTML.match(/<\/noscript/i)) {
|
|
679
|
+
_forceRemove(currentNode);
|
|
680
|
+
return true;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (tagName === 'noembed' && currentNode.innerHTML.match(/<\/noembed/i)) {
|
|
537
684
|
_forceRemove(currentNode);
|
|
538
685
|
return true;
|
|
539
686
|
}
|
|
@@ -574,18 +721,13 @@ function createDOMPurify() {
|
|
|
574
721
|
* @param {string} value Attribute value.
|
|
575
722
|
* @return {Boolean} Returns true if `value` is valid, otherwise false.
|
|
576
723
|
*/
|
|
724
|
+
// eslint-disable-next-line complexity
|
|
577
725
|
var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
578
726
|
/* Make sure attribute cannot clobber */
|
|
579
727
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
580
728
|
return false;
|
|
581
729
|
}
|
|
582
730
|
|
|
583
|
-
/* Sanitize attribute content to be template-safe */
|
|
584
|
-
if (SAFE_FOR_TEMPLATES) {
|
|
585
|
-
value = value.replace(MUSTACHE_EXPR$$1, ' ');
|
|
586
|
-
value = value.replace(ERB_EXPR$$1, ' ');
|
|
587
|
-
}
|
|
588
|
-
|
|
589
731
|
/* Allow valid data-* attributes: At least one character after "-"
|
|
590
732
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
591
733
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
@@ -606,7 +748,8 @@ function createDOMPurify() {
|
|
|
606
748
|
} else if (IS_ALLOWED_URI$$1.test(value.replace(ATTR_WHITESPACE$$1, ''))) {
|
|
607
749
|
// This attribute is safe
|
|
608
750
|
/* Keep image data URIs alive if src/xlink:href is allowed */
|
|
609
|
-
|
|
751
|
+
/* Further prevent gadget XSS for dynamically built script tags */
|
|
752
|
+
} else if ((lcName === 'src' || lcName === 'xlink:href') && lcTag !== 'script' && value.indexOf('data:') === 0 && DATA_URI_TAGS[lcTag]) {
|
|
610
753
|
// This attribute is safe
|
|
611
754
|
/* Allow unknown protocols: This provides support for links that
|
|
612
755
|
are handled by protocol handlers which may be unknown ahead of
|
|
@@ -621,6 +764,7 @@ function createDOMPurify() {
|
|
|
621
764
|
} else {
|
|
622
765
|
return false;
|
|
623
766
|
}
|
|
767
|
+
|
|
624
768
|
return true;
|
|
625
769
|
};
|
|
626
770
|
|
|
@@ -632,9 +776,8 @@ function createDOMPurify() {
|
|
|
632
776
|
* @protect removeAttribute
|
|
633
777
|
* @protect setAttribute
|
|
634
778
|
*
|
|
635
|
-
* @param {Node}
|
|
779
|
+
* @param {Node} currentNode to sanitize
|
|
636
780
|
*/
|
|
637
|
-
// eslint-disable-next-line complexity
|
|
638
781
|
var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
639
782
|
var attr = void 0;
|
|
640
783
|
var value = void 0;
|
|
@@ -664,7 +807,8 @@ function createDOMPurify() {
|
|
|
664
807
|
while (l--) {
|
|
665
808
|
attr = attributes[l];
|
|
666
809
|
var _attr = attr,
|
|
667
|
-
name = _attr.name
|
|
810
|
+
name = _attr.name,
|
|
811
|
+
namespaceURI = _attr.namespaceURI;
|
|
668
812
|
|
|
669
813
|
value = attr.value.trim();
|
|
670
814
|
lcName = name.toLowerCase();
|
|
@@ -682,7 +826,7 @@ function createDOMPurify() {
|
|
|
682
826
|
// attribute at the time.
|
|
683
827
|
if (lcName === 'name' && currentNode.nodeName === 'IMG' && attributes.id) {
|
|
684
828
|
idAttr = attributes.id;
|
|
685
|
-
attributes =
|
|
829
|
+
attributes = apply(arraySlice, attributes, []);
|
|
686
830
|
_removeAttribute('id', currentNode);
|
|
687
831
|
_removeAttribute(name, currentNode);
|
|
688
832
|
if (attributes.indexOf(idAttr) > l) {
|
|
@@ -691,7 +835,7 @@ function createDOMPurify() {
|
|
|
691
835
|
} else if (
|
|
692
836
|
// This works around a bug in Safari, where input[type=file]
|
|
693
837
|
// cannot be dynamically set after type has been removed
|
|
694
|
-
currentNode.nodeName === 'INPUT' && lcName === 'type' && value === 'file' && (ALLOWED_ATTR[lcName] || !FORBID_ATTR[lcName])) {
|
|
838
|
+
currentNode.nodeName === 'INPUT' && lcName === 'type' && value === 'file' && hookEvent.keepAttr && (ALLOWED_ATTR[lcName] || !FORBID_ATTR[lcName])) {
|
|
695
839
|
continue;
|
|
696
840
|
} else {
|
|
697
841
|
// This avoids a crash in Safari v9.0 with double-ids.
|
|
@@ -700,6 +844,7 @@ function createDOMPurify() {
|
|
|
700
844
|
if (name === 'id') {
|
|
701
845
|
currentNode.setAttribute(name, '');
|
|
702
846
|
}
|
|
847
|
+
|
|
703
848
|
_removeAttribute(name, currentNode);
|
|
704
849
|
}
|
|
705
850
|
|
|
@@ -708,6 +853,12 @@ function createDOMPurify() {
|
|
|
708
853
|
continue;
|
|
709
854
|
}
|
|
710
855
|
|
|
856
|
+
/* Sanitize attribute content to be template-safe */
|
|
857
|
+
if (SAFE_FOR_TEMPLATES) {
|
|
858
|
+
value = value.replace(MUSTACHE_EXPR$$1, ' ');
|
|
859
|
+
value = value.replace(ERB_EXPR$$1, ' ');
|
|
860
|
+
}
|
|
861
|
+
|
|
711
862
|
/* Is `value` valid for this attribute? */
|
|
712
863
|
var lcTag = currentNode.nodeName.toLowerCase();
|
|
713
864
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
@@ -716,9 +867,15 @@ function createDOMPurify() {
|
|
|
716
867
|
|
|
717
868
|
/* Handle invalid data-* attribute set by try-catching it */
|
|
718
869
|
try {
|
|
719
|
-
|
|
870
|
+
if (namespaceURI) {
|
|
871
|
+
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
872
|
+
} else {
|
|
873
|
+
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
874
|
+
currentNode.setAttribute(name, value);
|
|
875
|
+
}
|
|
876
|
+
|
|
720
877
|
DOMPurify.removed.pop();
|
|
721
|
-
} catch (
|
|
878
|
+
} catch (error) {}
|
|
722
879
|
}
|
|
723
880
|
|
|
724
881
|
/* Execute a hook if present */
|
|
@@ -799,10 +956,12 @@ function createDOMPurify() {
|
|
|
799
956
|
if (typeof dirty === 'string') {
|
|
800
957
|
return window.toStaticHTML(dirty);
|
|
801
958
|
}
|
|
959
|
+
|
|
802
960
|
if (_isNode(dirty)) {
|
|
803
961
|
return window.toStaticHTML(dirty.outerHTML);
|
|
804
962
|
}
|
|
805
963
|
}
|
|
964
|
+
|
|
806
965
|
return dirty;
|
|
807
966
|
}
|
|
808
967
|
|
|
@@ -824,13 +983,16 @@ function createDOMPurify() {
|
|
|
824
983
|
if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
|
|
825
984
|
/* Node is already a body, use as is */
|
|
826
985
|
body = importedNode;
|
|
986
|
+
} else if (importedNode.nodeName === 'HTML') {
|
|
987
|
+
body = importedNode;
|
|
827
988
|
} else {
|
|
989
|
+
// eslint-disable-next-line unicorn/prefer-node-append
|
|
828
990
|
body.appendChild(importedNode);
|
|
829
991
|
}
|
|
830
992
|
} else {
|
|
831
993
|
/* Exit directly if we have nothing to do */
|
|
832
|
-
if (!RETURN_DOM && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
|
|
833
|
-
return dirty;
|
|
994
|
+
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
|
|
995
|
+
return trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
834
996
|
}
|
|
835
997
|
|
|
836
998
|
/* Initialize the document to work on */
|
|
@@ -838,7 +1000,7 @@ function createDOMPurify() {
|
|
|
838
1000
|
|
|
839
1001
|
/* Check we have a DOM node from the data */
|
|
840
1002
|
if (!body) {
|
|
841
|
-
return RETURN_DOM ? null :
|
|
1003
|
+
return RETURN_DOM ? null : emptyHTML;
|
|
842
1004
|
}
|
|
843
1005
|
}
|
|
844
1006
|
|
|
@@ -873,6 +1035,8 @@ function createDOMPurify() {
|
|
|
873
1035
|
oldNode = currentNode;
|
|
874
1036
|
}
|
|
875
1037
|
|
|
1038
|
+
oldNode = null;
|
|
1039
|
+
|
|
876
1040
|
/* If we sanitized `dirty` in-place, return it. */
|
|
877
1041
|
if (IN_PLACE) {
|
|
878
1042
|
return dirty;
|
|
@@ -884,6 +1048,7 @@ function createDOMPurify() {
|
|
|
884
1048
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
885
1049
|
|
|
886
1050
|
while (body.firstChild) {
|
|
1051
|
+
// eslint-disable-next-line unicorn/prefer-node-append
|
|
887
1052
|
returnNode.appendChild(body.firstChild);
|
|
888
1053
|
}
|
|
889
1054
|
} else {
|
|
@@ -902,7 +1067,15 @@ function createDOMPurify() {
|
|
|
902
1067
|
return returnNode;
|
|
903
1068
|
}
|
|
904
1069
|
|
|
905
|
-
|
|
1070
|
+
var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
|
1071
|
+
|
|
1072
|
+
/* Sanitize final string template-safe */
|
|
1073
|
+
if (SAFE_FOR_TEMPLATES) {
|
|
1074
|
+
serializedHTML = serializedHTML.replace(MUSTACHE_EXPR$$1, ' ');
|
|
1075
|
+
serializedHTML = serializedHTML.replace(ERB_EXPR$$1, ' ');
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
return trustedTypesPolicy ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
906
1079
|
};
|
|
907
1080
|
|
|
908
1081
|
/**
|
|
@@ -941,6 +1114,7 @@ function createDOMPurify() {
|
|
|
941
1114
|
if (!CONFIG) {
|
|
942
1115
|
_parseConfig({});
|
|
943
1116
|
}
|
|
1117
|
+
|
|
944
1118
|
var lcTag = tag.toLowerCase();
|
|
945
1119
|
var lcName = attr.toLowerCase();
|
|
946
1120
|
return _isValidAttribute(lcTag, lcName, value);
|
|
@@ -957,6 +1131,7 @@ function createDOMPurify() {
|
|
|
957
1131
|
if (typeof hookFunction !== 'function') {
|
|
958
1132
|
return;
|
|
959
1133
|
}
|
|
1134
|
+
|
|
960
1135
|
hooks[entryPoint] = hooks[entryPoint] || [];
|
|
961
1136
|
hooks[entryPoint].push(hookFunction);
|
|
962
1137
|
};
|