package carpool.resources;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import org.restlet.engine.header.Header;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.*;
import org.restlet.util.Series;
import org.restlet.data.*;
import org.json.JSONObject;
import carpool.common.DebugLog;
import carpool.configurations.CarpoolConfig;
import carpool.dbservice.AuthDaoService;
import carpool.encryption.SessionCrypto;
import carpool.exception.PseudoException;
import carpool.exception.auth.AccountAuthenticationException;
import carpool.exception.auth.DuplicateSessionCookieException;
import carpool.exception.auth.SessionEncodingException;
import carpool.exception.validation.EntityTooLargeException;
import carpool.factory.JSONFactory;
import carpool.resources.userResource.userAuthResource.UserAuthenticationResource;
public class PseudoResource extends ServerResource{
/*set the response header to allow for CORS*/
public void addCORSHeader(){
Series<Header> responseHeaders = (Series<Header>) getResponse().getAttributes().get("org.restlet.http.headers");
if (responseHeaders == null) {
responseHeaders = new Series(Header.class);
responseHeaders.add("Access-Control-Allow-Origin", "*");
responseHeaders.add("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS");
responseHeaders.add("Access-Control-Allow-Headers", "Content-Type");
responseHeaders.add("Access-Control-Allow-Headers", "authCode");
responseHeaders.add("Access-Control-Allow-Headers", "origin, x-requested-with, content-type");
}
if (responseHeaders != null){
getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders);
}
}
protected Object parseJSON(Representation entity) throws PseudoException{
return null;
}
public void checkEntity(Representation entity) throws EntityTooLargeException{
if (entity != null && entity.getSize() > CarpoolConfig.max_PostLength){
throw new EntityTooLargeException();
}
}
public void checkFileEntity(Representation entity) throws NullPointerException, EntityTooLargeException{
if (entity != null && entity.getSize() > CarpoolConfig.max_FileLength){
throw new EntityTooLargeException();
}
}
/******************
*
* Cookie Area
*
******************/
public boolean validateAuthentication(int userId) throws PseudoException{
return !CarpoolConfig.cookieEnabled ? true : UserAuthenticationResource.validateCookieSession(userId, this.getSessionString());
}
public void addAuthenticationSession(int userId) throws PseudoException{
Series<CookieSetting> cookieSettings = this.getResponse().getCookieSettings();
CookieSetting newCookie = UserAuthenticationResource.openCookieSession(userId);
cookieSettings.clear();
cookieSettings.add(newCookie);
this.setCookieSettings(cookieSettings);
}
public void closeAuthenticationSession(int userId) throws PseudoException{
Series<Cookie> cookies = this.getRequest().getCookies();
UserAuthenticationResource.closeCookieSession(cookies);
Series<CookieSetting> cookieSettings = this.getResponse().getCookieSettings();
cookieSettings.clear();
this.setCookieSettings(cookieSettings);
}
/******************
*
* Query Area
*
******************/
public String getReqAttr(String fieldName) throws UnsupportedEncodingException{
Object attr = this.getRequestAttributes().get(fieldName);
return attr != null ? java.net.URLDecoder.decode((String)attr, "utf-8") : null;
}
public String getQueryVal(String fieldName) throws UnsupportedEncodingException{
String val = getQuery().getValues(fieldName);
return val != null ? java.net.URLDecoder.decode(val, "utf-8") : null;
}
public String getPlainQueryVal(String fieldName){
String val = getQuery().getValues(fieldName);
return val;
}
public String getToUtf(String var) throws UnsupportedEncodingException{
return java.net.URLEncoder.encode(var, "utf-8");
}
/******************
*
* Exception Handling Area
*
******************/
public StringRepresentation doPseudoException(PseudoException e){
DebugLog.d(e);
switch(e.getCode()){
case 1: case 2: case 4: case 8: case 19: case 21:
//Not Found
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
break;
case 3: case 5: case 9: case 20:
//OwnerNotMatch
setStatus(Status.CLIENT_ERROR_NOT_ACCEPTABLE);
break;
case 6:
//TransactionAccessViolation
setStatus(Status.CLIENT_ERROR_FAILED_DEPENDENCY);
break;
case 7:
//TransactionStateViolation
setStatus(Status.CLIENT_ERROR_PRECONDITION_FAILED);
break;
case 10: case 11:
//DuplicateSessionCookie: //SessionEncoding
this.getResponse().getCookieSettings().clear();
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
break;
// case 12: gone
// //UnacceptableSearchState
// setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
// break;
case 13:
//UnexceppedCookie
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
break;
case 14:
//AccountAuthentication
setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
break;
case 15:
//EntityTooLarge
setStatus(Status.CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE);
break;
case 16:
//LocationNotFoundException
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
break;
case 17:
//LocationException
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
break;
case 18:
//ValidationException
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
break;
default:
setStatus(Status.SERVER_ERROR_INTERNAL);
break;
}
return new StringRepresentation(e.getExceptionText());
}
public StringRepresentation doException(Exception e){
DebugLog.d(e);
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return new StringRepresentation("不好意思..哪里弄错了,请稍后重试");
}
public Representation buildQuickResponse(String responseText){
JSONObject response = new JSONObject();
response = JSONFactory.toJSON(responseText);
return new JsonRepresentation(response);
}
public Representation quickRespond(String responseText){
addCORSHeader();
return buildQuickResponse(responseText);
}
/******************
*
* Take the options
*
******************/
//needed here since backbone will try to send OPTIONS to /id before PUT or DELETE
@Options
public Representation takeOptions(Representation entity) {
addCORSHeader();
setStatus(Status.SUCCESS_OK);
return new JsonRepresentation(new JSONObject());
}
/******************
*
* New Session Area
*
******************/
protected boolean validateAuthentication() throws PseudoException{
return !CarpoolConfig.cookieEnabled ? true : validateCookieSession();
}
protected String generateAuthenticationSessionString(int userId) throws PseudoException{
return generateSesstionString(userId);
}
protected void openAuthenticationSession(int userId) throws PseudoException{
Series<CookieSetting> cookieSettings = this.getResponse().getCookieSettings();
CookieSetting newCookie = openSession(userId);
cookieSettings.add(newCookie);
this.setCookieSettings(cookieSettings);
}
protected void closeAuthenticationSession() throws PseudoException{
closeSession();
}
protected String getSessionString() throws PseudoException{
ArrayList<String> sessionString = new ArrayList<String>();
String newDecryptedString = "";
//first check header for auth, if not in header, then check for cookies for auth
Series<Header> requestHeaders = (Series<Header>) getRequest().getAttributes().get("org.restlet.http.headers");
if (requestHeaders != null) {
if (requestHeaders.getFirstValue(CarpoolConfig.cookie_userSession, true) != null){
sessionString.add(requestHeaders.getFirstValue(CarpoolConfig.cookie_userSession, true));
}
}
if (sessionString.size() == 0){
Series<Cookie> cookies = this.getRequest().getCookies();
for( Cookie cookie : cookies){
if (cookie.getName().equals(CarpoolConfig.cookie_userSession)){
sessionString.add(cookie.getValue());
}
}
}
// if (sessionString.size() > 1){
// throw new DuplicateSessionCookieException();
// }
if (sessionString.size() == 0){
return "";
}
else{
try{
newDecryptedString = SessionCrypto.decrypt(sessionString.get(0));
}
catch (Exception e){
e.printStackTrace();
throw new SessionEncodingException();
}
return newDecryptedString;
}
}
protected int getUserIdFromSessionString(String sessionString)throws PseudoException{
String userIdStr = sessionString.split(CarpoolConfig.redisSeperatorRegex)[1];
int userId = -1;
try{
userId = Integer.parseInt(userIdStr);
} catch (NumberFormatException e){
throw new AccountAuthenticationException("UserCookieResource:: getSessionString:: Session does not exist");
}
return userId;
}
/******************
*
* Authentication Area
*
******************/
private String generateSesstionString(int userId) throws PseudoException{
// generate session string and stores session in Redis
String sessionString = AuthDaoService.generateUserSession(userId);
try{
String encrypted = SessionCrypto.encrypt(sessionString);
return encrypted;
} catch (Exception e){
throw new SessionEncodingException();
}
}
private boolean validateCookieSession() throws PseudoException{
String sessionString = getSessionString();
if (sessionString == null || sessionString.length() == 0){
return false;
}
int userId = getUserIdFromSessionString(sessionString);
if (userId == -1){
throw new AccountAuthenticationException("UserCookieResource:: validateCookieSession:: Invalid ID, ID is -1");
}
boolean login = false;
try{
String decryptedString = SessionCrypto.decrypt(sessionString);
login = AuthDaoService.validateUserSession(userId, decryptedString);
}
catch (Exception e){
e.printStackTrace();
throw new SessionEncodingException();
}
if (!login){
throw new AccountAuthenticationException("UserCookieResource:: validateCookieSession:: Session Validation Failed");
}
return login;
}
private CookieSetting openSession(int userId) throws PseudoException{
String encryptedString = generateSesstionString(userId);
CookieSetting newCookieSetting;
try{
newCookieSetting = new CookieSetting(0, CarpoolConfig.cookie_userSession, encryptedString);
newCookieSetting.setMaxAge(CarpoolConfig.cookie_maxAge);
}
catch (Exception e){
throw new SessionEncodingException();
}
return newCookieSetting;
}
private boolean closeSession() throws PseudoException{
try{
String sessionString = getSessionString();
String decryptedString = SessionCrypto.decrypt(sessionString);
return AuthDaoService.closeUserSession(decryptedString);
}
catch (AccountAuthenticationException e){
DebugLog.d(e);
return true;
}
catch (Exception e){
DebugLog.d(e);
throw new SessionEncodingException();
}
}
}