LeitorDeManga: Bypass jschallenge (#9804)
* Fix 403 * Rewrite to an eligible tailrec statement * Bump version * Remove use function
This commit is contained in:
parent
9840ff97d5
commit
9755776353
@ -3,7 +3,7 @@ ext {
|
|||||||
extClass = '.YakshaScans'
|
extClass = '.YakshaScans'
|
||||||
themePkg = 'madara'
|
themePkg = 'madara'
|
||||||
baseUrl = 'https://yakshascans.com'
|
baseUrl = 'https://yakshascans.com'
|
||||||
overrideVersionCode = 1
|
overrideVersionCode = 2
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,33 +22,43 @@ class YakshaScans : Madara(
|
|||||||
.addInterceptor(::jsChallengeInterceptor)
|
.addInterceptor(::jsChallengeInterceptor)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
// Linked to src/pt/leitordemanga
|
||||||
private fun jsChallengeInterceptor(chain: Interceptor.Chain): Response {
|
private fun jsChallengeInterceptor(chain: Interceptor.Chain): Response {
|
||||||
val request = chain.request()
|
val response = chain.proceed(chain.request())
|
||||||
val origRes = chain.proceed(request)
|
if (response.code != 403) {
|
||||||
if (origRes.code != 403) return origRes
|
return response
|
||||||
origRes.close()
|
}
|
||||||
|
response.close()
|
||||||
|
|
||||||
// Same delay as the source
|
|
||||||
Thread.sleep(3000L)
|
Thread.sleep(3000L)
|
||||||
val token = fetchToken(chain).sha256()
|
val token = fetchToken(chain).sha256()
|
||||||
|
val body = FormBody.Builder()
|
||||||
|
.add("challenge", token)
|
||||||
|
.build()
|
||||||
|
|
||||||
val body = FormBody.Builder().add("challenge", token).build()
|
chain.proceed(POST("$baseUrl/hcdn-cgi/jschallenge-validate", headers, body))
|
||||||
val challengeReq = POST("$baseUrl/hcdn-cgi/jschallenge-validate", headers, body = body)
|
.apply(Response::close)
|
||||||
|
.run {
|
||||||
val challengeResponse = chain.proceed(challengeReq)
|
if (!isSuccessful) {
|
||||||
challengeResponse.close()
|
throw IOException("Failed to bypass js challenge!")
|
||||||
if (challengeResponse.code != 200) throw IOException("Failed to bypass js challenge!")
|
}
|
||||||
|
}
|
||||||
return chain.proceed(request)
|
return chain.proceed(chain.request())
|
||||||
}
|
}
|
||||||
|
|
||||||
private tailrec fun fetchToken(chain: Interceptor.Chain, attempt: Int = 0): String {
|
private tailrec fun fetchToken(chain: Interceptor.Chain, attempt: Int = 0): String {
|
||||||
if (attempt > 5) throw IOException("Failed to fetch challenge token!")
|
if (attempt > MAX_ATTEMPT) {
|
||||||
val request = GET("$baseUrl/hcdn-cgi/jschallenge", headers)
|
throw IOException("Failed to fetch challenge token!")
|
||||||
val res = chain.proceed(request).body.string()
|
}
|
||||||
|
|
||||||
return res.substringAfter("cjs = '").substringBefore("'")
|
val response = chain.proceed(GET("$baseUrl/hcdn-cgi/jschallenge", headers))
|
||||||
.takeUnless { it == "nil" } ?: fetchToken(chain, attempt + 1)
|
val token = TOKEN_REGEX.find(response.body.string())?.groups?.get(1)?.value
|
||||||
|
|
||||||
|
return if (token != null && token != "nil") {
|
||||||
|
token
|
||||||
|
} else {
|
||||||
|
fetchToken(chain, attempt + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.sha256(): String {
|
private fun String.sha256(): String {
|
||||||
@ -62,4 +72,9 @@ class YakshaScans : Madara(
|
|||||||
|
|
||||||
override val mangaDetailsSelectorDescription: String =
|
override val mangaDetailsSelectorDescription: String =
|
||||||
"div.description-summary div.summary__content h3 + p, div.description-summary div.summary__content:not(:has(h3)), div.summary_content div.post-content_item > h5 + div, div.summary_content div.manga-excerpt"
|
"div.description-summary div.summary__content h3 + p, div.description-summary div.summary__content:not(:has(h3)), div.summary_content div.post-content_item > h5 + div, div.summary_content div.manga-excerpt"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val MAX_ATTEMPT = 5
|
||||||
|
private val TOKEN_REGEX = """cjs[^']+'([^']+)""".toRegex()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ ext {
|
|||||||
extClass = '.LeitorDeManga'
|
extClass = '.LeitorDeManga'
|
||||||
themePkg = 'madara'
|
themePkg = 'madara'
|
||||||
baseUrl = 'https://leitordemanga.com'
|
baseUrl = 'https://leitordemanga.com'
|
||||||
overrideVersionCode = 0
|
overrideVersionCode = 1
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi.extension.pt.leitordemanga
|
package eu.kanade.tachiyomi.extension.pt.leitordemanga
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Response
|
||||||
|
import java.io.IOException
|
||||||
|
import java.security.MessageDigest
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -17,5 +24,57 @@ class LeitorDeManga : Madara(
|
|||||||
|
|
||||||
override val client: OkHttpClient = super.client.newBuilder()
|
override val client: OkHttpClient = super.client.newBuilder()
|
||||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||||
|
.addInterceptor(::jsChallengeInterceptor)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
// Linked to src/en/yakshascans
|
||||||
|
private fun jsChallengeInterceptor(chain: Interceptor.Chain): Response {
|
||||||
|
val response = chain.proceed(chain.request())
|
||||||
|
if (response.code != 403) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
response.close()
|
||||||
|
|
||||||
|
Thread.sleep(3000L)
|
||||||
|
val token = fetchToken(chain).sha256()
|
||||||
|
val body = FormBody.Builder()
|
||||||
|
.add("challenge", token)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
chain.proceed(POST("$baseUrl/hcdn-cgi/jschallenge-validate", headers, body))
|
||||||
|
.apply(Response::close)
|
||||||
|
.run {
|
||||||
|
if (!isSuccessful) {
|
||||||
|
throw IOException("Failed to bypass js challenge!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chain.proceed(chain.request())
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec fun fetchToken(chain: Interceptor.Chain, attempt: Int = 0): String {
|
||||||
|
if (attempt > MAX_ATTEMPT) {
|
||||||
|
throw IOException("Failed to fetch challenge token!")
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = chain.proceed(GET("$baseUrl/hcdn-cgi/jschallenge", headers))
|
||||||
|
val token = TOKEN_REGEX.find(response.body.string())?.groups?.get(1)?.value
|
||||||
|
|
||||||
|
return if (token != null && token != "nil") {
|
||||||
|
token
|
||||||
|
} else {
|
||||||
|
fetchToken(chain, attempt + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.sha256(): String {
|
||||||
|
return MessageDigest
|
||||||
|
.getInstance("SHA-256")
|
||||||
|
.digest(toByteArray())
|
||||||
|
.fold("", { str, it -> str + "%02x".format(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val MAX_ATTEMPT = 5
|
||||||
|
private val TOKEN_REGEX = """cjs[^']+'([^']+)""".toRegex()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user