275 lines
9.5 KiB
PHP
275 lines
9.5 KiB
PHP
<?php
|
|
/**
|
|
* app/models/sessions.php
|
|
*
|
|
* This model is used for the modification and management of the session data.
|
|
*
|
|
* Notes: After refactor, the sessions will use ID's for short term, and Cookies
|
|
* will use the token for long term storage
|
|
*
|
|
* @version 5.0.1
|
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
|
* @link https://TheTempusProject.com
|
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
|
*/
|
|
namespace TheTempusProject\Models;
|
|
|
|
use TheTempusProject\Bedrock\Functions\Check;
|
|
use TheTempusProject\Bedrock\Functions\Code;
|
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
|
use TheTempusProject\Bedrock\Functions\Session;
|
|
use TheTempusProject\Bedrock\Functions\Cookie;
|
|
use TheTempusProject\Classes\DatabaseModel;
|
|
use TheTempusProject\Classes\Config;
|
|
use TheTempusProject\TheTempusProject as App;
|
|
|
|
class Sessions extends DatabaseModel {
|
|
public $tableName = 'sessions';
|
|
public $modelVersion = '1.0';
|
|
public $databaseMatrix = [
|
|
[ 'userID', 'int', '5' ],
|
|
[ 'userGroup', 'int', '5' ],
|
|
[ 'expire', 'int', '10' ],
|
|
[ 'ip', 'varchar', '15' ],
|
|
[ 'hash', 'varchar', '80' ],
|
|
[ 'lastPage', 'varchar', '64' ],
|
|
[ 'username', 'varchar', '20' ],
|
|
[ 'token', 'varchar', '120' ],
|
|
];
|
|
public $searchFields = [
|
|
'username',
|
|
];
|
|
public static $activeSession = false;
|
|
|
|
/**
|
|
* The model constructor.
|
|
*/
|
|
public function __construct() {
|
|
parent::__construct();
|
|
self::$session = $this;
|
|
}
|
|
|
|
/**
|
|
* Check if a session exists, verifies the username,
|
|
* password, and IP address to prevent forgeries.
|
|
*
|
|
* @param {int} [$id] - The id of the session being checked.
|
|
* @return {bool}
|
|
*/
|
|
public function checkSession( $sessionID ) {
|
|
$user = new User;
|
|
// @todo lets put this on some sort of realistic checking regime other than check everything every time
|
|
if ( empty( $sessionID ) ) {
|
|
Debug::log( 'sessionID false' );
|
|
return false;
|
|
}
|
|
if ( !Check::id( $sessionID ) ) {
|
|
Debug::log( 'sessionID not id' );
|
|
return false;
|
|
}
|
|
$data = self::$db->get( $this->tableName, [ 'ID', '=', $sessionID ] );
|
|
if ( $data->count() == 0 ) {
|
|
Debug::info( 'Session token not found.' );
|
|
return false;
|
|
}
|
|
$session = $data->first();
|
|
$user = $user->findById( $session->userID );
|
|
if ( $user === false ) {
|
|
Debug::info( 'User not found in DB.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
if ( $user->username != $session->username ) {
|
|
Debug::info( 'Usernames do not match.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
if ( $user->password != $session->hash ) {
|
|
Debug::info( 'Session Password does not match.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
if ( time() > $session->expire ) {
|
|
Debug::info( 'Session Expired.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
if ( $user->userGroup !== $session->userGroup ) {
|
|
Debug::info( 'Groups do not match.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
if ( $_SERVER['REMOTE_ADDR'] != $session->ip ) {
|
|
Debug::info( 'IP addresses do not match.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
self::$activeSession = $session;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks the "remember me" cookie we use to identify
|
|
* unique sessions across multiple visits. Checks that
|
|
* the tokens match, checks the username as well as the
|
|
* password from the database to ensure it hasn't been
|
|
* modified elsewhere between visits.
|
|
*
|
|
* @param {string} [$token] - The unique token saved as a cookie that is being checked.
|
|
* @return {bool}
|
|
*/
|
|
public function checkCookie( $cookieToken, $create = false ) {
|
|
$user = new User;
|
|
if ( $cookieToken === false ) {
|
|
Debug::info( 'cookieToken false' );
|
|
return false;
|
|
}
|
|
$data = self::$db->get( $this->tableName, [ 'token', '=', $cookieToken ] );
|
|
if ( !$data->count() ) {
|
|
Debug::info( 'sessions->checkCookie - Session token not found.' );
|
|
return false;
|
|
}
|
|
$session = $data->first();
|
|
$user = self::$user->findById( $session->userID );
|
|
if ( $user === false ) {
|
|
Debug::info( 'sessions->checkCookie - could not find user by ID.' );
|
|
return false;
|
|
}
|
|
if ( $user->username != $session->username ) {
|
|
Debug::info( 'sessions->checkCookie - Usernames do not match.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
if ( $user->password != $session->hash ) {
|
|
Debug::info( 'sessions->checkCookie - Session Password does not match.' );
|
|
$this->destroy( $session->ID );
|
|
return false;
|
|
}
|
|
if ( $create ) {
|
|
return $this->newSession( null, false, false, $session->userID );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Creates a new session from the data provided. The
|
|
* expiration time is optional and will be set to the
|
|
* system default if not provided.
|
|
*
|
|
* @param {int} [$ID] - The User ID of the new session holder.
|
|
* @param {int} [$expire] - The expiration time (in seconds).
|
|
* @return {bool}
|
|
*/
|
|
public function newSession( $expire = null, $override = false, $remember = false, $userID = null ) {
|
|
if ( empty( $expire ) ) {
|
|
// default Session Expiration is 24 hours
|
|
$expireLimit = Config::getValue( 'main/loginTimer' );
|
|
$expire = ( time() + $expireLimit );
|
|
Debug::log( 'Using default expiration time' );
|
|
}
|
|
$lastPage = App::getUrl();
|
|
if ( self::$activeSession != false ) {
|
|
// there is already an active session
|
|
if ( $override === false ) {
|
|
Debug::error( 'No need for a new session.' );
|
|
return false;
|
|
}
|
|
// We can override the active session
|
|
$data = self::$db->get( $this->tableName, [ 'userID', '=', self::$activeSession->ID ] );
|
|
if ( $data->count() ) {
|
|
Debug::log( 'Deleting old session from db' );
|
|
$session = self::$db->first();
|
|
$this->destroy( $session->ID );
|
|
}
|
|
}
|
|
if ( empty( $userID ) ) {
|
|
if ( App::$activeUser === null ) {
|
|
Debug::info( 'Must provide user details to create a new session.' );
|
|
return false;
|
|
}
|
|
$userID = App::$activeUser->ID;
|
|
}
|
|
$userObject = self::$user->findById( $userID );
|
|
if ( $userObject === false ) {
|
|
Debug::info( 'User not found.' );
|
|
return false;
|
|
}
|
|
$token = Code::genToken();
|
|
$result = self::$db->insert(
|
|
$this->tableName,
|
|
[
|
|
'username' => $userObject->username,
|
|
'hash' => $userObject->password,
|
|
'userGroup' => $userObject->userGroup,
|
|
'userID' => $userObject->ID,
|
|
'lastPage' => $lastPage,
|
|
'expire' => $expire,
|
|
'ip' => $_SERVER['REMOTE_ADDR'],
|
|
'token' => $token,
|
|
]
|
|
);
|
|
$sessionID = self::$db->lastId();
|
|
|
|
|
|
$sessionData = self::$db->get( $this->tableName, [ 'ID', '=', $sessionID ] )->first();
|
|
|
|
|
|
Session::put( 'SessionID', $sessionID );
|
|
if ( $remember ) {
|
|
Cookie::put( 'RememberToken', $token, ( time() + ( 3600 * 24 * 30 ) ) );
|
|
}
|
|
self::$activeSession = $sessionData;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Function to update the users' current active page.
|
|
* NOTE: Current session assumed if no $id is provided.
|
|
*
|
|
* @param {string} [$page] - The name of the page you are updating to.
|
|
* @param {int|null} [$id] - The ID of the session you are updating.
|
|
* @return {bool}
|
|
*/
|
|
public function updatePage( $page, $id = null ) {
|
|
if ( empty( $id ) ) {
|
|
if ( self::$activeSession === false ) {
|
|
Debug::info( 'Session::updatePage - Must provide session ID or have active session' );
|
|
return false;
|
|
}
|
|
$id = self::$activeSession->ID;
|
|
}
|
|
if ( !Check::id( $id ) ) {
|
|
Debug::info( 'Session::updatePage - Invalid ID' );
|
|
return false;
|
|
}
|
|
if ( !self::$db->update( $this->tableName, $id, [ 'lastPage' => $page ] ) ) {
|
|
Debug::info( 'Session::updatePage - Failed to update database' );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Destroy a session.
|
|
*
|
|
* @param {int} [$id] - The ID of the session you wish to destroy.
|
|
* @return {bool}
|
|
*/
|
|
public function destroy( $id ) {
|
|
Session::delete( 'SessionID' );
|
|
Cookie::delete( 'RememberToken' );
|
|
if ( !Check::id( $id ) ) {
|
|
Debug::info( 'Session::destroy - Invalid ID' );
|
|
return false;
|
|
}
|
|
$data = self::$db->get( $this->tableName, [ 'ID', '=', $id ] );
|
|
if ( !$data->count() ) {
|
|
Debug::info( 'Session::destroy - Session not found in DB' );
|
|
return false;
|
|
}
|
|
self::$db->delete( $this->tableName, [ 'ID', '=', $id ] );
|
|
self::$activeSession = false;
|
|
return true;
|
|
}
|
|
}
|