diff options
author | Ignat Beresnev <ignat.beresnev@jetbrains.com> | 2023-07-07 14:21:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-07 14:21:15 +0200 |
commit | 14cd0f3e42e13927f9852d2cb74cc0098c1a429c (patch) | |
tree | 7da6ca0fbae833ab58d5d9ee2f353fa96eb0fe27 | |
parent | f23a4a9e72b372e94f28fa95d3ca595e9945857a (diff) | |
download | dokka-14cd0f3e42e13927f9852d2cb74cc0098c1a429c.tar.gz dokka-14cd0f3e42e13927f9852d2cb74cc0098c1a429c.tar.bz2 dokka-14cd0f3e42e13927f9852d2cb74cc0098c1a429c.zip |
Do not leak unknown asset paths into HTML (#3061)
Fixes #3040
3 files changed, 95 insertions, 36 deletions
diff --git a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt index 4fee280e..aae2f65d 100644 --- a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt +++ b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt @@ -92,7 +92,7 @@ class DefaultTemplateModelFactory(val context: DokkaContext) : TemplateModelFact private fun Appendable.resourcesForPage(pathToRoot: String, resources: List<String>): Unit = resources.forEach { - append(with(createHTML()) { + val resourceHtml = with(createHTML()) { when { it.URIExtension == "css" -> link( @@ -112,7 +112,11 @@ class DefaultTemplateModelFactory(val context: DokkaContext) : TemplateModelFact it.isImage() -> link(href = if (it.isAbsolute) it else "$pathToRoot$it") else -> null } - } ?: it) + } + + if (resourceHtml != null) { + append(resourceHtml) + } } } diff --git a/plugins/base/src/test/kotlin/resourceLinks/ResourceLinksTest.kt b/plugins/base/src/test/kotlin/resourceLinks/ResourceLinksTest.kt index a751f071..0bbd35d1 100644 --- a/plugins/base/src/test/kotlin/resourceLinks/ResourceLinksTest.kt +++ b/plugins/base/src/test/kotlin/resourceLinks/ResourceLinksTest.kt @@ -13,13 +13,16 @@ import org.jetbrains.dokka.plugability.DokkaPluginApiPreview import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement import org.jetbrains.dokka.transformers.pages.PageTransformer import org.jsoup.Jsoup +import org.jsoup.nodes.TextNode import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import utils.TestOutputWriterPlugin +import utils.assertContains import java.io.File import kotlin.test.assertNotNull import kotlin.test.assertNull +import kotlin.test.assertTrue class ResourceLinksTest : BaseAbstractTest() { class TestResourcesAppenderPlugin(val resources: List<String>) : DokkaPlugin() { @@ -205,4 +208,90 @@ class ResourceLinksTest : BaseAbstractTest() { } } } + + @Test // see #3040; plain text added to <head> can be rendered by engines inside <body> as well + fun `should not add unknown resources as text to the head or body section`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + + pluginsConfigurations = mutableListOf( + PluginConfigurationImpl( + DokkaBase::class.java.canonicalName, + DokkaConfiguration.SerializationFormat.JSON, + toJsonString( + DokkaBaseConfiguration( + customAssets = listOf(File("test/unknown-file.ext")) + ) + ) + ) + ) + } + + val writerPlugin = TestOutputWriterPlugin() + testInline( + """ + |/src/main/kotlin/test/Test.kt + |package test + | + |class Test + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val testClassPage = writerPlugin.writer.contents + .getValue("root/test/-test/-test.html") + .let { Jsoup.parse(it) } + + val headChildNodes = testClassPage.head().childNodes() + assertTrue("<head> section should not contain non-blank text nodes") { + headChildNodes.all { it !is TextNode || it.isBlank } + } + + val bodyChildNodes = testClassPage.body().childNodes() + assertTrue("<body> section should not contain non-blank text nodes. Something leaked from head?") { + bodyChildNodes.all { it !is TextNode || it.isBlank } + } + } + } + } + + @Test + fun `should load script as defer if name ending in _deferred`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + val writerPlugin = TestOutputWriterPlugin() + testInline( + """ + |/src/main/kotlin/test/Test.kt + |package test + | + |class Test + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val generatedFiles = writerPlugin.writer.contents + + assertContains(generatedFiles.keys, "scripts/symbol-parameters-wrapper_deferred.js") + + val scripts = generatedFiles.getValue("root/test/-test/-test.html").let { Jsoup.parse(it) }.select("script") + val deferredScriptSources = scripts.filter { element -> element.hasAttr("defer") }.map { it.attr("src") } + + // important to check symbol-parameters-wrapper_deferred specifically since it might break some features + assertContains(deferredScriptSources, "../../../scripts/symbol-parameters-wrapper_deferred.js") + } + } + } } diff --git a/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt b/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt index 30fc127f..b2b590d3 100644 --- a/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt +++ b/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt @@ -177,40 +177,6 @@ class PageTransformerBuilderTest : BaseAbstractTest() { } } - @Test - fun `should load script as defer if name ending in _deferred`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/main/kotlin") - } - } - } - val writerPlugin = TestOutputWriterPlugin() - testInline( - """ - |/src/main/kotlin/test/Test.kt - |package test - | - |class Test - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - renderingStage = { _, _ -> - val generatedFiles = writerPlugin.writer.contents - - assertContains(generatedFiles.keys, "scripts/symbol-parameters-wrapper_deferred.js") - - val scripts = generatedFiles.getValue("root/test/-test/-test.html").let { Jsoup.parse(it) }.select("script") - val deferredScriptSources = scripts.filter { element -> element.hasAttr("defer") }.map { it.attr("src") } - - // important to check symbol-parameters-wrapper_deferred specifically since it might break some features - assertContains(deferredScriptSources, "../../../scripts/symbol-parameters-wrapper_deferred.js") - } - } - } - private fun <T> Collection<T>.assertCount(n: Int, prefix: String = "") = assert(count() == n) { "${prefix}Expected $n, got ${count()}" } |