Passing CloudFlare checks
parent
17c20b2bf9
commit
5190ec3e98
@ -0,0 +1,8 @@
|
||||
package org.koitharu.kotatsu.ui.utils.cloudflare
|
||||
|
||||
interface CloudFlareCallback {
|
||||
|
||||
fun onPageLoaded()
|
||||
|
||||
fun onCheckPassed()
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package org.koitharu.kotatsu.ui.utils.cloudflare
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import okhttp3.Cookie
|
||||
import okhttp3.CookieJar
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
class CloudFlareClient(
|
||||
private val callback: CloudFlareCallback,
|
||||
private val targetUrl: String
|
||||
) : WebViewClient(), KoinComponent {
|
||||
|
||||
private val cookieJar = get<CookieJar>()
|
||||
private val cookieManager = CookieManager.getInstance()
|
||||
|
||||
init {
|
||||
cookieManager.removeAllCookies(null)
|
||||
}
|
||||
|
||||
override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
|
||||
super.onPageStarted(view, url, favicon)
|
||||
checkClearance()
|
||||
}
|
||||
|
||||
override fun onPageCommitVisible(view: WebView?, url: String?) {
|
||||
super.onPageCommitVisible(view, url)
|
||||
callback.onPageLoaded()
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
super.onPageFinished(view, url)
|
||||
callback.onPageLoaded()
|
||||
}
|
||||
|
||||
private fun checkClearance() {
|
||||
val httpUrl = targetUrl.toHttpUrl()
|
||||
val cookies = cookieManager.getCookie(targetUrl).split(';').mapNotNull {
|
||||
Cookie.parse(httpUrl, it)
|
||||
}
|
||||
if (cookies.none { it.name == CF_CLEARANCE }) {
|
||||
return
|
||||
}
|
||||
cookieJar.saveFromResponse(httpUrl, cookies)
|
||||
callback.onCheckPassed()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val CF_UID = "__cfduid"
|
||||
const val CF_CLEARANCE = "cf_clearance"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package org.koitharu.kotatsu.ui.utils.cloudflare
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.WebSettings
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import kotlinx.android.synthetic.main.fragment_cloudflare.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.network.UserAgentInterceptor
|
||||
import org.koitharu.kotatsu.ui.base.AlertDialogFragment
|
||||
import org.koitharu.kotatsu.utils.ext.stringArgument
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class CloudFlareDialog : AlertDialogFragment(R.layout.fragment_cloudflare), CloudFlareCallback {
|
||||
|
||||
private val url by stringArgument(ARG_URL)
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
with(webView.settings) {
|
||||
javaScriptEnabled = true
|
||||
cacheMode = WebSettings.LOAD_DEFAULT
|
||||
domStorageEnabled = true
|
||||
databaseEnabled = true
|
||||
userAgentString = UserAgentInterceptor.userAgent
|
||||
}
|
||||
webView.webViewClient = CloudFlareClient(this, url.orEmpty())
|
||||
CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true)
|
||||
if (url.isNullOrEmpty()) {
|
||||
dismissAllowingStateLoss()
|
||||
} else {
|
||||
webView.loadUrl(url.orEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
webView.stopLoading()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onBuildDialog(builder: AlertDialog.Builder) {
|
||||
builder.setNegativeButton(android.R.string.cancel, null)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
webView.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
webView.onPause()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onPageLoaded() {
|
||||
progressBar?.isInvisible = true
|
||||
}
|
||||
|
||||
override fun onCheckPassed() {
|
||||
((parentFragment ?: activity) as? SwipeRefreshLayout.OnRefreshListener)?.onRefresh()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "CloudFlareDialog"
|
||||
private const val ARG_URL = "url"
|
||||
|
||||
fun newInstance(url: String) = CloudFlareDialog().withArgs(1) {
|
||||
putString(ARG_URL, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.material.progressindicator.ProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="40dp"
|
||||
android:indeterminate="true"
|
||||
app:indicatorColor="?colorAccent"
|
||||
app:indicatorType="circular" />
|
||||
|
||||
</FrameLayout>
|
||||
Loading…
Reference in New Issue