mirror of https://github.com/ThmmyNoLife/mTHMMY
Ezerous
8 years ago
6 changed files with 352 additions and 291 deletions
@ -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<Cookie> 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-----------------------------------------
|
||||
|
|
||||
|
} |
Loading…
Reference in new issue