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]; } }