77 lines
2.6 KiB
PHP
77 lines
2.6 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Auth;
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Facades\RateLimiter;
|
|
use Illuminate\Validation\Rules\Password;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Component;
|
|
|
|
#[Layout('layouts.auth')]
|
|
class PasswordChange extends Component
|
|
{
|
|
public string $current = '';
|
|
|
|
public string $password = '';
|
|
|
|
public string $password_confirmation = '';
|
|
|
|
public function update()
|
|
{
|
|
// Throttle the current-password re-auth so a hijacked session can't brute-force the
|
|
// password. Keyed on the authenticated user id (never IP) and auto-expiring, so it can
|
|
// only slow the user's own session briefly — never a cross-user or control-plane lockout.
|
|
$key = 'reauth:'.Auth::id();
|
|
if (RateLimiter::tooManyAttempts($key, 5)) {
|
|
throw ValidationException::withMessages([
|
|
'current' => __('auth.too_many_attempts', ['seconds' => RateLimiter::availableIn($key)]),
|
|
]);
|
|
}
|
|
|
|
try {
|
|
$this->validate([
|
|
'current' => ['required', 'current_password'],
|
|
'password' => ['required', 'confirmed', Password::min(6)->mixedCase()->numbers()],
|
|
], attributes: [
|
|
'current' => __('auth.attr_current_password'),
|
|
'password' => __('auth.attr_new_password'),
|
|
]);
|
|
} catch (ValidationException $e) {
|
|
if (array_key_exists('current', $e->errors())) {
|
|
RateLimiter::hit($key, 60);
|
|
}
|
|
throw $e;
|
|
}
|
|
|
|
RateLimiter::clear($key);
|
|
|
|
Auth::user()->forceFill([
|
|
'password' => Hash::make($this->password),
|
|
'must_change_password' => false,
|
|
])->save();
|
|
|
|
// 2FA is optional now — go straight to the panel; 2FA is offered in Settings.
|
|
return $this->redirect(route('dashboard'), navigate: true);
|
|
}
|
|
|
|
/**
|
|
* Keep the current password for now — rotation is not forced. Remember the choice for this session
|
|
* so the prompt does not reappear; `must_change_password` stays true, so the persistent default-
|
|
* password banner keeps warning until the password is actually changed.
|
|
*/
|
|
public function skip()
|
|
{
|
|
session()->put('onboarding.password_skipped', true);
|
|
|
|
return $this->redirect(route('dashboard'), navigate: true);
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.auth.password-change')->title(__('auth.title_password_change'));
|
|
}
|
|
}
|