clusev/app/Livewire/Settings/Sessions.php

106 lines
3.6 KiB
PHP

<?php
namespace App\Livewire\Settings;
use App\Services\SessionService;
use App\Support\Confirm\ConfirmToken;
use App\Support\Confirm\InvalidConfirmToken;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\On;
use Livewire\Component;
class Sessions extends Component
{
/**
* Open the R5 confirm for "sign out other devices". The current session is
* kept; only the other rows are deleted on confirm. The modal writes the
* audit row (session.logout_others) and re-dispatches the apply event.
*/
public function confirmLogoutOthers(): void
{
$this->dispatch('openModal',
component: 'modals.confirm-action',
arguments: [
'heading' => __('sessions.logout_others'),
'body' => __('sessions.logout_others_body'),
'confirmLabel' => __('sessions.logout_others'),
'danger' => true,
'icon' => 'logout',
'notify' => __('sessions.logout_others_notify'),
'token' => ConfirmToken::issue(
'sessionsLogoutOthers',
[],
'session.logout_others',
Auth::user()?->email,
),
],
);
}
#[On('sessionsLogoutOthers')]
public function logoutOthers(string $confirmToken, SessionService $sessions): void
{
try {
ConfirmToken::consume($confirmToken, 'sessionsLogoutOthers');
} catch (InvalidConfirmToken) {
return; // forged / replayed / direct-bypass attempt — no-op
}
$sessions->logoutOtherDevices(Auth::user());
// List re-renders on the next round trip; no explicit refresh needed.
}
/**
* Open the R5 confirm for the destructive GLOBAL logout. On confirm every
* session is wiped and every remember_token rotated — including this
* operator's, so the apply handler redirects to login.
*/
public function confirmLogoutAll(): void
{
$this->dispatch('openModal',
component: 'modals.confirm-action',
arguments: [
'heading' => __('sessions.logout_all'),
'body' => __('sessions.logout_all_body'),
'confirmLabel' => __('sessions.logout_all'),
'danger' => true,
'icon' => 'power',
// Defer the toast: this session is about to be destroyed and the
// user redirected to login, so a toast would never be seen.
'notify' => '',
'token' => ConfirmToken::issue(
'sessionsLogoutAll',
[],
'session.logout_all',
Auth::user()?->email,
),
],
);
}
#[On('sessionsLogoutAll')]
public function logoutAll(string $confirmToken, SessionService $sessions)
{
try {
ConfirmToken::consume($confirmToken, 'sessionsLogoutAll');
} catch (InvalidConfirmToken) {
return; // forged / replayed / direct-bypass attempt — no-op
}
// Truncates all sessions + rotates every remember_token. This logs the
// operator out too, so push them to login (AuthenticateSession would
// otherwise bounce the very next request).
$sessions->logoutEveryone();
Auth::logout();
return $this->redirect(route('login'), navigate: true);
}
public function render()
{
return view('livewire.settings.sessions', [
'sessions' => app(SessionService::class)->forUser(Auth::user()),
]);
}
}