Spoof or remove X-Requested-With
header from webview (#1812)
(cherry picked from commit 793d7fbe40c87ed233da8cc99d544d01024ed4f5) # Conflicts: # CHANGELOG.md # app/src/main/java/eu/kanade/tachiyomi/App.kt # core/common/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt
This commit is contained in:
parent
5346eac037
commit
dfde271f7f
@ -3,6 +3,7 @@ package eu.kanade.presentation.webview
|
|||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.webkit.WebResourceRequest
|
import android.webkit.WebResourceRequest
|
||||||
|
import android.webkit.WebResourceResponse
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@ -26,6 +27,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.kevinnzou.web.AccompanistWebViewClient
|
import com.kevinnzou.web.AccompanistWebViewClient
|
||||||
@ -37,13 +39,18 @@ import eu.kanade.presentation.components.AppBar
|
|||||||
import eu.kanade.presentation.components.AppBarActions
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
import eu.kanade.presentation.components.WarningBanner
|
import eu.kanade.presentation.components.WarningBanner
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
|
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||||
import eu.kanade.tachiyomi.util.system.getHtml
|
import eu.kanade.tachiyomi.util.system.getHtml
|
||||||
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.Request
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WebViewScreenContent(
|
fun WebViewScreenContent(
|
||||||
@ -58,8 +65,11 @@ fun WebViewScreenContent(
|
|||||||
) {
|
) {
|
||||||
val state = rememberWebViewState(url = url, additionalHttpHeaders = headers)
|
val state = rememberWebViewState(url = url, additionalHttpHeaders = headers)
|
||||||
val navigator = rememberWebViewNavigator()
|
val navigator = rememberWebViewNavigator()
|
||||||
|
val context = LocalContext.current
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
val network = remember { Injekt.get<NetworkHelper>() }
|
||||||
|
val spoofedPackageName = remember { WebViewUtil.spoofedPackageName(context) }
|
||||||
|
|
||||||
var currentUrl by remember { mutableStateOf(url) }
|
var currentUrl by remember { mutableStateOf(url) }
|
||||||
var showCloudflareHelp by remember { mutableStateOf(false) }
|
var showCloudflareHelp by remember { mutableStateOf(false) }
|
||||||
@ -114,6 +124,40 @@ fun WebViewScreenContent(
|
|||||||
}
|
}
|
||||||
return super.shouldOverrideUrlLoading(view, request)
|
return super.shouldOverrideUrlLoading(view, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun shouldInterceptRequest(
|
||||||
|
view: WebView?,
|
||||||
|
request: WebResourceRequest?,
|
||||||
|
): WebResourceResponse? {
|
||||||
|
return try {
|
||||||
|
val internalRequest = Request.Builder().apply {
|
||||||
|
url(request!!.url.toString())
|
||||||
|
request.requestHeaders.forEach { (key, value) ->
|
||||||
|
if (key == "X-Requested-With" && value in setOf(context.packageName, spoofedPackageName)) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
addHeader(key, value)
|
||||||
|
}
|
||||||
|
method(request.method, null)
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
val response = network.nonCloudflareClient.newCall(internalRequest).execute()
|
||||||
|
|
||||||
|
val contentType = response.body.contentType()?.let { "${it.type}/${it.subtype}" } ?: "text/html"
|
||||||
|
val contentEncoding = response.body.contentType()?.charset()?.name() ?: "utf-8"
|
||||||
|
|
||||||
|
WebResourceResponse(
|
||||||
|
contentType,
|
||||||
|
contentEncoding,
|
||||||
|
response.code,
|
||||||
|
response.message,
|
||||||
|
response.headers.associate { it.first to it.second },
|
||||||
|
response.body.byteStream(),
|
||||||
|
)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
super.shouldInterceptRequest(view, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,18 +277,16 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
try {
|
try {
|
||||||
// Override the value passed as X-Requested-With in WebView requests
|
// Override the value passed as X-Requested-With in WebView requests
|
||||||
val stackTrace = Looper.getMainLooper().thread.stackTrace
|
val stackTrace = Looper.getMainLooper().thread.stackTrace
|
||||||
val chromiumElement = stackTrace.find {
|
val isChromiumCall = stackTrace.any {
|
||||||
it.className.equals(
|
it.className.startsWith("org.chromium.") &&
|
||||||
"org.chromium.base.BuildInfo",
|
it.methodName in setOf("getAll", "getPackageName", "<init>")
|
||||||
ignoreCase = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) {
|
|
||||||
return WebViewUtil.SPOOF_PACKAGE_NAME
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isChromiumCall) return WebViewUtil.spoofedPackageName(applicationContext)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getPackageName()
|
return super.getPackageName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,7 @@ open /* SY <-- */ class NetworkHelper(
|
|||||||
/* SY --> */
|
/* SY --> */
|
||||||
open /* SY <-- */val cookieJar = AndroidCookieJar()
|
open /* SY <-- */val cookieJar = AndroidCookieJar()
|
||||||
|
|
||||||
/* SY --> */
|
private val clientBuilder: OkHttpClient.Builder = run {
|
||||||
open /* SY <-- */val client: OkHttpClient = run {
|
|
||||||
val builder = OkHttpClient.Builder()
|
val builder = OkHttpClient.Builder()
|
||||||
.cookieJar(cookieJar)
|
.cookieJar(cookieJar)
|
||||||
.connectTimeout(30, TimeUnit.SECONDS)
|
.connectTimeout(30, TimeUnit.SECONDS)
|
||||||
@ -49,10 +48,6 @@ open /* SY <-- */ class NetworkHelper(
|
|||||||
builder.addNetworkInterceptor(httpLoggingInterceptor)
|
builder.addNetworkInterceptor(httpLoggingInterceptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.addInterceptor(
|
|
||||||
CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider),
|
|
||||||
)
|
|
||||||
|
|
||||||
when (preferences.dohProvider().get()) {
|
when (preferences.dohProvider().get()) {
|
||||||
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
|
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
|
||||||
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
||||||
@ -66,11 +61,19 @@ open /* SY <-- */ class NetworkHelper(
|
|||||||
PREF_DOH_CONTROLD -> builder.dohControlD()
|
PREF_DOH_CONTROLD -> builder.dohControlD()
|
||||||
PREF_DOH_NJALLA -> builder.dohNajalla()
|
PREF_DOH_NJALLA -> builder.dohNajalla()
|
||||||
PREF_DOH_SHECAN -> builder.dohShecan()
|
PREF_DOH_SHECAN -> builder.dohShecan()
|
||||||
|
else -> builder
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val nonCloudflareClient = clientBuilder.build()
|
||||||
|
|
||||||
|
/* SY --> */
|
||||||
|
open /* SY <-- */ val client = clientBuilder
|
||||||
|
.addInterceptor(
|
||||||
|
CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider),
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Since extension-lib 1.5
|
* @deprecated Since extension-lib 1.5
|
||||||
*/
|
*/
|
||||||
|
@ -13,7 +13,8 @@ import tachiyomi.core.common.util.system.logcat
|
|||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
|
||||||
object WebViewUtil {
|
object WebViewUtil {
|
||||||
const val SPOOF_PACKAGE_NAME = "org.chromium.chrome"
|
private const val CHROME_PACKAGE = "com.android.chrome"
|
||||||
|
private const val SYSTEM_SETTINGS_PACKAGE = "com.android.settings"
|
||||||
|
|
||||||
const val MINIMUM_WEBVIEW_VERSION = 118
|
const val MINIMUM_WEBVIEW_VERSION = 118
|
||||||
|
|
||||||
@ -58,6 +59,16 @@ object WebViewUtil {
|
|||||||
|
|
||||||
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)
|
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun spoofedPackageName(context: Context): String {
|
||||||
|
return try {
|
||||||
|
context.packageManager.getPackageInfo(CHROME_PACKAGE, PackageManager.GET_META_DATA)
|
||||||
|
|
||||||
|
CHROME_PACKAGE
|
||||||
|
} catch (_: PackageManager.NameNotFoundException) {
|
||||||
|
SYSTEM_SETTINGS_PACKAGE
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun WebView.isOutdated(): Boolean {
|
fun WebView.isOutdated(): Boolean {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user