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
This commit is contained in:
Vetle Ledaal 2022-02-09 11:14:22 +00:00 committed by GitHub
parent 383ba02bfc
commit 82d8a2f2ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 7 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'Tsumino'
pkgNameSuffix = 'en.tsumino'
extClass = '.Tsumino'
extVersionCode = 5
extVersionCode = 6
isNsfw = true
}

View File

@ -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<SChapter> {
val document = response.asJsoup()
cfDecodeEmails(document)
val collection = document.select(".book-collection-table a")
return if (collection.isNotEmpty()) {
getCollection(document, ".book-collection-table a")

View File

@ -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("")
}
}
}