65 lines
2.1 KiB
PHP
65 lines
2.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Player;
|
|
|
|
use App\Models\Player;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
final class PlayerPasswordService
|
|
{
|
|
public function change(Player $player, string $currentPassword, string $newPassword): Player
|
|
{
|
|
return DB::transaction(function () use ($player, $currentPassword, $newPassword): Player {
|
|
$locked = Player::query()->lockForUpdate()->findOrFail($player->id);
|
|
$this->assertPasswordManagedLocally($locked);
|
|
|
|
if (! is_string($locked->password_hash) || ! Hash::check($currentPassword, $locked->password_hash)) {
|
|
throw ValidationException::withMessages([
|
|
'current_password' => ['current_password_invalid'],
|
|
]);
|
|
}
|
|
|
|
if (Hash::check($newPassword, $locked->password_hash)) {
|
|
throw ValidationException::withMessages([
|
|
'password' => ['new_password_must_differ'],
|
|
]);
|
|
}
|
|
|
|
return $this->persist($locked, $newPassword);
|
|
});
|
|
}
|
|
|
|
public function reset(Player $player, string $newPassword): Player
|
|
{
|
|
return DB::transaction(function () use ($player, $newPassword): Player {
|
|
$locked = Player::query()->lockForUpdate()->findOrFail($player->id);
|
|
$this->assertPasswordManagedLocally($locked);
|
|
|
|
return $this->persist($locked, $newPassword);
|
|
});
|
|
}
|
|
|
|
private function assertPasswordManagedLocally(Player $player): void
|
|
{
|
|
if (! $player->isLotteryNative()) {
|
|
throw ValidationException::withMessages([
|
|
'password' => ['native_password_unavailable'],
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function persist(Player $player, string $newPassword): Player
|
|
{
|
|
$player->forceFill([
|
|
'password_hash' => Hash::make($newPassword),
|
|
'native_token_version' => (int) $player->native_token_version + 1,
|
|
'login_failed_count' => 0,
|
|
'login_locked_until' => null,
|
|
])->save();
|
|
|
|
return $player->refresh();
|
|
}
|
|
}
|