mailwolt/app/Models/TwoFactorRecoveryCode.php

83 lines
2.0 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TwoFactorRecoveryCode extends Model
{
use HasFactory;
protected $table = 'two_factor_recovery_codes';
protected $fillable = [
'user_id',
'code_hash',
'used_at',
];
protected $casts = [
'used_at' => 'datetime',
];
// === Beziehungen ===
public function user()
{
return $this->belongsTo(User::class);
}
// === Logik ===
/**
* Prüft, ob der eingegebene Code gültig ist (noch nicht benutzt & hash-match)
*/
public static function verifyAndConsume(int $userId, string $inputCode): bool
{
$codes = self::where('user_id', $userId)
->whereNull('used_at')
->get();
foreach ($codes as $code) {
if (password_verify($inputCode, $code->code_hash)) {
$code->update(['used_at' => now()]);
return true;
}
}
return false;
}
/**
* Prüft, ob der Code für den Benutzer existiert (ohne ihn zu verbrauchen)
*/
public static function checkValid(int $userId, string $inputCode): bool
{
return self::where('user_id', $userId)
->whereNull('used_at')
->get()
->contains(fn($c) => password_verify($inputCode, $c->code_hash));
}
/**
* Generiert neue Recovery-Codes (löscht alte unbenutzte)
*/
public static function generateNewSet(int $userId, int $count = 10): array
{
self::where('user_id', $userId)->delete();
$plainCodes = [];
for ($i = 0; $i < $count; $i++) {
$plain = strtoupper(str()->random(10));
self::create([
'user_id' => $userId,
'code_hash' => password_hash($plain, PASSWORD_DEFAULT),
]);
$plainCodes[] = $plain;
}
return $plainCodes;
}
}