diff --git a/build.gradle b/build.gradle index 13ef32a9..f3ae0fae 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ ext { moshi = "1.13.0" } -version = "2.6.9" +version = "2.6.10-SNAPSHOT" group = "io.github.wulkanowy" nexusPublishing { diff --git a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/ApiEndpoints.kt b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/ApiEndpoints.kt index 7bf8ca3c..c09f0ca4 100644 --- a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/ApiEndpoints.kt +++ b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/ApiEndpoints.kt @@ -630,6 +630,27 @@ internal val ApiEndpointsVTokenMap = mapOf( "Usuniete" to "6fb7f517-7287-41c3-8d30-64e654f647a7", "UsunieteSkrzynka" to "937cd3ba-6fa9-4e44-bb99-e4fd282803c2", ), + "uonetplus-uczenplus" to mapOf( + "Context" to "cbdc1e7c-612f-4b7d-911d-c76701a0bd41", + "Frekwencja" to "04921511-8b5f-44fc-8d2c-d9c5157393d1", + "Usprawiedliwienia" to "0e579c35-e3e0-466c-ae2c-82b2b972097f", + "FrekwencjaStatystyki" to "39dccbf3-8a04-41b1-a48d-8c056dff702c", + "ZarejestrowaneUrzadzenia" to "06b04925-c003-4a53-8f9e-b720e368862a", + "Zebrania" to "968f86f2-92a0-4f6e-b22c-4791e3362554", + "RealizacjaZajec" to "3e1c3fb2-1b8a-4579-b7d8-ea2cfa263d42", + "SprawdzianyZadaniaDomowe" to "bf7d0726-7979-4aee-89e2-9b74bbe0820d", + "SprawdzianSzczegoly" to "3dcff009-c0ad-4b7f-95eb-18be7e3b9019", + "ZadanieDomoweSzczegoly" to "2d8b6288-1f13-4ca7-bb6f-334de9a663d0", + "PlanZajec" to "acd3f4c1-f366-41a4-b2a1-c3543d173ec7", + "DniWolne" to "f28b5242-c33a-4ef3-8c3d-e8fb4d39f801", + "Uwagi" to "1a0d8d8b-de01-4fe7-ae28-8fed2d68e9b5", + "Nauczyciele" to "ce89218b-4609-4e10-92aa-217521e5d99a", + "Informacje" to "984449a8-907b-4488-9f90-8f0c6e56c03c", + "DaneUcznia" to "64348eca-82d1-442a-acc3-4886ca5daa33", + "UczenZdjecie" to "4ed033b1-f8f4-4ca1-b277-60be0f80ab0f", + "OkresyKlasyfikacyjne" to "6ff9273a-fb69-417d-aca9-d60ecceaad26", + "Oceny" to "86f8dd7b-e144-42d9-a389-0648503a479d", + ), ), "24.04.0008.58830" to mapOf( "uonetplus-wiadomosciplus" to mapOf( @@ -644,24 +665,38 @@ internal val ApiEndpointsVTokenMap = mapOf( ), ) -internal val ApiEndpointsVTokenSchemeMap = mapOf( +internal val ApiEndpointsVHeaders = mapOf( "24.04.0003.58698" to mapOf( - "uonetplus-wiadomosciplus" to "{UUID}-{name}-{appCustomerDb}-{appVersion}", + "uonetplus-wiadomosciplus" to mapOf( + "V-Token" to "{UUID}-{name}-{appCustomerDb}-{appVersion}", + ), ), "24.04.0004.58722" to mapOf( - "uonetplus-wiadomosciplus" to "{UUID}-{appCustomerDb}-{appVersion}", + "uonetplus-wiadomosciplus" to mapOf( + "V-Token" to "{UUID}-{appCustomerDb}-{appVersion}", + ), ), "24.04.0005.58736" to mapOf( - "uonetplus-wiadomosciplus" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", + "uonetplus-wiadomosciplus" to mapOf( + "V-Token" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", + ), ), "24.04.0006.58753" to mapOf( - "uonetplus-wiadomosciplus" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", + "uonetplus-wiadomosciplus" to mapOf( + "V-Token" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", + ), ), "24.04.0007.58773" to mapOf( - "uonetplus-wiadomosciplus" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", - "uonetplus-uczenplus" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", + "uonetplus-wiadomosciplus" to mapOf( + "V-Token" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", + ), + "uonetplus-uczenplus" to mapOf( + "V-Token" to "{UUID}-{appCustomerDb}-{appVersion}-{apiKey}", + ), ), "24.04.0008.58830" to mapOf( - "uonetplus-wiadomosciplus" to "{UUID}-{appCustomerDb}-{appCustomerDbSig}-{appVersion}-{apiKey}", + "uonetplus-wiadomosciplus" to mapOf( + "V-Apitoken" to "{UUID}-{appCustomerDb}-{appCustomerDbSig}-{appVersion}-{apiKey}", + ), ), ) diff --git a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Scrapper.kt b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Scrapper.kt index 17c07fff..6ea9a4df 100644 --- a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Scrapper.kt +++ b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Scrapper.kt @@ -224,10 +224,10 @@ class Scrapper { vTokenMap = value } - var vTokenSchemeMapping: Map> - get() = vTokenSchemeMap + var vHeaders: Map>> + get() = vHeadersMap set(value) { - vTokenSchemeMap = value + vHeadersMap = value } var vParamsEvaluation: suspend () -> EvaluateHandler @@ -239,7 +239,7 @@ class Scrapper { internal companion object { var endpointsMap: Map>> = ApiEndpointsMap var vTokenMap: Map>> = ApiEndpointsVTokenMap - var vTokenSchemeMap: Map> = ApiEndpointsVTokenSchemeMap + var vHeadersMap: Map>> = ApiEndpointsVHeaders var vParamsRun: suspend () -> EvaluateHandler = { object : EvaluateHandler {} } } diff --git a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Utils.kt b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Utils.kt index bd27d062..c0ca88b4 100644 --- a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Utils.kt +++ b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/Utils.kt @@ -15,7 +15,6 @@ import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.Request import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.slf4j.LoggerFactory @@ -307,13 +306,22 @@ internal suspend fun getModuleHeadersFromDocument(document: Document): ModuleHea ) } -internal fun Request.Builder.attachVToken(moduleHost: String, url: HttpUrl, headers: ModuleHeaders?): Request.Builder { - val vToken = url.getMatchedVToken(moduleHost, headers) ?: return this - addHeader("V-Apitoken", vToken) - return this +internal fun getVHeaders(moduleHost: String, url: HttpUrl, headers: ModuleHeaders?): Map { + val vHeaders = Scrapper.vHeadersMap[headers?.appVersion] ?: ApiEndpointsVHeaders[headers?.appVersion] + + return vHeaders?.get(moduleHost).orEmpty().mapNotNull { (key, scheme) -> + val headerValue = url.getMatchedVHeader( + moduleHost = moduleHost, + domainSchema = scheme, + headers = headers, + ) + if (headerValue != null) { + key to headerValue + } else null + }.toMap() } -internal fun HttpUrl.getMatchedVToken(moduleHost: String, headers: ModuleHeaders?): String? { +private fun HttpUrl.getMatchedVHeader(moduleHost: String, domainSchema: String?, headers: ModuleHeaders?): String? { val pathSegmentIndex = getPathIndexByModuleHost(moduleHost) val pathKey = pathSegments.getOrNull(pathSegmentIndex) val mappedUuid = (Scrapper.vTokenMap[headers?.appVersion] ?: ApiEndpointsVTokenMap[headers?.appVersion]) @@ -321,17 +329,19 @@ internal fun HttpUrl.getMatchedVToken(moduleHost: String, headers: ModuleHeaders ?.get(pathKey) ?: return null - return getVToken(mappedUuid, headers, moduleHost) + return getVToken( + uuid = mappedUuid, + headers = headers, + domainSchema = domainSchema, + ) } private val vTokenSchemeKeysRegex = "\\{([^{}]+)\\}".toRegex() -private fun getVToken(uuid: String, headers: ModuleHeaders?, moduleHost: String): String? { +private fun getVToken(uuid: String, headers: ModuleHeaders?, domainSchema: String?): String? { if (uuid.isBlank()) return null - val schemeToSubstitute = (Scrapper.vTokenSchemeMap[headers?.appVersion] ?: ApiEndpointsVTokenSchemeMap[headers?.appVersion]) - ?.get(moduleHost) - ?: "{UUID}-{appCustomerDb}-{appCustomerDbSig}-{appVersion}-{apiKey}" + val schemeToSubstitute = domainSchema ?: "{UUID}-{appCustomerDb}-{appCustomerDbSig}-{appVersion}-{apiKey}" val vTokenEncoded = runCatching { vTokenSchemeKeysRegex.replace(schemeToSubstitute) { diff --git a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/interceptor/AutoLoginInterceptor.kt b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/interceptor/AutoLoginInterceptor.kt index 416a892c..040ce479 100644 --- a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/interceptor/AutoLoginInterceptor.kt +++ b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/interceptor/AutoLoginInterceptor.kt @@ -9,10 +9,10 @@ import io.github.wulkanowy.sdk.scrapper.Scrapper.LoginType.ADFSLight import io.github.wulkanowy.sdk.scrapper.Scrapper.LoginType.ADFSLightCufs import io.github.wulkanowy.sdk.scrapper.Scrapper.LoginType.ADFSLightScoped import io.github.wulkanowy.sdk.scrapper.Scrapper.LoginType.STANDARD -import io.github.wulkanowy.sdk.scrapper.attachVToken import io.github.wulkanowy.sdk.scrapper.exception.VulcanClientError import io.github.wulkanowy.sdk.scrapper.exception.VulcanServerError import io.github.wulkanowy.sdk.scrapper.getModuleHeadersFromDocument +import io.github.wulkanowy.sdk.scrapper.getVHeaders import io.github.wulkanowy.sdk.scrapper.isAnyMappingAvailable import io.github.wulkanowy.sdk.scrapper.login.LoginModuleResult import io.github.wulkanowy.sdk.scrapper.login.LoginResult @@ -176,7 +176,14 @@ internal class AutoLoginInterceptor( addHeader("X-V-RequestVerificationToken", it.token) addHeader("X-V-AppGuid", it.appGuid) addHeader("X-V-AppVersion", it.appVersion) - attachVToken(moduleHost, url, headers) + + getVHeaders( + moduleHost = moduleHost, + url = url, + headers = headers, + ).forEach { (key, headerValue) -> + addHeader(key, headerValue) + } } } .url(mappedUrl) diff --git a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/repository/RegisterRepository.kt b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/repository/RegisterRepository.kt index d7006bc3..88ad7558 100644 --- a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/repository/RegisterRepository.kt +++ b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/repository/RegisterRepository.kt @@ -3,10 +3,10 @@ package io.github.wulkanowy.sdk.scrapper.repository import io.github.wulkanowy.sdk.scrapper.Scrapper import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException import io.github.wulkanowy.sdk.scrapper.exception.StudentGraduateException -import io.github.wulkanowy.sdk.scrapper.getMatchedVToken import io.github.wulkanowy.sdk.scrapper.getModuleHeadersFromDocument import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol import io.github.wulkanowy.sdk.scrapper.getScriptParam +import io.github.wulkanowy.sdk.scrapper.getVHeaders import io.github.wulkanowy.sdk.scrapper.interceptor.StudentModuleHost import io.github.wulkanowy.sdk.scrapper.interceptor.StudentPlusModuleHost import io.github.wulkanowy.sdk.scrapper.interceptor.handleErrors @@ -41,7 +41,6 @@ import org.jsoup.nodes.Element import org.jsoup.parser.Parser import org.jsoup.select.Elements import org.slf4j.LoggerFactory -import pl.droidsonroids.jspoon.Jspoon import kotlin.io.encoding.ExperimentalEncodingApi @Suppress("UnnecessaryOptInAnnotation") @@ -63,10 +62,6 @@ internal class RegisterRepository( private val logger = LoggerFactory.getLogger(this::class.java) } - private val certificateAdapter by lazy { - Jspoon.create().adapter(CertificateResponse::class.java) - } - suspend fun getUserSubjects(): RegisterUser { val symbolLoginType = getLoginType(startSymbol.getNormalizedSymbol()) val certificateResponse = getCert(symbolLoginType) @@ -350,21 +345,21 @@ internal class RegisterRepository( val moduleHeaders = getModuleHeadersFromDocument(homepage) val baseStudentPlus = url.generate(UrlGenerator.Site.STUDENT_PLUS) val contextUrl = (baseStudentPlus + "api/Context").toHttpUrl() - val contextVToken = contextUrl.getMatchedVToken(StudentPlusModuleHost, moduleHeaders) + val contextVHeaders = getVHeaders(StudentPlusModuleHost, contextUrl, moduleHeaders) val mappedContextUrl = contextUrl.mapModuleUrl(StudentPlusModuleHost, moduleHeaders.appVersion) val semestersUrl = (baseStudentPlus + "api/OkresyKlasyfikacyjne").toHttpUrl() - val semestersVToken = semestersUrl.getMatchedVToken(StudentPlusModuleHost, moduleHeaders) + val semesterVHeaders = getVHeaders(StudentPlusModuleHost, semestersUrl, moduleHeaders) val mappedSemestersUrl = semestersUrl.mapModuleUrl(StudentPlusModuleHost, moduleHeaders.appVersion) return studentPlus - .getContextByUrl(vToken = contextVToken, url = mappedContextUrl.toString()).students + .getContextByUrl(vHeaders = contextVHeaders, url = mappedContextUrl.toString()).students .map { contextStudent -> val semesters = runCatching { when { contextStudent.isAuthorizationRequired -> emptyList() else -> studentPlus.getSemestersByUrl( - vToken = semestersVToken, + vHeaders = semesterVHeaders, url = mappedSemestersUrl.toString(), key = contextStudent.key, diaryId = contextStudent.registerId, diff --git a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/service/StudentPlusService.kt b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/service/StudentPlusService.kt index 5e2262f1..6c47667c 100644 --- a/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/service/StudentPlusService.kt +++ b/sdk-scrapper/src/main/kotlin/io/github/wulkanowy/sdk/scrapper/service/StudentPlusService.kt @@ -26,6 +26,7 @@ import retrofit2.Response import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header +import retrofit2.http.HeaderMap import retrofit2.http.POST import retrofit2.http.Query import retrofit2.http.Url @@ -36,13 +37,13 @@ internal interface StudentPlusService { @GET suspend fun getContextByUrl( - @Header("V-Apitoken") vToken: String?, + @HeaderMap vHeaders: Map, @Url url: String, ): ContextResponse @GET suspend fun getSemestersByUrl( - @Header("V-Apitoken") vToken: String?, + @HeaderMap vHeaders: Map, @Url url: String, @Query("key") key: String, @Query("idDziennik") diaryId: Int, diff --git a/sdk/src/main/kotlin/io/github/wulkanowy/sdk/Sdk.kt b/sdk/src/main/kotlin/io/github/wulkanowy/sdk/Sdk.kt index 630082fd..8fe3eadc 100644 --- a/sdk/src/main/kotlin/io/github/wulkanowy/sdk/Sdk.kt +++ b/sdk/src/main/kotlin/io/github/wulkanowy/sdk/Sdk.kt @@ -248,10 +248,10 @@ class Sdk { scrapper.vTokenMapping = value } - var vTokenSchemeMapping - get() = scrapper.vTokenSchemeMapping + var vHeaders + get() = scrapper.vHeaders set(value) { - scrapper.vTokenSchemeMapping = value + scrapper.vHeaders = value } var vParamsEvaluation: suspend () -> EvaluateHandler