diff options
| -rw-r--r-- | core/classes/Database.php | 2 | ||||
| -rw-r--r-- | core/classes/Request.php | 53 | ||||
| -rw-r--r-- | core/classes/User.php | 111 | ||||
| -rw-r--r-- | core/classes/authentication/User.php | 22 | ||||
| -rw-r--r-- | html/app/config/app_constants.php (renamed from html/app/config/assets.php) | 34 | ||||
| -rw-r--r-- | html/app/controllers/Auth.php | 196 | ||||
| -rw-r--r-- | html/app/models/admin/History_model.php | 28 | ||||
| -rw-r--r-- | html/app/models/admin/User_model.php | 227 | ||||
| -rw-r--r-- | html/app/models/user/Validate_model.php | 27 | ||||
| -rw-r--r-- | html/index.php | 2 |
10 files changed, 562 insertions, 140 deletions
diff --git a/core/classes/Database.php b/core/classes/Database.php index 35ff65f..629753c 100644 --- a/core/classes/Database.php +++ b/core/classes/Database.php @@ -82,9 +82,11 @@ class Database { * --- * set and execute a query safely; * save results as associative array; DO NOT RETURN RESULTS + * * @param $sql (string): SQL query * @param $args (array): array of values to bind into SQL * @param $pypass (boolean): flag to bypass security check + * * @return $this (database handler) */ public function query($sql, $args=[]) diff --git a/core/classes/Request.php b/core/classes/Request.php index 20b82c7..6b82dc5 100644 --- a/core/classes/Request.php +++ b/core/classes/Request.php @@ -89,6 +89,59 @@ class Request // if SCRF-token is not valideted, serve 403 return $array; } + + + + + public function isAjax(): bool + { + // check headers 'XMLHttpRequest' == $this->headers->get('X-Requested-With'); + } + + + public function isSecure(): bool + { + // chech if HTTPS + } + + + public function hasSession(): bool + { + // chech if Session exist + } + + + /** + * Get the user making the request. + * + * @param string|null $guard + * @return mixed + */ + public function user($guard = null) + { + // return call_user_func($this->getUserResolver(), $guard); + } + + public function getUserResolver() + { + // return $this->userResolver ?: function () { + // + // }; + } + + /** + * Set the user resolver callback. + * + * @param \Closure $callback + * @return $this + */ + public function setUserResolver(Closure $callback) + { + // $this->userResolver = $callback; + // return $this; + } + + } diff --git a/core/classes/User.php b/core/classes/User.php deleted file mode 100644 index 65b5018..0000000 --- a/core/classes/User.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php - -class User_depricated -{ - - /** PROPERTIES - * ------------------------------------------------------------------------- - */ - - private $isLogged = false; - - private $who = Array( - 'title' => '', - 'name' => '', - 'middle'=> '', - 'surname' =>'', - 'email' => '' - ); - - private $addresses = Array(); - - - - /** METHODS - * ------------------------------------------------------------------------- - */ - - - public function create() - { - - } - - - public function setDefaultAddress($id) - { - - } - - - public function addAddress() - { - // update session data - // update user record - } - - - public function changePassword() - { - - } - - - public function confirmEmail() - { - - } - - - public function sendEmail() - { - - } - - /** sendOTP() - * sent One-Time-Password - * - */ - public function sendOTP($ttl) - { - $to = $this->who; - $otp = rand(10000,99999); - $expire = time() + $ttl; - - $mail = new PHPMailer(true); - try { - //Server settings - // ... - - //Recipients - $mail->setFrom('from@example.com', 'Mailer'); - $mail->addAddress($to['email'], $to['surname'] .' '. $to['name']); //Add a recipient - $mail->addReplyTo('info@example.com', 'Information'); - - //Attachments - $mail->addAttachment('/var/tmp/file.tar.gz'); //Add attachments - $mail->addAttachment('/tmp/image.jpg', 'new.jpg'); //Optional name - - //Content - $mail->isHTML(true); //Set email format to HTML - $mail->Subject = 'Your OTP'; - $mail->Body = 'This is the HTML message body <b>in bold!</b>'; - $mail->AltBody = 'This is the body in plain text for non-HTML mail clients'; - - $mail->send(); - echo 'Message has been sent'; - } catch (Exception $e) { - echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}"; - } - - } - - /** updateSession() - * regenerates session - */ - public function updateSession() - { - - } - -} diff --git a/core/classes/authentication/User.php b/core/classes/authentication/User.php index 4aef375..cc9d5e3 100644 --- a/core/classes/authentication/User.php +++ b/core/classes/authentication/User.php @@ -20,6 +20,9 @@ class User implements UserInterface // @var array private $roles = []; + // @var array + private $privileges = []; + // @var bool private $enabled = true; @@ -52,6 +55,14 @@ class User implements UserInterface return $this->roles; } + /** getPrivileges + * @return array + */ + public function getPrivileges(): array + { + return $this->privileges; + } + /** isEnabled * @return bool */ @@ -98,6 +109,17 @@ class User implements UserInterface return $this; } + /** setPrivileges() + * + * @param array $roles + * @return User + */ + public function setPrivileges(array $privileges): self + { + $this->privileges = $privileges; + return $this; + } + /** setEnabled * * @param bool $enabled diff --git a/html/app/config/assets.php b/html/app/config/app_constants.php index 9203c47..3dac5ec 100644 --- a/html/app/config/assets.php +++ b/html/app/config/app_constants.php @@ -1,6 +1,38 @@ <?php -// PATHS USED HEAVILY ////////////////////////////////////////////////////////// +// DEFAULT VALUES ////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- + +// default privileges (for the subscribed user) +// (array of privilege aliases) +// --- +define('DEFAULT_PRIVILEGES', [ + 'e.1', // economics, level 1 + 'p.1' // programming. level 1 +]); + + + + +// ACCESS HISTORY ////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// (user-)access types + +define('TRACK_LOGIN', 1); // login / logout +define('TRACK_ACCOUNT', 2); // create user / activate account +define('TRACK_PAYMENTS', 3); // order / payment / refund etc... + +// access type strings +// --- +define('USER_ACCESS_TYPE', [ + 1 => 'Login', + 2 => 'Account', + 3 => 'Payment' +]); + + + +// ASSETS: PATHS USED HEAVILY ////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // these paths are used in order to easily find and autoload useful elemets diff --git a/html/app/controllers/Auth.php b/html/app/controllers/Auth.php new file mode 100644 index 0000000..c75f979 --- /dev/null +++ b/html/app/controllers/Auth.php @@ -0,0 +1,196 @@ +<?php + +namespace app\controllers; + +use Registry; +use UserManager; +use User; +use app\models\user\User_model; + + +/** class Auth + * + * handles user's Authentication and Authorizarion + * + */ +class Auth { + + /** login + * + * checks visitor's credentials; + * if valid, authenticates user + * + */ + public static function login() + { + $req = Registry::get('REQUEST'); + + // get the record of the target user + $record = User_model::checkUser('email', $req->POST['email']); + + // if no user exists, return false + if ($record === false) return false; + + // create a user object + $user = (new User()) + ->setUserName($record['email']) + ->setPassword($record['password']) + ->setRoles(json_decode($record['roles'])) + ->setEnabled($record['active']); + + // let user manager to validate user credentials + $userManager = new UserManager(); + + if ($userManager->isPasswordValid($user, $req->POST['password'])) { + + // login OK, set Token in session + $userManager->createUserToken($user); + + } else { + return false; + } + } + + + /** register + * + * registers new user + * + */ + public static function register() + { + $userManager = new UserManager(); + $req = Registry::get('REQUEST'); + + // create a salted password hash + $password = $userManager->cryptPassword($req->POST['password']); + + $user = (new User()) + ->setUserName($req->POST['username']) + ->setPassword($password) + ->setRoles(['ROLE_USER']); + + // TODO: + // store user to database + + $userManager->createUserToken($user); + } + + + + public static function logout() + { + $userManager = new UserManager(); + $userManager->logout(); + } + + + + /** isGranted( ROLE ) + * + * checks if the user is granted (some of) the specified role(s) + * to access the source + * + * NOTE: + * if no roles are specified then user is granted + * (because every user is granted the 'no-role') + * + * @param $roles (array): array of roles to check (if any is granted) + * + */ + public static function isGranted($roles = []) + { + // no role required ? user is granted access + if ($roles == []) return true; + + // else, UserManager knows if user isGranted + $userManager = new UserManager(); + if ($userManager->isGranted($roles)) { + return true; + + } else { + return false; + } + } + + + /** hasPermition( PERMIT ) + * + * checks if the user owns the specified permition + * to access the source + * + */ + public static function hasPermition($permit = []) + { + if ($permit == []) return true; + } + + + /** isAuthenticated() + * + * chechs if the user's roles and permitions + * satisfy the specified requirements + * to access the source + * + * @param $requirements (array of rules-array) + * + * example: + * [ + * [ + * role => ['editor','designer'] + * permition => ['10', '12', '18'] + * ], + * [ + * role => ['admin' , 'developερ'] + * ], + * [ + * permition => [ 3 ] + * ] + * ] + * + * defines (and parses to) a requirements rule of: + * [ + * user should be editor or designer + * and have permition 10 or 12 or 18 + * ] + * OR + * [ + * user should be an administratoe or developer + * ] + * OR + * [ + * user should have permition #3 + * ] + * + * + */ + public static function isAuthorized($requirements) + { + $authorized = false; + foreach($requirements as $required) { + if ( (self::isGranted($required['role'] ?? [])) + && (self::hasPermition($required['permition'] ?? [])) ) { + $authorized = true; + } + } + return $authorized; + } + + + + + public static function forgot_pass() + { + } + + + + public static function validate_otp() + { + } + + + +} + + diff --git a/html/app/models/admin/History_model.php b/html/app/models/admin/History_model.php new file mode 100644 index 0000000..63086e3 --- /dev/null +++ b/html/app/models/admin/History_model.php @@ -0,0 +1,28 @@ +<?php + +namespace app\models\admin; + +use \Registry; +use app\models\admin\history; + +class User_model +{ + + /** track user access + * + */ + public static function trackUserAccess($user_id, $type, $message, $note='') + { + $access = [ + 'user_id' => $user_id, + 'type' => $type, + 'message' => $message, + 'note' => $note, + 'ip' => Registry::get('REQUEST')->IP + ]; + + } + + + +}
\ No newline at end of file diff --git a/html/app/models/admin/User_model.php b/html/app/models/admin/User_model.php new file mode 100644 index 0000000..63d826f --- /dev/null +++ b/html/app/models/admin/User_model.php @@ -0,0 +1,227 @@ +<?php + +namespace app\models\admin; + +use \Registry; +use app\models\admin\history; + +class User_model +{ + + /** check user (by index key) + * + * @param $indexKey (string) : key for user identification + * @param $value (string) + * + * NOTE: $indexKey MUST BE a unique key + * + * @return $user : [array] or false + */ + public static function checkUser($indexKey, $value) + { + $user = Registry::use('database')->query( + "SELECT * FROM user WHERE {$indexKey} = :val", + [ ':val' => $value ] + )->getFirst(); + + // if no user, return false + if ($user === false) return false; + + return $user; + } + + + /** get user (by index key) + * + * user detailed array + * includes all user properties + granted roles + privileges + * + * @param $id (int) : user id + * @param $value (string) + */ + public static function getUser($id) + { + $user = Registry::use('database')->query( + "SELECT user.*, + ( -- construct array (json) of roles granted to user + SELECT CONCAT( + '[', + GROUP_CONCAT(role.id), + ']' + ) + FROM `role` + WHERE role.id IN ( + SELECT user_role.role_id + FROM user_role + WHERE user_role.user_id = :id + ) + ) AS Roles_json, + ( -- construct array of (root-)privileges granted to user + SELECT CONCAT( + '[', + GROUP_CONCAT(privilege.id), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_privilege.user_id = :id + ) + ) AS RootPrivileges_json, + ( + SELECT CONCAT( -- array of array of sub-privileges + '[', + GROUP_CONCAT( + ( + SELECT CONCAT( -- array (json) of subprivileges + '[', + GROUP_CONCAT(included_id), + ']' + ) + FROM privilege_includes + WHERE privilege_id = privilege.id + ) + ), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_id = :id + ) + ) AS SubPrivileges_json + FROM user + WHERE id = :id", + [ ':id' => $id ] + )->getFirst(); + + + // if no user, return false + if ($user === false) return false; + + + // TODO: + // * merge root+sub privilede lists + // * convert json strings to php arrays + + + // TODO: + // cache user super array + + return $user; + } + + + /** create user + * + */ + public static function createUser($data, $privileges = ['ec.1', 'pr.1']) + { + $user = [ + 'prefix' => $data['prefix'], + 'name' => $data['name'], + 'surname' => $data['surname'], + 'email' => $data['email'], + 'password' => $data['password'], + 'active' => 0 // needs email confirmation + ]; + + $sql = "INSERT INTO user (`prefix`, `name`, `surname`, email, `password`, user_id) + VALUES (:prrfic, :name, :surname, :email, :password, :userid)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute($user); + + $inserted_id = $this->pdo->lastInsertId(); + + // set default privileges + self::set_user_privileges($privileges); + + // update history + + + + return [ "success" => true, 'id' => $inserted_id ]; + } + + + + + /** inherited privileges + * + * list of all inhereted (sub-)privileges + * from a list of root-privileges + * + * @param $list (array of int): list of root privilege id(s) + */ + public static function inheritedPrivileges($list) + { + $rootList = "(". implode(', ', $list) .")"; + + $subPrivileges = Registry::use('database')->runQuery( + "SELECT privilege.id, ( + SELECT CONCAT('[', GROUP_CONCAT(included_id), ']') FROM privilege_includes + WHERE privilege_id = privilege.id + ) as subprivilege_json + FROM privilege + WHERE privilege.id IN {$rootlist}", [] + ); + } + + + +} + +/* example query getUser (super-array) +--- -- -- - - - + +SELECT user.*, +( -- array (json) of roles granted to user + SELECT CONCAT('[', GROUP_CONCAT(role.id), ']') + FROM `role` + WHERE role.id IN ( + SELECT user_role.role_id + FROM user_role + WHERE user_role.user_id = 1 + ) +) AS Roles_json, +( + SELECT CONCAT( + '[', + GROUP_CONCAT(privilege.id), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_privilege.user_id = 1 + ) +) AS RootPrivileges_json, +( + SELECT CONCAT( -- array of array of sub-privileges + '[', + GROUP_CONCAT( -- array (json) of subprivileges + ( + SELECT CONCAT( + '[', + GROUP_CONCAT(included_id), + ']' + ) + FROM privilege_includes + WHERE privilege_id = privilege.id + ) + ), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_id = 1 + ) +) AS SubPrivileges_json +FROM user +WHERE id = 1 +--- */
\ No newline at end of file diff --git a/html/app/models/user/Validate_model.php b/html/app/models/user/Validate_model.php deleted file mode 100644 index 16ad70a..0000000 --- a/html/app/models/user/Validate_model.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -namespace app\models\user; - -use \Registry; - - -class Validate -{ - /** ticket - * - * validate that the user owns the `ticket` - * - */ - public static function ticket($ticket) - { - } - - /** access - * - * validate that the `ticket` is compatible with access_level - */ - public static function access($ticket, $access_level) - { - } - -}
\ No newline at end of file diff --git a/html/index.php b/html/index.php index 05d4822..d26d0a3 100644 --- a/html/index.php +++ b/html/index.php @@ -25,7 +25,7 @@ require_once '../core/config/constants.php'; // general constants require_once '../core/config/anom_settings.php'; // core framework constants -require_once 'app/config/assets.php'; // application constants +require_once 'app/config/app_constants.php'; // application constants // Enable Autoloader |
