diff --git a/app/src/main/java/de/sebse/fuplanner/MainActivity.java b/app/src/main/java/de/sebse/fuplanner/MainActivity.java index a81611b..7749e98 100644 --- a/app/src/main/java/de/sebse/fuplanner/MainActivity.java +++ b/app/src/main/java/de/sebse/fuplanner/MainActivity.java @@ -45,7 +45,7 @@ import de.sebse.fuplanner.services.fulogin.AccountGeneral; import de.sebse.fuplanner.services.kvv.KVV; import de.sebse.fuplanner.services.kvv.KVVListener; import de.sebse.fuplanner.services.kvv.sync.KVVContentProvider; -import de.sebse.fuplanner.services.kvv.types.LoginToken; +import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; import de.sebse.fuplanner.services.kvv.types.Modules; import de.sebse.fuplanner.services.news.NewsManager; import de.sebse.fuplanner.tools.CustomAccountManager; @@ -658,7 +658,7 @@ public class MainActivity extends AppCompatActivity @Override - public void onLogin(LoginToken token, boolean isOnlyRefresh) { + public void onLogin(LoginTokenKVV token, boolean isOnlyRefresh) { toLoginState(token.getFullName(), token.getEmail(), getDefaultFragmentAfterLogin()); if (!isOnlyRefresh) { registerSync(); diff --git a/app/src/main/java/de/sebse/fuplanner/services/fulogin/AccountGeneral.java b/app/src/main/java/de/sebse/fuplanner/services/fulogin/AccountGeneral.java index af6749e..7c15881 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/fulogin/AccountGeneral.java +++ b/app/src/main/java/de/sebse/fuplanner/services/fulogin/AccountGeneral.java @@ -4,5 +4,4 @@ public class AccountGeneral { public static final String ACCOUNT_TYPE = "de.sebse.fuplanner.fuauth"; public static final String AUTHTOKEN_TYPE_KVV = "KVV"; public static final String AUTHTOKEN_TYPE_BLACKBOARD = "Blackboard"; - public static final long SYNC_INTERVAL = 6 * 60 * 60; // defined in seconds } diff --git a/app/src/main/java/de/sebse/fuplanner/services/fulogin/UserLoginTask.java b/app/src/main/java/de/sebse/fuplanner/services/fulogin/UserLoginTask.java index 897b17f..c4ea487 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/fulogin/UserLoginTask.java +++ b/app/src/main/java/de/sebse/fuplanner/services/fulogin/UserLoginTask.java @@ -14,9 +14,10 @@ import java.util.concurrent.atomic.AtomicReference; import androidx.annotation.Nullable; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.kvv.sync.Login; -import de.sebse.fuplanner.services.kvv.types.LoginToken; +import de.sebse.fuplanner.services.kvv.sync.BBLogin; +import de.sebse.fuplanner.services.kvv.sync.KVVLogin; import de.sebse.fuplanner.tools.logging.Logger; +import de.sebse.fuplanner.tools.network.NetworkErrorCallback; /** @@ -34,20 +35,22 @@ public class UserLoginTask extends AsyncTask { };*/ static final String PARAM_USER_PASS = "PARAM_USER_PASS"; - private final String mEmail; + private final String mUsername; private final String mPassword; - private final Login mVolleyLogin; + private final KVVLogin mKVVLogin; + private final BBLogin mBBLogin; private String mTokenType; private Logger log = new Logger(this); @SuppressLint("StaticFieldLeak") @Nullable private FUAuthenticatorActivity mActivity; - UserLoginTask(String email, String password, String tokenType, @NotNull Context context) { - mEmail = email; + UserLoginTask(String username, String password, String tokenType, @NotNull Context context) { + mUsername = username; mPassword = password; mTokenType = tokenType; - mVolleyLogin = new Login(context); + mKVVLogin = new KVVLogin(context); + mBBLogin = new BBLogin(context); if (context instanceof FUAuthenticatorActivity) mActivity = (FUAuthenticatorActivity) context; } @@ -57,30 +60,38 @@ public class UserLoginTask extends AsyncTask { // TODO: attempt authentication against a network service. CountDownLatch latch = new CountDownLatch(1); - AtomicReference login = new AtomicReference<>(); - mVolleyLogin.doLogin(mEmail, mPassword, success -> { - mVolleyLogin.testLoginToken(success, success1 -> { - login.set(success); - latch.countDown(); - }, error -> { - log.e(error); - latch.countDown(); - }); - }, error -> { + AtomicReference login = new AtomicReference<>(); + NetworkErrorCallback errorFunc = error -> { log.e(error); latch.countDown(); - }); + }; + switch (mTokenType) { + case AccountGeneral.AUTHTOKEN_TYPE_KVV: + mKVVLogin.doLogin(mUsername, mPassword, success -> { + mKVVLogin.testLoginToken(success, success1 -> { + login.set(success1.toJsonString()); + latch.countDown(); + }, errorFunc); + }, errorFunc); + break; + case AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD: + mBBLogin.doLogin(mUsername, mPassword, success -> { + mBBLogin.testLoginToken(success, success1 -> { + login.set(success1.toJsonString()); + latch.countDown(); + }, errorFunc); + }, errorFunc); + break; + default: + return null; + } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } - if (login.get() == null) { - return null; - } else { - return login.get().toJsonString(); - } + return login.get(); } @Override @@ -94,7 +105,7 @@ public class UserLoginTask extends AsyncTask { if (success != null) { final Intent res = new Intent(); - res.putExtra(AccountManager.KEY_ACCOUNT_NAME, mEmail); + res.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername); res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE); res.putExtra(AccountManager.KEY_AUTHTOKEN, success); res.putExtra(PARAM_USER_PASS, mPassword); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java index 523e066..818c6a2 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java @@ -2,11 +2,11 @@ package de.sebse.fuplanner.services.kvv; import com.android.volley.NetworkResponse; -import de.sebse.fuplanner.services.kvv.types.LoginToken; +import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; import de.sebse.fuplanner.tools.CustomAccountManager; public interface KVVListener { - default void onLogin(LoginToken token, boolean isOnlyRefresh) {} + default void onLogin(LoginTokenKVV token, boolean isOnlyRefresh) {} default void onLogout() {} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java index d8f5d1b..ef54cb9 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java @@ -1,12 +1,16 @@ package de.sebse.fuplanner.services.kvv; import android.content.Context; +import android.util.Pair; import org.jetbrains.annotations.NotNull; import androidx.annotation.Nullable; import de.sebse.fuplanner.services.fulogin.AccountGeneral; -import de.sebse.fuplanner.services.kvv.types.LoginToken; +import de.sebse.fuplanner.services.kvv.sync.BBLogin; +import de.sebse.fuplanner.services.kvv.sync.KVVLogin; +import de.sebse.fuplanner.services.kvv.types.LoginTokenBB; +import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; import de.sebse.fuplanner.tools.CustomAccountManager; import de.sebse.fuplanner.tools.NetworkCallbackCollector; import de.sebse.fuplanner.tools.network.HTTPService; @@ -16,9 +20,10 @@ import de.sebse.fuplanner.tools.network.NetworkErrorCallback; public class Login extends HTTPService { private final KVVListener mListener; - @Nullable private LoginToken mToken; + @Nullable private LoginTokenKVV mTokenKVV; + @Nullable private LoginTokenBB mTokenBB; private boolean mLoginPending = false; - private final NetworkCallbackCollector mRefreshCallbacks = new NetworkCallbackCollector<>(); + private final NetworkCallbackCollector> mRefreshCallbacks = new NetworkCallbackCollector<>(); Login(KVVListener listener, Context context) { super(context); @@ -31,27 +36,33 @@ public class Login extends HTTPService { return; } mLoginPending = true; - LoginToken.load(mListener.getAccountManager(), token -> { - boolean result = setToken(token); - mLoginPending = false; - callback.run(result); + LoginTokenKVV.load(mListener.getAccountManager(), tokenKVV -> { + LoginTokenBB.load(mListener.getAccountManager(), tokenBB -> { + boolean result = setToken(tokenKVV, tokenBB); + mLoginPending = false; + callback.run(result); + }); }); } public void isOfflineStoredAvailable(BooleanInterface callback) { - LoginToken.load(mListener.getAccountManager(), token -> { - callback.run(token != null); + LoginTokenKVV.load(mListener.getAccountManager(), tokenKVV -> { + LoginTokenBB.load(mListener.getAccountManager(), tokenBB -> { + callback.run(tokenKVV != null && tokenBB != null); + }); }); } public boolean logout(boolean delete) { if (mLoginPending) return false; - if (mToken == null) + if (mTokenKVV == null || mTokenBB == null) return true; - if (delete) - mToken.delete(mListener.getAccountManager()); - mToken = null; + if (delete) { + mTokenKVV.delete(mListener.getAccountManager()); + mTokenBB.delete(mListener.getAccountManager()); + } + mTokenKVV = null; return handleCallbacks(false); } @@ -60,43 +71,57 @@ public class Login extends HTTPService { } public boolean isLoggedIn() { - return mToken != null; + return mTokenKVV != null && mTokenBB != null; } public boolean isInOnlineMode() { return isLoggedIn(); } - void testLoginToken(@NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) { - if (mToken == null) { + void testLoginToken(@NotNull NetworkCallback> callback, @NotNull NetworkErrorCallback errorCallback) { + if (mTokenKVV == null) { errorCallback.onError(new NetworkError(100173, -1, "Not logged in!")); return; } - testLoginToken(mToken, callback, errorCallback); + if (mTokenBB == null) { + errorCallback.onError(new NetworkError(100174, -1, "Not logged in!")); + return; + } + testLoginToken(mTokenKVV, mTokenBB, callback, errorCallback); } - private void testLoginToken(@NotNull LoginToken token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) { - new de.sebse.fuplanner.services.kvv.sync.Login(getContext()).testLoginToken(token, callback, errorCallback); + private void testLoginToken(@NotNull LoginTokenKVV tokenKVV, @NotNull LoginTokenBB tokenBB, @NotNull NetworkCallback> callback, @NotNull NetworkErrorCallback errorCallback) { + new KVVLogin(getContext()).testLoginToken(tokenKVV, tokenKVV1 -> { + new BBLogin(getContext()).testLoginToken(tokenBB, tokenBB1 -> { + callback.onResponse(new Pair<>(tokenKVV1, tokenBB1)); + }, errorCallback); + }, errorCallback); } - @Nullable public LoginToken getLoginToken() { - return mToken; + @Nullable public LoginTokenKVV getLoginTokenKVV() { + return mTokenKVV; } - void refreshLogin(NetworkCallback success, NetworkErrorCallback error) { + @Nullable public LoginTokenBB getLoginTokenBB() { + return mTokenBB; + } + + void refreshLogin(NetworkCallback> success, NetworkErrorCallback error) { boolean isFirst = mRefreshCallbacks.isEmpty(); mRefreshCallbacks.add(success, error); if (!isFirst) return; CustomAccountManager manager = mListener.getAccountManager(); manager.doInvalidateToken(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, ignored -> { - restoreOnlineLogin(isRestored -> { - if (isRestored) - testLoginToken(mRefreshCallbacks::responseResponse, mRefreshCallbacks::responseError); - else { - logout(true); - mRefreshCallbacks.responseError(new NetworkError(100180, 403, "Re-login failed!")); - } + manager.doInvalidateToken(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD, ignored2 -> { + restoreOnlineLogin(isRestored -> { + if (isRestored) + testLoginToken(mRefreshCallbacks::responseResponse, mRefreshCallbacks::responseError); + else { + logout(true); + mRefreshCallbacks.responseError(new NetworkError(100180, 403, "Re-login failed!")); + } + }); }); }); } @@ -104,8 +129,8 @@ public class Login extends HTTPService { private boolean handleCallbacks(boolean isOnlyRefresh) { - if (mToken != null) { - mListener.onLogin(mToken, isOnlyRefresh); + if (mTokenKVV != null) { + mListener.onLogin(mTokenKVV, isOnlyRefresh); return true; } else { mListener.onLogout(); @@ -113,11 +138,12 @@ public class Login extends HTTPService { } } - private boolean setToken(@Nullable LoginToken token) { - if (token == null) + private boolean setToken(@Nullable LoginTokenKVV tokenKVV, @Nullable LoginTokenBB tokenBB) { + if (tokenKVV == null || tokenBB == null) return false; - boolean isOnlyRefresh = mToken != null; - mToken = token; + boolean isOnlyRefresh = mTokenKVV != null && tokenBB != null; + mTokenKVV = tokenKVV; + mTokenBB = tokenBB; return isOnlyRefresh || handleCallbacks(isOnlyRefresh); } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java index d6b4877..35c7a20 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java @@ -33,12 +33,12 @@ public class ModulesAnnouncements extends PartModules> { } @Override - protected void upgrade(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + protected void upgradeKVV(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { errorCallback.onError(new NetworkError(101204, 500, "Currently running in offline mode!")); return; } - super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), mLogin.getLoginToken().getCookies(), response -> { + super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101201, 403, "No announcements retrieved!")); @@ -88,4 +88,9 @@ public class ModulesAnnouncements extends PartModules> { callback.onResponse(announcements); }, error -> errorCallback.onError(new NetworkError(101203, error.networkResponse.statusCode, "Cannot get announcements!"))); } + + @Override + protected void upgradeBB(String ID, NetworkCallback> callback, NetworkErrorCallback errorCallback) { + callback.onResponse(new ArrayList<>()); + } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java index c7948a5..bfc2106 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java @@ -34,12 +34,12 @@ public class ModulesAssignments extends PartModules { } @Override - protected void upgrade(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { - if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + protected void upgradeKVV(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { errorCallback.onError(new NetworkError(101304, 500, "Currently running in offline mode!")); return; } - get(String.format("https://kvv.imp.fu-berlin.de/direct/assignment/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> { + get(String.format("https://kvv.imp.fu-berlin.de/direct/assignment/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101301, 403, "No assignments retrieved!")); @@ -87,4 +87,9 @@ public class ModulesAssignments extends PartModules { callback.onResponse(assignments); }, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get assignments!"))); } + + @Override + protected void upgradeBB(String ID, NetworkCallback callback, NetworkErrorCallback errorCallback) { + callback.onResponse(new AssignmentList()); + } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java index 13417f9..e6fa177 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java @@ -32,12 +32,12 @@ public class ModulesEvents extends PartModules { } @Override - protected void upgrade(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { - if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + protected void upgradeKVV(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { errorCallback.onError(new NetworkError(101404, 500, "Currently running in offline mode!")); return; } - get(String.format("https://kvv.imp.fu-berlin.de/direct/calendar/site/%s.json?detailed=true", ID), mLogin.getLoginToken().getCookies(), response -> { + get(String.format("https://kvv.imp.fu-berlin.de/direct/calendar/site/%s.json?detailed=true", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101401, 403, "No events retrieved!")); @@ -80,4 +80,9 @@ public class ModulesEvents extends PartModules { callback.onResponse(events); }, error -> errorCallback.onError(new NetworkError(101403, error.networkResponse.statusCode, "Cannot get events!"))); } + + @Override + protected void upgradeBB(String ID, NetworkCallback callback, NetworkErrorCallback errorCallback) { + callback.onResponse(new EventList()); + } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java index 74672d9..781ab42 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java @@ -33,12 +33,12 @@ public class ModulesGradebook extends PartModules> { } @Override - protected void upgrade(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + protected void upgradeKVV(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { errorCallback.onError(new NetworkError(101504, 500, "Currently running in offline mode!")); return; } - super.get(String.format("https://kvv.imp.fu-berlin.de/direct/gradebook/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> { + super.get(String.format("https://kvv.imp.fu-berlin.de/direct/gradebook/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101501, 403, "No gradebook retrieved!")); @@ -73,4 +73,9 @@ public class ModulesGradebook extends PartModules> { callback.onResponse(gradebook); }, error -> errorCallback.onError(new NetworkError(101503, error.networkResponse.statusCode, "Cannot get gradebook!"))); } + + @Override + protected void upgradeBB(String ID, NetworkCallback> callback, NetworkErrorCallback errorCallback) { + callback.onResponse(new ArrayList<>()); + } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java index 7d7a10b..99ddc84 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java @@ -9,8 +9,10 @@ import org.json.JSONObject; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.concurrent.CountDownLatch; import java.util.regex.MatchResult; import de.sebse.fuplanner.services.kvv.types.Lecturer; @@ -61,7 +63,10 @@ public class ModulesList extends HTTPService { } private void find(String moduleID, NetworkCallback moduleNetworkCallback, NetworkErrorCallback errorCallback, int retries) { - if (mModules != null && mLogin.getLoginToken() != null && mLogin.getLoginToken().isOtherUser(mModules.getUsername())) + if (mModules != null && + mLogin.getLoginTokenKVV() != null && mLogin.getLoginTokenKVV().isOtherUser(mModules.getUsername()) && + mLogin.getLoginTokenBB() != null && mLogin.getLoginTokenBB().isOtherUser(mModules.getUsername()) + ) delete(); if (retries < 0) { errorCallback.onError(new NetworkError(101107, -1, "Too many retries!")); @@ -114,7 +119,10 @@ public class ModulesList extends HTTPService { } private void recv(final NetworkCallback callback, final NetworkErrorCallback errorCallback, boolean forceRefresh, final int retries) { - if (mModules != null && mLogin.getLoginToken() != null && mLogin.getLoginToken().isOtherUser(mModules.getUsername())) + if (mModules != null && + mLogin.getLoginTokenKVV() != null && mLogin.getLoginTokenKVV().isOtherUser(mModules.getUsername()) && + mLogin.getLoginTokenBB() != null && mLogin.getLoginTokenBB().isOtherUser(mModules.getUsername()) + ) delete(); mQueue.add(() -> { if (this.mModules != null && !forceRefresh) { @@ -122,19 +130,10 @@ public class ModulesList extends HTTPService { mQueue.next(); return; } - this.upgrade(success -> { - if (this.mModules == null) - this.mModules = success; - else if(this.mModules.updateList(success)) { - mListener.onModuleListChange(); - store(); - } - callback.onResponse(this.mModules); - mQueue.next(); - }, error -> { + NetworkErrorCallback errorFunc = (error -> { if (retries > 0 && (error.getHttpStatus() == 401 || error.getHttpStatus() == 403)) { mLogin.refreshLogin(success -> { - recv(callback, errorCallback, forceRefresh, retries-1); + recv(callback, errorCallback, forceRefresh, retries - 1); mQueue.next(); }, error1 -> { errorCallback.onError(error1); @@ -145,28 +144,40 @@ public class ModulesList extends HTTPService { errorCallback.onError(error); mQueue.next(); }); + this.upgradeKVV(successKVV -> { + this.upgradeBlackboard(successKVV, success -> { + if (this.mModules == null) + this.mModules = success; + else if (this.mModules.updateList(success)) { + mListener.onModuleListChange(); + store(); + } + callback.onResponse(this.mModules); + mQueue.next(); + }, errorFunc); + }, errorFunc); }); } - private void upgrade(final NetworkCallback callback, final NetworkErrorCallback errorCallback) { - if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { - errorCallback.onError(new NetworkError(101105, 500, "Currently running in offline mode!")); + private void upgradeKVV(final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { + errorCallback.onError(new NetworkError(101110, 500, "Currently running in offline mode!")); return; } - get("https://kvv.imp.fu-berlin.de/direct/site.json", mLogin.getLoginToken().getCookies(), response -> { + get("https://kvv.imp.fu-berlin.de/direct/site.json", mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { - errorCallback.onError(new NetworkError(101101, 403, "No module list retrieved!")); + errorCallback.onError(new NetworkError(101111, 403, "No module list retrieved!")); return; } - Modules modules = new Modules(mLogin.getLoginToken().getUsername()); + Modules modules = new Modules(mLogin.getLoginTokenKVV().getUsername()); JSONArray sites; try { JSONObject json = new JSONObject(body); sites = json.getJSONArray("site_collection"); } catch (JSONException e) { e.printStackTrace(); - errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!")); + errorCallback.onError(new NetworkError(101112, 403, "Cannot parse module list!")); return; } for (int i = 0; i < sites.length(); i++) { @@ -192,13 +203,13 @@ public class ModulesList extends HTTPService { String description = site.optString("description", ""); description = String.valueOf(PartModules.fromHtml(description)); String id = site.getString("id"); - modules.addModule(semester, lvNumbers, title, lecturers, type, description, id); + modules.addModule(semester, lvNumbers, title, lecturers, type, description, id, Modules.TYPE_KVV); } catch (JSONException e) { - log.e(new NetworkError(101103, 403, "Cannot parse module list!")); + log.e(new NetworkError(101113, 403, "Cannot parse module list!")); log.e("ID:", i, "JSON:", sites); e.printStackTrace(); } catch (NoSuchFieldException e) { - log.e(new NetworkError(101106, 403, "Cannot parse module list!")); + log.e(new NetworkError(101114, 403, "Cannot parse module list!")); log.e("ID:", i, "JSON:", sites); e.printStackTrace(); } @@ -208,6 +219,76 @@ public class ModulesList extends HTTPService { mLogin.testLoginToken(token -> callback.onResponse(modules), errorCallback); else callback.onResponse(modules); - }, error -> errorCallback.onError(new NetworkError(101104, error.networkResponse.statusCode, "Cannot get module list!"))); + }, error -> errorCallback.onError(new NetworkError(101115, error.networkResponse.statusCode, "Cannot get module list!"))); + } + + private void upgradeBlackboard(final Modules modulesKVV, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null) { + errorCallback.onError(new NetworkError(101120, 500, "Currently running in offline mode!")); + return; + } + get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/users/%s/courses", mLogin.getLoginTokenBB().getId()), mLogin.getLoginTokenBB().getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(101121, 403, "No module list retrieved!")); + return; + } + final JSONArray[] sites = new JSONArray[1]; + try { + JSONObject json = new JSONObject(body); + sites[0] = json.getJSONArray("results"); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(101122, 403, "Cannot parse module list!")); + return; + } + final int[] latch = {sites[0].length()}; + for (int i = 0; i < sites[0].length(); i++) { + try { + JSONObject site = sites[0].getJSONObject(i); + String courseId = site.getString("courseId"); + get(String.format("https://lms.fu-berlin.de/learn/api/v1/courses/%s", courseId), mLogin.getLoginTokenBB().getCookies(), response1 -> { + String body1 = response1.getParsed(); + if (body1 == null) { + errorCallback.onError(new NetworkError(101124, 403, "No module list retrieved!")); + return; + } + try { + JSONObject json = new JSONObject(body1); + String name = json.getString("name"); + String type = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 1); + String lvNumber = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 2); + String semYear = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 3); + String semType = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 4); + boolean found = false; + for (Modules.Module module: modulesKVV) { + if (module.lvNumber.contains(lvNumber)) { + found = true; + break; + } + } + if (!found) + modulesKVV.addModule(new Semester(semType.equals("W") ? Semester.SEM_WS : Semester.SEM_SS, Integer.valueOf(semYear)), new HashSet<>(), name, new LinkedHashSet<>(), type, "", courseId, Modules.TYPE_BB); + latch[0]--; + if (latch[0] == 0) + callback.onResponse(modulesKVV); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(101125, 403, "Cannot parse module list!")); + return; + } catch (NoSuchFieldException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(101127, 403, "Cannot parse module list!")); + return; + } + }, error -> errorCallback.onError(new NetworkError(101126, error.networkResponse.statusCode, "Cannot get module list!"))); + } catch (JSONException e) { + log.e(new NetworkError(101123, 403, "Cannot parse module list!")); + log.e("ID:", i, "JSON:", sites[0]); + e.printStackTrace(); + } + } + }, error -> errorCallback.onError(new NetworkError(101125, error.networkResponse.statusCode, "Cannot get module list!"))); + } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java index 5fd6c43..eede02d 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java @@ -42,12 +42,12 @@ public class ModulesResources extends PartModules> { } @Override - protected void upgrade(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + protected void upgradeKVV(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!")); return; } - get(String.format("https://kvv.imp.fu-berlin.de/direct/content/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> { + get(String.format("https://kvv.imp.fu-berlin.de/direct/content/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101601, 403, "No resources retrieved!")); @@ -124,6 +124,10 @@ public class ModulesResources extends PartModules> { }, error -> errorCallback.onError(new NetworkError(101603, error.networkResponse.statusCode, "Cannot get resources!"))); } + @Override + protected void upgradeBB(String ID, NetworkCallback> callback, NetworkErrorCallback errorCallback) { + callback.onResponse(new ArrayList<>()); + } @@ -160,11 +164,11 @@ public class ModulesResources extends PartModules> { } private void fileUpgrade(String filename, String url, String modulename, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { - if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!")); return; } - get(url, mLogin.getLoginToken().getCookies(), response -> { + get(url, mLogin.getLoginTokenKVV().getCookies(), response -> { if (Regex.has("\\.[Uu][Rr][Ll]$", url)){ // Return redirected URL String path = response.getHeaders().get("Location"); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/PartModules.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/PartModules.java index eae3b53..3a1905c 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/PartModules.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/PartModules.java @@ -25,7 +25,7 @@ abstract class PartModules extends Part { mQueue.next(); return; } - upgrade(module.getID(), success -> { + upgrade(module.getModuleType(), module.getID(), success -> { if (setPart(module, success)) { this.mList.store(); } @@ -61,5 +61,18 @@ abstract class PartModules extends Part { protected abstract boolean setPart(Modules.Module module, T part); - protected abstract void upgrade(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback); + protected void upgrade(final int moduleType, final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + switch (moduleType) { + case Modules.TYPE_KVV: + upgradeKVV(ID, callback, errorCallback); + break; + case Modules.TYPE_BB: + upgradeBB(ID, callback, errorCallback); + break; + } + } + + protected abstract void upgradeKVV(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback); + + protected abstract void upgradeBB(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback); } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/BBLogin.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/BBLogin.java new file mode 100644 index 0000000..6892bba --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/BBLogin.java @@ -0,0 +1,266 @@ +package de.sebse.fuplanner.services.kvv.sync; + +import android.content.Context; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import de.sebse.fuplanner.services.kvv.types.LoginTokenBB; +import de.sebse.fuplanner.tools.network.HTTPService; +import de.sebse.fuplanner.tools.network.NetworkCallback; +import de.sebse.fuplanner.tools.network.NetworkError; +import de.sebse.fuplanner.tools.network.NetworkErrorCallback; + +public class BBLogin extends HTTPService { + public BBLogin(Context context) { + super(context); + } + + public void testLoginToken(@NotNull LoginTokenBB token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) { + get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/users/?userName=%s", token.getUsername()), token.getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(100272, 403, "Testing login failed!")); + return; + } + try { + JSONObject json = new JSONObject(body); + json = json.getJSONArray("results").getJSONObject(0); + String id = json.getString("id"); + String studentId = json.getString("studentId"); + token.setAdditionals(id, studentId); + callback.onResponse(token); + } catch (JSONException e) { + errorCallback.onError(new NetworkError(100271, 403, "Cannot parse profile!")); + } + }, error -> errorCallback.onError(new NetworkError(100270, error.networkResponse.statusCode, "Testing login failed!"))); + } + + + + + + + + + + + + + + + + public void doLogin(String username, String password, NetworkCallback callback, NetworkErrorCallback error) { + step1(success1 -> { + String samlLocation = success1.get("Location"); + step2(samlLocation, success2 -> { + String fuJSESSIONID = success2.get("JSESSIONID"); + step3(fuJSESSIONID, success3 -> { + step4(username, password, fuJSESSIONID, success4 -> { + String samlResponse = success4.get("SAMLResponse"); + step5(samlResponse, success5 -> { + String shibsessionKey = success5.get("shibsessionKey"); + String shibsessionName = success5.get("shibsessionName"); + step6(shibsessionKey, shibsessionName, success6 -> { + String s_session_id = success6.get("s_session_id"); + String session_id = success6.get("session_id"); + LoginTokenBB token = new LoginTokenBB(username, s_session_id, session_id); + callback.onResponse(token); + }, error); + }, error); + }, error); + }, error); + }, error); + }, error); + } + + /* + 1= GET https://lms.fu-berlin.de/lms-apps/login/sso/index.php + -> Location-Header: https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState] + */ + private void step1(final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + get("https://lms.fu-berlin.de/lms-apps/login/sso/index.php", null, response -> { + String location = response.getHeaders().get("Location"); + if (location==null) { + errorCallback.onError(new NetworkError(100211, -1, "Error on getting SAML request!")); + return; + } + HashMap object = new HashMap<>(); + object.put("Location", location); + callback.onResponse(object); + }, error -> errorCallback.onError(new NetworkError(100210, error.networkResponse.statusCode, "Error on getting SAML request!"))); + } + + /* + 2= GET [Location-Header 1] + -> Set-Cookie: JSESSIONID=[JSESSION-FU] + -> Location: /idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1 + */ + private void step2(String url, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + get(url, null, response -> { + String cookies = response.getHeaders().get("Set-Cookie"); + if (cookies==null) { + errorCallback.onError(new NetworkError(100221, -1, "Error on starting FU session!")); + return; + } + HashMap object; + try { + object = getCookie(cookies, new String[]{"JSESSIONID"}); + } catch (NoSuchFieldException e) { + errorCallback.onError(new NetworkError(100222, -1, "Error on starting FU session!")); + return; + } + callback.onResponse(object); + }, error -> errorCallback.onError(new NetworkError(100220, error.networkResponse.statusCode, "Error on starting FU session!"))); + } + + /* + 3= GET [Location-Header 2] + + Cookie: JSESSIONID=[JSESSION-FU] + */ + private void step3(String JSESSIONID_FU, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + HashMap cookies = new HashMap<>(); + cookies.put("JSESSIONID", JSESSIONID_FU); + head("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> { + callback.onResponse(true); + }, error -> errorCallback.onError(new NetworkError(100230, error.networkResponse.statusCode, "Error starting login page!"))); + } + + /* + 4= POST [Location-Header 2] + + Body: j_username=[USERNAME]&j_password=[PASSWORD]&_eventId_proceed= + + Header: Content-Type: application/x-www-form-urlencoded + + Header: Referer: [Location-Header 2] + + Cookie: JSESSIONID=[JSESSION-FU] + -> Set-Cookie: shib_idp_session=[SHIB-IDP-SESSION] + -> Body SAMLResponse-Input-value + */ + private void step4(String username, String password, String JSESSIONID_FU, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + HashMap cookies = new HashMap<>(); + cookies.put("JSESSIONID", JSESSIONID_FU); + HashMap body = new HashMap<>(); + body.put("j_username", username); + body.put("j_password", password); + body.put("_eventId_proceed", ""); + post("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, body, response -> { + String cookies1 = response.getHeaders().get("Set-Cookie"); + if (cookies1 ==null) { + errorCallback.onError(new NetworkError(100241, -1, "Error on logging in to FU Identity Server!")); + return; + } + HashMap object; + try { + object = getCookie(cookies1, new String[]{"shib_idp_session"}); + } catch (NoSuchFieldException e) { + errorCallback.onError(new NetworkError(100242, -1, "Error on logging in to FU Identity Server!")); + return; + } + + String content = response.getParsed(); + if (content == null) { + errorCallback.onError(new NetworkError(100243, -1, "Error on getting SAML response!")); + return; + } + Pattern pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)"); + Matcher matcher = pattern.matcher(content); + if (!matcher.find()) { + errorCallback.onError(new NetworkError(100244, -1, "Error on getting SAML response!")); + return; + } + object.put("SAMLResponse", matcher.group(1)); + callback.onResponse(object); + }, error -> errorCallback.onError(new NetworkError(100245, error.networkResponse.statusCode, "Error on logging in to FU Identity Server!"))); + } + + /* + 5= POST https://lms.fu-berlin.de/Shibboleth.sso/SAML2/POST + + Body: SAMLResponse=[SAML-RESPONSE] + + Header: Content-Type: application/x-www-form-urlencoded + -> Set-Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] + */ + private void step5(String SAMLResponse, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + HashMap body = new HashMap<>(); + body.put("SAMLResponse", SAMLResponse); + post("https://lms.fu-berlin.de/Shibboleth.sso/SAML2/POST", null, body, response -> { + String cookies = response.getHeaders().get("Set-Cookie"); + if (cookies ==null) { + errorCallback.onError(new NetworkError(100251, -1, "Error on starting KVV session!")); + return; + } + HashMap object = new HashMap<>(); + + + Pattern pattern = Pattern.compile("(_shibsession_[0-9a-f]+)=([^;]+);"); + Matcher matcher = pattern.matcher(cookies); + if (!matcher.find()) { + errorCallback.onError(new NetworkError(100252, -1, "Error on starting KVV session!")); + } + object.put("shibsessionKey", matcher.group(1)); + object.put("shibsessionName", matcher.group(2)); + + callback.onResponse(object); + }, error -> errorCallback.onError(new NetworkError(100250, error.networkResponse.statusCode, "Error on starting KVV session!"))); + } + + + /* + 6= https://lms.fu-berlin.de/webapps/bb-auth-provider-shibboleth-bb_bb60/execute/shibbolethLogin?returnUrl=https://lms.fu-berlin.de/webapps/portal/execute/defaultTab&authProviderId=_3_1 + + Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] + -> Set-Cookie: JSESSIONID: [JSESSION-KVV] + */ + private void step6(String shibsessionKey, String shibsessionName, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + HashMap cookies = new HashMap<>(); + cookies.put(shibsessionKey, shibsessionName); + log.d(shibsessionKey, shibsessionName); + get("https://lms.fu-berlin.de/webapps/bb-auth-provider-shibboleth-bb_bb60/execute/shibbolethLogin?returnUrl=https://lms.fu-berlin.de/webapps/portal/execute/defaultTab&authProviderId=_3_1", cookies, response -> { + String cookies1 = response.getHeaders().get("Set-Cookie"); + if (cookies1 ==null) { + errorCallback.onError(new NetworkError(100261, -1, "Cannot finish login process!")); + return; + } + HashMap object; + try { + object = getCookie(cookies1, new String[]{"session_id", "s_session_id"}); + } catch (NoSuchFieldException e) { + errorCallback.onError(new NetworkError(100262, -1, "Cannot finish login process!")); + return; + } + callback.onResponse(object); + }, error -> errorCallback.onError(new NetworkError(100260, error.networkResponse.statusCode, "Cannot finish login process!"))); + } + + + + + + + + + + + + + private String getCookie(String cookies, String name) throws NoSuchFieldException { + Pattern pattern = Pattern.compile(name+"=([^;]+);"); + Matcher matcher = pattern.matcher(cookies); + if (!matcher.find()) { + log.e("GETcookie failed", name); + log.e("GETcookie failed", cookies); + throw new NoSuchFieldException(); + } + return matcher.group(1); + } + + private HashMap getCookie(String cookies, String[] names) throws NoSuchFieldException { + HashMap result = new HashMap<>(); + for (String name: names) { + result.put(name,this.getCookie(cookies, name)); + } + return result; + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/Login.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVLogin.java similarity index 93% rename from app/src/main/java/de/sebse/fuplanner/services/kvv/sync/Login.java rename to app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVLogin.java index a4e8173..6b7f1a0 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/Login.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVLogin.java @@ -10,19 +10,19 @@ import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; -import de.sebse.fuplanner.services.kvv.types.LoginToken; +import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; import de.sebse.fuplanner.tools.network.HTTPService; import de.sebse.fuplanner.tools.network.NetworkCallback; import de.sebse.fuplanner.tools.network.NetworkError; import de.sebse.fuplanner.tools.network.NetworkErrorCallback; -public class Login extends HTTPService { - public Login(Context context) { +public class KVVLogin extends HTTPService { + public KVVLogin(Context context) { super(context); } - public void testLoginToken(@NotNull LoginToken token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) { + public void testLoginToken(@NotNull LoginTokenKVV token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) { get(String.format("https://kvv.imp.fu-berlin.de/direct/profile/%s.json", token.getUsername()), token.getCookies(), response -> { String body = response.getParsed(); if (body == null) { @@ -55,7 +55,7 @@ public class Login extends HTTPService { - public void doLogin(String username, String password, NetworkCallback callback, NetworkErrorCallback error) { + public void doLogin(String username, String password, NetworkCallback callback, NetworkErrorCallback error) { step1(success1 -> { String samlLocation = success1.get("Location"); step2(samlLocation, success2 -> { @@ -68,7 +68,7 @@ public class Login extends HTTPService { String shibsessionName = success5.get("shibsessionName"); step6(shibsessionKey, shibsessionName, success6 -> { String kvvJSESSIONID = success6.get("JSESSIONID"); - LoginToken token = new LoginToken(username, kvvJSESSIONID); + LoginTokenKVV token = new LoginTokenKVV(username, kvvJSESSIONID); callback.onResponse(token); }, error); }, error); @@ -80,7 +80,7 @@ public class Login extends HTTPService { /* 1= GET https://kvv.imp.fu-berlin.de/Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub - -> Location-Header: https://identity.fu-berlin.de:9443/idp-fub-qa/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState] + -> Location-Header: https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState] */ private void step1(final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { get("https://kvv.imp.fu-berlin.de/Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub", null, response -> { @@ -98,7 +98,7 @@ public class Login extends HTTPService { /* 2= GET [Location-Header 1] -> Set-Cookie: JSESSIONID=[JSESSION-FU] - -> Location: /idp-fub-qa/profile/SAML2/Redirect/SSO?execution=e1s1 + -> Location: /idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1 */ private void step2(String url, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { get(url, null, response -> { @@ -125,7 +125,7 @@ public class Login extends HTTPService { private void step3(String JSESSIONID_FU, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { HashMap cookies = new HashMap<>(); cookies.put("JSESSIONID", JSESSIONID_FU); - get("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> { + head("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> { callback.onResponse(true); }, error -> errorCallback.onError(new NetworkError(100130, error.networkResponse.statusCode, "Error starting login page!"))); } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenBB.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenBB.java new file mode 100644 index 0000000..dc180fa --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenBB.java @@ -0,0 +1,133 @@ +package de.sebse.fuplanner.services.kvv.types; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import de.sebse.fuplanner.services.fulogin.AccountGeneral; +import de.sebse.fuplanner.tools.CustomAccountManager; + +/** + * Created by sebastian on 29.10.17. + */ + +public class LoginTokenBB { + private final String s_session_id; + private final String session_id; + private final String username; + @Nullable private String id; + @Nullable private String studentId; + + public LoginTokenBB(String username, String s_session_id, String session_id) { + this.username = username; + this.s_session_id = s_session_id; + this.session_id = session_id; + } + + public static void load(CustomAccountManager manager, LoginTokenInterface callback) { + if (!manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE)) { + callback.run(null); + return; + } + manager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD, tokenString -> { + if (tokenString == null) { + callback.run(null); + return; + } + callback.run(LoginTokenBB.fromJsonString(tokenString)); + }); + } + + public void delete(CustomAccountManager manager) { + manager.deleteAccount(AccountGeneral.ACCOUNT_TYPE); + } + + public void setAdditionals(String id, String studentId) { + this.id = id; + this.studentId = studentId; + } + + public String getUsername() { + return username; + } + + private String getSessionId() { + return session_id; + } + + public String getSSessionId() { + return s_session_id; + } + + @Nullable + public String getId() { + return id; + } + + @Nullable + public String getStudentId() { + return studentId; + } + + public HashMap getCookies() { + HashMap cookies = new HashMap<>(); + cookies.put("session_id", getSessionId()); + cookies.put("s_session_id", getSSessionId()); + return cookies; + } + + public boolean isOtherUser(String username) { + return !this.getUsername().equals(username); + } + + @NonNull + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + HashMap cookies = this.getCookies(); + for (String header: cookies.keySet()) { + result.append(header).append("=").append(cookies.get(header)).append(";"); + } + return result.substring(0, result.length()-1); + } + + public String toJsonString() { + JSONObject json = new JSONObject(); + try { + json.put("s_session_id", s_session_id); + json.put("session_id", session_id); + json.put("username", username); + json.put("id", id); + json.put("studentId", studentId); + } catch (JSONException e) { + return null; + } + return json.toString(); + } + + private static LoginTokenBB fromJsonString(String tokenString) { + try { + JSONObject json = new JSONObject(tokenString); + LoginTokenBB token = new LoginTokenBB( + json.getString("username"), + json.getString("s_session_id"), + json.getString("session_id")); + if (!json.isNull("id")) + token.setAdditionals( + json.getString("id"), + json.getString("studentId") + ); + return token; + } catch (JSONException e) { + e.printStackTrace(); + return null; + } + } + + public interface LoginTokenInterface { + void run(LoginTokenBB token); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginToken.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenKVV.java similarity index 89% rename from app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginToken.java rename to app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenKVV.java index 95daa6f..07d51b1 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginToken.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenKVV.java @@ -3,26 +3,24 @@ package de.sebse.fuplanner.services.kvv.types; import org.json.JSONException; import org.json.JSONObject; -import java.io.Serializable; import java.util.HashMap; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import de.sebse.fuplanner.services.fulogin.AccountGeneral; import de.sebse.fuplanner.tools.CustomAccountManager; -import de.sebse.fuplanner.tools.logging.Logger; /** * Created by sebastian on 29.10.17. */ -public class LoginToken implements Serializable { +public class LoginTokenKVV { private final String username; private final String JSESSIONID; @Nullable private String fullName; @Nullable private String email; - public LoginToken(String username, String JSESSIONID) { + public LoginTokenKVV(String username, String JSESSIONID) { this.username = username; this.JSESSIONID = JSESSIONID; } @@ -37,7 +35,7 @@ public class LoginToken implements Serializable { callback.run(null); return; } - callback.run(LoginToken.fromJsonString(tokenString)); + callback.run(LoginTokenKVV.fromJsonString(tokenString)); }); } @@ -103,10 +101,10 @@ public class LoginToken implements Serializable { return json.toString(); } - private static LoginToken fromJsonString(String tokenString) { + private static LoginTokenKVV fromJsonString(String tokenString) { try { JSONObject json = new JSONObject(tokenString); - LoginToken token = new LoginToken( + LoginTokenKVV token = new LoginTokenKVV( json.getString("username"), json.getString("JSESSIONID")); if (!json.isNull("fullName")) @@ -122,6 +120,6 @@ public class LoginToken implements Serializable { } public interface LoginTokenInterface { - void run(LoginToken token); + void run(LoginTokenKVV token); } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Modules.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Modules.java index 128ba8e..188c755 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Modules.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Modules.java @@ -25,6 +25,9 @@ import androidx.annotation.Nullable; */ public class Modules implements Iterable, Serializable { + public static final int TYPE_KVV = 1; + public static final int TYPE_BB = 2; + private SortedListModule list; private final String mUsername; private transient long mLastTimestamp = 0; @@ -37,8 +40,8 @@ public class Modules implements Iterable, Serializable { this.list = new SortedListModule(); } - public void addModule(@Nullable Semester semester, HashSet lvNumber, String title, LinkedHashSet lecturer, String type, String description, String ID) { - Module m = new Module(semester, lvNumber, title, lecturer, type, description, ID); + public void addModule(@Nullable Semester semester, HashSet lvNumber, String title, LinkedHashSet lecturer, String type, String description, String ID, int moduleType) { + Module m = new Module(semester, lvNumber, title, lecturer, type, description, ID, moduleType); this.list.add(m); } @@ -154,14 +157,16 @@ public class Modules implements Iterable, Serializable { } public class Module implements Serializable { + @Nullable public final Semester semester; - @NotNull final HashSet lvNumber; + @NotNull public final HashSet lvNumber; @NotNull public final String title; @NotNull public final ArrayList lecturer; @Nullable public final String type; @Nullable public final String description; @NotNull private final String ID; + @NotNull private final int moduleType; @Nullable public ArrayList announcements; @Nullable public AssignmentList assignments; @Nullable public EventList events; @@ -182,7 +187,7 @@ public class Modules implements Iterable, Serializable { return userPoint/maxPoint; } - private Module(@Nullable Semester semester, @NotNull HashSet lvNumber, @NotNull String title, @NotNull LinkedHashSet lecturer, @Nullable String type, @Nullable String description, @NotNull String ID) { + private Module(@Nullable Semester semester, @NotNull HashSet lvNumber, @NotNull String title, @NotNull LinkedHashSet lecturer, @Nullable String type, @Nullable String description, @NotNull String ID, @NotNull int moduleType) { title = title.replaceAll("(.*?) (S[0-9]{2}|W[0-9/]{5})", "$1"); @@ -193,6 +198,7 @@ public class Modules implements Iterable, Serializable { this.type = type; this.description = description; this.ID = ID; + this.moduleType = moduleType; } @NonNull @@ -213,7 +219,11 @@ public class Modules implements Iterable, Serializable { @Override public int hashCode() { - return Objects.hashCode(semester, lvNumber, title, lecturer, type, description, ID); + return Objects.hashCode(semester, lvNumber, title, lecturer, type, description, ID, moduleType); + } + + public int getModuleType() { + return moduleType; } } } diff --git a/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java b/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java index f035efc..c18197f 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java @@ -52,8 +52,17 @@ public class HTTPService { successResponseListener.remove(id); } + protected void head(String url, @Nullable final HashMap cookies, Response.Listener response, Response.ErrorListener error) { + get(url, cookies, response, error, true); + } + protected void get(String url, @Nullable final HashMap cookies, Response.Listener response, Response.ErrorListener error) { - HttpRequest request = new HttpRequest(Request.Method.GET, url, response, error) { + get(url, cookies, response, error, false); + } + + protected void get(String url, @Nullable final HashMap cookies, Response.Listener response, Response.ErrorListener error, boolean noBody) { + int requestMethod = noBody ? Request.Method.HEAD : Request.Method.GET; + HttpRequest request = new HttpRequest(requestMethod, url, response, error) { @Override public void deliverError(VolleyError error) { if (error == null) {