From 3a7cea849c54961bc4087b5d221a30e6822946de Mon Sep 17 00:00:00 2001 From: Dominik Hebeler <dominik@hebeler.club> Date: Wed, 21 Aug 2024 13:09:34 +0200 Subject: [PATCH] centrqalize login code storage --- .../Http/Controllers/LogsApiController.php | 31 +++++---- .../Models/Authorization/LogsAuthGuard.php | 69 +++++++++++++++++-- metager/app/Models/Authorization/LogsUser.php | 14 ++-- metager/app/Providers/LogsUserProvider.php | 2 +- metager/resources/views/logs/login.blade.php | 3 + 5 files changed, 96 insertions(+), 23 deletions(-) diff --git a/metager/app/Http/Controllers/LogsApiController.php b/metager/app/Http/Controllers/LogsApiController.php index 0320d4725..d01a70d34 100644 --- a/metager/app/Http/Controllers/LogsApiController.php +++ b/metager/app/Http/Controllers/LogsApiController.php @@ -7,6 +7,7 @@ use App\Models\Authorization\LogsUser; use Auth; use DB; use Illuminate\Http\Request; +use Illuminate\Support\MessageBag; use Mail; use Validator; @@ -71,12 +72,19 @@ class LogsApiController extends Controller public function login(Request $request) { + if (!is_null(Auth::guard("logs")->user()->getAuthIdentifier())) { + session()->flash("email", Auth::guard("logs")->user()->getAuthIdentifier()); + } return view("logs.login", ['title' => __('titles.logs.login')]); } public function login_post(Request $request) { + $email_validation = "email:rfc,dns"; + if (!$request->filled("code")) { + $email_validation = "required|" . $email_validation; + } $validator = Validator::make($request->input(), [ - "email" => "required|email:rfc,dns", + "email" => $email_validation, 'code' => 'regex:/^\d{6}$/i' ]); @@ -86,19 +94,18 @@ class LogsApiController extends Controller } $validated = $validator->validated(); - $user = app(LogsUser::class)->fetchUserByMail($validated["email"]); - - if (!is_null($user->getAuthIdentifier()) && !is_null($user->getAuthPassword())) { - if (!empty($validated["code"])) { - if (Auth::guard("logs")->attempt(["username" => $validated["email"], "password" => $validated["code"]])) { - session(["logs_authenticated" => true]); - $url = session("url.intended"); - return redirect($url); - } + if (isset($validated["code"])) { + if (Auth::guard("logs")->validate(["username" => $validated["email"], "password" => $validated["code"]])) { + $url = session("url.intended"); + return redirect($url); } else { - // Send Email with login Code - Mail::to($validated["email"])->send(new LogsLoginCode($user->getAuthPassword())); + // Code wasn't correct + $errors = new MessageBag(); + $errors->add("invalid_logincode", "Login Code was invalid"); + return redirect(route("logs:login"))->withErrors($errors); } + } else { + Auth::guard("logs")->init($validated["email"]); } return redirect(route("logs:login"))->with(["email" => $validated["email"]]); } diff --git a/metager/app/Models/Authorization/LogsAuthGuard.php b/metager/app/Models/Authorization/LogsAuthGuard.php index eca6b6058..9a7fc1ea1 100644 --- a/metager/app/Models/Authorization/LogsAuthGuard.php +++ b/metager/app/Models/Authorization/LogsAuthGuard.php @@ -1,21 +1,71 @@ <?php namespace App\Models\Authorization; +use App\Mail\LogsLoginCode; +use Cache; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Http\Request; +use Mail; class LogsAuthGuard implements \Illuminate\Contracts\Auth\Guard { + const SESSION_LOGS_USERNAME_KEY = "logs_username"; + const CACHE_LOGS_PASSWORD_KEY = "logs_password"; + const SESSION_LOGS_AUTHORIZED_KEY = "logs_authorized"; + const SESSION_LOGS_AUTH_TRIES_KEY = "logs_authroization_tries"; private UserProvider $userProvider; private Request $request; private Authenticatable|null $user; + private bool $authorized = false; public function __construct(UserProvider $userProvider, Request $request) { $this->userProvider = $userProvider; $this->request = $request; $this->user = null; + if (!is_null(session(self::SESSION_LOGS_AUTHORIZED_KEY))) { + $this->authorized = session(self::SESSION_LOGS_AUTHORIZED_KEY); + } + if (!is_null(session(self::SESSION_LOGS_USERNAME_KEY))) { + $credentials = ["username" => session(self::SESSION_LOGS_USERNAME_KEY)]; + if (Cache::has(self::CACHE_LOGS_PASSWORD_KEY . ":" . $credentials["username"])) { + $credentials["password"] = Cache::get(self::CACHE_LOGS_PASSWORD_KEY . ":" . $credentials["username"]); + } + $this->user = $this->userProvider->retrieveByCredentials($credentials); + $this->sendPassword(); + } + } + + /** + * Initializes a new authorization providing an email address. + * That email address has to be authorized with a logincode furtheron. + * + * + * @param string $email + * @return void + */ + public function init(string $email) + { + $this->user = $this->userProvider->retrieveByCredentials(["username" => $email]); + session([ + self::SESSION_LOGS_USERNAME_KEY => $this->user->getAuthIdentifier(), + ]); + $this->sendPassword(); } + /** + * Checks if a logincode needs to be sent out to the user by mail + * @return void + */ + private function sendPassword() + { + // Store the password + if (!$this->authorized && !is_null($this->user->getAuthPassword()) && !Cache::has(self::CACHE_LOGS_PASSWORD_KEY . ":" . $this->user->getAuthIdentifier())) { + Cache::put(self::CACHE_LOGS_PASSWORD_KEY . ":" . $this->user->getAuthIdentifier(), $this->user->getAuthPassword(), now()->addMinutes(5)); + // Send Email with login Code + Mail::to($this->user->getAuthIdentifier())->send(new LogsLoginCode($this->user->getAuthPassword())); + } + } + /** * Determine if the current user is authenticated. * @@ -23,7 +73,7 @@ class LogsAuthGuard implements \Illuminate\Contracts\Auth\Guard */ public function check(): bool { - return !is_null($this->user); + return $this->authorized; } /** @@ -67,13 +117,24 @@ class LogsAuthGuard implements \Illuminate\Contracts\Auth\Guard public function validate(array $credentials = []) { if (empty($credentials["username"]) || empty($credentials["password"])) { + session([self::SESSION_LOGS_AUTHORIZED_KEY => false]); + $this->authorized = false; return false; } - $user = $this->userProvider->retrieveByCredentials($credentials); - if (!is_null($user) && $this->userProvider->validateCredentials($user, $credentials)) { - $this->setUser($user); + + if (!is_null($this->user) && $this->userProvider->validateCredentials($this->user, $credentials)) { + session([self::SESSION_LOGS_AUTHORIZED_KEY => true]); + $this->authorized = true; return true; } else { + session([self::SESSION_LOGS_AUTHORIZED_KEY => false]); + $tries = session(self::SESSION_LOGS_AUTH_TRIES_KEY, 0); + if ($tries < 5) { + session([self::SESSION_LOGS_AUTH_TRIES_KEY => ($tries + 1)]); + } else { + Cache::forget(self::CACHE_LOGS_PASSWORD_KEY . ":" . $this->user->getAuthIdentifier()); + } + $this->authorized = false; return false; } } diff --git a/metager/app/Models/Authorization/LogsUser.php b/metager/app/Models/Authorization/LogsUser.php index 37643fbe9..4eaa51e50 100644 --- a/metager/app/Models/Authorization/LogsUser.php +++ b/metager/app/Models/Authorization/LogsUser.php @@ -11,23 +11,25 @@ class LogsUser implements Authenticatable private int $discount; - public function fetchUserByMail(string $username) + public function fetchUserByCredentials(array $credentials) { - $user = DB::table("logs_users")->where("email", "=", $username)->first(); + $user = DB::table("logs_users")->where("email", "=", $credentials["username"])->first(); + $this->email = $credentials["username"]; if (!is_null($user)) { - $this->email = $username; - if (!empty(session("login_token"))) { - $this->login_token = session("login_token"); + if (isset($credentials["password"])) { + $this->login_token = $credentials["password"]; } else { $this->login_token = (string) rand(0, 999999); while (strlen($this->login_token) < 6) { $this->login_token = '0' . $this->login_token; } - session(["login_token" => $this->login_token]); } $this->discount = $user->discount; + } else { + $this->login_token = ""; } return $this; + } /** * Get the name of the unique identifier for the user. diff --git a/metager/app/Providers/LogsUserProvider.php b/metager/app/Providers/LogsUserProvider.php index f5ac5bcf6..6f025a8de 100644 --- a/metager/app/Providers/LogsUserProvider.php +++ b/metager/app/Providers/LogsUserProvider.php @@ -60,7 +60,7 @@ class LogsUserProvider implements UserProvider if (empty($credentials)) { return; } - return $this->user->fetchUserByMail($credentials["username"]); + return $this->user->fetchUserByCredentials($credentials); } /** diff --git a/metager/resources/views/logs/login.blade.php b/metager/resources/views/logs/login.blade.php index 38c0511f8..21df09d45 100644 --- a/metager/resources/views/logs/login.blade.php +++ b/metager/resources/views/logs/login.blade.php @@ -16,6 +16,9 @@ @endif <form action="{{ route("logs:login:post")}}" method="post"> <input type="hidden" name="_token" value="{{ csrf_token() }}" /> + @if(session("email")) + <input type="hidden" name="email" value="{{session('email')}}"> + @endif <div class="input-group"> <label for="email">Email Addresse</label> @if(session("email")) -- GitLab