From 3fcd47cf915e1728235ad29ad69285373019da23 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sun, 17 May 2020 17:26:27 +0200 Subject: [PATCH] [API/Gdynia] Add web login. --- .../edziennik/data/api/Constants.kt | 4 + .../edziennik/data/api/Errors.kt | 4 + .../data/api/edziennik/gdynia/DataGdynia.kt | 39 ++++++ .../data/api/edziennik/gdynia/Gdynia.kt | 2 +- .../api/edziennik/gdynia/login/GdyniaLogin.kt | 54 ++++++++ .../edziennik/gdynia/login/GdyniaLoginWeb.kt | 118 ++++++++++++++++++ .../edziennik/podlasie/data/PodlasieApi.kt | 12 +- .../template/login/TemplateLoginWeb.kt | 6 - app/src/main/res/values/errors.xml | 8 ++ app/src/main/res/values/strings.xml | 3 +- 10 files changed, 235 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLogin.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLoginWeb.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index ee52cf1a..d524a6dc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -122,3 +122,7 @@ const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" const val PODLASIE_API_VERSION = "1.0.31" const val PODLASIE_API_URL = "https://cpdklaser.zeto.bialystok.pl/api" const val PODLASIE_API_USER_ENDPOINT = "/pobierzDaneUcznia" + +const val GDYNIA_WEB_URL = "https://nasze.miasto.gdynia.pl/ed_miej" +const val GDYNIA_WEB_LOGIN = "login.pl" +const val GDYNIA_WEB_LOGIN_CHECK = "login_check.pl" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index 8301f62f..6df17843 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -206,6 +206,10 @@ const val ERROR_PODLASIE_API_NO_TOKEN = 630 const val ERROR_PODLASIE_API_OTHER = 631 const val ERROR_PODLASIE_API_DATA_MISSING = 632 +const val ERROR_LOGIN_GDYNIA_WEB_INVALID_CREDENTIALS = 701 +const val ERROR_LOGIN_GDYNIA_WEB_MISSING_SESSION_ID = 709 +const val ERROR_LOGIN_GDYNIA_WEB_OTHER = 710 + const val ERROR_TEMPLATE_WEB_OTHER = 801 const val EXCEPTION_API_TASK = 900 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/DataGdynia.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/DataGdynia.kt index a94913e4..936e914a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/DataGdynia.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/DataGdynia.kt @@ -33,4 +33,43 @@ class DataGdynia(app: App, profile: Profile?, loginStore: LoginStore) : Data(app var loginPassword: String? get() { mLoginPassword = mLoginPassword ?: loginStore.getLoginData("password", null); return mLoginPassword } set(value) { loginStore.putLoginData("password", value); mLoginPassword = value } + + /* __ __ _ + \ \ / / | | + \ \ /\ / /__| |__ + \ \/ \/ / _ \ '_ \ + \ /\ / __/ |_) | + \/ \/ \___|_._*/ + + /* + .-. + _.--"""".o/ .-.-._ + __' ."""; { _J ,__ `. + ; o\.-.`._.'J; ; / `- / ; + `--i`". `" .'; `._ __.' | + \ `""" \ `; : + `."-. ; ____/ / + `-.` `-.-' `"-..' + ___ `;__.-'" `. + .-{_ `--._ /.-" `-. + / ""T ""---...' _.-"" """-. `. +; / __.-"". `. `, _.. + \ / __.-"" '. \ `.,__ .'L' } + `---"`-.__ __." .-. j `. : `. .' ,' / + """" / \ : `. | F' \ ; + ; `-._,L_,-""-. `-, ; ` ; / + `. 7 `-._ `.__/_ \/ + \ _; \ _.' `-. / + `---" `.___,, ;"" \ .' + _/ ; `" + .-" _,-' + { ""; + ;-.____.'`. + `. \ '. : + \ : : / + `':*/ + private var mWebSid: String? = null + var webSid: String? + get() { mWebSid = mWebSid ?: loginStore.getLoginData("webSid", null); return mWebSid } + set(value) { loginStore.putLoginData("webSid", value); mWebSid = value } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/Gdynia.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/Gdynia.kt index b6b44c4e..5e3cc3d6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/Gdynia.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/Gdynia.kt @@ -19,7 +19,7 @@ import pl.szczodrzynski.edziennik.utils.Utils class Gdynia(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface { companion object { - const val TAG = "Gdynia" +private const val TAG = "Gdynia" } val internalErrorList = mutableListOf() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLogin.kt new file mode 100644 index 00000000..5512523b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLogin.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2020-5-17 + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.gdynia.login + +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_GDYNIA_WEB +import pl.szczodrzynski.edziennik.data.api.edziennik.gdynia.DataGdynia +import pl.szczodrzynski.edziennik.utils.Utils + +class GdyniaLogin(val data: DataGdynia, val onSuccess: () -> Unit) { + companion object { +private const val TAG = "GdyniaLogin" + } + + init { + nextLoginMethod(onSuccess) + } + + private var cancelled = false + + private fun nextLoginMethod(onSuccess: () -> Unit) { + if (data.targetLoginMethodIds.isEmpty()) { + onSuccess() + return + } + if (cancelled) { + onSuccess() + return + } + useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + data.progress(data.progressStep) + if (usedMethodId != -1) + data.loginMethods.add(usedMethodId) + nextLoginMethod(onSuccess) + } + } + + private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + // this should never be true + if (data.loginMethods.contains(loginMethodId)) { + onSuccess(-1) + return + } + Utils.d(TAG, "Using login method $loginMethodId") + when (loginMethodId) { + LOGIN_METHOD_GDYNIA_WEB -> { + data.startProgress(R.string.edziennik_progress_login_gdynia_web) + GdyniaLoginWeb(data) { onSuccess(loginMethodId) } + } + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLoginWeb.kt new file mode 100644 index 00000000..1580b3a9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/gdynia/login/GdyniaLoginWeb.kt @@ -0,0 +1,118 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2020-5-17 + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.gdynia.login + +import im.wangchao.mhttp.Request +import im.wangchao.mhttp.Response +import im.wangchao.mhttp.callback.TextCallbackHandler +import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.data.api.edziennik.gdynia.DataGdynia +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.get +import pl.szczodrzynski.edziennik.isNotNullNorEmpty +import pl.szczodrzynski.edziennik.md5 + +class GdyniaLoginWeb(val data: DataGdynia, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "GdyniaLoginWeb" + } + + init { + run { + if (data.isWebLoginValid()) { + data.app.cookieJar.set("nasze.miasto.gdynia.pl", "sid", data.webSid) + onSuccess() + } else { + data.app.cookieJar.clear("nasze.miasto.gdynia.pl") + if (data.loginUsername.isNotNullNorEmpty() && data.loginPassword.isNotNullNorEmpty()) { + loginWithCredentials() + } else { + data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING)) + } + } + } + } + + private fun loginWithCredentials() { + val checkCallback = object : TextCallbackHandler() { + override fun onSuccess(text: String?, response: Response?) { + val cookies = data.app.cookieJar.getAll("nasze.miasto.gdynia.pl") + + data.webSid = cookies["sid"] + + onSuccess() + return + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + data.error(ApiError(TAG, ERROR_REQUEST_FAILURE) + .withResponse(response) + .withThrowable(throwable)) + } + } + + val loginCallback = object : TextCallbackHandler() { + override fun onSuccess(text: String?, response: Response?) { + if (text == null || response == null) { + data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY) + .withResponse(response)) + return + } + + val error = """

(.*?)

""".toRegex().find(text)?.get(1)?.trim() + + error?.let { code -> + when (code) { + "Niepoprawna nazwa użytkownika lub hasło" -> ERROR_LOGIN_GDYNIA_WEB_INVALID_CREDENTIALS + else -> ERROR_LOGIN_GDYNIA_WEB_OTHER + }.let { errorCode -> + data.error(ApiError(TAG, errorCode) + .withApiResponse(text) + .withResponse(response)) + return + } + } + + val sid = "sid=(.*?)&".toRegex().find(text)?.get(1) + + if (sid == null) { + data.error(ApiError(TAG, ERROR_LOGIN_GDYNIA_WEB_MISSING_SESSION_ID) + .withApiResponse(text) + .withResponse(response)) + return + } + + Request.builder() + .url("$GDYNIA_WEB_URL/$GDYNIA_WEB_LOGIN_CHECK") + .userAgent(SYSTEM_USER_AGENT) + .addParameter("sid", sid) + .addParameter("url_back", "") + .get() + .callback(checkCallback) + .build() + .enqueue() + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + data.error(ApiError(TAG, ERROR_REQUEST_FAILURE) + .withResponse(response) + .withThrowable(throwable)) + } + } + + Request.builder() + .url("$GDYNIA_WEB_URL/$GDYNIA_WEB_LOGIN") + .userAgent(SYSTEM_USER_AGENT) + .addParameter("action", "set") + .addParameter("user", data.loginUsername) + .addParameter("login", "Zaloguj się") + .addParameter("pass_md5", data.loginPassword?.md5()) + .addParameter("url_back", "") + .post() + .callback(loginCallback) + .build() + .enqueue() + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieApi.kt index af5ff9d7..ab4dce51 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieApi.kt @@ -6,7 +6,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data import com.google.gson.JsonObject import im.wangchao.mhttp.Request -import im.wangchao.mhttp.RequestParams import im.wangchao.mhttp.Response import im.wangchao.mhttp.callback.JsonCallbackHandler import pl.szczodrzynski.edziennik.data.api.* @@ -86,12 +85,11 @@ open class PodlasieApi(open val data: DataPodlasie, open val lastSync: Long?) { Request.builder() .url(url) .userAgent(SYSTEM_USER_AGENT) - .requestParams(RequestParams(mapOf( - "token" to data.apiToken, - "securityToken" to getSecurityToken(), - "mobileId" to data.app.deviceId, - "ver" to PODLASIE_API_VERSION - ))) + .addParameter("token", data.apiToken) + .addParameter("securityToken", getSecurityToken()) + .addParameter("mobileId", data.app.deviceId) + .addParameter("ver", PODLASIE_API_VERSION) + .get() .callback(callback) .build() .enqueue() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLoginWeb.kt index d7a24ef0..e6092c9a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLoginWeb.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLoginWeb.kt @@ -6,7 +6,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.template.login import pl.szczodrzynski.edziennik.currentTimeUnix import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_DATA_MISSING -import pl.szczodrzynski.edziennik.data.api.ERROR_PROFILE_MISSING import pl.szczodrzynski.edziennik.data.api.edziennik.template.DataTemplate import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -16,11 +15,6 @@ class TemplateLoginWeb(val data: DataTemplate, val onSuccess: () -> Unit) { } init { run { - if (data.profile == null) { - data.error(ApiError(TAG, ERROR_PROFILE_MISSING)) - return@run - } - if (data.isWebLoginValid()) { data.app.cookieJar.set("eregister.example.com", "AuthCookie", data.webCookie) onSuccess() diff --git a/app/src/main/res/values/errors.xml b/app/src/main/res/values/errors.xml index 0fe3df08..7995253c 100644 --- a/app/src/main/res/values/errors.xml +++ b/app/src/main/res/values/errors.xml @@ -166,6 +166,10 @@ ERROR_PODLASIE_API_OTHER ERROR_PODLASIE_API_DATA_MISSING + ERROR_LOGIN_GDYNIA_WEB_INVALID_CREDENTIALS + ERROR_LOGIN_GDYNIA_WEB_MISSING_SESSION_ID + ERROR_LOGIN_GDYNIA_WEB_OTHER + ERROR_TEMPLATE_WEB_OTHER EXCEPTION_API_TASK @@ -354,6 +358,10 @@ ERROR_PODLASIE_API_OTHER Brak danych. Zgłoś błąd programiście. + Niepoprawna nazwa użytkownika lub hasło + Brakujące ID sesji. Zgłoś błąd programiście. + Wystąpił błąd podczas logowania + ERROR_TEMPLATE_WEB_OTHER Błąd synchronizacji. Upewnij się, że masz połączenie z internetem, a następnie zgłoś błąd. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ad4d82b..207f12f0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1343,7 +1343,7 @@ Zaloguj się do dziennika Vulcan na komputerze, wybierz zakładkę Dostęp Mobilny, kliknij przycisk Zarejestruj urządzenie mobilne. Podaj otrzymany Token, Symbol i PIN w polach poniżej. Podaj dane, którymi logujesz się na stronie internetowej dziennika VULCAN lub na miejskiej platformie. Podaj dane, których używasz do logowania na stronie MobiDziennika. Jako adres serwera możesz wpisać adres strony internetowej, na której masz MobiDziennik. - Logowanie do dziennika Vulcan... + Logowanie do dziennika Vulcan… iDziennik Progman / iUczniowie Zaloguj używając nazwy użytkownika i hasła Podaj dane, których używasz na stronie internetowej e-dziennika @@ -1356,4 +1356,5 @@ Zaloguj używając tokenu Podaj token aplikacji mobilnej. Logowanie do PPE… + Logowanie do dziennika gdyńskiego…