mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	Spoof or remove X-Requested-With header from webview (#1812)
				
					
				
			This commit is contained in:
		| @@ -3,6 +3,7 @@ package eu.kanade.presentation.webview | ||||
| import android.content.pm.ApplicationInfo | ||||
| import android.graphics.Bitmap | ||||
| import android.webkit.WebResourceRequest | ||||
| import android.webkit.WebResourceResponse | ||||
| import android.webkit.WebView | ||||
| import androidx.compose.foundation.clickable | ||||
| import androidx.compose.foundation.layout.Box | ||||
| @@ -26,6 +27,7 @@ import androidx.compose.runtime.setValue | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.draw.clip | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import androidx.compose.ui.platform.LocalUriHandler | ||||
| import androidx.compose.ui.unit.dp | ||||
| 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.WarningBanner | ||||
| 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.setDefaultSettings | ||||
| import kotlinx.collections.immutable.persistentListOf | ||||
| import kotlinx.coroutines.launch | ||||
| import okhttp3.Request | ||||
| import tachiyomi.i18n.MR | ||||
| import tachiyomi.presentation.core.components.material.Scaffold | ||||
| import tachiyomi.presentation.core.i18n.stringResource | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
|  | ||||
| @Composable | ||||
| fun WebViewScreenContent( | ||||
| @@ -58,8 +65,11 @@ fun WebViewScreenContent( | ||||
| ) { | ||||
|     val state = rememberWebViewState(url = url, additionalHttpHeaders = headers) | ||||
|     val navigator = rememberWebViewNavigator() | ||||
|     val context = LocalContext.current | ||||
|     val uriHandler = LocalUriHandler.current | ||||
|     val scope = rememberCoroutineScope() | ||||
|     val network = remember { Injekt.get<NetworkHelper>() } | ||||
|     val spoofedPackageName = remember { WebViewUtil.spoofedPackageName(context) } | ||||
|  | ||||
|     var currentUrl by remember { mutableStateOf(url) } | ||||
|     var showCloudflareHelp by remember { mutableStateOf(false) } | ||||
| @@ -114,6 +124,40 @@ fun WebViewScreenContent( | ||||
|                 } | ||||
|                 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) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -219,17 +219,15 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor | ||||
|         try { | ||||
|             // Override the value passed as X-Requested-With in WebView requests | ||||
|             val stackTrace = Looper.getMainLooper().thread.stackTrace | ||||
|             val chromiumElement = stackTrace.find { | ||||
|                 it.className.equals( | ||||
|                     "org.chromium.base.BuildInfo", | ||||
|                     ignoreCase = true, | ||||
|                 ) | ||||
|             } | ||||
|             if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { | ||||
|                 return WebViewUtil.SPOOF_PACKAGE_NAME | ||||
|             val isChromiumCall = stackTrace.any { | ||||
|                 it.className.startsWith("org.chromium.") && | ||||
|                     it.methodName in setOf("getAll", "getPackageName", "<init>") | ||||
|             } | ||||
|  | ||||
|             if (isChromiumCall) return WebViewUtil.spoofedPackageName(applicationContext) | ||||
|         } catch (_: Exception) { | ||||
|         } | ||||
|  | ||||
|         return super.getPackageName() | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user