mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-11 17:20:49 +01:00
Only show Webview update prompt if CF bypass fails
This commit is contained in:
parent
f29124773b
commit
a50a3df716
4 changed files with 48 additions and 34 deletions
|
@ -7,8 +7,11 @@ import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.webkit.WebSettings
|
import android.webkit.WebSettings
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
|
import android.widget.Toast
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
||||||
import eu.kanade.tachiyomi.util.system.checkVersion
|
import eu.kanade.tachiyomi.util.system.isOutdated
|
||||||
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
|
@ -21,8 +24,6 @@ import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class CloudflareInterceptor(private val context: Context) : Interceptor {
|
class CloudflareInterceptor(private val context: Context) : Interceptor {
|
||||||
|
|
||||||
private val serverCheck = arrayOf("cloudflare-nginx", "cloudflare")
|
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
private val networkHelper: NetworkHelper by injectLazy()
|
private val networkHelper: NetworkHelper by injectLazy()
|
||||||
|
@ -44,36 +45,35 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
||||||
val response = chain.proceed(originalRequest)
|
val response = chain.proceed(originalRequest)
|
||||||
|
|
||||||
// Check if Cloudflare anti-bot is on
|
// Check if Cloudflare anti-bot is on
|
||||||
if (response.code == 503 && response.header("Server") in serverCheck) {
|
if (response.code != 503 || response.header("Server") !in SERVER_CHECK) {
|
||||||
try {
|
return response
|
||||||
response.close()
|
|
||||||
networkHelper.cookieManager.remove(originalRequest.url, listOf("__cfduid", "cf_clearance"), 0)
|
|
||||||
val oldCookie = networkHelper.cookieManager.get(originalRequest.url)
|
|
||||||
.firstOrNull { it.name == "cf_clearance" }
|
|
||||||
return if (resolveWithWebView(originalRequest, oldCookie)) {
|
|
||||||
chain.proceed(originalRequest)
|
|
||||||
} else {
|
|
||||||
throw IOException("Failed to bypass Cloudflare!")
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Because OkHttp's enqueue only handles IOExceptions, wrap the exception so that
|
|
||||||
// we don't crash the entire app
|
|
||||||
throw IOException(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
try {
|
||||||
|
response.close()
|
||||||
|
networkHelper.cookieManager.remove(originalRequest.url, COOKIE_NAMES, 0)
|
||||||
|
val oldCookie = networkHelper.cookieManager.get(originalRequest.url)
|
||||||
|
.firstOrNull { it.name == "cf_clearance" }
|
||||||
|
resolveWithWebView(originalRequest, oldCookie)
|
||||||
|
return chain.proceed(originalRequest)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Because OkHttp's enqueue only handles IOExceptions, wrap the exception so that
|
||||||
|
// we don't crash the entire app
|
||||||
|
throw IOException(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
private fun resolveWithWebView(request: Request, oldCookie: Cookie?): Boolean {
|
private fun resolveWithWebView(request: Request, oldCookie: Cookie?) {
|
||||||
// We need to lock this thread until the WebView finds the challenge solution url, because
|
// We need to lock this thread until the WebView finds the challenge solution url, because
|
||||||
// OkHttp doesn't support asynchronous interceptors.
|
// OkHttp doesn't support asynchronous interceptors.
|
||||||
val latch = CountDownLatch(1)
|
val latch = CountDownLatch(1)
|
||||||
|
|
||||||
var webView: WebView? = null
|
var webView: WebView? = null
|
||||||
|
|
||||||
var challengeFound = false
|
var challengeFound = false
|
||||||
var cloudflareBypassed = false
|
var cloudflareBypassed = 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) ?: "" }
|
||||||
|
@ -82,8 +82,6 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
||||||
val webview = WebView(context)
|
val webview = WebView(context)
|
||||||
webView = webview
|
webView = webview
|
||||||
|
|
||||||
webview.checkVersion()
|
|
||||||
|
|
||||||
webview.settings.javaScriptEnabled = true
|
webview.settings.javaScriptEnabled = true
|
||||||
webview.settings.userAgentString = request.header("User-Agent")
|
webview.settings.userAgentString = request.header("User-Agent")
|
||||||
|
|
||||||
|
@ -135,10 +133,28 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
|
||||||
latch.await(12, TimeUnit.SECONDS)
|
latch.await(12, TimeUnit.SECONDS)
|
||||||
|
|
||||||
handler.post {
|
handler.post {
|
||||||
|
if (!cloudflareBypassed) {
|
||||||
|
isWebviewOutdated = webView?.isOutdated() == true
|
||||||
|
}
|
||||||
|
|
||||||
webView?.stopLoading()
|
webView?.stopLoading()
|
||||||
webView?.destroy()
|
webView?.destroy()
|
||||||
}
|
}
|
||||||
return cloudflareBypassed
|
|
||||||
|
// Throw exception if we failed to bypass Cloudflare
|
||||||
|
if (!cloudflareBypassed) {
|
||||||
|
// Prompt user to update WebView if it seems too outdated
|
||||||
|
if (isWebviewOutdated) {
|
||||||
|
context.toast(R.string.information_webview_outdated, Toast.LENGTH_LONG)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(context.getString(R.string.information_cloudflare_bypass_failure))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SERVER_CHECK = arrayOf("cloudflare-nginx", "cloudflare")
|
||||||
|
private val COOKIE_NAMES = listOf("__cfduid", "cf_clearance")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,10 @@ import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||||
import eu.kanade.tachiyomi.util.system.*
|
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
||||||
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.invisible
|
import eu.kanade.tachiyomi.util.view.invisible
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import kotlinx.android.synthetic.main.webview_activity.*
|
import kotlinx.android.synthetic.main.webview_activity.*
|
||||||
|
@ -53,8 +56,6 @@ class WebViewActivity : BaseActivity() {
|
||||||
val url = intent.extras!!.getString(URL_KEY) ?: return
|
val url = intent.extras!!.getString(URL_KEY) ?: return
|
||||||
val headers = source.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }
|
val headers = source.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }
|
||||||
|
|
||||||
webview.checkVersion()
|
|
||||||
|
|
||||||
webview.settings.javaScriptEnabled = true
|
webview.settings.javaScriptEnabled = true
|
||||||
webview.settings.userAgentString = source.headers["User-Agent"]
|
webview.settings.userAgentString = source.headers["User-Agent"]
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
package eu.kanade.tachiyomi.util.system
|
package eu.kanade.tachiyomi.util.system
|
||||||
|
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.widget.Toast
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
private val WEBVIEW_UA_VERSION_REGEX by lazy {
|
private val WEBVIEW_UA_VERSION_REGEX by lazy {
|
||||||
Regex(""".*Chrome/(\d+)\..*""")
|
Regex(""".*Chrome/(\d+)\..*""")
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val MINIMUM_WEBVIEW_VERSION = 72
|
private const val MINIMUM_WEBVIEW_VERSION = 70
|
||||||
|
|
||||||
fun WebView.checkVersion() {
|
fun WebView.isOutdated(): Boolean {
|
||||||
if (getWebviewMajorVersion(this) < MINIMUM_WEBVIEW_VERSION) {
|
return getWebviewMajorVersion(this) < MINIMUM_WEBVIEW_VERSION
|
||||||
this.context.toast(R.string.information_webview_outdated, Toast.LENGTH_LONG)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://stackoverflow.com/a/29218966
|
// Based on https://stackoverflow.com/a/29218966
|
||||||
|
|
|
@ -521,6 +521,7 @@
|
||||||
<string name="information_no_recent_manga">No recently read manga</string>
|
<string name="information_no_recent_manga">No recently read manga</string>
|
||||||
<string name="information_empty_library">Your library is empty, add series to your library from the catalogues.</string>
|
<string name="information_empty_library">Your library is empty, add series to your library from the catalogues.</string>
|
||||||
<string name="information_empty_category">You have no categories. Hit the plus button to create one for organizing your library.</string>
|
<string name="information_empty_category">You have no categories. Hit the plus button to create one for organizing your library.</string>
|
||||||
|
<string name="information_cloudflare_bypass_failure">Failed to bypass Cloudflare</string>
|
||||||
<string name="information_webview_outdated">Please update the WebView app for better compatibility</string>
|
<string name="information_webview_outdated">Please update the WebView app for better compatibility</string>
|
||||||
|
|
||||||
<!-- Download Notification -->
|
<!-- Download Notification -->
|
||||||
|
|
Loading…
Reference in a new issue