Bypass cloudflare WAF using webview in MyReadingManga (#8562)
* Bypass cloudflare WAF using webview * MyReadingManga: remove single cookie when bypassing Cloudflare
This commit is contained in:
parent
8c302fe615
commit
10c2dc0395
@ -5,7 +5,7 @@ ext {
|
|||||||
extName = 'MyReadingManga'
|
extName = 'MyReadingManga'
|
||||||
pkgNameSuffix = 'all.myreadingmanga'
|
pkgNameSuffix = 'all.myreadingmanga'
|
||||||
extClass = '.MyReadingMangaFactory'
|
extClass = '.MyReadingMangaFactory'
|
||||||
extVersionCode = 41
|
extVersionCode = 42
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.all.myreadingmanga
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Application
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.webkit.CookieManager
|
||||||
|
import android.webkit.WebResourceError
|
||||||
|
import android.webkit.WebResourceRequest
|
||||||
|
import android.webkit.WebSettings
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.webkit.WebViewClient
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class CloudflareWafInterceptor(private val cookieDomain: String) : Interceptor {
|
||||||
|
private val context = Injekt.get<Application>()
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
private val cookieManager = CookieManager.getInstance()
|
||||||
|
|
||||||
|
private val initWebView by lazy {
|
||||||
|
WebSettings.getDefaultUserAgent(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
initWebView
|
||||||
|
|
||||||
|
val originalRequest = chain.request()
|
||||||
|
val request = originalRequest.newBuilder()
|
||||||
|
.header("User-Agent", initWebView)
|
||||||
|
.build()
|
||||||
|
val response = chain.proceed(request)
|
||||||
|
|
||||||
|
if (response.code != 403 || response.header("Server") !in SERVER_CHECK) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
response.close()
|
||||||
|
|
||||||
|
// Remove all cookies and retry the Cloudflare WAF in a webview.
|
||||||
|
// This is the key.
|
||||||
|
cookieManager.setCookie(request.url.toString(), "__cf_bm=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=$cookieDomain")
|
||||||
|
cookieManager.flush()
|
||||||
|
resolveWithWebView(request)
|
||||||
|
|
||||||
|
return chain.proceed(request)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IOException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
|
private fun resolveWithWebView(request: Request) {
|
||||||
|
val latch = CountDownLatch(1)
|
||||||
|
|
||||||
|
var webView: WebView? = null
|
||||||
|
|
||||||
|
val origRequestUrl = request.url.toString()
|
||||||
|
val headers = request.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
|
||||||
|
headers.remove("cookie")
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
val webview = WebView(context)
|
||||||
|
webView = webview
|
||||||
|
with(webview.settings) {
|
||||||
|
javaScriptEnabled = true
|
||||||
|
domStorageEnabled = true
|
||||||
|
databaseEnabled = true
|
||||||
|
useWideViewPort = false
|
||||||
|
loadWithOverviewMode = false
|
||||||
|
userAgentString = request.header("User-Agent")
|
||||||
|
}
|
||||||
|
|
||||||
|
webview.webViewClient = object : WebViewClient() {
|
||||||
|
override fun onPageFinished(view: WebView, url: String) {
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
webView?.loadUrl(origRequestUrl, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.await(TIMEOUT_SEC, TimeUnit.SECONDS)
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
webView?.stopLoading()
|
||||||
|
webView?.destroy()
|
||||||
|
webView = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SERVER_CHECK = arrayOf("cloudflare-nginx", "cloudflare")
|
||||||
|
const val TIMEOUT_SEC: Long = 10
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,6 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
@ -31,6 +30,7 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
|||||||
override val name = "MyReadingManga"
|
override val name = "MyReadingManga"
|
||||||
final override val baseUrl = "https://myreadingmanga.info"
|
final override val baseUrl = "https://myreadingmanga.info"
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
|
.addInterceptor(CloudflareWafInterceptor(".myreadingmanga.info"))
|
||||||
.connectTimeout(1, TimeUnit.MINUTES)
|
.connectTimeout(1, TimeUnit.MINUTES)
|
||||||
.readTimeout(1, TimeUnit.MINUTES)
|
.readTimeout(1, TimeUnit.MINUTES)
|
||||||
.retryOnConnectionFailure(true)
|
.retryOnConnectionFailure(true)
|
||||||
@ -38,9 +38,6 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
|||||||
.build()!!
|
.build()!!
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
|
||||||
.add("Referer", baseUrl)
|
|
||||||
|
|
||||||
// Popular - Random
|
// Popular - Random
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
return GET("$baseUrl/search/?wpsolr_sort=sort_by_random&wpsolr_page=$page&wpsolr_fq[0]=lang_str:$siteLang", headers) // Random Manga as returned by search
|
return GET("$baseUrl/search/?wpsolr_sort=sort_by_random&wpsolr_page=$page&wpsolr_fq[0]=lang_str:$siteLang", headers) // Random Manga as returned by search
|
||||||
|
Loading…
x
Reference in New Issue
Block a user