Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions sanitize_html/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v2.3.0
* Support `allowElements` to allow custom tag names.

## v2.2.0
* Allow the `<picture>` and `<source>` elements, with `srcset` on `<source>`,
matching the [`html-pipeline` allowlist](https://github.com/gjtorikian/html-pipeline/blob/main/lib/html_pipeline/sanitization_filter.rb)
Expand Down
4 changes: 4 additions & 0 deletions sanitize_html/lib/sanitize_html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import 'src/sane_html_validator.dart' show SaneHtmlValidator;
/// guard against XSS as this sanitizer also attempts to prevent the sanitized
/// HTML from interfering with the page it is injected into.
///
/// The optional [allowElements] callback will be called with uppercase tag names.
///
/// For example, while it is possible to allow many CSS properties, this
/// sanitizer does not allow any CSS. This creates a sanitizer that is easy to
/// validate and is usually fine when sanitizing HTML from rendered markdown.
Expand Down Expand Up @@ -71,11 +73,13 @@ import 'src/sane_html_validator.dart' show SaneHtmlValidator;
/// [3]: https://support.google.com/webmasters/answer/81749
String sanitizeHtml(
String htmlString, {
bool Function(String)? allowElements,
bool Function(String)? allowElementId,
bool Function(String)? allowClassName,
Iterable<String>? Function(String)? addLinkRel,
}) {
return SaneHtmlValidator(
allowElements: allowElements,
allowElementId: allowElementId,
allowClassName: allowClassName,
addLinkRel: addLinkRel,
Expand Down
5 changes: 4 additions & 1 deletion sanitize_html/lib/src/sane_html_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,13 @@ final _elementAttributeValidators =
///
/// [1]: https://github.com/gjtorikian/html-pipeline/blob/main/lib/html_pipeline/sanitization_filter.rb
class SaneHtmlValidator {
final bool Function(String)? allowElements;
final bool Function(String)? allowElementId;
final bool Function(String)? allowClassName;
final Iterable<String>? Function(String)? addLinkRel;

SaneHtmlValidator({
required this.allowElements,
required this.allowElementId,
required this.allowClassName,
required this.addLinkRel,
Expand All @@ -256,7 +258,8 @@ class SaneHtmlValidator {
void _sanitize(Node node) {
if (node is Element) {
final tagName = node.localName!.toUpperCase();
if (!_allowedElements.contains(tagName)) {
if (!_allowedElements.contains(tagName) &&
!(allowElements?.call(tagName) ?? false)) {
node.remove();
return;
}
Expand Down
2 changes: 1 addition & 1 deletion sanitize_html/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: sanitize_html
version: 2.2.0
version: 2.3.0
description: >-
Function for sanitizing HTML to prevent XSS by restrict elements and
attributes to a safe subset of allowed values.
Expand Down
10 changes: 10 additions & 0 deletions sanitize_html/test/sanitize_html_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void main() {

return sanitizeHtml(
template,
allowElements: (tagName) => tagName == 'ONLY-ALLOWED-TAG',
allowElementId: (id) => id == 'only-allowed-id',
allowClassName: (className) => className == 'only-allowed-class',
addLinkRel: (href) => href == 'bad-link' ? ['ugc', 'nofollow'] : null,
Expand Down Expand Up @@ -65,6 +66,13 @@ void main() {
testContains('<p>hello', '</p>');
testContains('<p>hello', '<p>');

// test tag name filtering
testContains(
'<only-allowed-tag>hello</only-allowed-tag>', '<only-allowed-tag>');
testContains('<only-allowed-tag>hello</only-allowed-tag>', 'hello');
testNotContains('<disallowed-tag>hello</disallowed-tag>', 'disallowed-tag');
testNotContains('<disallowed-tag>hello</disallowed-tag>', 'hello');

// test id filtering..
testContains('<span id="only-allowed-id">hello</span>', 'id');
testContains('<span id="only-allowed-id">hello</span>', 'only-allowed-id');
Expand Down Expand Up @@ -185,6 +193,8 @@ void main() {
withOptionalConfiguration: false);
testNotContains('<a href="any-href">hey', 'rel=',
withOptionalConfiguration: false);
testNotContains('<any-tag>hello</any-tag>', 'hello',
withOptionalConfiguration: false);
testNotContains('<span id="any-id">hello</span>', 'id=',
withOptionalConfiguration: false);
testNotContains('<span class="any-class">hello</span>', 'class=',
Expand Down
Loading