mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-09 20:15:05 +01:00
Updates to cloudflare / useragent from upstream
Co-Authored-By: arkon <4098258+arkon@users.noreply.github.com>
This commit is contained in:
parent
9e3aaab95f
commit
331d2fcd9e
@ -10,7 +10,10 @@ import android.widget.Toast
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
||||||
|
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||||
import eu.kanade.tachiyomi.util.system.isOutdated
|
import eu.kanade.tachiyomi.util.system.isOutdated
|
||||||
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
|
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
@ -39,9 +42,17 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val originalRequest = chain.request()
|
||||||
|
|
||||||
|
if (!WebViewUtil.supportsWebView(context)) {
|
||||||
|
launchUI {
|
||||||
|
context.toast(R.string.webview_is_required, Toast.LENGTH_LONG)
|
||||||
|
}
|
||||||
|
return chain.proceed(originalRequest)
|
||||||
|
}
|
||||||
|
|
||||||
initWebView
|
initWebView
|
||||||
|
|
||||||
val originalRequest = chain.request()
|
|
||||||
val response = chain.proceed(originalRequest)
|
val response = chain.proceed(originalRequest)
|
||||||
|
|
||||||
// Check if Cloudflare anti-bot is on
|
// Check if Cloudflare anti-bot is on
|
||||||
@ -77,16 +88,17 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
var isWebViewOutdated = false
|
var isWebViewOutdated = false
|
||||||
|
|
||||||
val origRequestUrl = request.url.toString()
|
val origRequestUrl = request.url.toString()
|
||||||
val headers = request.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }
|
val headers = request.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
|
||||||
|
headers["X-Requested-With"] = WebViewUtil.REQUESTED_WITH
|
||||||
|
|
||||||
handler.post {
|
handler.post {
|
||||||
val webview = WebView(context)
|
val webview = WebView(context)
|
||||||
webView = webview
|
webView = webview
|
||||||
webview.settings.javaScriptEnabled = true
|
webview.setDefaultSettings()
|
||||||
|
|
||||||
// Avoid set empty User-Agent, Chromium WebView will reset to default if empty
|
// Avoid sending empty User-Agent, Chromium WebView will reset to default if empty
|
||||||
webview.settings.userAgentString =
|
webview.settings.userAgentString = request.header("User-Agent")
|
||||||
request.header("User-Agent") ?: HttpSource.DEFAULT_USERAGENT
|
?: HttpSource.DEFAULT_USER_AGENT
|
||||||
|
|
||||||
webview.webViewClient = object : WebViewClientCompat() {
|
webview.webViewClient = object : WebViewClientCompat() {
|
||||||
override fun onPageFinished(view: WebView, url: String) {
|
override fun onPageFinished(view: WebView, url: String) {
|
||||||
@ -101,7 +113,6 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
latch.countDown()
|
latch.countDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP error codes are only received since M
|
|
||||||
if (url == origRequestUrl && !challengeFound) {
|
if (url == origRequestUrl && !challengeFound) {
|
||||||
// The first request didn't return the challenge, abort.
|
// The first request didn't return the challenge, abort.
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
@ -117,7 +128,7 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
) {
|
) {
|
||||||
if (isMainFrame) {
|
if (isMainFrame) {
|
||||||
if (errorCode == 503) {
|
if (errorCode == 503) {
|
||||||
// Found the cloudflare challenge page.
|
// Found the Cloudflare challenge page.
|
||||||
challengeFound = true
|
challengeFound = true
|
||||||
} else {
|
} else {
|
||||||
// Unlock thread, the challenge wasn't found.
|
// Unlock thread, the challenge wasn't found.
|
||||||
@ -156,6 +167,6 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val SERVER_CHECK = arrayOf("cloudflare-nginx", "cloudflare")
|
private val SERVER_CHECK = arrayOf("cloudflare-nginx", "cloudflare")
|
||||||
private val COOKIE_NAMES = listOf("__cfduid", "cf_clearance")
|
private val COOKIE_NAMES = listOf("cf_clearance")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ class UserAgentInterceptor : Interceptor {
|
|||||||
val newRequest = originalRequest
|
val newRequest = originalRequest
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.removeHeader("User-Agent")
|
.removeHeader("User-Agent")
|
||||||
.addHeader("User-Agent", HttpSource.DEFAULT_USERAGENT)
|
.addHeader("User-Agent", HttpSource.DEFAULT_USER_AGENT)
|
||||||
.build()
|
.build()
|
||||||
chain.proceed(newRequest)
|
chain.proceed(newRequest)
|
||||||
} else {
|
} else {
|
||||||
|
@ -74,7 +74,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
* Headers builder for requests. Implementations can override this method for custom headers.
|
* Headers builder for requests. Implementations can override this method for custom headers.
|
||||||
*/
|
*/
|
||||||
protected open fun headersBuilder() = Headers.Builder().apply {
|
protected open fun headersBuilder() = Headers.Builder().apply {
|
||||||
add("User-Agent", DEFAULT_USERAGENT)
|
add("User-Agent", DEFAULT_USER_AGENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -371,6 +371,6 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
override fun getFilterList() = FilterList()
|
override fun getFilterList() = FilterList()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val DEFAULT_USERAGENT = "Mozilla/5.0 (Windows NT 6.3; WOW64)"
|
const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,37 @@
|
|||||||
package eu.kanade.tachiyomi.util.system
|
package eu.kanade.tachiyomi.util.system
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.webkit.CookieManager
|
||||||
import android.webkit.WebSettings
|
import android.webkit.WebSettings
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
object WebViewUtil {
|
||||||
|
const val REQUESTED_WITH = "com.android.browser"
|
||||||
|
|
||||||
|
const val MINIMUM_WEBVIEW_VERSION = 88
|
||||||
|
|
||||||
|
fun supportsWebView(context: Context): Boolean {
|
||||||
|
try {
|
||||||
|
// May throw android.webkit.WebViewFactory$MissingWebViewPackageException if WebView
|
||||||
|
// is not installed
|
||||||
|
CookieManager.getInstance()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Timber.e(e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun WebView.isOutdated(): Boolean {
|
||||||
|
return getWebViewMajorVersion() < WebViewUtil.MINIMUM_WEBVIEW_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
fun WebView.setDefaultSettings() {
|
fun WebView.setDefaultSettings() {
|
||||||
with(settings) {
|
with(settings) {
|
||||||
javaScriptEnabled = true
|
javaScriptEnabled = true
|
||||||
@ -15,32 +44,25 @@ fun WebView.setDefaultSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val WEBVIEW_UA_VERSION_REGEX by lazy {
|
private fun WebView.getWebViewMajorVersion(): Int {
|
||||||
Regex(""".*Chrome/(\d+)\..*""")
|
val uaRegexMatch = """.*Chrome/(\d+)\..*""".toRegex().matchEntire(getDefaultUserAgentString())
|
||||||
}
|
return if (uaRegexMatch != null && uaRegexMatch.groupValues.size > 1) {
|
||||||
|
|
||||||
private const val MINIMUM_WEBVIEW_VERSION = 86
|
|
||||||
|
|
||||||
fun WebView.isOutdated(): Boolean {
|
|
||||||
return getWebviewMajorVersion(this) < MINIMUM_WEBVIEW_VERSION
|
|
||||||
}
|
|
||||||
|
|
||||||
// Based on https://stackoverflow.com/a/29218966
|
|
||||||
private fun getWebviewMajorVersion(webview: WebView): Int {
|
|
||||||
val originalUA: String = webview.settings.userAgentString
|
|
||||||
|
|
||||||
// Next call to getUserAgentString() will get us the default
|
|
||||||
webview.settings.userAgentString = null
|
|
||||||
|
|
||||||
val uaRegexMatch = WEBVIEW_UA_VERSION_REGEX.matchEntire(webview.settings.userAgentString)
|
|
||||||
val webViewVersion: Int = if (uaRegexMatch != null && uaRegexMatch.groupValues.size > 1) {
|
|
||||||
uaRegexMatch.groupValues[1].toInt()
|
uaRegexMatch.groupValues[1].toInt()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on https://stackoverflow.com/a/29218966
|
||||||
|
private fun WebView.getDefaultUserAgentString(): String {
|
||||||
|
val originalUA: String = settings.userAgentString
|
||||||
|
|
||||||
|
// Next call to getUserAgentString() will get us the default
|
||||||
|
settings.userAgentString = null
|
||||||
|
val defaultUserAgentString = settings.userAgentString
|
||||||
|
|
||||||
// Revert to original UA string
|
// Revert to original UA string
|
||||||
webview.settings.userAgentString = originalUA
|
settings.userAgentString = originalUA
|
||||||
|
|
||||||
return webViewVersion
|
return defaultUserAgentString
|
||||||
}
|
}
|
||||||
|
@ -788,6 +788,8 @@
|
|||||||
<!-- Webview -->
|
<!-- Webview -->
|
||||||
<string name="failed_to_bypass_cloudflare">Failed to bypass Cloudflare</string>
|
<string name="failed_to_bypass_cloudflare">Failed to bypass Cloudflare</string>
|
||||||
<string name="please_update_webview">Please update the WebView app for better compatibility</string>
|
<string name="please_update_webview">Please update the WebView app for better compatibility</string>
|
||||||
|
<!-- Do not translate "WebView" -->
|
||||||
|
<string name="webview_is_required">WebView is required for Tachiyomi</string>
|
||||||
|
|
||||||
<!-- Miscellaneous -->
|
<!-- Miscellaneous -->
|
||||||
<string name="add">Add</string>
|
<string name="add">Add</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user