diff --git a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBrowser.kt b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBrowser.kt index faac04dc..c3acbf11 100644 --- a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBrowser.kt +++ b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageBrowser.kt @@ -140,7 +140,12 @@ class PackageBrowser: V8Package { val charset = charsetFromContentType(contentType) ?: Charsets.UTF_8 val html = bodyBytes.toString(charset) - val injected = injectIntoHead(html, scripts.joinToString("\n")) + val cspHeader = resp.header("Content-Security-Policy") + ?: resp.header("Content-Security-Policy-Report-Only") + + val nonce = extractNonceFromCsp(cspHeader) ?: extractNonceFromHtml(html) + + val injected = injectIntoHead(html, scripts.joinToString("\n"), nonce) val outBytes = injected.toByteArray(charset) val headers = resp.headers.toMultimap() .mapValues { it.value.joinToString(",") } @@ -300,7 +305,7 @@ class PackageBrowser: V8Package { private fun releaseReadyIfCurrent(url: String?) { if (url == null) return val expected = _expectedMainUrl - if (url.toUri().host != expected?.toUri()?.host) return + if (url.trimEnd('/') != expected?.trimEnd('/')) return _readySemaphore?.release() _readySemaphore = null @@ -442,8 +447,9 @@ class PackageBrowser: V8Package { return runCatching { Charset.forName(name) }.getOrNull() } - private fun injectIntoHead(html: String, js: String): String { - val tag = "\n" + private fun injectIntoHead(html: String, js: String, nonce: String?): String { + val nonceAttr = nonce?.let { " nonce=\"${escapeHtmlAttr(it)}\"" } ?: "" + val tag = "\n" val head = Regex("(?i)
]*>").find(html) if (head != null) { @@ -455,7 +461,6 @@ class PackageBrowser: V8Package { append(html, i, html.length) } } - return tag + html } @@ -467,6 +472,20 @@ class PackageBrowser: V8Package { } } + private fun extractNonceFromCsp(csp: String?): String? { + if (csp.isNullOrBlank()) return null + val m = Regex("(?i)'nonce-([^'\\s;]+)'").find(csp) ?: return null + return m.groupValues[1] + } + + private fun extractNonceFromHtml(html: String): String? { + val m = Regex("(?i)