diff --git a/app/build.gradle b/app/build.gradle index b9d3d155..df5dde57 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -155,6 +155,8 @@ dependencies { debugImplementation "com.github.ChuckerTeam.Chucker:library:3.0.1" releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1" + + implementation 'com.github.wulkanowy:uonet-request-signer:master-SNAPSHOT' } repositories { mavenCentral() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt index 465ea051..178b3bc9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt @@ -51,19 +51,20 @@ val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT const val VULCAN_API_USER_AGENT = "MobileUserAgent" const val VULCAN_API_APP_NAME = "VULCAN-Android-ModulUcznia" const val VULCAN_API_APP_VERSION = "19.4.1.436" +const val VULCAN_API_PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06" val VULCAN_API_DEVICE_NAME = "Szkolny.eu ${Build.MODEL}" -const val VULCAN_API_ENDPOINT_CERTIFICATE = "mobile-api/Uczen.v3.UczenStart/Certyfikat"; -const val VULCAN_API_ENDPOINT_STUDENT_LIST = "mobile-api/Uczen.v3.UczenStart/ListaUczniow"; -const val VULCAN_API_ENDPOINT_DICTIONARIES = "mobile-api/Uczen.v3.Uczen/Slowniki"; -const val VULCAN_API_ENDPOINT_TIMETABLE = "mobile-api/Uczen.v3.Uczen/PlanLekcjiZeZmianami"; -const val VULCAN_API_ENDPOINT_GRADES = "mobile-api/Uczen.v3.Uczen/Oceny"; -const val VULCAN_API_ENDPOINT_GRADES_PROPOSITIONS = "mobile-api/Uczen.v3.Uczen/OcenyPodsumowanie"; -const val VULCAN_API_ENDPOINT_EVENTS = "mobile-api/Uczen.v3.Uczen/Sprawdziany"; -const val VULCAN_API_ENDPOINT_HOMEWORK = "mobile-api/Uczen.v3.Uczen/ZadaniaDomowe"; -const val VULCAN_API_ENDPOINT_NOTICES = "mobile-api/Uczen.v3.Uczen/UwagiUcznia"; -const val VULCAN_API_ENDPOINT_ATTENDANCE = "mobile-api/Uczen.v3.Uczen/Frekwencje"; -const val VULCAN_API_ENDPOINT_MESSAGES_RECEIVED = "mobile-api/Uczen.v3.Uczen/WiadomosciOdebrane"; -const val VULCAN_API_ENDPOINT_MESSAGES_SENT = "mobile-api/Uczen.v3.Uczen/WiadomosciWyslane"; -const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci"; -const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken"; \ No newline at end of file +const val VULCAN_API_ENDPOINT_CERTIFICATE = "mobile-api/Uczen.v3.UczenStart/Certyfikat" +const val VULCAN_API_ENDPOINT_STUDENT_LIST = "mobile-api/Uczen.v3.UczenStart/ListaUczniow" +const val VULCAN_API_ENDPOINT_DICTIONARIES = "mobile-api/Uczen.v3.Uczen/Slowniki" +const val VULCAN_API_ENDPOINT_TIMETABLE = "mobile-api/Uczen.v3.Uczen/PlanLekcjiZeZmianami" +const val VULCAN_API_ENDPOINT_GRADES = "mobile-api/Uczen.v3.Uczen/Oceny" +const val VULCAN_API_ENDPOINT_GRADES_PROPOSITIONS = "mobile-api/Uczen.v3.Uczen/OcenyPodsumowanie" +const val VULCAN_API_ENDPOINT_EVENTS = "mobile-api/Uczen.v3.Uczen/Sprawdziany" +const val VULCAN_API_ENDPOINT_HOMEWORK = "mobile-api/Uczen.v3.Uczen/ZadaniaDomowe" +const val VULCAN_API_ENDPOINT_NOTICES = "mobile-api/Uczen.v3.Uczen/UwagiUcznia" +const val VULCAN_API_ENDPOINT_ATTENDANCE = "mobile-api/Uczen.v3.Uczen/Frekwencje" +const val VULCAN_API_ENDPOINT_MESSAGES_RECEIVED = "mobile-api/Uczen.v3.Uczen/WiadomosciOdebrane" +const val VULCAN_API_ENDPOINT_MESSAGES_SENT = "mobile-api/Uczen.v3.Uczen/WiadomosciWyslane" +const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci" +const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt index 229ff405..bad56ff6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt @@ -126,4 +126,5 @@ const val EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN = 902 const val EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903 const val EXCEPTION_LIBRUS_API_REQUEST = 904 const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 905 -const val EXCEPTION_NOTIFY_AND_SYNC = 910 \ No newline at end of file +const val EXCEPTION_VULCAN_API_REQUEST = 906 +const val EXCEPTION_NOTIFY_AND_SYNC = 910 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/DataVulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/DataVulcan.kt index d19a95af..fd3b1d22 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/DataVulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/DataVulcan.kt @@ -169,4 +169,9 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app else -> null } } + + val fullApiUrl: String? + get() { + return "${apiUrl}${schoolSymbol}/" + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanApi.kt new file mode 100644 index 00000000..5d818426 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanApi.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2019-10-19 + */ + +package pl.szczodrzynski.edziennik.api.v2.vulcan.data + +import com.google.gson.JsonObject +import im.wangchao.mhttp.Request +import im.wangchao.mhttp.Response +import im.wangchao.mhttp.callback.JsonCallbackHandler +import io.github.wulkanowy.signer.signContent +import pl.szczodrzynski.edziennik.api.v2.* +import pl.szczodrzynski.edziennik.api.v2.models.ApiError +import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.utils.Utils.d +import java.net.HttpURLConnection +import java.util.* + +open class VulcanApi(open val data: DataVulcan) { + companion object { + const val TAG = "VulcanApi" + } + + val profileId + get() = data.profile?.id ?: -1 + + val profile + get() = data.profile + + fun apiGet(tag: String, endpoint: String, method: Int = POST, payload: JsonObject? = null, onSuccess: (json: JsonObject) -> Unit) { + d(tag, "Request: Librus/Api - ${data.fullApiUrl}/$endpoint") + + val finalPayload = JsonObject() + finalPayload.addProperty("IdUczen", data.studentId) + finalPayload.addProperty("IdOkresKlasyfikacyjny", data.studentSemesterId) + finalPayload.addProperty("IdOddzial", data.studentClassId) + finalPayload.addProperty("RemoteMobileTimeKey", System.currentTimeMillis() / 1000) + finalPayload.addProperty("TimeKey", System.currentTimeMillis() / 1000 - 1) + finalPayload.addProperty("RequestId", UUID.randomUUID().toString()) + finalPayload.addProperty("RemoteMobileAppVersion", VULCAN_API_APP_VERSION) + finalPayload.addProperty("RemoteMobileAppName", VULCAN_API_APP_NAME) + + val callback = object : JsonCallbackHandler() { + override fun onSuccess(json: JsonObject?, response: Response?) { + if (json == null && response?.parserErrorBody == null) { + data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY) + .withResponse(response)) + return + } + + // TODO: Vulcan error handling + + if (json == null) { + data.error(ApiError(tag, ERROR_RESPONSE_EMPTY) + .withResponse(response)) + return + } + + try { + onSuccess(json) + } catch (e: Exception) { + data.error(ApiError(tag, EXCEPTION_VULCAN_API_REQUEST) + .withResponse(response) + .withThrowable(e) + .withApiResponse(json)) + } + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + data.error(ApiError(tag, ERROR_REQUEST_FAILURE) + .withResponse(response) + .withThrowable(throwable)) + } + } + + Request.builder() + .url("${data.fullApiUrl}$endpoint") + .userAgent(VULCAN_API_USER_AGENT) + .addHeader("RequestCertificateKey", data.apiCertificateKey) + .addHeader("RequestSignatureValue", + signContent(VULCAN_API_PASSWORD, data.apiCertificatePfx, finalPayload.toString())) + .apply { + when (method) { + GET -> get() + POST -> post() + } + } + .setJsonBody(finalPayload) + .allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST) + .allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN) + .allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED) + .callback(callback) + .build() + .enqueue() + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt index 1023cb4f..fb2dc15d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt @@ -4,7 +4,10 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan.data +import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_GRADES +import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiGrades import pl.szczodrzynski.edziennik.utils.Utils class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { @@ -35,11 +38,11 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) { Utils.d(TAG, "Using endpoint $endpointId") when (endpointId) { - /*ENDPOINT_VULCAN_API -> { - data.startProgress(R.string.edziennik_progress_endpoint_data) - VulcanApi(data) { onSuccess() } - }*/ + ENDPOINT_VULCAN_API_GRADES -> { + data.startProgress(R.string.edziennik_progress_endpoint_grades) + VulcanApiGrades(data) { onSuccess() } + } else -> onSuccess() } } -} \ No newline at end of file +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiGrades.kt new file mode 100644 index 00000000..7818ed00 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiGrades.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2019-10-19 + */ + +package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api + +import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_GRADES +import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_GRADES +import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi +import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.getJsonArray + +class VulcanApiGrades(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) { + companion object { + const val TAG = "VulcanApiGrades" + } + + init { + apiGet(TAG, VULCAN_API_ENDPOINT_GRADES) { json -> + val grades = json.getJsonArray("Data") + + data.setSyncNext(ENDPOINT_VULCAN_API_GRADES, SYNC_ALWAYS) + onSuccess() + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/login/VulcanLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/login/VulcanLoginApi.kt index be8e9aa9..abfa5c19 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/login/VulcanLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/login/VulcanLoginApi.kt @@ -13,7 +13,6 @@ import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.models.ApiError import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan -import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils.d import java.net.HttpURLConnection.HTTP_BAD_REQUEST import java.util.* @@ -131,4 +130,4 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) { .build() .enqueue() } -} \ No newline at end of file +}