package com.pugh.sockso.web; import com.pugh.sockso.Utils; import com.pugh.sockso.db.Database; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Date; import org.apache.log4j.Logger; /** * Handles storing and retreiving information from the session * */ public class Session { protected static final String SESS_ID_COOKIE = "sessId"; protected static final String SESS_CODE_COOKIE = "sessCode"; private final Logger log = Logger.getLogger( Session.class ); private final Database db; private final Request req; private final Response res; /** * Constructor * * @param db * @param req * @param res * */ public Session( final Database db, final Request req, final Response res ) { this.db = db; this.req = req; this.res = res; } /** * Creates a new session for the user with the specified ID * * @param userId * * @throws java.sql.SQLException * */ public void create( final int userId ) throws SQLException { PreparedStatement st = null; ResultSet rs = null; String sql = ""; try { final String sessCode = Utils.getRandomString( 10 ); sql = " insert into sessions ( code, user_id, date_created ) " + " values ( ?, ?, current_timestamp ); "; st = db.prepare( sql ); st.setString( 1, sessCode ); st.setInt( 2, userId ); st.execute(); Utils.close( st ); // fetch created session info, then set cookies // and send user back to home page sql = " select s.id as id " + " from sessions s " + " where s.code = ? " + " and s.user_id = ? " + " order by s.date_created desc " + " limit 1 "; st = db.prepare( sql ); st.setString( 1, sessCode ); st.setInt( 2, userId ); rs = st.executeQuery(); if ( !rs.next() ) throw new SQLException( "could not fetch session id" ); final int sessId = rs.getInt( "id" ); res.addCookie( new HttpResponseCookie(SESS_ID_COOKIE,Integer.toString(sessId)) ); res.addCookie( new HttpResponseCookie(SESS_CODE_COOKIE,sessCode) ); } finally { Utils.close( rs ); Utils.close( st ); } } /** * Destroys the current session * */ public void destroy() { res.addCookie( new HttpResponseCookie(SESS_ID_COOKIE,"",new Date(),"/") ); res.addCookie( new HttpResponseCookie(SESS_CODE_COOKIE,"",new Date(),"/") ); } /** * tries to use cookies to restore a user session * * @return User if logged in, null otherwise * */ protected User getCurrentUser() throws SQLException { User user = null; ResultSet rs = null; PreparedStatement st = null; try { final int sessId = fetchSessionId( req ); final String sessCode = fetchSessionCode( req ); final String sql = " select u.id, u.name, u.email, u.is_admin " + " from users u " + " inner join sessions s " + " on s.user_id = u.id " + " where s.id = ? " + " and s.code = ? "; st = db.prepare( sql ); st.setInt( 1, sessId ); st.setString( 2, sessCode ); rs = st.executeQuery(); if ( rs.next() ) { log.debug( "Fetched user!" ); user = new User( rs.getInt("id"), rs.getString("name"), "", rs.getString("email"), sessId, sessCode, rs.getBoolean("is_admin") ); } } catch ( final NumberFormatException e ) { // probably just no session log.error( e ); } finally { Utils.close( rs ); Utils.close( st ); } return user; } /** * returns the session id for the session, preferably from a cookie, but will * get it from the request if it's not present here. if nothing is found (or * invalid data is found) it'll return -1. * * @param Request req * * @return * */ protected int fetchSessionId( final Request req ) { try { final String[] sessIds = new String[] { req.getCookie( SESS_ID_COOKIE ), req.getArgument( SESS_ID_COOKIE ) }; for ( final String sessId : sessIds ) { if ( sessId.matches("^\\d+$") ) return Integer.parseInt( sessId ); } } catch ( final NumberFormatException e ) { /* ignore, we'll return the default */ } return -1; } /** * fetches the session code first from a cookie, but will also try from the request. * return the empty string if nothing is found. * * @param Request req * * @return * */ protected String fetchSessionCode( final Request req ) { final String[] sessCodes = new String[] { req.getCookie( SESS_CODE_COOKIE ), req.getArgument( SESS_CODE_COOKIE ) }; for ( final String sessCode : sessCodes ) { if ( !sessCode.equals("") ) { return sessCode; } } return ""; } }