dompurify 2.0.7 → 2.0.8
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 +21 -12
- package/dist/purify.cjs.js +139 -88
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +139 -88
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +139 -88
- 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 +4 -4
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG.
|
|
8
8
|
|
|
9
|
-
It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version 2.0.
|
|
9
|
+
It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version 2.0.8.
|
|
10
10
|
|
|
11
11
|
DOMPurify is written in JavaScript and works in all modern browsers (Safari, Opera (15+), Internet Explorer (10+), Edge, Firefox and Chrome - as well as almost anything else using Blink or WebKit). It doesn't break on MSIE6 or other legacy browsers. It either uses [a fall-back](#what-about-older-browsers-like-msie8) or simply does nothing.
|
|
12
12
|
|
|
@@ -48,27 +48,30 @@ If you're using an [AMD](https://github.com/amdjs/amdjs-api/wiki/AMD) module loa
|
|
|
48
48
|
|
|
49
49
|
```javascript
|
|
50
50
|
require(['dompurify'], function(DOMPurify) {
|
|
51
|
-
|
|
51
|
+
var clean = DOMPurify.sanitize(dirty);
|
|
52
52
|
});
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
DOMPurify also works server-side with node.js as well as client-side via [Browserify](http://browserify.org/) or similar translators.
|
|
55
|
+
DOMPurify also works server-side with node.js as well as client-side via [Browserify](http://browserify.org/) or similar translators. Node.js 0.x is not supported; either [io.js](https://iojs.org) or Node.js 4.x or newer is required.
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
58
|
npm install dompurify
|
|
59
59
|
```
|
|
60
|
+
|
|
60
61
|
For JSDOM v10 or newer
|
|
62
|
+
|
|
61
63
|
```javascript
|
|
62
64
|
const createDOMPurify = require('dompurify');
|
|
63
65
|
const { JSDOM } = require('jsdom');
|
|
64
66
|
|
|
65
|
-
const window =
|
|
67
|
+
const window = new JSDOM('').window;
|
|
66
68
|
const DOMPurify = createDOMPurify(window);
|
|
67
69
|
|
|
68
70
|
const clean = DOMPurify.sanitize(dirty);
|
|
69
71
|
```
|
|
70
72
|
|
|
71
73
|
For JSDOM versions older than v10
|
|
74
|
+
|
|
72
75
|
```javascript
|
|
73
76
|
const createDOMPurify = require('dompurify');
|
|
74
77
|
const jsdom = require('jsdom').jsdom;
|
|
@@ -96,7 +99,7 @@ How does purified markup look like? Well, [the demo](https://cure53.de/purify) s
|
|
|
96
99
|
```javascript
|
|
97
100
|
DOMPurify.sanitize('<img src=x onerror=alert(1)//>'); // becomes <img src="x">
|
|
98
101
|
DOMPurify.sanitize('<svg><g/onload=alert(2)//<p>'); // becomes <svg><g></g></svg>
|
|
99
|
-
DOMPurify.sanitize('<p>abc<iframe
|
|
102
|
+
DOMPurify.sanitize('<p>abc<iframe//src=jAva	script:alert(3)>def'); // becomes <p>abcdef</p>
|
|
100
103
|
DOMPurify.sanitize('<math><mi//xlink:href="data:x,<script>alert(4)</script>">'); // becomes <math><mi></mi></math>
|
|
101
104
|
DOMPurify.sanitize('<TABLE><tr><td>HELLO</tr></TABL>'); // becomes <table><tbody><tr><td>HELLO</td></tr></tbody></table>
|
|
102
105
|
DOMPurify.sanitize('<UL><li><A HREF=//google.com>click</UL>'); // becomes <ul><li><a href="//google.com">click</a></li></ul>
|
|
@@ -114,7 +117,7 @@ If not even `toStaticHTML` is supported, DOMPurify does nothing at all. It simpl
|
|
|
114
117
|
|
|
115
118
|
## What about DOMPurify and Trusted Types?
|
|
116
119
|
|
|
117
|
-
In version 1.0.9, support for [Trusted Types API](https://github.com/WICG/trusted-types) was added to DOMPurify.
|
|
120
|
+
In version 1.0.9, support for [Trusted Types API](https://github.com/WICG/trusted-types) was added to DOMPurify.
|
|
118
121
|
In version 2.0.0, a config flag was added to control DOMPurify's behavior regarding this.
|
|
119
122
|
|
|
120
123
|
When `DOMPurify.sanitize` is used in an environment where the Trusted Types API is available and `RETURN_TRUSTED_TYPE` is set to `true`, it tries to return a `TrustedHTML` value instead of a string (the behavior for `RETURN_DOM`, `RETURN_DOM_FRAGMENT`, and `RETURN_DOM_IMPORT` config options does not change).
|
|
@@ -205,6 +208,7 @@ var dirty = document.createElement('a');
|
|
|
205
208
|
dirty.setAttribute('href', 'javascript:alert(1)');
|
|
206
209
|
var clean = DOMPurify.sanitize(dirty, {IN_PLACE: true}); // see https://github.com/cure53/DOMPurify/issues/288 for more info
|
|
207
210
|
```
|
|
211
|
+
|
|
208
212
|
There is even [more examples here](https://github.com/cure53/DOMPurify/tree/master/demos#what-is-this), showing how you can run, customize and configure DOMPurify to fit your needs.
|
|
209
213
|
|
|
210
214
|
## Persistent Configuration
|
|
@@ -216,7 +220,7 @@ Instead of repeatedly passing the same configuration to `DOMPurify.sanitize`, yo
|
|
|
216
220
|
DOMPurify allows you to augment its functionality by attaching one or more functions with the `DOMPurify.addHook` method to one of the following hooks:
|
|
217
221
|
|
|
218
222
|
- `beforeSanitizeElements`
|
|
219
|
-
- `uponSanitizeElement`
|
|
223
|
+
- `uponSanitizeElement` (No 's' - called for every element)
|
|
220
224
|
- `afterSanitizeElements`
|
|
221
225
|
- `beforeSanitizeAttributes`
|
|
222
226
|
- `uponSanitizeAttribute`
|
|
@@ -230,9 +234,14 @@ It passes the currently processed DOM node, when needed a literal with verified
|
|
|
230
234
|
_Example_:
|
|
231
235
|
|
|
232
236
|
```javascript
|
|
233
|
-
DOMPurify.addHook('beforeSanitizeElements', function(
|
|
234
|
-
|
|
235
|
-
|
|
237
|
+
DOMPurify.addHook('beforeSanitizeElements', function(
|
|
238
|
+
currentNode,
|
|
239
|
+
hookEvent,
|
|
240
|
+
config
|
|
241
|
+
) {
|
|
242
|
+
// Do something with the current node and return it
|
|
243
|
+
// You can also mutate hookEvent (i.e. set hookEvent.forceKeepAttr = true)
|
|
244
|
+
return currentNode;
|
|
236
245
|
});
|
|
237
246
|
```
|
|
238
247
|
|
|
@@ -280,8 +289,8 @@ Feature releases will not be announced to this list.
|
|
|
280
289
|
|
|
281
290
|
## Who contributed?
|
|
282
291
|
|
|
283
|
-
Many people helped DOMPurify become what it is and need to be acknowledged here!
|
|
292
|
+
Many people helped and help DOMPurify become what it is and need to be acknowledged here!
|
|
284
293
|
|
|
285
|
-
|
|
294
|
+
[oreoshake 💸](https://github.com/oreoshake), [dcramer 💸](https://github.com/dcramer),[tdeekens](https://github.com/tdeekens), [neilj](https://github.com/neilj), [fhemberger](https://github.com/fhemberger), [Joris-van-der-Wel](https://github.com/Joris-van-der-Wel), [ydaniv](https://github.com/ydaniv), [filedescriptor](https://github.com/filedescriptor), [ConradIrwin](https://github.com/ConradIrwin), [gibson042](https://github.com/gibson042), [choumx](https://github.com/choumx), [0xSobky](https://github.com/0xSobky), [styfle](https://github.com/styfle), [koto](https://github.com/koto), [tlau88](https://github.com/tlau88), [strugee](https://github.com/strugee), [oparoz](https://github.com/oparoz), [mathiasbynens](https://github.com/mathiasbynens), [edg2s](https://github.com/edg2s), [dnkolegov](https://github.com/dnkolegov), [dhardtke](https://github.com/dhardtke), [wirehead](https://github.com/wirehead), [thorn0](https://github.com/thorn0), [styu](https://github.com/styu), [mozfreddyb](https://github.com/mozfreddyb), [mikesamuel](https://github.com/mikesamuel), [jorangreef](https://github.com/jorangreef), [jimmyhchan](https://github.com/jimmyhchan), [jameydeorio](https://github.com/jameydeorio), [jameskraus](https://github.com/jameskraus), [hyderali](https://github.com/hyderali), [hansottowirtz](https://github.com/hansottowirtz), [hackvertor](https://github.com/hackvertor), [freddyb](https://github.com/freddyb), [flavorjones](https://github.com/flavorjones), [djfarrelly](https://github.com/djfarrelly), [devd](https://github.com/devd), [camerondunford](https://github.com/camerondunford), [buu700](https://github.com/buu700), [buildog](https://github.com/buildog), [alabiaga](https://github.com/alabiaga), [Vector919](https://github.com/Vector919), [Robbert](https://github.com/Robbert), [GreLI](https://github.com/GreLI), [FuzzySockets](https://github.com/FuzzySockets), [ArtemBernatskyy](https://github.com/ArtemBernatskyy), [@garethheyes](https://twitter.com/garethheyes), [@filedescriptor](https://twitter.com/filedescriptor), [@shafigullin](https://twitter.com/shafigullin), [@mmrupp](https://twitter.com/mmrupp), [@irsdl](https://twitter.com/irsdl),[ShikariSenpai](https://github.com/ShikariSenpai), [ansjdnakjdnajkd](https://github.com/ansjdnakjdnajkd), [@asutherland](https://twitter.com/asutherland), [@mathias](https://twitter.com/mathias), [@cgvwzq](https://twitter.com/cgvwzq), [@robbertatwork](https://twitter.com/robbertatwork), [@giutro](https://twitter.com/giutro) and especially [@masatokinugawa](https://twitter.com/masatokinugawa)
|
|
286
295
|
|
|
287
296
|
And last but not least, thanks to [BrowserStack](https://browserstack.com) for supporting this project with their services for free and delivering excellent, dedicated and very professional support on top of that.
|
package/dist/purify.cjs.js
CHANGED
|
@@ -1,41 +1,77 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
return x;
|
|
5
|
-
};
|
|
3
|
+
function _toConsumableArray$1(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); } }
|
|
6
4
|
|
|
7
|
-
var
|
|
5
|
+
var hasOwnProperty = Object.hasOwnProperty;
|
|
6
|
+
var setPrototypeOf = Object.setPrototypeOf;
|
|
7
|
+
var isFrozen = Object.isFrozen;
|
|
8
|
+
var objectKeys = Object.keys;
|
|
9
|
+
var freeze = Object.freeze;
|
|
10
|
+
var seal = Object.seal; // eslint-disable-line import/no-mutable-exports
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
var
|
|
12
|
+
var _ref = typeof Reflect !== 'undefined' && Reflect;
|
|
13
|
+
var apply = _ref.apply;
|
|
14
|
+
var construct = _ref.construct;
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
if (!apply) {
|
|
17
|
+
apply = function apply(fun, thisValue, args) {
|
|
18
|
+
return fun.apply(thisValue, args);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!freeze) {
|
|
23
|
+
freeze = function freeze(x) {
|
|
24
|
+
return x;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
13
27
|
|
|
14
|
-
|
|
28
|
+
if (!seal) {
|
|
29
|
+
seal = function seal(x) {
|
|
30
|
+
return x;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
15
33
|
|
|
16
|
-
|
|
34
|
+
if (!construct) {
|
|
35
|
+
construct = function construct(Func, args) {
|
|
36
|
+
return new (Function.prototype.bind.apply(Func, [null].concat(_toConsumableArray$1(args))))();
|
|
37
|
+
};
|
|
38
|
+
}
|
|
17
39
|
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
40
|
+
var arrayForEach = unapply(Array.prototype.forEach);
|
|
41
|
+
var arrayIndexOf = unapply(Array.prototype.indexOf);
|
|
42
|
+
var arrayJoin = unapply(Array.prototype.join);
|
|
43
|
+
var arrayPop = unapply(Array.prototype.pop);
|
|
44
|
+
var arrayPush = unapply(Array.prototype.push);
|
|
45
|
+
var arraySlice = unapply(Array.prototype.slice);
|
|
21
46
|
|
|
22
|
-
var
|
|
47
|
+
var stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
48
|
+
var stringMatch = unapply(String.prototype.match);
|
|
49
|
+
var stringReplace = unapply(String.prototype.replace);
|
|
50
|
+
var stringIndexOf = unapply(String.prototype.indexOf);
|
|
51
|
+
var stringTrim = unapply(String.prototype.trim);
|
|
23
52
|
|
|
24
|
-
var
|
|
53
|
+
var regExpTest = unapply(RegExp.prototype.test);
|
|
54
|
+
var regExpCreate = unconstruct(RegExp);
|
|
25
55
|
|
|
26
|
-
var
|
|
56
|
+
var typeErrorCreate = unconstruct(TypeError);
|
|
27
57
|
|
|
28
|
-
|
|
58
|
+
function unapply(func) {
|
|
59
|
+
return function (thisArg) {
|
|
60
|
+
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
61
|
+
args[_key - 1] = arguments[_key];
|
|
62
|
+
}
|
|
29
63
|
|
|
30
|
-
|
|
31
|
-
|
|
64
|
+
return apply(func, thisArg, args);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
32
67
|
|
|
33
|
-
|
|
34
|
-
|
|
68
|
+
function unconstruct(func) {
|
|
69
|
+
return function () {
|
|
70
|
+
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
71
|
+
args[_key2] = arguments[_key2];
|
|
72
|
+
}
|
|
35
73
|
|
|
36
|
-
|
|
37
|
-
apply$1 = function apply(fun, thisValue, args) {
|
|
38
|
-
return fun.apply(thisValue, args);
|
|
74
|
+
return construct(func, args);
|
|
39
75
|
};
|
|
40
76
|
}
|
|
41
77
|
|
|
@@ -52,10 +88,10 @@ function addToSet(set, array) {
|
|
|
52
88
|
while (l--) {
|
|
53
89
|
var element = array[l];
|
|
54
90
|
if (typeof element === 'string') {
|
|
55
|
-
var lcElement = element
|
|
91
|
+
var lcElement = stringToLowerCase(element);
|
|
56
92
|
if (lcElement !== element) {
|
|
57
93
|
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
58
|
-
if (!
|
|
94
|
+
if (!isFrozen(array)) {
|
|
59
95
|
array[l] = lcElement;
|
|
60
96
|
}
|
|
61
97
|
|
|
@@ -75,7 +111,7 @@ function clone(object) {
|
|
|
75
111
|
|
|
76
112
|
var property = void 0;
|
|
77
113
|
for (property in object) {
|
|
78
|
-
if (apply
|
|
114
|
+
if (apply(hasOwnProperty, object, [property])) {
|
|
79
115
|
newObject[property] = object[property];
|
|
80
116
|
}
|
|
81
117
|
}
|
|
@@ -83,9 +119,24 @@ function clone(object) {
|
|
|
83
119
|
return newObject;
|
|
84
120
|
}
|
|
85
121
|
|
|
86
|
-
var
|
|
87
|
-
|
|
88
|
-
|
|
122
|
+
var html = freeze(['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', 'picture', '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']);
|
|
123
|
+
|
|
124
|
+
// SVG
|
|
125
|
+
var svg = freeze(['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']);
|
|
126
|
+
|
|
127
|
+
var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
|
|
128
|
+
|
|
129
|
+
var mathMl = freeze(['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']);
|
|
130
|
+
|
|
131
|
+
var text = freeze(['#text']);
|
|
132
|
+
|
|
133
|
+
var html$1 = freeze(['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']);
|
|
134
|
+
|
|
135
|
+
var svg$1 = freeze(['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']);
|
|
136
|
+
|
|
137
|
+
var mathMl$1 = freeze(['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']);
|
|
138
|
+
|
|
139
|
+
var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
89
140
|
|
|
90
141
|
var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
91
142
|
var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm);
|
|
@@ -101,22 +152,10 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
|
|
101
152
|
|
|
102
153
|
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); } }
|
|
103
154
|
|
|
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
|
-
|
|
110
155
|
var getGlobal = function getGlobal() {
|
|
111
156
|
return typeof window === 'undefined' ? null : window;
|
|
112
157
|
};
|
|
113
158
|
|
|
114
|
-
if (!apply) {
|
|
115
|
-
apply = function apply(fun, thisValue, args) {
|
|
116
|
-
return fun.apply(thisValue, args);
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
159
|
/**
|
|
121
160
|
* Creates a no-op policy for internal use only.
|
|
122
161
|
* Don't export this function outside this module!
|
|
@@ -167,7 +206,7 @@ function createDOMPurify() {
|
|
|
167
206
|
* Version label, exposed for easier checks
|
|
168
207
|
* if DOMPurify is up to date or not
|
|
169
208
|
*/
|
|
170
|
-
DOMPurify.version = '2.0.
|
|
209
|
+
DOMPurify.version = '2.0.8';
|
|
171
210
|
|
|
172
211
|
/**
|
|
173
212
|
* Array of elements that DOMPurify removed during sanitation.
|
|
@@ -197,7 +236,7 @@ function createDOMPurify() {
|
|
|
197
236
|
Text = window.Text,
|
|
198
237
|
Comment = window.Comment,
|
|
199
238
|
DOMParser = window.DOMParser,
|
|
200
|
-
|
|
239
|
+
trustedTypes = window.trustedTypes;
|
|
201
240
|
|
|
202
241
|
// As per issue #47, the web-components registry is inherited by a
|
|
203
242
|
// new document created via createHTMLDocument. As per the spec
|
|
@@ -213,7 +252,7 @@ function createDOMPurify() {
|
|
|
213
252
|
}
|
|
214
253
|
}
|
|
215
254
|
|
|
216
|
-
var trustedTypesPolicy = _createTrustedTypesPolicy(
|
|
255
|
+
var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
|
|
217
256
|
var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
|
|
218
257
|
|
|
219
258
|
var _document = document,
|
|
@@ -374,9 +413,7 @@ function createDOMPurify() {
|
|
|
374
413
|
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
|
|
375
414
|
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
376
415
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
377
|
-
|
|
378
416
|
IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
|
|
379
|
-
|
|
380
417
|
if (SAFE_FOR_TEMPLATES) {
|
|
381
418
|
ALLOW_DATA_ATTR = false;
|
|
382
419
|
}
|
|
@@ -465,7 +502,7 @@ function createDOMPurify() {
|
|
|
465
502
|
* @param {Node} node a DOM node
|
|
466
503
|
*/
|
|
467
504
|
var _forceRemove = function _forceRemove(node) {
|
|
468
|
-
DOMPurify.removed
|
|
505
|
+
arrayPush(DOMPurify.removed, { element: node });
|
|
469
506
|
try {
|
|
470
507
|
node.parentNode.removeChild(node);
|
|
471
508
|
} catch (error) {
|
|
@@ -481,12 +518,12 @@ function createDOMPurify() {
|
|
|
481
518
|
*/
|
|
482
519
|
var _removeAttribute = function _removeAttribute(name, node) {
|
|
483
520
|
try {
|
|
484
|
-
DOMPurify.removed
|
|
521
|
+
arrayPush(DOMPurify.removed, {
|
|
485
522
|
attribute: node.getAttributeNode(name),
|
|
486
523
|
from: node
|
|
487
524
|
});
|
|
488
525
|
} catch (error) {
|
|
489
|
-
DOMPurify.removed
|
|
526
|
+
arrayPush(DOMPurify.removed, {
|
|
490
527
|
attribute: null,
|
|
491
528
|
from: node
|
|
492
529
|
});
|
|
@@ -510,17 +547,15 @@ function createDOMPurify() {
|
|
|
510
547
|
dirty = '<remove></remove>' + dirty;
|
|
511
548
|
} else {
|
|
512
549
|
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
|
513
|
-
var matches = dirty
|
|
550
|
+
var matches = stringMatch(dirty, /^[\s]+/);
|
|
514
551
|
leadingWhitespace = matches && matches[0];
|
|
515
|
-
if (leadingWhitespace) {
|
|
516
|
-
dirty = dirty.slice(leadingWhitespace.length);
|
|
517
|
-
}
|
|
518
552
|
}
|
|
519
553
|
|
|
554
|
+
var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
520
555
|
/* Use DOMParser to workaround Firefox bug (see comment below) */
|
|
521
556
|
if (useDOMParser) {
|
|
522
557
|
try {
|
|
523
|
-
doc = new DOMParser().parseFromString(
|
|
558
|
+
doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
|
|
524
559
|
} catch (error) {}
|
|
525
560
|
}
|
|
526
561
|
|
|
@@ -537,7 +572,7 @@ function createDOMPurify() {
|
|
|
537
572
|
body = _doc.body;
|
|
538
573
|
|
|
539
574
|
body.parentNode.removeChild(body.parentNode.firstElementChild);
|
|
540
|
-
body.outerHTML =
|
|
575
|
+
body.outerHTML = dirtyPayload;
|
|
541
576
|
}
|
|
542
577
|
|
|
543
578
|
if (dirty && leadingWhitespace) {
|
|
@@ -570,7 +605,7 @@ function createDOMPurify() {
|
|
|
570
605
|
(function () {
|
|
571
606
|
try {
|
|
572
607
|
var doc = _initDocument('<x/><title></title><img>');
|
|
573
|
-
if (/<\/title
|
|
608
|
+
if (regExpTest(/<\/title/, doc.querySelector('title').innerHTML)) {
|
|
574
609
|
removeTitle = true;
|
|
575
610
|
}
|
|
576
611
|
} catch (error) {}
|
|
@@ -630,7 +665,7 @@ function createDOMPurify() {
|
|
|
630
665
|
return;
|
|
631
666
|
}
|
|
632
667
|
|
|
633
|
-
hooks[entryPoint]
|
|
668
|
+
arrayForEach(hooks[entryPoint], function (hook) {
|
|
634
669
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
635
670
|
});
|
|
636
671
|
};
|
|
@@ -659,7 +694,7 @@ function createDOMPurify() {
|
|
|
659
694
|
}
|
|
660
695
|
|
|
661
696
|
/* Now let's check the element's type and name */
|
|
662
|
-
var tagName = currentNode.nodeName
|
|
697
|
+
var tagName = stringToLowerCase(currentNode.nodeName);
|
|
663
698
|
|
|
664
699
|
/* Execute a hook if present */
|
|
665
700
|
_executeHook('uponSanitizeElement', currentNode, {
|
|
@@ -688,23 +723,23 @@ function createDOMPurify() {
|
|
|
688
723
|
}
|
|
689
724
|
|
|
690
725
|
/* Remove in case a noscript/noembed XSS is suspected */
|
|
691
|
-
if (tagName === 'noscript' && /<\/noscript/i
|
|
726
|
+
if (tagName === 'noscript' && regExpTest(/<\/noscript/i, currentNode.innerHTML)) {
|
|
692
727
|
_forceRemove(currentNode);
|
|
693
728
|
return true;
|
|
694
729
|
}
|
|
695
730
|
|
|
696
|
-
if (tagName === 'noembed' && /<\/noembed/i
|
|
731
|
+
if (tagName === 'noembed' && regExpTest(/<\/noembed/i, currentNode.innerHTML)) {
|
|
697
732
|
_forceRemove(currentNode);
|
|
698
733
|
return true;
|
|
699
734
|
}
|
|
700
735
|
|
|
701
736
|
/* Convert markup to cover jQuery behavior */
|
|
702
|
-
if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && (!currentNode.content || !currentNode.content.firstElementChild) && /</g
|
|
703
|
-
DOMPurify.removed
|
|
737
|
+
if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && (!currentNode.content || !currentNode.content.firstElementChild) && regExpTest(/</g, currentNode.textContent)) {
|
|
738
|
+
arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
|
|
704
739
|
if (currentNode.innerHTML) {
|
|
705
|
-
currentNode.innerHTML = currentNode.innerHTML
|
|
740
|
+
currentNode.innerHTML = stringReplace(currentNode.innerHTML, /</g, '<');
|
|
706
741
|
} else {
|
|
707
|
-
currentNode.innerHTML = currentNode.textContent
|
|
742
|
+
currentNode.innerHTML = stringReplace(currentNode.textContent, /</g, '<');
|
|
708
743
|
}
|
|
709
744
|
}
|
|
710
745
|
|
|
@@ -712,10 +747,10 @@ function createDOMPurify() {
|
|
|
712
747
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
|
713
748
|
/* Get the element's text content */
|
|
714
749
|
content = currentNode.textContent;
|
|
715
|
-
content = content
|
|
716
|
-
content = content
|
|
750
|
+
content = stringReplace(content, MUSTACHE_EXPR$$1, ' ');
|
|
751
|
+
content = stringReplace(content, ERB_EXPR$$1, ' ');
|
|
717
752
|
if (currentNode.textContent !== content) {
|
|
718
|
-
DOMPurify.removed
|
|
753
|
+
arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
|
|
719
754
|
currentNode.textContent = content;
|
|
720
755
|
}
|
|
721
756
|
}
|
|
@@ -745,9 +780,9 @@ function createDOMPurify() {
|
|
|
745
780
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
746
781
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
747
782
|
We don't need to check the value; it's always URI safe. */
|
|
748
|
-
if (ALLOW_DATA_ATTR && DATA_ATTR$$1
|
|
783
|
+
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$$1, lcName)) {
|
|
749
784
|
// This attribute is safe
|
|
750
|
-
} else if (ALLOW_ARIA_ATTR && ARIA_ATTR$$1
|
|
785
|
+
} else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) {
|
|
751
786
|
// This attribute is safe
|
|
752
787
|
/* Otherwise, check the name is permitted */
|
|
753
788
|
} else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
@@ -758,16 +793,16 @@ function createDOMPurify() {
|
|
|
758
793
|
// This attribute is safe
|
|
759
794
|
/* Check no script, data or unknown possibly unsafe URI
|
|
760
795
|
unless we know URI values are safe for that attribute */
|
|
761
|
-
} else if (IS_ALLOWED_URI$$1
|
|
796
|
+
} else if (regExpTest(IS_ALLOWED_URI$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) {
|
|
762
797
|
// This attribute is safe
|
|
763
798
|
/* Keep image data URIs alive if src/xlink:href is allowed */
|
|
764
799
|
/* Further prevent gadget XSS for dynamically built script tags */
|
|
765
|
-
} else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && value
|
|
800
|
+
} else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) {
|
|
766
801
|
// This attribute is safe
|
|
767
802
|
/* Allow unknown protocols: This provides support for links that
|
|
768
803
|
are handled by protocol handlers which may be unknown ahead of
|
|
769
804
|
time, e.g. fb:, spotify: */
|
|
770
|
-
} else if (ALLOW_UNKNOWN_PROTOCOLS && !IS_SCRIPT_OR_DATA$$1
|
|
805
|
+
} else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) {
|
|
771
806
|
// This attribute is safe
|
|
772
807
|
/* Check for binary attributes */
|
|
773
808
|
// eslint-disable-next-line no-negated-condition
|
|
@@ -824,15 +859,20 @@ function createDOMPurify() {
|
|
|
824
859
|
name = _attr.name,
|
|
825
860
|
namespaceURI = _attr.namespaceURI;
|
|
826
861
|
|
|
827
|
-
value = attr.value
|
|
828
|
-
lcName = name
|
|
862
|
+
value = stringTrim(attr.value);
|
|
863
|
+
lcName = stringToLowerCase(name);
|
|
829
864
|
|
|
830
865
|
/* Execute a hook if present */
|
|
831
866
|
hookEvent.attrName = lcName;
|
|
832
867
|
hookEvent.attrValue = value;
|
|
833
868
|
hookEvent.keepAttr = true;
|
|
869
|
+
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
|
834
870
|
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
|
835
871
|
value = hookEvent.attrValue;
|
|
872
|
+
/* Did the hooks approve of the attribute? */
|
|
873
|
+
if (hookEvent.forceKeepAttr) {
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
836
876
|
|
|
837
877
|
/* Remove attribute */
|
|
838
878
|
// Safari (iOS + Mac), last tested v8.0.5, crashes if you try to
|
|
@@ -840,10 +880,10 @@ function createDOMPurify() {
|
|
|
840
880
|
// attribute at the time.
|
|
841
881
|
if (lcName === 'name' && currentNode.nodeName === 'IMG' && attributes.id) {
|
|
842
882
|
idAttr = attributes.id;
|
|
843
|
-
attributes =
|
|
883
|
+
attributes = arraySlice(attributes, []);
|
|
844
884
|
_removeAttribute('id', currentNode);
|
|
845
885
|
_removeAttribute(name, currentNode);
|
|
846
|
-
if (attributes
|
|
886
|
+
if (arrayIndexOf(attributes, idAttr) > l) {
|
|
847
887
|
currentNode.setAttribute('id', idAttr.value);
|
|
848
888
|
}
|
|
849
889
|
} else if (
|
|
@@ -867,16 +907,22 @@ function createDOMPurify() {
|
|
|
867
907
|
continue;
|
|
868
908
|
}
|
|
869
909
|
|
|
910
|
+
/* Work around a security issue in jQuery 3.0 */
|
|
911
|
+
if (SAFE_FOR_JQUERY && regExpTest(/\/>/i, value)) {
|
|
912
|
+
_removeAttribute(name, currentNode);
|
|
913
|
+
continue;
|
|
914
|
+
}
|
|
915
|
+
|
|
870
916
|
/* Take care of an mXSS pattern using namespace switches */
|
|
871
|
-
if (/svg|math/i
|
|
917
|
+
if (regExpTest(/svg|math/i, currentNode.namespaceURI) && regExpTest(regExpCreate('</(' + arrayJoin(objectKeys(FORBID_CONTENTS), '|') + ')', 'i'), value)) {
|
|
872
918
|
_removeAttribute(name, currentNode);
|
|
873
919
|
continue;
|
|
874
920
|
}
|
|
875
921
|
|
|
876
922
|
/* Sanitize attribute content to be template-safe */
|
|
877
923
|
if (SAFE_FOR_TEMPLATES) {
|
|
878
|
-
value = value
|
|
879
|
-
value = value
|
|
924
|
+
value = stringReplace(value, MUSTACHE_EXPR$$1, ' ');
|
|
925
|
+
value = stringReplace(value, ERB_EXPR$$1, ' ');
|
|
880
926
|
}
|
|
881
927
|
|
|
882
928
|
/* Is `value` valid for this attribute? */
|
|
@@ -894,7 +940,7 @@ function createDOMPurify() {
|
|
|
894
940
|
currentNode.setAttribute(name, value);
|
|
895
941
|
}
|
|
896
942
|
|
|
897
|
-
DOMPurify.removed
|
|
943
|
+
arrayPop(DOMPurify.removed);
|
|
898
944
|
} catch (error) {}
|
|
899
945
|
}
|
|
900
946
|
|
|
@@ -961,11 +1007,11 @@ function createDOMPurify() {
|
|
|
961
1007
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
962
1008
|
// eslint-disable-next-line no-negated-condition
|
|
963
1009
|
if (typeof dirty.toString !== 'function') {
|
|
964
|
-
throw
|
|
1010
|
+
throw typeErrorCreate('toString is not a function');
|
|
965
1011
|
} else {
|
|
966
1012
|
dirty = dirty.toString();
|
|
967
1013
|
if (typeof dirty !== 'string') {
|
|
968
|
-
throw
|
|
1014
|
+
throw typeErrorCreate('dirty is not a string, aborting');
|
|
969
1015
|
}
|
|
970
1016
|
}
|
|
971
1017
|
}
|
|
@@ -993,6 +1039,11 @@ function createDOMPurify() {
|
|
|
993
1039
|
/* Clean up removed elements */
|
|
994
1040
|
DOMPurify.removed = [];
|
|
995
1041
|
|
|
1042
|
+
/* Check if dirty is correctly typed for IN_PLACE */
|
|
1043
|
+
if (typeof dirty === 'string') {
|
|
1044
|
+
IN_PLACE = false;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
996
1047
|
if (IN_PLACE) {
|
|
997
1048
|
/* No special handling necessary for in-place sanitization */
|
|
998
1049
|
} else if (dirty instanceof Node) {
|
|
@@ -1091,8 +1142,8 @@ function createDOMPurify() {
|
|
|
1091
1142
|
|
|
1092
1143
|
/* Sanitize final string template-safe */
|
|
1093
1144
|
if (SAFE_FOR_TEMPLATES) {
|
|
1094
|
-
serializedHTML = serializedHTML
|
|
1095
|
-
serializedHTML = serializedHTML
|
|
1145
|
+
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$$1, ' ');
|
|
1146
|
+
serializedHTML = stringReplace(serializedHTML, ERB_EXPR$$1, ' ');
|
|
1096
1147
|
}
|
|
1097
1148
|
|
|
1098
1149
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
@@ -1135,8 +1186,8 @@ function createDOMPurify() {
|
|
|
1135
1186
|
_parseConfig({});
|
|
1136
1187
|
}
|
|
1137
1188
|
|
|
1138
|
-
var lcTag = tag
|
|
1139
|
-
var lcName = attr
|
|
1189
|
+
var lcTag = stringToLowerCase(tag);
|
|
1190
|
+
var lcName = stringToLowerCase(attr);
|
|
1140
1191
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1141
1192
|
};
|
|
1142
1193
|
|
|
@@ -1153,7 +1204,7 @@ function createDOMPurify() {
|
|
|
1153
1204
|
}
|
|
1154
1205
|
|
|
1155
1206
|
hooks[entryPoint] = hooks[entryPoint] || [];
|
|
1156
|
-
hooks[entryPoint]
|
|
1207
|
+
arrayPush(hooks[entryPoint], hookFunction);
|
|
1157
1208
|
};
|
|
1158
1209
|
|
|
1159
1210
|
/**
|
|
@@ -1165,7 +1216,7 @@ function createDOMPurify() {
|
|
|
1165
1216
|
*/
|
|
1166
1217
|
DOMPurify.removeHook = function (entryPoint) {
|
|
1167
1218
|
if (hooks[entryPoint]) {
|
|
1168
|
-
hooks[entryPoint]
|
|
1219
|
+
arrayPop(hooks[entryPoint]);
|
|
1169
1220
|
}
|
|
1170
1221
|
};
|
|
1171
1222
|
|