CopyManga: Update getting decrypt passwords. (#9209)
Instead of looking for attributes on elements, we now have to evaluate JavaScript to get the decryption password. Fixes #9197
This commit is contained in:
parent
f26a96c95f
commit
cb60de30dc
|
@ -5,7 +5,7 @@ ext {
|
||||||
extName = 'CopyManga'
|
extName = 'CopyManga'
|
||||||
pkgNameSuffix = 'zh.copymanga'
|
pkgNameSuffix = 'zh.copymanga'
|
||||||
extClass = '.CopyManga'
|
extClass = '.CopyManga'
|
||||||
extVersionCode = 16
|
extVersionCode = 17
|
||||||
}
|
}
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.zh.copymanga
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import com.luhuiguo.chinese.ChineseUtils
|
import com.luhuiguo.chinese.ChineseUtils
|
||||||
|
import com.squareup.duktape.Duktape
|
||||||
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
|
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
|
@ -20,6 +21,7 @@ import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
@ -179,7 +181,7 @@ class CopyManga : ConfigurableSource, HttpSource() {
|
||||||
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val disposablePass = document.select("div.detailPass").first()?.attr("disposable")
|
val disposablePass = this.evaluateScript(document, "dio")
|
||||||
|
|
||||||
// Get encrypted chapters data from another endpoint
|
// Get encrypted chapters data from another endpoint
|
||||||
val chapterResponse =
|
val chapterResponse =
|
||||||
|
@ -234,7 +236,7 @@ class CopyManga : ConfigurableSource, HttpSource() {
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val disposableData = document.select("div.imageData").first().attr("contentKey")
|
val disposableData = document.select("div.imageData").first().attr("contentKey")
|
||||||
val disposablePass = document.select("div.imagePass").first()?.attr("contentKey")
|
val disposablePass = this.evaluateScript(document, "jojo")
|
||||||
|
|
||||||
val pageJsonString = decryptChapterData(disposableData, disposablePass)
|
val pageJsonString = decryptChapterData(disposableData, disposablePass)
|
||||||
val pageArray = JSONArray(pageJsonString)
|
val pageArray = JSONArray(pageJsonString)
|
||||||
|
@ -448,11 +450,24 @@ class CopyManga : ConfigurableSource, HttpSource() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun evaluateScript(document: Document, expression: String): String {
|
||||||
|
return Duktape.create().use { duktape ->
|
||||||
|
document.select("script:not([src])").map(Element::data).forEach { script ->
|
||||||
|
try {
|
||||||
|
duktape.evaluate(script)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
// Ignore any exception from evaluating the script
|
||||||
|
}
|
||||||
|
}
|
||||||
|
duktape.evaluate(expression).toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// thanks to unpacker toolsite, http://matthewfl.com/unPacker.html
|
// thanks to unpacker toolsite, http://matthewfl.com/unPacker.html
|
||||||
private fun decryptChapterData(disposableData: String, disposablePass: String?): String {
|
private fun decryptChapterData(disposableData: String, disposablePass: String?): String {
|
||||||
val prePart = disposableData.substring(0, 16)
|
val prePart = disposableData.substring(0, 16)
|
||||||
val postPart = disposableData.substring(16, disposableData.length)
|
val postPart = disposableData.substring(16, disposableData.length)
|
||||||
val disposablePassByteArray = (disposablePass ?: "xxxmanga.abc.key").toByteArray(Charsets.UTF_8)
|
val disposablePassByteArray = (disposablePass ?: "hotmanga.aes.key").toByteArray(Charsets.UTF_8)
|
||||||
val prepartByteArray = prePart.toByteArray(Charsets.UTF_8)
|
val prepartByteArray = prePart.toByteArray(Charsets.UTF_8)
|
||||||
val dataByteArray = hexStringToByteArray(postPart)
|
val dataByteArray = hexStringToByteArray(postPart)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue