From 85af4c5f97419ffe83964a7f613c94200ac664ae Mon Sep 17 00:00:00 2001 From: Claudemirovsky <63046606+Claudemirovsky@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:05:56 -0300 Subject: [PATCH] en/AscalonScans: Fix http 403 (#577) * fix: Fix http 403 - Bypass JS Challenge * chore: Bump version * refactor: Apply suggestion - Explicitly close response * refactor: Apply suggestion - add tailrec modifier * fix: Prevent future headaches - Use the same delay as the challenge * fix: Apply suggestion - Prevent throwing without closing response --- .../ascalonscans/src/AscalonScans.kt | 55 +++++++++++++++++++ .../mangathemesia/MangaThemesiaGenerator.kt | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 multisrc/overrides/mangathemesia/ascalonscans/src/AscalonScans.kt diff --git a/multisrc/overrides/mangathemesia/ascalonscans/src/AscalonScans.kt b/multisrc/overrides/mangathemesia/ascalonscans/src/AscalonScans.kt new file mode 100644 index 000000000..76c7d20c4 --- /dev/null +++ b/multisrc/overrides/mangathemesia/ascalonscans/src/AscalonScans.kt @@ -0,0 +1,55 @@ +package eu.kanade.tachiyomi.extension.en.ascalonscans + +import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.network.interceptor.rateLimitHost +import okhttp3.FormBody +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor +import okhttp3.Response +import java.io.IOException +import java.security.MessageDigest + +class AscalonScans : MangaThemesia("AscalonScans", "https://ascalonscans.com", "en") { + override val client = super.client.newBuilder() + .rateLimitHost(baseUrl.toHttpUrl(), 2) + .addInterceptor(::jsChallengeInterceptor) + .build() + + private fun jsChallengeInterceptor(chain: Interceptor.Chain): Response { + val request = chain.request() + val origRes = chain.proceed(request) + if (origRes.code != 403) return origRes + origRes.close() + + // Same delay as the source + Thread.sleep(3000L) + val token = fetchToken(chain).sha256() + + val body = FormBody.Builder().add("challenge", token).build() + val challengeReq = POST("$baseUrl/hcdn-cgi/jschallenge-validate", headers, body = body) + + val challengeResponse = chain.proceed(challengeReq) + challengeResponse.close() + if (challengeResponse.code != 200) throw IOException("Failed to bypass js challenge!") + + return chain.proceed(request) + } + + private tailrec fun fetchToken(chain: Interceptor.Chain, attempt: Int = 0): String { + if (attempt > 5) throw IOException("Failed to fetch challenge token!") + val request = GET("$baseUrl/hcdn-cgi/jschallenge", headers) + val res = chain.proceed(request).body.string() + + return res.substringAfter("cjs = '").substringBefore("'") + .takeUnless { it == "nil" } ?: fetchToken(chain, attempt + 1) + } + + private fun String.sha256(): String { + return MessageDigest + .getInstance("SHA-256") + .digest(toByteArray()) + .fold("", { str, it -> str + "%02x".format(it) }) + } +} diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt index 5cd3a58ac..f5e832f25 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt @@ -20,7 +20,7 @@ class MangaThemesiaGenerator : ThemeSourceGenerator { SingleLang("Animated Glitched Comics", "https://agscomics.com", "en"), SingleLang("Animated Glitched Scans", "https://anigliscans.xyz", "en", overrideVersionCode = 1), SingleLang("Arven Scans", "https://arvenscans.com", "en"), - SingleLang("AscalonScans", "https://ascalonscans.com", "en"), + SingleLang("AscalonScans", "https://ascalonscans.com", "en", overrideVersionCode = 1), SingleLang("Asura Scans", "https://asuratoon.com", "en"), SingleLang("Azure Scans", "https://azuremanga.com", "en", overrideVersionCode = 1), SingleLang("Banana-Scan", "https://banana-scan.com", "fr", className = "BananaScan", isNsfw = true),