From fb470200834e7c3ca2483421ee6842f207fd1f72 Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Tue, 12 Oct 2021 17:40:59 +0200 Subject: [PATCH 1/7] Sanitizing html after markdown and tool/inject-html directive rendering --- CHANGELOG.md | 5 + lib/src/dartdoc_options.dart | 6 + lib/src/model/documentation.dart | 5 +- lib/src/render/documentation_renderer.dart | 279 ++++++++++++++++++++- test/end2end/model_special_cases_test.dart | 2 +- 5 files changed, 285 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34554d2cba..1c60eb63da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.1.0-dev +* BREAKING CHANGE: HTML output from markdown rendering, `{@tool}` and + `{@inject-html}` is sanitized by default. HTML sanitization can be disabled + with `--no-sanitize-html`. + ## 4.0.0 * BREAKING CHANGE: Refactors to support NNBD and adapt to new analyzer changes are technically semver breaking. If you make extensive use of diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index 8d6325d4ba..02ee96c9e5 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -1311,6 +1311,8 @@ class DartdocOptionContext extends DartdocOptionContextBase bool get injectHtml => optionSet['injectHtml'].valueAt(context); + bool get sanitizeHtml => optionSet['sanitizeHtml'].valueAt(context); + bool get excludeFooterVersion => optionSet['excludeFooterVersion'].valueAt(context); @@ -1460,6 +1462,10 @@ Future> createDartdocOptions( DartdocOptionArgOnly('injectHtml', false, resourceProvider, help: 'Allow the use of the {@inject-html} directive to inject raw ' 'HTML into dartdoc output.'), + DartdocOptionArgOnly('sanitizeHtml', true, resourceProvider, + negatable: true, + help: 'Sanitize HTML generated from markdown, {@tool} and ' + '{@inject-html} directives.'), DartdocOptionArgOnly( 'input', resourceProvider.pathContext.current, resourceProvider, optionIs: OptionKind.dir, diff --git a/lib/src/model/documentation.dart b/lib/src/model/documentation.dart index 44dc46d891..6039501b15 100644 --- a/lib/src/model/documentation.dart +++ b/lib/src/model/documentation.dart @@ -51,8 +51,9 @@ class Documentation { } _hasExtendedDocs = parseResult.hasExtendedDocs; - var renderResult = - _renderer.render(parseResult.nodes, processFullDocs: processFullDocs); + var renderResult = _renderer.render(parseResult.nodes, + processFullDocs: processFullDocs, + sanitizeHtml: _element.config.sanitizeHtml); if (processFullDocs) { _asHtml = renderResult.asHtml; diff --git a/lib/src/render/documentation_renderer.dart b/lib/src/render/documentation_renderer.dart index 47b2351238..a6a0c68b44 100644 --- a/lib/src/render/documentation_renderer.dart +++ b/lib/src/render/documentation_renderer.dart @@ -2,7 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'package:html/parser.dart' show parse; +import 'package:html/dom.dart' as dom; +import 'package:html/parser.dart' show parseFragment; + import 'package:markdown/markdown.dart' as md; import 'package:meta/meta.dart'; @@ -10,6 +12,7 @@ abstract class DocumentationRenderer { DocumentationRenderResult render( List nodes, { @required bool processFullDocs, + @required bool sanitizeHtml, }); } @@ -20,16 +23,16 @@ class DocumentationRendererHtml implements DocumentationRenderer { DocumentationRenderResult render( List nodes, { @required bool processFullDocs, + @required bool sanitizeHtml, }) { if (nodes.isEmpty) { return DocumentationRenderResult.empty; } + var rawHtml = md.HtmlRenderer().render(nodes); - var asHtmlDocument = parse(rawHtml); - for (var s in asHtmlDocument.querySelectorAll('script')) { - s.remove(); - } - for (var pre in asHtmlDocument.querySelectorAll('pre')) { + var asHtmlFragment = parseFragment(rawHtml); + + for (var pre in asHtmlFragment.querySelectorAll('pre')) { if (pre.children.length > 1 && pre.children.first.localName != 'code') { continue; } @@ -44,16 +47,21 @@ class DocumentationRendererHtml implements DocumentationRenderer { // Assume the user intended Dart if there are no other classes present. if (!specifiesLanguage) pre.classes.add('language-dart'); } + + if (sanitizeHtml) { + _sanitize(asHtmlFragment); + } + var asHtml = ''; if (processFullDocs) { // `trim` fixes an issue with line ending differences between Mac and // Windows. - asHtml = asHtmlDocument.body.innerHtml?.trim(); + asHtml = asHtmlFragment.outerHtml.trim(); } - var asOneLiner = asHtmlDocument.body.children.isEmpty + var asOneLiner = asHtmlFragment.children.isEmpty ? '' - : asHtmlDocument.body.children.first.innerHtml; + : asHtmlFragment.children.first.innerHtml; return DocumentationRenderResult(asHtml: asHtml, asOneLiner: asOneLiner); } @@ -68,3 +76,256 @@ class DocumentationRenderResult { const DocumentationRenderResult( {@required this.asHtml, @required this.asOneLiner}); } + +bool _allowClassName(String className) => + className == 'deprecated' || className.startsWith('language-'); + +Iterable _addLinkRel(String uri) { + final u = Uri.tryParse(uri); + if (u == null || !['http', 'https', 'mailto'].contains(u.scheme)) { + return ['nofollow']; + } + if (u.host.isNotEmpty) { + // TODO(jonasfj): Consider allowing non-ugc links for trusted sites. + return ['ugc']; + } + return []; +} + +void _sanitize(dom.Node node) { + if (node is dom.Element) { + final tagName = node.localName.toUpperCase(); + if (!_allowedElements.contains(tagName)) { + node.remove(); + return; + } + node.attributes.removeWhere((k, v) { + final attrName = k.toString(); + if (attrName == 'class') { + node.classes.removeWhere((cn) => !_allowClassName(cn)); + return node.classes.isEmpty; + } + return !_isAttributeAllowed(tagName, attrName, v); + }); + if (tagName == 'A') { + final href = node.attributes['href']; + if (href != null) { + final rels = _addLinkRel(href); + if (rels != null && rels.isNotEmpty) { + node.attributes['rel'] = rels.join(' '); + } + } + } + } + if (node.hasChildNodes()) { + // doing it in reverse order, because we could otherwise skip one, when a + // node is removed... + for (var i = node.nodes.length - 1; i >= 0; i--) { + _sanitize(node.nodes[i]); + } + } +} + +bool _isAttributeAllowed(String tagName, String attrName, String value) { + if (_alwaysAllowedAttributes.contains(attrName)) return true; + + // Special validators for special attributes on special tags (href/src/cite) + final attributeValidators = _elementAttributeValidators[tagName]; + if (attributeValidators == null) { + return false; + } + + final validator = attributeValidators[attrName]; + if (validator == null) { + return false; + } + + return validator(value); +} + +// Inspired by the set of HTML tags allowed in GFM. +final _allowedElements = { + 'H1', + 'H2', + 'H3', + 'H4', + 'H5', + 'H6', + 'H7', + 'H8', + 'BR', + 'B', + 'I', + 'STRONG', + 'EM', + 'A', + 'PRE', + 'CODE', + 'IMG', + 'TT', + 'DIV', + 'INS', + 'DEL', + 'SUP', + 'SUB', + 'P', + 'OL', + 'UL', + 'TABLE', + 'THEAD', + 'TBODY', + 'TFOOT', + 'BLOCKQUOTE', + 'DL', + 'DT', + 'DD', + 'KBD', + 'Q', + 'SAMP', + 'VAR', + 'HR', + 'RUBY', + 'RT', + 'RP', + 'LI', + 'TR', + 'TD', + 'TH', + 'S', + 'STRIKE', + 'SUMMARY', + 'DETAILS', + 'CAPTION', + 'FIGURE', + 'FIGCAPTION', + 'ABBR', + 'BDO', + 'CITE', + 'DFN', + 'MARK', + 'SMALL', + 'SPAN', + 'TIME', + 'WBR', +}; + +// Inspired by the set of HTML attributes allowed in GFM. +final _alwaysAllowedAttributes = { + 'abbr', + 'accept', + 'accept-charset', + 'accesskey', + 'action', + 'align', + 'alt', + 'aria-describedby', + 'aria-hidden', + 'aria-label', + 'aria-labelledby', + 'axis', + 'border', + 'cellpadding', + 'cellspacing', + 'char', + 'charoff', + 'charset', + 'checked', + 'clear', + 'cols', + 'colspan', + 'color', + 'compact', + 'coords', + 'datetime', + 'dir', + 'disabled', + 'enctype', + 'for', + 'frame', + 'headers', + 'height', + 'hreflang', + 'hspace', + 'ismap', + 'label', + 'lang', + 'maxlength', + 'media', + 'method', + 'multiple', + 'name', + 'nohref', + 'noshade', + 'nowrap', + 'open', + 'prompt', + 'readonly', + 'rel', + 'rev', + 'rows', + 'rowspan', + 'rules', + 'scope', + 'selected', + 'shape', + 'size', + 'span', + 'start', + 'summary', + 'tabindex', + 'target', + 'title', + 'type', + 'usemap', + 'valign', + 'value', + 'vspace', + 'width', + 'itemprop', +}; + +bool _alwaysAllowed(String _) => true; + +bool _validLink(String url) { + try { + final uri = Uri.parse(url); + return uri.isScheme('https') || + uri.isScheme('http') || + uri.isScheme('mailto') || + !uri.hasScheme; + } on FormatException { + return false; + } +} + +bool _validUrl(String url) { + try { + final uri = Uri.parse(url); + return uri.isScheme('https') || uri.isScheme('http') || !uri.hasScheme; + } on FormatException { + return false; + } +} + +final _citeAttributeValidator = { + 'cite': _validUrl, +}; + +final _elementAttributeValidators = + >{ + 'A': { + 'href': _validLink, + }, + 'IMG': { + 'src': _validUrl, + 'longdesc': _validUrl, + }, + 'DIV': { + 'itemscope': _alwaysAllowed, + 'itemtype': _alwaysAllowed, + }, + 'BLOCKQUOTE': _citeAttributeValidator, + 'DEL': _citeAttributeValidator, + 'INS': _citeAttributeValidator, + 'Q': _citeAttributeValidator, +}; diff --git a/test/end2end/model_special_cases_test.dart b/test/end2end/model_special_cases_test.dart index 244c1268f7..1b12ae75a8 100644 --- a/test/end2end/model_special_cases_test.dart +++ b/test/end2end/model_special_cases_test.dart @@ -289,7 +289,7 @@ void main() { pubPackageMetaProvider, PhysicalPackageConfigProvider(), excludeLibraries: ['css', 'code_in_comments', 'excluded'], - additionalArguments: ['--inject-html']); + additionalArguments: ['--inject-html', '--no-sanitize-html']); injectionExLibrary = injectionPackageGraph.libraries.firstWhere((lib) => lib.name == 'ex'); From 7e9b6097f63fafdb7fcf3ebb013789e9a88a4bfd Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Wed, 13 Oct 2021 15:26:29 +0200 Subject: [PATCH 2/7] Making sanitizing hidden and off by deafult --- CHANGELOG.md | 5 ++--- lib/src/dartdoc_options.dart | 4 ++-- lib/src/render/documentation_renderer.dart | 8 +++++--- test/end2end/model_special_cases_test.dart | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c60eb63da..7eb72cc29b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,6 @@ ## 4.1.0-dev -* BREAKING CHANGE: HTML output from markdown rendering, `{@tool}` and - `{@inject-html}` is sanitized by default. HTML sanitization can be disabled - with `--no-sanitize-html`. +* Experimental feature: HTML output from markdown rendering, `{@tool}` and + `{@inject-html}` is sanitized when hidden option `--sanitize-html` is passed. ## 4.0.0 * BREAKING CHANGE: Refactors to support NNBD and adapt to new analyzer diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index 02ee96c9e5..0c6760fd6b 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -1462,8 +1462,8 @@ Future> createDartdocOptions( DartdocOptionArgOnly('injectHtml', false, resourceProvider, help: 'Allow the use of the {@inject-html} directive to inject raw ' 'HTML into dartdoc output.'), - DartdocOptionArgOnly('sanitizeHtml', true, resourceProvider, - negatable: true, + DartdocOptionArgOnly('sanitizeHtml', false, resourceProvider, + hide: true, help: 'Sanitize HTML generated from markdown, {@tool} and ' '{@inject-html} directives.'), DartdocOptionArgOnly( diff --git a/lib/src/render/documentation_renderer.dart b/lib/src/render/documentation_renderer.dart index a6a0c68b44..1b78c9771d 100644 --- a/lib/src/render/documentation_renderer.dart +++ b/lib/src/render/documentation_renderer.dart @@ -50,6 +50,11 @@ class DocumentationRendererHtml implements DocumentationRenderer { if (sanitizeHtml) { _sanitize(asHtmlFragment); + } else { + // Never allow scripts! + for (var s in asHtmlFragment.querySelectorAll('script')) { + s.remove(); + } } var asHtml = ''; @@ -82,9 +87,6 @@ bool _allowClassName(String className) => Iterable _addLinkRel(String uri) { final u = Uri.tryParse(uri); - if (u == null || !['http', 'https', 'mailto'].contains(u.scheme)) { - return ['nofollow']; - } if (u.host.isNotEmpty) { // TODO(jonasfj): Consider allowing non-ugc links for trusted sites. return ['ugc']; diff --git a/test/end2end/model_special_cases_test.dart b/test/end2end/model_special_cases_test.dart index 1b12ae75a8..244c1268f7 100644 --- a/test/end2end/model_special_cases_test.dart +++ b/test/end2end/model_special_cases_test.dart @@ -289,7 +289,7 @@ void main() { pubPackageMetaProvider, PhysicalPackageConfigProvider(), excludeLibraries: ['css', 'code_in_comments', 'excluded'], - additionalArguments: ['--inject-html', '--no-sanitize-html']); + additionalArguments: ['--inject-html']); injectionExLibrary = injectionPackageGraph.libraries.firstWhere((lib) => lib.name == 'ex'); From 5bf75492693364a62b42f934033101dc595b4e4d Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Wed, 13 Oct 2021 15:41:59 +0200 Subject: [PATCH 3/7] dart run ginder build --- dartdoc_options.yaml | 2 +- lib/src/generator/templates.runtime_renderers.dart | 1 + lib/src/version.dart | 2 +- pubspec.yaml | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dartdoc_options.yaml b/dartdoc_options.yaml index 71e9748c24..3102516a30 100644 --- a/dartdoc_options.yaml +++ b/dartdoc_options.yaml @@ -1,4 +1,4 @@ dartdoc: linkToSource: root: '.' - uriTemplate: 'https://github.com/dart-lang/dartdoc/blob/v4.0.0/%f%#L%l%' + uriTemplate: 'https://github.com/dart-lang/dartdoc/blob/v4.1.0-dev/%f%#L%l%' diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 0aaf845c2d..4f6d336ad6 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -15260,6 +15260,7 @@ const _invisibleGetters = { 'includeExternal', 'includeSource', 'injectHtml', + 'sanitizeHtml', 'excludeFooterVersion', 'tools', 'inputDir', diff --git a/lib/src/version.dart b/lib/src/version.dart index 66803eca53..e1b28724bd 100644 --- a/lib/src/version.dart +++ b/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '4.0.0'; +const packageVersion = '4.1.0-dev'; diff --git a/pubspec.yaml b/pubspec.yaml index 7603d6f8c0..ac7724910e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: dartdoc -# Run `grind build` after updating. -version: 4.0.0 +# Run `dart run grinder build` after updating. +version: 4.1.0-dev description: A non-interactive HTML documentation generator for Dart source code. homepage: https://github.com/dart-lang/dartdoc environment: From e014a45708a2333eb89cce55f01dd98009cd409b Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Wed, 13 Oct 2021 16:31:16 +0200 Subject: [PATCH 4/7] Tests of HTML sanitizing --- test/end2end/model_special_cases_test.dart | 49 ++++++++++++++++++++++ testing/test_package/lib/example.dart | 21 ++++++++++ 2 files changed, 70 insertions(+) diff --git a/test/end2end/model_special_cases_test.dart b/test/end2end/model_special_cases_test.dart index 244c1268f7..84bfeb32a0 100644 --- a/test/end2end/model_special_cases_test.dart +++ b/test/end2end/model_special_cases_test.dart @@ -275,6 +275,55 @@ void main() { }, skip: !_constructorTearoffsAllowed.allows(utils.platformVersion)); }); + group('HTML is sanitized when enabled', () { + Class classWithHtml; + Method blockHtml; + Method inlineHtml; + + PackageGraph packageGraph; + Library exLibrary; + + setUpAll(() async { + packageGraph = await utils.bootBasicPackage('testing/test_package', + pubPackageMetaProvider, PhysicalPackageConfigProvider(), + excludeLibraries: ['css', 'code_in_comments', 'excluded'], + additionalArguments: ['--sanitize-html']); + + exLibrary = packageGraph.libraries.firstWhere((lib) => lib.name == 'ex'); + + classWithHtml = + exLibrary.classes.firstWhere((c) => c.name == 'SanitizableHtml'); + blockHtml = classWithHtml.instanceMethods + .firstWhere((m) => m.name == 'blockHtml'); + inlineHtml = classWithHtml.instanceMethods + .firstWhere((m) => m.name == 'inlineHtml'); + for (var modelElement in packageGraph.allLocalModelElements) { + modelElement.documentation; + } + }); + + test('can have inline HTML', () { + expect(inlineHtml.documentationAsHtml, contains('')); + }); + + test('can have block HTML', () { + expect(blockHtml.documentationAsHtml, contains('

')); + }); + + test('will add rel=ugc for outgoing links', () { + expect(inlineHtml.documentationAsHtml, + contains('')); + }); + + test('removes bad inline HTML', () { + expect(inlineHtml.documentationAsHtml, isNot(contains('bad-idea'))); + }); + + test('removes bad block HTML', () { + expect(blockHtml.documentationAsHtml, isNot(contains('bad-idea'))); + }); + }); + group('HTML Injection when allowed', () { Class htmlInjection; Method injectSimpleHtml; diff --git a/testing/test_package/lib/example.dart b/testing/test_package/lib/example.dart index 7d6a25afcd..687612be2d 100644 --- a/testing/test_package/lib/example.dart +++ b/testing/test_package/lib/example.dart @@ -606,6 +606,27 @@ abstract class HtmlInjection { void injectHtmlFromTool(); } +abstract class SanitizableHtml { + /// Has both good and bad block HTML + /// + ///

A fine headline

+ /// + /// + void blockHtml(); + + /// Has both good and bad inline HTML + /// + /// Writing little text is fine. + /// + /// Having links is okay
link, but they + /// should have ugc. + /// + /// This is a bad link. + void inlineHtml(); +} + /// Just a class with a synthetic constructor. class WithSyntheticConstructor {} From 73ac1d4c7582312202bdc9eae8f92427b0c5c116 Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Thu, 14 Oct 2021 12:40:52 +0200 Subject: [PATCH 5/7] Fix number of classes --- test/end2end/model_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart index 4e9cac2468..7a88c7e0e1 100644 --- a/test/end2end/model_test.dart +++ b/test/end2end/model_test.dart @@ -2045,7 +2045,7 @@ void main() { }); test('correctly finds all the classes', () { - expect(classes, hasLength(39)); + expect(classes, hasLength(40)); }); test('abstract', () { From 2c29efaa82afaace070e74b823ea4b2294f9195a Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Thu, 14 Oct 2021 16:04:13 +0200 Subject: [PATCH 6/7] Moved html sanitizer tests --- test/end2end/model_special_cases_test.dart | 11 ++++++---- test/end2end/model_test.dart | 2 +- testing/test_package/lib/example.dart | 21 ------------------ testing/test_package_sanitize_html/README.md | 2 ++ .../lib/test_package_sanitize_html.dart | 22 +++++++++++++++++++ .../test_package_sanitize_html/pubspec.yaml | 6 +++++ 6 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 testing/test_package_sanitize_html/README.md create mode 100644 testing/test_package_sanitize_html/lib/test_package_sanitize_html.dart create mode 100644 testing/test_package_sanitize_html/pubspec.yaml diff --git a/test/end2end/model_special_cases_test.dart b/test/end2end/model_special_cases_test.dart index 84bfeb32a0..766e8a171b 100644 --- a/test/end2end/model_special_cases_test.dart +++ b/test/end2end/model_special_cases_test.dart @@ -284,10 +284,13 @@ void main() { Library exLibrary; setUpAll(() async { - packageGraph = await utils.bootBasicPackage('testing/test_package', - pubPackageMetaProvider, PhysicalPackageConfigProvider(), - excludeLibraries: ['css', 'code_in_comments', 'excluded'], - additionalArguments: ['--sanitize-html']); + packageGraph = await utils.bootBasicPackage( + 'testing/test_package_sanitize_html', + pubPackageMetaProvider, + PhysicalPackageConfigProvider(), + excludeLibraries: ['css', 'code_in_comments', 'excluded'], + additionalArguments: ['--sanitize-html'], + ); exLibrary = packageGraph.libraries.firstWhere((lib) => lib.name == 'ex'); diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart index 7a88c7e0e1..4e9cac2468 100644 --- a/test/end2end/model_test.dart +++ b/test/end2end/model_test.dart @@ -2045,7 +2045,7 @@ void main() { }); test('correctly finds all the classes', () { - expect(classes, hasLength(40)); + expect(classes, hasLength(39)); }); test('abstract', () { diff --git a/testing/test_package/lib/example.dart b/testing/test_package/lib/example.dart index 687612be2d..7d6a25afcd 100644 --- a/testing/test_package/lib/example.dart +++ b/testing/test_package/lib/example.dart @@ -606,27 +606,6 @@ abstract class HtmlInjection { void injectHtmlFromTool(); } -abstract class SanitizableHtml { - /// Has both good and bad block HTML - /// - ///

A fine headline

- /// - /// - void blockHtml(); - - /// Has both good and bad inline HTML - /// - /// Writing little text is fine. - /// - /// Having links is okay link, but they - /// should have ugc. - /// - /// This is a bad link. - void inlineHtml(); -} - /// Just a class with a synthetic constructor. class WithSyntheticConstructor {} diff --git a/testing/test_package_sanitize_html/README.md b/testing/test_package_sanitize_html/README.md new file mode 100644 index 0000000000..779f52f04a --- /dev/null +++ b/testing/test_package_sanitize_html/README.md @@ -0,0 +1,2 @@ +# Test Package for HTML sanitizing + diff --git a/testing/test_package_sanitize_html/lib/test_package_sanitize_html.dart b/testing/test_package_sanitize_html/lib/test_package_sanitize_html.dart new file mode 100644 index 0000000000..1a082ec05c --- /dev/null +++ b/testing/test_package_sanitize_html/lib/test_package_sanitize_html.dart @@ -0,0 +1,22 @@ +library ex; + +abstract class SanitizableHtml { + /// Has both good and bad block HTML + /// + ///

A fine headline

+ /// + /// + void blockHtml(); + + /// Has both good and bad inline HTML + /// + /// Writing little text is fine. + /// + /// Having links is okay link, but they + /// should have ugc. + /// + /// This is a bad link. + void inlineHtml(); +} diff --git a/testing/test_package_sanitize_html/pubspec.yaml b/testing/test_package_sanitize_html/pubspec.yaml new file mode 100644 index 0000000000..fc99c6cfe8 --- /dev/null +++ b/testing/test_package_sanitize_html/pubspec.yaml @@ -0,0 +1,6 @@ +name: test_package +homepage: http://github.com/dart-lang +description: Worst package ever. +version: 0.0.1 +environment: + sdk: '>=2.14.0-0 <3.0.0' From 2ff87028ed0c0bc80b93271b9f8f2855be4b3348 Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Fri, 15 Oct 2021 11:49:48 +0200 Subject: [PATCH 7/7] Removed the script removing hack --- lib/src/render/documentation_renderer.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/src/render/documentation_renderer.dart b/lib/src/render/documentation_renderer.dart index 1b78c9771d..6d80625b20 100644 --- a/lib/src/render/documentation_renderer.dart +++ b/lib/src/render/documentation_renderer.dart @@ -50,11 +50,6 @@ class DocumentationRendererHtml implements DocumentationRenderer { if (sanitizeHtml) { _sanitize(asHtmlFragment); - } else { - // Never allow scripts! - for (var s in asHtmlFragment.querySelectorAll('script')) { - s.remove(); - } } var asHtml = '';