68 lines
1.9 KiB
PHP
68 lines
1.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Auth;
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
|
|
class RegistrationVerificationTokenService
|
|
{
|
|
public function createForUser(int $userId): string
|
|
{
|
|
DB::table('user_verification_tokens')->where('user_id', $userId)->delete();
|
|
|
|
$rawToken = Str::random(64);
|
|
$tokenHash = $this->hashToken($rawToken);
|
|
|
|
// Support environments where the migration hasn't renamed the column yet
|
|
$column = \Illuminate\Support\Facades\Schema::hasColumn('user_verification_tokens', 'token_hash') ? 'token_hash' : 'token';
|
|
|
|
DB::table('user_verification_tokens')->insert([
|
|
'user_id' => $userId,
|
|
$column => $tokenHash,
|
|
'expires_at' => now()->addHours($this->ttlHours()),
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
return $rawToken;
|
|
}
|
|
|
|
public function findValidRecord(string $rawToken): ?object
|
|
{
|
|
$tokenHash = $this->hashToken($rawToken);
|
|
|
|
$column = \Illuminate\Support\Facades\Schema::hasColumn('user_verification_tokens', 'token_hash') ? 'token_hash' : 'token';
|
|
|
|
$record = DB::table('user_verification_tokens')
|
|
->where($column, $tokenHash)
|
|
->first();
|
|
|
|
if (! $record) {
|
|
return null;
|
|
}
|
|
|
|
if (! hash_equals((string) ($record->{$column} ?? ''), $tokenHash)) {
|
|
return null;
|
|
}
|
|
|
|
if (now()->greaterThan($record->expires_at)) {
|
|
DB::table('user_verification_tokens')->where('id', $record->id)->delete();
|
|
|
|
return null;
|
|
}
|
|
|
|
return $record;
|
|
}
|
|
|
|
private function ttlHours(): int
|
|
{
|
|
return max(1, (int) config('registration.verify_token_ttl_hours', 24));
|
|
}
|
|
|
|
private function hashToken(string $rawToken): string
|
|
{
|
|
return hash('sha256', $rawToken);
|
|
}
|
|
}
|