dompurify 3.2.6 → 3.3.0
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 +47 -7
- package/dist/purify.cjs.d.ts +8 -4
- package/dist/purify.cjs.js +59 -25
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.d.mts +8 -4
- package/dist/purify.es.mjs +59 -25
- package/dist/purify.es.mjs.map +1 -1
- package/dist/purify.js +59 -25
- package/dist/purify.js.map +1 -1
- package/dist/purify.min.js +2 -2
- package/dist/purify.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# DOMPurify
|
|
2
2
|
|
|
3
|
-
[](http://badge.fury.io/js/dompurify)  [](https://www.npmjs.com/package/dompurify)  [](https://github.com/cure53/DOMPurify/network/dependents) [](https://cloudback.it)
|
|
4
4
|
|
|
5
5
|
DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG.
|
|
6
6
|
|
|
7
|
-
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 **v3.
|
|
7
|
+
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 **v3.3.0**.
|
|
8
8
|
|
|
9
9
|
DOMPurify is written in JavaScript and works in all modern browsers (Safari (10+), Opera (15+), Edge, Firefox and Chrome - as well as almost anything else using Blink, Gecko or WebKit). It doesn't break on MSIE or other legacy browsers. It simply does nothing.
|
|
10
10
|
|
|
@@ -175,8 +175,8 @@ const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_TEMPLATES: true});
|
|
|
175
175
|
|
|
176
176
|
|
|
177
177
|
// change how e.g. comments containing risky HTML characters are treated.
|
|
178
|
-
// be very careful, this setting should only be set to `false` if you really only handle
|
|
179
|
-
// HTML and nothing else, no SVG, MathML or the like.
|
|
178
|
+
// be very careful, this setting should only be set to `false` if you really only handle
|
|
179
|
+
// HTML and nothing else, no SVG, MathML or the like.
|
|
180
180
|
// Otherwise, changing from `true` to `false` will lead to XSS in this or some other way.
|
|
181
181
|
const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_XML: false});
|
|
182
182
|
```
|
|
@@ -215,6 +215,24 @@ const clean = DOMPurify.sanitize(dirty, {ADD_TAGS: ['my-tag']});
|
|
|
215
215
|
// extend the existing array of allowed attributes and add my-attr to allow-list
|
|
216
216
|
const clean = DOMPurify.sanitize(dirty, {ADD_ATTR: ['my-attr']});
|
|
217
217
|
|
|
218
|
+
// use functions to control which additional tags and attributes are allowed
|
|
219
|
+
const allowlist = {
|
|
220
|
+
'one': ['attribute-one'],
|
|
221
|
+
'two': ['attribute-two']
|
|
222
|
+
};
|
|
223
|
+
const clean = DOMPurify.sanitize(
|
|
224
|
+
'<one attribute-one="1" attribute-two="2"></one><two attribute-one="1" attribute-two="2"></two>',
|
|
225
|
+
{
|
|
226
|
+
ADD_TAGS: (tagName) => {
|
|
227
|
+
return Object.keys(allowlist).includes(tagName);
|
|
228
|
+
},
|
|
229
|
+
ADD_ATTR: (attributeName, tagName) => {
|
|
230
|
+
|
|
231
|
+
return allowlist[tagName]?.includes(attributeName) || false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
); // <one attribute-one="1"></one><two attribute-two="2"></two>
|
|
235
|
+
|
|
218
236
|
// prohibit ARIA attributes, leave other safe HTML as is (default is true)
|
|
219
237
|
const clean = DOMPurify.sanitize(dirty, {ALLOW_ARIA_ATTR: false});
|
|
220
238
|
|
|
@@ -230,6 +248,8 @@ const clean = DOMPurify.sanitize(dirty, {ALLOW_DATA_ATTR: false});
|
|
|
230
248
|
// The same goes for their attributes. By default, the built-in or configured allow.list is used.
|
|
231
249
|
//
|
|
232
250
|
// You can use a RegExp literal to specify what is allowed or a predicate, examples for both can be seen below.
|
|
251
|
+
// When using a predicate function for attributeNameCheck, it can optionally receive the tagName as a second parameter
|
|
252
|
+
// for more granular control over which attributes are allowed for specific elements.
|
|
233
253
|
// The default values are very restrictive to prevent accidental XSS bypasses. Handle with great care!
|
|
234
254
|
|
|
235
255
|
const clean = DOMPurify.sanitize(
|
|
@@ -264,6 +284,26 @@ const clean = DOMPurify.sanitize(
|
|
|
264
284
|
},
|
|
265
285
|
}
|
|
266
286
|
); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>
|
|
287
|
+
|
|
288
|
+
// Example with attributeNameCheck receiving tagName as a second parameter
|
|
289
|
+
const clean = DOMPurify.sanitize(
|
|
290
|
+
'<element-one attribute-one="1" attribute-two="2"></element-one><element-two attribute-one="1" attribute-two="2"></element-two>',
|
|
291
|
+
{
|
|
292
|
+
CUSTOM_ELEMENT_HANDLING: {
|
|
293
|
+
tagNameCheck: (tagName) => tagName.match(/^element-(one|two)$/),
|
|
294
|
+
attributeNameCheck: (attr, tagName) => {
|
|
295
|
+
if (tagName === 'element-one') {
|
|
296
|
+
return ['attribute-one'].includes(attr);
|
|
297
|
+
} else if (tagName === 'element-two') {
|
|
298
|
+
return ['attribute-two'].includes(attr);
|
|
299
|
+
} else {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
allowCustomizedBuiltInElements: false,
|
|
304
|
+
},
|
|
305
|
+
}
|
|
306
|
+
); // <element-one attribute-one="1"></element-one><element-two attribute-two="2"></element-two>
|
|
267
307
|
```
|
|
268
308
|
### Control behavior relating to URI values
|
|
269
309
|
```js
|
|
@@ -281,9 +321,9 @@ const clean = DOMPurify.sanitize(dirty, {ADD_URI_SAFE_ATTR: ['my-attr']});
|
|
|
281
321
|
const clean = DOMPurify.sanitize(dirty, {ALLOW_UNKNOWN_PROTOCOLS: true});
|
|
282
322
|
|
|
283
323
|
// allow specific protocols handlers in URL attributes via regex (default is false, be careful, XSS risk)
|
|
284
|
-
// by default only http, https, ftp, ftps, tel, mailto, callto, sms, cid and
|
|
324
|
+
// by default only (protocol-)relative URLs, http, https, ftp, ftps, tel, mailto, callto, sms, cid, xmpp and matrix are allowed.
|
|
285
325
|
// Default RegExp: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i;
|
|
286
|
-
const clean = DOMPurify.sanitize(dirty, {ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|
|
|
326
|
+
const clean = DOMPurify.sanitize(dirty, {ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i});
|
|
287
327
|
|
|
288
328
|
```
|
|
289
329
|
### Influence the return-type
|
|
@@ -427,7 +467,7 @@ Feature releases will not be announced to this list.
|
|
|
427
467
|
|
|
428
468
|
Many people helped and help DOMPurify become what it is and need to be acknowledged here!
|
|
429
469
|
|
|
430
|
-
[hash_kitten ❤️](https://twitter.com/hash_kitten), [kevin_mizu ❤️](https://twitter.com/kevin_mizu), [icesfont ❤️](https://github.com/icesfont), [reduckted ❤️](https://github.com/reduckted), [dcramer 💸](https://github.com/dcramer), [JGraph 💸](https://github.com/jgraph), [baekilda 💸](https://github.com/baekilda), [Healthchecks 💸](https://github.com/healthchecks), [Sentry 💸](https://github.com/getsentry), [jarrodldavis 💸](https://github.com/jarrodldavis), [CynegeticIO](https://github.com/CynegeticIO), [ssi02014 ❤️](https://github.com/ssi02014), [GrantGryczan](https://github.com/GrantGryczan), [Lowdefy](https://twitter.com/lowdefy), [granlem](https://twitter.com/MaximeVeit), [oreoshake](https://github.com/oreoshake), [tdeekens ❤️](https://github.com/tdeekens), [peernohell ❤️](https://github.com/peernohell), [is2ei](https://github.com/is2ei), [SoheilKhodayari](https://github.com/SoheilKhodayari), [franktopel](https://github.com/franktopel), [NateScarlet](https://github.com/NateScarlet), [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), [terjanq](https://twitter.com/terjanq), [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), [@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), [@CmdEngineer\_](https://twitter.com/CmdEngineer_), [@avr4mit](https://twitter.com/avr4mit), [davecardwell](https://github.com/davecardwell) and especially [@securitymb ❤️](https://twitter.com/securitymb) & [@masatokinugawa ❤️](https://twitter.com/masatokinugawa)
|
|
470
|
+
[Cybozu 💛💸](https://github.com/cybozu), [hata6502 💸](https://github.com/hata6502), [intra-mart-dh 💸](https://github.com/intra-mart-dh), [nelstrom ❤️](https://github.com/nelstrom), [hash_kitten ❤️](https://twitter.com/hash_kitten), [kevin_mizu ❤️](https://twitter.com/kevin_mizu), [icesfont ❤️](https://github.com/icesfont), [reduckted ❤️](https://github.com/reduckted), [dcramer 💸](https://github.com/dcramer), [JGraph 💸](https://github.com/jgraph), [baekilda 💸](https://github.com/baekilda), [Healthchecks 💸](https://github.com/healthchecks), [Sentry 💸](https://github.com/getsentry), [jarrodldavis 💸](https://github.com/jarrodldavis), [CynegeticIO](https://github.com/CynegeticIO), [ssi02014 ❤️](https://github.com/ssi02014), [GrantGryczan](https://github.com/GrantGryczan), [Lowdefy](https://twitter.com/lowdefy), [granlem](https://twitter.com/MaximeVeit), [oreoshake](https://github.com/oreoshake), [tdeekens ❤️](https://github.com/tdeekens), [peernohell ❤️](https://github.com/peernohell), [is2ei](https://github.com/is2ei), [SoheilKhodayari](https://github.com/SoheilKhodayari), [franktopel](https://github.com/franktopel), [NateScarlet](https://github.com/NateScarlet), [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), [terjanq](https://twitter.com/terjanq), [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), [@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), [@CmdEngineer\_](https://twitter.com/CmdEngineer_), [@avr4mit](https://twitter.com/avr4mit), [davecardwell](https://github.com/davecardwell) and especially [@securitymb ❤️](https://twitter.com/securitymb) & [@masatokinugawa ❤️](https://twitter.com/masatokinugawa)
|
|
431
471
|
|
|
432
472
|
## Testing powered by
|
|
433
473
|
|
package/dist/purify.cjs.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.
|
|
1
|
+
/*! @license DOMPurify 3.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.0/LICENSE */
|
|
2
2
|
|
|
3
3
|
import { TrustedTypePolicy, TrustedHTML, TrustedTypesWindow } from 'trusted-types/lib';
|
|
4
4
|
|
|
@@ -8,16 +8,20 @@ import { TrustedTypePolicy, TrustedHTML, TrustedTypesWindow } from 'trusted-type
|
|
|
8
8
|
interface Config {
|
|
9
9
|
/**
|
|
10
10
|
* Extend the existing array of allowed attributes.
|
|
11
|
+
* Can be an array of attribute names, or a function that receives
|
|
12
|
+
* the attribute name and tag name to determine if the attribute is allowed.
|
|
11
13
|
*/
|
|
12
|
-
ADD_ATTR?: string[] | undefined;
|
|
14
|
+
ADD_ATTR?: string[] | ((attributeName: string, tagName: string) => boolean) | undefined;
|
|
13
15
|
/**
|
|
14
16
|
* Extend the existing array of elements that can use Data URIs.
|
|
15
17
|
*/
|
|
16
18
|
ADD_DATA_URI_TAGS?: string[] | undefined;
|
|
17
19
|
/**
|
|
18
20
|
* Extend the existing array of allowed tags.
|
|
21
|
+
* Can be an array of tag names, or a function that receives
|
|
22
|
+
* the tag name to determine if the tag is allowed.
|
|
19
23
|
*/
|
|
20
|
-
ADD_TAGS?: string[] | undefined;
|
|
24
|
+
ADD_TAGS?: string[] | ((tagName: string) => boolean) | undefined;
|
|
21
25
|
/**
|
|
22
26
|
* Extend the existing array of elements that are safe for URI-like values (be careful, XSS risk).
|
|
23
27
|
*/
|
|
@@ -76,7 +80,7 @@ interface Config {
|
|
|
76
80
|
* Regular expression or function to match to allowed attributes.
|
|
77
81
|
* Default is null (disallow any attributes not on the allow list).
|
|
78
82
|
*/
|
|
79
|
-
attributeNameCheck?: RegExp | ((attributeName: string) => boolean) | null | undefined;
|
|
83
|
+
attributeNameCheck?: RegExp | ((attributeName: string, tagName?: string) => boolean) | null | undefined;
|
|
80
84
|
/**
|
|
81
85
|
* Allow custom elements derived from built-ins if they pass `tagNameCheck`. Default is false.
|
|
82
86
|
*/
|
package/dist/purify.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.
|
|
1
|
+
/*! @license DOMPurify 3.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.0/LICENSE */
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -29,12 +29,18 @@ if (!seal) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
if (!apply) {
|
|
32
|
-
apply = function apply(
|
|
33
|
-
|
|
32
|
+
apply = function apply(func, thisArg) {
|
|
33
|
+
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
|
34
|
+
args[_key - 2] = arguments[_key];
|
|
35
|
+
}
|
|
36
|
+
return func.apply(thisArg, args);
|
|
34
37
|
};
|
|
35
38
|
}
|
|
36
39
|
if (!construct) {
|
|
37
|
-
construct = function construct(Func
|
|
40
|
+
construct = function construct(Func) {
|
|
41
|
+
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
|
42
|
+
args[_key2 - 1] = arguments[_key2];
|
|
43
|
+
}
|
|
38
44
|
return new Func(...args);
|
|
39
45
|
};
|
|
40
46
|
}
|
|
@@ -63,8 +69,8 @@ function unapply(func) {
|
|
|
63
69
|
if (thisArg instanceof RegExp) {
|
|
64
70
|
thisArg.lastIndex = 0;
|
|
65
71
|
}
|
|
66
|
-
for (var
|
|
67
|
-
args[
|
|
72
|
+
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
|
73
|
+
args[_key3 - 1] = arguments[_key3];
|
|
68
74
|
}
|
|
69
75
|
return apply(func, thisArg, args);
|
|
70
76
|
};
|
|
@@ -75,12 +81,12 @@ function unapply(func) {
|
|
|
75
81
|
* @param func - The constructor function to be wrapped and called.
|
|
76
82
|
* @returns A new function that constructs an instance of the given constructor function with the provided arguments.
|
|
77
83
|
*/
|
|
78
|
-
function unconstruct(
|
|
84
|
+
function unconstruct(Func) {
|
|
79
85
|
return function () {
|
|
80
|
-
for (var
|
|
81
|
-
args[
|
|
86
|
+
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
|
|
87
|
+
args[_key4] = arguments[_key4];
|
|
82
88
|
}
|
|
83
|
-
return construct(
|
|
89
|
+
return construct(Func, args);
|
|
84
90
|
};
|
|
85
91
|
}
|
|
86
92
|
/**
|
|
@@ -179,8 +185,8 @@ function lookupGetter(object, prop) {
|
|
|
179
185
|
return fallbackValue;
|
|
180
186
|
}
|
|
181
187
|
|
|
182
|
-
const html$1 = 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', 'dialog', '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']);
|
|
183
|
-
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', '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', 'view', 'vkern']);
|
|
188
|
+
const html$1 = 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', 'dialog', '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', 'search', 'section', 'select', 'shadow', 'slot', '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']);
|
|
189
|
+
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
184
190
|
const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
|
|
185
191
|
// List of SVG elements that are disallowed by default.
|
|
186
192
|
// We still need to know them so that we can do namespace
|
|
@@ -193,8 +199,8 @@ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mgly
|
|
|
193
199
|
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
194
200
|
const text = freeze(['#text']);
|
|
195
201
|
|
|
196
|
-
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', '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', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
|
|
197
|
-
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', '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', 'exponent', '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', 'intercept', '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', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', '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']);
|
|
202
|
+
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
|
|
203
|
+
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', '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', 'exponent', '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', 'intercept', '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', 'mask-type', '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', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', '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']);
|
|
198
204
|
const mathMl = 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']);
|
|
199
205
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
200
206
|
|
|
@@ -301,7 +307,7 @@ const _createHooksMap = function _createHooksMap() {
|
|
|
301
307
|
function createDOMPurify() {
|
|
302
308
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
303
309
|
const DOMPurify = root => createDOMPurify(root);
|
|
304
|
-
DOMPurify.version = '3.
|
|
310
|
+
DOMPurify.version = '3.3.0';
|
|
305
311
|
DOMPurify.removed = [];
|
|
306
312
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
307
313
|
// Not running in a browser, provide a factory function
|
|
@@ -412,6 +418,21 @@ function createDOMPurify() {
|
|
|
412
418
|
let FORBID_TAGS = null;
|
|
413
419
|
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
414
420
|
let FORBID_ATTR = null;
|
|
421
|
+
/* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */
|
|
422
|
+
const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
|
|
423
|
+
tagCheck: {
|
|
424
|
+
writable: true,
|
|
425
|
+
configurable: false,
|
|
426
|
+
enumerable: true,
|
|
427
|
+
value: null
|
|
428
|
+
},
|
|
429
|
+
attributeCheck: {
|
|
430
|
+
writable: true,
|
|
431
|
+
configurable: false,
|
|
432
|
+
enumerable: true,
|
|
433
|
+
value: null
|
|
434
|
+
}
|
|
435
|
+
}));
|
|
415
436
|
/* Decide if ARIA attributes are okay */
|
|
416
437
|
let ALLOW_ARIA_ATTR = true;
|
|
417
438
|
/* Decide if custom data attributes are okay */
|
|
@@ -604,16 +625,24 @@ function createDOMPurify() {
|
|
|
604
625
|
}
|
|
605
626
|
/* Merge configuration parameters */
|
|
606
627
|
if (cfg.ADD_TAGS) {
|
|
607
|
-
if (
|
|
608
|
-
|
|
628
|
+
if (typeof cfg.ADD_TAGS === 'function') {
|
|
629
|
+
EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
|
|
630
|
+
} else {
|
|
631
|
+
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
632
|
+
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
633
|
+
}
|
|
634
|
+
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
609
635
|
}
|
|
610
|
-
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
611
636
|
}
|
|
612
637
|
if (cfg.ADD_ATTR) {
|
|
613
|
-
if (
|
|
614
|
-
|
|
638
|
+
if (typeof cfg.ADD_ATTR === 'function') {
|
|
639
|
+
EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
|
|
640
|
+
} else {
|
|
641
|
+
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
642
|
+
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
643
|
+
}
|
|
644
|
+
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
615
645
|
}
|
|
616
|
-
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
617
646
|
}
|
|
618
647
|
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
619
648
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
@@ -921,7 +950,7 @@ function createDOMPurify() {
|
|
|
921
950
|
return true;
|
|
922
951
|
}
|
|
923
952
|
/* Remove element if anything forbids its presence */
|
|
924
|
-
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
953
|
+
if (!(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName])) {
|
|
925
954
|
/* Check if we have a custom element to handle */
|
|
926
955
|
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
927
956
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
@@ -993,12 +1022,12 @@ function createDOMPurify() {
|
|
|
993
1022
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
994
1023
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
995
1024
|
We don't need to check the value; it's always URI safe. */
|
|
996
|
-
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
1025
|
+
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
997
1026
|
if (
|
|
998
1027
|
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
999
1028
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1000
1029
|
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
1001
|
-
_isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) ||
|
|
1030
|
+
_isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) ||
|
|
1002
1031
|
// Alternative, second condition checks if it's an `is`-attribute, AND
|
|
1003
1032
|
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1004
1033
|
lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {
|
|
@@ -1077,7 +1106,12 @@ function createDOMPurify() {
|
|
|
1077
1106
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
1078
1107
|
}
|
|
1079
1108
|
/* Work around a security issue with comments inside attributes */
|
|
1080
|
-
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
|
|
1109
|
+
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title|textarea)/i, value)) {
|
|
1110
|
+
_removeAttribute(name, currentNode);
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
/* Make sure we cannot easily use animated hrefs, even if animations are allowed */
|
|
1114
|
+
if (lcName === 'attributename' && stringMatch(value, 'href')) {
|
|
1081
1115
|
_removeAttribute(name, currentNode);
|
|
1082
1116
|
continue;
|
|
1083
1117
|
}
|