From 9a7187bf36cbb5481ec8fb3f0e356383172e8bdd Mon Sep 17 00:00:00 2001 From: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:59:49 +0500 Subject: [PATCH] MirrorDesu: change domain and decrypt pagelist (#1738) --- src/id/mirrordesu/build.gradle | 9 ++- .../extension/id/mirrordesu/MirrorDesu.kt | 74 ++++++++++++++++++- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/id/mirrordesu/build.gradle b/src/id/mirrordesu/build.gradle index 8e4ddddcf..d3f413c6c 100644 --- a/src/id/mirrordesu/build.gradle +++ b/src/id/mirrordesu/build.gradle @@ -2,9 +2,14 @@ ext { extName = 'MirrorDesu' extClass = '.MirrorDesu' themePkg = 'mangathemesia' - baseUrl = 'https://mirrordesu.me' - overrideVersionCode = 0 + baseUrl = 'https://mirrordesu.one' + overrideVersionCode = 1 isNsfw = true } apply from: "$rootDir/common.gradle" + +dependencies { + implementation(project(":lib:cryptoaes")) + implementation(project(":lib:synchrony")) +} diff --git a/src/id/mirrordesu/src/eu/kanade/tachiyomi/extension/id/mirrordesu/MirrorDesu.kt b/src/id/mirrordesu/src/eu/kanade/tachiyomi/extension/id/mirrordesu/MirrorDesu.kt index 3703c33a2..320b0b925 100644 --- a/src/id/mirrordesu/src/eu/kanade/tachiyomi/extension/id/mirrordesu/MirrorDesu.kt +++ b/src/id/mirrordesu/src/eu/kanade/tachiyomi/extension/id/mirrordesu/MirrorDesu.kt @@ -1,13 +1,81 @@ package eu.kanade.tachiyomi.extension.id.mirrordesu +import android.util.Base64 +import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES +import eu.kanade.tachiyomi.lib.synchrony.Deobfuscator import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.network.interceptor.rateLimit -import okhttp3.OkHttpClient +import eu.kanade.tachiyomi.source.model.Page +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import org.jsoup.nodes.Document -class MirrorDesu : MangaThemesia("MirrorDesu", "https://mirrordesu.me", "id", "/komik") { - override val client: OkHttpClient = super.client.newBuilder() +class MirrorDesu : MangaThemesia( + "MirrorDesu", + "https://mirrordesu.one", + "id", + "/komik", +) { + override val client = super.client.newBuilder() .rateLimit(4) .build() override val hasProjectPage = true + + override fun pageListParse(document: Document): List { + val script = document.selectFirst("script:containsData(ts_reader)")?.data() + ?: return super.pageListParse(document) + + val deobfuscatedScript = Deobfuscator.deobfuscateScript(script)!! + + val (dataKey, pwdKey) = obfuscatedNamesRegex.find(deobfuscatedScript)!! + .groupValues.let { it[1] to it[2] } + + val encData = deobfuscatedScript.substringAfter(dataKey) + .substringAfter("\'") + .substringBefore("\'") + .let { json.decodeFromString(it) } + + val unsaltedCiphertext = Base64.decode(encData.cipherText, Base64.DEFAULT) + val salt = encData.salt.decodeHex() + val ciphertext = Base64.encodeToString(salted + salt + unsaltedCiphertext, Base64.DEFAULT) + + val pwd = Regex("""let\s*$pwdKey\s*=\s*'(\w+)'""").find(deobfuscatedScript)!! + .groupValues[1] + + val data = CryptoAES.decrypt(ciphertext, pwd) + + val tsReader = json.decodeFromString(json.decodeFromString(data)) + val imageUrls = tsReader.sources.firstOrNull()?.images ?: return emptyList() + return imageUrls.mapIndexed { index, imageUrl -> Page(index, document.location(), imageUrl) } + } + + private fun String.decodeHex(): ByteArray { + check(length % 2 == 0) { "Must have an even length" } + + return chunked(2) + .map { it.toInt(16).toByte() } + .toByteArray() + } + + private val salted = "Salted__".toByteArray(Charsets.UTF_8) + + private val obfuscatedNamesRegex = Regex("""CryptoJSAesJson\.decrypt\(\s*(\w+)\s*,\s*(\w+)\s*\)""") + + @Serializable + class EncryptedDto( + @SerialName("ct") val cipherText: String, + @SerialName("s") val salt: String, + ) + + @Serializable + class TSReader( + val sources: List, + ) + + @Serializable + class ReaderImageSource( + val images: List, + ) }