235 lines
6.3 KiB
PHP
235 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Http\Request as IlluminateRequest;
|
|
use Illuminate\Http\Response as IlluminateHtmlResponse;
|
|
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
|
use Illuminate\Support\MessageBag;
|
|
|
|
|
|
use Google2FA;
|
|
use Request;
|
|
|
|
class AuthGoogle2FA
|
|
{
|
|
const CONFIG_PACKAGE_NAME = 'google2fa';
|
|
const SESSION_AUTH_PASSED = 'auth_passed';
|
|
const OTP_EMPTY = 'empty';
|
|
const OTP_VALID = 'valid';
|
|
const OTP_INVALID = 'invalid';
|
|
|
|
protected $password;
|
|
protected $request;
|
|
protected $auth;
|
|
|
|
public function __construct(IlluminateRequest $request)
|
|
{
|
|
$this->request = $request;
|
|
return $this;
|
|
}
|
|
|
|
public function init(IlluminateRequest $request)
|
|
{
|
|
$this->request = $request;
|
|
return $this;
|
|
}
|
|
|
|
public function isAuthenticated()
|
|
{
|
|
if(!$this->hasSecretKey() || !$this->isEnabled() || $this->noUserIsAuthenticated()){
|
|
return false;
|
|
}
|
|
if($this->twoFactorAuthStillValid()){
|
|
return true;
|
|
}
|
|
return ($this->checkOTP() === $this::OTP_VALID);
|
|
}
|
|
|
|
public function logout()
|
|
{
|
|
$this->sessionForget();
|
|
}
|
|
|
|
public function makeActiveOneTimePasswordResponse()
|
|
{
|
|
|
|
if($this->request->isMethod('post') && Request::get('action') === 'activate_user_one_time_password'){
|
|
$user = $this->getUser();
|
|
$user->google2fa = true;
|
|
$user->save();
|
|
return back();
|
|
}
|
|
$MyGoogle2FA = new MyGoogle2FA();
|
|
$MyGoogle2FA->init($this->getUser())->generate();
|
|
$fill = [
|
|
'MyGoogle2FA' => $MyGoogle2FA,
|
|
];
|
|
$view = view("auth.google2fa_activate", $fill);
|
|
return new IlluminateHtmlResponse($view);
|
|
|
|
|
|
}
|
|
|
|
public function makeRequestOneTimePasswordResponse()
|
|
{
|
|
$view = view($this->config('view'));
|
|
$statusCode = $this->makeStatusCode();
|
|
if ($statusCode !== SymfonyResponse::HTTP_OK) {
|
|
$view->withErrors($this->getErrorBagForStatusCode($statusCode));
|
|
}
|
|
return new IlluminateHtmlResponse($view, $statusCode);
|
|
}
|
|
|
|
protected function checkOTP()
|
|
{
|
|
if (!$this->request->has($this->config('otp_input') )|| empty($this->request->input($this->config('otp_input')))) {
|
|
return $this::OTP_EMPTY;
|
|
}
|
|
|
|
$isValid = $this->verifyOneTimePassword();
|
|
|
|
if ($isValid) {
|
|
$this->login();
|
|
return $this::OTP_VALID;
|
|
}
|
|
return $this::OTP_INVALID;
|
|
}
|
|
|
|
protected function login()
|
|
{
|
|
$this->sessionPut($this::SESSION_AUTH_PASSED, true);
|
|
}
|
|
|
|
protected function verifyOneTimePassword()
|
|
{
|
|
return Google2FA::verifyKey($this->getGoogle2FASecretKey(), $this->getOneTimePassword());
|
|
}
|
|
|
|
private function getOneTimePassword()
|
|
{
|
|
$password =$this->request->input($this->config('otp_input'));
|
|
if (is_null($password) || empty($password)) {
|
|
if ($this->config('throw_exceptions', true)) {
|
|
throw new \Exception($this->config('error_messages.cannot_be_empty')); }
|
|
}
|
|
return $password;
|
|
}
|
|
|
|
private function getGoogle2FASecretKey()
|
|
{
|
|
return $this->getUser()->{$this->config('otp_secret_column')};
|
|
}
|
|
private function hasSecretKey()
|
|
{
|
|
$secret = $this->getGoogle2FASecretKey();
|
|
return !is_null($secret) && !empty($secret);
|
|
}
|
|
|
|
private function twoFactorAuthStillValid()
|
|
{
|
|
return (bool) $this->sessionGet($this::SESSION_AUTH_PASSED, false);
|
|
}
|
|
|
|
private function isEnabled()
|
|
{
|
|
return $this->config('enabled');
|
|
}
|
|
|
|
private function noUserIsAuthenticated()
|
|
{
|
|
return is_null($this->getUser());
|
|
}
|
|
|
|
private function config($string, $default = null)
|
|
{
|
|
if (is_null(config($config = $this::CONFIG_PACKAGE_NAME))) {
|
|
throw new \Exception("Config ({$config}.php) not found. Have you published it?");
|
|
}
|
|
return config(
|
|
implode('.', [$this::CONFIG_PACKAGE_NAME, $string]),
|
|
$default
|
|
);
|
|
}
|
|
|
|
private function getAuth()
|
|
{
|
|
if (is_null($this->auth)) {
|
|
$this->auth = app($this->config('auth'));
|
|
|
|
if (!empty($this->config('guard'))) {
|
|
$this->auth = app($this->config('auth'))->guard($this->config('guard'));
|
|
}
|
|
}
|
|
|
|
return $this->auth;
|
|
}
|
|
|
|
private function getUser()
|
|
{
|
|
return $this->getAuth()->user();
|
|
}
|
|
|
|
private function makeSessionVarName($name = null)
|
|
{
|
|
return $this->config('session_var') . (is_null($name) || empty($name) ? '' : '.' . $name);
|
|
}
|
|
|
|
private function sessionGet($var = null, $default = null)
|
|
{
|
|
return $this->request->session()->get(
|
|
$this->makeSessionVarName($var),
|
|
$default
|
|
);
|
|
}
|
|
|
|
private function sessionPut($var, $value)
|
|
{
|
|
$this->request->session()->put(
|
|
$this->makeSessionVarName($var),
|
|
$value
|
|
);
|
|
return $value;
|
|
}
|
|
|
|
private function sessionForget($var = null)
|
|
{
|
|
$this->request->session()->forget(
|
|
$this->makeSessionVarName($var)
|
|
);
|
|
}
|
|
|
|
private function makeStatusCode()
|
|
{
|
|
if ($this->request->isMethod('get') || ($this->checkOTP() === $this::OTP_VALID)) {
|
|
return SymfonyResponse::HTTP_OK;
|
|
}
|
|
|
|
if ($this->checkOTP() === $this::OTP_EMPTY) {
|
|
return SymfonyResponse::HTTP_BAD_REQUEST;
|
|
}
|
|
|
|
return SymfonyResponse::HTTP_UNPROCESSABLE_ENTITY;
|
|
}
|
|
private function getErrorBagForStatusCode($statusCode)
|
|
{
|
|
$errorMap = [
|
|
SymfonyResponse::HTTP_UNPROCESSABLE_ENTITY => 'google2fa.error_messages.wrong_otp',
|
|
SymfonyResponse::HTTP_BAD_REQUEST => 'google2fa.error_messages.cannot_be_empty',
|
|
];
|
|
|
|
return $this->createErrorBagForMessage(
|
|
trans(
|
|
config(
|
|
array_key_exists($statusCode, $errorMap) ? $errorMap[$statusCode] : 'google2fa.error_messages.unknown'
|
|
)
|
|
)
|
|
);
|
|
}
|
|
private function createErrorBagForMessage($message)
|
|
{
|
|
return new MessageBag([
|
|
'message' => $message,
|
|
]);
|
|
}
|
|
}
|