ycyc
This commit is contained in:
@@ -106,6 +106,78 @@ final class Auth
|
||||
return $userId;
|
||||
}
|
||||
|
||||
public function createResetCode(string $email): array
|
||||
{
|
||||
$pdo = $this->pdo();
|
||||
$email = strtolower(trim($email));
|
||||
|
||||
$stmt = $pdo->prepare('SELECT u.id, p.display_name FROM users u LEFT JOIN user_profiles p ON p.user_id = u.id WHERE u.email = :email LIMIT 1');
|
||||
$stmt->execute(['email' => $email]);
|
||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
if (!$row) {
|
||||
throw new \RuntimeException('E-Mail ist nicht registriert.');
|
||||
}
|
||||
|
||||
$userId = (int)$row['id'];
|
||||
$displayName = (string)($row['display_name'] ?? $email);
|
||||
$code = $this->generateCode(6);
|
||||
$hash = hash('sha256', $code);
|
||||
|
||||
$pdo->prepare('DELETE FROM user_tokens WHERE user_id = :uid AND type = :t')->execute(['uid' => $userId, 't' => 'reset']);
|
||||
$stmt = $pdo->prepare('INSERT INTO user_tokens (user_id, type, code, token_hash, expires_at, created_at) VALUES (:uid, :type, :code, :hash, DATE_ADD(NOW(), INTERVAL 2 HOUR), NOW())');
|
||||
$stmt->execute([
|
||||
'uid' => $userId,
|
||||
'type' => 'reset',
|
||||
'code' => $code,
|
||||
'hash' => $hash,
|
||||
]);
|
||||
|
||||
return ['user_id' => $userId, 'code' => $code, 'display_name' => $displayName];
|
||||
}
|
||||
|
||||
public function verifyResetCode(string $email, string $code): int
|
||||
{
|
||||
$pdo = $this->pdo();
|
||||
$email = strtolower(trim($email));
|
||||
$hash = hash('sha256', $code);
|
||||
|
||||
$stmt = $pdo->prepare('SELECT u.id, t.id AS tid, t.token_hash FROM users u JOIN user_tokens t ON t.user_id = u.id AND t.type = :type WHERE u.email = :email AND (t.used_at IS NULL) AND t.expires_at > NOW() ORDER BY t.expires_at DESC LIMIT 1');
|
||||
$stmt->execute(['type' => 'reset', 'email' => $email]);
|
||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
if (!$row || !hash_equals((string)$row['token_hash'], $hash)) {
|
||||
throw new \RuntimeException('Code ist ungültig oder abgelaufen.');
|
||||
}
|
||||
|
||||
$userId = (int)$row['id'];
|
||||
$tid = (int)$row['tid'];
|
||||
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
$pdo->prepare('UPDATE user_tokens SET used_at = NOW() WHERE id = :id')->execute(['id' => $tid]);
|
||||
$pdo->commit();
|
||||
} catch (\Throwable $e) {
|
||||
$pdo->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
|
||||
public function resetPassword(int $userId, string $password): void
|
||||
{
|
||||
$pdo = $this->pdo();
|
||||
if ($password === '' || strlen($password) < 8) {
|
||||
throw new \InvalidArgumentException('Passwort muss mindestens 8 Zeichen haben.');
|
||||
}
|
||||
$hash = password_hash($password, PASSWORD_ARGON2ID);
|
||||
$stmt = $pdo->prepare('UPDATE users SET password_hash = :pw, status = :status, updated_at = NOW() WHERE id = :id');
|
||||
$stmt->execute([
|
||||
'pw' => $hash,
|
||||
'status' => 'active',
|
||||
'id' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
private function generateCode(int $len = 6): string
|
||||
{
|
||||
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
||||
|
||||
Reference in New Issue
Block a user