sanitize-html 2.14.0 → 2.15.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 +18 -3
- package/index.js +22 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -494,6 +494,21 @@ sanitizeHtml(
|
|
|
494
494
|
);
|
|
495
495
|
```
|
|
496
496
|
|
|
497
|
+
The filter function can also return the string `"excludeTag"` to only remove the tag, while keeping its content. For example, you can remove tags for anchors with invalid links:
|
|
498
|
+
|
|
499
|
+
```js
|
|
500
|
+
sanitizeHtml(
|
|
501
|
+
'This is a <a href="javascript:alert(123)">bad link</a> and a <a href="https://www.linux.org">good link</a>',
|
|
502
|
+
{
|
|
503
|
+
exclusiveFilter: function(frame) {
|
|
504
|
+
// the href attribute is removed by the URL protocol check
|
|
505
|
+
return frame.tag === 'a' && !frame.attribs.href ? 'excludeTag' : false;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
// Output: 'This is a bad link and a <a href="https://www.linux.org">good link</a>'
|
|
510
|
+
```
|
|
511
|
+
|
|
497
512
|
The `frame` object supplied to the callback provides the following attributes:
|
|
498
513
|
|
|
499
514
|
- `tag`: The tag name, i.e. `'img'`.
|
|
@@ -709,9 +724,9 @@ This will transform `<disallowed>content</disallowed>` to `<disallowed>con
|
|
|
709
724
|
|
|
710
725
|
Valid values are: `'discard'` (default), `'completelyDiscard'` (remove disallowed tag's content), `'escape'` (escape the tag) and `'recursiveEscape'` (to escape the tag and all its content).
|
|
711
726
|
|
|
712
|
-
#### Discard disallowed but
|
|
727
|
+
#### Discard disallowed but the inner content of disallowed tags is kept.
|
|
713
728
|
|
|
714
|
-
If you set `disallowedTagsMode` to `discard`, disallowed tags are discarded but
|
|
729
|
+
If you set `disallowedTagsMode` to `discard`, disallowed tags are discarded but the inner content of disallowed tags is kept.
|
|
715
730
|
|
|
716
731
|
```js
|
|
717
732
|
disallowedTagsMode: 'discard'
|
|
@@ -720,7 +735,7 @@ This will transform `<disallowed>content</disallowed>` to `content`
|
|
|
720
735
|
|
|
721
736
|
#### Discard entire content of a disallowed tag
|
|
722
737
|
|
|
723
|
-
If you set `disallowedTagsMode` to `completelyDiscard`, disallowed tags and any
|
|
738
|
+
If you set `disallowedTagsMode` to `completelyDiscard`, disallowed tags and any text they contain are discarded. This also discards top-level text. Any subtags are still included, as long as those individual subtags are allowed.
|
|
724
739
|
|
|
725
740
|
```js
|
|
726
741
|
disallowedTagsMode: 'completelyDiscard'
|
package/index.js
CHANGED
|
@@ -97,6 +97,7 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
97
97
|
this.attribs = attribs || {};
|
|
98
98
|
this.tagPosition = result.length;
|
|
99
99
|
this.text = ''; // Node inner text
|
|
100
|
+
this.openingTagLength = 0;
|
|
100
101
|
this.mediaChildren = [];
|
|
101
102
|
|
|
102
103
|
this.updateParentNodeText = function() {
|
|
@@ -268,7 +269,6 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
268
269
|
skipTextDepth = 1;
|
|
269
270
|
}
|
|
270
271
|
}
|
|
271
|
-
skipMap[depth] = true;
|
|
272
272
|
}
|
|
273
273
|
depth++;
|
|
274
274
|
if (skip) {
|
|
@@ -279,7 +279,7 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
279
279
|
if (options.textFilter) {
|
|
280
280
|
result += options.textFilter(escaped, name);
|
|
281
281
|
} else {
|
|
282
|
-
result +=
|
|
282
|
+
result += escaped;
|
|
283
283
|
}
|
|
284
284
|
addedText = true;
|
|
285
285
|
}
|
|
@@ -507,6 +507,7 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
507
507
|
result = tempResult + escapeHtml(result);
|
|
508
508
|
tempResult = '';
|
|
509
509
|
}
|
|
510
|
+
frame.openingTagLength = result.length - frame.tagPosition;
|
|
510
511
|
},
|
|
511
512
|
ontext: function(text) {
|
|
512
513
|
if (skipText) {
|
|
@@ -529,11 +530,11 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
529
530
|
// your concern, don't allow them. The same is essentially true for style tags
|
|
530
531
|
// which have their own collection of XSS vectors.
|
|
531
532
|
result += text;
|
|
532
|
-
} else {
|
|
533
|
+
} else if (!addedText) {
|
|
533
534
|
const escaped = escapeHtml(text, false);
|
|
534
|
-
if (options.textFilter
|
|
535
|
+
if (options.textFilter) {
|
|
535
536
|
result += options.textFilter(escaped, tag);
|
|
536
|
-
} else
|
|
537
|
+
} else {
|
|
537
538
|
result += escaped;
|
|
538
539
|
}
|
|
539
540
|
}
|
|
@@ -584,9 +585,21 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
584
585
|
delete transformMap[depth];
|
|
585
586
|
}
|
|
586
587
|
|
|
587
|
-
if (options.exclusiveFilter
|
|
588
|
-
|
|
589
|
-
|
|
588
|
+
if (options.exclusiveFilter) {
|
|
589
|
+
const filterResult = options.exclusiveFilter(frame);
|
|
590
|
+
if (filterResult === 'excludeTag') {
|
|
591
|
+
if (skip) {
|
|
592
|
+
// no longer escaping the tag since it's not added at all
|
|
593
|
+
result = tempResult;
|
|
594
|
+
tempResult = '';
|
|
595
|
+
}
|
|
596
|
+
// remove the opening tag from the result
|
|
597
|
+
result = result.substring(0, frame.tagPosition) + result.substring(frame.tagPosition + frame.openingTagLength);
|
|
598
|
+
return;
|
|
599
|
+
} else if (filterResult) {
|
|
600
|
+
result = result.substring(0, frame.tagPosition);
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
590
603
|
}
|
|
591
604
|
|
|
592
605
|
frame.updateParentNodeMediaChildren();
|
|
@@ -832,7 +845,7 @@ sanitizeHtml.defaults = {
|
|
|
832
845
|
'main', 'nav', 'section',
|
|
833
846
|
// Text content
|
|
834
847
|
'blockquote', 'dd', 'div', 'dl', 'dt', 'figcaption', 'figure',
|
|
835
|
-
'hr', 'li', '
|
|
848
|
+
'hr', 'li', 'menu', 'ol', 'p', 'pre', 'ul',
|
|
836
849
|
// Inline text semantics
|
|
837
850
|
'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn',
|
|
838
851
|
'em', 'i', 'kbd', 'mark', 'q',
|
package/package.json
CHANGED