141 lines
3.7 KiB
PHP
141 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Auth;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Auth\LoginRequest;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Route;
|
|
use Illuminate\Support\Str;
|
|
use Inertia\Inertia;
|
|
use Inertia\Response;
|
|
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
|
|
|
class AuthenticatedSessionController extends Controller
|
|
{
|
|
/**
|
|
* Show the login page.
|
|
*/
|
|
public function create(Request $request): Response
|
|
{
|
|
return Inertia::render('auth/login', [
|
|
'canResetPassword' => Route::has('password.request'),
|
|
'status' => $request->session()->get('status'),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Handle an incoming authentication request.
|
|
*/
|
|
public function store(LoginRequest $request): SymfonyResponse
|
|
{
|
|
try {
|
|
$request->authenticate();
|
|
} catch (\Illuminate\Validation\ValidationException $e) {
|
|
$request->session()->flash('error', __('auth.login_failed'));
|
|
|
|
return redirect()->route('login')->withErrors($e->errors());
|
|
}
|
|
|
|
Log::info('Login attempt', ['login' => $request->login, 'authenticated' => Auth::check()]);
|
|
|
|
$request->session()->regenerate();
|
|
$request->session()->flash('success', __('auth.login_success'));
|
|
|
|
$user = Auth::user();
|
|
if ($user && $user->email_verified_at === null) {
|
|
return Inertia::location(route('verification.notice'));
|
|
}
|
|
|
|
$returnTo = $this->resolveReturnTo($request);
|
|
if ($returnTo !== null) {
|
|
return Inertia::location($returnTo);
|
|
}
|
|
|
|
return Inertia::location($this->defaultAdminPath());
|
|
}
|
|
|
|
/**
|
|
* Destroy an authenticated session.
|
|
*/
|
|
public function destroy(Request $request): RedirectResponse
|
|
{
|
|
Auth::guard('web')->logout();
|
|
|
|
$request->session()->invalidate();
|
|
$request->session()->regenerateToken();
|
|
|
|
return redirect('/');
|
|
}
|
|
|
|
private function resolveReturnTo(Request $request): ?string
|
|
{
|
|
$encoded = $request->string('return_to')->trim();
|
|
|
|
if ($encoded === '') {
|
|
return null;
|
|
}
|
|
|
|
return $this->decodeReturnTo($encoded, $request);
|
|
}
|
|
|
|
private function decodeReturnTo(string $value, Request $request): ?string
|
|
{
|
|
$candidate = $this->decodeBase64Url($value) ?? $value;
|
|
$candidate = trim($candidate);
|
|
|
|
if ($candidate === '') {
|
|
return null;
|
|
}
|
|
|
|
if (str_starts_with($candidate, '/')) {
|
|
return $candidate;
|
|
}
|
|
|
|
$targetHost = parse_url($candidate, PHP_URL_HOST);
|
|
$scheme = parse_url($candidate, PHP_URL_SCHEME);
|
|
|
|
if (! $scheme || ! $targetHost) {
|
|
return null;
|
|
}
|
|
|
|
$appHost = parse_url($request->getSchemeAndHttpHost(), PHP_URL_HOST);
|
|
|
|
if ($appHost && ! Str::endsWith($targetHost, $appHost)) {
|
|
return null;
|
|
}
|
|
|
|
return $candidate;
|
|
}
|
|
|
|
private function defaultAdminPath(): string
|
|
{
|
|
$base = rtrim(route('tenant.admin.app', absolute: false), '/');
|
|
if ($base === '') {
|
|
$base = '/event-admin';
|
|
}
|
|
|
|
return $base.'/events';
|
|
}
|
|
|
|
private function decodeBase64Url(string $value): ?string
|
|
{
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
$padded = str_pad($value, strlen($value) + ((4 - (strlen($value) % 4)) % 4), '=');
|
|
$normalized = strtr($padded, '-_', '+/');
|
|
$decoded = base64_decode($normalized, true);
|
|
|
|
if ($decoded === false) {
|
|
return null;
|
|
}
|
|
|
|
return $decoded;
|
|
}
|
|
}
|