From 8b841ebe6770e5bd61bc4dbffb4457b9dab0a924 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 28 Nov 2016 16:32:27 +0200 Subject: [PATCH] First fix login/logout --- app/build.gradle | 8 +- .../thmmy/mthmmy/activities/BaseActivity.java | 263 ++-------------- .../mthmmy/activities/LoginActivity.java | 46 +-- .../thmmy/mthmmy/activities/MainActivity.java | 31 +- .../sections/recent/RecentFragment.java | 4 +- .../thmmy/mthmmy/session/SessionManager.java | 291 ++++++++++++++++++ 6 files changed, 352 insertions(+), 291 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java diff --git a/app/build.gradle b/app/build.gradle index dfc04319..4ee4c703 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,15 +2,15 @@ apply plugin: 'com.android.application' android { compileSdkVersion 25 - buildToolsVersion "25.0.0" + buildToolsVersion "25.0.1" defaultConfig { vectorDrawables.useSupportLibrary = true applicationId "gr.thmmy.mthmmy" minSdkVersion 19 targetSdkVersion 25 - versionCode 2 - versionName "0.16" + versionCode 3 + versionName "0.17" } buildTypes { release { @@ -23,7 +23,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:25.0.1' - compile 'com.android.support:design:25.0.0' + compile 'com.android.support:design:25.0.1' compile 'com.squareup.okhttp3:okhttp:3.4.0' compile 'com.jakewharton:butterknife:7.0.1' compile 'org.jsoup:jsoup:1.10.1' diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java index 36924d18..287bc00c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java @@ -3,279 +3,52 @@ package gr.thmmy.mthmmy.activities; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.util.Log; import com.franmontiel.persistentcookiejar.PersistentCookieJar; import com.franmontiel.persistentcookiejar.cache.SetCookieCache; import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.io.IOException; -import java.util.List; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.net.ssl.SSLHandshakeException; - -import okhttp3.Cookie; -import okhttp3.CookieJar; -import okhttp3.FormBody; -import okhttp3.HttpUrl; +import gr.thmmy.mthmmy.session.SessionManager; import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -public class BaseActivity extends AppCompatActivity { +public class BaseActivity extends AppCompatActivity +{ + // Client & Cookies + protected static OkHttpClient client; + private static PersistentCookieJar cookieJar; + private static SharedPrefsCookiePersistor sharedPrefsCookiePersistor; -//----------------------------------------CLASS VARIABLES----------------------------------------- - /* --Response Codes-- */ - static final int LOGGED_OUT = 0; - static final int LOGGED_IN = 1; - static final int WRONG_USER = 2; - static final int WRONG_PASSWORD = 3; - static final int FAILED = 4; - static final int CERTIFICATE_ERROR = 5; - static final int OTHER_ERROR = 6; - /* --Response Codes End-- */ - /* --Shared Preferences-- */ - static final String USER_NAME = "userNameKey"; - static final String GUEST_PREF_USERNAME = "GUEST"; - static final String LOG_STATUS = "isLoggedIn"; - private static final String SHARED_PREFS_NAME = "thmmySharedPrefs"; - static SharedPreferences _prefs; - /* --Shared Preferences End-- */ + //Shared Preferences + private static final String SHARED_PREFS_NAME = "ThmmySharedPrefs"; + protected static SharedPreferences sharedPrefs; - /* --Client Stuff-- */ - static OkHttpClient client; - private static CookieJar cookieJar; - private static SharedPrefsCookiePersistor sharedPrefsCookiePersistor; - /* --Client Stuff End-- */ + //SessionManager + protected static SessionManager sessionManager; //Other variables private static boolean init = false; //To initialize stuff only once per app start - private static final String TAG = "BaseActivity"; -//--------------------------------------CLASS VARIABLES END--------------------------------------- - -//-------------------------------------CLIENT AND COOKIES----------------------------------------- - private static CookieJar getCookieJar() { - return cookieJar; - } - - private static SharedPrefsCookiePersistor getSharedPrefsCookiePersistor() { - return sharedPrefsCookiePersistor; - } - public static OkHttpClient getClient() { - return client; - } -//-----------------------------------CLIENT AND COOKIES END--------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!init) { - _prefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE); + sharedPrefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE); sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(BaseActivity.this); cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor); client = new OkHttpClient.Builder() .cookieJar(cookieJar) .build(); + sessionManager = new SessionManager(client, cookieJar, sharedPrefsCookiePersistor, sharedPrefs); init = true; } } - /* - THMMY CLASS - -- inner class of BaseActivity - - This class handles all session related operations (e.g. login, logout) - Also stores data to SharedPreferences file. - */ - -//---------------------------------------INNER CLASS BEGINS--------------------------------------- - public static class Thmmy { - //Class variables - private static final HttpUrl loginUrl = HttpUrl - .parse("https://www.thmmy.gr/smf/index.php?action=login2"); - private static final HttpUrl indexUrl = HttpUrl - .parse("https://www.thmmy.gr/smf/index.php"); - - -//-------------------------------------------LOGIN------------------------------------------------ - //Two options: (username, password, duration) or nothing - cookies - static void login(String... strings) { - Log.d("Login", "Logging in..."); - Request request; - - if (strings.length == 3) { //Actual login - String loginName = strings[0]; - String password = strings[1]; - String duration = strings[2]; - - ((PersistentCookieJar) getCookieJar()).clear(); - - RequestBody formBody = new FormBody.Builder() //Build login form - .add("user", loginName) - .add("passwrd", password) - .add("cookielength", duration) //Forever is -1 - .build(); - request = new Request.Builder() //Build the request - .url(loginUrl) - .post(formBody) - .build(); - } else { //Already logged in, just get cookies - request = new Request.Builder() //Build the request - .url(loginUrl) - .build(); - } - - try { - Response response = client.newCall(request).execute(); //Make the request - /* --Handle response-- */ - Document document = Jsoup.parse(response.body().string()); - Element logout = document.getElementById("logoutbtn"); //Get logout button - - if (logout != null) { //If there is a logout button, then I successfully logged in - Log.i("Login", "Login successful"); - setPersistentCookieSession(); - - //Edit SharedPreferences, save session's data - _prefs.edit().putString(USER_NAME, extractUserName(document)).apply(); - _prefs.edit().putInt(LOG_STATUS, LOGGED_IN).apply(); - } else { //I am not logged in, what went wrong? - Log.w("Login", "Login failed"); - _prefs.edit().putInt(LOG_STATUS, FAILED).apply(); //Request failed - - //Making error more specific - - Elements error = document.select("b:contains(That username does not exist.)"); - if (error.size() == 1) { //Wrong username - _prefs.edit().putInt(LOG_STATUS, WRONG_USER).apply(); - Log.d("Login", "Wrong Username"); - } - - error = document.select("body:contains(Password incorrect)"); - if (error.size() == 1) { //Wrong password - _prefs.edit().putInt(LOG_STATUS, WRONG_PASSWORD).apply(); - Log.d("Login", "Wrong Password"); - } - - ((PersistentCookieJar) getCookieJar()).clear(); - - } - //Request exception handling - } catch (SSLHandshakeException e) { - _prefs.edit().putInt(LOG_STATUS, CERTIFICATE_ERROR).apply(); - Log.w("Login", "Certificate problem"); - - } catch (Exception e) { - _prefs.edit().putInt(LOG_STATUS, OTHER_ERROR).apply(); - Log.e("Login", "Error", e); - } - } -//--------------------------------------LOGIN ENDS------------------------------------------------ - -//---------------------------------------LOGOUT--------------------------------------------------- - static int logout() { - String _logout_link = ""; - { //Find current logout link - try { - //Build and make a request for the index (home) page - Request request = new Request.Builder() - .url(indexUrl) - .build(); - Response response = client.newCall(request).execute(); - Document document = Jsoup.parse(response.body().string()); - Element logout = document.getElementById("logoutbtn"); //Find the logout button - _logout_link = HttpUrl.parse(logout.attr("href")).toString(); //Get the url - } catch (IOException e) { - e.printStackTrace(); - } - } - - if (Objects.equals(_logout_link, "")) { //If logout button wasn't found - return OTHER_ERROR; //Something went wrong - } - - //Attempt logout - OkHttpClient client = getClient(); - Request request = new Request.Builder() - .url(_logout_link) - .build(); - - try { - Response response = client.newCall(request).execute(); - Document document = Jsoup.parse(response.body().string()); - - Elements login = document.select("[pageValue=Login]"); //Find login button - ((PersistentCookieJar) getCookieJar()).clear(); - if (!login.isEmpty()) { //If found, logout was successful - Log.i("Logout", "Logout successful"); - _prefs.edit().clear().apply(); //Clear session data - //User is now guest - _prefs.edit().putString(USER_NAME, GUEST_PREF_USERNAME).apply(); - _prefs.edit().putInt(LOG_STATUS, LOGGED_IN).apply(); - return LOGGED_OUT; - } else { - Log.w("Logout", "Logout failed"); - return FAILED; - } - } catch (SSLHandshakeException e) { - Log.w("Logout", "Certificate problem (please switch to unsafe connection)."); - return CERTIFICATE_ERROR; - - } catch (Exception e) { - Log.d("Logout", "ERROR", e); - return OTHER_ERROR; - } - } -//----------------------------------------LOGOUT ENDS--------------------------------------------- - -//-------------------------------------------MISC------------------------------------------------- - private static String extractUserName(Document doc) { - if (doc != null) { - Elements user = doc.select("div[id=myuser] > h3"); - - if (user.size() == 1) { - String txt = user.first().ownText(); - - Pattern pattern = Pattern.compile(", (.*?),"); - Matcher matcher = pattern.matcher(txt); - if (matcher.find()) - return matcher.group(1); - } - } - - return null; - } - - private static void setPersistentCookieSession() { - List cookieList = getCookieJar().loadForRequest(HttpUrl - .parse("https://www.thmmy.gr")); - - if (cookieList.size() == 2) { - if ((cookieList.get(0).name().equals("THMMYgrC00ki3")) - && (cookieList.get(1).name().equals("PHPSESSID"))) { - Cookie.Builder builder = new Cookie.Builder(); - builder.name(cookieList.get(1).name()) - .value(cookieList.get(1).value()) - .domain(cookieList.get(1).domain()) - .expiresAt(cookieList.get(0).expiresAt()); - cookieList.remove(1); - cookieList.add(builder.build()); - getSharedPrefsCookiePersistor().clear(); - getSharedPrefsCookiePersistor().saveAll(cookieList); - } - } - } + public static OkHttpClient getClient() + { + return client; } -//----------------------------------------INNER CLASS ENDS---------------------------------------- + } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java index f741f0db..39256f21 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java @@ -12,6 +12,12 @@ import android.widget.Toast; import gr.thmmy.mthmmy.R; +import static gr.thmmy.mthmmy.session.SessionManager.EXCEPTION; +import static gr.thmmy.mthmmy.session.SessionManager.FAILURE; +import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS; +import static gr.thmmy.mthmmy.session.SessionManager.WRONG_PASSWORD; +import static gr.thmmy.mthmmy.session.SessionManager.WRONG_USER; + public class LoginActivity extends BaseActivity { //-----------------------------------------CLASS VARIABLES------------------------------------------ @@ -64,8 +70,7 @@ public class LoginActivity extends BaseActivity { public void onClick(View view) { //Session data update - _prefs.edit().putString(USER_NAME, GUEST_PREF_USERNAME).apply(); - _prefs.edit().putInt(LOG_STATUS, LOGGED_IN).apply(); + sessionManager.guestLogin(); //Go to main Intent intent = new Intent(LoginActivity.this, MainActivity.class); @@ -115,8 +120,7 @@ public class LoginActivity extends BaseActivity { @Override protected Integer doInBackground(String... params) { - Thmmy.login(params[0], params[1], "-1"); //Attempt login - return _prefs.getInt(LOG_STATUS, OTHER_ERROR); + return sessionManager.login(params[0], params[1]); } @Override @@ -134,6 +138,16 @@ public class LoginActivity extends BaseActivity { @Override protected void onPostExecute(Integer result) { //Handle attempt result switch (result) { + case SUCCESS: //Successful login + Toast.makeText(getApplicationContext(), + "Login successful!", Toast.LENGTH_LONG) + .show(); + //Go to main + Intent intent = new Intent(LoginActivity.this, MainActivity.class); + startActivity(intent); + finish(); + overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); + break; case WRONG_USER: Toast.makeText(getApplicationContext(), "Wrong username!", Toast.LENGTH_LONG).show(); @@ -143,31 +157,17 @@ public class LoginActivity extends BaseActivity { "Wrong password!", Toast.LENGTH_LONG) .show(); break; - case FAILED: + case FAILURE: Toast.makeText(getApplicationContext(), - "Check your connection!", Toast.LENGTH_LONG) + "Login failed...", Toast.LENGTH_LONG) .show(); break; - case CERTIFICATE_ERROR: + case EXCEPTION: Toast.makeText(getApplicationContext(), - "Certificate error!", Toast.LENGTH_LONG) + "Login failed...", Toast.LENGTH_LONG) .show(); break; - case OTHER_ERROR: - Toast.makeText(getApplicationContext(), - "Check your connection!", Toast.LENGTH_LONG) - .show(); - break; - case LOGGED_IN: //Successful login - Toast.makeText(getApplicationContext(), - "Login successful!", Toast.LENGTH_LONG) - .show(); - //Go to main - Intent intent = new Intent(LoginActivity.this, MainActivity.class); - startActivity(intent); - finish(); - overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); - break; + } //Login failed btnLogin.setEnabled(true); //Re-enable login button diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java index afe564d8..916e81e8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java @@ -14,13 +14,12 @@ import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; -import java.util.Objects; - import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.data.TopicSummary; import gr.thmmy.mthmmy.sections.recent.RecentFragment; -import static gr.thmmy.mthmmy.activities.BaseActivity.Thmmy.logout; +import static gr.thmmy.mthmmy.session.SessionManager.LOGGED_IN; +import static gr.thmmy.mthmmy.session.SessionManager.LOGGED_OUT; public class MainActivity extends BaseActivity implements RecentFragment.OnListFragmentInteractionListener { @@ -33,7 +32,7 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - if (_prefs.getInt(LOG_STATUS, OTHER_ERROR) != LOGGED_IN) { //If not logged in + if (sessionManager.getLogStatus()== LOGGED_OUT) { //If not logged in //Go to login Intent intent = new Intent(MainActivity.this, LoginActivity.class); startActivity(intent); @@ -69,13 +68,11 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF this.menu = menu; getMenuInflater().inflate(R.menu.menu_main, menu); - if (_prefs.getInt(LOG_STATUS, OTHER_ERROR) == LOGGED_IN - && !Objects.equals(_prefs.getString(USER_NAME, null), GUEST_PREF_USERNAME)) { - //Will enter when logged out or if user is guest - hideLogin(); - } else - //Will enter when logged in + if (sessionManager.getLogStatus()!= LOGGED_IN) //When logged out or if user is guest hideLogout(); + else + hideLogin(); + return true; } @@ -171,7 +168,7 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF ProgressDialog progressDialog; protected Integer doInBackground(Void... voids) { - return logout(); + return sessionManager.logout(); } protected void onPreExecute() { //Show a progress dialog until done @@ -184,15 +181,13 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF protected void onPostExecute(Integer result) { //Handle attempt result progressDialog.dismiss(); //Hide progress dialog - if (result == LOGGED_OUT) { //Successful logout - /* - At this point result is LOGGED_OUT - BUT pref's LOGIN_STATUS variable is LOGGED_IN!! - and USER_NAME is GUEST - */ + if (result == LOGGED_OUT) //Successful logout + { Toast.makeText(getBaseContext(), "Logged out successfully!", Toast.LENGTH_LONG).show(); + sessionManager.guestLogin(); //Fall to guest login hideLogout(); - } else //Logout failed + } + else //Logout failed hideLogin(); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentFragment.java index 57fbd931..864ee202 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentFragment.java @@ -27,7 +27,9 @@ import java.util.regex.Pattern; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.BaseActivity; import gr.thmmy.mthmmy.data.TopicSummary; +import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.CustomRecyclerView; +import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -202,7 +204,7 @@ public class RecentFragment extends Fragment { public class RecentTask extends AsyncTask { private static final String TAG = "RecentTask"; - private final String thmmyUrl = "https://www.thmmy.gr/smf/index.php"; + private final HttpUrl thmmyUrl = SessionManager.indexUrl; private Document document; diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java new file mode 100644 index 00000000..d608c68f --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -0,0 +1,291 @@ +package gr.thmmy.mthmmy.session; + +import android.content.SharedPreferences; +import android.util.Log; + +import com.franmontiel.persistentcookiejar.PersistentCookieJar; +import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import okhttp3.Cookie; +import okhttp3.FormBody; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +/** + This class handles all session related operations (e.g. login, logout) + and stores data to SharedPreferences (session informarion and cookies). +*/ +public class SessionManager +{ + //Class TAG + private static final String TAG = "SessionManager"; + + //Generic constants + public static final HttpUrl indexUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php"); + private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); + private static final String guestName = "Guest"; + + //Response Codes + public static final int SUCCESS = 0; + public static final int FAILURE = 1; //Generic Error + public static final int WRONG_USER = 2; + public static final int WRONG_PASSWORD = 3; + public static final int EXCEPTION = 4; + + //Login status codes + public static final int LOGGED_OUT = 0; + public static final int LOGGED_IN = 1; //Logged in (as a normal user) + public static final int AS_GUEST = 2; //User chose to continue as guest + + // Client & Cookies + private OkHttpClient client; + private PersistentCookieJar cookieJar; + private SharedPrefsCookiePersistor cookiePersistor; //Used to explicitly edit cookies in cookieJar + + //Shared Preferences & its keys + private SharedPreferences sharedPrefs; + private static final String USERNAME = "Username"; + private static final String LOGOUT_LINK = "LogoutLink"; + private static final String LOGIN_STATUS = "IsLoggedIn"; + + //Constructor + public SessionManager(OkHttpClient client, PersistentCookieJar cookieJar, + SharedPrefsCookiePersistor cookiePersistor, SharedPreferences sharedPrefs) + { + this.client = client; + this.cookiePersistor=cookiePersistor; + this.cookieJar = cookieJar; + this.sharedPrefs = sharedPrefs; + } + + //------------------------------------AUTH BEGINS---------------------------------------------- + /** + * Login function with two options: (username, password) or nothing (using saved cookies). + * Always call it in a separate thread. + */ + public int login(String... strings) + { + Log.i(TAG, "Logging in..."); + + //Build the login request for each case + Request request; + if (strings.length == 2) + { + clearSessionData(); + + String loginName = strings[0]; + String password = strings[1]; + + RequestBody formBody = new FormBody.Builder() + .add("user", loginName) + .add("passwrd", password) + .add("cookielength", "-1") //-1 is forever + .build(); + request = new Request.Builder() + .url(loginUrl) + .post(formBody) + .build(); + } + else + { + request = new Request.Builder() + .url(loginUrl) + .build(); + } + + try { + //Make request & handle response + Response response = client.newCall(request).execute(); + Document document = Jsoup.parse(response.body().string()); + + Element logoutButton = document.getElementById("logoutbtn"); //Attempt to find logout button + if (logoutButton != null) //If logout button exists, login was successful + { + Log.i(TAG, "Login successful!"); + setPersistentCookieSession(); //Store cookies + + //Edit SharedPreferences, save session's data + sharedPrefs.edit().putInt(LOGIN_STATUS, LOGGED_IN).apply(); + sharedPrefs.edit().putString(USERNAME, extractUserName(document)).apply(); + sharedPrefs.edit().putString(LOGOUT_LINK, HttpUrl.parse(logoutButton.attr("href")).toString()).apply(); + + return SUCCESS; + } + else + { + Log.i(TAG, "Login failed."); + + //Investigate login failure + Elements error = document.select("b:contains(That username does not exist.)"); + if (error.size() == 1) { //Wrong username + Log.i(TAG, "Wrong Username"); + return WRONG_USER; + } + + error = document.select("body:contains(Password incorrect)"); + if (error.size() == 1) { //Wrong password + Log.i(TAG, "Wrong Password"); + return WRONG_PASSWORD; + } + + //Other error e.g. session was reset server-side + clearSessionData(); //Clear invalid saved data + return FAILURE; + } + //Handle exception + } catch (Exception e) { + Log.w(TAG, "Login Exception: "+ e.getMessage(), e); + return EXCEPTION; + } + } + + /** + * A function that checks the validity of the current saved session (if it exists). + * If LOGIN_STATUS is true, it will call login() with cookies. This can only return + * the codes {SUCCESS, FAILURE, EXCEPTION}. EXCEPTION is considered a SUCCESS (e.g. no internet + * connection), at least until a more thorough handling of different exceptions is implemented. + * Always call it in a separate thread. + */ + public void validateSession() + { + Log.i(TAG, "Validating session..."); + + //Check if user is currently logged in + int status = sharedPrefs.getInt(LOGIN_STATUS,LOGGED_OUT); + if(status==LOGGED_IN) + { + int loginResult = login(); + if(loginResult == SUCCESS || loginResult == EXCEPTION) + return; + } + else if(status==AS_GUEST) + return; + + clearSessionData(); + } + + /** + * Call this function when user explicitly chooses to continue as a guest (UI thread). + */ + public void guestLogin() + { + Log.i("TAG", "Continuing as a guest, as chosen by the user."); + clearSessionData(); + sharedPrefs.edit().putInt(LOGIN_STATUS, AS_GUEST).apply(); + } + + + /** + * Logout function. Always call it in a separate thread. + */ + public int logout() + { + Log.i(TAG, "Logging out..."); + + Request request = new Request.Builder() + .url(sharedPrefs.getString(LOGOUT_LINK,"LogoutLink")) + .build(); + + try { + //Make request & handle response + Response response = client.newCall(request).execute(); + Document document = Jsoup.parse(response.body().string()); + + Elements loginButton = document.select("[value=Login]"); //Attempt to find login button + if (!loginButton.isEmpty()) //If login button exists, logout was successful + { + Log.i("Logout", "Logout successful!"); + return SUCCESS; + } + else + { + Log.i(TAG, "Logout failed."); + return FAILURE; + } + } catch (Exception e) { + Log.w(TAG, "Logout Exception: "+ e.getMessage(), e); + return EXCEPTION; + } finally { + //All data should always be cleared from device regardless the result of logout + clearSessionData(); + Log.i(TAG,"Session data cleared."); + } + } + //--------------------------------------AUTH ENDS----------------------------------------------- + + //---------------------------------------GETTERS------------------------------------------------ + public String getUsername() { + return sharedPrefs.getString(USERNAME, "Username"); + } + + public String getLogoutLink() { + return sharedPrefs.getString(LOGOUT_LINK, "LogoutLink"); + } + + public int getLogStatus() { + return sharedPrefs.getInt(LOGIN_STATUS, LOGGED_OUT); + } + + //--------------------------------------GETTERS END--------------------------------------------- + + //------------------------------------OTHER FUNCTIONS------------------------------------------- + private void setPersistentCookieSession() + { + List cookieList = cookieJar.loadForRequest(indexUrl); + + if (cookieList.size() == 2) + { + if ((cookieList.get(0).name().equals("THMMYgrC00ki3")) + && (cookieList.get(1).name().equals("PHPSESSID"))) { + Cookie.Builder builder = new Cookie.Builder(); + builder.name(cookieList.get(1).name()) + .value(cookieList.get(1).value()) + .domain(cookieList.get(1).domain()) + .expiresAt(cookieList.get(0).expiresAt()); + cookieList.remove(1); + cookieList.add(builder.build()); + cookiePersistor.clear(); + cookiePersistor.saveAll(cookieList); + } + } + } + + private void clearSessionData() + { + cookieJar.clear(); + sharedPrefs.edit().clear().apply(); //Clear session data + sharedPrefs.edit().putString(USERNAME, guestName).apply(); //User becomes guest + sharedPrefs.edit().putInt(LOGIN_STATUS, LOGGED_OUT).apply(); + } + + private String extractUserName(Document doc) + { + if (doc != null) { + Elements user = doc.select("div[id=myuser] > h3"); + + if (user.size() == 1) { + String txt = user.first().ownText(); + + Pattern pattern = Pattern.compile(", (.*?),"); + Matcher matcher = pattern.matcher(txt); + if (matcher.find()) + return matcher.group(1); + } + } + return null; + } + //----------------------------------OTHER FUNCTIONS END----------------------------------------- + +}