This commit is contained in:
2025-12-26 02:44:15 +01:00
parent 9fb863365c
commit 811d3df7a0
11 changed files with 589 additions and 75 deletions

View File

@@ -39,7 +39,7 @@ final class Auth
$stmt->execute([
'email' => $email,
'pw' => $hash,
'status' => 'active',
'status' => 'pending',
]);
$userId = (int)$pdo->lastInsertId();
@@ -59,7 +59,64 @@ final class Auth
}
}
public function login(string $email, string $password): int
public function createVerifyCode(int $userId, string $email): string
{
$pdo = $this->pdo();
$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' => 'verify']);
$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 48 HOUR), NOW())');
$stmt->execute([
'uid' => $userId,
'type' => 'verify',
'code' => $code,
'hash' => $hash,
]);
return $code;
}
public function verifyCode(string $email, string $code): int
{
$pdo = $this->pdo();
$email = strtolower(trim($email));
$hash = hash('sha256', $code);
$stmt = $pdo->prepare('SELECT u.id, u.status, 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' => 'verify', '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->prepare('UPDATE users SET status = :st, email_verified_at = NOW() WHERE id = :id')->execute(['st' => 'active', 'id' => $userId]);
$pdo->commit();
} catch (\Throwable $e) {
$pdo->rollBack();
throw $e;
}
return $userId;
}
private function generateCode(int $len = 6): string
{
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$out = '';
for ($i = 0; $i < $len; $i++) {
$out .= $chars[random_int(0, strlen($chars) - 1)];
}
return $out;
}
public function login(string $email, string $password): array
{
$pdo = $this->pdo();
$email = strtolower(trim($email));
@@ -71,18 +128,18 @@ final class Auth
if (!$row) {
throw new \RuntimeException('E-Mail oder Passwort ist falsch.');
}
if ($row['status'] !== 'active') {
throw new \RuntimeException('Account ist nicht aktiv.');
}
if (!password_verify($password, (string)$row['password_hash'])) {
throw new \RuntimeException('E-Mail oder Passwort ist falsch.');
}
$userId = (int)$row['id'];
$status = (string)$row['status'];
$upd = $pdo->prepare('UPDATE users SET last_login_at = NOW() WHERE id = :id');
$upd->execute(['id' => $userId]);
if ($status === 'active') {
$upd = $pdo->prepare('UPDATE users SET last_login_at = NOW() WHERE id = :id');
$upd->execute(['id' => $userId]);
}
return $userId;
return ['id' => $userId, 'status' => $status];
}
}