#include "user_manager.h" #include "jwt_auth.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // Define static permission constants const std::string UserManager::Permissions::READ = "read"; const std::string UserManager::Permissions::GENERATE = "generate"; const std::string UserManager::Permissions::QUEUE_MANAGE = "queue_manage"; const std::string UserManager::Permissions::MODEL_MANAGE = "model_manage"; const std::string UserManager::Permissions::USER_MANAGE = "user_manage"; const std::string UserManager::Permissions::ADMIN = "admin"; UserManager::UserManager(const std::string& dataDir, AuthMethod authMethod) : m_dataDir(dataDir) , m_authMethod(authMethod) , m_pamAuthEnabled(false) { #ifdef ENABLE_PAM_AUTH m_pamAuth = std::make_unique(); #endif } UserManager::~UserManager() { shutdown(); } bool UserManager::initialize() { try { // Create data directory if it doesn't exist std::filesystem::create_directories(m_dataDir); // Load existing user data if (!loadUserData()) { // Create default admin user if no users exist if (m_users.empty()) { auto [success, adminId] = createUser("admin", "admin123", "admin@localhost", UserRole::ADMIN, "system"); if (!success) { return false; } } } // Load existing API key data loadApiKeyData(); return true; } catch (const std::exception& e) { return false; } } void UserManager::shutdown() { // Save data before shutdown saveUserData(); saveApiKeyData(); } AuthResult UserManager::authenticateUser(const std::string& username, const std::string& password) { AuthResult result; result.success = false; try { // Find user by username auto it = m_users.find(username); if (it == m_users.end()) { result.errorMessage = "User not found"; result.errorCode = "USER_NOT_FOUND"; return result; } const UserInfo& user = it->second; // Check if user is active if (!user.active) { result.errorMessage = "User account is disabled"; result.errorCode = "ACCOUNT_DISABLED"; return result; } // Verify password if (!verifyPassword(password, user.passwordHash)) { result.errorMessage = "Invalid password"; result.errorCode = "INVALID_PASSWORD"; return result; } // Authentication successful result.success = true; result.userId = user.id; result.username = user.username; result.role = user.role; result.permissions = user.permissions; // Update last login time m_users[username].lastLoginAt = getCurrentTimestamp(); saveUserData(); } catch (const std::exception& e) { result.errorMessage = "Authentication failed: " + std::string(e.what()); result.errorCode = "AUTH_ERROR"; } return result; } AuthResult UserManager::authenticateUnix(const std::string& username, const std::string& password) { AuthResult result; result.success = false; // Check if Unix authentication is the configured method if (m_authMethod != AuthMethod::UNIX) { result.errorMessage = "Unix authentication is not enabled"; result.errorCode = "UNIX_AUTH_DISABLED"; return result; } try { // If PAM is enabled, delegate to PAM authentication if (m_pamAuthEnabled) { return authenticatePam(username, password); } // Traditional Unix auth without PAM - just check if user exists // This is a fallback for when PAM is not available struct passwd* pw = getpwnam(username.c_str()); if (!pw) { result.errorMessage = "Unix user not found"; result.errorCode = "UNIX_USER_NOT_FOUND"; return result; } // Check if user exists in our system or create guest user UserInfo user; auto it = m_users.find(username); if (it != m_users.end()) { user = it->second; } else { // Create guest user for Unix authentication user.id = generateUserId(); user.username = username; user.email = username + "@localhost"; user.role = roleToString(UserRole::USER); user.permissions = getDefaultPermissions(UserRole::USER); user.active = true; user.createdAt = getCurrentTimestamp(); user.createdBy = "system"; m_users[username] = user; saveUserData(); } // Authentication successful result.success = true; result.userId = user.id; result.username = user.username; result.role = user.role; result.permissions = user.permissions; } catch (const std::exception& e) { result.errorMessage = "Unix authentication failed: " + std::string(e.what()); result.errorCode = "UNIX_AUTH_ERROR"; } return result; } AuthResult UserManager::authenticatePam(const std::string& username, const std::string& password) { AuthResult result; result.success = false; // Check if PAM authentication is the configured method if (m_authMethod != AuthMethod::PAM) { result.errorMessage = "PAM authentication is not enabled"; result.errorCode = "PAM_AUTH_DISABLED"; return result; } #ifdef ENABLE_PAM_AUTH if (!m_pamAuth || !m_pamAuth->isAvailable()) { result.errorMessage = "PAM authentication not available"; result.errorCode = "PAM_AUTH_UNAVAILABLE"; return result; } try { // Authenticate with PAM PamAuthResult pamResult = m_pamAuth->authenticate(username, password); if (!pamResult.success) { result.errorMessage = pamResult.errorMessage; result.errorCode = pamResult.errorCode; return result; } // Check if user exists in our system or create guest user UserInfo user; auto it = m_users.find(username); if (it != m_users.end()) { user = it->second; } else { // Create guest user for PAM authentication user.id = generateUserId(); user.username = username; user.email = username + "@localhost"; user.role = roleToString(UserRole::USER); user.permissions = getDefaultPermissions(UserRole::USER); user.active = true; user.createdAt = getCurrentTimestamp(); user.createdBy = "system"; m_users[username] = user; saveUserData(); } // Authentication successful result.success = true; result.userId = user.id; result.username = user.username; result.role = user.role; result.permissions = user.permissions; } catch (const std::exception& e) { result.errorMessage = "PAM authentication failed: " + std::string(e.what()); result.errorCode = "PAM_AUTH_ERROR"; } #else result.errorMessage = "PAM authentication not available (compiled without PAM support)"; result.errorCode = "PAM_NOT_AVAILABLE"; #endif return result; } AuthResult UserManager::authenticateApiKey(const std::string& apiKey) { AuthResult result; result.success = false; try { // Hash the API key to compare with stored hashes std::string keyHash = hashApiKey(apiKey); auto it = m_apiKeyMap.find(keyHash); if (it == m_apiKeyMap.end()) { result.errorMessage = "Invalid API key"; result.errorCode = "INVALID_API_KEY"; return result; } const std::string& keyId = it->second; const ApiKeyInfo& keyInfo = m_apiKeys[keyId]; // Check if key is active if (!keyInfo.active) { result.errorMessage = "API key is disabled"; result.errorCode = "API_KEY_DISABLED"; return result; } // Check expiration if (keyInfo.expiresAt > 0 && getCurrentTimestamp() >= keyInfo.expiresAt) { result.errorMessage = "API key has expired"; result.errorCode = "API_KEY_EXPIRED"; return result; } // Get user information auto userIt = m_users.find(keyInfo.userId); if (userIt == m_users.end()) { result.errorMessage = "API key owner not found"; result.errorCode = "USER_NOT_FOUND"; return result; } const UserInfo& user = userIt->second; if (!user.active) { result.errorMessage = "API key owner account is disabled"; result.errorCode = "ACCOUNT_DISABLED"; return result; } // Authentication successful result.success = true; result.userId = user.id; result.username = user.username; result.role = user.role; result.permissions = keyInfo.permissions.empty() ? user.permissions : keyInfo.permissions; // Update last used timestamp m_apiKeys[keyId].lastUsedAt = getCurrentTimestamp(); saveApiKeyData(); } catch (const std::exception& e) { result.errorMessage = "API key authentication failed: " + std::string(e.what()); result.errorCode = "API_KEY_AUTH_ERROR"; } return result; } std::pair UserManager::createUser(const std::string& username, const std::string& password, const std::string& email, UserRole role, const std::string& createdBy) { try { // Validate inputs if (!validateUsername(username)) { return {false, "Invalid username format"}; } if (!validatePassword(password)) { return {false, "Password does not meet requirements"}; } if (!validateEmail(email)) { return {false, "Invalid email format"}; } // Check if user already exists if (m_users.find(username) != m_users.end()) { return {false, "User already exists"}; } // Create user UserInfo user; user.id = generateUserId(); user.username = username; user.email = email; user.passwordHash = hashPassword(password); user.role = roleToString(role); user.permissions = getDefaultPermissions(role); user.active = true; user.createdAt = getCurrentTimestamp(); user.passwordChangedAt = getCurrentTimestamp(); user.createdBy = createdBy; m_users[username] = user; saveUserData(); return {true, user.id}; } catch (const std::exception& e) { return {false, "Failed to create user: " + std::string(e.what())}; } } std::pair UserManager::updateUser(const std::string& userId, const std::map& updates) { try { // Find user by ID std::string username; for (const auto& pair : m_users) { if (pair.second.id == userId) { username = pair.first; break; } } if (username.empty()) { return {false, "User not found"}; } UserInfo& user = m_users[username]; // Update allowed fields for (const auto& update : updates) { const std::string& field = update.first; const std::string& value = update.second; if (field == "email") { if (!validateEmail(value)) { return {false, "Invalid email format"}; } user.email = value; } else if (field == "role") { user.role = value; user.permissions = getDefaultPermissions(stringToRole(value)); } else if (field == "active") { user.active = (value == "true" || value == "1"); } } saveUserData(); return {true, "User updated successfully"}; } catch (const std::exception& e) { return {false, "Failed to update user: " + std::string(e.what())}; } } std::pair UserManager::deleteUser(const std::string& userId, const std::string& requestingUserId) { try { // Find user by ID std::string username; for (const auto& pair : m_users) { if (pair.second.id == userId) { username = pair.first; break; } } if (username.empty()) { return {false, "User not found"}; } // Check permissions if (!canManageUser(requestingUserId, userId)) { return {false, "Insufficient permissions to delete user"}; } // Delete user's API keys auto it = m_apiKeys.begin(); while (it != m_apiKeys.end()) { if (it->second.userId == userId) { m_apiKeyMap.erase(it->second.keyHash); it = m_apiKeys.erase(it); } else { ++it; } } // Delete user m_users.erase(username); saveUserData(); saveApiKeyData(); return {true, "User deleted successfully"}; } catch (const std::exception& e) { return {false, "Failed to delete user: " + std::string(e.what())}; } } std::pair UserManager::changePassword(const std::string& userId, const std::string& oldPassword, const std::string& newPassword, const std::string& requestingUserId) { try { // Find user by ID std::string username; for (const auto& pair : m_users) { if (pair.second.id == userId) { username = pair.first; break; } } if (username.empty()) { return {false, "User not found"}; } UserInfo& user = m_users[username]; // Check permissions (admin can change without old password) if (requestingUserId != userId) { if (!canManageUser(requestingUserId, userId)) { return {false, "Insufficient permissions to change password"}; } } else { // User changing own password - verify old password if (!verifyPassword(oldPassword, user.passwordHash)) { return {false, "Current password is incorrect"}; } } // Validate new password if (!validatePassword(newPassword)) { return {false, "New password does not meet requirements"}; } // Update password user.passwordHash = hashPassword(newPassword); user.passwordChangedAt = getCurrentTimestamp(); saveUserData(); return {true, "Password changed successfully"}; } catch (const std::exception& e) { return {false, "Failed to change password: " + std::string(e.what())}; } } UserInfo UserManager::getUserInfo(const std::string& userId) { for (const auto& pair : m_users) { if (pair.second.id == userId) { return pair.second; } } return UserInfo{}; } UserInfo UserManager::getUserInfoByUsername(const std::string& username) { auto it = m_users.find(username); if (it != m_users.end()) { return it->second; } return UserInfo{}; } std::vector UserManager::listUsers(const std::string& requestingUserId) { std::vector users; // Check if requester is admin UserInfo requester = getUserInfo(requestingUserId); bool isAdmin = (requester.role == roleToString(UserRole::ADMIN)); for (const auto& pair : m_users) { const UserInfo& user = pair.second; // Non-admins can only see themselves if (!isAdmin && user.id != requestingUserId) { continue; } // Don't include sensitive information for non-admins UserInfo userInfo = user; if (!isAdmin) { userInfo.passwordHash = ""; userInfo.apiKeys.clear(); } users.push_back(userInfo); } return users; } std::pair UserManager::createApiKey(const std::string& userId, const std::string& name, const std::vector& permissions, int64_t expiresAt, const std::string& createdBy) { try { // Check if user exists bool userExists = false; for (const auto& pair : m_users) { if (pair.second.id == userId) { userExists = true; break; } } if (!userExists) { return {false, "User not found"}; } // Generate API key std::string apiKey = JWTAuth::generateApiKey(32); std::string keyId = generateKeyId(); std::string keyHash = hashApiKey(apiKey); // Create API key info ApiKeyInfo keyInfo; keyInfo.keyId = keyId; keyInfo.keyHash = keyHash; keyInfo.name = name; keyInfo.userId = userId; keyInfo.permissions = permissions; keyInfo.active = true; keyInfo.createdAt = getCurrentTimestamp(); keyInfo.lastUsedAt = 0; keyInfo.expiresAt = expiresAt; keyInfo.createdBy = createdBy; m_apiKeys[keyId] = keyInfo; m_apiKeyMap[keyHash] = keyId; saveApiKeyData(); return {true, apiKey}; } catch (const std::exception& e) { return {false, "Failed to create API key: " + std::string(e.what())}; } } std::pair UserManager::revokeApiKey(const std::string& keyId, const std::string& requestingUserId) { try { auto it = m_apiKeys.find(keyId); if (it == m_apiKeys.end()) { return {false, "API key not found"}; } const ApiKeyInfo& keyInfo = it->second; // Check permissions if (keyInfo.userId != requestingUserId) { if (!canManageUser(requestingUserId, keyInfo.userId)) { return {false, "Insufficient permissions to revoke API key"}; } } // Remove API key m_apiKeyMap.erase(keyInfo.keyHash); m_apiKeys.erase(it); saveApiKeyData(); return {true, "API key revoked successfully"}; } catch (const std::exception& e) { return {false, "Failed to revoke API key: " + std::string(e.what())}; } } std::vector UserManager::listApiKeys(const std::string& userId, const std::string& requestingUserId) { std::vector apiKeys; // Check if requester is admin or owner UserInfo requester = getUserInfo(requestingUserId); bool isAdmin = (requester.role == roleToString(UserRole::ADMIN)); bool isOwner = (requestingUserId == userId); for (const auto& pair : m_apiKeys) { const ApiKeyInfo& keyInfo = pair.second; // Filter by user ID if specified if (!userId.empty() && keyInfo.userId != userId) { continue; } // Check permissions if (!isAdmin && keyInfo.userId != requestingUserId) { continue; } // Don't include hash for non-owners ApiKeyInfo keyInfoCopy = keyInfo; if (!isOwner && !isAdmin) { keyInfoCopy.keyHash = ""; } apiKeys.push_back(keyInfoCopy); } return apiKeys; } ApiKeyInfo UserManager::getApiKeyInfo(const std::string& keyId, const std::string& requestingUserId) { auto it = m_apiKeys.find(keyId); if (it == m_apiKeys.end()) { return ApiKeyInfo{}; } const ApiKeyInfo& keyInfo = it->second; // Check permissions UserInfo requester = getUserInfo(requestingUserId); bool isAdmin = (requester.role == roleToString(UserRole::ADMIN)); bool isOwner = (keyInfo.userId == requestingUserId); if (!isAdmin && !isOwner) { return ApiKeyInfo{}; } // Don't include hash for non-owners ApiKeyInfo keyInfoCopy = keyInfo; if (!isOwner) { keyInfoCopy.keyHash = ""; } return keyInfoCopy; } void UserManager::updateApiKeyLastUsed(const std::string& keyId) { auto it = m_apiKeys.find(keyId); if (it != m_apiKeys.end()) { it->second.lastUsedAt = getCurrentTimestamp(); saveApiKeyData(); } } bool UserManager::hasPermission(const std::string& userId, const std::string& permission) { UserInfo user = getUserInfo(userId); if (user.id.empty()) { return false; } return JWTAuth::hasPermission(user.permissions, permission); } bool UserManager::hasAnyPermission(const std::string& userId, const std::vector& permissions) { UserInfo user = getUserInfo(userId); if (user.id.empty()) { return false; } return JWTAuth::hasAnyPermission(user.permissions, permissions); } std::string UserManager::roleToString(UserRole role) { switch (role) { case UserRole::GUEST: return "guest"; case UserRole::USER: return "user"; case UserRole::ADMIN: return "admin"; case UserRole::SERVICE: return "service"; default: return "unknown"; } } UserManager::UserRole UserManager::stringToRole(const std::string& roleStr) { if (roleStr == "guest") return UserRole::GUEST; if (roleStr == "user") return UserRole::USER; if (roleStr == "admin") return UserRole::ADMIN; if (roleStr == "service") return UserRole::SERVICE; return UserRole::USER; // Default } std::vector UserManager::getDefaultPermissions(UserRole role) { switch (role) { case UserRole::GUEST: return {Permissions::READ}; case UserRole::USER: return {Permissions::READ, Permissions::GENERATE}; case UserRole::ADMIN: return {Permissions::READ, Permissions::GENERATE, Permissions::QUEUE_MANAGE, Permissions::MODEL_MANAGE, Permissions::USER_MANAGE, Permissions::ADMIN}; case UserRole::SERVICE: return {Permissions::READ, Permissions::GENERATE, Permissions::QUEUE_MANAGE}; default: return {}; } } void UserManager::setAuthMethod(AuthMethod method) { m_authMethod = method; } UserManager::AuthMethod UserManager::getAuthMethod() const { return m_authMethod; } void UserManager::setPamAuthEnabled(bool enable) { m_pamAuthEnabled = enable; #ifdef ENABLE_PAM_AUTH if (enable && m_pamAuth && !m_pamAuth->isAvailable()) { if (!m_pamAuth->initialize()) { m_pamAuthEnabled = false; } } #endif } bool UserManager::isPamAuthEnabled() const { return m_pamAuthEnabled; } std::map UserManager::getStatistics() { std::map stats; stats["total_users"] = m_users.size(); stats["active_users"] = 0; stats["admin_users"] = 0; stats["total_api_keys"] = m_apiKeys.size(); stats["active_api_keys"] = 0; stats["expired_api_keys"] = 0; int64_t currentTime = getCurrentTimestamp(); for (const auto& pair : m_users) { const UserInfo& user = pair.second; if (user.active) { stats["active_users"]++; } if (user.role == roleToString(UserRole::ADMIN)) { stats["admin_users"]++; } } for (const auto& pair : m_apiKeys) { const ApiKeyInfo& keyInfo = pair.second; if (keyInfo.active) { stats["active_api_keys"]++; } if (keyInfo.expiresAt > 0 && currentTime >= keyInfo.expiresAt) { stats["expired_api_keys"]++; } } return stats; } std::string UserManager::hashPassword(const std::string& password) { // Simple SHA256 hash for now (in production, use proper password hashing like bcrypt/argon2) unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256((unsigned char*)password.c_str(), password.length(), hash); std::stringstream ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i]; } return "sha256:" + ss.str(); } bool UserManager::verifyPassword(const std::string& password, const std::string& storedHash) { // Simple SHA256 verification (in production, use proper password hashing) if (storedHash.substr(0, 7) != "sha256:") { return false; } unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256((unsigned char*)password.c_str(), password.length(), hash); std::stringstream ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i]; } return "sha256:" + ss.str() == storedHash; } std::string UserManager::hashApiKey(const std::string& apiKey) { // Use SHA256 for API key hashing unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256((unsigned char*)apiKey.c_str(), apiKey.length(), hash); std::stringstream ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i]; } return ss.str(); } std::string UserManager::generateUserId() { return "user_" + std::to_string(getCurrentTimestamp()) + "_" + std::to_string(rand() % 10000); } std::string UserManager::generateKeyId() { return "key_" + std::to_string(getCurrentTimestamp()) + "_" + std::to_string(rand() % 10000); } bool UserManager::saveUserData() { try { nlohmann::json usersData = nlohmann::json::object(); for (const auto& pair : m_users) { const UserInfo& user = pair.second; nlohmann::json userData = { {"id", user.id}, {"username", user.username}, {"email", user.email}, {"password_hash", user.passwordHash}, {"role", user.role}, {"permissions", user.permissions}, {"api_keys", user.apiKeys}, {"active", user.active}, {"created_at", user.createdAt}, {"last_login_at", user.lastLoginAt}, {"password_changed_at", user.passwordChangedAt}, {"created_by", user.createdBy} }; usersData[user.username] = userData; } std::string filename = m_dataDir + "/users.json"; std::ofstream file(filename); if (!file.is_open()) { return false; } file << usersData.dump(2); file.close(); return true; } catch (const std::exception& e) { return false; } } bool UserManager::loadUserData() { try { std::string filename = m_dataDir + "/users.json"; std::ifstream file(filename); if (!file.is_open()) { return false; // File doesn't exist is OK for first run } nlohmann::json usersJson; file >> usersJson; file.close(); m_users.clear(); for (auto& item : usersJson.items()) { const std::string& username = item.key(); nlohmann::json& userJson = item.value(); UserInfo user; user.id = userJson.value("id", ""); user.username = userJson.value("username", username); user.email = userJson.value("email", ""); user.passwordHash = userJson.value("password_hash", ""); user.role = userJson.value("role", "user"); user.permissions = userJson.value("permissions", std::vector{}); user.apiKeys = userJson.value("api_keys", std::vector{}); user.active = userJson.value("active", true); user.createdAt = userJson.value("created_at", 0); user.lastLoginAt = userJson.value("last_login_at", 0); user.passwordChangedAt = userJson.value("password_changed_at", 0); user.createdBy = userJson.value("created_by", "system"); m_users[username] = user; } return true; } catch (const std::exception& e) { return false; } } bool UserManager::saveApiKeyData() { try { nlohmann::json apiKeysData = nlohmann::json::object(); for (const auto& pair : m_apiKeys) { const ApiKeyInfo& keyInfo = pair.second; nlohmann::json keyData = { {"key_id", keyInfo.keyId}, {"key_hash", keyInfo.keyHash}, {"name", keyInfo.name}, {"user_id", keyInfo.userId}, {"permissions", keyInfo.permissions}, {"active", keyInfo.active}, {"created_at", keyInfo.createdAt}, {"last_used_at", keyInfo.lastUsedAt}, {"expires_at", keyInfo.expiresAt}, {"created_by", keyInfo.createdBy} }; apiKeysData[keyInfo.keyId] = keyData; } std::string filename = m_dataDir + "/api_keys.json"; std::ofstream file(filename); if (!file.is_open()) { return false; } file << apiKeysData.dump(2); file.close(); return true; } catch (const std::exception& e) { return false; } } bool UserManager::loadApiKeyData() { try { std::string filename = m_dataDir + "/api_keys.json"; std::ifstream file(filename); if (!file.is_open()) { return false; // File doesn't exist is OK for first run } nlohmann::json apiKeysJson; file >> apiKeysJson; file.close(); m_apiKeys.clear(); m_apiKeyMap.clear(); for (auto& item : apiKeysJson.items()) { const std::string& keyId = item.key(); nlohmann::json& keyJson = item.value(); ApiKeyInfo keyInfo; keyInfo.keyId = keyJson.value("key_id", keyId); keyInfo.keyHash = keyJson.value("key_hash", ""); keyInfo.name = keyJson.value("name", ""); keyInfo.userId = keyJson.value("user_id", ""); keyInfo.permissions = keyJson.value("permissions", std::vector{}); keyInfo.active = keyJson.value("active", true); keyInfo.createdAt = keyJson.value("created_at", 0); keyInfo.lastUsedAt = keyJson.value("last_used_at", 0); keyInfo.expiresAt = keyJson.value("expires_at", 0); keyInfo.createdBy = keyJson.value("created_by", "system"); m_apiKeys[keyId] = keyInfo; m_apiKeyMap[keyInfo.keyHash] = keyId; } return true; } catch (const std::exception& e) { return false; } } int64_t UserManager::getCurrentTimestamp() { return std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); } bool UserManager::validateUsername(const std::string& username) { if (username.length() < 3 || username.length() > 32) { return false; } // Username should contain only alphanumeric characters, underscores, and hyphens std::regex pattern("^[a-zA-Z0-9_-]+$"); return std::regex_match(username, pattern); } bool UserManager::validatePassword(const std::string& password) { if (password.length() < 8 || password.length() > 128) { return false; } // Password should contain at least one letter and one digit bool hasLetter = false; bool hasDigit = false; for (char c : password) { if (std::isalpha(c)) hasLetter = true; if (std::isdigit(c)) hasDigit = true; } return hasLetter && hasDigit; } bool UserManager::validateEmail(const std::string& email) { if (email.length() < 5 || email.length() > 254) { return false; } // Basic email validation std::regex pattern("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"); return std::regex_match(email, pattern); } bool UserManager::canManageUser(const std::string& requestingUserId, const std::string& targetUserId) { // Users can always manage themselves if (requestingUserId == targetUserId) { return true; } // Check if requester is admin UserInfo requester = getUserInfo(requestingUserId); return requester.role == roleToString(UserRole::ADMIN); }