114 lines
3.7 KiB
PHP
114 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Actions\Auth\LoginAction;
|
|
use App\Actions\Auth\VerifyTwoFactorAction;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Auth\LoginRequest;
|
|
use App\Http\Requests\Auth\TwoFactorChallengeRequest;
|
|
use App\Http\Requests\Auth\TwoFactorConfirmRequest;
|
|
use App\Http\Requests\Auth\TwoFactorDisableRequest;
|
|
use App\Http\Resources\UserResource;
|
|
use App\Services\Audit\AuditLogger;
|
|
use App\Services\TwoFactorService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class AuthController extends Controller
|
|
{
|
|
public function login(LoginRequest $request, LoginAction $action, AuditLogger $audit)
|
|
{
|
|
$result = $action->execute($request, $request->string('login')->toString(), $request->string('password')->toString());
|
|
|
|
if ($result['status'] === 'requires_2fa') {
|
|
return response()->json(['requires_2fa' => true, 'challenge_token' => $result['challenge_token']]);
|
|
}
|
|
|
|
$audit->log($result['user'], 'auth.login');
|
|
|
|
return UserResource::make($result['user']);
|
|
}
|
|
|
|
public function verifyTwoFactor(TwoFactorChallengeRequest $request, VerifyTwoFactorAction $action, AuditLogger $audit)
|
|
{
|
|
$user = $action->execute($request, $request->string('challenge_token')->toString(), $request->string('code')->toString());
|
|
|
|
$audit->log($user, 'auth.2fa_verified');
|
|
|
|
return UserResource::make($user);
|
|
}
|
|
|
|
public function logout(Request $request, AuditLogger $audit)
|
|
{
|
|
$audit->log($request->user(), 'auth.logout');
|
|
|
|
Auth::guard('web')->logout();
|
|
$request->session()->invalidate();
|
|
$request->session()->regenerateToken();
|
|
|
|
return response()->noContent();
|
|
}
|
|
|
|
public function me(Request $request)
|
|
{
|
|
return UserResource::make($request->user());
|
|
}
|
|
|
|
public function enableTwoFactor(Request $request, TwoFactorService $twoFactor)
|
|
{
|
|
$user = $request->user();
|
|
$secret = $twoFactor->generateSecret();
|
|
|
|
// Stored but not yet "enabled" until confirmed with a valid code.
|
|
$user->forceFill(['two_factor_secret' => $secret])->save();
|
|
|
|
return response()->json([
|
|
'secret' => $secret,
|
|
'otpauth_url' => $twoFactor->otpAuthUrl($user, $secret),
|
|
]);
|
|
}
|
|
|
|
public function confirmTwoFactor(TwoFactorConfirmRequest $request, TwoFactorService $twoFactor, AuditLogger $audit)
|
|
{
|
|
$user = $request->user();
|
|
|
|
if (! $user->two_factor_secret || ! $twoFactor->verifyCode($user->two_factor_secret, $request->string('code')->toString())) {
|
|
throw ValidationException::withMessages(['code' => 'That code is invalid.']);
|
|
}
|
|
|
|
$user->forceFill([
|
|
'two_factor_enabled' => true,
|
|
'two_factor_confirmed_at' => now(),
|
|
])->save();
|
|
|
|
$recoveryCodes = $twoFactor->generateRecoveryCodes($user);
|
|
|
|
$audit->log($user, 'auth.2fa_enabled');
|
|
|
|
return response()->json(['recovery_codes' => $recoveryCodes]);
|
|
}
|
|
|
|
public function disableTwoFactor(TwoFactorDisableRequest $request, AuditLogger $audit)
|
|
{
|
|
$user = $request->user();
|
|
|
|
if (! Hash::check($request->string('password')->toString(), $user->password)) {
|
|
throw ValidationException::withMessages(['password' => 'That password is incorrect.']);
|
|
}
|
|
|
|
$user->twoFactorRecoveryCodes()->delete();
|
|
$user->forceFill([
|
|
'two_factor_enabled' => false,
|
|
'two_factor_secret' => null,
|
|
'two_factor_confirmed_at' => null,
|
|
])->save();
|
|
|
|
$audit->log($user, 'auth.2fa_disabled');
|
|
|
|
return response()->noContent();
|
|
}
|
|
}
|