Fix universal captcha detection

This commit is contained in:
NerdNumber9 2019-04-21 20:46:29 -04:00
parent 6ce70296a6
commit 59fcfbe9d2
6 changed files with 70 additions and 37 deletions

View File

@ -3,7 +3,10 @@ package eu.kanade.tachiyomi.network
import android.content.Context
import android.os.Build
import exh.log.maybeInjectEHLogger
import exh.patch.MANGADEX_DOMAIN
import exh.patch.MANGADEX_SOURCE_ID
import exh.patch.attachMangaDexLogin
import exh.patch.detectCaptchas
import okhttp3.*
import java.io.File
import java.io.IOException
@ -33,6 +36,7 @@ open class NetworkHelper(context: Context) {
open val cloudflareClient = client.newBuilder()
.addInterceptor(CloudflareInterceptor(context))
.attachMangaDexLogin()
.detectCaptchas(context, MANGADEX_SOURCE_ID, listOf(MANGADEX_DOMAIN))
.build()
private fun OkHttpClient.Builder.enableTLS12(): OkHttpClient.Builder {

View File

@ -6,9 +6,8 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.network.*
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.*
import exh.patch.detectCaptchas
import exh.source.DelegatedHttpSource
import exh.ui.captcha.BrowserActionActivity
import exh.util.interceptAsHtml
import okhttp3.*
import rx.Observable
import uy.kohesive.injekt.Injekt
@ -79,22 +78,10 @@ abstract class HttpSource : CatalogueSource {
* Default network client for doing requests.
*/
open val client: OkHttpClient
get() = delegate?.baseHttpClient ?: network.client.newBuilder().addInterceptor { chain ->
// Automatic captcha detection
val response = chain.proceed(chain.request())
if(!response.isSuccessful) {
response.interceptAsHtml { doc ->
if (doc.getElementsByClass("g-recaptcha").isNotEmpty()) {
// Found it, allow the user to solve this thing
BrowserActionActivity.launchUniversal(
Injekt.get<Application>(),
this,
chain.request().url().toString()
)
}
}
} else response
}.build()
get() = delegate?.baseHttpClient ?: network.client
.newBuilder()
.detectCaptchas(Injekt.get<Application>(), id, null)
.build()
/**
* Headers builder for requests. Implementations can override this method for custom headers.

View File

@ -27,7 +27,7 @@ private fun verifyComplete(url: String): Boolean {
fun OkHttpClient.Builder.attachMangaDexLogin() =
addInterceptor { chain ->
val response = chain.proceed(chain.request())
if(response.request().url().host() == "mangadex.org") {
if(response.request().url().host() == MANGADEX_DOMAIN) {
response.interceptAsHtml { doc ->
if (doc.title().trim().equals("Login - MangaDex", true)) {
BrowserActionActivity.launchAction(
@ -36,7 +36,7 @@ fun OkHttpClient.Builder.attachMangaDexLogin() =
HIDE_SCRIPT,
"https://mangadex.org/login",
"Login",
(Injekt.get<SourceManager>().get(2499283573021220255) as? HttpSource)?.headers?.toMultimap()?.mapValues {
(Injekt.get<SourceManager>().get(MANGADEX_SOURCE_ID) as? HttpSource)?.headers?.toMultimap()?.mapValues {
it.value.joinToString(",")
} ?: emptyMap()
)
@ -44,3 +44,6 @@ fun OkHttpClient.Builder.attachMangaDexLogin() =
}
} else response
}
const val MANGADEX_SOURCE_ID = 2499283573021220255
const val MANGADEX_DOMAIN = "mangadex.org"

View File

@ -0,0 +1,28 @@
package exh.patch
import android.content.Context
import exh.ui.captcha.BrowserActionActivity
import exh.util.interceptAsHtml
import okhttp3.OkHttpClient
fun OkHttpClient.Builder.detectCaptchas(context: Context, sourceId: Long, domains: List<String>? = null): OkHttpClient.Builder {
return addInterceptor { chain ->
// Automatic captcha detection
val response = chain.proceed(chain.request())
if(!response.isSuccessful) {
if(domains != null && response.request().url().host() !in domains)
return@addInterceptor response
response.interceptAsHtml { doc ->
if (doc.getElementsByClass("g-recaptcha").isNotEmpty()) {
// Found it, allow the user to solve this thing
BrowserActionActivity.launchUniversal(
context,
sourceId,
chain.request().url().toString()
)
}
}
} else response
}
}

View File

@ -648,6 +648,17 @@ class BrowserActionActivity : AppCompatActivity() {
context.startActivity(intent)
}
fun launchUniversal(context: Context,
sourceId: Long,
url: String) {
val intent = baseIntent(context).apply {
putExtra(SOURCE_ID_EXTRA, sourceId)
putExtra(URL_EXTRA, url)
}
context.startActivity(intent)
}
fun launchAction(context: Context,
completionVerifier: ActionCompletionVerifier,
script: String?,

View File

@ -8,24 +8,24 @@ import org.jsoup.nodes.Document
fun Response.interceptAsHtml(block: (Document) -> Unit): Response {
val body = body()
if(body != null) {
if (body.contentType()?.type() == "text"
&& body.contentType()?.subtype() == "html") {
val bodyString = body.string()
val rebuiltResponse = newBuilder()
.body(ResponseBody.create(body.contentType(), bodyString))
.build()
try {
// Search for captcha
val parsed = asJsoup(html = bodyString)
block(parsed)
} catch (t: Throwable) {
// Ignore all errors
XLog.w("Interception error!", t)
}
return rebuiltResponse
if (body?.contentType()?.type() == "text"
&& body.contentType()?.subtype() == "html") {
val bodyString = body.string()
val rebuiltResponse = newBuilder()
.body(ResponseBody.create(body.contentType(), bodyString))
.build()
try {
// Search for captcha
val parsed = asJsoup(html = bodyString)
block(parsed)
} catch (t: Throwable) {
// Ignore all errors
XLog.w("Interception error!", t)
} finally {
close()
}
return rebuiltResponse
}
return this
}