security: Bridge代理fetch+移除跨域设置+CSP头限制
CRITICAL修复: - 移除allowFileAccessFromFileURLs/allowUniversalAccessFromFileURLs - 移除mixedContentMode=ALWAYS_ALLOW - WebViewClient注入CSP: default-src 'none';script-src 'unsafe-inline';connect-src 'none' - 新增Bridge.fetchManifest(channel)/Bridge.fetchText(path)原生HTTP代理 - manifest JSON + version.txt通过Bridge读取,无需WebView跨域
This commit is contained in:
Binary file not shown.
@@ -3,8 +3,11 @@ package dev.yuzu.gca
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import java.io.File
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
@@ -20,10 +23,17 @@ class MainActivity : AppCompatActivity() {
|
||||
settings.javaScriptEnabled = true
|
||||
settings.domStorageEnabled = true
|
||||
settings.allowFileAccess = true
|
||||
settings.allowFileAccessFromFileURLs = true
|
||||
settings.allowUniversalAccessFromFileURLs = true
|
||||
settings.mixedContentMode = android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
||||
addJavascriptInterface(Bridge(this@MainActivity), "Android")
|
||||
webViewClient = object : WebViewClient() {
|
||||
override fun onPageFinished(view: WebView, url: String) {
|
||||
view.evaluateJavascript("""
|
||||
var meta = document.createElement('meta');
|
||||
meta.httpEquiv = 'Content-Security-Policy';
|
||||
meta.content = "default-src 'none'; script-src 'unsafe-inline'; connect-src 'none'";
|
||||
document.head.appendChild(meta);
|
||||
""".trimIndent(), null)
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheFile.exists()) {
|
||||
val html = cacheFile.readText()
|
||||
@@ -47,17 +57,57 @@ class MainActivity : AppCompatActivity() {
|
||||
ctx.cacheFile.writeText(html)
|
||||
Log.i(TAG, "Hot-update HTML saved (${html.length}B)")
|
||||
}
|
||||
|
||||
@android.webkit.JavascriptInterface
|
||||
fun clearCache() {
|
||||
ctx.cacheFile.delete()
|
||||
Log.i(TAG, "Cache cleared")
|
||||
}
|
||||
|
||||
@android.webkit.JavascriptInterface
|
||||
fun sha256(input: String): String {
|
||||
val md = java.security.MessageDigest.getInstance("SHA-256")
|
||||
val digest = md.digest(input.toByteArray(Charsets.UTF_8))
|
||||
return digest.joinToString("") { "%02x".format(it) }
|
||||
}
|
||||
|
||||
/** Fetch manifest JSON from Gitea — proxy to avoid CORS in WebView */
|
||||
@android.webkit.JavascriptInterface
|
||||
fun fetchManifest(channel: String): String {
|
||||
val url = "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/raw/branch/main/ota/h5/manifest-$channel.json"
|
||||
Log.i(TAG, "Bridge fetching $url")
|
||||
return try {
|
||||
val conn = URL(url).openConnection() as HttpURLConnection
|
||||
conn.connectTimeout = 10_000
|
||||
conn.readTimeout = 10_000
|
||||
conn.instanceFollowRedirects = true
|
||||
val code = conn.responseCode
|
||||
if (code != 200) throw Exception("HTTP $code")
|
||||
conn.inputStream.bufferedReader().readText()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Bridge fetch failed: ${e.message}")
|
||||
"""{"error":"${e.message}"}"""
|
||||
}
|
||||
}
|
||||
|
||||
/** Fetch text file from Gitea — proxy for version.txt etc */
|
||||
@android.webkit.JavascriptInterface
|
||||
fun fetchText(path: String): String {
|
||||
val url = "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/raw/branch/main/ota/$path"
|
||||
Log.i(TAG, "Bridge fetching $url")
|
||||
return try {
|
||||
val conn = URL(url).openConnection() as HttpURLConnection
|
||||
conn.connectTimeout = 10_000
|
||||
conn.readTimeout = 10_000
|
||||
conn.instanceFollowRedirects = true
|
||||
val code = conn.responseCode
|
||||
if (code != 200) throw Exception("HTTP $code")
|
||||
conn.inputStream.bufferedReader().readText()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Bridge fetchText($path) failed: ${e.message}")
|
||||
"ERROR: ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object { private const val TAG = "GCA-H5" }
|
||||
|
||||
Reference in New Issue
Block a user