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.
Files changed (3) hide show
  1. package/README.md +18 -3
  2. package/index.js +22 -9
  3. 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 `&lt;disallowed&gt;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 but the inner content of disallowed tags is kept.
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 but the inner content of disallowed tags is kept.
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 content they contain are discarded. Any subtags are still included, as long as those individual subtags are allowed.
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 += escapeHtml(frame.innerText);
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 && !addedText) {
535
+ if (options.textFilter) {
535
536
  result += options.textFilter(escaped, tag);
536
- } else if (!addedText) {
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 && options.exclusiveFilter(frame)) {
588
- result = result.substr(0, frame.tagPosition);
589
- return;
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', 'main', 'ol', 'p', 'pre', 'ul',
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanitize-html",
3
- "version": "2.14.0",
3
+ "version": "2.15.0",
4
4
  "description": "Clean up user-submitted HTML, preserving allowlisted elements and allowlisted attributes on a per-element basis",
5
5
  "sideEffects": false,
6
6
  "main": "index.js",