[APIv2/Librus] Update Librus Messages login method.

This commit is contained in:
Kuba Szczodrzyński 2019-09-25 21:28:04 +02:00
parent 4cbb573d17
commit 2870931481
8 changed files with 124 additions and 38 deletions

View File

@ -80,6 +80,9 @@ const val ERROR_LIBRUS_API_NOTES_NOT_ACTIVE = 151
const val ERROR_LOGIN_LIBRUS_SYNERGIA_NO_TOKEN = 152
const val ERROR_LOGIN_LIBRUS_SYNERGIA_TOKEN_INVALID = 153
const val ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID = 154
const val ERROR_LIBRUS_MESSAGES_ACCESS_DENIED = 155
const val ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED = 156
const val ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID = 157
const val EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901
const val EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN = 902

View File

@ -26,9 +26,9 @@ const val LOGIN_MODE_VULCAN_WEB = 0
// LOGIN METHODS
const val LOGIN_METHOD_NOT_NEEDED = -1
const val LOGIN_METHOD_LIBRUS_PORTAL = 100// 0
const val LOGIN_METHOD_LIBRUS_API = 200// 1
const val LOGIN_METHOD_LIBRUS_SYNERGIA = 300 // 2
const val LOGIN_METHOD_LIBRUS_PORTAL = 100
const val LOGIN_METHOD_LIBRUS_API = 200
const val LOGIN_METHOD_LIBRUS_SYNERGIA = 300
const val LOGIN_METHOD_LIBRUS_MESSAGES = 400
const val LOGIN_METHOD_MOBIDZIENNIK_API = 100
const val LOGIN_METHOD_IDZIENNIK_WEB = 100

View File

@ -23,15 +23,23 @@ class LibrusTest(val app: App) {
}
val profile = Profile(1, "Profil", "xd", 1).apply {
putStudentData("accountLogin", "1234567")
//putStudentData("accountPassword", "zaq1@WSX")
//putStudentData("accountLogin", "1234567")
//putStudentData("accountCode", LIBRUS_JST_DEMO_CODE)
//putStudentData("accountPin", LIBRUS_JST_DEMO_PIN)
putStudentData("accountLogin", "1234567")
putStudentData("accountToken", "token")
putStudentData("accountTokenTime", 1569523077)
}
val loginStore = LoginStore(1, LOGIN_TYPE_LIBRUS, JsonObject().apply {
addProperty("email", "test@example.com")
addProperty("password", "zaq1@WSX")
addProperty("accessToken", "token")
addProperty("refreshToken", "refresh")
addProperty("tokenExpiryTime", 1569523077)
}).also {
it.mode = LOGIN_MODE_LIBRUS_EMAIL
}
@ -54,7 +62,7 @@ class LibrusTest(val app: App) {
}
}
LoginLibrus(data, LOGIN_METHOD_LIBRUS_SYNERGIA) {
LoginLibrus(data, LOGIN_METHOD_LIBRUS_MESSAGES) {
d(TAG, "Login succeeded.")
d(TAG, "Profile data: ${data.profile?.studentData?.toString()}")
d(TAG, "LoginStore data: ${data.loginStore.data}")

View File

@ -4,6 +4,8 @@
package pl.szczodrzynski.edziennik.api.v2.librus.data
import okhttp3.Cookie
import okhttp3.HttpUrl
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_API
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_MESSAGES
@ -27,10 +29,26 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
loginMethods += LOGIN_METHOD_LIBRUS_PORTAL
if (isApiLoginValid())
loginMethods += LOGIN_METHOD_LIBRUS_API
if (isSynergiaLoginValid())
if (isSynergiaLoginValid()) {
loginMethods += LOGIN_METHOD_LIBRUS_SYNERGIA
if (isMessagesLoginValid())
app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name("DZIENNIKSID")
.value(synergiaSessionId!!)
.domain("synergia.librus.pl")
.secure().httpOnly().build()
))
}
if (isMessagesLoginValid()) {
loginMethods += LOGIN_METHOD_LIBRUS_MESSAGES
app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name("DZIENNIKSID")
.value(messagesSessionId!!)
.domain("wiadomosci.librus.pl")
.secure().httpOnly().build()
))
}
}
/* _____ _ _

View File

@ -30,6 +30,7 @@ class LoginLibrus(val data: DataLibrus, vararg loginMethodIds: Int, val onSucces
loginMethodList = loginMethodList.toHashSet().toMutableList()
loginMethodList.sort()
data.satisfyLoginMethods()
nextLoginMethod()
}
@ -69,7 +70,7 @@ class LoginLibrus(val data: DataLibrus, vararg loginMethodIds: Int, val onSucces
}
}
LOGIN_METHOD_LIBRUS_MESSAGES -> {
LoginLibrusApi(data) {
LoginLibrusMessages(data) {
data.loginMethods.add(loginMethodId)
onSuccess()
}

View File

@ -4,10 +4,15 @@
package pl.szczodrzynski.edziennik.api.v2.librus.login
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie
import okhttp3.HttpUrl
import okhttp3.internal.http.HttpDate
import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.currentTimeUnix
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
companion object {
@ -21,13 +26,21 @@ class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
}
if (data.isMessagesLoginValid()) {
data.app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name("DZIENNIKSID")
.value(data.messagesSessionId!!)
.domain("wiadomosci.librus.pl")
.secure().httpOnly().build()
))
onSuccess()
}
else {
data.app.cookieJar.clearForDomain("wiadomosci.librus.pl")
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
loginWithSynergia()
}
else if (data.apiLogin != null && data.apiPassword != null) {
else if (data.apiLogin != null && data.apiPassword != null && false) {
loginWithCredentials()
}
else {
@ -46,7 +59,41 @@ class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
/**
* A login method using the Synergia website (/wiadomosci2 Auto Login).
*/
private fun loginWithSynergia() {
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
val callback = object : TextCallbackHandler() {
override fun onSuccess(text: String?, response: Response?) {
val location = response?.headers()?.get("Location")
when {
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
location?.contains("AutoLogon") == true -> {
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
sessionId = sessionId?.replace("-MAINT", "")
if (sessionId == null) {
data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID, response, text)
return
}
data.messagesSessionId = sessionId
data.messagesSessionIdExpiryTime = currentTimeUnix() + 3600 /* 1h */
onSuccess()
}
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable)
}
}
Request.builder()
.url(url)
.userAgent(SYNERGIA_USER_AGENT)
.get()
.callback(callback)
.withClient(data.app.httpLazy)
.build()
.enqueue()
}
}

View File

@ -9,6 +9,7 @@ import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.JsonCallbackHandler
import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie
import okhttp3.HttpUrl
import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
@ -30,13 +31,21 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
}
if (data.isSynergiaLoginValid()) {
data.app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name("DZIENNIKSID")
.value(data.synergiaSessionId!!)
.domain("synergia.librus.pl")
.secure().httpOnly().build()
))
onSuccess()
}
else {
data.app.cookieJar.clearForDomain("synergia.librus.pl")
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_API)) {
loginWithApi()
}
else if (data.apiLogin != null && data.apiPassword != null) {
else if (data.apiLogin != null && data.apiPassword != null && false) {
loginWithCredentials()
}
else {
@ -48,7 +57,6 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
/**
* HTML form-based login method. Uses a Synergia login and password.
*/
// TODO if loginWithCredentials fails and it is possible to use API, use it
private fun loginWithCredentials() {
}
@ -131,13 +139,7 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
override fun onSuccess(json: String?, response: Response?) {
val location = response?.headers()?.get("Location")
if (location?.endsWith("centrum_powiadomien") == true) {
val cookieList = data.app.cookieJar.loadForRequest(HttpUrl.get("https://synergia.librus.pl"))
var sessionId: String? = null
for (cookie in cookieList) {
if (cookie.name().equals("DZIENNIKSID", ignoreCase = true)) {
sessionId = cookie.value()
}
}
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
if (sessionId == null) {
data.error(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID, response, json)
return

View File

@ -18,6 +18,7 @@ package im.wangchao.mhttp.internal.cookie;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
@ -42,21 +43,13 @@ public class PersistentCookieJar implements ClearableCookieJar {
}
@Override
synchronized public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
//Log.d("PersistentCookieJar", "FINISHING "+url.toString());
synchronized public void saveFromResponse(@Nullable HttpUrl url, List<Cookie> cookies) {
// cookies need to be reversed, in order to replace old cookies with these coming later
// (if there are duplicate cookies in the same response)
List<Cookie> reverseCookies = new ArrayList<>(cookies);
Collections.reverse(reverseCookies);
/*for (Cookie cookie: reverseCookies) {
Log.d("PersistentCookieJar", "Saving cookie "+cookie.toString()+" from URL "+url.toString());
}*/
cache.addAll(reverseCookies);
persistor.saveAll(reverseCookies);
/*Log.d("PersistentCookieJar", "Cookies saved: ");
for (Cookie cookie : cache) {
Log.d("PersistentCookieJar", "Saving cookie " + cookie.toString() + " from URL " + url.toString());
}*/
}
@NonNull
@ -65,23 +58,15 @@ public class PersistentCookieJar implements ClearableCookieJar {
List<Cookie> removedCookies = new ArrayList<>();
List<Cookie> validCookies = new ArrayList<>();
//Log.d("PersistentCookieJar", "REQUESTING "+url.toString());
for (Iterator<Cookie> it = cache.iterator(); it.hasNext(); ) {
Cookie currentCookie = it.next();
//Log.d("PersistentCookieJar", "Loading "+currentCookie.toString()+" to URL "+url.toString());
if (isCookieExpired(currentCookie)) {
//Log.d("PersistentCookieJar", "Cookie expired at "+new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.getDefault()).format(new Date(currentCookie.expiresAt())));
removedCookies.add(currentCookie);
it.remove();
} else if (currentCookie.matches(url)) {
//Log.d("PersistentCookieJar", "Cookie is still valid until "+new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.getDefault()).format(new Date(currentCookie.expiresAt())));
validCookies.add(currentCookie);
}
/*else {
Log.d("PersistentCookieJar", "URL doesn't match");
}*/
}
persistor.removeAll(removedCookies);
@ -89,6 +74,28 @@ public class PersistentCookieJar implements ClearableCookieJar {
return validCookies;
}
@Nullable
synchronized public String getCookie(String domain, String name) {
String cookieValue = null;
List<Cookie> removedCookies = new ArrayList<>();
for (Iterator<Cookie> it = cache.iterator(); it.hasNext(); ) {
Cookie currentCookie = it.next();
if (isCookieExpired(currentCookie)) {
removedCookies.add(currentCookie);
it.remove();
} else if (domain.equals(currentCookie.domain()) && name.equals(currentCookie.name())) {
cookieValue = currentCookie.value();
break;
}
}
persistor.removeAll(removedCookies);
return cookieValue;
}
private static boolean isCookieExpired(Cookie cookie) {
return cookie.expiresAt() < System.currentTimeMillis();
}