codex update

This commit is contained in:
2025-12-05 01:17:28 +01:00
parent 9dee06cdd6
commit 546146ed4e
14 changed files with 924 additions and 873 deletions

105
src/AuthService.php Normal file
View File

@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
// -----------------------------------------------------------------
// AuthService.php: Kapselt die gesamte Authentifizierungslogik.
// -----------------------------------------------------------------
class AuthService
{
private array $conf;
private PDO $pdo;
// Abhängigkeiten (Konfiguration und PDO) werden per Konstruktor übergeben
public function __construct(array $conf, PDO $pdo)
{
$this->conf = $conf;
$this->pdo = $pdo;
}
// --- Private Utility Methoden ---
private function fail(string $msg, $detail = null, int $code = 400): void
{
// Wir müssen hier direkt antworten, da wir das Fail-Verhalten des Kernels benötigen.
// Im ApiKernel werden wir die respond/fail-Methoden als public lassen,
// um sie hier injizieren zu können, oder wir lassen sie hier im Global Scope
// (WENN Sie die ursprünglichen globalen Funktionen respond/fail wieder zulassen).
// Für eine saubere Kapselung injizieren wir die Respond-Logik.
// HIER verwenden wir eine einfache JSON-Antwort, da die fail-Methode
// normalerweise den gesamten Kernel stoppt. Wir nutzen exit.
http_response_code($code);
echo json_encode(['ok'=>false,'error'=>$msg,'detail'=>$detail], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
exit;
}
private function verifyPassword(string $input, string $stored, array $authDbConf): bool
{
if (preg_match('~^\$2[aby]\$~', $stored) || strpos($stored, '$argon2') === 0) return password_verify($input, $stored);
$legacy = strtolower($authDbConf['legacy'] ?? '');
if ($legacy === 'md5') return hash_equals($stored, md5($input));
if ($legacy === 'sha1') return hash_equals($stored, sha1($input));
if (password_get_info($stored)['algo'] !== 0) return password_verify($input, $stored);
return hash_equals($stored, $input);
}
// --- Public Service Methoden ---
public function requireAuth(): array
{
if (empty($_SESSION['auth'])) $this->fail('Not authenticated', null, 401);
return $_SESSION['auth'];
}
public function logout(): bool
{
$_SESSION = [];
if (session_id() !== '') session_destroy();
return true;
}
public function login(array $in): array
{
$authDb = $this->conf['auth']['db'] ?? [];
$colUser = $authDb['col_user'] ?? 'email';
$colPass = $authDb['col_pass'] ?? 'password';
$colName = $authDb['col_name'] ?? 'name';
$colId = $authDb['col_id'] ?? 'id';
$colStatus = $authDb['col_status']?? null;
$activeValues = $authDb['active_values'] ?? ['active','1',1];
$table = $authDb['table'] ?? 'emailtemplate_users';
$identifier = trim((string)($in['username'] ?? $in['user'] ?? $in['email'] ?? $in['login'] ?? ''));
$password = (string)($in['password'] ?? $in['pass'] ?? $in['pwd'] ?? '');
if ($identifier === '' || $password === '') $this->fail('username/password required', null, 422);
$stmt = $this->pdo->prepare("SELECT * FROM `$table` WHERE `$colUser` = :u LIMIT 1");
$stmt->execute([':u'=>$identifier]);
$row = $stmt->fetch();
if (!$row) $this->fail('Invalid credentials', null, 401);
if ($colStatus && isset($row[$colStatus])) {
if (!in_array($row[$colStatus], $activeValues, true)) {
$this->fail('Account inactive', null, 403);
}
}
$stored = (string)($row[$colPass] ?? '');
if ($stored === '' || !$this->verifyPassword($password, $stored, $authDb)) {
$this->fail('Invalid credentials', null, 401);
}
$_SESSION['auth'] = [
'id' => $row[$colId] ?? null,
'name' => $row[$colName] ?? ($row[$colUser] ?? $identifier),
'email' => $row[$colUser] ?? $identifier,
'at' => time(),
];
$token = base64_encode(hash('sha256', ($_SESSION['auth']['id'] ?? $identifier).'|'.session_id(), true));
return ['user'=>$_SESSION['auth'], 'token'=>$token];
}
}