feat: apiKey parsing (#205)

Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
This commit is contained in:
londek 2024-05-15 13:02:34 +02:00 committed by GitHub
parent de2a887188
commit 660e075cce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 27 additions and 6 deletions

View file

@ -12,6 +12,7 @@ import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.slf4j.LoggerFactory
import retrofit2.HttpException
import retrofit2.Response
@ -75,6 +76,22 @@ internal fun getScriptParam(name: String, content: String, fallback: String = ""
}
}
internal fun getApiKey(document: Document, fallback: String = ""): String {
val script = document.getElementsByTag("script").toList()
.map { element -> element.html() }
.filter { text -> text.length < 500 }
.filter { text -> text.contains("VParam") && text.contains("apiKey") }
.firstOrNull()
if (script == null) {
return fallback
}
return "(\\d{5,8})".toRegex().find(script).let { result ->
if (null !== result) result.groupValues[1] else fallback
}
}
internal fun getScriptFlag(name: String, content: String, fallback: Boolean = false): Boolean {
return "$name: (false|true)".toRegex().find(content).let { result ->
if (null !== result) result.groupValues[1].toBoolean() else fallback
@ -244,7 +261,8 @@ internal fun getPathIndexByModuleHost(moduleHost: String): Int = when (moduleHos
private val vParamsRegex = "([a-zA-Z]+)\\s*:\\s*'([^']*)'".toRegex()
internal fun getModuleHeadersFromDocument(htmlContent: String): ModuleHeaders {
internal fun getModuleHeadersFromDocument(document: Document): ModuleHeaders {
val htmlContent = document.select("script").html()
val matches = vParamsRegex.findAll(htmlContent)
return ModuleHeaders(
token = getScriptParam("antiForgeryToken", htmlContent),
@ -252,6 +270,7 @@ internal fun getModuleHeadersFromDocument(htmlContent: String): ModuleHeaders {
appVersion = getScriptParam("version", htmlContent).ifBlank {
getScriptParam("appVersion", htmlContent)
},
apiKey = getApiKey(document),
email = getScriptParam("name", htmlContent),
symbol = getScriptParam("appCustomerDb", htmlContent),
vParams = matches.toList().associate { match ->
@ -289,12 +308,14 @@ private fun getVToken(uuid: String, headers: ModuleHeaders?, moduleHost: String)
val scheme = Scrapper.vTokenSchemeMap[headers?.appVersion]
?.get(moduleHost)
?: "{UUID}-{appCustomerDb}-{appVersion}"
val schemeToSubstitute = scheme.replace("{UUID}", uuid)
val schemeToSubstitute = scheme
.replace("{UUID}", uuid)
val vTokenEncoded = runCatching {
vTokenSchemeKeysRegex.replace(schemeToSubstitute) {
val key = it.groupValues[1]
headers?.vParams.orEmpty()[key] ?: key
val fallback = if (key == "apiKey") headers?.apiKey.orEmpty() else key
headers?.vParams.orEmpty()[key] ?: fallback
}
}.onFailure {
logger.error("Error preparing vtoken!", it)

View file

@ -142,8 +142,7 @@ internal class AutoLoginInterceptor(
}
private fun saveModuleHeaders(doc: Document, url: HttpUrl) {
val htmlContent = doc.select("script").html()
val moduleHeaders = getModuleHeadersFromDocument(htmlContent)
val moduleHeaders = getModuleHeadersFromDocument(doc)
if (moduleHeaders.token.isBlank()) {
logger.info("There is no token found on $url")

View file

@ -4,6 +4,7 @@ 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(),

View file

@ -343,7 +343,7 @@ internal class RegisterRepository(
}
private suspend fun getEduOneDiaries(baseStudentPlus: String, homepage: String): List<RegisterStudent> {
val moduleHeaders = getModuleHeadersFromDocument(homepage)
val moduleHeaders = getModuleHeadersFromDocument(Jsoup.parse(homepage))
val contextUrl = (baseStudentPlus + "api/Context").toHttpUrl()
val contextVToken = contextUrl.getMatchedVToken(StudentPlusModuleHost, moduleHeaders)