diff --git a/resources/js/nostrLogin.js b/resources/js/nostrLogin.js index 7b6c15d..a0d22c7 100644 --- a/resources/js/nostrLogin.js +++ b/resources/js/nostrLogin.js @@ -10,6 +10,11 @@ export default () => ({ // session-id migration (which would otherwise yield a 419 on the next // round-trip). nostrLoginInProgress: false, + // Toggled by the @lightning-login-ready handler in login.blade.php once + // the server signals a matching LoginKey. Same purpose: pause wire:poll + // before the full-page navigation to /auth/complete-lightning so the + // browser does not race the redirect with another poll tick. + lightningLoginInProgress: false, async init() { this.startTime = Date.now(); diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index 7d9c4df..bf80d9e 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -7,11 +7,18 @@ - - + + - + @@ -148,14 +155,15 @@ - + @auth - - + @auth - + - + - - - - - - -
-
- - -
- {{ auth()->user()?->name }} - - @if(strlen(auth()->user()?->name) > 12) - {{ Str::substr(auth()->user()?->name, 0, 4) }} - ...{{ Str::substr(auth()->user()?->name, -4) }} - @else - {{ auth()->user()?->name }} - @endif - -
-
-
-
- - - - - {{ __('Settings') }} - - - - -
- @csrf - - {{ __('Log Out') }} - -
-
-
@endauth diff --git a/resources/views/livewire/auth/login.blade.php b/resources/views/livewire/auth/login.blade.php index 8a3ab09..697fae9 100644 --- a/resources/views/livewire/auth/login.blade.php +++ b/resources/views/livewire/auth/login.blade.php @@ -282,42 +282,35 @@ class extends Component { return Str::transliterate(Str::lower($this->email).'|'.request()->ip()); } - public function checkAuth() + public function checkAuth(): void { $loginKey = LoginKey::query() ->where('k1', $this->k1) - ->whereDate('created_at', '>=', now()->subMinutes(5)) + ->where('created_at', '>=', now()->subMinutes(5)) ->first(); - if ($loginKey) { - // Persist the locale choice before the auth round-trip — once we - // redirect, this component is unmounted and $currentLangCountry - // would otherwise be lost. - session(['lang_country' => $this->currentLangCountry]); - - // Hand off to a dedicated controller via full-page redirect. - // Calling auth()->login() inside the wire:poll handler rotates - // the session id and CSRF token mid-flight. Any Livewire request - // that arrives in the same window — a parallel wire:poll tick, - // a sibling component update, a click on the Nostr button — - // would then 419 (TokenMismatch). The controller performs the - // login on a clean, non-Livewire request before redirecting on - // to the dashboard. - return $this->redirect( - route('auth.ln.complete', ['k1' => $this->k1]), - navigate: false, - ); + if (! $loginKey) { + return; } - // Check if k1 has expired (older than 5 minutes) - $k1CreatedAt = now()->subMinutes(5); - if ($this->k1 && now()->diffInMinutes($k1CreatedAt) >= 5) { - $this->authError = 'Session expired. Please try again.'; + // Persist the locale choice before the auth round-trip — once we + // navigate, this component is unmounted and $currentLangCountry + // would otherwise be lost. + session(['lang_country' => $this->currentLangCountry]); - return true; - } - - return true; + // Hand the full-page navigation off to the client: returning a + // Livewire redirect from inside wire:poll has shown races with + // subsequent poll ticks (visible as a "request loop without + // redirect" for the user). Dispatching an event lets Alpine pause + // wire:poll via lightningLoginInProgress and run a clean + // window.location navigation. The dedicated /auth/complete-lightning + // controller then performs auth()->login() on a non-Livewire + // request, avoiding the session-id/CSRF rotation race that + // previously yielded 419s. + $this->dispatch( + 'lightning-login-ready', + url: route('auth.ln.complete', ['k1' => $this->k1]), + ); } /** @@ -345,7 +338,8 @@ class extends Component {
@@ -447,7 +441,12 @@ class extends Component { flight. Otherwise wire:poll can fire a parallel /livewire/update request that races with auth()->login()'s session migration and lands on an invalidated session id, producing 419 TokenMismatch. --}} -