finish decryption, and give up ;(

This commit is contained in:
jmir1
2021-07-15 11:10:51 +02:00
parent 5950c1c1d1
commit 5cd9f6f6e9
3 changed files with 32 additions and 25 deletions

View File

@ -59,7 +59,7 @@ class Hanime : AnimeHttpSource() {
val responseString = response.body!!.string() val responseString = response.body!!.string()
return parseSearchJson(responseString) return parseSearchJson(responseString)
} }
fun parseSearchJson(jsonLine: String?): AnimesPage { private fun parseSearchJson(jsonLine: String?): AnimesPage {
val jElement: JsonElement = JsonParser.parseString(jsonLine) val jElement: JsonElement = JsonParser.parseString(jsonLine)
val jObject: JsonObject = jElement.asJsonObject val jObject: JsonObject = jElement.asJsonObject
val nbPages = jObject.get("nbPages").asInt val nbPages = jObject.get("nbPages").asInt

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.animeextension.en.twistmoe package eu.kanade.tachiyomi.animeextension.en.twistmoe
import android.annotation.TargetApi import android.annotation.TargetApi
import android.os.Build import android.os.Build
import android.util.Log
import java.security.MessageDigest import java.security.MessageDigest
import java.util.Base64 import java.util.Base64
import javax.crypto.Cipher import javax.crypto.Cipher
@ -15,20 +14,27 @@ class AESDecrypt {
fun aesEncrypt(v: String, secretKey: ByteArray, initializationVector: ByteArray) = encrypt(v, secretKey, initializationVector) fun aesEncrypt(v: String, secretKey: ByteArray, initializationVector: ByteArray) = encrypt(v, secretKey, initializationVector)
fun aesDecrypt(v: ByteArray, secretKey: ByteArray, initializationVector: ByteArray) = decrypt(v, secretKey, initializationVector) fun aesDecrypt(v: ByteArray, secretKey: ByteArray, initializationVector: ByteArray) = decrypt(v, secretKey, initializationVector)
fun getIvAndKey(v: String): ByteArray { fun getIvAndKey(v: String): ByteArray {
// credits: https://github.com/anime-dl/anime-downloader/blob/c030fded0b7f79d5bb8a07f5cf6b2ae8fa3954a1/anime_downloader/sites/twistmoe.py
val byteStr = decoder.decode(v.toByteArray(Charsets.UTF_8)) val byteStr = decoder.decode(v.toByteArray(Charsets.UTF_8))
val md5 = MessageDigest.getInstance("MD5") val md5 = MessageDigest.getInstance("MD5")
assert(byteStr.decodeToString(0, 8) == "Salted__") assert(byteStr.decodeToString(0, 8) == "Salted__")
val salt = byteStr.sliceArray(8..15) val salt = byteStr.sliceArray(8..15)
assert(salt.lastIndex == 7)
val secretStr = "267041df55ca2b36f2e322d05ee2c9cf" val secretStr = "267041df55ca2b36f2e322d05ee2c9cf"
val secret = secretStr val secret = secretStr
.map { it.toByte() } .map { it.toByte() }
.toByteArray() .toByteArray()
val step1 = md5.digest(salt) val data = secret + salt
val step2 = step1 + md5.digest(step1 + secret) var key = md5.digest(data)
val step3 = step2 + md5.digest(step2 + secret) var finalKey = key
Log.i("lol", step3.decodeToString()) while (finalKey.lastIndex < 47) {
assert(step3.lastIndex == 47) key = md5.digest(key + data)
return step3 finalKey += key
}
return finalKey.sliceArray(0..47)
}
fun unpad(v: String): String {
return v.substring(0..v.lastIndex - v.last().toInt())
} }
fun getToDecode(v: String): ByteArray { fun getToDecode(v: String): ByteArray {
val byteStr = decoder.decode(v.toByteArray(Charsets.UTF_8)) val byteStr = decoder.decode(v.toByteArray(Charsets.UTF_8))
@ -37,6 +43,7 @@ class AESDecrypt {
} }
private fun cipher(opmode: Int, secretKey: ByteArray, initializationVector: ByteArray): Cipher { private fun cipher(opmode: Int, secretKey: ByteArray, initializationVector: ByteArray): Cipher {
if (secretKey.lastIndex != 31) throw RuntimeException("SecretKey length is not 32 chars") if (secretKey.lastIndex != 31) throw RuntimeException("SecretKey length is not 32 chars")
if (initializationVector.lastIndex != 15) throw RuntimeException("IV length is not 16 chars")
val c = Cipher.getInstance("AES/CBC/NoPadding") val c = Cipher.getInstance("AES/CBC/NoPadding")
val sk = SecretKeySpec(secretKey, "AES") val sk = SecretKeySpec(secretKey, "AES")
val iv = IvParameterSpec(initializationVector) val iv = IvParameterSpec(initializationVector)

View File

@ -19,6 +19,7 @@ import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
import java.lang.Exception
import java.util.Date import java.util.Date
class TwistMoe : AnimeHttpSource() { class TwistMoe : AnimeHttpSource() {
@ -32,7 +33,7 @@ class TwistMoe : AnimeHttpSource() {
override val supportsLatest = false override val supportsLatest = false
private val popularRequestHeaders = private val popularRequestHeaders =
Headers.headersOf("x-access-token", "0df14814b9e590a1f26d3071a4ed7974") Headers.headersOf("x-access-token", "0df14814b9e590a1f26d3071a4ed7974", "referer", baseUrl)
override fun popularAnimeRequest(page: Int): Request = override fun popularAnimeRequest(page: Int): Request =
GET("https://api.twist.moe/api/anime", popularRequestHeaders) GET("https://api.twist.moe/api/anime", popularRequestHeaders)
@ -56,7 +57,6 @@ class TwistMoe : AnimeHttpSource() {
else -> SAnime.UNKNOWN else -> SAnime.UNKNOWN
} }
anime.thumbnail_url = "https://homepages.cae.wisc.edu/~ece533/images/cat.png" anime.thumbnail_url = "https://homepages.cae.wisc.edu/~ece533/images/cat.png"
anime.initialized = true
animeList.add(anime) animeList.add(anime)
} }
return AnimesPage(animeList, false) return AnimesPage(animeList, false)
@ -88,7 +88,6 @@ class TwistMoe : AnimeHttpSource() {
1 -> SAnime.ONGOING 1 -> SAnime.ONGOING
else -> SAnime.UNKNOWN else -> SAnime.UNKNOWN
} }
anime.initialized = true
return anime return anime
} }
@ -116,29 +115,30 @@ class TwistMoe : AnimeHttpSource() {
} }
override fun episodeListRequest(anime: SAnime): Request { override fun episodeListRequest(anime: SAnime): Request {
val aes = AESDecrypt() // aes.unpad(aes.aesDecrypt(toDecode, ivAndKey.sliceArray(0..31), ivAndKey.sliceArray(32..47)))
val ivAndKey = aes.getIvAndKey("U2FsdGVkX19njUQXx448lKxE4wUQA8tH45sgjCYckbrdS15QHY3fW5ChD6UpcoackxmWn8/5Tk88yAAwSukKwKpfvI6rQ1ERxFcAspfBCj8U/IQYoE3gZy+Esgumt/Fz")
val toDecode = aes.getToDecode("U2FsdGVkX19njUQXx448lKxE4wUQA8tH45sgjCYckbrdS15QHY3fW5ChD6UpcoackxmWn8/5Tk88yAAwSukKwKpfvI6rQ1ERxFcAspfBCj8U/IQYoE3gZy+Esgumt/Fz")
Log.i("lol_key", ivAndKey.sliceArray(0..31).decodeToString())
Log.i("lol_iv", ivAndKey.sliceArray(32..47).decodeToString())
Log.i("lol_final", aes.aesDecrypt(toDecode, ivAndKey.sliceArray(0..31), ivAndKey.sliceArray(32..47)))
val slug = anime.url.substringAfter("/a/") val slug = anime.url.substringAfter("/a/")
return GET("https://api.twist.moe/api/anime/$slug/sources", popularRequestHeaders) return GET("https://api.twist.moe/api/anime/$slug/sources", popularRequestHeaders)
} }
override fun episodeListParse(response: Response): List<SEpisode> { override fun episodeListParse(response: Response): List<SEpisode> {
val responseString = response.body!!.string() val responseString = response.body!!.string()
val jElement: JsonElement = JsonParser.parseString(responseString) Log.i("lol_response", responseString)
val array: JsonArray = jElement.asJsonArray val array = JsonParser.parseString(responseString).asJsonArray
val episodeList = mutableListOf<SEpisode>() val episodeList = mutableListOf<SEpisode>()
for (entry in array) { for (entry in array) {
val episode = SEpisode.create() try {
episode.date_upload = Date.parse(entry.asJsonObject.get("updated_at").asString) Log.i("lol", entry.toString())
episode.name = "Episode " + entry.asJsonObject.get("number").asString val episode = SEpisode.create()
episode.url = entry.asJsonObject.get("source").asString episode.date_upload = Date.parse(entry.asJsonObject.get("updated_at").asString)
episode.episode_number = entry.asJsonObject.get("number").asFloat episode.name = "Episode " + entry.asJsonObject.get("number").asNumber.toString()
episodeList.add(episode) episode.episode_number = entry.asJsonObject.get("number").asFloat
episode.url = response.request.url.toString() + "#${episode.episode_number}"
episodeList.add(episode)
} catch (e: Exception) {
Log.i("lol_e", e.message!!)
}
} }
Log.i("lol", episodeList.lastIndex.toString())
return episodeList return episodeList
} }