From d77bac0ab3033e7f700c873889923f7eee876250 Mon Sep 17 00:00:00 2001 From: REJack Date: Sat, 26 Jan 2019 12:23:35 +0100 Subject: [PATCH] first steps to Single Login Mode - updated Config/Aauth (2 new config vars) - renamed & updated create_user_sessions_table migration - updated Libraries/Aauth (added 2 new methods) - added UserSessionModel --- app/Config/Aauth.php | 12 + ...1026042034_create_user_sessions_table.php} | 9 +- app/Libraries/Aauth.php | 48 ++++ app/Models/Aauth/UserSessionModel.php | 258 ++++++++++++++++++ 4 files changed, 324 insertions(+), 3 deletions(-) rename app/Database/Migrations/{20181026042034_create_ci_sessions_table.php => 20181026042034_create_user_sessions_table.php} (85%) create mode 100644 app/Models/Aauth/UserSessionModel.php diff --git a/app/Config/Aauth.php b/app/Config/Aauth.php index 6e8aff1..1c745f5 100644 --- a/app/Config/Aauth.php +++ b/app/Config/Aauth.php @@ -64,6 +64,11 @@ class Aauth extends BaseConfig | User Variables |-------------------------------------------------------------------------- | + | 'userActiveTime' + | + | User Active Time, time range for session time checkup + | (default: '5 minutes') + | | 'userVerification' | | User Verification, if TRUE sends a verification email on account creation @@ -74,6 +79,7 @@ class Aauth extends BaseConfig | Regex pattern for valid chars for username | (default: '^[a-zA-Z0-9]{3,}$') */ + public $userActiveTime = '5 minutes'; public $userVerification = false; public $userRegexPattern = '^[a-zA-Z0-9]{3,}$'; @@ -306,6 +312,11 @@ class Aauth extends BaseConfig | The table which contains users | (default: 'aauth_users') | + | 'dbTableUserSessions' + | + | The table which contains user sessions + | (default: 'aauth_user_sessions') + | | 'dbTableUserVariables' | | The table which contains users variables @@ -377,6 +388,7 @@ class Aauth extends BaseConfig public $dbProfile = 'default'; public $dbReturnType = 'array'; public $dbTableUsers = 'aauth_users'; + public $dbTableUserSessions = 'aauth_user_sessions'; public $dbTableUserVariables = 'aauth_user_variables'; public $dbTableLoginAttempts = 'aauth_login_attempts'; public $dbTableLoginTokens = 'aauth_login_tokens'; diff --git a/app/Database/Migrations/20181026042034_create_ci_sessions_table.php b/app/Database/Migrations/20181026042034_create_user_sessions_table.php similarity index 85% rename from app/Database/Migrations/20181026042034_create_ci_sessions_table.php rename to app/Database/Migrations/20181026042034_create_user_sessions_table.php index 7f8ca80..15952e8 100644 --- a/app/Database/Migrations/20181026042034_create_ci_sessions_table.php +++ b/app/Database/Migrations/20181026042034_create_user_sessions_table.php @@ -18,6 +18,7 @@ namespace App\Database\Migrations; use CodeIgniter\Database\Migration; +use Config\Aauth as AauthConfig; /** * Create CI session table @@ -26,7 +27,7 @@ use CodeIgniter\Database\Migration; * * @codeCoverageIgnore */ -class Migration_create_ci_sessions_table extends Migration +class Migration_create_user_sessions_table extends Migration { /** * Create Table @@ -35,6 +36,8 @@ class Migration_create_ci_sessions_table extends Migration */ public function up() { + $config = new AauthConfig(); + $this->forge->addField([ 'id' => [ 'type' => 'VARCHAR', @@ -61,7 +64,7 @@ class Migration_create_ci_sessions_table extends Migration ]); $this->forge->addKey('id', true); $this->forge->addKey('timestamp'); - $this->forge->createTable('ci_sessions', true); + $this->forge->createTable($config->dbTableUserSessions, true); } //-------------------------------------------------------------------- @@ -73,6 +76,6 @@ class Migration_create_ci_sessions_table extends Migration */ public function down() { - $this->forge->dropTable('ci_sessions', true); + $this->forge->dropTable($config->dbTableUserSessions, true); } } diff --git a/app/Libraries/Aauth.php b/app/Libraries/Aauth.php index 9a777af..a040876 100644 --- a/app/Libraries/Aauth.php +++ b/app/Libraries/Aauth.php @@ -19,6 +19,7 @@ namespace App\Libraries; use \App\Models\Aauth\UserModel; use \App\Models\Aauth\UserVariableModel; +use \App\Models\Aauth\UserSessionModel; use \App\Models\Aauth\LoginAttemptModel; use \App\Models\Aauth\LoginTokenModel; use \App\Models\Aauth\GroupModel; @@ -977,6 +978,53 @@ class Aauth return $user['id']; } + public function getActiveUsersCount() + { + $userSessionModel = new UserSessionModel(); + + return count($userSessionModel->findAll()); + } + + public function listActiveUsers() + { + $userSessionModel = new UserSessionModel(); + + $usersIds = []; + + foreach ($userSessionModel->findAll() as $userSession) + { + $result = $matches = []; + $data = ';' . $userSession['data']; + $keyreg = '/;([^|{}"]+)\|/'; + + preg_match_all($keyreg, $data, $matches); + + if (isset($matches[1])) + { + $keys = $matches[1]; + $values = preg_split($keyreg, $data); + + if (count($values) > 1) + { + array_shift($values); + } + + $result = array_combine($keys, $values); + } + + $user = unserialize($result['user']); + $usersIds[] = $user['id']; + } + + $userModel = new UserModel(); + + $userModel->select('id, email, username, banned, created_at, updated_at, last_activity, last_ip_address, last_login'); + + $userModel->whereIn('id', $usersIds); + + return $userModel->findAll(); + } + /** * Is banned * diff --git a/app/Models/Aauth/UserSessionModel.php b/app/Models/Aauth/UserSessionModel.php new file mode 100644 index 0000000..6ef4ab7 --- /dev/null +++ b/app/Models/Aauth/UserSessionModel.php @@ -0,0 +1,258 @@ +config = new AauthConfig(); + $this->DBGroup = $this->config->dbProfile; + $this->table = $this->config->dbTableUserSessions; + $this->tempReturnType = $this->returnType; + + if ($db instanceof ConnectionInterface) + { + $this->db = & $db; + } + else + { + $this->db = Database::connect($this->DBGroup); + } + } + + /** + * Find all active user sessions + * + * @param integer $userId User id + * @param boolean $system Whether system variable + * + * @return object + */ + public function findAll() + { + $builder = $this->builder(); + $builder->where('timestamp >', strtotime('-' . $this->config->userActiveTime)); + $builder->where("data NOT LIKE CONCAT('%', timestamp, '%')"); + $builder->like('data', 'user|'); + + $this->tempReturnType = $this->returnType; + + return $builder->get()->getResult($this->tempReturnType); + } + + /** + * Delete User Variable + * + * @param integer $userId User id + * @param string $dataKey Key of variable + * @param boolean $system Whether system variable + * + * @return boolean + */ + public function delete(int $userId, string $dataKey, bool $system = null) + { + $builder = $this->builder(); + $builder->where('user_id', $userId); + $builder->where('data_key', $dataKey); + $builder->where('system', ($system ? 1 : 0)); + $builder->delete(); + + return true; + } + + //-------------------------------------------------------------------- + // Utility + //-------------------------------------------------------------------- + + /** + * Sets the return type of the results to be as an associative array. + * + * @return Model + */ + public function asArray() + { + $this->tempReturnType = $this->returnType = 'array'; + + return $this; + } + + /** + * Sets the return type to be of the specified type of object. + * Defaults to a simple object, but can be any class that has + * class vars with the same name as the table columns, or at least + * allows them to be created. + * + * @param string $class Class + * + * @return Model + */ + public function asObject(string $class = 'object') + { + $this->tempReturnType = $this->returnType = $class; + + return $this; + } + + /** + * Returns the first row of the result set. Will take any previous + * Query Builder calls into account when determing the result set. + * + * @return array|object|null + */ + public function first() + { + $builder = $this->builder(); + + $row = $builder->limit(1, 0)->get(); + $row = $row->getFirstRow($this->tempReturnType); + + $this->tempReturnType = $this->returnType; + + return $row; + } + + /** + * Provides a shared instance of the Query Builder. + * + * @param string $table Table name + * + * @return BaseBuilder + */ + protected function builder(string $table = null) + { + if ($this->builder instanceof BaseBuilder) + { + return $this->builder; + } + + $table = empty($table) ? $this->table : $table; + + $this->builder = $this->db->table($table); + + return $this->builder; + } + + /** + * Provides direct access to method in the builder (if available) + * and the database connection. + * + * @param string $name Name + * @param array $params Params + * + * @return Model|null + */ + public function __call(string $name, array $params) + { + $result = null; + + if (method_exists($this->db, $name)) + { + $result = $this->db->$name(...$params); + } + elseif (method_exists($builder = $this->builder(), $name)) + { + $result = $builder->$name(...$params); + } + + // Don't return the builder object unless specifically requested + //, since that will interrupt the usability flow + // and break intermingling of model and builder methods. + if ($name !== 'builder' && empty($result)) + { + return $result; + } + if ($name !== 'builder' && ! $result instanceof BaseBuilder) + { + return $result; + } + + return $this; + } +}