conn = $conn; } /** * Generate a new API key * * @param string $keyName Descriptive name for the key * @param int $createdBy User ID who created the key * @param int|null $expiresInDays Number of days until expiration (null for no expiration) * @return array Array with 'success', 'api_key' (plaintext), 'key_prefix', 'error' */ public function createKey($keyName, $createdBy, $expiresInDays = null) { // Generate random API key (32 bytes = 64 hex characters) $apiKey = bin2hex(random_bytes(32)); // Create key prefix (first 8 characters) for identification $keyPrefix = substr($apiKey, 0, 8); // Hash the API key for storage $keyHash = hash('sha256', $apiKey); // Calculate expiration date if specified $expiresAt = null; if ($expiresInDays !== null) { $expiresAt = date('Y-m-d H:i:s', strtotime("+$expiresInDays days")); } // Insert API key into database $stmt = $this->conn->prepare( "INSERT INTO api_keys (key_name, key_hash, key_prefix, created_by, expires_at) VALUES (?, ?, ?, ?, ?)" ); $stmt->bind_param("sssis", $keyName, $keyHash, $keyPrefix, $createdBy, $expiresAt); if ($stmt->execute()) { $keyId = $this->conn->insert_id; $stmt->close(); return [ 'success' => true, 'api_key' => $apiKey, // Return plaintext key ONCE 'key_prefix' => $keyPrefix, 'key_id' => $keyId, 'expires_at' => $expiresAt ]; } else { $error = $this->conn->error; $stmt->close(); return [ 'success' => false, 'error' => $error ]; } } /** * Validate an API key * * @param string $apiKey Plaintext API key to validate * @return array|null API key record if valid, null if invalid */ public function validateKey($apiKey) { if (empty($apiKey)) { return null; } // Hash the provided key $keyHash = hash('sha256', $apiKey); // Query for matching key $stmt = $this->conn->prepare( "SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1" ); $stmt->bind_param("s", $keyHash); $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows === 0) { $stmt->close(); return null; } $keyData = $result->fetch_assoc(); $stmt->close(); // Check expiration if ($keyData['expires_at'] !== null) { $expiresAt = strtotime($keyData['expires_at']); if ($expiresAt < time()) { return null; // Key has expired } } // Update last_used timestamp $this->updateLastUsed($keyData['api_key_id']); return $keyData; } /** * Update last_used timestamp for an API key * * @param int $keyId API key ID * @return bool Success status */ private function updateLastUsed($keyId) { $stmt = $this->conn->prepare("UPDATE api_keys SET last_used = NOW() WHERE api_key_id = ?"); $stmt->bind_param("i", $keyId); $success = $stmt->execute(); $stmt->close(); return $success; } /** * Revoke an API key (set is_active to false) * * @param int $keyId API key ID * @return bool Success status */ public function revokeKey($keyId) { $stmt = $this->conn->prepare("UPDATE api_keys SET is_active = 0 WHERE api_key_id = ?"); $stmt->bind_param("i", $keyId); $success = $stmt->execute(); $stmt->close(); return $success; } /** * Delete an API key permanently * * @param int $keyId API key ID * @return bool Success status */ public function deleteKey($keyId) { $stmt = $this->conn->prepare("DELETE FROM api_keys WHERE api_key_id = ?"); $stmt->bind_param("i", $keyId); $success = $stmt->execute(); $stmt->close(); return $success; } /** * Get all API keys (for admin panel) * * @return array Array of API key records (without hashes) */ public function getAllKeys() { $stmt = $this->conn->prepare( "SELECT ak.*, u.username, u.display_name FROM api_keys ak LEFT JOIN users u ON ak.created_by = u.user_id ORDER BY ak.created_at DESC" ); $stmt->execute(); $result = $stmt->get_result(); $keys = []; while ($row = $result->fetch_assoc()) { // Remove key_hash from response for security unset($row['key_hash']); $keys[] = $row; } $stmt->close(); return $keys; } /** * Get API key by ID * * @param int $keyId API key ID * @return array|null API key record (without hash) or null if not found */ public function getKeyById($keyId) { $stmt = $this->conn->prepare( "SELECT ak.*, u.username, u.display_name FROM api_keys ak LEFT JOIN users u ON ak.created_by = u.user_id WHERE ak.api_key_id = ?" ); $stmt->bind_param("i", $keyId); $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows > 0) { $key = $result->fetch_assoc(); // Remove key_hash from response for security unset($key['key_hash']); $stmt->close(); return $key; } $stmt->close(); return null; } /** * Get keys created by a specific user * * @param int $userId User ID * @return array Array of API key records */ public function getKeysByUser($userId) { $stmt = $this->conn->prepare( "SELECT * FROM api_keys WHERE created_by = ? ORDER BY created_at DESC" ); $stmt->bind_param("i", $userId); $stmt->execute(); $result = $stmt->get_result(); $keys = []; while ($row = $result->fetch_assoc()) { // Remove key_hash from response for security unset($row['key_hash']); $keys[] = $row; } $stmt->close(); return $keys; } }