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; $colRole = $authDb['col_role'] ?? 'role'; $colCustomer = $authDb['customer_fk'] ?? 'customer_id'; $customerTable = $authDb['customer_table'] ?? 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); } $customerId = isset($row[$colCustomer]) ? (int)$row[$colCustomer] : null; $customerData = $customerId ? $this->fetchCustomerData($customerId, $customerTable, $authDb) : null; $_SESSION['auth'] = [ 'id' => $row[$colId] ?? null, 'name' => $row[$colName] ?? ($row[$colUser] ?? $identifier), 'email' => $row[$colUser] ?? $identifier, 'role' => $row[$colRole] ?? 'user', 'customer_id' => $customerId, 'customer' => $customerData, 'permissions' => [ 'owner' => ($row[$colRole] ?? '') === 'owner', ], 'at' => time(), ]; $token = base64_encode(hash('sha256', ($_SESSION['auth']['id'] ?? $identifier).'|'.session_id(), true)); return ['user'=>$_SESSION['auth'], 'token'=>$token]; } private function fetchCustomerData(?int $customerId, ?string $table, array $authDb): ?array { if (!$customerId || !$table) return null; $cols = $authDb['customer_cols'] ?? []; $select = ['`id`']; foreach ($cols as $alias => $column) { $select[] = sprintf('`%s` AS `%s`', $column, $alias); } $sql = sprintf('SELECT %s FROM `%s` WHERE `id` = :id LIMIT 1', implode(',', $select), $table); $stmt = $this->pdo->prepare($sql); $stmt->execute([':id' => $customerId]); $row = $stmt->fetch(); return $row ?: null; } }