Files
My-KOPKB/be/Modules/Auth/Services/PasswordResetOtpService.php

100 lines
2.6 KiB
PHP

<?php
namespace Modules\Auth\Services;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use Modules\Auth\Actions\Fortify\PasswordValidationRules;
use Modules\Auth\Emails\PasswordResetOtpEmail;
use Modules\Auth\Entities\PasswordResetOtp;
use Modules\Auth\Entities\User;
class PasswordResetOtpService
{
use PasswordValidationRules;
public function send(User $user): void
{
$otp = $this->generateOtp();
PasswordResetOtp::query()
->where('user_id', $user->id)
->delete();
PasswordResetOtp::create([
'user_id' => $user->id,
'code' => Hash::make($otp),
'expires_at' => now()->addMinutes($this->expiryMinutes()),
'attempts' => 0,
]);
$user->notify(new PasswordResetOtpEmail($otp));
}
public function reset(User $user, string $otp, array $input): void
{
validator($input, [
'password' => $this->passwordRules(),
])->validate();
$record = PasswordResetOtp::query()
->where('user_id', $user->id)
->latest()
->first();
if (! $record) {
throw ValidationException::withMessages([
'otp' => ['Kod OTP tidak dijumpai. Sila minta kod baharu.'],
]);
}
if ($record->isExpired()) {
$record->delete();
throw ValidationException::withMessages([
'otp' => ['Kod OTP telah tamat tempoh. Sila minta kod baharu.'],
]);
}
if ($record->hasExceededMaxAttempts()) {
$record->delete();
throw ValidationException::withMessages([
'otp' => ['Terlalu banyak percubaan. Sila minta kod baharu.'],
]);
}
if (! Hash::check($otp, $record->code)) {
$record->increment('attempts');
if ($record->fresh()->hasExceededMaxAttempts()) {
$record->delete();
}
throw ValidationException::withMessages([
'otp' => ['Kod OTP tidak sah.'],
]);
}
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
$user->tokens()->delete();
PasswordResetOtp::query()
->where('user_id', $user->id)
->delete();
}
protected function generateOtp(): string
{
return str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
}
protected function expiryMinutes(): int
{
return (int) config('auth.password_reset.expiry_minutes', 10);
}
}