diff --git a/app/Http/Responses/LoginResponse.php b/app/Http/Responses/LoginResponse.php index 87982eca..ded8f861 100644 --- a/app/Http/Responses/LoginResponse.php +++ b/app/Http/Responses/LoginResponse.php @@ -2,6 +2,7 @@ namespace App\Http\Responses; +use App\Services\AuthEntryPointService; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract; @@ -9,13 +10,15 @@ use Laravel\Fortify\Fortify; class LoginResponse implements LoginResponseContract { + public function __construct(private readonly AuthEntryPointService $authEntryPointService) {} + /** * Create an HTTP response that represents the object. */ public function toResponse($request): JsonResponse|RedirectResponse { - // Flash a session variable to indicate the user just logged in session()->flash('show_encryption_prompt', true); + $this->authEntryPointService->queueReturningUserCookie(); return $request->wantsJson() ? response()->json(['two_factor' => false]) diff --git a/app/Http/Responses/RegisterResponse.php b/app/Http/Responses/RegisterResponse.php index 7314fb55..f0533182 100644 --- a/app/Http/Responses/RegisterResponse.php +++ b/app/Http/Responses/RegisterResponse.php @@ -2,14 +2,19 @@ namespace App\Http\Responses; +use App\Services\AuthEntryPointService; use Illuminate\Http\JsonResponse; use Laravel\Fortify\Contracts\RegisterResponse as RegisterResponseContract; use Symfony\Component\HttpFoundation\Response; class RegisterResponse implements RegisterResponseContract { + public function __construct(private readonly AuthEntryPointService $authEntryPointService) {} + public function toResponse($request): Response { + $this->authEntryPointService->queueReturningUserCookie(); + if ($request->wantsJson()) { return new JsonResponse('', 201); } diff --git a/app/Http/Responses/TwoFactorLoginResponse.php b/app/Http/Responses/TwoFactorLoginResponse.php index 1d62c4c4..6cf31aee 100644 --- a/app/Http/Responses/TwoFactorLoginResponse.php +++ b/app/Http/Responses/TwoFactorLoginResponse.php @@ -2,6 +2,7 @@ namespace App\Http\Responses; +use App\Services\AuthEntryPointService; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract; @@ -9,13 +10,15 @@ use Laravel\Fortify\Fortify; class TwoFactorLoginResponse implements TwoFactorLoginResponseContract { + public function __construct(private readonly AuthEntryPointService $authEntryPointService) {} + /** * Create an HTTP response that represents the object. */ public function toResponse($request): JsonResponse|RedirectResponse { - // Flash a session variable to indicate the user just logged in session()->flash('show_encryption_prompt', true); + $this->authEntryPointService->queueReturningUserCookie(); return $request->wantsJson() ? new JsonResponse('', 204) diff --git a/app/Services/AuthEntryPointService.php b/app/Services/AuthEntryPointService.php new file mode 100644 index 00000000..4265058f --- /dev/null +++ b/app/Services/AuthEntryPointService.php @@ -0,0 +1,58 @@ +hasAuthenticatedBefore($request) + || ! Features::enabled(Features::registration()) + || $this->landingAuthOverrideService->authButtonsHidden($request) + ) { + return route('login'); + } + + return route('register'); + } + + public function queueReturningUserCookie(): void + { + Cookie::queue($this->makeReturningUserCookie()); + } + + private function hasAuthenticatedBefore(Request $request): bool + { + return filter_var($request->cookie(self::COOKIE_NAME), FILTER_VALIDATE_BOOL); + } + + private function makeReturningUserCookie(): HttpFoundationCookie + { + return Cookie::make( + self::COOKIE_NAME, + '1', + self::COOKIE_MINUTES, + '/', + config('session.domain'), + config('session.secure'), + true, + false, + config('session.same_site', 'lax'), + ); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index 41a83c47..58d435d1 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -6,6 +6,7 @@ use App\Http\Middleware\EnsureUserIsSubscribed; use App\Http\Middleware\HandleAppearance; use App\Http\Middleware\HandleInertiaRequests; use App\Http\Middleware\SetLocale; +use App\Services\AuthEntryPointService; use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; @@ -21,6 +22,8 @@ return Application::configure(basePath: dirname(__DIR__)) health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { + $middleware->redirectGuestsTo(fn (Request $request) => app(AuthEntryPointService::class)->guestRedirectRoute($request)); + $middleware->encryptCookies(except: ['appearance', 'sidebar_state', 'chart-color-scheme']); $middleware->trustProxies( diff --git a/resources/js/components/partials/header.tsx b/resources/js/components/partials/header.tsx index cd8e013a..3bd7f3bf 100644 --- a/resources/js/components/partials/header.tsx +++ b/resources/js/components/partials/header.tsx @@ -1,5 +1,5 @@ import { cn } from '@/lib/utils'; -import { dashboard } from '@/routes'; +import { dashboard, login } from '@/routes'; import { type SharedData } from '@/types'; import { __ } from '@/utils/i18n'; import { Link, usePage } from '@inertiajs/react'; @@ -119,7 +119,7 @@ export default function Header({ ) : ( <> - +