captcha cleanup and added 2fa logins
This commit is contained in:
@@ -6,10 +6,11 @@ use App\Helpers;
|
||||
use App\Jobs\SendEmail;
|
||||
use App\Mail\UserEmailUpdateRequest;
|
||||
use App\Models\User;
|
||||
use App\Providers\QRCodeProvider;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use RobThree\Auth\Algorithm;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
@@ -130,4 +131,110 @@ class AccountController extends Controller
|
||||
session()->flash('message-type', 'success');
|
||||
return redirect()->route('index');
|
||||
}
|
||||
|
||||
public static function getTFAInstance()
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new QRCodeProvider(), 'STEMMechanics', 6, 30, Algorithm::Sha512);
|
||||
$tfa->ensureCorrectTime();
|
||||
return $tfa;
|
||||
}
|
||||
|
||||
public function show_tfa()
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user->tfa_secret === null) {
|
||||
$tfa = self::getTFAInstance();
|
||||
$secret = $tfa->createSecret();
|
||||
|
||||
return response()->json([
|
||||
'secret' => $secret,
|
||||
]);
|
||||
} else {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
public function show_tfa_image(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user->tfa_secret === null && $request->has('secret')) {
|
||||
$tfa = self::getTFAInstance();
|
||||
|
||||
$qrCodeProvider = new QRCodeProvider();
|
||||
$qrCode = $qrCodeProvider->getQRCodeImage(
|
||||
$tfa->getQRText($user->email, $request->get('secret')),
|
||||
200
|
||||
);
|
||||
|
||||
return response()->stream(function () use ($qrCode) {
|
||||
echo $qrCode;
|
||||
}, 200, ['Content-Type' => $qrCodeProvider->getMimeType()]);
|
||||
} else {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
public function post_tfa(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->tfa_secret === null && $request->has('secret') && $request->has('code')) {
|
||||
$secret = $request->get('secret');
|
||||
$code = $request->get('code');
|
||||
|
||||
$tfa = self::getTFAInstance();
|
||||
|
||||
if ($tfa->verifyCode($secret, $code, 4)) {
|
||||
$user->tfa_secret = $secret;
|
||||
$user->save();
|
||||
|
||||
$codes = $user->generateBackupCodes();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'codes' => $codes
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy_tfa(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->tfa_secret !== null) {
|
||||
$user->tfa_secret = null;
|
||||
$user->save();
|
||||
|
||||
$user->backupCodes()->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
} else {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
||||
public function post_tfa_reset_backup_codes(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->tfa_secret !== null) {
|
||||
$codes = $user->generateBackupCodes();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'codes' => $codes
|
||||
]);
|
||||
} else {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
||||
use App\Jobs\SendEmail;
|
||||
use App\Mail\UserEmailUpdateConfirm;
|
||||
use App\Mail\UserLogin;
|
||||
use App\Mail\UserLoginBackupCode;
|
||||
use App\Mail\UserRegister;
|
||||
use App\Mail\UserWelcome;
|
||||
use App\Models\Token;
|
||||
@@ -47,13 +48,60 @@ class AuthController extends Controller
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'captcha' => 'required_captcha',
|
||||
], [
|
||||
'email.required' => __('validation.custom_messages.email_required'),
|
||||
'email.email' => __('validation.custom_messages.email_invalid'),
|
||||
]);
|
||||
|
||||
$forceEmailLogin = false;
|
||||
|
||||
if($request->has('code')) {
|
||||
$user = User::where('email', $request->email)->whereNotNull('email_verified_at')->first();
|
||||
if($user) {
|
||||
$tfa = AccountController::getTFAInstance();
|
||||
if ($request->code && $tfa->verifyCode($user->tfa_secret, $request->code, 4)) {
|
||||
$data = ['url' => session()->pull('url.intended', null)];
|
||||
return $this->loginByUser($user, $data);
|
||||
}
|
||||
}
|
||||
|
||||
return view('auth.login-2fa', ['email' => $request->email])->withErrors([
|
||||
'code' => 'The 2FA code is not valid',
|
||||
]);
|
||||
}
|
||||
|
||||
if($request->has('backup_code')) {
|
||||
$user = User::where('email', $request->email)->whereNotNull('email_verified_at')->first();
|
||||
if($user) {
|
||||
if($user->verifyBackupCode($request->backup_code)) {
|
||||
$data = ['url' => session()->pull('url.intended', null)];
|
||||
|
||||
dispatch(new SendEmail($user->email, new UserLoginBackupCode($user->email)))->onQueue('mail');
|
||||
|
||||
return $this->loginByUser($user, $data);
|
||||
}
|
||||
}
|
||||
|
||||
return view('auth.login-2fa', ['email' => $request->email, 'method' => 'backup'])->withErrors([
|
||||
'backup_code' => 'The backup code is not valid',
|
||||
]);
|
||||
}
|
||||
|
||||
if($request->has('method')) {
|
||||
if($request->get('method') === 'email') {
|
||||
$forceEmailLogin = true;
|
||||
} else {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
$user = User::where('email', $request->email)->whereNotNull('email_verified_at')->first();
|
||||
if($user) {
|
||||
if ($user) {
|
||||
if (!$forceEmailLogin && $user->tfa_secret !== null) {
|
||||
return view('auth.login-2fa', ['user' => $user]);
|
||||
}
|
||||
|
||||
$token = $user->tokens()->create([
|
||||
'type' => 'login',
|
||||
'data' => ['url' => session()->pull('url.intended', null)],
|
||||
@@ -190,6 +238,7 @@ class AuthController extends Controller
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'captcha' => 'required_captcha',
|
||||
], [
|
||||
'email.required' => __('validation.custom_messages.email_required'),
|
||||
'email.email' => __('validation.custom_messages.email_invalid')
|
||||
|
||||
Reference in New Issue
Block a user