Files
ai-stylegallery/app/Filament/Pages/Auth/Login.php

197 lines
6.0 KiB
PHP

<?php
namespace App\Filament\Pages\Auth;
use App\Models\User;
use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException;
use Filament\Auth\Http\Responses\Contracts\LoginResponse;
use Filament\Auth\Pages\Login as BaseLogin;
use Filament\Facades\Filament;
use Filament\Forms\Components\Hidden;
use Filament\Models\Contracts\FilamentUser;
use Filament\Schemas\Components\Component;
use Filament\Schemas\Components\View;
use Filament\Schemas\Schema;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Hash;
class Login extends BaseLogin
{
protected int $maxPinLength = 8;
public function form(Schema $schema): Schema
{
return $schema
->components([
Hidden::make('email')
->rules(fn (): array => $this->shouldShowPinLogin() ? ['required', 'email'] : [])
->visible(fn (): bool => $this->shouldShowPinLogin())
->dehydrated(fn (): bool => $this->shouldShowPinLogin())
->live(),
Hidden::make('pin')
->rules(fn (): array => $this->shouldShowPinLogin() ? [
'nullable',
'min:4',
"max:{$this->maxPinLength}",
'regex:/^\\d+$/',
] : [])
->visible(fn (): bool => $this->shouldShowPinLogin())
->dehydrated(fn (): bool => $this->shouldShowPinLogin())
->live(),
$this->getEmailFormComponent(),
$this->getPasswordFormComponent(),
$this->getRememberFormComponent(),
View::make('filament.pages.auth.kiosk-login')
->viewData([
'hasPinUsers' => $this->shouldShowPinLogin(),
'users' => $this->getKioskUsers(),
'maxPinLength' => $this->maxPinLength,
])
->columnSpanFull(),
]);
}
public function authenticate(): ?LoginResponse
{
try {
$this->rateLimit(5);
} catch (TooManyRequestsException $exception) {
$this->getRateLimitedNotification($exception)?->send();
return null;
}
$data = $this->form->getState();
if (blank($data['pin'] ?? null)) {
return parent::authenticate();
}
$authGuard = Filament::auth();
$credentials = [
'email' => $data['email'] ?? null,
'password' => '',
];
$user = User::query()
->where('email', $data['email'] ?? '')
->first();
$pin = (string) ($data['pin'] ?? '');
if (
(! $user)
|| blank($user->admin_pin_hash)
|| $pin === ''
|| (! ctype_digit($pin))
|| (strlen($pin) < 4 || strlen($pin) > $this->maxPinLength)
|| (! Hash::check($pin, $user->admin_pin_hash))
) {
$this->userUndertakingMultiFactorAuthentication = null;
$this->fireFailedEvent($authGuard, $user, $credentials);
$this->throwFailureValidationException();
}
if (
filled($this->userUndertakingMultiFactorAuthentication) &&
(decrypt($this->userUndertakingMultiFactorAuthentication) === $user->getAuthIdentifier())
) {
$this->multiFactorChallengeForm->validate();
} else {
foreach (Filament::getMultiFactorAuthenticationProviders() as $multiFactorAuthenticationProvider) {
if (! $multiFactorAuthenticationProvider->isEnabled($user)) {
continue;
}
$this->userUndertakingMultiFactorAuthentication = encrypt($user->getAuthIdentifier());
if ($multiFactorAuthenticationProvider instanceof \Filament\Auth\MultiFactor\Contracts\HasBeforeChallengeHook) {
$multiFactorAuthenticationProvider->beforeChallenge($user);
}
break;
}
if (filled($this->userUndertakingMultiFactorAuthentication)) {
$this->multiFactorChallengeForm->fill();
return null;
}
}
if ($user instanceof FilamentUser) {
if (! $user->canAccessPanel(Filament::getCurrentOrDefaultPanel())) {
$this->fireFailedEvent($authGuard, $user, $credentials);
$this->throwFailureValidationException();
}
}
$authGuard->login($user, $data['remember'] ?? true);
session()->regenerate();
return app(LoginResponse::class);
}
public function selectUser(int $userId): void
{
$user = $this->getKioskUsers()->firstWhere('id', $userId);
if (! $user) {
return;
}
$this->data['email'] = $user->email;
$this->data['pin'] = '';
}
public function appendPinDigit(int $digit): void
{
$pin = (string) ($this->data['pin'] ?? '');
if (strlen($pin) >= $this->maxPinLength) {
return;
}
$this->data['pin'] = $pin.$digit;
}
public function deletePinDigit(): void
{
$pin = (string) ($this->data['pin'] ?? '');
if ($pin === '') {
return;
}
$this->data['pin'] = substr($pin, 0, -1);
}
public function clearPin(): void
{
$this->data['pin'] = '';
}
/**
* @return \Illuminate\Support\Collection<int, User>
*/
protected function getKioskUsers(): Collection
{
return User::query()
->whereNotNull('admin_pin_hash')
->orderBy('name')
->get(['id', 'name', 'email', 'admin_pin_hash']);
}
protected function shouldShowPinLogin(): bool
{
return $this->getKioskUsers()->isNotEmpty();
}
protected function getPasswordFormComponent(): Component
{
return parent::getPasswordFormComponent()
->required(fn (): bool => blank($this->data['pin'] ?? null));
}
}