Add vparam js evaluation
This commit is contained in:
parent
0989dc2442
commit
1eeea1e249
8 changed files with 80 additions and 19 deletions
|
@ -1,3 +1,13 @@
|
|||
public abstract interface class io/github/wulkanowy/sdk/scrapper/EvaluateHandler : java/io/Closeable {
|
||||
public abstract fun close ()V
|
||||
public abstract fun evaluate (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class io/github/wulkanowy/sdk/scrapper/EvaluateHandler$DefaultImpls {
|
||||
public static fun close (Lio/github/wulkanowy/sdk/scrapper/EvaluateHandler;)V
|
||||
public static fun evaluate (Lio/github/wulkanowy/sdk/scrapper/EvaluateHandler;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class io/github/wulkanowy/sdk/scrapper/Scrapper {
|
||||
public fun <init> ()V
|
||||
public final fun addInterceptor (Lokhttp3/Interceptor;Z)V
|
||||
|
@ -82,6 +92,7 @@ public final class io/github/wulkanowy/sdk/scrapper/Scrapper {
|
|||
public final fun getUserAgent ()Ljava/lang/String;
|
||||
public final fun getUserAgentTemplate ()Ljava/lang/String;
|
||||
public final fun getUserSubjects (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun getVParamsEvaluation ()Lkotlin/jvm/functions/Function1;
|
||||
public final fun getVTokenMapping ()Ljava/util/Map;
|
||||
public final fun getVTokenSchemeMapping ()Ljava/util/Map;
|
||||
public final fun isEduOne ()Z
|
||||
|
@ -112,6 +123,7 @@ public final class io/github/wulkanowy/sdk/scrapper/Scrapper {
|
|||
public final fun setSymbol (Ljava/lang/String;)V
|
||||
public final fun setUnitId (I)V
|
||||
public final fun setUserAgentTemplate (Ljava/lang/String;)V
|
||||
public final fun setVParamsEvaluation (Lkotlin/jvm/functions/Function1;)V
|
||||
public final fun setVTokenMapping (Ljava/util/Map;)V
|
||||
public final fun setVTokenSchemeMapping (Ljava/util/Map;)V
|
||||
public final fun unregisterDevice (ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package io.github.wulkanowy.sdk.scrapper
|
||||
|
||||
import java.io.Closeable
|
||||
|
||||
interface EvaluateHandler : Closeable {
|
||||
|
||||
suspend fun evaluate(code: String): String? = null
|
||||
|
||||
override fun close() = Unit
|
||||
}
|
|
@ -230,10 +230,17 @@ class Scrapper {
|
|||
vTokenSchemeMap = value
|
||||
}
|
||||
|
||||
var vParamsEvaluation: suspend () -> EvaluateHandler
|
||||
get() = vParamsRun
|
||||
set(value) {
|
||||
vParamsRun = value
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
var endpointsMap: Map<String, Map<String, Map<String, String>>> = ApiEndpointsMap
|
||||
var vTokenMap: Map<String, Map<String, Map<String, String>>> = ApiEndpointsVTokenMap
|
||||
var vTokenSchemeMap: Map<String, Map<String, String>> = ApiEndpointsVTokenSchemeMap
|
||||
var vParamsRun: suspend () -> EvaluateHandler = { object : EvaluateHandler {} }
|
||||
}
|
||||
|
||||
private val appInterceptors: MutableList<Pair<Interceptor, Boolean>> = mutableListOf()
|
||||
|
|
|
@ -8,6 +8,11 @@ import io.github.wulkanowy.sdk.scrapper.login.UrlGenerator
|
|||
import io.github.wulkanowy.sdk.scrapper.messages.Mailbox
|
||||
import io.github.wulkanowy.sdk.scrapper.messages.Recipient
|
||||
import io.github.wulkanowy.sdk.scrapper.messages.RecipientType
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
|
@ -258,25 +263,47 @@ internal fun getPathIndexByModuleHost(moduleHost: String): Int = when (moduleHos
|
|||
|
||||
private val vParamsRegex = "([a-zA-Z]+)\\s*:\\s*'([^']*)'".toRegex()
|
||||
|
||||
internal fun getModuleHeadersFromDocument(document: Document): ModuleHeaders {
|
||||
internal suspend fun getModuleHeadersFromDocument(document: Document): ModuleHeaders {
|
||||
val htmlContent = document.select("script").html()
|
||||
val matches = vParamsRegex.findAll(htmlContent)
|
||||
|
||||
val scripts = document.select("script").toList()
|
||||
.filter { it.attr("src").isNullOrBlank() }
|
||||
.map { it.html() }
|
||||
|
||||
val evaluatedJs = runBlocking {
|
||||
Scrapper.vParamsRun().use { handler ->
|
||||
scripts.map {
|
||||
runCatching {
|
||||
val result = handler.evaluate("var window = this; $it; JSON.stringify(VParam)")
|
||||
result?.let { Json.parseToJsonElement(it) }?.jsonObject?.toMap().orEmpty()
|
||||
}.getOrDefault(emptyMap())
|
||||
}
|
||||
}
|
||||
}.flatMap { it.toList() }.toMap()
|
||||
.mapValues {
|
||||
when (it.value) {
|
||||
is JsonPrimitive -> it.value.jsonPrimitive.content
|
||||
else -> it.value.toString()
|
||||
}
|
||||
}
|
||||
|
||||
return ModuleHeaders(
|
||||
token = getScriptParam("antiForgeryToken", htmlContent),
|
||||
appGuid = getScriptParam("appGuid", htmlContent),
|
||||
appVersion = getScriptParam("version", htmlContent).ifBlank {
|
||||
getScriptParam("appVersion", htmlContent)
|
||||
},
|
||||
apiKey = getApiKey(document),
|
||||
email = getScriptParam("name", htmlContent),
|
||||
symbol = getScriptParam("appCustomerDb", htmlContent),
|
||||
vParams = matches.toList().associate { match ->
|
||||
vParamsRaw = matches.toList().associate { match ->
|
||||
if (match.groupValues.size == 3) {
|
||||
match.groupValues[1] to match.groupValues[2]
|
||||
} else {
|
||||
null to null
|
||||
}
|
||||
},
|
||||
} + mapOf("apiKey" to getApiKey(document)),
|
||||
vParamsEvaluated = evaluatedJs,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -302,29 +329,25 @@ private val vTokenSchemeKeysRegex = "\\{([^{}]+)\\}".toRegex()
|
|||
private fun getVToken(uuid: String, headers: ModuleHeaders?, moduleHost: String): String? {
|
||||
if (uuid.isBlank()) return null
|
||||
|
||||
val scheme = Scrapper.vTokenSchemeMap[headers?.appVersion]
|
||||
val schemeToSubstitute = Scrapper.vTokenSchemeMap[headers?.appVersion]
|
||||
?.get(moduleHost)
|
||||
?: "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}"
|
||||
val schemeToSubstitute = scheme
|
||||
.replace("{UUID}", uuid)
|
||||
.let { updatedScheme ->
|
||||
headers?.apiKey?.takeIf { it.isNotBlank() }?.let {
|
||||
updatedScheme.replace("{apiKey}", it)
|
||||
} ?: updatedScheme
|
||||
}
|
||||
|
||||
val vTokenEncoded = runCatching {
|
||||
vTokenSchemeKeysRegex.replace(schemeToSubstitute) {
|
||||
val key = it.groupValues[1]
|
||||
headers?.vParams.orEmpty()[key] ?: key
|
||||
val headersRaw = headers?.vParamsRaw.orEmpty()[key]
|
||||
val headerEvaluated = headers?.vParamsEvaluated.orEmpty()[key]
|
||||
headerEvaluated ?: headersRaw ?: "{$key}"
|
||||
}
|
||||
}.onFailure {
|
||||
logger.error("Error preparing vtoken!", it)
|
||||
logger.error("Error preparing vToken!", it)
|
||||
}.getOrDefault(
|
||||
schemeToSubstitute
|
||||
.replace("{appCustomerDb}", headers?.symbol.orEmpty())
|
||||
.replace("{appVersion}", headers?.appVersion.orEmpty()),
|
||||
.replace("{appVersion}", headers?.appVersion.orEmpty())
|
||||
.replace("{email}", headers?.email.orEmpty()),
|
||||
)
|
||||
|
||||
return vTokenEncoded.md5()
|
||||
return vTokenEncoded.replace("{UUID}", uuid).md5()
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ internal class AutoLoginInterceptor(
|
|||
}
|
||||
|
||||
private fun saveModuleHeaders(doc: Document, url: HttpUrl) {
|
||||
val moduleHeaders = getModuleHeadersFromDocument(doc)
|
||||
val moduleHeaders = runBlocking { getModuleHeadersFromDocument(doc) }
|
||||
|
||||
if (moduleHeaders.token.isBlank()) {
|
||||
logger.info("There is no token found on $url")
|
||||
|
|
|
@ -4,8 +4,8 @@ internal data class ModuleHeaders(
|
|||
val token: String,
|
||||
val appGuid: String,
|
||||
val appVersion: String,
|
||||
val apiKey: String,
|
||||
val symbol: String? = null,
|
||||
val email: String? = null,
|
||||
val vParams: Map<String?, String?> = emptyMap(),
|
||||
val vParamsRaw: Map<String?, String?> = emptyMap(),
|
||||
val vParamsEvaluated: Map<String, String> = emptyMap(),
|
||||
)
|
||||
|
|
|
@ -90,6 +90,7 @@ public final class io/github/wulkanowy/sdk/Sdk {
|
|||
public final fun getUserSubjectsFromScrapper (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun getUserSubjectsFromScrapper (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public static synthetic fun getUserSubjectsFromScrapper$default (Lio/github/wulkanowy/sdk/Sdk;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
|
||||
public final fun getVParamsEvaluation ()Lkotlin/jvm/functions/Function1;
|
||||
public final fun getVTokenMapping ()Ljava/util/Map;
|
||||
public final fun getVTokenSchemeMapping ()Ljava/util/Map;
|
||||
public final fun isEduOne ()Z
|
||||
|
@ -123,6 +124,7 @@ public final class io/github/wulkanowy/sdk/Sdk {
|
|||
public final fun setSymbol (Ljava/lang/String;)V
|
||||
public final fun setUnitId (I)V
|
||||
public final fun setUserAgentTemplate (Ljava/lang/String;)V
|
||||
public final fun setVParamsEvaluation (Lkotlin/jvm/functions/Function1;)V
|
||||
public final fun setVTokenMapping (Ljava/util/Map;)V
|
||||
public final fun setVTokenSchemeMapping (Ljava/util/Map;)V
|
||||
public final fun switchDiary (III)Lio/github/wulkanowy/sdk/Sdk;
|
||||
|
|
|
@ -67,6 +67,7 @@ import io.github.wulkanowy.sdk.pojo.Subject
|
|||
import io.github.wulkanowy.sdk.pojo.Teacher
|
||||
import io.github.wulkanowy.sdk.pojo.Timetable
|
||||
import io.github.wulkanowy.sdk.pojo.Token
|
||||
import io.github.wulkanowy.sdk.scrapper.EvaluateHandler
|
||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -253,6 +254,12 @@ class Sdk {
|
|||
scrapper.vTokenSchemeMapping = value
|
||||
}
|
||||
|
||||
var vParamsEvaluation: suspend () -> EvaluateHandler
|
||||
get() = scrapper.vParamsEvaluation
|
||||
set(value) {
|
||||
scrapper.vParamsEvaluation = value
|
||||
}
|
||||
|
||||
var emptyCookieJarInterceptor: Boolean = false
|
||||
set(value) {
|
||||
field = value
|
||||
|
|
Loading…
Reference in a new issue