From 82d8a2f2aba6f5e7a276f89958447283ed15adf4 Mon Sep 17 00:00:00 2001 From: Vetle Ledaal Date: Wed, 9 Feb 2022 11:14:22 +0000 Subject: [PATCH] Tsumino: bypass email protection (#10760) * Tsumino: bypass email protection * Rewrite cfDecodeEmail Use less magic, safety is kept in mind for the key and data. Invalid key returns an empty string, invalid data is skipped. Returns not null since the Element.text() function validates that the input is not null -- and it's probably a useless distincion anyways. * further kotlin-ify cfDecodeEmails --- src/en/tsumino/build.gradle | 2 +- .../tachiyomi/extension/en/tsumino/Tsumino.kt | 7 +++-- .../extension/en/tsumino/TsuminoUtils.kt | 29 ++++++++++++++++--- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/en/tsumino/build.gradle b/src/en/tsumino/build.gradle index 052136188..1035ac0a6 100644 --- a/src/en/tsumino/build.gradle +++ b/src/en/tsumino/build.gradle @@ -6,7 +6,7 @@ ext { extName = 'Tsumino' pkgNameSuffix = 'en.tsumino' extClass = '.Tsumino' - extVersionCode = 5 + extVersionCode = 6 isNsfw = true } diff --git a/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/Tsumino.kt b/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/Tsumino.kt index 3b3c9f348..91abdbf0d 100644 --- a/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/Tsumino.kt +++ b/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/Tsumino.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.extension.en.tsumino +import eu.kanade.tachiyomi.extension.en.tsumino.TsuminoUtils.Companion.cfDecodeEmails import eu.kanade.tachiyomi.extension.en.tsumino.TsuminoUtils.Companion.getArtists import eu.kanade.tachiyomi.extension.en.tsumino.TsuminoUtils.Companion.getChapter import eu.kanade.tachiyomi.extension.en.tsumino.TsuminoUtils.Companion.getCollection @@ -160,13 +161,13 @@ class Tsumino : HttpSource() { val document = response.asJsoup() val infoElement = document.select("div.book-page-container") return SManga.create().apply { - title = infoElement.select("#Title").text() + title = document.select("meta[property=og:title]").first()!!.attr("content") artist = getArtists(document) author = artist status = SManga.COMPLETED thumbnail_url = infoElement.select("img").attr("src") description = getDesc(document) - genre = document.select("#Tag a").joinToString { it.text() } + genre = document.select("#Tag a").joinToString { it.attr("data-define") } } } @@ -174,6 +175,8 @@ class Tsumino : HttpSource() { override fun chapterListParse(response: Response): List { val document = response.asJsoup() + cfDecodeEmails(document) + val collection = document.select(".book-collection-table a") return if (collection.isNotEmpty()) { getCollection(document, ".book-collection-table a") diff --git a/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/TsuminoUtils.kt b/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/TsuminoUtils.kt index de048573f..39b49c9b1 100644 --- a/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/TsuminoUtils.kt +++ b/src/en/tsumino/src/eu/kanade/tachiyomi/extension/en/tsumino/TsuminoUtils.kt @@ -11,7 +11,7 @@ class TsuminoUtils { val artists = document.select("#Artist a") artists.forEach { - stringBuilder.append(it.text()) + stringBuilder.append(it.attr("data-define")) if (it != artists.last()) stringBuilder.append(", ") @@ -25,7 +25,7 @@ class TsuminoUtils { val groups = document.select("#Group a") groups.forEach { - stringBuilder.append(it.text()) + stringBuilder.append(it.attr("data-define")) if (it != groups.last()) stringBuilder.append(", ") @@ -47,7 +47,7 @@ class TsuminoUtils { stringBuilder.append("Parodies: ") parodies.forEach { - stringBuilder.append(it.text()) + stringBuilder.append(it.attr("data-define")) if (it != parodies.last()) stringBuilder.append(", ") @@ -59,7 +59,7 @@ class TsuminoUtils { stringBuilder.append("Characters: ") characters.forEach { - stringBuilder.append(it.text()) + stringBuilder.append(it.attr("data-define")) if (it != characters.last()) stringBuilder.append(", ") @@ -93,5 +93,26 @@ class TsuminoUtils { chapterList.add(chapter) return chapterList } + + fun cfDecodeEmails(document: Document) { + document.select(".__cf_email__")!! + .map { it to cfDecodeEmail(it.attr("data-cfemail")) } + .forEach { (element, plaintext) -> element.text(plaintext) } + } + + fun cfDecodeEmail(encoded: String): String { + val encodedList = encoded + .chunked(2) + .map { it.toIntOrNull(16) } + + val key = encodedList + .firstOrNull() + ?: return "" + + return encodedList + .drop(1) + .mapNotNull { it?.xor(key)?.toChar() } + .joinToString("") + } } }