diff --git a/.gitignore b/.gitignore index f56cefe..e1e6c5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,19 @@ -test -Experimental -vendor -composer.lock \ No newline at end of file +# Global +.phpunit* +.composer +composer.lock +package-lock.json +vendor/ +test/ +*.tests.php +workflows + +# OS Generated +.DS_Store* +ehthumbs.db +Icon? +Thumbs.db +*.swp + +# phpstorm +.idea/* diff --git a/README.md b/README.md index 7846809..e35cfe9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@



-

Leaf Auth Module

+

Leaf Auth v2



@@ -10,7 +10,9 @@ [![Total Downloads](https://poser.pugx.org/leafs/auth/downloads)](https://packagist.org/packages/leafs/auth) [![License](https://poser.pugx.org/leafs/auth/license)](https://packagist.org/packages/leafs/auth) -Leaf's auth helper packaged as a serve-yourself module. +Leaf auth is a simple but powerful module which comes with powerful functions for handling all your authentication needs. + +v2 comes with tons of fixes, improvements and upgrades. Running on top of leaf db v2, it also has support for other database types like PostgreSQL, Sqlite and many more. ## Installation @@ -20,6 +22,84 @@ You can easily install Leaf using [Composer](https://getcomposer.org/). composer require leafs/auth ``` +Or with leaf db + +```sh +leaf install auth +``` + +## Basic Usage + +After installing leaf auth, you need to connect to your database. v2 presents additional ways to achieve this. + +### connect + +The connect method allows you to pass in your database connection parameters directly to leaf auth. + +```php +auth()->connect('127.0.0.1', 'dbname', 'username', 'password'); +``` + +### autoConnect + +This method creates a database connection using your env variables. + +```env +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=LEAF_DB_NAME +DB_USERNAME=LEAF_DB_USERNAME +DB_PASSWORD= +``` + +And call `autoConnect` in your app. + +```php +auth()->autoConnect(); +``` + +### db connection (v2 only) + +Leaf auth now allows you to directly pass a PDO connection into leaf auth. This allows you to share your connection with leaf auth and avoid multiple connections. + +```php +$auth = new Leaf\Auth; +$auth->dbConnection($pdoConnecction); +``` + +This also means that you can share you leaf db v2 connection with leaf auth like this: + +```php +$auth = new Leaf\Auth; +$auth->dbConnection($db->connection()); +``` + +### Leaf db (auth v2 + leaf 3 only) + +If you are using leaf auth in a leaf 3 app, you will have access to the `auth` global as shown in some of the above connections. Along with this, if you already have a leaf db connection, you no longer need to explicitly connect to your database. Leaf auth searches for a leaf db instance and connects to it automatically. + +**Note that this only works in a leaf 3 app and only if you already have a leaf db connection.** + +```php +connect('127.0.0.1', 'dbname', 'username', 'password'); + +// you can use auth straight away without any connect +auth()->login(...); +``` + +## 📚 Auth methods + +After connecting your db, you can use any of the methods below. + +WIP: This page will be updated + +## ⚡️ Funtional Mode + +When using leaf auth in a leaf 3 app, you will have access to the `auth`, `guard`, `hasAuth` and `sessionUser` globals. + ## 💬 Stay In Touch - [Twitter](https://twitter.com/leafphp) @@ -85,6 +165,13 @@ And to all our existing cash/code contributors, we love you all ❤️ Vano + + + +
+ Casprine +
+ diff --git a/composer.json b/composer.json index 6079f26..e389b0d 100644 --- a/composer.json +++ b/composer.json @@ -34,9 +34,9 @@ "require": { "leafs/date": "^1.0", "leafs/password": "^1.0", - "leafs/session": "^1.0", - "leafs/db": "^1.0", - "leafs/form": "^1.0", - "leafs/http": "^1.0" + "leafs/session": "^1.1", + "leafs/db": "^2.0", + "leafs/form": "^1.1", + "leafs/http": "^1.2.1" } } diff --git a/src/Auth.php b/src/Auth.php old mode 100755 new mode 100644 index fdb6fde..71e73db --- a/src/Auth.php +++ b/src/Auth.php @@ -2,222 +2,539 @@ namespace Leaf; +use Leaf\Auth\Core; +use Leaf\Helpers\Authentication; +use Leaf\Helpers\Password; + /** * Leaf Simple Auth * ------------------------- - * Authentication made easy. + * Simple, straightforward authentication. * * @author Michael Darko * @since 1.5.0 * @version 2.0.0 */ -class Auth +class Auth extends Core { /** - * Create a db connection + * Simple user login + * + * @param string table: Table to look for users + * @param array $credentials User credentials * - * @param string $host The db name - * @param string $user - * @param string $password - * @param string $dbname + * @return array|null null or all user info + tokens + session data */ - public static function connect(string $host, string $user, string $password, string $dbname): void - { - Auth\Core::connect($host, $user, $password, $dbname); - } - - /** - * Create a database connection from env variables - */ - public static function autoConnect() - { - Auth\Core::autoConnect(); - } - - /** - * Set auth config - */ - public static function config($config, $value = null) - { - return Auth\Core::config($config, $value); - } - - /** - * Simple user login - * - * @param string table: Table to look for users - * @param array $credentials User credentials - * @param array $validate Validation for parameters - * - * @return array user: all user info + tokens + session data - */ - public static function login(string $table, array $credentials, array $validate = []): array + public static function login( + string $table, + array $credentials + ) { + static::leafDbConnect(); + if (static::config('USE_SESSION')) { + static::useSession(); + } + + $passKey = static::$settings['PASSWORD_KEY']; + $password = $credentials[$passKey] ?? null; + + if (isset($credentials[$passKey])) { + unset($credentials[$passKey]); + } else { + static::$settings['AUTH_NO_PASS'] = true; + } + + $user = static::$db->select($table)->where($credentials)->fetchAssoc(); + + if (!$user) { + static::$errors['auth'] = static::$settings['LOGIN_PARAMS_ERROR']; + return null; + } + + if (static::$settings['AUTH_NO_PASS'] === false) { + $passwordIsValid = true; + + if (static::$settings['PASSWORD_VERIFY'] !== false && isset($user[$passKey])) { + if (is_callable(static::$settings['PASSWORD_VERIFY'])) { + $passwordIsValid = call_user_func(static::$settings['PASSWORD_VERIFY'], $password, $user[$passKey]); + } else if (static::$settings['PASSWORD_VERIFY'] === Password::MD5) { + $passwordIsValid = (md5($password) === $user[$passKey]); + } else { + $passwordIsValid = Password::verify($password, $user[$passKey]); + } + } + + if (!$passwordIsValid) { + static::$errors['password'] = static::$settings['LOGIN_PASSWORD_ERROR']; + return null; + } + } + + $token = Authentication::generateSimpleToken( + $user[static::$settings['ID_KEY']], + static::config('TOKEN_SECRET'), + static::config('TOKEN_LIFETIME') + ); + + if (isset($user[static::$settings['ID_KEY']])) { + $userId = $user[static::$settings['ID_KEY']]; + } + + if (static::$settings['HIDE_ID']) { + unset($user[static::$settings['ID_KEY']]); + } + + if (static::$settings['HIDE_PASSWORD'] && (isset($user[$passKey]) || !$user[$passKey])) { + unset($user[$passKey]); + } + + if (!$token) { + static::$errors = array_merge(static::$errors, Authentication::errors()); + return null; + } + + if (static::config('USE_SESSION')) { + if (isset($userId)) { + $user[static::$settings['ID_KEY']] = $userId; + } + + static::$session->set('AUTH_USER', $user); + static::$session->set('HAS_SESSION', true); + + if (static::config('SAVE_SESSION_JWT')) { + static::$session->set('AUTH_TOKEN', $token); + } + + exit(header('location: ' . static::config('GUARD_HOME'))); + } + + $response['user'] = $user; + $response['token'] = $token; + + return $response; + } + + /** + * Simple user registration + * + * @param string $table Table to store user in + * @param array $credentials Information for new user + * @param array $uniques Parameters which should be unique + * + * @return array null or all user info + tokens + session data + */ + public static function register( + string $table, + array $credentials, + array $uniques = [] + ) { + static::leafDbConnect(); + + $passKey = static::$settings['PASSWORD_KEY']; + + if (!isset($credentials[$passKey])) { + static::$settings['AUTH_NO_PASS'] = true; + } + + if (static::$settings['AUTH_NO_PASS'] === false) { + if (static::$settings['PASSWORD_ENCODE'] !== false) { + if (is_callable(static::$settings['PASSWORD_ENCODE'])) { + $credentials[$passKey] = call_user_func(static::$settings['PASSWORD_ENCODE'], $credentials[$passKey]); + } else if (static::$settings['PASSWORD_ENCODE'] === 'md5') { + $credentials[$passKey] = md5($credentials[$passKey]); + } else { + $credentials[$passKey] = Password::hash($credentials[$passKey]); + } + } + } + + if (static::$settings['USE_TIMESTAMPS']) { + $now = Date::now(); + $credentials['created_at'] = $now; + $credentials['updated_at'] = $now; + } + + if (static::$settings['USE_UUID'] !== false) { + $credentials[static::$settings['ID_KEY']] = static::$settings['USE_UUID']; + } + + try { + $query = static::$db->insert($table)->params($credentials)->unique($uniques)->execute(); + } catch (\Throwable $th) { + trigger_error($th->getMessage()); + } + + if (!$query) { + static::$errors = array_merge(static::$errors, static::$db->errors()); + return null; + } + + $user = static::$db->select($table)->where($credentials)->fetchAssoc(); + + if (!$user) { + static::$errors = array_merge(static::$errors, static::$db->errors()); + return null; + } + + $token = Authentication::generateSimpleToken( + $user[static::$settings['ID_KEY']], + static::config('TOKEN_SECRET'), + static::config('TOKEN_LIFETIME') + ); + + if (isset($user[static::$settings['ID_KEY']])) { + $userId = $user[static::$settings['ID_KEY']]; + } + + if (static::$settings['HIDE_ID']) { + unset($user[static::$settings['ID_KEY']]); + } + + if (static::$settings['HIDE_PASSWORD'] && (isset($user[$passKey]) || !$user[$passKey])) { + unset($user[$passKey]); + } + + if (!$token) { + static::$errors = array_merge(static::$errors, Authentication::errors()); + return null; + } + + if (static::config('USE_SESSION')) { + if (static::config('SESSION_ON_REGISTER')) { + if (isset($userId)) { + $user[static::$settings['ID_KEY']] = $userId; + } + + static::$session->set('AUTH_USER', $user); + static::$session->set('HAS_SESSION', true); + + if (static::config('SAVE_SESSION_JWT')) { + static::$session->set('AUTH_TOKEN', $token); + } + + exit(header('location: ' . static::config('GUARD_HOME'))); + } else { + exit(header('location: ' . static::config('GUARD_LOGIN'))); + } + } + + $response['user'] = $user; + $response['token'] = $token; + + return $response; + } + + /** + * Simple user update + * + * @param string $table Table to store user in + * @param array $credentials New information for user + * @param array $where Information to find user by + * @param array $uniques Parameters which should be unique + * + * @return array all user info + tokens + session data + */ + public static function update(string $table, array $credentials, array $uniques = []) { - return Auth\Login::user($table, $credentials, $validate); - } - - /** - * Simple user registration - * - * @param string $table Table to store user in - * @param array $credentials Information for new user - * @param array $uniques Parameters which should be unique - * @param array $validate Validation for parameters - * - * @return array user: all user info + tokens + session data - */ - public static function register(string $table, array $credentials, array $uniques = [], array $validate = []): array + static::leafDbConnect(); + if (static::config('USE_SESSION')) { + static::useSession(); + } + + $passKey = static::$settings['PASSWORD_KEY']; + $loggedInUser = static::user(); + + if (!$loggedInUser) { + static::$errors['auth'] = 'Not authenticated'; + return null; + } + + $where = isset($loggedInUser[static::$settings['ID_KEY']]) ? [static::$settings['ID_KEY'] => $loggedInUser[static::$settings['ID_KEY']]] : $loggedInUser; + + if (!isset($credentials[$passKey])) { + static::$settings['AUTH_NO_PASS'] = true; + } + + if ( + static::$settings['AUTH_NO_PASS'] === false && + static::$settings['PASSWORD_ENCODE'] !== false + ) { + if (is_callable(static::$settings['PASSWORD_ENCODE'])) { + $credentials[$passKey] = call_user_func(static::$settings['PASSWORD_ENCODE'], $credentials[$passKey]); + } else if (static::$settings['PASSWORD_ENCODE'] === 'md5') { + $credentials[$passKey] = md5($credentials[$passKey]); + } else { + $credentials[$passKey] = Password::hash($credentials[$passKey]); + } + } + + if (static::$settings['USE_TIMESTAMPS']) { + $credentials['updated_at'] = Date::now(); + } + + if (count($uniques) > 0) { + foreach ($uniques as $unique) { + if (!isset($credentials[$unique])) { + trigger_error("$unique not found in credentials."); + } + + $data = static::$db->select($table)->where($unique, $credentials[$unique])->fetchAssoc(); + + $wKeys = array_keys($where); + $wValues = array_values($where); + + if (isset($data[$wKeys[0]]) && $data[$wKeys[0]] != $wValues[0]) { + static::$errors[$unique] = "$unique already exists"; + } + } + + if (count(static::$errors) > 0) return null; + } + + try { + $query = static::$db->update($table)->params($credentials)->where($where)->execute(); + } catch (\Throwable $th) { + trigger_error($th->getMessage()); + } + + if (!$query) { + static::$errors = array_merge(static::$errors, static::$db->errors()); + return null; + } + + if (isset($credentials['updated_at'])) { + unset($credentials['updated_at']); + } + + $user = static::$db->select($table)->where($credentials)->fetchAssoc(); + if (!$user) { + static::$errors = array_merge(static::$errors, static::$db->errors()); + return null; + } + + $token = Authentication::generateSimpleToken( + $user[static::$settings['ID_KEY']], + static::config('TOKEN_SECRET'), + static::config('TOKEN_LIFETIME') + ); + + if (isset($user[static::$settings['ID_KEY']])) { + $userId = $user[static::$settings['ID_KEY']]; + } + + if (static::$settings['HIDE_ID'] && isset($user[static::$settings['ID_KEY']])) { + unset($user[static::$settings['ID_KEY']]); + } + + if (static::$settings['HIDE_PASSWORD'] && (isset($user[$passKey]) || !$user[$passKey])) { + unset($user[$passKey]); + } + + if (!$token) { + static::$errors = array_merge(static::$errors, Authentication::errors()); + return null; + } + + if (static::config('USE_SESSION')) { + if (isset($userId)) { + $user[static::$settings['ID_KEY']] = $userId; + } + + static::$session->set('AUTH_USER', $user); + static::$session->set('HAS_SESSION', true); + + if (static::config('SAVE_SESSION_JWT')) { + static::$session->set('AUTH_TOKEN', $token); + } + + return $user; + } + + $response['user'] = $user; + $response['token'] = $token; + + return $response; + } + + /** + * Validation for parameters + * + * @param array $rules Rules for parameter validation + */ + public function validate(array $rules): bool + { + $validation = Form::validate($rules); + + if (!$validation) { + static::$errors = array_merge(static::$errors, Form::errors()); + } + + return $validation; + } + + /** + * Manually start an auth session + */ + public static function useSession() + { + static::config('USE_SESSION', true); + static::$session = Auth\Session::init(); + } + + /** + * Throw a 'use session' warning + */ + protected static function sessionCheck() + { + if (!static::config('USE_SESSION')) { + trigger_error('Turn on USE_SESSION to use this feature.'); + } + + if (!static::$session) { + static::useSession(); + } + } + + /** + * A simple auth guard: 'guest' pages can't be viewed when logged in, + * 'auth' pages can't be viewed without authentication + * + * @param string $type The type of guard/guard options + */ + public static function guard(string $type) + { + static::sessionCheck(); + + if ($type === 'guest' && static::status()) { + exit(header('location: ' . static::config('GUARD_HOME'), true, 302)); + } + + if ($type === 'auth' && !static::status()) { + exit(header('location: ' . static::config('GUARD_LOGIN'), true, 302)); + } + } + + /** + * Check session status + */ + public static function status() + { + static::sessionCheck(); + + return static::$session->get('AUTH_USER') ?? false; + } + + /** + * Return the user id encoded in token or session + */ + public static function id() + { + static::leafDbConnect(); + + if (static::config('USE_SESSION')) { + return static::$session->get('AUTH_USER')[static::$settings['ID_KEY']] ?? null; + } + + $payload = static::validateToken(static::config('TOKEN_SECRET')); + if (!$payload) return null; + return $payload->user_id; + } + + /** + * Get the current user data from token + * + * @param string $table The table to look for user + * @param array $hidden Fields to hide from user array + */ + public static function user(string $table = 'users', array $hidden = []) + { + if (!static::id()) { + if (static::config('USE_SESSION')) { + return static::$session->get('AUTH_USER'); + } + + return null; + } + + $user = static::$db->select($table)->where('id', static::id())->fetchAssoc(); + + if (count($hidden) > 0) { + foreach ($hidden as $item) { + if (isset($user[$item]) || !$user[$item]) { + unset($user[$item]); + } + } + } + + return $user; + } + + /** + * End a session + * + * @param string $location A route to redirect to after logout + */ + public static function logout(?string $location = null) + { + static::sessionCheck(); + + static::$session->destroy(); + + if (is_string($location)) { + $route = static::config($location) ?? $location; + return \Leaf\Http\Response::redirect($route); + } + } + + /** + * Session last active + */ + public static function lastActive() { - return Auth\Register::user($table, $credentials, $uniques, $validate); - } - - /** - * Simple user update - * - * @param string $table Table to store user in - * @param array $credentials New information for user - * @param array $where Information to find user by - * @param array $uniques Parameters which should be unique - * @param array $validate Validation for parameters - * - * @return array user: all user info + tokens + session data - */ - public static function update(string $table, array $credentials, array $where, array $uniques = [], array $validate = []): array + static::sessionCheck(); + + return time() - static::$session->get('SESSION_LAST_ACTIVITY'); + } + + /** + * Refresh session + * + * @param bool $clearData Remove existing session data + */ + public static function refresh(bool $clearData = true) + { + static::sessionCheck(); + + $success = static::$session->regenerate($clearData); + + static::$session->set('SESSION_STARTED_AT', time()); + static::$session->set('SESSION_LAST_ACTIVITY', time()); + static::$session->set('AUTH_SESISON', true); + + return $success; + } + + /** + * Define/Return session middleware + * + * @param string $name The name of the middleware to set/get + * @param callable|null $handler The handler for the middleware + */ + public static function middleware(string $name, ?callable $handler = null) { - return Auth\User::update($table, $credentials, $where, $uniques, $validate); - } - - /** - * Validate Json Web Token - * - * @param string $token The token validate - * @param string|null $secretKey The secret key used to encode token - */ - public static function validate(string $token, string $secretKey = null) - { - return Auth\User::validate($token, $secretKey); - } - - /** - * Validate Bearer Token - * - * @param string|null $secretKey The secret key used to encode token - */ - public static function validateToken(string $secretKey = null) - { - return Auth\User::validateToken($secretKey); - } - - /** - * Get Bearer token - */ - public static function getBearerToken() - { - return Auth\User::getBearerToken(); - } - - /** - * Get the current user data from token - * - * @param string $table The table to look for user - * @param array $hidden Fields to hide from user array - */ - public static function user(string $table = "users", array $hidden = []) - { - return Auth\User::info($table, $hidden); - } - - /** - * Return the user id encoded in token - */ - public static function id() - { - return Auth\User::id(); - } - - /** - * Return form field - */ - public static function get($param) - { - return Auth\Core::$form->get($param); - } - - /** - * Manually start an auth session - */ - public static function useSession() - { - Auth\Session::init(); - } - - /** - * Session Length - */ - public static function sessionLength() - { - return Auth\Session::length(); - } - - /** - * Session last active - * - * @deprecated Use `Auth\Session::lastActive()` instead - */ - public static function sessionActive() - { - return Auth\Session::lastActive(); - } - - /** - * Check session status - */ - protected static function session() - { - return Auth\Session::status(); - } - - /** - * End a session - */ - public static function endSession($location = null) - { - return Auth\Session::end($location); - } - - /** - * Define/Return session middleware - * - * **This method only works with session auth** - */ - public static function middleware(string $name, callable $handler = null) - { - return Auth\Session::middleware($name, $handler); - } - - /** - * Save some data to auth session - * - * @deprecated Use `Auth::save()` instead - */ - public static function saveToSession($key, $data = null) - { - Auth\Session::save($key, $data); - } - - /** - * Save some data to auth session - */ - public static function save($key, $data = null) - { - Auth\Session::save($key, $data); - } - - /** - * Get all authentication errors as associative array - */ - public static function errors(): array - { - return Auth\Core::errors(); - } + static::sessionCheck(); + + if (!$handler) return static::$middleware[$name]; + + static::$middleware[$name] = $handler; + } + + /** + * Check how long a session has been going on + */ + public static function length() + { + static::sessionCheck(); + + return time() - static::$session->get('SESSION_STARTED_AT'); + } } diff --git a/src/Auth/Core.php b/src/Auth/Core.php index 384e1e7..ef65478 100644 --- a/src/Auth/Core.php +++ b/src/Auth/Core.php @@ -2,8 +2,7 @@ namespace Leaf\Auth; -use Leaf\Db; -use Leaf\Form; +use Leaf\Helpers\Authentication; /** * Leaf Simple Auth [Core] @@ -19,17 +18,7 @@ class Core /** * All errors caught */ - protected static $errorsArray = []; - - /** - * @var \Leaf\Http\Session - */ - protected static $session; - - /** - * All defined session middleware - */ - protected static $middleware = []; + protected static $errors = []; /** * Auth Settings @@ -60,56 +49,87 @@ class Core /** * @var \Leaf\Db */ - public static $db; + protected static $db; /** - * @var \Leaf\Form + * @var \Leaf\Http\Session */ - public static $form; - - public function __construct($useSession = false) - { - static::$form = new Form; - static::$db = new Db(); + protected static $session; - if ($useSession) { - static::$useSession(); - } + /** + * Connect leaf auth to the database + * + * @param string|array $host Host Name or full config + * @param string $dbname Database name + * @param string $user Database username + * @param string $password Database password + * @param string $dbtype Type of database: mysql, postgres, sqlite, ... + * @param array $pdoOptions Options for PDO connection + */ + public static function connect( + $host, + string $dbname, + string $user, + string $password, + string $dbtype, + array $pdoOptions = [] + ) { + $db = new \Leaf\Db(); + $db->connect($host, $dbname, $user, $password, $dbtype, $pdoOptions); } /** - * Create a db connection - * - * @param string $host The db name - * @param string $user - * @param string $password - * @param string $dbname + * Connect to database using environment variables + * + * @param array $pdoOptions Options for PDO connection */ - public static function connect(string $host, string $user, string $password, string $dbname): void + public function autoConnect(array $pdoOptions = []) { - static::$form = new Form; - static::$db = new Db; + $this->connect( + getenv('DB_HOST'), + getenv('DB_DATABASE'), + getenv('DB_USERNAME'), + getenv('DB_PASSWORD'), + getenv('DB_CONNECTION') ? getenv('DB_CONNECTION') : 'mysql', + $pdoOptions, + ); + } - static::$db->connect($host, $user, $password, $dbname); + /** + * Pass in db connetion instance directly + * + * @param \PDO $connection A connection instance of your db + */ + public static function dbConnection(\PDO $connection) + { + $db = new \Leaf\Db(); + $db->connection($connection); + static::$db = $db; } /** - * Create a database connection from env variables + * Auto connect to leaf db */ - public static function autoConnect(): void + protected static function leafDbConnect() { - static::connect( - getenv("DB_HOST"), - getenv("DB_USERNAME"), - getenv("DB_PASSWORD"), - getenv("DB_DATABASE") - ); + if (!static::$db && function_exists('db')) { + if (db()->connection() instanceof \PDO) { + static::$db = db(); + } + } + + if (!static::$db) { + trigger_error('You need to connect to your database first'); + } } /** * Set auth config + * + * @param string|array $config The auth config key or array of config + * @param string $value The value if $config is a string */ - public static function config($config, $value = null) + public static function config($config, ?string $value = null) { if (is_array($config)) { foreach ($config as $key => $configValue) { @@ -122,13 +142,47 @@ public static function config($config, $value = null) } /** - * Exception for experimental features + * Validate Json Web Token + * + * @param string $token The token validate + * @param string $secretKey The secret key used to encode token */ - protected static function experimental($method) + public static function validateUserToken(string $token, ?string $secretKey = null) { - if (!static::config("USE_SESSION")) { - trigger_error("Auth::$method is experimental. Turn on USE_SESSION to use this feature."); - } + $payload = Authentication::validate($token, $secretKey ?? static::config("TOKEN_SECRET")); + if ($payload) return $payload; + + static::$errors = array_merge(static::$errors, Authentication::errors()); + + return null; + } + + /** + * Validate Bearer Token + * + * @param string $secretKey The secret key used to encode token + */ + public static function validateToken(?string $secretKey = null) + { + $payload = Authentication::validateToken($secretKey ?? static::config("TOKEN_SECRET")); + if ($payload) return $payload; + + static::$errors = array_merge(static::$errors, Authentication::errors()); + + return null; + } + + /** + * Get Bearer token + */ + public static function getBearerToken() + { + $token = Authentication::getBearerToken(); + if ($token) return $token; + + static::$errors = array_merge(static::$errors, Authentication::errors()); + + return null; } /** @@ -136,6 +190,6 @@ protected static function experimental($method) */ public static function errors(): array { - return static::$errorsArray; + return static::$errors; } } diff --git a/src/Auth/Login.php b/src/Auth/Login.php deleted file mode 100644 index dfbb245..0000000 --- a/src/Auth/Login.php +++ /dev/null @@ -1,107 +0,0 @@ -select($table)->where($credentials)->validate($validate)->fetchAssoc(); - if (!$user) { - static::$errorsArray["auth"] = static::$settings["LOGIN_PARAMS_ERROR"]; - return null; - } - - if (static::$settings["AUTH_NO_PASS"] === false) { - $passwordIsValid = true; - - if (static::$settings["PASSWORD_VERIFY"] !== false && isset($user[$passKey])) { - if (is_callable(static::$settings["PASSWORD_VERIFY"])) { - $passwordIsValid = call_user_func(static::$settings["PASSWORD_VERIFY"], $password, $user[$passKey]); - } else if (static::$settings["PASSWORD_VERIFY"] === Password::MD5) { - $passwordIsValid = (md5($password) === $user[$passKey]); - } else { - $passwordIsValid = Password::verify($password, $user[$passKey]); - } - } - - if (!$passwordIsValid) { - static::$errorsArray["password"] = static::$settings["LOGIN_PASSWORD_ERROR"]; - return null; - } - } - - $token = Authentication::generateSimpleToken( - $user[static::$settings["ID_KEY"]], - static::config("TOKEN_SECRET"), - static::config("TOKEN_LIFETIME") - ); - - if (isset($user[static::$settings["ID_KEY"]])) { - $userId = $user[static::$settings["ID_KEY"]]; - } - - if (static::$settings["HIDE_ID"]) { - unset($user[static::$settings["ID_KEY"]]); - } - - if (static::$settings["HIDE_PASSWORD"] && (isset($user[$passKey]) || !$user[$passKey])) { - unset($user[$passKey]); - } - - if (!$token) { - static::$errorsArray = array_merge(static::$errorsArray, Authentication::errors()); - return null; - } - - if (static::config("USE_SESSION")) { - if (isset($userId)) { - $user[static::$settings["ID_KEY"]] = $userId; - } - - static::save("AUTH_USER", $user); - static::save("HAS_SESSION", true); - - if (static::config("SAVE_SESSION_JWT")) { - static::save("AUTH_TOKEN", $token); - } - - exit(header("location: " . static::config("GUARD_HOME"))); - } - - $response["user"] = $user; - $response["token"] = $token; - - return $response; - } -} \ No newline at end of file diff --git a/src/Auth/Register.php b/src/Auth/Register.php deleted file mode 100644 index 3d187e1..0000000 --- a/src/Auth/Register.php +++ /dev/null @@ -1,125 +0,0 @@ -insert($table)->params($credentials)->unique($uniques)->validate($validate)->execute(); - } catch (\Throwable $th) { - trigger_error($th->getMessage()); - } - - if (!$query) { - static::$errorsArray = array_merge(static::$errorsArray, static::$db->errors()); - return null; - } - - $user = static::$db->select($table)->where($credentials)->validate($validate)->fetchAssoc(); - - if (!$user) { - static::$errorsArray = array_merge(static::$errorsArray, static::$db->errors()); - return null; - } - - $token = Authentication::generateSimpleToken( - $user[static::$settings["ID_KEY"]], - static::config("TOKEN_SECRET"), - static::config("TOKEN_LIFETIME") - ); - - if (isset($user[static::$settings["ID_KEY"]])) { - $userId = $user[static::$settings["ID_KEY"]]; - } - - if (static::$settings["HIDE_ID"]) { - unset($user[static::$settings["ID_KEY"]]); - } - - if (static::$settings["HIDE_PASSWORD"] && (isset($user[$passKey]) || !$user[$passKey])) { - unset($user[$passKey]); - } - - if (!$token) { - static::$errorsArray = array_merge(static::$errorsArray, Authentication::errors()); - return null; - } - - if (static::config("USE_SESSION")) { - if (static::config("SESSION_ON_REGISTER")) { - if (isset($userId)) { - $user[static::$settings["ID_KEY"]] = $userId; - } - - static::save("AUTH_USER", $user); - static::save("HAS_SESSION", true); - - if (static::config("SAVE_SESSION_JWT")) { - static::save("AUTH_TOKEN", $token); - } - - exit(header("location: " . static::config("GUARD_HOME"))); - } else { - exit(header("location: " . static::config("GUARD_LOGIN"))); - } - } - - $response["user"] = $user; - $response["token"] = $token; - - return $response; - } -} diff --git a/src/Auth/Session.php b/src/Auth/Session.php index ab0e1cc..e4b9111 100644 --- a/src/Auth/Session.php +++ b/src/Auth/Session.php @@ -1,142 +1,38 @@ get("SESSION_STARTED_AT")) { static::$session->set("SESSION_STARTED_AT", time()); } static::$session->set("SESSION_LAST_ACTIVITY", time()); - } - - /** - * Session Length - */ - public static function length() - { - static::experimental("length"); - - return time() - static::$session->get("SESSION_STARTED_AT"); - } - - /** - * Session last active - */ - public static function lastActive() - { - static::experimental("lastActive"); - - return time() - static::$session->get("SESSION_LAST_ACTIVITY"); - } - - /** - * Refresh session - */ - public static function refresh($clearData = true) - { - static::experimental("refresh"); - - $success = static::$session->regenerate($clearData); - - static::$session->set("SESSION_STARTED_AT", time()); - static::$session->set("SESSION_LAST_ACTIVITY", time()); - static::$session->set("AUTH_SESISON", true); - - return $success; - } - - /** - * Define/Return session middleware - * - * **This method only works with session auth** - */ - public static function middleware(string $name, callable $handler = null) - { - static::experimental("middleware"); - - if (!$handler) return static::$middleware[$name]; - - static::$middleware[$name] = $handler; - } - - /** - * Check session status - */ - public static function status() - { - static::experimental("status"); - - return static::$session->get("AUTH_USER") ?? false; - } - - /** - * End a session - */ - public static function end($location = null) - { - static::experimental("end"); - - static::$session->destroy(); - - if ($location) { - $route = static::config($location) ?? $location; - \Leaf\Http\Response::redirect($route); - } - } - - /** - * A simple auth guard: 'guest' pages can't be viewed when logged in, - * 'auth' pages can't be viewed without authentication - * - * @param array|string $type The type of guard/guard options - */ - public static function guard($type) - { - static::experimental("guard"); - - if (is_array($type)) { - if (isset($type["hasAuth"])) { - $type = $type["hasAuth"] ? 'auth' : 'guest'; - } - } - - if ($type === 'guest' && static::status()) { - exit(header("location: " . static::config("GUARD_HOME"), true, 302)); - } - - if ($type === 'auth' && !static::status()) { - exit(header("location: " . static::config("GUARD_LOGIN"), true, 302)); - } - } - - /** - * Save some data to auth session - */ - public static function save($key, $data = null) - { - static::experimental("save"); - static::$session->set($key, $data); + return static::$session; } } diff --git a/src/Auth/User.php b/src/Auth/User.php deleted file mode 100644 index 3d99fdb..0000000 --- a/src/Auth/User.php +++ /dev/null @@ -1,226 +0,0 @@ - 0) { - foreach ($uniques as $unique) { - if (!isset($credentials[$unique])) { - trigger_error("$unique not found in credentials."); - } - - $data = static::$db->select($table)->where($unique, $credentials[$unique])->fetchAssoc(); - - $wKeys = array_keys($where); - $wValues = array_values($where); - - if (isset($data[$wKeys[0]]) && $data[$wKeys[0]] != $wValues[0]) { - static::$errorsArray[$unique] = "$unique already exists"; - } - } - - if (count(static::$errorsArray) > 0) return null; - } - - try { - $query = static::$db->update($table)->params($credentials)->where($where)->validate($validate)->execute(); - } catch (\Throwable $th) { - trigger_error($th->getMessage()); - } - - if (!$query) { - static::$errorsArray = array_merge(static::$errorsArray, static::$db->errors()); - return null; - } - - if (isset($credentials["updated_at"])) { - unset($credentials["updated_at"]); - } - - $user = static::$db->select($table)->where($credentials)->validate($validate)->fetchAssoc(); - if (!$user) { - static::$errorsArray = array_merge(static::$errorsArray, static::$db->errors()); - return null; - } - - $token = Authentication::generateSimpleToken( - $user[static::$settings["ID_KEY"]], - static::config("TOKEN_SECRET"), - static::config("TOKEN_LIFETIME") - ); - - if (isset($user[static::$settings["ID_KEY"]])) { - $userId = $user[static::$settings["ID_KEY"]]; - } - - if (static::$settings["HIDE_ID"] && isset($user[static::$settings["ID_KEY"]])) { - unset($user[static::$settings["ID_KEY"]]); - } - - if (static::$settings["HIDE_PASSWORD"] && (isset($user[$passKey]) || !$user[$passKey])) { - unset($user[$passKey]); - } - - if (!$token) { - static::$errorsArray = array_merge(static::$errorsArray, Authentication::errors()); - return null; - } - - if (static::config("USE_SESSION")) { - if (isset($userId)) { - $user[static::$settings["ID_KEY"]] = $userId; - } - - static::save("AUTH_USER", $user); - static::save("HAS_SESSION", true); - - if (static::config("SAVE_SESSION_JWT")) { - static::save("AUTH_TOKEN", $token); - } - - return $user; - } - - $response["user"] = $user; - $response["token"] = $token; - - return $response; - } - - /** - * Validate Json Web Token - * - * @param string $token The token validate - * @param string $secretKey The secret key used to encode token - */ - public static function validate($token, $secretKey = null) - { - $payload = Authentication::validate($token, $secretKey ?? static::config("TOKEN_SECRET")); - if ($payload) return $payload; - - static::$errorsArray = array_merge(static::$errorsArray, Authentication::errors()); - - return null; - } - - /** - * Validate Bearer Token - * - * @param string $secretKey The secret key used to encode token - */ - public static function validateToken($secretKey = null) - { - $payload = Authentication::validateToken($secretKey ?? static::config("TOKEN_SECRET")); - if ($payload) return $payload; - - static::$errorsArray = array_merge(static::$errorsArray, Authentication::errors()); - - return null; - } - - /** - * Get Bearer token - */ - public static function getBearerToken() - { - $token = Authentication::getBearerToken(); - if ($token) return $token; - - static::$errorsArray = array_merge(static::$errorsArray, Authentication::errors()); - - return null; - } - - /** - * Return the user id encoded in token - */ - public static function id() - { - if (static::config("USE_SESSION")) { - return static::$session->get("AUTH_USER")[static::$settings["ID_KEY"]] ?? null; - } - - $payload = static::validateToken(static::config("TOKEN_SECRET")); - if (!$payload) return null; - return $payload->user_id; - } - - /** - * Get the current user data from token - * - * @param string $table The table to look for user - * @param array $hidden Fields to hide from user array - */ - public static function info($table = "users", $hidden = []) - { - if (!static::id()) { - if (static::config("USE_SESSION")) { - return static::$session->get("AUTH_USER"); - } - - return null; - } - - $user = static::$db->select($table)->where("id", static::id())->fetchAssoc(); - - if (count($hidden) > 0) { - foreach ($hidden as $item) { - if (isset($user[$item]) || !$user[$item]) { - unset($user[$item]); - } - } - } - - return $user; - } -} diff --git a/src/functions.php b/src/functions.php index f5aec8f..b2b8f59 100644 --- a/src/functions.php +++ b/src/functions.php @@ -1,37 +1,34 @@ $auth]); - } - - return $auth; - } - - return \Leaf\Auth::class; + if (!(\Leaf\Config::get("auth.instance"))) { + \Leaf\Config::set("auth.instance", new Leaf\Auth()); } - if ($guard === 'session') { - return \Leaf\Auth::session(); - } + return \Leaf\Config::get("auth.instance"); + } +} - return \Leaf\Auth::guard($guard); +if (!function_exists('guard') && function_exists('auth')) { + /** + * Run an auth guard + * + * @param string $guard The auth guard to run + */ + function guard(string $guard) + { + return auth()->guard($guard); } } -if (!function_exists('hasAuth')) { +if (!function_exists('hasAuth') && function_exists('auth')) { /** * Find out if there's an active sesion */ @@ -41,7 +38,7 @@ function hasAuth(): bool } } -if (!function_exists('sessionUser')) { +if (!function_exists('sessionUser') && function_exists('auth')) { /** * Get the currently logged in user */